【原创】自己动手写缓存系统(tmcache)

tmcache是一款简易缓存系统,采用哈希表存储数据,并支持基本的缓存操作如set/get/delete等。它通过线程处理并发连接,并利用概率算法不定期清理过期数据。

自己动手写缓存系统 - tmcache

作者:heiyeluren
时间:2008-10-24
博客:
http://blog.youkuaiyun.com/heiyeshuwu

【 原理介绍 】

tmcache 大致就是一个类似于Memcache的缓存服务器,用过的应该都大致了解它的执行过程,为了便于理解,我简单描述一下。

发送请求过程:
客户端(PHP/Java/C++) --> 缓存服务器 --> 内存(共享内存)

接收数据过程:
内存(共享内存) --> 缓存服务器 --> 客户端

大致描述就是:客户端(任何能够访问Socket的客户端语言或工具) 访问缓存服务器的指定端口,进行 存储/读取/删除 数据的操作,缓存服务器接收到指令后进行内存操作,操作结束后回写结果给客户端。所以缓存服务器端包含这些模块:Socket通信、协议解析、数据存储、数据有效期控制

以下代码就是按照这些模块来进行描述的,下面的代码取自于 tmcache - TieMa(Tiny&Mini) Memory Cache,tmcache 目前支持的功能包括:

* Based memory data storage
* Compatible memcached communication protocol
* Few operation interface, The use of simple
* Support custom port,max_clients,memory use control


tmcache下载(Windows版可直接运行):

Windows版本:http://heiyeluren.googlecode.com/files/tmcache-1.0.0_alpha-win32.zip
Unix/Linux版: http://heiyeluren.googlecode.com/files/tmcache-1.0.0_alpha.tar.gz

【 系统实现 】

一、通信协议处理模块

这个主要是包含一方面是监听处理Socket,tmcache里主要是依靠 init_server_listen() 函数进行监听操作,同时并发接受连接是程序里很重要的一块,可以选择方式有 select/poll 多路IO的方式,epoll/kqueue 的事件方式,另外还可以使用线程(thread)的方式,tmcache为了兼容性和简单起见,使用了线程的方式。


线程相关核心处理代码:

  1. voidtm_thread(intserversock,unsignedintmax_client){
  2. intclientsock,*arg;
  3. structsockaddr_inclient_addr;
  4. charcurrtime[32];
  5. unsignedclientlen;
  6. pthread_attr_tthread_attr;
  7. void*thread_result;
  8. /*Settingpthreadattribute*/
  9. pthread_attr_init(&thread_attr);
  10. pthread_attr_setdetachstate(&thread_attr,PTHREAD_CREATE_DETACHED);
  11. /*Rununtilcancelled*/
  12. while(1){
  13. pthread_tthread;
  14. unsignedintclientlen=sizeof(client_addr);
  15. memset(currtime,0,sizeof(currtime));
  16. getdate(currtime);
  17. /*Waitforclientconnection*/
  18. if((clientsock=accept(serversock,(structsockaddr*)&client_addr,&clientlen))<0){
  19. die("Failedtoacceptclientconnection");
  20. }
  21. /*Usethreadprocessnewconnection*/
  22. arg=&clientsock;
  23. if(pthread_create(thread,&thread_attr,tm_thread_callback,(void*)arg)!=0){
  24. die("Createnewthreadfailed");
  25. }
  26. }
  27. /*Destorypthreadattribute*/
  28. (void)pthread_attr_destroy(&thread_attr);
  29. }


协议处理是很核心的,主要是包括存储数据的 set/add/replace/append,还有提取数据的 get/gets,删除数据的 delete/remove,获取状态 stats/stat 等指令的各种操作,主要操作处理函数是 proc_request(),它负责协议的分析很调用相关的接口来进行处理。


二、数据处理模块

这是数据存储处理的核心,主要是通过使用哈希表来存储数据,使用队列来记录数据的存储顺序并且为内存不够用时的处理数据结构,还有使用概率处理算法来不定期清除过期数据等等。

1. 哈希表数据存储

数据是采用哈希表的存储方式,存储速度简单快速,算法效率是 O(1),非常适合这种 Key => Value 的存储场合,核心的哈希算法是经典的Times33算法:


  1. unsignedtm_hash(constchar*str,unsignedtable_size){
  2. unsignedlonghash=5381;
  3. intc;
  4. while(c=*str++)hash=((hash<<5)+hash)+c;/*hash*33+c*/
  5. hash=table_size>0?hash%table_size:hash;
  6. returnhash;
  7. }

同时如果存在一个数据节点冲突的情况,则采用开拉链法来解决,一个哈希存储节点的数据结构,next程序用于存储下一个相同哈希映射结果的值:

  1. /*Hashdataitemstruct*/
  2. structtm_hash_entry_t{
  3. char*key;/*datakeystring*/
  4. char*data;/*datavaluestring*/
  5. size_tlength;/*datalength*/
  6. unsignedcreated;/*datacreatetime(UnixTimestamp)*/
  7. unsignedexpired;/*dataexpiretime(UnixTimestamp)*/
  8. structtm_hash_entry_t*next;/*keyconflictlinknextdatanodepointer*/
  9. };


2. 数据失效处理

目前主要是两种方法处理时效,一种是当访问某个数据节点的时候,如果发现该数据的 expired 字段已经超过当前时间,那么将remove该节点。另外一种方法是在进行数据操作的时候,按照概率计算算法,不定期的清除掉已经过期的算法,看看概率算法实现:

  1. statusget_gc_probability(unsignedprobaility,unsigneddivisor){
  2. intn;
  3. structtimevaltv;
  4. gettimeofday(&tv,(structtimezone*)NULL);
  5. srand((int)(tv.tv_usec+tv.tv_sec));
  6. n=1+(int)((float)divisor*rand()/(RAND_MAX+1.0));
  7. return(n<=probaility?TRUE:FALSE);
  8. }

概率的几率百分比是通过 probaility 和 divisor 来确定的,缺省是 1/100 的几率,就是一百次操作里,有一次是可能执行清除过期数据操作的,这样做便于减轻程序操作的压力。


3. 内存使用完了的操作

如果tmcache启动的时候,设定了16MB的内存使用空间,但是最后内存不够用了,那么就只有通过清除前面插入的缓存数据来空出空间来进行存储新数据,这里主要是使用了队列,因为队列是使用先进先出(First in first out) 的原则的,代码:

  1. /*currentmemoryusesizeexceedMAX_MEM_SIZE,removelastnodefromqueue,removekeyfromhashtable*/
  2. if((get_mem_used()+length)>g_max_mem_size){
  3. structtm_queue_node_t*qnode;
  4. while((get_mem_used()+length)>g_max_mem_size){
  5. qnode=tm_qremove(g_qlist);
  6. remove_data(qnode->key);
  7. }
  8. }

这样做的缺点很明显,就是明明数据没有失效期,确被删除了,所以,缓存工具并不能作为持久化数据一样的对待方式,必须确保每次查询缓存的时候都进行了相应的存储操作,因为无法保证数据是还在内存中的。

【 结束语 】

基本可以确定 tmcache 是一个非常简单的缓存系统,比Memcache差距很远,更多来说 tmcache 只是一个学习的作品,同时也是做了一些简单的引导思路,希望对真正要做一个成型复杂稳定的缓存系统做一个抛砖引玉的简单参考,所以,tmcache 并不是一个稳定可靠的缓存系统,也不适合用于生产环境,更适合作为一个学习参考的小东西。 :-)


关于其他上面没有描述的内容,建议阅读tmcache的代码来获得更多相关知识。

下载地址:http://code.google.com/p/heiyeluren/downloads

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值