很多开源项目中都使用了redis,这些项目为什么使用redis?使用redis有什么好处?怎么使用redis?带着这些疑问,我们来了解一下redis。
一、什么是Redis
Redis是一个免费开源用于内存存储的数据结构服务器,可用作数据库,高速缓存和消息队列代理。它支持字符串、哈希表、列表、集合、有序集合等数据类型。它支持多种集群部署,辅助项目达到更高的性能。
二、Redis的结构
Redis 数据类型分为:字符串、哈希、列表、集合、有序集合等五种类型。
1.String(字符串)
字符串类型是redis中最基本的数据类型,一个key对应一个value。字符串类型实际上可以是字符串(简单的字符串、复杂的字符串(xml、json)、数字(整数、浮点数)、二进制(图片、音频、视频))等,但最大不能超过512M。
2.Hash(哈希)
哈希类型是一个Map,我们知道redis本身就是键值对结构,哈希结构就是“值”也充当键值对结构,如 value={{value-a1,value-b1},......value-an,value-bn}}
3.list(链表)
列表类型是用来储存多个有序的字符串,列表中的每个字符串成为元素(element),一个列表最多可以储存2的32次方-1个元素,在redis中,可以队列表两端插入(pubsh)和弹出(pop),还可以获取指定范围的元素列表、获取指定索引下表的元素等,列表是一种比较灵活的数据结构,它可以充当栈和队列的角色,在实际开发中有很多应用场景。
4.Set(集合)
集合类型也是用来保存多个字符串的元素,但和列表不同的是集合中不允许有重复的元素,并且集合中的元素是无序的,不能通过索引下标获取元素,redis除了支持集合内的增删改查,同时还支持多个集合取交集、并集、差集,并合理的使用好集合类型
5.zset (有序集合)
有序集合也是用来保存多个字符串的元素,跟集合的区别在于,有序集合中的元素是可以排序的,它给每个元素设置一个分数,作为排序的依据。
三、Redis的三种集群模式
Redis的三种集群模式主要是:主从模式(redis2.8版本之前的模式)、哨兵sentinel模式(redis2.8及之后的模式)和redis cluster集群模式(redis3.0版本之后)。
1、主从模式(master-slave)
(1)模式来源:
同Mysql主从复制的原因一样,Redis虽然读取写入的速度都特别快,但是也会产生读压力特别大的情况。为了分担读压力,Redis支持主从复制,在主从复制中,数据库分为两类:主数据库(master)和从数据库(slave)。Redis的主从结构可以采用一主多从或者级联结构,客户端可对主数据库进行读写操作,对从数据库进行读操作,主数据库写入的数据会实时自动同步给从数据库。
(2)工作机制:
当主数据库slave启动后,主动向从数据库master发送同步SYNC命令。master接收到SYNC命令后在后台保存快照(RDB持久化)和缓存保存快照这段时间的命令,然后将保存的快照文件和缓存的命令发送给slave。slave接收到快照文件和命令后加载快照文件和缓存的执行命令。
复制初始化后,master每次接收到的写命令都会同步发送给slave,保证主从数据一致性。
(3)优缺点
优点:master能自动将数据同步到slave,可以进行读写分离,分担master的读压力;
master、slave之间的同步是以非阻塞的方式进行的,同步期间,客户端仍然可以提交查询或更新请求
缺点:不具备自动容错与恢复功能。主从模式下,master节点在主从模式中唯一,若master挂掉,则redis无法对外提供写服务,导致客户端请求失败,需要等待机器重启或手动切换客户端IP才能恢复;
master宕机,如果宕机前数据没有同步完,则切换IP后会存在数据不一致的问题
难以支持动态扩容,Redis的容量受限于单机配置。
2、哨兵(Sentinel)
(1)模式来源:
主从模式的弊端就是不具备高可用性,当master挂掉以后,Redis将不能再对外提供写入操作,因此sentinel应运而生。sentinel中文含义为哨兵,顾名思义,它的作用就是监控redis集群的运行状况。那么如何得知某一台redis服务器挂了,如何切换,如何保证备份的机器是原始服务器的完整备份呢?这时候就需要Sentinel和Replication(复制)出场了。Sentinel可以管理多个Redis服务器,它提供了监控,提醒以及自动的故障转移的功能;Replication则是负责让一个Redis服务器可以配备多个备份的服务器。Redis也是利用这两个功能来保证Redis的高可用的。
在redis3.0以前的版本要实现集群一般是借助哨兵sentinel工具来监控master节点的状态,如果master节点异常,则会做主从切换,将某一台slave作为master,哨兵的配置略微复杂,并且性能和高可用性等各方面表现一般,特别是在主从切换的瞬间存在访问瞬断的情况,而且哨兵模式只有一个主节点对外提供服务,没法支持很高的并发,且单个主节点内存也不宜设置得过大,否则会导致持久化文件过大,影响数据恢复或主从同步的效率。
(2)工作机制:
每个Sentinel(哨兵)进程以每秒钟一次的频率向整个redis集群中的master主服务器、slave从服务器以及其他的Sentinel(哨兵)进程发送一个ping命令。
如果一个实例距离最后一次有效回复ping命令的时间超过down-after-milliseconds选项所指定的值则这个实例会被Sentinel标记为主观下线(SDOWN)。
如是是master主服务器被标记为SDOWN,则正在监控这个服务器的所有Sentinel都要以每秒一次的频率确认服务器是否真的已经进入SDOWN(主观下线状态)。
当有足够数量(≥配置文件配置值)的Sentinel在指定的时间内确认了master进入了SDOWN状态,则master被标记为ODOWN(客观下线状态)。
在一般情况下,每个Sentinel会每10秒向redis 主服务器和从服务器发送Info命令。但是当master被标记为客观下线时,频率改为1秒一次。
若没有足够数量的Sentinel同意master服务器下线,则master的SDOWN状态被移除,若master重新向Sentinel发送ping命令返回了有效回复,则master的SDOWN状态被移除。
(3)优缺点
优点:哨兵集群,基于主从复制模式,所有的主从配置优点,它都有主从可以切换,故障可以转移,高可用性的系统哨兵模式就是主从模式的升级,手动到自动,更加健壮;
缺点:Redis不好在线扩容的,集群容量一旦到达上限,在线扩容就十分麻烦,哨兵模式的配置繁琐;
3、集群(Cluster )
(1)模式来源:
sentinel模式基本可以满足一般生产的需求,具备高可用性。但是当数据量过大到一台服务器存放不下的情况时,主从模式或sentinel模式就不能满足需求了,这个时候需要对存储的数据进行分片,将数据存储到多个Redis实例中。单台服务器资源的总是有上限的,CPU资源和IO资源我们可以通过主从复制,进行读写分离,把一部分CPU和IO的压力转移到从服务器上。但是内存资源怎么办,主从模式做到的只是相同数据的备份,并不能横向扩充内存;单台机器的内存也只能进行加大处理,但是总有上限的。所以我们就需要一种解决方案,可以让我们横向扩展。cluster模式的出现就是为了解决单机Redis容量有限的问题,将Redis的数据根据一定的规则分配到多台机器。
cluster可以说是sentinel和主从模式的结合体,通过cluster可以实现主从和master重选功能,所以如果配置两个副本三个分片的话,就需要六个Redis实例。因为Redis的数据是根据一定规则分配到cluster的不同机器的,当数据量过大时,可以新增机器进行扩容。
使用集群,只需要将redis配置文件中的cluster-enable配置打开即可。每个集群中至少需要三个主数据库才能正常运行,新增节点非常方便。还有就是客户端与redis节点直连,不需要中间代理层.客户端不需要连接集群所有节点,连接集群中任何一个可用节点即可。
(2)工作机制:
在redis的每一个节点上,有两样东西我们比较关注,一个是插槽(slot),它的取值范围是:0~16383。还有一个就是cluster,它类似是一个集群管理的插件。当我们的存取的key到达的时候,redis会根据特定的算法得出一个结果,然后把结果对16384求余数,这样每个 key都会对应一个编号在 0-16383 之间的哈希槽,通过这个值,去找到对应的插槽所对应的节点,然后直接自动跳转到这个对应的节点上进行存取操作。
Redis Cluster 一般由多个节点组成,节点数量至少为 6 个才能保证组成完整高可用的集群,其中三个为主节点,三个为从节点。三个主节点会分配槽,处理客户端的命令请求,而从节点可用在主节点故障后,顶替主节点。
(3)优缺点
优点:无中心架构,数据按照slot分布在多个节点;
集群中的每个节点都是平等的关系,每个节点都保存各自的数据和整个集群的状态。每个节点都和其他所有节点连接,而且这些连接保持活跃,这样就保证了我们只需要连接集群中的任意一个节点,就可以获取到其他节点的数据;
可线性扩展到1000多个节点,节点可动态添加或删除;
能够实现自动故障转移,节点之间通过gossip协议交换状态信息,用投票机制完成slave到master的角色转换;
缺点:客户端实现复杂,驱动要求实现Smart Client,缓存slots mapping信息并及时更新,提高了开发难度;slave充当“冷备”,不能缓解读压力;批量操作限制,目前只支持具有相同slot值的key执行批量操作,对其他的如sunion、mset和mget等支持不是很好;
不支持多数据库空间,单机redis可以支持16个db,从db0到db15,而集群模式下只能使用一个。
综上所诉,主从模式和哨兵模式都不利于扩展,系统的高可用性都依赖于master的内存大小,哨兵模式在redis2.6开始支持,2.8稳定,cluster模式是redis可扩展的模式。
四、Redis的运用
Redis可用作数据库,高速缓存和消息队列代理,那么当你打算使用它们这些功能的时候,可以考虑一下与其他产品的对比,选出一个更好用的。
1、redis与Mysql/Oracle数据库比较
Mysql/Oracle等数据库可以将数据保存数据库当中,应用启动以后建立数据库连接就可以通过代码逻辑对数据库进行中增删改查。而Redis也是可以做为数据库来使用的,它可以看做一个key/value型数据库,Redis会根据配置定时将内存中的数据写入到硬盘中,但我们在项目中一般不会将Redis直接当作数据库来使用,主要原因在于:
(1)Redis只能存储key/value类型,虽然value的类型可以有多种,但是对于关联性的记录查询,没有Oracle/Mysql方便。
(2)Redis内存数据写入硬盘有一定的时间间隔,在这个间隔内数据可能会丢失,安全性不高。
2、redis高速缓存
redis做为高速缓存,这也是redis应用最广的地方。 对于那些经常被查询,不经常被修改和删除的数据,利用Redis缓存可以提升网站的访问速度,大大降低数据库的压力。redis作为高速缓存,带来这么大的优势的同时也存在一定的弊端,因为Redis是存放在内存中的,就会导致内存占用过高,另外持久化的代价也过高。
相比于其他的缓存工具,比如Ehcache和Memcached,开源项目使用redis的比例还是要略高一点,redis同这些缓存工具相比,有以下特征或者优势:
(1)结构简单,key/value型数据库,赋值取值方式简单。但同时它的数据结构又非常丰富,它支持字符串、哈希表、列表、集合、位图等数据类型。
(2)支持多语言集成,redis发展到今天,Redis客户端支持多种语言,包括:C、C++、C#、php、java、python、go等语言,根据自己的开发语言,选择合适的redis client版本类型即可。并且每一种语言下还包括多种类型可供选择,比如Java语言,redis client提供了诸如Jedis、Redisson、JRedis、JDBC-Redis、RJC、redis-protocol、aredis、lettuce等类型可供选择,目前比较推荐使用的是Jedis、Redisson。
(3)支持直连模式,哨兵模式(Sentinal),集群模式等,用于负载均衡和容灾,具有高可用性。
3、redis 持久化
redis的数据是存储在内存中的,如果搭载redis的服务器哪天突然心情不好,宕机不干活了,就会导致所有的缓存都丢失了。虽然可以把Redis服务器重新上线,但是由于内存的数据丢失,造成了缓存雪崩,应用服务器和数据库的压力一下子就上来了,对于一些并发很高的应用,说不动此时就导致应用崩溃无法访问。这个时候Redis的持久化功能就派上用场了,可以缓解一下缓存雪崩带来的影响。redis的持久化指的是redis会把内存的中的数据写入到硬盘中,在redis重新启动的时候加载这些数据,从而最大限度的降低缓存丢失带来的影响。
4、做为消息队列
Redis也是可以做为消息队列的,对于一些要求不高的运用场景可以使用redis,redis具备发布订阅功能。而如果专门来做消息队列处理或者要求比较,那还是选择更专业一点的Kafka、rabbitMQ等。