暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

【存储系统架构设计-缓存系统】从0编写一款缓存服务opCache

也输思雪计算机之路 2021-10-18
219
1,主体概述 
目前市场上缓存都比较常见,如redis,每一种都有其自己的用途,要想真正理解它们,需要我们阅读源码,阅读源码就很少会有人去做了,更别说阅读源码等掌握本质之后的事情。我个人看来,要想真正的学会某些东西,最好的就是自己造轮子,因为这些出来时都有其自己的背景和目标,也并不一定就适合我们的项目场景。所以,我打算自己编写一款缓存服务,旨在高效,高可用,可扩展,也就有了opCache缓存。

   

   上述为opCache缓存架构图,具体写流程如下:

,客户端通过连接池连接

2,进入解析器对请求解析(解析出是set还是get或者delete)

3,进入执行器执行

4,将数据写入到buffer,并且新增日志事件到log buffer(buffer poollog buffercheckpoint刷盘机制),响应立即返回。

5,buffer pool满了或者到一定触发时刻会将buffer pool数据先刷到immutable(内存)中(在该空间中的数据,不可修改)

6,刷盘线程会将immutable中的数据刷到磁盘,此处刷盘分了层次(LSM架构),分为level0层、level1层、level2层等,每层有各自限制大小,当上一层满了后,会触发下沉刷盘机制,将上一层的数据下刷到下一层去。

,level0层比较特殊,是immutable的全数据,会对key去重,也即会出现多个相同key的不同版本,其余level层的key本层唯一

具体读流程如下:

,客户端通过连接池连接

,解析器解析

,执行器处理

,查询buffer pool中是否有该key,如果没有,则查询immutable中是否存在该key

5,查询level0中是否存在该key(在该层查询出多个key的版本时,以最新版本的为准)

6,查询level1中是否有该key(以此类推)

Ps:这样一层层查询,怎么判断该key是否在该层?这里会使用布隆过滤器处理。

2,疑难点解答

编写语言为什么选择golang?

主要是之前我开源的rpc框架和MQ都是用golang写的,而且golang做并发有天然优势。

buffer pool也是存内存的,数据量大了,比如百万时,会很慢,有怎么考虑?

确实会有这问题,golangGC机制三色法,会对变量进行扫描处理,但好的是11版本后,对map已经进行了优化,如果map的类型是基本类型不是引用,则GC不会扫描map的元素,所以1.0版我用的是map[string]int,这样可避免GC扫描。

Map你存的数据对吧?可你那里是int,怎么存具体的key-value键值对的?

对,这里的map存的是int,也即是mapkey是字符串,valueint,这里其实用了一个大的全局数组来存放真正的对应键值对(value会被转成字节数组),然后map中存放的则是该全局数组中该key的下标位置。

1.0版有做什么性能方面考虑吗?比如怎么提升读写并发?

1.0版就已经做了读写并发的考虑,因为这也为后续的分布式部署打下基础。简单来说就是 shard分片。读写请求进来后,会对key进行hash加密计算出数值,然后进行分片路由,判断路由到哪一个分片上面,每一个shard分片都有一个对应的map和全局数据,这样可以提升读写并发。

当前1.0进度如何?规划是什么?

目前1.0初版已完成,码云地址https://gitee.com/opjesus/op_cache,目前支持简单的set,gethttp处理器未编写),目前存在问题是,全局数组是有大小限制的,对同一个key进行set时,是会在全局数组末尾新增元素,不会去删除之前key的值,那么怎么让之前的key过期?后面会将读写buffer独立开,分成buffer pool(读缓冲)和change buffer(写缓冲)buffer pool会使用新老生代替换方式淘汰机制,change buffer则缓存修改命令。


文章转载自也输思雪计算机之路,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论