调度算法
- 平滑的加权轮询算法
每个server都配有三个参数,即weight、current_weight、effective_weight。
weight是配置中指定的,固定不变
current_weight是实时权重,每次选择server时,都会重新计算一次,计算方法为current_weight += effective_weight
effective_weight也是会变化的。其初始值为weight,当server返回失败时减1,成功时加1,但最大不超过weight
每次选current_weight最大的为最终的server,选完之后,需要更新被选中机器的current_weight,即减去总得weight和
平滑的加权轮询算法,除了可以让请求按照机器权重调度,还能避免同一个请求连续发多次时打到同一个机器,详情:https://github.com/phusion/nginx/commit/27e94984486058d73157038f7950a0a36ecc6e35
锁
自旋锁
nginx的自旋锁依赖于原子变量操作
为了降低进行CAS操作的频率。进行了让cpu进行睡眠的操作,而且睡眠时长以2的幂增加
当达到最大睡眠时长,仍然没有获取到锁时(即CAS操作未成功),则让出cpu的使用权
代码实现在src/core/ngx_spinlock.c
应用场景:占用锁的时长短,并且当第一次未获取到锁时,下次尝试时不希望重新被调度
读写锁
依赖于原子变量的操作
写锁在同一时刻只能由一个线程获得。获取时有个2048的pause循环,当pause了2048次后仍然没有获取到,则主动让出cpu
读锁同一时刻可能由多个线程访问。只不过是在原子变量上+1。当然了,获取读锁时仍然要保证同一时刻只能有一个线程修改原子变量
内存池
nginx中也使用了内存池。但其使用比较特殊
以请求为单位。内存池上的内存只有在请求结束时才会释放
分大小内存。用两个链表管理。其中大内存是可以在请求结束前主动释放的
大小内存的分界点是:可以认为是4K(其实比4k小一点)
大内存除了有可存放数据的空间外,还会额外分配一个管理结构体(其实就两个指针,一个指针指向下一个大内存的管理结构体,另一个指针指向实际存放数据的起始处),这个结构体是维护在小内存的链表上的
内存默认以16个字节为对齐单位,但提供了一个接口可供用户选择
代码在src/core/ngx_palloc.c,500行左右
使用注意项:
不要陷入循环,不断的申请内存,会导致内存耗尽
内存大内存后,如果不再使用,可以调用ngx_pfree主动释放,减少请求占用内存时长。但是其管理结构体所占的内存仍然没有释放(存放在小内存的链表上)