官方网站:https://redis.io/
基础教程:https://www.runoob.com/redis/redis-tutorial.html
场景解决方案:http://www.redis.cn/articles.html
一、功能介绍:
应用场景与最佳实战:http://www.redis.cn/articles/20160726002.html
1.缓存
redis使用内存做数据读写,速度快,效率高。
还可以给数据库减负:https://mp.weixin.qq.com/s?__biz=MzU1MzE2NzIzMg==&mid=2247485727&idx=1&sn=319e4c967c3d27ffd1d90db8ff5d1f15&chksm=fbf7b9f0cc8030e6a90ca223409d29d719766bda3d6ca67f4f8db693ea6e865efa344db4ef29&mpshare=1&scene=23&srcid=0726S7HTxGItY2fjbNQCeaUh%23rd
2.数据库
redis有两种持久化方式,可以选择性开启。
方式一:RDB,将数据写入到磁盘;
方式二:AOF,将对数据进行操作的命令写入到磁盘。
由于AOF持久化的实时性更好,即当进程意外退出时丢失的数据更少,因此AOF是目前主流的持久化方式。
3.消息机制
3.1 消息队列
基于reids的List数据类型,由于Redis的列表是使用双向链表实现的,保存了头尾节点,所以在列表头尾两边插取元素都是非常快的。
3.2 发布/订阅
基于redis的发布/订阅功能。
注:redis的发布订阅并没有持久化机制,只适用于数据安全性不高或者有容错机制的场景。如果对数据安全高的场景应该使用kafka和rabbitmq。
二、常用场景:
参考网址:https://wenku.baidu.com/view/5d21d28c185f312b3169a45177232f60ddcce7c6.html
三、安装教程
3.1单机安装教程:
Windows、centos、ubuntu:
https://www.runoob.com/redis/redis-install.html
3.3官方cluster版本的集群介绍
Redis Cluster是社区版推出的Redis分布式集群解决方案,主要解决Redis分布式方面的需求,比如,当遇到单机内存,并发和流量等瓶颈的时候,Redis Cluster能起到很好的负载均衡的目的。Redis Cluster集群节点最小配置6个节点以上(3主3从),其中主节点提供读写操作,从节点作为备用节点,不提供请求,只作为故障转移使用。Redis Cluster采用虚拟槽分区,所有的键根据哈希函数映射到0~16383个整数槽内,每个节点负责维护一部分槽以及槽所印映射的键值数据。
优点:
1、无中心架构
2、数据按照slot存储分布在多个节点,节点间数据共享,可动态调整数据分布。
3、可扩展性,可线性扩展到1000多个节点,节点可动态添加或删除。
4、高可用性,部分节点不可用时,集群仍可用。通过增加Slave做standby数据副本,能够实现故障自动failover,节点之间通过gossip协议交换状态信息,用投票机制完成Slave到Master的角色提升。
5、降低运维成本,提高系统的扩展性和可用性。
缺点:
1、Client实现复杂,驱动要求实现Smart Client,缓存slots mapping信息并及时更新,提高了开发难度,客户端的不成熟影响业务的稳定性。目前仅JedisCluster相对成熟,异常处理部分还不完善,比如常见的“max redirect exception”。
2、节点会因为某些原因发生阻塞(阻塞时间大于clutser-node-timeout),被判断下线,这种failover是没有必要的。
3、数据通过异步复制,不保证数据的强一致性。
4、多个业务使用同一套集群时,无法根据统计区分冷热数据,资源隔离性较差,容易出现相互影响的情况。
5、Slave在集群中充当“冷备”,不能缓解读压力,当然可以通过SDK的合理设计来提高Slave资源的利用率。
6、key批量操作限制,如使用mset、mget目前只支持具有相同slot值的key执行批量操作。对于映射为不同slot值的key由于keys 不支持跨slot查询,所以执行mset、mget、sunion等操作支持不友好。
7、key事务操作支持有限,只支持多key在同一节点上的事务操作,当多个key分布于不同的节点上时无法使用事务功能。
8、key作为数据分区的最小粒度,因此不能将一个很大的键值对象如hash、list等映射到不同的节点。
9、不支持多数据库空间,单机下的redis可以支持到16个数据库,集群模式下只能使用1个数据库空间,即db 0。
10、复制结构只支持一层,从节点只能复制主节点,不支持嵌套树状复制结构。
11、避免产生hot-key,导致主库节点成为系统的短板。
12、避免产生big-key,导致网卡撑爆、慢查询等。
13、重试时间应该大于cluster-node-time时间
14、Redis Cluster不建议使用pipeline和multi-keys操作,减少max redirect产生的场景。
3.2集群搭建教程(官方cluster版本):
在Docker中进行安装:https://www.cnblogs.com/cxbhakim/p/9151720.html (该方式采用redis自带的cluster 指令进行 集群节点的加入)
该教程中包括了手动使用cluster命令进行主从配置的方法。
redis哨兵机制,实现故障恢复自动化:http://www.redis.cn/articles/20181020001.html
在ubuntu中进行安装:https://www.cnblogs.com/bingshu/p/8490737.html (该方式采用 ruby 脚本,自动化集群搭建,实际仍然是采用 redis官方自带的 cluster指令)
issue:在Docker中配置文件中将守护进程设置为了 no ? 与unbuntu中的配置方式不同? 是否是导致docker中的集群无法被spring-boot客户端连接的原因?待解决…
如果不设置为守护进程,那么Redis只能前端启动,前端关闭,就会失效,不能作为隐藏式的服务。
四、Redis测试
4.1 集群读写散列测试
连接集群(单机模式)
实验结果:非集群连接,无法移动到计算后的插槽位,报错。
连接集群(集群模式)
实验结果:集群连接,移动到计算后的插槽位,正常。
4.2主从测试
主从读写测试:
2号服务器里面的key = aaa 的数据,在其从机 7005 中也存在
主从自动替换测试:
先关闭一台Redis(redis-cli shutdown)服务器,在查询Redis集群(cluster info),可以查询到从机自动替换。(从机冷备)
4.4 性能测试工具:
使用redis-benchmark命令
https://www.runoob.com/redis/redis-benchmarks.html
注: redis-benchmark非redis客户端的内部指令,其本身在redis/src目录下,ubuntu中安装的reids-tools工具中也包含了redis-benchmark命令,可直接在其他目录下操作。
测试命令:redis-benchmark -h ip地址 -h 端口号 -n 请求数 -q -d 测试字节数 -c 并发数
例如:测试100个并发量,请求数为1万,字节数1024 即1kb数据的redis性能。
redis-benchmark -h 10.86.196.192 -p 7001 -q -n 10000 -d 1024 -c 100
实验结果(结果测试项解释):
测试项(每秒钟请求数) 单机 集群
SET:将字符串值value关联到key 85470.09 119047.62
GET:返回key所关联的字符串值,如果key存储的值不是字符串类型,返回一个错误 102040.82 125000.00
INCR:将key中存储的数字值增一。不能转换为数字则报错; 95238.10 126582.27
LPUSH:将一个或多个值value插入到列表key的表头; 107526.88 74074.07
RPUSH:将一个或多个值value插入到列表key的表尾; 90909.09 89285.71
LPOP:移除并返回列表key的头元素; 86206.90 81967.21
RPOP:移除并返回列表key的尾元素; 92592.59 102040.82
SADD:将一个或多个member元素加入到集合set当中,已经存在于集合的member元素将被忽略; 113636.37 119047.62
HSET: 109890.11 112359.55
SPOP:移除并返回集合中的一个随机元素; 111111.11 111111.11
LPUSH:将一个或多个value插入到列表key的表头; 99009.90 86956.52
LRANGE_100:返回列表key中指定区间内的元素,前100条元素; 10683.76 12903.23
LRANGE_300:返回列表key中指定区间内的元素,前300条元素; 3518.65 3511.24
LRANGE_500:返回列表key中指定区间内的元素,前500条元素; 2151.93 2204.10
LRANGE_600:返回列表key中指定区间内的元素,前600条元素; 1558.85 1509.43
MSET:同时设置一个或多个key-value对,value为字符串。 68027.21 100000.00
4.5 性能问题排查:
五、高可用
在Web服务器中,高可用是指服务器可以正常访问的时间,衡量的标准是在多长时间内可以提供正常服务(99.9%、99.99%、99.999%等等)。但是在Redis语境中,高可用的含义似乎要宽泛一些,除了保证提供正常服务(如主从分离、快速容灾技术等),还需要考虑数据容量的扩展、数据安全不会丢失等。
在Redis中,实现高可用的技术主要包括持久化、复制、哨兵和集群,下面分别说明它们的作用,以及解决了什么样的问题:
1.持久化:持久化是最简单的高可用方法,有时甚至不被归为高可用的手段,主要作用是数据备份,即将数据存储在硬盘,保证数据不会因进程退出而丢失。
2.复制:复制是高可用Redis的基础,哨兵和集群都是在复制基础上实现高可用的。复制主要实现了数据的多机备份以及对于读操作的负载均衡和简单的故障恢复。缺陷是故障恢复无法自动化、写操作无法负载均衡、存储能力受到单机的限制。
3.哨兵:在复制的基础上,哨兵实现了自动化的故障恢复。缺陷是写操作无法负载均衡、存储能力受到单机的限制。
4.集群:通过集群,Redis解决了写操作无法负载均衡以及存储能力受到单机限制的问题,实现了较为完善的高可用方案。
5.1 持久化技术及方案选择
5.2 Redis Sentinel 高可用实现说明
http://www.redis.cn/articles.html
5.3 集群搭建与选择
5.3.1Redis 集群方案介绍
5.3.2 集群搭建模式方案选取
5.4 总结: Redis高可用技术优缺点
https://mp.weixin.qq.com/s/BoLsVKYyu8yRXZbxd1uuQw
六、JAVA spring-boot使用Redis
目前遇到的问题:
springBoot低版本比如1.4.2版本的jedis不支持集群中redis附有密码的模式。(启动报错:无权限验证!)
解决方案:(https://blog.csdn.net/ldy1016/article/details/80998687)
1.单独提升Spring-Boot的版本,升级到1.5.2或更高
2.单独提升Spring-Boot中的jedis和spring-data-redis包的版本,若jedis版本是2.8.x,spring-data-redis的版本是1.7.x,则将其单独提升到jedis版本是2.9.x,spring-data-redis的版本是1.8.x。
客户端序列化问题
7、应用场景下的问题
7.1 穿透和雪崩
穿透和雪崩都会导致后端数据库由于请求量过大,而导致崩溃。
击穿:主要是Redis服务正常,但是请求了大量缓存中不存在的数据。(通常是恶意攻击,或者是业务逻辑错误)
雪崩:主要是Redis服务突然宕机,导致大量请求只能去后端数据库获取数据。
缓存穿透及解决方案:
https://mp.weixin.qq.com/s?__biz=MzAwMDU1MTE1OQ==&mid=2653548432&idx=1&sn=ac120e1ffca7c2007c0bc5df51e03d7b&chksm=813a7e08b64df71ec7b8b6afc2a36a8ff1d780db54a395b58a9f18f084080c09de514e999834&mpshare=1&scene=1&srcid=0324u7jGCykTaFZPCCIrwBwU&key=8b1ec02b44dde3bc9a71dc40c489a145b0da63c71eaf9c1d9df4cf551f5896a6f3cab0a9797a85474ef4a63941b24a40f90bcef85195aab7fa0e3667f2ceda40b5d1758c9b33fed9d819a3ee7766bc62&ascene=0&uin=MzM4Njg2NDU1&devicetype=iMac+MacBookPro12%2C1+OSX+OSX+10.10.3+build(14D136)&version=11020201&pass_ticket=vKWb90vuWopMvZ8u8BmZrit4a4GPlHhnzGmcasQ3RnDZlOYPt0O9QqwIDnzcKArU
7.2 缓存并发
详情:多个客户端同时设置相同的key,而由于内核采用单线程处理数据的redis只能处理一个命令,导致其他客户端后设置的值,将前面设置的值给覆盖掉了。
由于CPU选择性执行,多个请求的再次执行顺序是不确定的,因此缓存中的数据取决于最后一个被执行的那个请求,而不是最后一个到来的那个请求。因此导致有可能得不到正确数据。
分析:不推荐使用redis的事务机制。因为我们的生产环境,基本都是redis集群环境,做了数据分片操作。一个事务中有涉及到多个key操作的时候,这多个key不一定都存储在同一个redis-server上。因此,redis的事务机制,十分鸡肋。
解决方案:如下所示
(1)如果对这个key操作,不要求顺序
这种情况下,准备一个分布式锁,大家去抢锁,抢到锁就做set操作即可,比较简单。
(2)如果对这个key操作,要求顺序
假设有一个key1,系统A需要将key1设置为valueA,系统B需要将key1设置为valueB,系统C需要将key1设置为valueC.
期望按照key1的value值按照 valueA–>valueB–>valueC的顺序变化。这种时候我们在数据写入数据库的时候,需要保存一个时间戳。假设时间戳如下
系统A key 1 {valueA 3:00}
系统B key 1 {valueB 3:05}
系统C key 1 {valueC 3:10}
那么,假设这会系统B先抢到锁,将key1设置为{valueB 3:05}。接下来系统A抢到锁,发现自己的valueA的时间戳早于缓存中的时间戳,那就不做set操作了。以此类推。
其他方法,比如利用队列,将set方法变成串行访问也可以。