Эх сурвалжийг харах

capturing Redis queries at the eBPF level

Nikolay Sivko 3 жил өмнө
parent
commit
56e395920f

+ 1 - 1
containers/container.go

@@ -461,7 +461,7 @@ func (c *Container) onL7Request(pid uint32, fd uint64, r *ebpftracer.L7Request)
 			switch r.Protocol {
 			case ebpftracer.L7ProtocolHTTP:
 				status = strconv.Itoa(r.Status)
-			case ebpftracer.L7ProtocolPostgres:
+			case ebpftracer.L7ProtocolPostgres, ebpftracer.L7ProtocolRedis:
 				if r.Status == 500 {
 					status = "failed"
 				} else {

+ 2 - 0
containers/metrics.go

@@ -76,10 +76,12 @@ var (
 	L7Requests = map[ebpftracer.L7Protocol]prometheus.CounterOpts{
 		ebpftracer.L7ProtocolHTTP:     {Name: "container_http_requests_total", Help: "Total number of outbound HTTP requests"},
 		ebpftracer.L7ProtocolPostgres: {Name: "container_postgres_queries_total", Help: "Total number of outbound Postgres queries"},
+		ebpftracer.L7ProtocolRedis:    {Name: "container_redis_queries_total", Help: "Total number of outbound Redis queries"},
 	}
 	L7Latency = map[ebpftracer.L7Protocol]prometheus.HistogramOpts{
 		ebpftracer.L7ProtocolHTTP:     {Name: "container_http_request_duration_seconds_total", Help: "Histogram of the response time for each outbound HTTP request"},
 		ebpftracer.L7ProtocolPostgres: {Name: "container_postgres_queries_duration_seconds_total", Help: "Histogram of the execution time for each outbound Postgres query"},
+		ebpftracer.L7ProtocolRedis:    {Name: "container_redis_queries_duration_seconds_total", Help: "Histogram of the execution time for each outbound Redis query"},
 	}
 )
 

Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 0 - 0
ebpftracer/ebpf.go


+ 6 - 0
ebpftracer/ebpf/l7.c

@@ -1,9 +1,11 @@
 #include "http.c"
 #include "postgres.c"
+#include "redis.c"
 
 #define PROTOCOL_UNKNOWN    0
 #define PROTOCOL_HTTP	    1
 #define PROTOCOL_POSTGRES	2
+#define PROTOCOL_REDIS	    3
 
 struct l7_event {
 	__u64 fd;
@@ -78,6 +80,8 @@ int trace_enter_write(__u64 fd, char *buf, __u64 size) {
         req.protocol = PROTOCOL_HTTP;
     } else if (is_postgres_query(buf, size)) {
         req.protocol = PROTOCOL_POSTGRES;
+    } else if (is_redis_query(buf)) {
+        req.protocol = PROTOCOL_REDIS;
     } else {
         return 0;
     }
@@ -126,6 +130,8 @@ int trace_exit_read(struct trace_event_raw_sys_exit_rw__stub* ctx) {
         e.status = parse_http_status(args->buf);
     } else if (req->protocol == PROTOCOL_POSTGRES) {
         e.status = parse_postgres_status(args->buf, ctx->ret);
+    } else if (req->protocol == PROTOCOL_REDIS) {
+        e.status = parse_redis_status(args->buf, ctx->ret);
     }
     if (e.status == 0) {
         return 0;

+ 44 - 0
ebpftracer/ebpf/redis.c

@@ -0,0 +1,44 @@
+// Redis serialization protocol (RESP) specification
+// https://redis.io/docs/reference/protocol-spec/
+
+static __always_inline
+int is_redis_query(char *buf) {
+    char b[5];
+    if (bpf_probe_read(&b, sizeof(b), (void *)((char *)buf)) < 0) {
+        return 0;
+    }
+    if (b[0] != '*' || b[1] < '0' || b[1] > '9') {
+        return 0;
+    }
+    // *3\r\n...
+    if (b[2] == '\r' && b[3] == '\n') {
+        return 1;
+    }
+    // *12\r\n...
+    if (b[2] >= '0' && b[2] <= '9' && b[3] == '\r' && b[4] == '\n') {
+        return 1;
+    }
+    return 0;
+}
+
+static __always_inline
+__u32 parse_redis_status(char *buf, int buf_size) {
+    char type;
+    char end[2];
+    if (bpf_probe_read(&type, sizeof(type), (void *)((char *)buf)) < 0) {
+        return 0;
+    }
+    if (bpf_probe_read(&end, sizeof(end), (void *)((char *)buf+buf_size-2)) < 0) {
+        return 0;
+    }
+    if (end[0] != '\r' || end[1] != '\n') {
+        return 0;
+    }
+    if (type == '*' || type == ':' || type == '$' || type == '+') {
+        return 200;
+    }
+    if (type == '-') {
+        return 500;
+    }
+    return 0;
+}

+ 3 - 0
ebpftracer/tracer.go

@@ -44,6 +44,7 @@ type L7Protocol uint8
 const (
 	L7ProtocolHTTP     L7Protocol = 1
 	L7ProtocolPostgres L7Protocol = 2
+	L7ProtocolRedis    L7Protocol = 3
 )
 
 func (p L7Protocol) String() string {
@@ -52,6 +53,8 @@ func (p L7Protocol) String() string {
 		return "HTTP"
 	case L7ProtocolPostgres:
 		return "Postgres"
+	case L7ProtocolRedis:
+		return "Redis"
 	}
 	return "UNKNOWN:" + strconv.Itoa(int(p))
 }

Энэ ялгаанд хэт олон файл өөрчлөгдсөн тул зарим файлыг харуулаагүй болно