是什么
为什么要:
一开始是web/server/mysql结构, 随着数据量增加,业务场景不断扩充。
数据表从单表演化为分库分表。
【数据量增长、读写数据压力不断增加】(一台MySQL速度跟不上),【mysql从单机到集群】(出现集群)
一主MySQL多从MySQL
主负责写,从负责读。
秒杀、高qps情况下MySQL作实时查询支撑不住。
考虑从内存读取数据,把数据存到内存,redis应运而生。
数据分冷热数据,(经常访问的)热数据存到内存中。
读场景:浏览器发起的请求,来到服务器端,服务器判断数据在redis(内存)中是否在,存在返回一个用户。不存在,去MySQL中读取数据,再回写到redis中
【回写到redis中】
写场景:一般有两种方式,此处为一种。
go/Java服务端先写入MySQL数据,MySQL会产生监听binlog,记录MySQL中数据变更。
很多开源框架可以反解binlong,解析到数据变更后,再把数据变更写到redis里。
基本原理
内存中数据,服务器重启后数据会丢失。
redis数据的特征:一定程度的持久化。重启不会丢失。
如何保证数据不会丢失
redis基本结构:
客户端/Java/go程序读写redis数据时,走的是RESP协议。
协议传到redis服务端,服务端收到请求就把数据读写到内存中。
其实在读写到内存之前,会产生一条日志【叫(appendonly.aof)AOF文件】,写到磁盘文件上
AOF:append of field 把新数据追加到文件末尾。
如果服务器宕机,redis重启的时候会读取aof文件,重放完aof中的命令后才会拉起redis服务。数据不会丢失。
RDB文件(是二进制的文件):保存了当前redis实例的所有的[key信息/文件]。
整个启动过程,先读取RDB文件,再去对比RDB之后有没有未执行的命令 如果有就会把AOF没有执行的命令加载进去
redis是单线程处理所有操作命令
多命令进入,排队处理
案例
连续签到
如何归零:用到redis的过期。 设置过期时间。
数据结构
为什么要学数据结构:实际开发中,重视基础。 比如用到key/value存储的功能时,设计时为什么用这个数据结构?为什么用这个数据结构会提升性能,压缩存储?
go的string比较特殊:
是二进制安全的数据,实际存储二进制数据。
- 存储时足够节省空间
- 很快读数据
- 字符变更时很快把数据写进去
注意事项
sds
实际分四段。
len:字符串的容量长度 alloc:存储的长度 flags: buffer:实际存储位置
寻址的时候get一个key,key指针会指到这,先左移得到flags知道当前存的是什么数据类型。就知道指针向左移几位是元信息。左移一个是字符串长度“向右移动指针移几位”。
Redis基本操作
2.3.1 熟悉以下命令的操作
- GET/SET/DEL/INCR/SETNX
- HSET/HGET/HINCRBY
- LPUSH/RPOP/LRANGE
- ZADD/ZRANGEBYSCORE/ZREVRANGE/ZINCRBY/ZSCORE
消息通知
redis的list其实是quicklist
双向链表+listpack。
listpack的结构:第一个字节记录,整个内存空间大小,右移一个字节得知存了几个元素,
哈希数据结构
速度参考:
一个qps,在mysql中count的10000行,需要十多ms。百万级别没法count
如果存到redis里查询,2ms就可以。
pipelining
redis中一次设置或者get多个key时,如果用多个redis链接,很磨叽,用pipelining。减少网络上的来回传输。
写
初始化pipelining,把三条命令打包set到pipelining。之后go客户端会把三条命令一次性发到服务器
读
Hmget
HGetAll
改数据/增加
redis有increase命令。
哈希也有增加哈希表中一个元素的值,调用incr__byfield.
redisclient.HIncrBy()方法。
哈希结构
为什么rehash?
在扩容的同时,又要保证redis正常响应,不能阻塞redis的访问。数据迁移,先扩容,再拷贝。
渐进式:把拷贝过程,平摊到每次用户访问过程中,迁移一部分数据。
原H0,新H1.
用户访问H0的元素时,顺带迁移到H1中。
最后H0指针指向H1,H1指针置空。
ZSET
用例:天梯榜单。【高qps下更新数据,且排序】
添加榜单 ZADD
ZRANGEBYSCORE 查看积分
ZREVRANGE 倒排序
ZINCRBY
ZSCORE get命令对应方法
zset数据结构
zskiplist跳表.
找7找3
head--3--7
head--3--1
redis的zset用的是哈希+跳表。
可以由排名跳表指针查元素的哈希kv 也可由key反哈希差跳表排名
跳表一般不会超过4层。
构成的是双向链表
限流
用key字段,后面带有时间戳(数字部分)。
时间戳最小单位为1s,规定1s内的请求数n
多次用到increase命令,通过一个请求就+1,请求数小于n,放行。超过n时,限流