Рубрики
Uncategorized

EBPF для Sre надежно

EBPF — это забавная технология, оно основано на BPF, который почти такой же старый, как сам Linux и … Теги с DevOps, Sre, EBPF.

EBPF — это забавная технология, оно основано на BPF, который почти такой же старый, как сам Linux, и все же EBPF сильно зависит в течение последних нескольких лет.

В моей книге EBPF это генератор системы событий. Постукивая в этот пул событий и прослушивание на правильном уровне, вы можете получить тонны понимания вашей системы.

Достаточно гриппирован, SRE также наступает на пару лет, и это точно говорит о том, как здоровье системы.

Итак, эти два могут быть сделаны друг для друга? Ну, может быть, не в таких откровение термины, но есть что-то очень привлекательное, чтобы принести их ближе.

SRE представил объективный уровень обслуживания ( SLO ) и индикаторы уровня обслуживания (SLI). SLO кодирует, что хорошо выглядит для аспектов, которые имеют значение для вас в вашей системе. SLI кодирует метрики, которые агрегаты как цель SLO. EBPF — интересный источник данных для показателей.

Например, скажем, у вас есть эта программа EBPF (через BCC ):

#include 
#include 
#include 

#define IP_TCP  6

int http_filter(struct __sk_buff *skb) {
    u8 *cursor = 0;

    // let's not care for anything not Ethernet or TCP
    struct ethernet_t *ethernet = cursor_advance(cursor, sizeof(*ethernet));
    if (!(ethernet->type == 0x0800)) {
        return 0;
    }

    struct ip_t *ip = cursor_advance(cursor, sizeof(*ip));
    if (ip->nextp != IP_TCP) {
        return 0;
    }

    return -1;
}

Простое Гнездовая фильтрация В самом деле. Мы только храним пакеты TCP, чтобы осмотреть их на землю пользователей и игнорировать остальные.

С землей пользователей мы сейчас имеем программу Python, которая вводит эту программу в ядро:

class MySocketHndl(psocket.SocketHndl):
    def __init__(self, b: BPF, timeout: int = None, iface: str = "lo"):
        """
        BCC gives the us a socket to listen from. Bind to it.
        """
        function_http_filter = b.load_func("http_filter", BPF.SOCKET_FILTER)
        BPF.attach_raw_socket(function_http_filter, iface)
        socket_fd = function_http_filter.sock

        self._socket = socket.fromfd(
            socket_fd, socket.PF_PACKET, socket.SOCK_RAW,
            socket.IPPROTO_IP)

        # blocks forever when timeout is None
        self._socket.settimeout(timeout)

@contextmanager
def bpfsock(iface: str = "lo"):
    """
    Loads the BPF program and starts listening on the socket we attach
    to the interface. Cleanup when finished.
    """
    try:
        b = BPF(src_file = "ebpf.c")
        psock = MySocketHndl(b=b, iface=iface)
        yield psock
    finally:
        psock.close()
        b.cleanup()

Мы просто прикрепляем к интерфейсу и добавляем наш фильтр в сокет, используемую для прослушивания интерфейса. Теперь мы можем обработать пакеты, как мы их видим. Затем мы уволяем любой пакет, на котором мы не заботимся, здесь ничего не HTTP, и мы анализируем действительные пакеты как HTTP-запросы/ответы, используя потрясающие Pypacker Отказ

def filter_pkt(eth: ethernet.Ethernet, target_port: int = 8000) -> bool:
    """
    Process only packets that are going to or from the target server.
    """
    if eth[ethernet.Ethernet, ip.IP, tcp.TCP] is not None:
        tcp_p = eth[tcp.TCP]
        if tcp_p.dport == target_port or tcp_p.sport == target_port:
            return True
    return False

def process():
    with bpfsock(iface="lo") as psock:
        for pkt in psock.recvp_iter(filter_match_recv=filter_pkt):
            h = http.HTTP(pkt[tcp.TCP].body_bytes)

Бум, мы золото!

Оттуда, все, что нам нужно сделать, это собрать некоторую информацию о запросах/ответах, которые мы видим (продолжительность, код состояния, запрошенный путь) и совокупные соотношения со временными окнами, которые мы заинтересованы в отслеживании.

total_count = class_2xx = good_latency_count = 0
for req in requests:
    if window_start <= req["end"] < window_end:
       total_count += 1
    # our SLO latency is 150ms
    if req["duration"] <= 0.15:
       good_latency_count += 1
    if req["status"] == 200:
       class_2xx += 1

    if total_count == 0:
       continue

   indicators.put(
     (
         "availability", last_push, next_push, path,
         100.0 * (class_2xx / total_count)
     )
   )
   indicators.put(
     (
         "latency", last_push, next_push, path,
         100.0 * (good_latency_count / total_count)
     )
   )

Здесь ничего не хочет.

Теперь, когда у нас есть наши показатели, мы можем отправить их надежно создавать наши результаты SLO:

def send_indicators():
    indicator_type, from_ts, to_ts, path, value = indicators.get()

    headers = {"Authorization": f"Bearer {TOKEN}"}
    indicator = {
        "metadata": {
             "labels": {
                 "category": indicator_type,
                 "path": path
             }
         },
         "spec": {
             "from": f"{from_ts.isoformat()}Z",
             "to": f"{to_ts.isoformat()}Z",
             "percent": value
         }
    }

    if indicator_type == "latency":
       indicator["metadata"]["labels"]["percentile"] = "100"
       indicator["metadata"]["labels"]["latency_target"] = "150ms"

    httpx.put(reliably_url, headers=headers, json=indicator)

Опять не хочу.

На этом этапе Надежно Теперь можно генерировать результаты SLO, вы можете начать просмотр с помощью Надежно CLI :

$ reliably slo report
Refreshing SLO report every 3 seconds. Press CTRL+C to quit.
                                                                  Current  Objective  / Time Window     Type             Trend      
  Service #1: ebpf-2021-demo                                 
  ❌ 99% of the responses are under 150ms                          98.99%      99.5%  / 10s             Latency          ✕ ✕ ✕ ✓ ✕  
  ❌ 99% of the responses to our users are in the 2xx class        98.66%        99%  / 10s             Availability     ✓ ✓ ✕ ✓ ✕  

Kaboom! Сейчас мы успешно сопоставили мероприятия по низким уровне EBPF в SLO-конструкции высокого уровня.

Очевидно, это довольно тривиальная витрина, но это многообещается. Тем не менее, существует некоторая маршрут, прежде чем весь процесс становится более привлекательным, так как UX EBPF, возможно, не такой прозрачный, как можно надеяться.

Тем не менее, так весело!

Код можно найти в https://github.com/lawouach/ebpf-2021-talk Отказ

Оригинал: «https://dev.to/reliably/ebpf-for-sre-with-reliably-18dc»