应用案例——高并发 WEB 服务器队列的应用
在高并发 HTTP 反向代理服务器 Nginx 中,存在着一个跟性能息息相关的模块 - 文件缓存。
经常访问到的文件会被 nginx 从磁盘缓存到内存,这样可以极大的提高 Nginx 的并发能力,不过因为内存的限制,当缓存的文件数达到一定程度的时候就会采取淘汰机制,优先淘汰进入时间比较久或是最近访问很少(LRU)的队列文件。
具体实现方案:
1. 使用双向循环队列保存缓存的文件节点,这样可以实现多种淘汰策略:
比如:如果采用淘汰进入时间比较久的策略,就可以使用队列的特性,先进先出
如果要采用按照 LRU,就遍历链表,找到节点删除。
源码实现:
nginx_queue.h
1 #ifndef _NGX_QUEUE_H_INCLUDED_ 2 #define _NGX_QUEUE_H_INCLUDED_ 3 typedef struct ngx_queue_s ngx_queue_t; 4 5 struct ngx_queue_s 6 { 7 ngx_queue_t* prev; 8 ngx_queue_t* next; 9 }; 10 11 #define ngx_queue_init(q) \ 12 (q)->prev = q; \ 13 (q)->next = q 14 #define ngx_queue_empty(h) \ 15 (h == (h)->prev) 16 #define ngx_queue_insert_head(h, x)\ 17 (x)->next = (h)->next; \ 18 (x)->next->prev = x; \ 19 (x)->prev = h; \ 20 (h)->next = x 21 #define ngx_queue_insert_after ngx_queue_insert_head 22 #define ngx_queue_insert_tail(h, x)\ 23 (x)->prev = (h)->prev; \ 24 (x)->prev->next = x; \ 25 (x)->next = h; \ 26 (h)->prev = x 27 #define ngx_queue_head(h) \ 28 (h)->next 29 #define ngx_queue_last(h) \ 30 (h)->prev 31 #define ngx_queue_sentinel(h) \ 32 (h) 33 #define ngx_queue_next(q) \ 34 (q)->next 35 #define ngx_queue_prev(q) \ 36 (q)->prev 37 #define ngx_queue_remove(x) \ 38 (x)->next->prev = (x)->prev; \ 39 (x)->prev->next = (x)->next 40 #define ngx_queue_data(q, type, link) 41 (type*)((char*)q - offsetof(type, link)) 42 #endif
Nginx_双向循环队列.cpp
1 #include <Windows.h> 2 #include <stdlib.h> 3 #include <iostream> 4 #include "nginx_queue.h" 5 #include <time.h> 6 7 using namespace std; 8 9 typedef struct ngx_cached_open_file_s 10 { 11 //其它属性省略... 12 int fd; 13 ngx_queue_t queue; 14 }ngx_cached_file_t; 15 16 typedef struct 17 { 18 //其它属性省略... 19 ngx_queue_t expire_queue; 20 //其它属性省略... 21 } ngx_open_file_cache_t; 22 23 int main(void) 24 { 25 ngx_open_file_cache_t* cache = new ngx_open_file_cache_t; 26 ngx_queue_t* q; 27 ngx_queue_init(&cache->expire_queue); 28 29 //1. 模拟文件模块,增加打开的文件到缓存中 30 for (int i = 0; i < 10; i++) 31 { 32 ngx_cached_file_t* e = new ngx_cached_file_t; 33 e->fd = i; 34 ngx_queue_insert_head(&cache->expire_queue, &e->queue); 35 } 36 37 //遍历队列 38 for (q = cache->expire_queue.next;q != ngx_queue_sentinel(&cache->expire_queue); q = q->next) 39 { 40 printf("队列中的元素:%d\n", (ngx_queue_data(q, ngx_cached_file_t, queue))->fd); 41 } 42 43 //模拟缓存的文件到期,执行出列操作 44 while (!ngx_queue_empty(&cache->expire_queue)) 45 { 46 q = ngx_queue_last(&cache->expire_queue); 47 ngx_cached_file_t* cached_file = ngx_queue_data(q, ngx_cached_file_t, queue); 48 printf("出队列中的元素:%d\n", cached_file->fd); 49 ngx_queue_remove(q); 50 delete(cached_file); 51 } 52 system("pause"); 53 return 0; 54 }
==================================================================================================================