Nginx学习之一-惊群现象
惊群问题(thundering herd)的产生
- ngx_thread_volatile ngx_event_t *ngx_posted_accept_events;
- ngx_thread_volatile ngx_event_t *ngx_posted_events;
- void
- ngx_process_events_and_timers(ngx_cycle_t *cycle)
- {
- ngx_uint_t flags;
- ngx_msec_t timer, delta;
- if (ngx_timer_resolution) {
- timer = NGX_TIMER_INFINITE;
- flags = 0;
- } else {
- timer = ngx_event_find_timer();
- flags = NGX_UPDATE_TIME;
- #if (NGX_THREADS)
- if (timer == NGX_TIMER_INFINITE || timer > 500) {
- timer = 500;
- }
- #endif
- }
- /*ngx_use_accept_mutex表示是否需要通过对accept加锁来解决惊群问题。当使用了master模式,nginx worker进程数>1时且配置文件中打开accept_mutex时,这个标志置为1
- 它在函数ngx_event_process_int中被设置,源代码为:
- if (ccf->master && ccf->worker_processes > 1 && ecf->accept_mutex) {
- ngx_use_accept_mutex = 1;
- ngx_accept_mutex_held = 0;
- ngx_accept_mutex_delay = ecf->accept_mutex_delay;
- } else {
- ngx_use_accept_mutex = 0;
- }*/
- if (ngx_use_accept_mutex) {
- //负载均衡处理
- if (ngx_accept_disabled > 0) {
- ngx_accept_disabled--;
- } else {
- //调用ngx_trylock_accept_mutex方法,尝试获取accept锁
- if (ngx_trylock_accept_mutex(cycle) == NGX_ERROR) {
- return;
- }
- //拿到锁
- if (ngx_accept_mutex_held) {
- /*给flags增加标记NGX_POST_EVENTS,这个标记作为处理时间核心函数ngx_process_events的一个参数,这个函数中所有事件将延后处理。会把accept事件都放到ngx_posted_accept_events链表中,epollin|epollout普通事件都放到ngx_posted_events链表中 */
- flags |= NGX_POST_EVENTS;
- } else {
- /*获取锁失败,意味着既不能让当前worker进程频繁的试图抢锁,也不能让它经过太长事件再去抢锁
- 下面的代码:即使开启了timer_resolution时间精度,牙需要让ngx_process_change方法在没有新事件的时候至少等待ngx_accept_mutex_delay毫秒之后再去试图抢锁
- 而没有开启时间精度时,如果最近一个定时器事件的超时时间距离现在超过了ngx_accept_mutex_delay毫秒,也要把timer设置为ngx_accept_mutex_delay毫秒,这是因为当前进程虽然没有抢到accept_mutex锁,但也不能让ngx_process_change方法在没有新事件的时候等待的时间超过ngx_accept_mutex_delay,这会影响整个负载均衡机制*/
- if (timer == NGX_TIMER_INFINITE
- || timer > ngx_accept_mutex_delay)
- {
- timer = ngx_accept_mutex_delay;
- }
- }
- }
- }
- //计算ngx_process_events消耗的时间
- delta = ngx_current_msec;
- //事件处理核心函数
- (void) ngx_process_events(cycle, timer, flags);
- delta = ngx_current_msec - delta;
- ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
- "timer delta: %M", delta);
- //ngx_posted_accept_events链表有数据,开始accept新连接
- if (ngx_posted_accept_events) {
- ngx_event_process_posted(cycle, &ngx_posted_accept_events);
- }
- //释放锁后再处理ngx_posted_events链表中的普通事件
- if (ngx_accept_mutex_held) {
- ngx_shmtx_unlock(&ngx_accept_mutex);
- }
- //如果ngx_process_events消耗的时间大于0,那么这是可能有新的定时器事件触发
- if (delta) {
- //处理定时器事件
- ngx_event_expire_timers();
- }
- ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
- "posted events %p", ngx_posted_events);
- //ngx_posted_events链表中有数据,进行处理
- if (ngx_posted_events) {
- if (ngx_threaded) {
- ngx_wakeup_worker_thread(cycle);
- } else {
- ngx_event_process_posted(cycle, &ngx_posted_events);
- }
- }
- }
上面代码中要进行说明的是,flags被设置后作为函数ngx_process_events方法的一个参数,在epoll模块中这个接口的实现方法是ngx_epoll_process_events(其具体代码见http://blog.csdn.net/xiajun07061225/article/details/9250341)。当falgs标志位含有nGX_POST_EVENTS时是不会立即调用事件的handler回调方法的,代码如下所示:
- //事件需要延后处理
- if (flags & NGX_POST_EVENTS) {
- /*如果要在post队列中延后处理该事件,首先要判断它是新连接时间还是普通事件
- 以确定是把它加入到ngx_posted_accept_events队列或者ngx_posted_events队列中。*/
- queue = (ngx_event_t **) (rev->accept ?
- &ngx_posted_accept_events : &ngx_posted_events);
- //将该事件添加到相应的延后队列中
- ngx_locked_post_event(rev, queue);
- } else {
- //立即调用事件回调方法来处理这个事件
- rev->handler(rev);
- }
- ngx_int_t
- ngx_trylock_accept_mutex(ngx_cycle_t *cycle)
- {
- //尝试获取accept_mutex锁。注意是非阻塞的。返回1表示成功,返回0表示失败。
- //ngx_accept_mutex 定义:ngx_shmtx_t ngx_accept_mutex;(ngx_shmtx_t是Nginx封装的互斥锁,用于经常间同步)
- if (ngx_shmtx_trylock(&ngx_accept_mutex)) {
- ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
- "accept mutex locked");
- //获取到锁,但是标志位ngx_accept_mutex_held为1,表示当前进程已经获取到锁了,立即返回。
- if (ngx_accept_mutex_held
- && ngx_accept_events == 0
- && !(ngx_event_flags & NGX_USE_RTSIG_EVENT))
- {
- return NGX_OK;
- }
- //将所有监听事件添加到当前的epoll等事件驱动模块中
- if (ngx_enable_accept_events(cycle) == NGX_ERROR) {
- //添加失败,必须释放互斥锁
- ngx_shmtx_unlock(&ngx_accept_mutex);
- return NGX_ERROR;
- }
- //标志位设置
- ngx_accept_events = 0;
- //当前进程已经获取到锁
- ngx_accept_mutex_held = 1;
- return NGX_OK;
- }
- ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
- "accept mutex lock failed: %ui", ngx_accept_mutex_held);
- //获取锁失败,但是标志位ngx_accept_mutex_held仍然为1,即当前进程还处在获取到锁的状态,这是不正确的
- if (ngx_accept_mutex_held) {
- //将所有监听事件从事件驱动模块中移除
- if (ngx_disable_accept_events(cycle) == NGX_ERROR) {
- return NGX_ERROR;
- }
- //没有获取到锁,设置标志位
- ngx_accept_mutex_held = 0;
- }
- return NGX_OK;
- }
Nginx学习之一-惊群现象的更多相关文章
- Nginx中的惊群现象解决方法
*什么是惊群现象?Nginx中用了什么方法来避免这种问题的发生?本篇就解决这两个问题...→_→* 惊群现象的定义与危害 在Nginx中,每一个worker进程都是由master进程fork出来的.m ...
- pthread_cond_signal惊群现象
1.如下代码所示: #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include < ...
- Redis 利用锁机制来防止缓存过期产生的惊群现象-转载自 http://my.oschina.net/u/1156660/blog/360552
首先,所谓的缓存过期引起的“惊群”现象是指,在大并发情况下,我们通常会用缓存来给数据库分压,但是会有这么一种情况发生,那就是在一定时间 内生成大量的缓存,然后当缓存到期之后又有大量的缓存失效,导致后端 ...
- NGINX怎样处理惊群的
写在前面 写NGINX系列的随笔,一来总结学到的东西,二来记录下疑惑的地方,在接下来的学习过程中去解决疑惑. 也希望同样对NGINX感兴趣的朋友能够解答我的疑惑,或者共同探讨研究. 整个NGINX系列 ...
- Accept 惊群现象测试perl脚本
$uname -a Linux debian-11-34 3.16.0-4-amd64 #1 SMP Debian 3.16.7-ckt9-3~deb8u1 (2015-04-24) x86_64 G ...
- Nginx模型 & 惊群问题
这篇写的不错 http://www.cnblogs.com/linguoguo/p/5511293.html Nginx为啥性能高-多进程异步IO模型 1. 对于每个worker进程来说,独立的进程, ...
- Linux网络编程“惊群”问题总结
1.前言 我从事Linux系统下网络开发将近4年了,经常还是遇到一些问题,只是知其然而不知其所以然,有时候和其他人交流,搞得非常尴尬.如今计算机都是多核了,网络编程框架也逐步丰富多了,我所知道的有多进 ...
- Nginx学习笔记(一) Nginx架构
Nginx架构 Nginx全程是什么? Nginx ("engine x") 是一个高性能的 HTTP 和 反向代理 服务器,也是一个 IMAP/POP3/SMTP 代理服务器. ...
- epoll 惊群处理
#include <sys/types.h> #include <sys/socket.h> #include <sys/epoll.h> #include < ...
随机推荐
- clog,cout,cerr 输出机制
clog:控制输出,使其输出到一个缓冲区,这个缓冲区关联着定义在 <cstdio> 的 stderr. cerr:强制输出刷新,没有缓冲区. cout:控制输出,使其输出到一个缓冲区,这个 ...
- HDU 6196 happy happy happy 爆搜加剪枝
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6196 题意:给你长度为n的序列,爸爸和儿子玩一个游戏,儿子先手,儿子每次都选择最左边与最右边最大的那个 ...
- mysql -> 简介&体系结构_01
数据库简介 数据库,简而言之可视为电子化的文件柜——存储电子文件的处所,用户可以对文件中的数据运行新增.截取.更新.删除等操作. 所谓“数据库”系以一定方式储存在一起.能予多个用户共享.具有尽可能小的 ...
- Little C Loves 3 I
CF#511 div2 A 现场掉分赛(翻车),就是这道题被叉了...qwq 其实就是一道水题: 因为CF有spj,所以直接构建特殊情况就行了. 当 n 是3的倍数的时候,显然 1,1,(n-2) 显 ...
- Java - 利用StringEscapeUtils对字符串进行各种转义与反转义
来自:http://blog.csdn.net/chenleixing/article/details/43456987 --------------------------------------- ...
- 压力测试随笔之:JMeter,LoadRunner 相得益彰
做压力测试,我喜欢先写 JMeter 脚本,功能测通以后再翻译成 LoadRunner 脚本,最后用 LoadRunner 完成压测.也许我是 Java 出身吧,对 JMeter 总是有一种亲切感用着 ...
- (转载)使用SQL-Server创建一个银行数据管理系统Ⅰ
首先,要创建一个完整的数据管理系统,不是一蹴而就的,一定要要一步一步的来,不断完善,最终方能达到自己想要的结果,所以我在这里也是一点一点分步来做的. 创建数据库,数据库属性在这里用的是默认(不推荐使用 ...
- poj 2369(置换群)
Permutations Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 3041 Accepted: 1641 Desc ...
- Spring Boot整合JPA、Redis和Swagger2
好久没有总结了,最近也一直在学习.今天就把spring boot与其它技术的整合做个小总结,主要是jpa.redis和swagger2.公司里有用到这些,整合起来也很简单. 首先,新建一个Spring ...
- Jquery Datatable自动生成序号
公司项目里,使用的是jquerydatatable框架来展示数据的,在使用的时候遇到一个问题,就是要自动生成序号,且在分页的时候,下一页的序号紧跟着前一页的序号,下面是代码: "fnDraw ...