redis(Remote Dictionary Server,远程字典服务器)是一个开源的、高性能的键值对(key-value)存储系统,是跨平台的非关系型数据库。
2008年,一款基于MySQL的网站实时统计系统——LLOOGG被正式推出。不久之后,Merzia公司由于不满于这个系统的现有性能,于2009年为LLOOGG设计了一个全新的数据库——Redis(第一个版本)。为了使Redis能够应用到更多地方,其创始人在社区开源代码,并与Redis另一名主要的代码贡献者共同开发着Redis。
2010年,VMware公司赞助Redis的开发,开发人员开始全职开发Redis。从2013年5月起,Pivotal成为Redis的主要赞助商。
根据Redis官网的最新介绍,Redis是一个开源(持有BSD许可)的、基于内存处理的数据结构存储,用作数据库存储、缓存处理、消息代理和流引擎(Streaming Engine)。Redis的功能十分强大,在短短几年的时间里,不仅获得了庞大的用户群体,还得到了大量程序员和IT公司的支持和推广。
DB-Engines网站根据键值对存储数据库管理系统的受欢迎程度对它们进行排名,该排名结果每月更新一次。DB-Engines网站的键值对数据库排名如下。
根据Stack Overflow年度开发人员的调查结果显示,Redis连续4年获得最受欢迎的键值对存储数据库的称号。Redis是基于ANSI C语言编写的,并且为开发者提供了多种语言的API,如C#、C++、GO、JAVA、php、Ruby、JavaScript、Perl、Python/ target=_blank class=infotextkey>Python等。伴随着Redis的用户越来越多,大部分的互联网公司都开始使用Redis作为公共缓存。
Redis作为热门的NoSQL数据库系统之一,提供了多种键值数据类型以适应不同场景下的存储需求。Redis主要有以下6个特点。
Redis通常被称为数据结构服务器,因为它不仅支持多种类型的数据结构,如字符串(strings)、散列(hashes)、列表(lists)、集合(sets)、有序集合等,而且还可以通过Redis哨兵(Sentinel)和自动分区(Cluster)实现高可用性。
Redis数据库的所有数据都被加载到内存中进行操作或处理,由于内存的读写速度远远大于硬盘,因此Redis的数据读写速度及性能也比其他数据库更加优秀,它每秒可以读写超过10万个键值。
Redis的数据存储在计算机内存中,为了能够持久地使用Redis数据,防止系统故障造成数据丢失,可以将Redis中的数据异步写入磁盘空间中,这个过程就叫做Redis持久化。Redis提供了两种不同的持久化方法,一种是快照(RDB,Redis DataBase),另一种是追加文件(AOF,Append Only File)。
Redis的事务操作可以保证数据操作的原子性,即一个事务中的所有命令要么全部执行,要么全部不执行。如果其中任何一个命令执行失败,整个事务将被回滚到之前的状态。这种原子性保证了Redis的数据操作具有可靠性和一致性。
Redis支持主从复制构建集群,支持数据的备份。为了分担读取数据的压力,Redis不仅支持主从同步,而且也支持一主多从以及多级从结构,其中主节点提供写操作,从节点仅提供读操作。对于“读多写少”的状况,可为主节点配置多个从节点,从而提高响应效率。
(1) Redis主从同步实现过程
Redis主从数据的同步是异步进行的,主从同步存在一个状态差,但不会影响主逻辑,也不会降低Redis的处理性能。
如图2-2所示,Redis实现主从同步的过程大致可以分为以下6步。
① 从节点执行slaveof命令;
② 从节点保存slaveof命令中主节点的信息,不做其他操作;
③ 从节点内部的定时任务发现有主节点的信息,开始使用socket连接主节点;
④ 连接成功后,从节点向主节点发送ping命令,请求连接;
⑤ 如果主节点设置了权限,从节点需要进行权限验证;如果验证失败,复制终止;权限验证通过后,主从节点进行数据同步,主节点将全部数据全部发送至从节点,做一次完整备份;
⑥ 主从节点完成备份后,主节点将持续发送给从节点新的数据变动命令,从节点实时同步,保证主从数据一致性。
(1) Redis数据同步的过程
Redis 2.8版本之后,从服务器对主服务器的同步操作需要使用psync命令来实现,主从服务器在执行psync命令期间的通信过程如下。
1) runId:每个Redis节点启动都会生成唯一的uuid,每次Redis重启后,runId都会发生变化。
2) offset:主节点和从节点各自维护自己的主从复制偏移量offset,当主节点有写入命令时,offset=offset+命令的字节长度。从节点在收到主节点发送的命令后,也会增加自己的offset,并把自己的offset发送给主节点。这样,主节点同时保存自己的offset和从节点的offset,并通过对比offset来判断主从节点数据是否一致。
发送psync命令的目的是让从服务器与主服务器进行同步,以确保从服务器的数据与主服务器的数据保持一致。当从服务器发送psync命令后,主服务器可能会有以下3种响应情况。
1) FULLRESYNC:第一次连接,进行全量复制
2) CONTINUE:进行部分复制
3) ERR:不支持psync命令,进行全量复制
Redis不仅是优秀的存储数据库,还担任着其他角色,比如缓存系统、队列系统等。
作为缓存系统,Redis为每个键设置生存时间(Time To Live,TTL),生存时间到期后键会自动被删除,还可以限定数据占用的最大内存空间,在数据达到空间限制后按照一定的规则自动淘汰不需要的键。借助Redis出色的性能、丰富的数据类型及其特有的持久化,用户可将Redis应用到更加宽广、丰富的业务中去。
Redis是一个高性能的优先级队列,它借助列表类型键实现队列,支持阻塞时的读取操作。除此之外,Redis还支持“发布/订阅”的消息模式,可帮助用户构建聊天室系统
Redis使用起来十分便捷,它提供了几十种编程语言的客户端库。用户可以使用命令操作Redis数据库,实现读写数据,便于在程序中与Redis的交互。命令语句与Redis的关系相当于SQL语句与MySQL的关系。
Redis的开发代码量仅3万多行,并且开源,便于用户通过修改Redis源代码来适应自己的项目需求。同时,对于希望充分发挥数据库性能的开发者而言,Redis也具有很大的吸引力。到目前为止,已有近百名开发者为Redis贡献了代码。在良好的开发氛围和严谨的版本发布机制下,Redis稳定版本的性能更具可靠性。
Redis 数据库主要被大型企业、初创公司和政府组织用于以下场景:缓存、构建队列系统、实时欺诈检测、全球用户会话管理、实时库存管理、AI/ML功能存储以及索赔处理。
Redis数据库在内存中读写数据的容量受到物理内存的限制,不适用海量数据的高性能读写,再加上它缺少原生的可扩展机制,不具备可扩展能力,需要通过客户端来实现分布式读写,因此Redis适合的场景主要局限在较小数据量的高性能操作和运算上。目前,国内的互联网企业,如新浪微博和知乎,以及国外互联网企业的产品,如Github、Stack Overflow、Flickr和Instagram,这些都是Redis的用户。
常见用例包括以下6种。
使用云数据库Redis时,Redis作为持久化数据库,主程序部署在ECS上,所有业务数据存储在Redis中。云数据库Redis版支持持久化功能,主备双机冗余数据存储,保证了服务的高可用性。适用场景为游戏网站及应用。
Redis最常见的应用场景是作为缓存系统。它使用String类型来将序列化后的对象存储到内存中。
Redis是单线程模型,而Memcached则支持多线程。应用在多核服务器上时,Redis的性能比Memcached要逊色一些。Redis的性能优异,通常情况下其性能不会成为服务的瓶颈。Redis将会很好地代替Memcached,成为热点数据缓存的首选工具。
Redis支持保存List链表和Set集合的数据结构,且支持对List进行各种操作。基于List来做FIFO双向链表可实现一个轻量级的高性能消息队列服务。常见的应用场景有12306网站的排队购票业务和候补业务,电商网站的秒杀、抢购等业务。
Redis使用有序集合和一个计算热度的算法,可以轻松地得到一个热度排行榜。常见的应用场景有新闻头条、微博热搜榜、热歌榜、游戏排行榜等。
当需要处理上亿数据量的情况时,可以考虑使用位操作。例如处理几亿用户的签到、去重登录的统计、查询用户的在线状态等场景。如果为每个用户建立一个key,那么对于拥有十亿用户的腾讯来说,所需要的内存大小将难以想象。使用Redis的位操作命令,如setbit、getbit和bitcount,可以解决上述问题。可以在Redis内部构建一个足够长的数组,每个数组的值为0或1。数组的下标(index)使用数字表示用户ID。这样,可以使用下标和元素值来记录并存储数亿条记录。
Redis高效率读写的特点可以充分发挥其计数功能。Redis的数据结构中,String、hash等支持原子性的递增操作,适用诸如统计点击数应用。因为Redis是单线程,所以能够避免并发问题,保证不会出错,而且其100%毫秒级的性能,非常适用于高并发的秒杀活动、分布式序列号的生成、网站访问统计等场景。
Redis以键值对的形式存储数据,而value则支持多种数据类型,常见的数据结构有String(字符串)、List(列表)、Set(集合)、Hash(散列)和Sorted Sets(有序结合)。本节将详细讲解这5种数据结构。
String类型是Redis最基本的数据类型,一个key对应一个value,String类型的value最大能存储512MB。String的值是二进制类型的,具有较高的安全性,其值的数据类型可以为文本、图片、视频或者序列化的对象。
String数据结构多用于实现计数功能,例如掘金文章的点击数量、阅读数量、视频观看量、分布式锁,也常用于集群环境下的session共享。
Redis列表是简单的字符串列表,按照插入顺序排序,最多可存储2³²-1个元素。对列表进行读写操作时,只能添加或读取一个元素到列表的头部(左边)或者尾部(右边)。
GoodID为列表的键名,2022001、2022002、2022003和2022003都是列表中的键值。这些值均按照插入顺序排列,分别为列表的第1个字符串元素、第2个字符串元素、第3个字符串元素、第4个字符串元素。另外,List允许出现重复的值,如该List中的第3个元素和第4个字符串元素都为2022003。
List数据结构可用于获取最新的评论列表、最近N天的活跃用户数、新闻推荐等。
Set是字符串元素的无序集合。其中,字符串元素是不重复且无序的,集合最多可存储2³²-1个元素。
Set类型与hash类型的存储结构相同,仅存储键,不存储值(nil)。这是因为Set的内部实现是一个value永远为null的HashMap。HashMap通过计算hash的方式来实现快速排重,这也是set能提供判断一个成员是否在集合内的原因。Set的value和List的value类似,都是一个字符串列表,区别在于Set是无序的,且Set中的元素是唯一的。
利用Redis提供的Set数据结构可以存储大量的数据,并且高效的内部存储机制使其在查询方面具有更高的工作效率。
Set可用于存储一些集合性的数据,比如微博应用中,把一个用户关注的人放在一个集合中,用户的粉丝放到一个集合中,通过集合的交集、并集、差集等操作,实现共同关注,互相关注、可能认识的人等功能。除此之外,Set集合常用于限时抽奖活动、共同好友、商品筛选等场景。
Redis Hash是一个无序的键值(key-value)对集合。Redis本身就是key-value类型,此处的Hash数据结构指的是key-value中的value,正是因为如此,hash特别适合用于存储对象。
Hash是一个字符串类型的key和value的映射表,其中存储键的类型必须为字符串类型,值的类型可以是不可重复的字符串、数字等。
Hash使用哈希表结构实现数据存储,一个存储空间保存多个键值对数据,常应用于各种商城购物车如淘宝、京东等。
Sorted Sets是在Set的基础上,为value中的每个字符串关联了一个score(得分)属性。Sorted Sets通过计算得分,将字符串进行排序,这也是有序集合与散列的主要区别。
有序集合允许直接操作值,散列则是通过键来查找值;有序集合的键是唯一的,值是不唯一的,而散列的值则是唯一的。有序集合是按照值的大小进行排序的,常用于各种排行榜,如百度新闻榜单、热搜榜等。