Redis - 大厂程序员是怎么用的
大数据量下mysql读写数据压力增加,希望从内存读取数据
- 写数据时,增量数据保存到磁盘上的AOF文件
- 全量数据RDB文件:包含所有数据
先读取RDB,看之后有没有没执行的命令,如果有,则加载AOF文件
redis的操作是单线程的,需要排队,先进先出
go导入redis包
go get github.com/go-redis/redis
import "github.com/go-redis/redis"
redis案例
1.连续签到
Key: cc_uid_1165894833417101
value: 252
expireAt:后天的O点
RedisClient.Incr()使原有值+1
2.消息通知 list队列
消息队列list:向队列中放入文章,只要里面有文章就会pop出来通知给ES数据库。
list的数据结构是Quicklist,是一个双向链表,每个节点的entry是一个listpack结构,包含许多元素、每个元素的长度
3.计数 哈希
一个用户的多项计数需求可使用hash结构存储,读很快。map[user_id]=struct{属性1,属性2...}。
读:hgetall命令。
写:使用流水线pipeline将多条数据一次性写redis
数值加一:RedisClient.HIncrBy()
hash的数据结构是dict,是一个单项链表,每个节点下面又有一个单向链表,相当于一个桶。桶0空间不够时需要扩容,使用rehash操作将其中数据全部迁移到另一个桶1中,也可使用渐进式rehash将部分数据迁移,性能更好
4.排行榜 zset
对大量数据(千万级别)进行排序,数据变化后排序,使用zset有序集
zset使用数据结构跳表(zskiplist)+哈希,跳表每个元素是哈希表的一个桶
- zadd:添加元素到集合
- zrange:返回正序的集合
- zrevrange:返回倒序的集合
- zrank:返回有序集合中指定成员的排名
- zscore:返回有序集中指定成员的分数值
5.限流
要求一秒内放行n个请求,超过n的无法访问
构建map[时间戳]=cnt,cnt>n禁止访问
6.分布式锁 SetNX
并发场景,要求一次只能有一个协程执行。执行完成后,其它等待中的协程才能执行。
redis的SetNX实现加锁、完成业务、释放锁,但不是高可用分布式锁
redis注意事项
1.大key和热key
(1)大key:value>10KB,读取成本高,容易导致慢查询(过期、删除),主从复制异常,服务阻塞。
处理:
- 大key拆分成小key
- 压缩:将value压缩后写入redis
- 冷热数据分离:热门的放在zset,其他放在db
(2)热key:QPS超过500
处理:
- 在redis cache前面再加一层LocalCache
- 拆分key,代价是更新时需要更新多个key,存在数据短暂不一致的风险
- 使用redis代理
2.慢查询
- pipeline一次不要传超过100个key
- zset不要大小超过5KB
- 对大key的删除和过期操作
3.缓存穿透:热点数据没查缓存,直接查了db。 原因:查询缓存中一定不存在的数据、缓存过期。 解决:缓存空值;布隆过滤器压缩key值,快速判断key是否存在
缓存雪崩:大量缓存同时过期 解决:将缓存失效时间分散开;使用缓存集群