redis用法(Java演示)
redis
- redis官网:
https://redis.io/download - win版本的redis
https://github.com/MicrosoftArchive/redis/releases - redis安装教程
http://blog.csdn.net/pf1234321/article/details/78040766
Redis 简介
redis是一种支持Key-Value等多种数据结构的存储系统。可用于缓存,事件发布或订阅,高速队列等场景。提供字符串,哈希,列表,队列,集合结构直接存取,基于内存,可持久化。
- 菜鸟教程
http://www.runoob.com/redis/redis-intro.html - 引用
https://blog.csdn.net/middleware2018/article/details/80355418
引入jedis依赖
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.8.0</version>
</dependency>
redis数据类型
部分函数示例
字符串(String)
set:设值,成功返回1
get:取值
incr:自增1(有自减)
setnx:设值,如果对应的key存在则返回0
jedis.set("string1","哈喽");
System.out.println(jedis.get("string1"));
jedis.set("num","4");
System.out.println(jedis.incr("num"));// 自增1
System.out.println(jedis.setnx("string1","aa"));
结果:
服务正在运行:PONG
哈喽
5
0
列表(List)
你可以添加一个元素到列表的头部(左边)或者尾部(右边)
一个列表最多可以包含 232 - 1 个元素 (4294967295, 每个列表超过40亿个元素)。
lpush:从左边进入
rpush:从右边进入
lpop:移除列表第一个元素并返回该元素
rpop:移除列表最后一个元素并返回该元素
jedis.lpush("list1","你好");
jedis.lpush("list1","哈喽");
List list = jedis.lrange("list1",0,2);
for (Object l: list){
System.out.println(l);
}
System.out.println(jedis.rpop("list1"));
结果:
哈喽
你好
你好
集合(Set)
Redis 的 Set 是 String 类型的无序集合。集合成员是唯一的,这就意味着集合中不能出现重复的数据。Redis 中集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是 O(1)。
sadd:向集合添加一个或多个成员
smembers:返回集合中的所有成员
jedis.sadd("set1","哈哈");
jedis.sadd("set1","你好");
System.out.println(jedis.smembers("set1"));
System.out.println(jedis.sadd("set1","哈哈"));
结果:
添加失败返回0
[哈哈, 你好]
0
有序集合(sorted set)
redis正是通过分数来为有序集合中的成员进行从小到大的排序。有序集合的成员是唯一的,但分数(score)却可以重复。
zadd:向有序集合添加一个或多个成员,或者更新已存在成员的分数
jedis.zadd("score1",0.2,"php");
jedis.zadd("score1",0.8,"java");
jedis.zadd("score1",0.5,"python");
Set set = jedis.zrange("score",0,2);
for (Object i:set){
System.out.println(i);
}
结果:
按照分数升序排序
php
python
java
哈希(Hash)
是一个string类型的field和value的映射表,hash特别适合用于存储对象
hmset:给指定key赋值(多字段或者map)
hmget:获取所有给定字段的值
hkeys:获取所有哈希表中的字段
Map map = new HashMap();
map.put("java","good");
map.put("python","good too");
jedis.hmset("hash1", map);
System.out.println(jedis.hmget("hash1","java"));
System.out.println(jedis.hkeys("hash1"));
结果:
[good]
[python, java]
redis的应用场景有哪些
- 会话缓存(最常用)
- 消息队列(比如支付)
- 活动排行榜或计数
- 发布,订阅消息(消息通知)
- 商品列表,评论列表等
redis的持久化
redis持久有两种方式: 快照(rdb文件),仅附加文件(aof文件)
都在conf配置文件中,默认为快照
快照(RDB)
将存储在内存的数据以快照的方式写入二进制文件中,如默认dump.rdb中
save 900 1
save 300 10
save 60 10000
900秒内如果超过1个Key被修改,则启动快照保存
300秒内如果超过10个Key被修改,则启动快照保存
60秒内如果超过10000个重点被修改,则启动快照保存
# yes启动快照,no关闭
rdbcompression yes
# rdb文件名
dbfilename dump.rdb
仅附加文件(AOF)
使用AOF持久时,服务会将每个收到的写命令通过写函数追加到文件中(appendonly.aof)
#关闭AOF持久化存储方式
appendonly no
#收到写命令后就立即写入磁盘,效率最差,效果最好
appendfsync always
#每秒写入磁盘一次,效率与效果居中
appendfsync everysec
#完全依赖操作系统,效率最佳,效果没法保证
appendfsync no
appendfsync 选项及同步频率
- always:每个 Redis 命令都要同步写入硬盘。这样会严重降低 Redis 的性能
- everysec:每秒执行一次同步,显式地将多个写命令同步到硬盘
- no:让操作系统来决定应该何时进行同步
恢复数据
如果需要恢复数据,只需将备份文件移动到 redis 安装目录并启动服务即可
rdb与aof对比
两种区别就是,一个是持续的用日志记录写操作,crash后利用日志恢复;一个是平时写操作的时候不触发写,只有手动提交save命令,或者是关闭命令时,才触发备份操作。
选择的标准,就是看系统是愿意牺牲一些性能,换取更高的缓存一致性(aof),还是愿意写操作频繁的时候,不启用备份来换取更高的性能,待手动运行save的时候,再做备份(rdb)。rdb这个就更有些 eventually consistent的意思了。
redis 分区
分区是分割数据到多个Redis实例的处理过程,因此每个实例只保存key的一个子集
分区的优势
- 通过利用多台计算机内存的和值,允许我们构造更大的数据库。
- 通过多核和多台计算机,允许我们扩展计算能力;通过多台计算机和网络适配器,允许我们扩展网络带宽。
分区的不足
- 当使用分区时,数据处理较为复杂
分区类型
- 范围分区:
最简单的分区方式是按范围分区,就是映射一定范围的对象到特定的Redis实例。
比如,ID从0到10000的用户会保存到实例R0,ID从10001到 20000的用户会保存到R1,以此类推。 - 哈希分区
另外一种分区方法是hash分区。用一个hash函数将key转换为一个数字,比如使用crc32 hash函数。
redis集群
redis集群是实现分区的一种方式,Redis 集群是一个可以在多个 Redis 节点之间进行数据共享的设施(installation)。
这里直接链接:https://www.cnblogs.com/gomysql/p/4395504.html
redis 主从复制
引用: https://www.cnblogs.com/leeSmall/p/8398401.html
主从复制: 主节点负责写数据,从节点负责读数据,主节点定期把数据同步到从节点保证数据的一致性
主从复制的相关操作
1.在同目录下复制一份6380.conf配置文件,修改
port 6380
slaveof 127.0.0.1 6379
2.先启动主节点
3.再启动从节点
服务端:redis-server.exe 6380.conf
客户端:redis-cli.exe -p 6380
4.测试
在从节点先get b没有数据
然后在主节点赋值set b 13
再到从节点get b就有数据了,且为13
5.断开主从复制:在slave节点,执行6380:>slaveof no one
6.断开后再变成主从复制:6380:> slaveof 127.0.0.1 6379
7.从节点建议用只读模式slave-read-only=yes, 若从节点修改数据,主从数据不一致
传输延迟
主从一般部署在不同机器上,复制时存在网络延时问题,redis提供repl-disable-tcp-nodelay参数决定是否关闭TCP_NODELAY,默认为关闭。
参数关闭时: 无论大小都会及时发布到从节点,占带宽,适用于主从网络好的场景,
参数启用时: 主节点合并所有数据成TCP包节省带宽,默认为40毫秒发一次,取决于内核,主从的同步延迟40毫秒,适用于网络环境复杂或带宽紧张,如跨机房。
数据同步
redis 2.8版本以上使用psync命令完成同步,过程分“全量”与“部分”复制
从服务器可以接受其他从服务器的连接。除了连接多个从服务器到同一个主服务器,从服务器也可以连接到其他的从服务器,形成图状结构。
全量复制: 一般用于初次复制场景(第一次建立SLAVE后全量)
部分复制: 网络出现问题,从节点再次连接主节点时,主节点补发缺少的数据,每次数据增量同步
心跳: 主从有长连接心跳,主节点默认每10S向从节点发ping命令,repl-ping-slave-period控制发送频率
Redis哨兵机制(Sentinel)
主从的缺点
主从复制,若主节点出现问题,则不能提供服务,需要人工修改配置将从变主,无法实现高可用。
原理
当主节点出现故障时,由Redis Sentinel自动完成故障发现和转移,并通知应用方,实现高可用性。
- 哨兵的定时监控任务
- 领导者哨兵选举流程
- 故障转移机制
过滤掉不健康的(下线或断线),没有回复过哨兵ping响应的从节点
选择salve-priority从节点优先级最高(redis.conf)的
选择复制偏移量最大,指复制最完整的从节点
如何安装和部署哨兵
- 先搭好一主两从redis的主从复制,和之前的主从复制搭建一样
从节点:6380.conf
从节点:6381.conf - 新增sentinel.conf 文件,默认是没有的
sentinel-26379.conf
sentinel-26380.conf
sentinel-26381.conf
#sentinel端口,默认23679
port 26379
#工作路径,注意路径不要和主重复
dir "redis-6379"
# 守护进程模式
daemonize yes
#关闭保护模式
#protected-mode no
# 指明日志文件名
#logfile "sentinel.log"
#哨兵监控的master,主从配置一样,这里只用输入redis主节点的ip/port和法定人数。
sentinel monitor mymaster 127.0.0.1 6379 2
# master或slave多长时间(默认30秒)不能使用后标记为s_down状态。
sentinel down-after-milliseconds mymaster 5000
#若sentinel在该配置值内未能完成failover操作(即故障时master/slave自动切换),则认为本次failover失败。
sentinel failover-timeout mymaster 18000
#设置master和slaves验证密码
#sentinel auth-pass mymaster 123456
# 指定了在执行故障转移时, 最多可以有多少个从服务器同时对新的主服务器进行同步
sentinel parallel-syncs mymaster 1
启动测试
- 启动主节点
- 启动哨兵:
redis-server.exe sentinel-26379.conf --sentinel
redis-server.exe sentinel-26380.conf --sentinel
redis-server.exe sentinel-26381.conf --sentinel
- 启动从节点:
redis-server.exe 6380.confredis-server.exe 6380.conf
redis-server.exe 6380.confredis-server.exe 6381.conf - 哨兵监测
监控节点启动、关闭
选举测试
杀掉端口6379进程
netstat -ano找到6379端口的PID为10496
taskkill /pid 16496 -f
观察哨兵,发现6379端口主节点挂掉了,选举了从节点端口6380为新主节点
在6380客户端查看信息info replication,已成为主节点且从节点为6381端口
部署建议
- sentinel节点应部署在多台物理机(线上环境)
- 至少三个且奇数个sentinel节点2.,至少三个且奇数个sentinel节点
- 通过以上我们知道,3个sentinel可同时监控一个主节点或多个主节点
监听N个主节点较多时,如果sentinel出现异常,会对多个主节点有影响,同时还会造成sentinel节点产生过多的网络连接,一般线上建议还是, 3个sentinel监听一个主节点
缓存雪崩和缓存穿透
转自:Hollis公众号
缓存雪崩是什么?
假设有如下一个系统,高峰期请求为5000次/秒,4000次走了缓存,只有1000次落到了数据库上,数据库每秒1000的并发是一个正常的指标,完全可以正常工作,但如果缓存宕机了,每秒5000次的请求会全部落到数据库上,数据库立马就死掉了,因为数据库一秒最多抗2000个请求,如果DBA重启数据库,立马又会被新的请求打死了,这就是缓存雪崩。
如何解决缓存雪崩
事前:redis高可用,主从+哨兵,redis cluster,避免全盘崩溃
事中:本地ehcache缓存 + hystrix限流&降级,避免MySQL被打死
事后:redis持久化,快速恢复缓存数据
缓存穿透是什么?
假如客户端每秒发送5000个请求,其中4000个为黑客的恶意攻击,即在数据库中也查不到。举个例子,用户id为正数,黑客构造的用户id为负数,
如果黑客每秒一直发送这4000个请求,缓存就不起作用,数据库也很快被打死。
如何解决缓存穿透
查询不到的数据也放到缓存,value为空,如set -999 “”
总而言之,缓存雪崩就是缓存失效,请求全部全部打到数据库,数据库瞬间被打死。缓存穿透就是查询了一个一定不存在的数据,并且从存储层查不到的数据没有写入缓存,这将导致这个不存在的数据每次请求都要到存储层去查询,失去了缓存的意义