一、特点
- 键值(key-value)型,value支持多种不同数据结构,功能丰富
- 单线程,每个命令具备原子性
- 低延迟,速度快(基于内存、IO多路复用、良好的编码)。
- 支持数据持久化
- 支持主从集群、分片集群
- 支持多语言客户端
1、redis是单线程的,保证原子性;6.0后网络请求是多线程,但是最终的命令执行依然是单线程
2、为什么快?低延迟,速度快(基于内存、10多路复用、良好的编码、c语言)
二、安装
错误的本质是我们在开始执行make 时遇到了错误(大部分是由于gcc未安装),然后我们安装好了gcc 后,我们再执行make ,这时就出现了jemalloc/jemalloc.h: No such file or directory。这是因为上次的
编译失败,有残留的文件,我们需要清理下,然后重新编译就可以了。
默认的安装路径是在 /usr/local/bin
目录下:
redis-cli:是redis提供的命令行客户端
redis-server:是redis的服务端启动脚本
redis-sentinel:是redis的哨兵启动脚本
前台启动
指定配置启动
修改配置文件
其他配置
启动
停止服务
开机自启
现在,我们可以用下面这组命令来操作redis了:
执行下面的命令,可以让redis开机自启:
三、应用
1、全局ID生成器
一位标志位(0)+42位时间戳+21位redis自增 100年
2、缓存
缓存预热
缓存穿透 1、缓存null数据 2、布隆过滤
缓存雪崩 1、设置不同过期时间 2、redis高可用 3、多层缓存 4、缓存预热 5、降级限流
缓存击穿 1、互斥锁(性能差,有死锁风险) 2、逻辑过期
3、秒杀
秒杀 一人一单、超卖问题 三种方式:
1、乐观锁减库存,成功率低,其他判断逻辑不能保证原子性
2、分布式锁执行,性能差
3、使用lua脚本判断资格,有序异步执行数据库逻辑
3.1、放入JDK阻塞队列
- 内存溢出问题、重启队列内数据丢失问题、取出数据后执行代码逻辑出现异常
3.2、或者redis的消息队列
3.2.1、list-双向链表 模拟 队列(LPUSH+BRPOP)(RPUSH+BLPOP),B:阻塞 支持数据持久化 只支持单消费者 问题:取出数据后执行代码逻辑出现异常
3.2.2、发布订阅 pub sub(天生阻塞) ,
PUBLISH channel msg ,SUBSCRIBE channel ,PSUBSCRIBE channe* 支持多消费者,多生产者 问题:不支持数据持久化 取出数据后执行代码逻辑出现异常 消息堆积有上限,超出时数据丢失
3.2.3、stream redis5.0后引入的一种新的数据类型,可以实现一个功能完善的消息队列 XADD s1 * k1 v1 k2 v2 发送消息,*表示使用redis自增id XLEN s1 查看消息数量 XREAD 读取消息,读完不会删除 消息可回溯 支持数据持久化 支持多消费者 可以阻塞读取 有消息漏读问题
3.2.4、stream-消费者组 :将多个消费者划分到一个组,监听同一个队列 消息分流:队列中消息会分流给组内的不同消费者,而不是重复消费,加快消息处理速度 消息标志:消费者组会维护一个标志,记录最后一个被处理的消息,消费者重启后,会从标志之后读取消息,避免消息漏读 消息确认:消费者获取消息后,消息处于pending状态,并存入一个pending-list(在redis中) 当处理完成后需要通过XACK来确认消息,标记消息为已处理,才会从pending-list移除。 XGROUP CREATE key groupname ID XREADGROUP GROUP XACK KEY group ID XPENDING
4、点赞和关注
大V 普通 僵尸粉-活跃粉丝 , 拉取关注的用户发布的内容,sortedSet 滚动分页查询,按照时间戳倒序排序。 因为查完第一页后,可能会新增数据,所以不能用索引来查,所以用score存时间戳,用时间戳筛选数据 ZREVRANGEBYSCORE key max min WITHSCORES LIMIT offset count max:第一次查询时,max=当前时间戳;当前查询的score的最大值,在本业务中即上一次排序列表中的最后一个元素的score-时间戳; min=0 不变 offset:第一次查询时,为0;后面查询时,offset为上一次查询结果中,与最后一个元素的score相等的元素个数,即跳过这些元素,避免重复显示 count=3 不变,每页查多少数据
5、附近商户-地理坐标
GEO数据结构,底层就时一个sortedset,经纬度转换为score GEOADD:添加一个地理空间信息,包含:经度(longitude)、纬度(latitude)、值(member) GEOADD g1 116.42803 39.903738 bjz 116.322287 39.893729 bjx GEODIST:计算指定的两个点之间的距离并返回 GEODIST g1 bjx bjz km GEOHASH:将指定member的坐标转为hash字符串形式并返回 GEOPOS:返回指定member的坐标 GEOPOS g1 bjz GEORADIUS:指定圆心、半径,找到该圆内包含的所有member,并按照与圆心之间的距离排序后返回。6.2以后已废弃 GEOSEARCH:在指定范围内搜索member,并按照与指定点之间的距离排序后返回。范围可以是圆形或矩形。6.2.新功能 GEOSEARCH g1 FROMMEMBER bjx BYRADIUS 300 km ASC WITHDIST 默认升序 GEOSEARCH g1 FROMLONLAT 116 39 BYRADIUS 300 km ASC WITHDIST GEOSEARCHSTORE:与GEOSEARCH功能一致,不过可以把结果存储到一个指定的key。 6.2.新功能
6、用户签到
BitMap - 位图 - 假设一次签到数据库中生成一行,每行占22字节,那么1000万个用户签到一个月=非常大的内存和行数 BitMap把每天签到与否抽象为bit的0或1,一个月31天,4个字节就能存下 BitMap利用redis的String类型数据结构(key-value),最大上限为512M,转为bit为2^32bit key为用户id:月份,value为bit转换成的string SETBIT key offset value –value为0或1 GETBIT key offset BITCOUNT key [start end] 从0开始,统计一个月内签到次数 BITFIELD查询、BITOP位运算、BITPOS查找第一个出现的位置 连续签到次数:从最后一次签到开始向前统计 BIFIELD key GET u5 0 ,获取0号到5号的所有签到数据,u表示返回无符号数 // num为取出签到数据bit转换成的十进制数 int count = 0; while (true) { // 6.1.让这个数字与1做与运算,得到数字的最后一个bit位 // 判断这个bit位是否为0 if ((num & 1) == 0) { // 如果为0,说明未签到,结束 break; } else { // 如果不为0,说明已签到,计数器+1 count++; } // 把数字右移一位,抛弃最后一个bit位,继续下一个bit位 num »>= 1; }
7、UV PV统计
HyperLogLog UV:Unique Visitor ,浏览网页的自然人,一天内同一个用户访问多次,只记录一次 PV:Page View,页面访问量,用户多次打开页面,记录多次 HyperLogLog:基于LogLog算法,用于确定非常大的集合的基数,而不需要存储所有值;伯努利实验,抛硬币 基于redis中的string结构实现,单个HLL内存永远小于16KB,测量结果有小于0.81%的误差,对于UV统计来说可以忽略 PFADD key element [element …] 添加 PFCOUNT key [key …] 统计数量 PFMERGE destkey sourcekey [sourcekey …] 合并 HyperLogLog存储数据天生是唯一的,适合做UV
8、分布式锁
redlock和mutilock 某台节点时钟漂移
四、分布式
单点问题:
- 数据丢失问题 – redis持久化
- 并发能力 - 主从,读写分离
- 存储空间 - 分片集群,利用插槽机制实现动态扩容
- 单点故障 -redis哨兵,健康监测和自动恢复