fatcache 的思考和总结

前一段时间基于 twitter/fatcahe 做一些二次开发, 主要是在上面支持redis协议和定制化数据结构的支持。现在针对使用fatcache开发过程中遇到的问题做一些总结和思考。

fatcache 可以简单的理解为是去掉多线程的memcached, 只是把数据放到磁盘。需要注意的是虽然数据放在磁盘,作为cache,服务重启数据也会丢失,这个主要是因为fatcache数据是通过存放在内存里面的索引来管理的,所以内存数据一丢,磁盘数据便无法读取。

fatcache的优点

  • 简单的协议, 支持memcached简单的文本协议
  • 单线程,实现足够简单,但同时会导致性能问题
  • 高效内存slab管理,跟mc的的slab管理类似,但有所区别
  • 针对SSD做写优化, 避免磁盘写放大和大量随机写

fatcache面临的问题

  • 单线程同步文件读写
  • 过期的key
  • 存放索引的hashtable无法自动扩容
  • 读磁盘数据不会让数据回到内存
  • 缺少stats命令
  • 重启数据丢失

问题对应的方案

Q1. 单线程同步文件读写

有人给fatcache提了一个pull request, 使用异步磁盘io, 这样能提高fatcache的吞吐, 但是官方并没有接受,可能认为异步文件io还是有不少坑。还有比较简单解决的解决方法就是异步线程写文件,可以提高响应速度。另外一种方案就是多线程改造,个人觉得在fatcache做过于复杂, 还不如考虑让memcached落地。

PS: 当对性能要求比较高,改动又很大基本可以重新考虑选型的问题, 选型是需要提前考虑性能问题

Q2. 过期key的问题

fatcache里面过期的key,不会主动剔除, 甚至是即使主动访问时,发现过期也不会主动剔除。只有在磁盘slab或者索引耗尽的时候,才会去做数据剔除。

个人认为可以在访问到数据,发现key过期时,就可以删掉索引, 好处如下:

  1. 避免索引过快耗尽而导致经常性剔除slab带来的性能损耗
  2. 存放索引的hashtable无法自动扩容, 及时删除过期索引,可以避免大量hash冲突导致的性能下降

当前另外一个比较明显的问题, 过期时间跟item数据放到一起, 放在磁盘中, 每次需要判断数据是否过期需要访问磁盘,性能消耗明显, 可以放到索引中, 用一些内存空间换性能,不过改动会比较大

Q3. 存放索引的hashtable无法自动扩容

意味着启动时,便要设置好hashtable大小, 如果太小会导致用一段时间后,变会有大量的key落到同一个槽而导致冲突过多而性能下降比较明显。 如果设置太大, 可能会浪费比较多的内存。

PS: 不过个人认为, 浪费一些可控的内存,远比冲突过多导致性能下降的痛苦好得多

当然最好的方案是跟memcached/redis一样,自动的进行扩容。

Q4. 读操作不会让数据回到内存

这个如果使用时在前面在挡一层全内存的缓存(如memcached), 这个问题可能就没那么明显. 或者也可以在里面实现一层读buffer, 缓存小部分最近读取的数据

Q5. stats 命令缺失

作为一个完整的服务,无法对服务进行健康检测,对当前使用情况一无所知, 这个问题个人觉得比较严重。后续个人想把stats这个功能做上,如果觉得比较稳定,再提交到官方版本。

Q6. 重启数据丢失

fatcache大量的数据是在磁盘,数据是否读取通过索引来读取, 而索引是在内存当中,也就是说, 如果服务因为bug或者断电挂了, 所有数据将丢失。

方案一: 可以像memcached那样,从其他实例来加载数据,但跟memcached不一样的是,fatcache的数据是在磁盘, 不是在内存,加热个几T的数据到磁盘,这个时间增长跟对于容量增长可能不是线性的,加热需要几个甚至几十个小时的都是可能的,这可是会要了亲的命啊~

方案二: 保存索引,因为数据本来就是在磁盘是不会丢的,所以如果可以把索引和内存slab的数据,跟redis类似,进行定时的备份, 然后通过索引来恢复是比较靠谱的方案.

方案三: 使用共享内存,这种方案可以保证即使是服务挂掉了,内存数据还是在的,缺点就是运维成本增加

The End

从当前Github上的star和fork数来看,用fatcache的人可能没有太多,遇到问题,能提供支持或者帮助的人可能不多,如果只是使用而没有深入去看代码的人可能要小心。还有当前fatcache统计信息这块还是处于裸奔状态,是不是twitter本身也用的没太多?

最后,之前已经给fatcache提了一些比较小的patch, 后续打算在业余空闲时间,会来优先解决下面的问题,等觉得比较稳定之后再回馈到官方:

  1. 增加stats命令, 这个应该是使用fatcache做为正式服务都是需要的功能
  2. 过期时间提到内存索引
  3. 索引hashtable自动扩容

这些功能会先放到个人的Github上 https://github.com/git-hulk/fatcache, 有兴趣的后续可以关注一下~