Redis使用指南
引言
Redis是一个开源的、高性能的(key-value)分布式内存数据库,基于内存上运行。
Redis是单进程多路IO复用模型每秒写8万次,读11万次。
Redis能干嘛?
可以用作数据库、缓存和消息中间件MQ。
- 持久化数据
- 缓存
- 发布订阅系统
- 计时器、计数器(浏览量)
- 地图信息分析
- …
数据共享
性能测试
redis-benchmark(官方自带的性能测试工具!)
1 | # 测试:100个并发连接 100000请求 |
命令
命令不区分大小写
1 | #切换数据库 |
String
1 | > set name kuangshen # 设置值 |
使用场景:
String类似的使用场景:value除了是我们的字符串还可以是我们的数字!
计数器
统计多单位的数量
粉丝数
对象缓存存储!
List
lpush
rpush
lrang
lpop
rpop
1 | > lpush list one # 将一个值或者多个值,插入到列表头部 (左) |
如果移除了所有值,空链表,也代表不存在!
使用场景:
消息队列 (Lpush Rpop), 栈( Lpush Lpop)!
Set
1 | > sadd myset "hello" # set集合中添加匀速 |
使用场景
- 推荐系统:微博,B站,共同关注!(并集) 数字集合类 差集 - 交集 - 并集
- 随机事件:抽奖 - srandmember命令
注: 当数据较大时,成本高、效率低;生产中单独实例部署,避免影响其他操作;
Hash
1 | > hset myhash field1 kuangshen # set一个具体 key-vlaue |
使用场景:
聚合场景,更适合于对象的 存储 如:商品详情页、用户信息之类的,经常变动的信息!
Zset
在set的基础上,增加了一个score值,用于比较排序。
1 | > zadd myset 1 one # 添加一个值 |
使用场景:
- 普通消息,重要消息。
- 取Top N 排行榜应用实现 or 评论排行(用时间做分值)
三种特殊数据类型
Geospatial
Redis 的 Geo 在Redis3.2 版本就推出了! 这个功能可以推算地理位置的信息,两地之间的距离,方圆 几里的人!
可以查询一些测试数据:http://www.jsons.cn/lngcodeinfo/0706D99C19A781A3/
只有 六个命令:
1 | # getadd 添加地理位置 |
- GEO 底层的实现原理其实就是 Zset!我们可以使用Zset命令来操作geo!
1 | > ZRANGE china:city 0 -1 # 查看地图中全部的元素 |
Hyperloglog
Redis 2.8.9 版本就更新了 Hyperloglog 数据结构!
Redis Hyperloglog 基数(不重复的元素)统计的算法;
优点:占用的内存是固定,2^64 不同的元素的技术,只需要 12KB 内存!如果要从内存角度来比较的 话 Hyperloglog 首选!
缺点:有误差,0.81%! 如果允许容错,那么一定可以使用 Hyperloglog ! 如:统计UV任务!
1 | > pfadd mykey a b c d e f g h i j # 创建第一组元素 mykey |
使用场景:
网页的 UV (一个人访问一个网站多次,但是还是算作一个人!)
Bitmap
都是操作二进制位来进行记录,就只有0 和 1 两个状态
可以用两个状态区分的,都可以使用 Bitmaps!
统计用户信息,活跃,不活跃! 登录 、未登录! 打卡,365打卡! 365 天 = 365 bit 1字节 = 8bit 46 个字节左右!
1 | > setbit sign 3 1 # 设置指定位置的值 |
架构
事务
Redis事务没有没有隔离级别的概念!
Redis单条命令式保存原子性的,但是事务不保证原子性!
Redis 事务本质:一组命令的集合! 一个事务中的所有命令都会被序列化,在事务执行过程的中,会按照顺序执行!
redis的事务:
开启事务(multi)
命令入队(……)
执行事务(exec)
取消事务(discard) //事务队列中命令都不会被执行!
编译型异常(代码有问题! 命令有错!) :事务中所有的命令都不会被执行!
eg: 错误的命令格式
运行时异常: 如果事务队列中存在语法性,那么执行命令的时候,其他命令是可以正常执行的,错误命令抛出异常!
eg: value类型不对
Watch监控 ==> 面试常问
- 悲观锁: 很悲观,认为什么时候都会出问题,无论做什么都会加锁!
- 乐观锁: 很乐观,认为什么时候都不会出问题,所以不会上锁! 更新数据的时候去判断一下,在此期间是否 有人修改过这个数据,获取version,更新的时候比较 version。
1 | 127.0.0.1:6379> set money 100 |
如果修改失败,获取最新的值就好
Redis主从复制、读写分离
1 | > info replication # 查看当前库的信息 |
测试主机
主机断开连接,从机依旧连接到主机的,但是没有写操作,这个时候,主机如果回来了,从机依旧可以直接获取到主机写的信息!
如果是使用命令行,来配置的主从,这个时候如果重启了,就会变回主机!只要变为从机,立马就会从主机中获取值!
复制3个配置文件,然后修改对应的信息
1、端口
2、pid 名字
3、log文件名字
4、dump.rdb 名字
复制原理
- Slave 启动成功连接到 master 后会发送一个sync同步命令
- Master 接到命令,启动后台的存盘进程,同时收集所有接收到的用于修改数据集命令,在后台进程执行完毕之后,master将传送整个数据文件到slave,并完成一次完全同步。
全量复制: 而slave服务在接收到数据库文件数据后,将其存盘并加载到内存中。
增量复制: Master 继续将新的所有收集到的修改命令依次传给slave,完成同步
但是只要是重新连接master,一次完全同步(全量复制)将被自动执行! 我们的数据一定可以在从机中 看到!
哨兵模式
(自动选举老大的模式)
这里的哨兵有两个作用
通过发送命令,让Redis服务器返回监控其运行状态,包括主服务器和从服务器。
当哨兵监测到master宕机,会自动将slave切换成master,然后通过发布订阅模式通知其他的从服 务器,修改配置文件,让它们切换主机。
假设主服务器宕机,哨兵1先检测到这个结果,系统并不会马上进行failover过程,仅仅是哨兵1主观的认 为主服务器不可用,这个现象成为主观下线。当后面的哨兵也检测到主服务器不可用,并且数量达到一 定值时,那么哨兵之间就会进行一次投票,投票的结果由一个哨兵发起,进行failover[故障转移]操作。 切换成功后,就会通过发布订阅模式,让各个哨兵把自己监控的从服务器实现切换主机,这个过程称为 客观下线。
设置哨兵
- 配置哨兵配置文件 sentinel.conf
1 | # sentinel monitor 被监控的名称 host port 1 |
- 启动哨兵
kconfig/sentinel.conf
注:如果主机此时回来了,只能归并到新的主机下,当做从机,这就是哨兵模式的规则!
优点:
- 哨兵集群,基于主从复制模式,所有的主从配置优点,它全有
- 主从可以切换,故障可以转移,系统的可用性就会更好 3、哨兵模式就是主从模式的升级,手动到自动,更加健壮!
缺点: - Redis 不好啊在线扩容的,集群容量一旦到达上限,在线扩容就十分麻烦! 2、实现哨兵模式的配置其实是很麻烦的,里面有很多选择!
哨兵模式的全部配置!
1 | # Example sentinel.conf |
其他
SpringBoot整合
在 SpringBoot2.x 之后,原来使用的jedis 被替换为了 lettuce?
- jedis : 采用的直连,多个线程操作的话,是不安全的,如果想要避免不安全的,使用 jedis pool 连接 池! 更像 BIO 模式
- lettuce : 采用netty,实例可以再多个线程中进行共享,不存在线程不安全的情况!可以减少线程数据 了,更像 NIO 模式
Redis发布订阅
Redis 通过 PUBLISH 、SUBSCRIBE 和 PSUBSCRIBE 等命令实现发布和订阅功能。
1 | > SUBSCRIBE kuangshenshuo # 订阅一个频道 kuangshenshuo |
1 | > PUBLISH kuangshenshuo "hello,kuangshen" # 发布者发布消息到频道! |
发布和订阅机制的底层实现
通过 SUBSCRIBE 命令订阅某频道后,redis-server 里维护了一个字典,字典的键就是一个个 频道!, 而字典的值则是一个链表,链表中保存了所有订阅这个 channel 的客户端。SUBSCRIBE 命令的关键, 就是将客户端添加到给定 channel 的订阅链表中。
通过 PUBLISH 命令向订阅者发送消息,redis-server 会使用给定的频道作为键,在它所维护的 channel 字典中查找记录了订阅这个频道的所有客户端的链表,遍历这个链表,将消息发布给所有订阅者。
Pub/Sub 从字面上理解就是发布(Publish)与订阅(Subscribe),在Redis中,你可以设定对某一个 key值进行消息发布及消息订阅,当一个key值上进行了消息发布后,所有订阅它的客户端都会收到相应 的消息。这一功能最明显的用法就是用作实时消息系统,比如普通的即时聊天,群聊等功能。
使用场景:
- 实时消息系统!
- 事实聊天!(频道当做聊天室,将信息回显给所有人即可!)
- 订阅,关注系统都是可以的!
稍微复杂的场景我们就会使用 消息中间件 MQ