欢迎转载,转载请注明出处
http://blog.csdn.net/yankai0219/article/details/8453317
文章内容 0.序
1.Nginx锁的核心数据结构
2.分析文件锁
|
0.序
强烈推荐的文章是
nginx中锁的设计以及惊群的处理,本文只是对文章中的内容进行了部分总结和部分解释。
Nginx之所以要采用Accept互斥锁就是为了避免惊群现象。
所谓惊群现象:指一个fd的事件被触发后,等候这个fd的所有线程/进程都被唤醒。虽然都被唤醒,但是只有一个会去响应。
Nginx使用的锁分为两种情况:1)一种是支持原子操作的情况,由NGX_HAVE_ATOMIC_OPS这个宏来进行控制的。2)一种是不支持原子操作的情况,使用文件锁来实现。
用户空间进程间锁的实现的原理很简单,就是弄出一个让所有进程共享的东西,比如mmap的内容或文件,然后通过这个东西来控制进程的互斥。
1.Nginx锁的核心数据结构
Nginx中锁的核心数据结构,也就是Nginx使用哪个变量来控制进程的行为。
|
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; } |