利用第一性原则思考,如何制造一个kv存储工具
从大局了解一个系统的设计与基本功能,在深入到细节中
目的是为了:实践中定位和解决问题时,就会轻松很多
\
对于一对一的查询可以将原先的sql转换成缓存存储,对于有聚合要求的还是应该是用关系型数据库
1.设计
设计一个SimpleKV的键值对存储系统
1.1存储那些数据(数据模型)
-
基本的key-value模型
-
memcached
- value为string
-
redis(支持多类型value)
- value包含string,hash,列表,集合等
-
不同的value实现,不同数据结构在性能、空间效率等方面的差异
1.2对数据有什么操作(操作接口)
-
PUT
- 新写入或更新一个key-value
-
GET
- 根据一个key获取对应的value
-
DELETE
- 根据key删除key-value
-
SCAN
- 根据一段key的返回返回对应的value值
-
EXISTS
- 某个key是否存在
\
-
存储方式
-
内存\
- 读写很快,访问速度很快(不需要磁盘寻址)
- 一旦掉电数据都会丢失
-
外存
- 数据持久化,不会丢失
- 整体性能会被拉低
-
1.3架构设计
-
架构设计
- 访问框架(俗称客户端)
- 索引模块(怎么找?)
- 操作模块(执行具体操作)
- 存储模块(实际存储位置)
1.4访问模式
-
通过行数据调用的方式供外部应用使用(没接触过)
- libsimplekv.so,就是以动态链接库的形式链接到我们自己的程序中,提供键值存储功能
- RocksDB\
-
通过网络框架以socket通信的形式对外提供键值对操作
-
网络框架中包括 Socket Server 和协议解析
-
Memcached 和 Redis 则是通过网络框架访问\
-
特点
- 提供了数据库的受用性
- 键值数据库的性能、运行模型提供了不同的设计选择,带来了一些潜在的问题\
-
设计上需要思考的点
- 网络连接
- 网络请求的解析
- 数据存取的处理
- 一个线程处理所有过程,可能导致阻塞后影响系统性能,降低系统响应速度
- 多线程处理会存在资源竞争等问题
-
1.5如何定位键值对位置
-
利用索引模块快速定位key是否存在和存储位置
-
索引类型
- 哈希表(Memcached 和 Redis)(高性能随机访问可以与hash的o(1)操作相匹配)
- B+树(mysql)
- 字典树
- 跳表(有序索引链表)(RocksDB)
1.6不同操作具体逻辑
- 对于 GET/SCAN 操作而言,此时根据 value 的存储位置返回 value 值即可
- 对于 PUT 一个新的键值对数据而言,SimpleKV 需要为该键值对分配内存空间
- 对于 DELETE 操作,SimpleKV 需要删除键值对,并释放相应的内存空间,这个过程由分配器完成
- 涉及到键值对的分配与释放
1.7重启后快速提供服务
-
内存分配器 glibc 的 malloc 和 free(用于内存管理)
- 但是可能造成内存碎片问题
-
Redis 的内存分配器提供了多种选择,分配效率也不一样
- redis持久化机制
- 每次操作都落盘,效率比较低
- 周期落盘,可能会有数据丢失
-
可以采用文件保存(kafka是通过文件保存)
2.总结
-
计算机存储只有(cpu缓存,内存,外存(磁盘))
-
Redis 主要通过网络框架进行访问,而不再是动态库了,这也使得 Redis 可以作为一个基础性的网络服务进行访问,扩大了 Redis 的应用范围
-
Redis 数据模型中的 value 类型很丰富,因此也带来了更多的操作接口\
-
Redis 的持久化模块能支持两种方式:日志(AOF)和快照(RDB)\
-
Redis 中包含了相应的集群功能支撑模块\