envoy源码分析(十一)--性能分析

 

主线程性能

如  envoy源码分析(八)--main线程专项分析  的分析,主线程有如下几部分功能:

1  xds消息处理

2  主动健康检查

3   admin接口请求处理

4   state信息周期合并

5   state sink 插件调用。

 

随着配置量增长,主动健康检查 与  admin 接口请求, 将成为主线程的性能瓶颈。导致CPU满载。

xds 消息可以配置成ads的增量模式,不对导致CPU瓶颈。

state的周期是全局可调的,另外 state sink 有 dog-stated 的 UDP 插件,可以将统计信息外送至stated统一处理。

 

worker线程转发性能

总结有4个瓶颈

1  accpt时 alloc fd的锁

2  中断与worker分开后,tcp_push_pending_frames的锁

     这个不是真的锁住了,中断在超线程上会有cache争抢问题,导致锁原子操作被放大。绑独立核心的时候没有这个问题。

3  libevent 启用多线程时的 mutex

4  libevnet 全局变量 event_debug_mode_on_  /  event_debug_mode_too_late  cache miss

 

如 envoy源码分析(十)--事件机制专项分析  的分析, libevent 的 多线程锁会成为瓶颈。

实测在32个CPU后,性能增长趋于平缓。

解法也比较简单直接。分成多进程,利用内核的port reuse,实现多进程无差别服务,

不需要做额外的角色管理,只需要同时订阅一份xds配置即可。

 

还有另一个解法,如  envoy源码分析(十)--事件机制专项分析  的分析

可以使用 io_uring

 

perf top 查看热点是 libevent 的锁:

image

 

使用bpftrace,找到热点锁的调用位置

/*
 * 追踪 pthread_mutex_lock 的等待耗时,并按锁地址和调用栈分组
 */

BEGIN {
    printf("正在追踪 Envoy 锁竞争... 按 Ctrl-C 结束并查看结果\n");
}

uprobe:libc:pthread_mutex_lock {
    @start[tid] = nsecs;
    @lock_addr[tid] = arg0; // 记录锁对象的内存地址
}

uretprobe:libc:pthread_mutex_lock /@start[tid]/ {
    $duration = nsecs - @start[tid];
    $lock = @lock_addr[tid];

    // 只记录耗时超过 1000 纳秒(1微秒)的竞争,过滤掉极快的无竞争加锁
    if ($duration > 1000) {
        @total_wait_ns[$lock] = sum($duration);      // 该地址锁的总等待时间
        @max_wait_ns[$lock] = max($duration);        // 该地址锁的最大单次等待
        @contention_stacks[ustack, $lock] = count(); // 导致竞争的调用栈
    }

    delete(@start[tid]);
    delete(@lock_addr[tid]);
}

END {
    printf("\n--- 各个锁地址的总等待时长 (ns) ---\n");
    // 结果会按总耗时排序输出
}

 

输出结果:

排名第一的函数,event_process_active_single_queue(),比第二名多了一个数量级

image

 

代码:

https://github.com/libevent/libevent/blob/release-2.1.12-stable/event.c#L1727

 

分析主要原因:

libevent的事件循环累计锁的原子操作,导致的 耗时操作的高频访问,引起的累计效果。

image

 

为什么线程数增多,会变的越来越严重?

猜测可能是缓存一致性问题引起。

 

函数 pthread_mutex_unlock_usrcnt

image

 

 

函数 event_del_nolock

image

event_debug_note_del_

全局变量:event_debug_mode_on_  /  event_debug_mode_too_late = 1;

 

 

 

函数 event_add_nolock 

image

 

event_debug_note_setup_

全局变量:event_debug_mode_on_  /  event_debug_mode_too_late = 1;

 

修改设置全局变量cache line 对齐:

envoy/build_root/bazel_root/base/external/com_github_libevent_libevent::event.c

image

 

image

 

 

用 bpftrace 查看锁是否被竞争

[root@A06-R08-I208-229-925A008 caotong1]# cat envoy-4.bt 
#!/usr/bin/env bpftrace

#include <linux/sched.h>

BEGIN {
    printf("正在监测锁(Lock/Unlock)访问分布... 采样周期 5s\n");
    printf("%-18s | %-16s | %s\n", "MUTEX_ADDR", "OP_TYPE", "THREAD_NAME:COUNT");
    printf("-------------------|------------------|--------------------------\n");
}

/* 监控加锁 */
uprobe:/lib64/libc.so.6:pthread_mutex_lock,
uprobe:/lib64/libc.so.6:pthread_mutex_trylock,
{
    @ops[arg0, "lock", comm] = count();
}

uprobe:/lib64/libc.so.6:pthread_mutex_unlock 
{
    @ops[arg0, "unlock", comm] = count();
}

END {
    print(@ops);
    clear(@ops);
}
[root@A06-R08-I208-229-925A008 caotong1]# #./envoy-4.bt  > 1
[root@A06-R08-I208-229-925A008 caotong1]# cat 1 |awk '{print $1}' |sort |uniq -c |tail
      4 @ops[8635020759488,
      4 @ops[8635020759808,
      4 @ops[8635020760128,
      4 @ops[8635020760448,
      4 @ops[8635020760768,
      4 @ops[8635020761088,
      4 @ops[8635020761344,
      2 @ops[93987636247152,
      4 @ops[93987636268544,
      1 正在监测锁(Lock/Unlock)访问分布...
[root@A06-R08-I208-229-925A008 caotong1]# cat 1 |grep 8635020761344
@ops[8635020761344, lock, envoy]: 144
@ops[8635020761344, unlock, envoy]: 146
@ops[8635020761344, lock, wrk:worker_47]: 746930
@ops[8635020761344, unlock, wrk:worker_47]: 747892
我现在想知道,锁8635020761344,在这些命中时的调用栈

 

针对锁 8635020761344 查看其调用栈

[root@A06-R08-I208-229-925A008 caotong1]# cat envoy-5.bt 
#!/usr/bin/env bpftrace

/* * 专门针对特定热点锁地址抓取调用栈
 * 热点地址: 8635020761344
 */

BEGIN {
    printf("正在追踪锁 8635020761344 的调用栈... (Ctrl+C 结束)\n");
}

uprobe:/lib64/libc.so.6:pthread_mutex_lock /arg0 == 8635020761344/ {
    @[comm, ustack] = count();
}

uprobe:/lib64/libc.so.6:pthread_mutex_unlock /arg0 == 8635020761344/ {
    @[comm, ustack] = count();
}

END {
    print(@);
    clear(@);
}

 

 

image

 

是 state 的定时刷新在枪锁。

 

posted on 2026-01-06 16:57  toong  阅读(1)  评论(0)    收藏  举报