转载:http://www.cnblogs.com/domslab/archive/2009/06/29/1513564.html
http://www.cnblogs.com/domslab/archive/2009/06/29/1513514.html
版本:1.1.0
协议:New BSD license
平台:.Net 2.0/Mono 2.0
系统:Windows/Linux/BSD
ThumbCached 是一个简单高效的用于小数据的分布式缓存及储存系统(用于开发Web网站)。适用于缓存及储存数量庞大、个体容量小、读取频繁、需要持久化、非关键性的数 据,例如网站中的缩略图、用户自定义头像、已格式化的页面文本等。ThumbCached 还可以内存缓存模式运行,作用相当于Memcached,在速度上可以达到 Memcached 的70%左右。在 1.1 版本中新增加了嵌入的运行方式,适用于以非服务的形式嵌入到一个Web应用程序。
功能特点:
* 使用一个文件来储存数据,可以避免过多的细小文件所造成磁盘空间浪费,同时方便数据的转移和备份。
* 服务程序和应用程序可以分布于不同的服务器,适用于分布式的网站。
* 数据的传输使用标准HTTP协议,方便多种程序语言(如ASP.NET,PHP等)访问。
* 能在一个服务实例中同时创建多个储存单元,以便于将不同类型的数据分开储存。
* 服务端使用高效的异步Socket技术。
Thumbcached 的程序结构图如下:
ThumbCached由HTTP Service、Cache item manager(上图中的 Buffer Pool)和StoreManager三部分组成,各部分的功能如下:
HTTP Service:接受及回答客户端的请求,传输数据;
Cache item manager:使用.Net的内存管理机制实现的缓冲,将被访问的cache项(以下称为“block”)缓存并加以管理,通过队列的方式将新增加或被更新的block项交给StoreManger;
StoreManager:持久化(储存)所有block的信息和二进制数据内容。
这样的设计能让读、写、更新数据的速度都比较快,因为常用的和新增加的缓存项都是放在pool里面的,而Store queue使用队列的方式将新增加的缓存项在后台持久化到文件。不过也是因为使用队列的原因,可能会导致pool的数据被删除而磁盘上的数据仍然存在的情 况,所以删除数据时是等待磁盘上的数据也删除完毕之后才返回的,因此删除操作比较慢。幸好在实际应用中很少删除操作。
在持久化(即储存)部分,使用了两个文件来配合实现,一个文件存block的信息,另外一个文件存block的数据。
block信息使用SQLite储存并对block的key作索引,这样查找block信息时速度很快,数据表设计如下:
第二个文件用于储存block数据,因为block数据是不定长的,所以第二个文件使用了自定义的数据结构,考虑到更新block数据时如果采用直 接丢弃旧的数据再新建一条记录这种方式会导致文件空间浪费,所以block数据的记录采用了覆盖旧记录加“链记录”的方式来实现。即每个记录都可以允许链 N块数据区域,这样能够最大限度地减少文件空间的浪费。下面是第二个文件的结构图:
储存数据之后,文件的内容会变成下图这样:
ThumbCached 使用HTTP协议跟应用程序通信,下面是协议的定义 :
添加缓存项:
—————————————————-
Request:
POST /update/ITEM_KEY?expire=EXPIRATION_SECOND&abs=EXPIRATION_TYPE HTTP/1.1
Host: HOSTNAME:PORT
Content-Length: INTEGER
Content-Type: THUMBCACHED_DATA_TYPE_NAME
Last-Modified: GMT_DATE_TIME
[\r\n]
[BINARY_DATA]
ITEM_KEY: a string to name an item
EXPIRATION_SECOND: an integer number to specify the item expiration time (take effective in non-persistance mode only)
EXPIRATION_TYPE: a number '0' or '1', if it equal to '1' that means absolute expire.
THUMBCACHED_DATA_TYPE_NAME: combine with 'tcd/' and an integer number,
enum DataTypeNumber
{
Binary =0,
Object =1,
Boolean =3,
Int32 =9,
Int64 =11,
Single = 13,
Double = 14,
DateTime = 16,
String = 18,
EmptyByteArray = 256 + 6,
EmptyString = 256 + 18
}
GMT_DATE_TIME: specify the item time, take effecive in persistance mode.
Response:
HTTP/1.1 200 OK
Content-Length: 0
获取一个缓存项:
—————————————————-
Request:
GET /fetch/ITEM_KEY HTTP/1.1
If-Modified_Since: GMT_DATE_TIME
GMT_DATE_TIME: specify one time to test the item last modified time, if the item
does not modified since GMT_DATE_TIME, this request will return 304-Not Modified http status code.
Response:
HTTP/1.1 200 OK
Content-Type: THUMBCACHED_DATA_TYPE_NAME
Content-Length: INTEGER
Last-Modified: GMT_DATE_TIME
[\r\n]
[BINARY_DATA]
如果指定的key不存在相应的缓存项,则返回404 http代码。
一次获取多个缓存项:
—————————————————-
Request:
GET /multifetch/?keys=KEY1,KEY2,KEY3… HTTP/1.1
Response:
HTTP/1.1 200 OK
Content-Length: INTEGER
[\r\n]
KEY1
THUMBCACHED_DATA_TYPE_NAME
GMT_DATE_TIME
DATA_LENGTH
[BINARY_DATA]
[\r\n]
KEY2
THUMBCACHED_DATA_TYPE_NAME
GMT_DATE_TIME
DATA_LENGTH
[BINARY_DATA]
[\r\n]
KEY3
……
如果指定的key当中有其中的一个或多个没有对应的缓存项,则不返回改key的数据。
删除一个缓存项:
—————————————————-
Request:
GET /remove/ITEM_KEY HTTP/1.1
Response:
HTTP/1.1 200 OK
获取服务器状态:
—————————————————-
Request:
GET /status HTTP/1.1
Response:
HTTP/1.1 200 OK
Content-Type: text/plain
Content-Length: INTEGER
[\r\n]
Pool memory: INTEGER
Used memory: INTEGER
Item amount: INTEGER
Item hits: INTEGER