大概用一个礼拜的时间把memlink的源代码读了一边,也对缓存系统的做法有了一个大概的了解,如果现在去实现一个key-value的话应该用不了多长时间。但是这些东西重在设计。因为很多时候这些方法做起来都是有利有弊,比如其中的块计数:虽然省下来一些空间,但是如果写入操作变的多的时候可能会有较多的数据复制,这样性能也就下来了。具体不同结构的取舍在与具体业务的读写比例吧(在努力想一个更加牛掰的方式)。
其中日志的不同,在一定的时间点之后会调用dump来保存hashtable,而在两次dump之间的操作也会被记录到SyncLog中,这样不会因为在两次dump之间宕机而导致操作丢失。但是这里有个问题,这样同步的操作会不会对写入造成影响?会不会有这种情况:一个线程在完成写内存之后开始写同步日志,因为是高并发的,所以这里会不断的请求过来,但是上次的日志还没写完就不能处理新的请求。
如果有缓存式文件读写,那同步日志就失去意义来吧。因为不管是用户空间的缓存还是内核的都会在断电之后消失掉。那为什么不能像JBD那样来实现日志功能?JBD是在记录元数据的改变,而JBD是处理元数据的,不然速度会很慢。那cache追求的就是速度,如果因为同步搞的速度降低了,那么这样的同步还有意义吗?不过貌似Redis和memlink中都是结合dump和redo来实现同步的,这个应该也不会有什么问题。因为写入不是很多,那么我们是否可用将一些写入、修改操作保存在一个集合中,在一定时间间隔之后将其整体写入?
再来看内存池。其实在内存池中的远不是物理内存,这里的作用也就是减少了malloc和free的调用。这个地方就会有一个问题,如果保存的内存池大小十分精确的时候,那有什么用呢?比如我的list中的DataBlock的大小是1023B,然后下次想再分配1000B大小的块的时候还会用到这个块么?用这个块显然是有个问题的:空间的浪费,但是其实我们可以把多余的空间做成跳表,这样的就会在list中查找的时候加快很多。在我们实现内存池的时候可以设置成几种形式:1KB、2KB等,在真正分配的时候在剩余的空间中塞如跳表指针。这样的话,如果插入的是一个变长的内存(比如string)的时候也可以比较好的使用内存。
在cache中用到异步通知的地方感觉不是很多,为什么不自己写一段代码来做而是使用通用的但是性能不是很好的libevent?
那在cache中是否应该使用多线程?每个请求处理的时间都是很短的,这样上下文的切换确实是个不小的代价,但是单线程利用不了多核的优势。那我们是否可以根据服务器上有多少个CPU来开启一定的线程?每个线程都在一个CPU上跑。让所有的任务在同一个CPU上跑有个问题就是高速缓存容易被刷调(不过这个问题在多线程中也没有很好的解决方法==!,最起码MMU、TTL中的东西被刷出去的概率就少很多来吧)。
---------------------------------------------
个人理解,欢迎拍砖。