设为首页 收藏本站
查看: 1062|回复: 0

[经验分享] Nginx Proxy Cache的slab page内存缓存机制

[复制链接]

尚未签到

发表于 2016-12-28 08:09:57 | 显示全部楼层 |阅读模式
  Nginx的内存缓存是通过slab pool来实现的,但是目前Nginx代码没有对http响应进行内存缓存。比如作为反向代理服务器时向后端获取的文件也只是缓存在磁盘里,而内存只是用来做索引。不过Nginx已经提供了内存缓存功能的函数,所以如果在其他地方有需要使用内存缓存的话,也可以通过修改代码来实现(当然,也可以用memory disk来实现内存缓存)。在Nginx的内存缓存机制中,最重要的结构就是ngx_slab_pool_t,里面存放了包括内存缓存的空间使用情况、位置映射以及缓存空间本身的几乎所有信息。先来看一下ngx_slab_pool_t吧。

typedef struct {
ngx_atomic_tlock;//mutex的锁
size_tmin_size;//内存缓存obj最小的大小,一般是1个byte
size_tmin_shift;//slab pool以shift来比较和计算所需分配的obj大小、
//每个缓存页能够容纳obj个数以及所分配的页在缓存空间的位置
ngx_slab_page_t*pages;//slab page空间的开头
ngx_slab_page_tfree;//如果要分配新的页,就从free.next开始
u_char*start;//实际缓存obj的空间的开头
u_char*end;//整个缓存空间的结尾
ngx_shmtx_tmutex;//互斥锁
u_char*log_ctx;
u_charzero;
void*data;
void*addr;//指向ngx_slab_pool_t的开头
} ngx_slab_pool_t;
 
struct ngx_slab_page_s {
uintptr_tslab;//多种情况,多个用途
//当需要分配新的页的时候,slab表示剩余页的数量
//当分配某些大小的obj的时候(一个缓存页存放多个obj),slab表
//示被分配的缓存的占用情况(是否空闲),以bit位来表示
ngx_slab_page_t*next;//在分配较小obj的时候,next指向slab page在pool->pages的位置
uintptr_tprev;
};
   注意,在ngx_slab_pool_t里面有两种类型的slab page,虽然都是ngx_slab_page_t定义的结构,但是功能不尽相同。一种是slots,用来表示存放较小obj的内存块(如果页大小是4096B,则是<2048B的obj,即小于1/2页),另一种来表示所要分配的空间在缓存区的位置。Nginx把缓存obj分成大的(>=2048B)和小的(<2048B)。每次给大的obj分配一整个页,而把多个小obj存放在一个页中间,用bitmap等方法来表示其占用情况。而小的obj又分为3种:小于128B,等于128B,大于128B且小于2048B。其中小于128B的obj需要在实际缓冲区额外分配bitmap空间来表示内存使用情况(因为slab成员只有4个byte即32bit,一个缓存页4KB可以存放的obj超过32个,所以不能用slab来表示),这样会造成一定的空间损失。等于或大于128B的obj因为可以用一个32bit的整形来表示其状态,所以就可以直接用slab成员。每次分配的空间是2^n,最小是8byte,8,16,32,64,128,256,512,1024,2048。小于2^i且大于2^(i-1)的obj会被分配一个2^i的空间,比如56byte的obj就会分配一个64byte的空间。
 
先看一下初始化slab pool的函数,在ngx_init_cycle()中调用的ngx_init_zone_pool()中被调用

void ngx_slab_init(ngx_slab_pool_t *pool)
{
//假设每个page是4KB
//设置ngx_slab_max_size = 2048B。如果一个页要存放多个obj,则obj size要小于这个数值
//设置ngx_slab_exact_size = 128B。分界是否要在缓存区分配额外空间给bitmap
//ngx_slab_exact_shift = 7,即128的位表示
//...
//pool->min_shift = 3
//最小分配的空间是8byte
pool->min_size = 1 << pool->min_shift;
//这些slab page是给大小为8,16,32,64,128,256,512,1024,2048byte的内存块
//这些slab page的位置是在pool->pages的前面
//初始化
p = (u_char *) pool + sizeof(ngx_slab_pool_t);
slots = (ngx_slab_page_t *) p;
n = ngx_pagesize_shift - pool->min_shift;
for (i = 0; i < n; i++) {
slots.slab = 0;
slots.next = &slots;
slots.prev = 0;
}
//跳过上面那些slab page
p += n * sizeof(ngx_slab_page_t);
//**计算这个空间总共可以分配的缓存页(4KB)的数量,每个页的overhead是一个slab page的大小
//**这儿的overhead还不包括之后给<128B物体分配的bitmap的损耗
pages = (ngx_uint_t) (size / (ngx_pagesize + sizeof(ngx_slab_page_t)));
//把每个缓存页对应的slab page归0
ngx_memzero(p, pages * sizeof(ngx_slab_page_t));
//pool->pages指向slab page的头
pool->pages = (ngx_slab_page_t *) p;
//初始化free,free.next是下次分配页时候的入口
pool->free.prev = 0;
pool->free.next = (ngx_slab_page_t *) p;
//更新第一个slab page的状态,这儿slab成员记录了整个缓存区的页数目
pool->pages->slab = pages;
pool->pages->next = &pool->free;
pool->pages->prev = (uintptr_t) &pool->free;
//实际缓存区(页)的开头,对齐
pool->start = (u_char *)ngx_align_ptr((uintptr_t) p + pages * sizeof(ngx_slab_page_t), ngx_pagesize);
//根据实际缓存区的开始和结尾再次更新内存页的数目
m = pages - (pool->end - pool->start) / ngx_pagesize;
if (m > 0) {
pages -= m;
pool->pages->slab = pages;
}
//...
}
 
下面来看一下需要分配缓存空间时调用的函数,由于是共享内存,所以在进程间需要用锁来保持同步

void * ngx_slab_alloc(ngx_slab_pool_t *pool, size_t size)
{
//spinlock获取锁
ngx_shmtx_lock(&pool->mutex);
p = ngx_slab_alloc_locked(pool, size);
//解锁
ngx_shmtx_unlock(&pool->mutex);
return p;
}
 
//返回的值是所要分配的空间在内存缓存区的位置
void * ngx_slab_alloc_locked(ngx_slab_pool_t *pool, size_t size)
{
//这儿假设page_size是4KB
//如果是large obj, size >= 2048B
if(...){
//分配1个或多个内存页
page = ngx_slab_alloc_pages(pool, (size + ngx_pagesize - 1) >> ngx_pagesize_shift);
//返回指向内存缓存页的位置,这儿slab page的位置与所要返回的缓存页的位置是对应的
p = (page - pool->pages) << ngx_pagesize_shift;
p += (uintptr_t) pool->start;
//done, return p
//...
}
//较小的obj, size < 2048B
//根据需要分配的size来确定在slots的位置,每个slot存放一种大小的obj的集合,如slots[0]表示8byte的空间,slots[3]表示64byte的空间
//如果obj过小(<1B),slot的位置是1B空间的位置,即最小分配1B
//...
//如果之前已经有此类大小obj且那个已经分配的内存缓存页还未满
if(...){
//小obj,size < 128B,更新内存缓存页中的bitmap,并返回待分配的空间在缓存的位置
//...
//size == 128B,因为一个页可以放32个,用slab page的slab成员来标注每块内存的占用情况,不需要另外在内存缓存区分配bitmap,并返回待分配的空间在缓存的位置
//...
//size > 128B,也是更新slab page的slab成员,但是需要预先设置slab的部分bit,因为一个页的obj数量小于32个,并返回待分配的空间在缓存的位置
//...
}
//此前没有此类大小的obj或者之前的页已经满了,分配一个新的页,page是新的页相应的slab page
page = ngx_slab_alloc_pages(pool, 1);
//小obj,size < 128B,更新内存缓存页中的bitmap,并返回待分配的空间在缓存的位置(跳过bitmap的位置)
//...
//size == 128B,更新slab page的slab成员(即页中的每个相同大小空间的占用情况),并返回待分配的空间在缓存的位置
//...
//size > 128B,更新slab page的slab成员(即页中的每个相同大小空间的占用情况),并返回待分配的空间在缓存的位置
//...
}
 
//返回一个slab page,这个slab page之后会被用来确定所需分配的空间在内存缓存的位置
static ngx_slab_page_t * ngx_slab_alloc_pages(...)
{
//从pool->free.next开始,每次取(slab page) page = page->next
for(;;){
//本个slab page剩下的缓存页数目>=需要分配的缓存页数目N
if(...){
//更新从本个slab page开始往下第N个slab page的缓存页数目为本个slab page数目减去N
//N为需要分配的缓存页数目
//更新pool->free.next,下次从第N个slab page开始
//...
//更新被分配的page slab中的第一个的slab成员,即页的个数和占用情况
page->slab = pages | NGX_SLAB_PAGE_START;
//...
//如果分配的页数N>1,更新后面page slab的slab成员为NGX_SLAB_PAGE_BUSY
//...
return page;
}
}
//没有找到空余的页
return NULL;
}
  附图
  1. ngx_slab_alloc_pages图例:
DSC0000.png

  2. 小物体bitmap图例:
  
DSC0001.png
  3. slab page和缓存页的映射:
  
DSC0002.png
  

DSC0003.png

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.iyunv.com/thread-320360-1-1.html 上篇帖子: nginx中配置php fastcgi组解决莫名其妙的502 Bad Gateway错误 下篇帖子: (转载)(张宴:Nginx 0.8.x + PHP 5.2.13(FastCGI))
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表