系统设计高频率元件之 Redis
2024年5月24日
在系统设计中有许多“高频率会用上”的要件。所谓的高频率会用上,是指不论哪类系统,都会有使用这些要件的需求。
其中键值对资料库是指由键值对 (key-value pair) 组成的存储机制。这种资料库在存资料时,会同时存一个独特的 id
,然后要取资料时,再根据这个 id
来取。
常见的键值对资料库有 DynamoDB、MongoDB,或是 etcd、Zookeeper,以及 Redis 等等,上面这些都是键值对资料库,但都有不同的特性。这篇会着重在 Redis 这类把资料存在记忆体的键值对资料库。目前社群中相似解决方案有很多,先前 Redis 开源授权风波后,各大厂都有推出相对应的解决方案。不过由于 Redis 在过去被广泛使用,以下都仍以 Redis 这个词来代表相似类型的解决方案。
Redis 的基本介绍与特性
如上面提到,Redis 是一种键值对资料库,是由键值对的方式来存资料,而 Redis 的每个键可以对应的资料结构很多元,基本上最常见的资料结构都有被支援。举例来说,字串 (string)、列表 (lists)、集合 (Sets),甚至是 布隆过滤器 (Bloom Filters) 以及地理空间索引 (Geospatial Indexes)
因为是键值对的操作,所以可以简单地用 SET
来为某个键设定对应的值,以及用 GET
来取得相对应键的值。举例来说,我们可以这样
SET explainThis 1
GET explainThis # 拿到 1
当然除了上面做基本的存跟取之外,Redis 还提供许多方法可以直接用。有兴趣的人可以参考相关文件 [连结],这边就不展开。下面我们将会聚焦谈几个 Redis 常在系统设计会被用的地方。
做为键值对资料库,Redis 的一大特性是把资料存在记忆体,这让 Redis 的速度很快。同时,Redis 的可扩展性很好。Redis 主要透过一种叫 hash slot 的分片方式,把键分到集群中的不同节点,让集群要添加节点变很容易,一个集群每秒处理百万个读取请求都很容易 (AWS 的 ElastiCache for Redis 先前号称做到每个集群能一秒处理五百万个读取请求)。
在初步了解完 Redis 与其特性后,接着让我们来谈一些实际可以应用上 Redis 的地方。
Redis 作为快取 (caching)
上面提到,Redis 又快又能处理大量请求,基于这个特性,Redis 很常会被作为快取来用。服务先查看 Redis,如果有快取且没过期,就直接用快取,就不用跟资料库拿。如果没有,就跟资料库拿,然后再放到快取,并设定快取的存活时间 (TTL)
在上面的流程中,如果快取还没有过期,直接跟 Redis 拿,会比跟资料库拿快很多;而有 Redis 做为快取,除了能够降低延迟外,也可以降低后端资料库的压力。如果在系统设计中遇到有低延迟要求的系统,Redis 可能是解决方案之一。
Redis 作为分布式锁 (distributed locking)
除了快取外,Redis 也很常会被拿来当分布式锁。在一个分散式系统中,如果要保持节点之间的一致性 (consistency),或是要确保同样的操作不会被重复做,这时就可以用 Redis 来做为分布式锁。
让我们用抢票系统作为例子来进一步说明。一般来说,抢票系统对于一致性要求很高,例如,使用者 A 抢到的票,不能同时被其他使用者抢,不然会出现一张票卖两个人,这就麻烦了。这时候就需要一个机制来避免这种重复的问题,而锁 (lock) 是很常会用到的方法。
当提到锁,你可能会想到用资料库的悲观锁 (pessmistic lock),但在抢票系统的情境下,这不是好的做法。因为通常抢票系统要让抢到票的人,保留时间来付款 (例如抢到后保留五分钟,没付款的话就释放掉);而悲观锁适合短时间上锁,要锁五到十分钟不适合用这种方式。
而分布式锁在这种情况就会更适合,具体来说,可以用 Redis 搭配存活时间 (TTL) 来实现。 以抢票系统来说,当使用者 A 抢到票,会用票的 id
以及存活时间 (TTL) 拿到 Redis 的锁。如果 A 有在锁的存活时间内完成付款,则会更新到资料库,确保其他人不会重复购票;假如时间到了没付款,锁就可以自动释放,让票能被其他人抢。
Redis 其他常见用途与追问的问题
除了上面提到的两种用途外,Redis 也有许多其他在系统设计中常会用到的地方。除此之外,在系统设计中,当提到 Redis 时,经常会有不同的追问题,例如 Redis 做为快取如何扩展到全球多区域、Redis 存记忆体那该如何做到资料持久 (persistence)、Redis 是键值对那该如何处理热键问题 (hot key)
上面这些我们都有在 E+ 的主题文中进一步讨论。有兴趣一读的人,欢迎加入 E+ (详细介绍见此)