您的位置:首页 > 运维架构 > Nginx

文章9:Nginx accept互斥锁

2015-07-31 02:24 537 查看
欢迎转载,转载请注明出处/article/1389062.html

文章内容

0.序
1.Nginx锁的核心数据结构
2.分析文件锁
0.序
强烈推荐的文章是nginx中锁的设计以及惊群的处理,本文只是对文章中的内容进行了部分总结和部分解释。
Nginx之所以要采用Accept互斥锁就是为了避免惊群现象。

所谓惊群现象:指一个fd的事件被触发后,等候这个fd的所有线程/进程都被唤醒。虽然都被唤醒,但是只有一个会去响应。

Nginx使用的锁分为两种情况:1)一种是支持原子操作的情况,由NGX_H***E_ATOMIC_OPS这个宏来进行控制的。2)一种是不支持原子操作的情况,使用文件锁来实现。
用户空间进程间锁的实现的原理很简单,就是弄出一个让所有进程共享的东西,比如mmap的内容或文件,然后通过这个东西来控制进程的互斥。
1.Nginx锁的核心数据结构
Nginx中锁的核心数据结构,也就是Nginx使用哪个变量来控制进程的行为。

typedef struct {

#if (NGX_H***E_ATOMIC_OPS)

ngx_atomic_t *lock; //原子操作

#else

ngx_fd_t fd; //fd表示进程间共享的文件句柄

u_char *name; //name表示文件名

#endif

} ngx_shmtx_t;

2.分析文件锁
由于本人对原子操作不了解,因此只能分析一下文件锁。Nginx使用文件锁,实际上就是APUE 14.3 记录锁中内容。
上锁:ngx_trylock_accept_mutex----------------->ngx_shmtx_trylock--------------->ngx_trylock_fd
删除锁:ngx_shmtx_unlock------------------------->ngx_unlock_fd
ngx_int_t

ngx_trylock_accept_mutex(ngx_cycle_t *cycle)

{

/*ngx_shmtx_trylock通过fcntl对ngx_accept_mutex中fd成员变量上锁,锁定整个文件*/
if (ngx_shmtx_trylock(&ngx_accept_mutex)) {/*锁定成功*/



ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0,

"accept mutex locked");

/*ngx_accept_mutex_held 获得锁的标志,如果本来已经获得锁,则直接返回OK*/

if (ngx_accept_mutex_held

&& ngx_accept_events == 0

&& !(ngx_event_flags & NGX_USE_RTSIG_EVENT))

{

return NGX_OK;

}

/*ngx_enable_accept_events将cycle->listening中的端口号都加到epoll事件中。把进程对应的监听socket 放入到epoll中进行监听,这样只有该进程能监听到accept操作。*/
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);

/*//如果我们前面已经获得了锁,然后这次获得锁失败,则说明当前的listen句柄已经被其他的进程锁监听,因此此时需要从epoll中移出调已经注册的listen句柄。这样就很好的控制了子进程的负载均衡 */
if (ngx_accept_mutex_held) {

/*ngx_disable_accept_events将cycle->listening中的端口号从epoll事件中删除*/
if (ngx_disable_accept_events(cycle) == NGX_ERROR) {

return NGX_ERROR;

}

ngx_accept_mutex_held = 0;

}

return NGX_OK;

}
ngx_shmtx_trylock(ngx_shmtx_t *mtx){

ngx_err_t err;

err = ngx_trylock_fd(mtx->fd);

if (err == 0) {

return 1;

}

}
ngx_err_t

ngx_trylock_fd(ngx_fd_t fd)

{

struct flock fl;

ngx_memzero(&fl, sizeof(struct flock));

fl.l_type = F_WRLCK;

fl.l_whence = SEEK_SET;

if (fcntl(fd, F_SETLK, &fl) == -1) {

return ngx_errno;

}

return 0;

}
删除锁的操作

void

ngx_shmtx_unlock(ngx_shmtx_t *mtx)

{

ngx_err_t err;

err = ngx_unlock_fd(mtx->fd);

if (err == 0) {

return;

}

ngx_log_abort(err, ngx_unlock_fd_n " %s failed", mtx->name);

}
ngx_err_t

ngx_unlock_fd(ngx_fd_t fd)

{

struct flock fl;

ngx_memzero(&fl, sizeof(struct flock));

fl.l_type = F_UNLCK;

fl.l_whence = SEEK_SET;

if (fcntl(fd, F_SETLK, &fl) == -1) {

return ngx_errno;

}

return 0;

}
版权声明:本文为博主原创文章,未经博主允许不得转载。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: