Optimización del rendimiento de Linux (cuatro) -Herramienta de supervisión del rendimiento de BCC

1. Introducción a BCC

1. Introducción a BCC

BCC es una biblioteca de Python que simplifica el proceso de desarrollo de aplicaciones eBPF y recopila una gran cantidad de aplicaciones eBPF relacionadas con el análisis de rendimiento. BCC proporciona un soporte de front-end diferente para el desarrollo de BPF, incluidos Python y Lua, y realiza la creación de mapas, la compilación de código, el análisis, la inyección y otras operaciones, de modo que los desarrolladores solo necesitan enfocarse en desarrollar el código del kernel para ser inyectado en lenguaje C.
La mayoría de las herramientas del conjunto de herramientas BCC deben ser compatibles con Linux Kernel 4.1 o superior, y el soporte completo de herramientas requiere Linux Kernel 4.15 o superior.
GitHub: https://github.com/iovisor/bcc

2. Instalación de BCC

yum install bcc-tools
export PATH=$PATH:/usr/share/bcc/tools

Dos herramientas de comando de uso común

1 、 abrenoop

Opensnoop muestra el proceso de intentar abrir el archivo mediante el seguimiento de la llamada al sistema open (), que se puede utilizar para localizar archivos de configuración o archivos de registro, o para solucionar problemas de aplicaciones fallidas que no se iniciaron.
Opensnoop rastrea dinámicamente la función del kernel sys_open () y actualiza cualquier cambio en la función. Opensnoop requiere compatibilidad con Linux Kernel 4.5. Debido a que usa BPF, requiere privilegios de root.
opensnoop [-h] [-T] [-U] [-x] [-p PID] [-t TID] [-u UID] [-d DURATION] [-n NAME] [-e] [-f FLAG_FILTER]
-h, --help: vista de información de ayuda
-T, --timestamp: resultado de salida imprimir marca de tiempo
-U, --print-uid: imprimir UID
-x, --failed: mostrar solo llamadas fallidas al sistema abierto
-p PID --pid PID: PID del proceso para rastrear solo
-t TID, --tid TID: solo rastrear subproceso TID
-u UID, --uid UID: Seguir solo UID
-d DURATION, --duration DURATION: rastrear tiempo, en segundos
- n NAME, --name NAME: solo imprime procesos que contienen name
-e, --extended_fields: muestra campos extendidos
-f FLAG_FILTER, --flag_filter FLAG_FILTER: especifica campos de filtro, como O_WRONLY

2 、 execsnoop

execsnoop rastrea los nuevos procesos rastreando las llamadas al sistema de exec. Los procesos que usan fork en lugar de exec no se incluirán en los resultados mostrados.
execsnoop requiere compatibilidad con BPF, por lo que se requieren privilegios de root.
execsnoop [-h] [-T] [-t] [-x] [-q] [-n NAME] [-l LINE] [--max-args MAX_ARGS]
-h: ver información de ayuda
-T: imprimir marca de tiempo, formato HH: MM: SS
-t: imprimir marca de tiempo
-x: incluir error exec
-n NOMBRE: imprimir solo la línea de comando cuya expresión regular coincide con el nombre
-l LINE: solo La línea de comando que coincide con LINE en los parámetros de impresión
--max-args MAXARGS: analiza y muestra el número máximo de parámetros, el valor predeterminado es 20

3 、 biolatencia

Biolatency rastrea el IO del dispositivo de bloque, registra la distribución de latencia IO y lo muestra en un histograma. Biolatency rastrea dinámicamente las blk_funciones familiares y registra los cambios en las funciones.
Biolatency requiere compatibilidad con BPF, por lo que se requieren privilegios de root.
biolatency [-h] [-F] [-T] [-Q] [-m] [-D] [interval [count]]
-h Imprime el mensaje de uso.
-T: la salida contiene la marca de tiempo
-m: muestra el histograma de nivel de ms
-D: imprime el histograma de cada dispositivo de disco
-F: imprime el histograma de cada conjunto de E / S
intervalo: intervalo de salida
cuenta: salida Cantidad
Optimización del rendimiento de Linux (cuatro) -Herramienta de supervisión del rendimiento de BCC

4 、 ext4slower

ext4slower rastrea las operaciones de lectura, escritura, apertura y sincronización del sistema de archivos ext4, mide el tiempo consumido por las operaciones correspondientes e imprime información detallada que excede el umbral. El valor mínimo del umbral predeterminado es 10 ms. Si el umbral es 0, se imprimen todos los eventos.
ext4slower requiere compatibilidad con BPF, por lo que se requieren privilegios de root.
ext4slower puede identificar E / S de disco más lento independiente a través del sistema de archivos.
ext4slower [-h] [-j] [-p PID] [min_ms]
-h, --help: ver información de ayuda
-j, --csv: imprimir campos en formato csv
-p PID, --pid PID: solo rastrear procesos PID
min_ms: rastrear umbral IO, el valor predeterminado es 10.
Optimización del rendimiento de Linux (cuatro) -Herramienta de supervisión del rendimiento de BCC

5 、 biosnoop

biosnoop puede rastrear la E / S del dispositivo e imprimir una línea de información resumida para cada dispositivo IO.
biosnoop rastrea dinámicamente las blk_funciones familiares y registra los cambios de funciones.
Biosnoop requiere compatibilidad con BPF, por lo que se requieren privilegios de root.
biosnoop [-hQ]
-h: ver información de ayuda
-Q: mostrar el tiempo pasado en la cola del SO
Optimización del rendimiento de Linux (cuatro) -Herramienta de supervisión del rendimiento de BCC

6 、 cachestat

Cachestat se utiliza para contar la tasa de aciertos y la tasa de errores de las páginas de Linux, realizar un seguimiento dinámico de la función de caché de la página del kernel y actualizar cualquier cambio en la función de caché.
Cachestat requiere compatibilidad con BPF, por lo que se requieren privilegios de root.
cachestat [-h] [-T] [interval] [count]
-h: ver información de ayuda
-T, --timestamp:
intervalo de la marca de tiempo de salida: intervalo de salida, en segundos
: cantidad de salida
Optimización del rendimiento de Linux (cuatro) -Herramienta de supervisión del rendimiento de BCC

7 、 cachetop

Cachetop se utiliza para contar la tasa de aciertos y la tasa de errores de la caché de la página de Linux de cada proceso, rastrear dinámicamente la función de caché de la página del kernel y actualizar cualquier cambio en la función de caché.
Cachestat requiere compatibilidad con BPF, por lo que se requieren privilegios de root.
c achetop [-h] [interval]
-h: Ver información de ayuda
intervalo: Intervalo de salida
Optimización del rendimiento de Linux (cuatro) -Herramienta de supervisión del rendimiento de BCC
PID: ID de proceso
UID: ID de usuario de proceso
HITS: Número de aciertos de caché de página
MISSES: Número de fallos de caché de página
DIRTIES: Número de páginas sucias agregadas a caché de página
READ_HIT%: Aciertos de lectura de caché de página Tasa
WRITE_HIT%: tasa de aciertos de escritura de la caché de la página
BUFFERS_MB: tamaño del búfer, fuente de datos / proc / meminfo
CACHED_MB: tamaño de la caché de la página actual, fuente de datos / proc / meminfo

8 、 tcpconnect

tcpconnect se usa para rastrear el número de conexiones TCP activas, rastrear dinámicamente las funciones tcp_v4_connect y tcp_v6_connect del kernel, y registrar cualquier cambio dentro de la función.
tcpconnect requiere compatibilidad con BPF, por lo que se requieren privilegios de root.
tcpconnect [-h] [-c] [-t] [-x] [-p PID] [-P PORT]
-h: ver información de ayuda
-t: imprimir marca de tiempo
-c: contar el número de conexiones de cada IP de origen e IP / puerto de destino
-p PID: solo rastrear procesos PID
-P PORT: lista de puertos de destino a rastrear, separados por comas
Optimización del rendimiento de Linux (cuatro) -Herramienta de supervisión del rendimiento de BCC

9 、 rastro

El rastreo se usa para rastrear una llamada de función e imprimir parámetros de función o valores de retorno. Requiere soporte BPF, por lo que se requieren privilegios de root.
trace [-h] [-b BUFFER_PAGES] [-p PID] [-L TID] [-v] [-Z STRING_SIZE] [-S] [-s SYM_FILE_LIST] [-M MAX_EVENTS] [-t] [-u] [-T] [-C] [-K] [-U] [-a] [-I header] probe [probe ...]
-h: ver información de ayuda
-p PID: solo rastrear el proceso PID
-L TID: solo rastrear el hilo de TID
-v: mostrar el programa BPF generado, usar para depurar
-z STRING_SIZE: recopilar la longitud de los parámetros de cadena
-s SYM_FILE_LIST: recopilar el tamaño de la pila
-M MAX_EVENTS: Número máximo de mensajes de seguimiento a
imprimir -t: Tiempo de impresión, en segundos.
-u: Imprime la marca de tiempo
-T: Imprime la columna de tiempo
-C: Imprime el ID de la CPU
-K: Imprime la pila del kernel de
cada evento -U: Imprime la pila del usuario de cada evento
-a: Imprime la secuencia virtual de la pila del kernel y la pila del usuario Dirección
-I encabezado: agregue el archivo de encabezado a la
sonda del programa BPF [sonda ...]: la sonda adjunta a la función
trace ':: do_sys_open "% s", arg2' para
rastrear todos los métodos de llamada de las llamadas al sistema abierto,
Optimización del rendimiento de Linux (cuatro) -Herramienta de supervisión del rendimiento de BCC
trace ':c:malloc "size = %d", arg1'
rastrear las llamadas malloc e imprimirlas Solicite el tamaño de la memoria asignada para
Optimización del rendimiento de Linux (cuatro) -Herramienta de supervisión del rendimiento de BCC
trace 'u:pthread:pthread_create "start addr = %llx", arg3'
rastrear la llamada a la función pthread_create e imprima la dirección de la función de inicio del hilo
Optimización del rendimiento de Linux (cuatro) -Herramienta de supervisión del rendimiento de BCC

10 、 punto muerto

interbloqueo se utiliza para encontrar posibles puntos muertos en un proceso en ejecución. El interbloqueo requiere compatibilidad con BPF adjuntando eventos uprobe, por lo que se requieren privilegios de root.
deadlock [-h] [--binary BINARY] [--dump-graph DUMP_GRAPH] [--verbose] [--lock-symbols LOCK_SYMBOLS] [--unlock-symbols UNLOCK_SYMBOLS] pid
-h, --help: Ver información de ayuda
--binary BINARY: Especifica la biblioteca de subprocesos, debe especificarse para el enlazador dinámico.
--dump-graph DUMP_GRAPH: Exporta el gráfico de mutex al archivo especificado
--verbose: Imprime estadísticas de mutex
--lock-symbols LOCK_SYMBOLS: Una lista de bloqueos para rastrear, separados por comas, el valor predeterminado es pthread_mutex_lock.
--unlock-symbols UNLOCK_SYMBOLS: una lista de desbloqueos que se deben rastrear, separados por comas, y el valor predeterminado es pthread_mutex_unlock.
pid: El ID del proceso que se rastreará para
deadlock 181 --binary /lib/x86_64-linux-gnu/libpthread.so.0
encontrar posibles puntos muertos en el proceso 181. Si el proceso es creado por un enlazador dinámico, necesita usar la biblioteca de subprocesos especificada por --binary.

11 、 fuga de memorias

memleak se utiliza para rastrear y encontrar la asignación de memoria y la coincidencia de versiones, y requiere compatibilidad con Linux Kernel 4.7 o superior.
memleak [-h] [-p PID] [-t] [-a] [-o OLDER] [-c COMMAND] [--combined-only] [-s SAMPLE_RATE] [-T TOP] [-z MIN_SIZE] [-Z MAX_SIZE] [-O OBJ] [INTERVAL] [COUNT]
-h: ver información de ayuda
-p PID: especificar el proceso PID
-t: rastrear todas las asignaciones de memoria y liberar solicitudes y resultados
-a: generar una lista de memoria no publicada
-z MIN_SIZE: capturar el valor mínimo de memoria asignada
-Z MAX_SIZE: capturar asignación El valor máximo de memoria
memleak -z 16 -Z 32
solo captura y analiza la asignación de memoria entre 16 bytes y 32 bytes.

Tres, desarrollo de programación BCC

1. Principio de realización de BCC

BCC es un conjunto de herramientas de eBPF, que es un paquete de nivel superior para extraer datos de eBPF. La forma de programación de las herramientas de BCC es un programa BPF anidado en Python. El código Python puede proporcionar a los usuarios una interfaz amigable de nivel superior para eBPF y también se puede utilizar para el procesamiento de datos. El programa BPF se inyectará en el kernel para extraer datos. Cuando el programa BPF se está ejecutando, LLVM compila el programa BPF para obtener el archivo elf del conjunto de instrucciones BPF, y la parte que se puede inyectar en el kernel se analiza desde el archivo elf y se usa el método bpf_load_program para completar la inyección.
El método del programa de inyección bpf_load_program agrega un mecanismo de verificación complejo Antes de ejecutar el programa de inyección, se realizan una serie de controles de seguridad para garantizar la seguridad del sistema en la mayor medida posible. El código de bytes BPF con verificación de seguridad se compila utilizando el JIT del kernel para generar instrucciones de ensamblaje nativas y se adjunta al programa de enlace específico del kernel. Finalmente, el modo kernel y el modo de usuario se comunican a través de un mecanismo de mapa eficiente, y la herramienta BCC usa Python para el procesamiento de datos en el modo de usuario.
Optimización del rendimiento de Linux (cuatro) -Herramienta de supervisión del rendimiento de BCC

2. Implementación de ejemplo de BCC

Parte de la codificación de Python requiere la introducción de módulos y paquetes utilizados.
En el código Python de la herramienta BCC, el código del programa en lenguaje BPF C se usa de la siguiente manera:
hello_world.py:

#!/usr/bin/python3
from bcc import BPF
bpf_program = '''
int kprobe__sys_clone(void *ctx) 
{ 
    bpf_trace_printk("Hello, World!\\n");
    return 0;
}'''
if __name__ == "__main__":
       BPF(text=bpf_program).trace_print()

kprobe__sys_cloneEs un atajo para el seguimiento dinámico del kernel a través de kprobes.Si la función C comienza con kprobe__, el resto se considera el nombre de la función del kernel a detectar.
bpf_trace_printk: salida
python3 hello_world.py
Optimización del rendimiento de Linux (cuatro) -Herramienta de supervisión del rendimiento de BCC

3. Ejemplo de defensa DDOS

#!/usr/bin/python
from bcc import BPF
import pyroute2
import time
import sys

flags = 0
def usage():
    print("Usage: {0} [-S] <ifdev>".format(sys.argv[0]))
    print("       -S: use skb mode\n")
    print("e.g.: {0} eth0\n".format(sys.argv[0]))
    exit(1)

if len(sys.argv) < 2 or len(sys.argv) > 3:
    usage()

if len(sys.argv) == 2:
    device = sys.argv[1]

if len(sys.argv) == 3:
    if "-S" in sys.argv:
        # XDP_FLAGS_SKB_MODE
        flags |= 2 << 0

    if "-S" == sys.argv[1]:
        device = sys.argv[2]
    else:
        device = sys.argv[1]

mode = BPF.XDP
ctxtype = "xdp_md"

# load BPF program
b = BPF(text = """
#define KBUILD_MODNAME "foo"
#include <uapi/linux/bpf.h>
#include <linux/in.h>
#include <linux/if_ether.h>
#include <linux/if_packet.h>
#include <linux/if_vlan.h>
#include <linux/ip.h>
#include <linux/ipv6.h>

// how to determin ddos
#define MAX_NB_PACKETS 1000
#define LEGAL_DIFF_TIMESTAMP_PACKETS 1000000

// store data, data can be accessd in kernel and user namespace
BPF_HASH(rcv_packets);
BPF_TABLE("percpu_array", uint32_t, long, dropcnt, 256);

static inline int parse_ipv4(void *data, u64 nh_off, void *data_end) {
    struct iphdr *iph = data + nh_off;
    if ((void*)&iph[1] > data_end)
        return 0;
    return iph->protocol;
}
static inline int parse_ipv6(void *data, u64 nh_off, void *data_end) {
    struct ipv6hdr *ip6h = data + nh_off;
    if ((void*)&ip6h[1] > data_end)
        return 0;
    return ip6h->nexthdr;
}

// determine ddos
static inline int detect_ddos(){
    // Used to count number of received packets
    u64 rcv_packets_nb_index = 0, rcv_packets_nb_inter=1, *rcv_packets_nb_ptr;
    // Used to measure elapsed time between 2 successive received packets
    u64 rcv_packets_ts_index = 1, rcv_packets_ts_inter=0, *rcv_packets_ts_ptr;
    int ret = 0;

    rcv_packets_nb_ptr = rcv_packets.lookup(&rcv_packets_nb_index);
    rcv_packets_ts_ptr = rcv_packets.lookup(&rcv_packets_ts_index);
    if(rcv_packets_nb_ptr != 0 && rcv_packets_ts_ptr != 0){
        rcv_packets_nb_inter = *rcv_packets_nb_ptr;
        rcv_packets_ts_inter = bpf_ktime_get_ns() - *rcv_packets_ts_ptr;
        if(rcv_packets_ts_inter < LEGAL_DIFF_TIMESTAMP_PACKETS){
            rcv_packets_nb_inter++;
        } else {
            rcv_packets_nb_inter = 0;
        }
        if(rcv_packets_nb_inter > MAX_NB_PACKETS){
            ret = 1;
        }
    }
    rcv_packets_ts_inter = bpf_ktime_get_ns();
    rcv_packets.update(&rcv_packets_nb_index, &rcv_packets_nb_inter);
    rcv_packets.update(&rcv_packets_ts_index, &rcv_packets_ts_inter);
    return ret;
}

// determine and recode by proto
int xdp_prog1(struct CTXTYPE *ctx) {
    void* data_end = (void*)(long)ctx->data_end;
    void* data = (void*)(long)ctx->data;
    struct ethhdr *eth = data;
    // drop packets
    int rc = XDP_PASS; // let pass XDP_PASS or redirect to tx via XDP_TX
    long *value;
    uint16_t h_proto;
    uint64_t nh_off = 0;
    uint32_t index;
    nh_off = sizeof(*eth);
    if (data + nh_off  > data_end)
        return rc;
    h_proto = eth->h_proto;
    // parse double vlans
    if (detect_ddos() == 0){
        return rc;
    }
    rc = XDP_DROP;
    #pragma unroll
    for (int i=0; i<2; i++) {
        if (h_proto == htons(ETH_P_8021Q) || h_proto == htons(ETH_P_8021AD)) {
            struct vlan_hdr *vhdr;
            vhdr = data + nh_off;
            nh_off += sizeof(struct vlan_hdr);
            if (data + nh_off > data_end)
                return rc;
                h_proto = vhdr->h_vlan_encapsulated_proto;
        }
    }
    if (h_proto == htons(ETH_P_IP))
        index = parse_ipv4(data, nh_off, data_end);
    else if (h_proto == htons(ETH_P_IPV6))
       index = parse_ipv6(data, nh_off, data_end);
    else
        index = 0;
    value = dropcnt.lookup(&index);
    if (value)
        *value += 1;
    return rc;
}
""", cflags=["-w", "-DCTXTYPE=%s" % ctxtype])

fn = b.load_func("xdp_prog1", mode)
b.attach_xdp(device, fn, flags)

dropcnt = b.get_table("dropcnt")
prev = [0] * 256
print("Printing drops per IP protocol-number, hit CTRL+C to stop")
while 1:
    try:
        for k in dropcnt.keys():
            val = dropcnt.sum(k).value
            i = k.value
            if val:
                delta = val - prev[i]
                prev[i] = val
                print("{}: {} pkt/s".format(i, delta))
        time.sleep(1)
    except KeyboardInterrupt:
        print("Removing filter from device")
        break;

b.remove_xdp(device, flags)

Supongo que te gusta

Origin blog.51cto.com/9291927/2593705
Recomendado
Clasificación