# 如果让从你设计一个键值KV，你会考虑哪些模块？

![](https://cdn.jsdelivr.net/gh/rongweihe/ImageHost01/Redis%E6%A0%B8%E5%BF%83%E5%8E%9F%E7%90%86%E5%92%8C%E5%AE%9E%E6%88%98-%E4%BB%8E%E9%9B%B6%E8%AE%BE%E8%AE%A1%E4%B8%80%E4%B8%AA%E9%94%AE%E5%80%BC%E6%95%B0%E6%8D%AE%E5%BA%93.png)

大体来说，一个最简单的键值数据库包括了访问框架、索引模块、操作模块和存储模块四部分。

![](https://cdn.jsdelivr.net/gh/rongweihe/ImageHost01/redis-键值数据库.png)



# 几点注意：

- 键值对保存在内存还是外存？对于 Redis 而言，缓存是非常重要的一个应用场景，通常采用内存保存键值数据。
- 采用什么访问模式？通过网络框架以 Socket 通信的形式对外提供键值对操作，这种形式可以提供广泛的键值存储服务。
- 如何定位键值对的位置？这依赖于键值数据库的索引模块。索引的作用是让 键值数据库根据 key 找到相应 value 的存储位置，进而执行操作。
- 内存键值数据库（例如 Redis）采用哈希表作为索引，很大一部分原因在于， 其键值数据基本都是保存在内存中的，而内存的高性能随机访问特性可以很好地与哈希表 O(1) 的操作复杂度相匹配。
- 不同操作的具体逻辑是怎样的？
- - 对于 GET/SCAN 操作而言，此时根据 value 的存储位置返回 value 值即可；
  - 对于 PUT 一个新的键值对数据而言，SimpleKV 需要为该键值对分配内存空间；
  - 对于 DELETE 操作，SimpleKV 需要删除键值对，并释放相应的内存空间，这个过程由 分配器完成。
- 如何实现重启后快速提供服务？
- - 最简单做法：采用常用的内存分配器 glibc 的 malloc 和 free。
  - Redis 的内存分配器提供了多种选择，分配效率也不一样，后面具体分析。
- 文件持久化？最简单可以直接采用了文件形式，而像 Redis为了适应不同的业务场景，提供了诸多的执行机制和优化改进，比如AOF 和 RDB 两种形式数据持久化。

# 简单键值KV 和 Redis 对比

![image-20210725162847881](https://cdn.jsdelivr.net/gh/rongweihe/ImageHost01/redis-duibi.png)

从这张对比图中，我们可以看到，从一个简单的键值 KV 演进到 Redis，有以下几个重要变化：

- Redis 主要通过网络框架进行访问，而不再是动态库了，这也使得 Redis 可以作为一个 基础性的网络服务进行访问，扩大了 Redis 的应用范围。
- Redis 数据模型中的 value 类型很丰富，因此也带来了更多的操作接口，例如面向列表 的 LPUSH/LPOP，面向集合的 SADD/SREM 等。
- Redis 的持久化模块能支持两种方式：日志（AOF）和快照（RDB），这两种持久化方 式具有不同的优劣势，影响到 Redis 的访问性能和可靠性。
-  只考虑了简单的单机键值数据库，但是，Redis 支持高可靠集群和高可扩展集 群，因此，Redis 中包含了相应的集群功能支撑模块。

参考：极客时间-《Redis核心技术与实战》。