写在前面
Redis是一款完全开源的高性能key-value数据库,是NoSQL数据库。Redis具有性能高、数据类型丰富、原子性等特点,同时Redis是运行在内存当中,并且可以持久化到硬盘上的。Redis的官方网址是redis.io/ ,可以在网站上进行Redis下载、文档学习等。
Redis中的数据结构
Redis提供了多种数据结构供用户选择,包括字符型、哈希表、列表、集合。
字符串
- Redis字符串是一种SDS的结构,该结构下记录了已使用字符数组长度、还剩下多少字符数组可以使用、指向分配字符数组的指针。
- SDS数据结构,一方面可以提高字符串拼接、缩短、求字符串长度等操作的效率,另一方面该种结构可以处理二进制数据,避免了很多情况下常规字符串比如‘\0’字符会造成的一些问题,也杜绝了缓存溢出等问题
- SDS的内存预留策略为如果字符串长度占用内存少于1MB,则预留当前字符串长度的空间,否则预留1MB空间
链表
- 链表是Redis中的一种数据结构,也是一种比较直观的线性结构,Redis中链表实现为双向链表,因此查找某个节点的前一个节点效率是比较高的。
- 链表用于Redis中列表键、发布与订阅等功能的实现中
字典
- 字典是Redis中的一种数据结构,其内部实现为哈希表,并且是采用链表式哈希实现的,即保持了两个桶数组,每一个桶都指向一个链表,链表中的节点的键的哈希值相同。其中一般情况下只使用一个桶数组,只有在rehash过程中才会两个桶都会用到。
- 为了效率起见,Redis在rehash过程中是采用了渐进式rehash的方式进行rehash,在每一个对字典的添加、删除、查找、更新操作上渐渐地进行hash操作,而不是一次性将字典中全部键值对进行rehash。
跳表
跳跃表是一种高效的数据结构,在均摊的情况下可以达到log级别的时间复杂度,而Redis中的有序集合也是采取了跳跃表的方式实现,而非平衡树。
Redis的使用场景
- 连续签到
- 有很多网站会有连续签到的功能,如果将签到信息放在SQL数据库每次查询都会消耗巨量的服务器资源,并且磁盘IO是相对于内存IO是慢很多的,因此将签到信息放在Redis中是很不错的选择。
- 消息通知
- 可以通过list数据结构作为消息队列,通过构造的队列的特性,当遇到文章更新时,将更新后的文章推送到ES。
- 排行榜
- 当一个排行榜中有很多用户,并且要求排名根据积分进行实时更新,这就要求我们用一个高效的数据结构进行存储,Redis中的有序集合是通过跳表实现的,而跳表天然是有序的并且插入删除都是log级别的,因此采用有序集合是一个很不错的选择。
- 分布式锁
- Redis自身的实现是单线程的,因为Redis效率非常高,CPU并不会成为Redis的瓶颈,并且单线程实现起来更简单。对于并发场景下,要求一次只执行一个协程,该场景可以使用redis的setnx实现。
常见的问题
大key
大key具有读取成本高、造成慢查询等问题,可以通过拆分、压缩等方式来解决。
热key
热key通常QPS比较高,可以通过设置Localcache、拆分等方式来解决。
缓存穿透
缓存穿透会导致相应过慢,可以通过缓存空值、布隆过滤器等方式来进行解决。
总结
Redis是一款非常常用并且非常重要的key-value数据库,我们不仅仅应该学会如何去用,明白其背后的原理也是十分重要的。在了解了Redis的底层实现之后,在实际应用时会更加得心应手。