c 做精品课程网站,龙江建网站,文化网站建设心得,wordpress制作婚礼网页什么是惊群效应#xff1f;
第一次听到的这个名词的时候觉得很是有趣#xff0c;不知道是个什么意思#xff0c;总觉得又是奇怪的中文翻译导致的。
复杂的说#xff08;来源于网络#xff09;TLDR; 惊群效应#xff08;thundering herd#xff09;是指多进程#xff…什么是惊群效应
第一次听到的这个名词的时候觉得很是有趣不知道是个什么意思总觉得又是奇怪的中文翻译导致的。
复杂的说来源于网络TLDR; 惊群效应thundering herd是指多进程多线程在同时阻塞等待同一个事件的时候休眠状态如果等待的这个事件发生那么他就会唤醒等待的所有进程或者线程但是最终却只能有一个进程线程获得这个时间的“控制权”对该事件进行处理而其他进程线程获取“控制权”失败只能重新进入休眠状态这种现象和性能浪费就叫做惊群效应。 简单的讲我的大白话 有一道雷打下来把很多人都吵醒了但只有其中一个人去收衣服了。也就是有一个请求过来了把很多进程都唤醒了但只有其中一个能最终处理。 原因问题
说起来其实也简单多数时候为了提高应用的请求处理能力会使用多进程多线程去监听请求当请求来时因为都有能力处理所以就都被唤醒了。
而问题就是最终还是只能有一个进程能来处理。当请求多了不停地唤醒、休眠、唤醒、休眠做了很多的无用功上下文切换又累对吧。那怎么解决这个问题呢下面就是今天要看的重点我们看看 nginx 是如何解决这个问题的。
Nginx 架构
第一点我们需要了解 nginx 大致的架构是怎么样的。nginx 将进程分为 master 和 worker 两类非常常见的一种 M-S 策略也就是 master 负责统筹管理 worker当然它也负责如启动、读取配置文件监听处理各种信号等工作。 但是第一个要注意的问题就出现了master 的工作有且只有这些对于请求来说它是不管的就如同图中所示请求是直接被 worker 处理的。如此一来请求应该被哪个 worker 处理呢worker 内部又是如何处理请求的呢
Nginx 使用 epoll
接下来我们就要知道 nginx 是如何使用 epoll 来处理请求的。下面可能会涉及到一些源码的内容但不用担心你不需要全部理解只需要知道它们的作用就可以了。顺便我会简单描述一下我是如何去找到这些源码的位置的。
Master 的工作
其实 Master 并不是毫无作为至少端口是它来占的。https://github.com/nginx/nginx/blob/b489ba83e9be446923facfe1a2fe392be3095d1f/src/core/ngx_connection.c#L407C13-L407C13
ngx_open_listening_sockets(ngx_cycle_t *cycle)
{.....for (i 0; i cycle-listening.nelts; i) {.....if (bind(s, ls[i].sockaddr, ls[i].socklen) -1) {if (listen(s, ls[i].backlog) -1) {
}
那么根据我们 nginx.conf 的配置文件看需要监听哪个端口于是就去 bind 的了这里没问题。
【发现源码】这里我是直接在代码里面搜 bind 方法去找的因为我知道不管你怎么样你总是要绑定端口的
然后是创建 worker 的虽不起眼但很关键。https://github.com/nginx/nginx/blob/b489ba83e9be446923facfe1a2fe392be3095d1f/src/os/unix/ngx_process.c#L186
ngx_spawn_process(ngx_cycle_t *cycle, ngx_spawn_proc_pt proc, void *data,char *name, ngx_int_t respawn)
{....pid fork(); 【发现源码】这里我直接搜 fork整个项目里面需要 fork 的情况只有两个地方很快就找到了 worker 由于是 fork 创建的也就是复制了一份 task_struct 结构。所以 master 的几乎全部它都有。
Worker 的工作
Nginx 有一个分模块的思想它将不同功能分成了不同的模块而 epoll 自然就是在 ngx_epoll_module.c 中了
https://github.com/nginx/nginx/blob/b489ba83e9be446923facfe1a2fe392be3095d1f/src/event/modules/ngx_epoll_module.c#L330C23-L330C23
ngx_epoll_init(ngx_cycle_t *cycle, ngx_msec_t timer)
{ngx_epoll_conf_t *epcf;epcf ngx_event_get_conf(cycle-conf_ctx, ngx_epoll_module);if (ep -1) {ep epoll_create(cycle-connection_n / 2);
其他不重要就连 epoll_ctl 和 epoll_wait 也不重要了这里你需要知道的就是从调用链路来看是 worker 创建的 epoll 对象也就是每个 worker 都有自己的 epoll 对象而监听的sokcet 是一样的 【发现源码】这里更加直接搜索 epoll_create 肯定就能找到 问题的关键
此时问题的关键基本就能了解了每个 worker 都有处理能力请求来了此时应该唤醒谁呢讲道理那不是所有 epoll 都会有事件所有 worker 都 accept 请求显然这样是不行的。那么 nginx 是如何解决的呢
相关视频推荐
Nginx源码解析惊群方案、惊群现象演示、锁方案讲解
16w行的nginx源码如何才能读懂呢全面分析nginx的机制
epoll的原理与使用epoll比select/poll强在哪里
Linux C/C开发后端/音视频/游戏/嵌入式/高性能网络/存储/基础架构/安全
需要C/C Linux服务器架构师学习资料加qun812855908获取资料包括C/CLinuxgolang技术NginxZeroMQMySQLRedisfastdfsMongoDBZK流媒体CDNP2PK8SDockerTCP/IP协程DPDKffmpeg等免费分享 如何解决
解决方式一共有三种下面我们一个个来看 accept_mutex应用层的解决方案 EPOLLEXCLUSIVE内核层的解决方案 SO_REUSEPORT内核层的解决方案
accept_mutex
看到 mutex 可能你就知道了锁嘛这也是对于高并发处理的 ”基操“ 遇事不决加锁没错加锁肯定能解决问题。https://github.com/nginx/nginx/blob/b489ba83e9be446923facfe1a2fe392be3095d1f/src/event/ngx_event_accept.c#L328
具体代码就不展示了其中细节很多但本质很容易理解就是当请求来了谁拿到了这个锁谁就去处理。没拿到的就不管了。锁的问题很直接除了慢没啥不好的但至少很公平。
EPOLLEXCLUSIVE EPOLLEXCLUSIVE 是 2016 年 4.5 内核新添加的一个 epoll 的标识。它降低了多个进程/线程通过 epoll_ctl 添加共享 fd 引发的惊群概率使得一个事件发生时只唤醒一个正在 epoll_wait 阻塞等待唤醒的进程而不是全部唤醒。 关键是每次内核只唤醒一个睡眠的进程处理资源
但这个方案不是完美的解决了它仅是降低了概率哦。为什么这样说呢相比于原来全部唤醒那肯定是好了不少降低了冲突。但由于本质来说 socket 是共享的当前进程处理完成的时间不确定在后面被唤醒的进程可能会发现当前的 socket 已经被之前唤醒的进程处理掉了。
SO_REUSEPORT
Nginx 在 1.9.1 版本加入了这个功能 https://www.nginx.com/blog/socket-sharding-nginx-release-1-9-1/
其本质是利用了 Linux 的 reuseport 的特性使用 reuseport 内核允许多个进程 listening socket 到同一个端口上而从内核层面做了负载均衡每次唤醒其中一个进程。
反应到 Nginx 上就是每个 Worker 进程都创建独立的 listening socket监听相同的端口accept 时只有一个进程会获得连接。效果就和下图所示一样。 而使用方式则是
http {server {listen 80 reuseport;server_name localhost;# ...}
}
从官方的测试情况来看确实是厉害 当然正所谓完事无绝对技术无银弹。这个方案的问题在于内核是不知道你忙还是不忙的。只会无脑的丢给你。与之前的抢锁对比抢锁的进程一定是不忙的现在手上的工作都已经忙不过来了没机会去抢锁了而这个方案可能导致如果当前进程忙不过来了还是会只要根据 reuseport 的负载规则轮到你了就会发送给你所以会导致有的请求被前面慢的请求卡住了。
总结
本文从了解什么 ”惊群效应“ 到 nginx 架构和 epoll 处理的原理最终分析三种不同的处理 “惊群效应” 的方案。分析到这里我想你应该明白其实 nginx 这个多队列服务模型是所存在的一些问题只不过绝大多数场景已经完完全全够用了。