`
bollaxu
  • 浏览: 219493 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

Nginx Proxy Cache的slab page内存缓存机制

阅读更多

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

typedef struct {
	ngx_atomic_t		lock;	//mutex的锁
	size_t			min_size;	//内存缓存obj最小的大小,一般是1个byte
	size_t			min_shift;	//slab pool以shift来比较和计算所需分配的obj大小、
								//每个缓存页能够容纳obj个数以及所分配的页在缓存空间的位置
	ngx_slab_page_t	*pages;		//slab page空间的开头
	ngx_slab_page_t	free;		//如果要分配新的页,就从free.next开始
	u_char			*start;		//实际缓存obj的空间的开头
	u_char			*end;		//整个缓存空间的结尾
	ngx_shmtx_t		mutex;		//互斥锁
	u_char			*log_ctx;
	u_char			zero;
	void			*data;		
	void			*addr;		//指向ngx_slab_pool_t的开头
} ngx_slab_pool_t;
 
struct ngx_slab_page_s {
	uintptr_t		slab;	//多种情况,多个用途
							//当需要分配新的页的时候,slab表示剩余页的数量
							//当分配某些大小的obj的时候(一个缓存页存放多个obj),slab表
							//示被分配的缓存的占用情况(是否空闲),以bit位来表示
	ngx_slab_page_t	*next;	//在分配较小obj的时候,next指向slab page在pool->pages的位置
	uintptr_t		prev;
};
 

注意,在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[i].slab = 0;
		slots[i].next = &slots[i];
		slots[i].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图例:

 

 

2. 小物体bitmap图例:


 

3. slab page和缓存页的映射:




  • 大小: 71 KB
  • 大小: 50.9 KB
  • 大小: 42.1 KB
  • 大小: 29.8 KB
  • 大小: 96.9 KB
0
1
分享到:
评论

相关推荐

    Nginx启用proxy_cache缓存的方法

    proxy_cache机制允许Nginx将从后端服务器获得的静态内容缓存到磁盘上,当相同请求再次发生时,可以直接从磁盘缓存中提供数据,而无需每次都向后端服务器获取。 proxy_cache的基本用法是在Nginx的配置文件中进行设置...

    nginx静态文件缓存的解决方案1

    这里,`proxy_cache_path` 指定了缓存存储的路径,`levels` 参数定义了缓存目录的层级,`keys_zone` 设置了一个名为 `cache_one` 的内存缓存区域,大小为 200MB,`inactive` 参数指定了1天内未被访问的缓存将被自动...

    nginx slab内存管理精简源码及注释

    的缓存与对齐机制,slab内存管理中一些设计相当巧妙的地方,也有一些地方个人感觉设计 不是很完美,或许是作为nginx设计综合考虑的结果。 nginx slab实现中的一大特色就是大量的位操作,这部分操作很多是与slot分级...

    nginx proxy_cache批量清除缓存的脚本介绍

    Nginx是一款高性能的HTTP和反向代理服务器,也是一个IMAP/POP3/SMTP服务器。...不过在运行脚本之前,了解nginxproxy_cache的工作机制和脚本的执行逻辑是很有必要的,以确保可以正确处理任何可能出现的问题。

    nginx系列(十)nginx缓存代理proxy_cacahe和CDN实现的原理

    “nginx系列(十)nginx缓存代理proxy_cache和CDN实现的原理”这个标题揭示了本文将探讨的主题,主要集中在两个关键点上:一是Nginx的缓存代理机制proxy_cache,二是如何利用Nginx实现内容分发网络(CDN)的功能。...

    nginx_cache_purge.zip

    《Nginx Cache Purge:高效管理Web缓存的利器》 在当今互联网环境中,Web服务器的性能优化至关重要,而缓存技术则是其中的关键一环。Nginx,以其高性能、稳定性以及模块化的特性,成为了许多网站首选的反向代理和...

    Nginx之proxy_redirect使用详解

    Nginx的强大功能还包括负载均衡、缓存管理、SSL/TLS支持等,proxy_redirect是我们在进行复杂的Web架构设计时经常用到的一个小工具。掌握如何正确和高效地使用proxy_redirect,能够帮助我们在保证Web应用安全和高效的...

    Nginx反向代理和proxy

    此文比较详细讲述了Nginx与proxy共同搭建反向代理服务的配置方法

    fastdfs + nginx + cache 集群安装配置 安装包

    fastdfs-5.05.tar.gz : FastDFS安装主文件包 libfastcommon-master.zip: FastDFS文件系统依赖包 nginx-1.8.1.tar.gz:nginx安装包 fastdfs-nginx-module_v1.16.tar.gz: nginx下...ngx_cache_purge-2.1.tar.gz:缓存

    linux-一个用于nginxproxy的轻量级协同容器它能够自动创建更新LetsEncrypt证书

    标题中的“Linux-一个用于nginx-proxy的轻量级协同容器它能够自动创建更新LetsEncrypt证书”指的是一个专门设计用于nginx-proxy的轻量级Docker容器,它的主要功能是自动化处理Let's Encrypt证书的申请和更新过程。...

    nginx缓存清除插件ngx_cache_purge.zip

    ngx_cache_purge 是 nginx 模块,此模块可以清理 nginx 的 FastCGI、proxy、 SCGI 和 uWSGI 的缓存。配置指令(相同位置语法)fastcgi_cache_purgesyntax: fastcgi_cache_purge on|off|&lt;method&gt; [from all|&lt;ip&gt; [.....

    nginx-cache-control:没有缓存清除模块的 Nginx 缓存控制插件

    nginx-缓存控制没有缓存清除模块的 Nginx 缓存控制插件部分代码是基于其他 Nginx Cache Plugins 的代码,但这是设计为简单、轻量级的实现== 具体.... == Mark Jaquith 提出了使用强制动态页面加载的标头的基本设计,...

    Nginx转发到动态域名的proxy.conf

    Nginx在vhost里的配置站点,通过proxy转发到动态域名的具体配置。 反向代理,动态域名 ,Proxy

    docker-letsencrypt-nginx-proxy-companion-examples, 结合 Docker gen和 letsencrypt Nginx 代理伙伴的示例.zip

    docker-letsencrypt-nginx-proxy-companion-examples, 结合 Docker gen和 letsencrypt Nginx 代理伙伴的示例 docker-letsencrypt-nginx-proxy-companion-examples这个库是使用 nginx代理插件, docker gen和 docker-...

    nginx-proxy-manager中的Nginx配置

    **Nginx配置详解——以Nginx Proxy Manager为例** Nginx Proxy Manager是一款基于Nginx构建的网络代理管理工具,它允许用户通过友好的Web界面轻松地配置和管理Nginx反向代理设置。在深入理解Nginx Proxy Manager的...

    Nginx Slab算法研究1

    Nginx Slab算法是一种内存管理机制,设计用于简化Nginx服务器的内存管理,以降低内存资源管理的复杂度。Nginx采用共享内存的方式来实现各进程间的数据共享,而对这部分共享内存的管理则依赖于Slab算法。Slab算法的...

Global site tag (gtag.js) - Google Analytics