目录
redis常用的数据类型
String、Set、ZSet、List、Hash,是比较常见的数据类型。
http://www.redis.cn/commands.html 官网文档对命令进行了说明,使用时可以直接去查。
除了一些基本的命令之外,应该掌握这些类型的应用场景。
- String 类型:可以用作一些基本的数据信息的缓存,也可以用做简单的计数。
- Set类型:set可以用作去重。set 集合的运算,可以用来做共同好友、好友推荐等等。
- Zset类型:有序集合,可以用作排序,比如热搜榜单等等。
- List类型:可以当作队列、栈,可以存储相同的元素。列表是有序的,还可以按区间取值,可以用作文章列表。
- Hash类型:key map形式,本质和String没有区别,是一个简单的key-value形式。
除此之外,还有HyperLogLog、Geospatial、Bitmap
- HyperLogLog可以用作基数(就是不重复元素的个数)统计,结果是一个估计值,有一定误差,并非准确值。HyperLogLog的内存占用量是很小的,不会超过12K。可以用作页面访问量的统计。对于页面访问量的统计,重要的是有多少访问量,而不是把访问的来源信息进行存储,所以使用HyperLogLog比Set更有优势。
- Geospatial可以用做经纬度距离的计算,geohash值的转换等等。可以用在附近的人,物体距离计算等场景。
- Bitmap位图,只有0和1两种状态。可以表示登录态、活跃态等常见的两种状态的场景。
单线程与多线程
因为redis是基于内存的操作,所有速度很快,单线程完全可以满足需求,单线程免去了上下文之间的切换,也不会因此消耗cup资源,单线程就不会有对数据操作产生的竞争,就不用去考虑加锁的问题,就不会出现死锁的现象。
单线程有这么多的优势,但是在redis6版本之后,还是引入了多线程,但是也不是各个方面都是用多线程,在指令执行的时候,还是使用单线程,这样省去了很多麻烦,在完全可以满足需求的情况下,使redis更简洁,不需要取考虑多线程并发的问题。
在读写网络时候,redis的单线程会耗费较多的时间,将这部分设计成多线程,是对redis的一个优化
除此之外,在UNLINK、FLUSHALL ASYNC 和 FLUSHDB ASYNC删除操作引入了多线程,有的元素可能非常大,进行删除的时候会耗费一定量的时间,多线程下,减少了对主线程阻塞的时间,执行提高效率。
redis中的事务
redis中的事务可以看作是一组命令的集合,其中的命令会按照顺序执行,redis的事务没有隔离级。
如果在执行一组命令的时候,出现了指令错误,会导致所有的指令都不会被执行,如果出现了逻辑错误,那只有这一条指令不会被执行,其余的都会被执行成功。所有redis的事务不能保证原子性。
redis其实是一个乐观锁机制,在执行一组事务的时候,允许其他操作对数据进行操作修改,可以通过watch监控数据的版本,进行校验数据是否被修改,如果被修改,则事务执行失败。
127.0.0.1:6379> set money 1000
OK
127.0.0.1:6379> watch money
OK
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> INCRBY money 1000
QUEUED
另起一个窗口,在执行完watch之后,执行
127.0.0.1:6379> INCRBY money 2000
(integer) 3000
此时执行exec命令之后,返回nil,表示没执行成功, 这是因为,在操作的时候,发现前后数据被修改了,所以执行失败
127.0.0.1:6379> DECRBY money 200
QUEUED
127.0.0.1:6379> EXEC
(nil)
unwatch、discard、exec命令之后都会释放锁,或者在执行出错的时候也会释放锁。
redis配置文件
虽然实际工作中,一般不会去修改配置文件,但是了解配置文件,会明白为什么redis会这么执行,为什么要这么配置。
redis的配置文件是大小写不敏感的。
可以引用其他配置
网络配置
bind 127.0.0.1 绑定地址,在配置redis集群时,需要绑定多个ip和端口
protected-mode yes 安全模式,默认开启
port 6379 端口号
通用设置
supervised no 守护进行,后台运行
pidfile /var/run/redis_6379.pid 如果开启,就要指定pid文件
日志级别
# debug (a lot of information, useful for development/testing)
# verbose (many rarely useful info, but not a mess like the debug level)
# notice (moderately verbose, what you want in production probably)
# warning (only very important / critical messages are logged)
loglevel notice
logfile "" 日志文件位置和名称
databases 16 默认数据库 16个
快照
900 秒 对一个key进行了修改
save 900 1
300秒内对10个key进行了修改
save 300 10
60秒内对1万个进行了修改
save 60 10000
也可以继续自定义
stop-writes-on-bgsave-error yes 持久化出错是否继续进行操作
rdbcompression yes 是否进行压缩, 会消耗一定的资源
rdbchecksum yes 保存时是否进行校验
dir ./ rdb保存的目录
安全
通过命令设置密码 requirepass 123 设置为123
设置密码以后,auth 123 可以进行登录,get requirpass 可以获取到密码
也可以在配置文件中进行设置
限制
# maxclients 10000 客户端最大数目
maxmemory <bytes> 设置最大内存
maxmemory-policy noeviction 内存溢出之后策略
-
volatile-lru -> 根据LRU算法生成的过期时间来删除。
-
allkeys-lru -> 根据LRU算法删除任何key。
-
volatile-random -> 根据过期设置来随机删除key。
-
allkeys->random -> 无差别随机删。
-
volatile-ttl -> 根据最近过期时间来删除(辅以TTL)
-
noeviction -> 谁也不删,直接在写操作时返回错误
LRU算法
Last Recently Used的缩写,最久未使用
append only 模式
aof配置 aof 是将操纵日志写入文件
appendonly no 默认不开启,一般情况下,rdb够用
appendfilename "appendonly.aof" aof的默认文件
# appendfsync always 发生数据修改就进行一次同步,消耗性能
appendfsync everysec 同步方式 默认每1s进行一次
# appendfsync no 从不进行tong
持久化方式
redis持久化方式有两种,一种是通过记录redis的操作,将命令进行记录,数据恢复时,通过执行命令来恢复,这种是AOF,还有一种是将所有的数据进行保存,以快照的形式进行数据存储,这中是RDB方式,各有利弊。
RDB 和 AOF
RDB触发规则:
- 执行flushall命令。(清空redis服务器)
- 配置文件里面配置的满足save条件(多少秒,进行了多少操作)的时候,会触发。
- 数据库正常退出
如果RDB和AOF同时开启,那么会优先采用AOF方式进行恢复,AOF通常保存的数据比较全。
在redis重启服务,AOF进行数据恢复的时候,如果日志文件出现损坏,那么服务是无法正常开启的。
redis提供了检查文件的功能,如果日志文件出现了损坏,可以进行修复,代价是出错命令所在地方无法被执行,也就可能导致数据出现丢失。
发布订阅
SUBSCRIBE lant 创建监听一个主题
publish lant "hello world" 向频道发布信息
监听到信息
1) "message"
2) "lant"
3) "hello world"
通过subscribe命令订阅频道后,redis-server里面维护了一个字典,字典的键是一个个的频道,值就是一个列表。
主从复制
主从复制,是指一台的数据,复制到其他从节点。数据复制只能是单向的,不能从附属节点到主节点。 主节点以写为主,从节点以读为主。单台主机建议不超过20G内存。
复制原理
slave 连接到master 之后,会发送同步命令,master接到命令后,会传送整个文件到slave,完成一次完全同步。
全量复制,slave接到数据文件之后,将其存盘,并加载到内存中,
增量复制,master继续将新的命令传送给slave,完成同步。
缓存穿透、雪崩、击穿
-
缓存击穿(查询量太大,缓存过期)
如果大量的请求集中在一个点,如果这个key在失效的瞬间,大量的请求就会到达数据库中,就好比在缓存中凿出一个洞,
解决方案:
- 设置key不过期,这种方法很耗内存。
- 使用分布式锁,当大量的请求,从redis请求到数据库,只允许一个请求进入数据库查询
-
缓存穿透
如果缓存中没有数据,就会到mysql中查询,如果mysql中也没有,这个请求就会一直打到mysql里面, 如果这个请求很多,就会导致服务器压力很大。
解决方案:
- 使用布隆过滤器,对请求数据进行校验,不符合的进行丢弃
- 存储空对象,查不到的,可以缓存一个空。如果空值很多,也会造成资源浪费。
-
雪崩(服务器宕机、大量请求)
服务器集体宕机,或者出现大量的热点请求。
解决方案:
- 降级限流,通过加锁或者队列来控制数据库写缓存的线程数,比如某个key只允许一个线程读写,其他的等待
- 数据预热,在活动开始之前,先将数据加载到缓存中。
推荐一个不错的up主 https://space.bilibili.com/95256449 做了很多免费的视频.