Redis学习笔记
1、Redis安装目录
-
redis-benchmark:性能测试工具
-
redis-check-aof:修复有问题的aof文件
-
redis-check-rdb:修复有问题的rdb文件
-
redis-sentinel:redis集群使用,启动哨兵
-
redis-server:redis启动命令
-
redis-cli:客户端,操作入口
2、redis相关知识
-
redis有16个库,类似数组下标从开始,初始默认==0号数据库==
-
使用 “select 数据库编号” 切换数据库,例如:select 1
-
dbsize:查看当前数据库key的数量
-
flushdb:清空当前数据库所有key
-
flushall:清空所有数据库所有key
-
redis是单线程 + 多路IO复用
2、Key的操作
3、基本数据类型
1、String
String类型是一个二进制安全的,意味着Redis的String类型可以储存任何类型的数据
String类型是Redis中最常用的类型,其Value最多可以存储==512M==
2、List
List是一个简单的字符串列表
底层是双向链表
3、Set
Set提供的功能与List列表相似,但与之不同的是Set可以自动排重
-
添加:sadd key value
-
查看所有元素:smembers key
-
查看集合是否有某个元素:sismember key elem
-
查看集合的元素个数:scard key
-
删除元素:srem key elem1 elem2 …
-
两个集合的差集:sdiff key1 key2(key1中的,不包含key2中的)
-
两个集合的交集:sinter key1 key2
-
两个集合的并集:sunion key1 key2
-
随机从集合中弹出n个值:spop key count
-
从集合1将值移动到集合2中:smove key1 key2 elem
4、Hash
5、Zset
Zset与Set相似,区别为Zset是一个有序的不重复的列表
之所以是有序,就是因为每个元素成员关联了一个评分(score),这个评分用来按照从低分到高分的方式排序集合中的成员。
==集合中的成员是唯一的,但分数是可以重复的。==
Zset的底层类似于hash<String,Double>,列表的member就是hash的key,列表的score就类似于hash的value
Zset的底层还是一个跳跃表
-
添加:zadd key1 score1 value1 key2 score2 value2 …
-
显示集合中的元素:zrange key start end ,例如:zrange users 0 -1
-
显示集合中的元素并带上分数:zrange key start end withscores
-
根据分数范围显示元素并带上分数:zrangebysocre key min max withscores
-
元素从大到小排序并显示分数:zrevrangebyscore key max min withscores
-
分数增加:zincrby key increment member
-
删除元素:zrem key member1 member2 …
-
根据分数范围统计个数:zcount key min max
-
返回指定成员的排名:zrank key member
4、Redis配置
5、Redis发布订阅
redis发布订阅(pub/sub)是一种消息通信模式:发布者(pub)发布消息,订阅者(sub)订阅消息
redis客户端可以订阅任意数据的频道
-
订阅频道:subscribe channel [channel …]
-
发布消息:publish channel message
-
退订频道:unsubscribe channel [channel …]
6、新数据类型
1、Bitmaps
Bitmaps本身并不是新的数据类型,底层就是key-value形式的字符串
它是对字符串进行位操作,正因为它是操作位的,所以它的==value只有0和1==
-
设置值:setbit key offset value
-
取值:getbit key offset
-
统计个数:bitcount key [start end]
3、Geospatial
对地理位置和经纬度的操作,能通过添加地理位置实现地理位置的直线距离
-
添加:geoadd key longitude latitude member [longitude latitude member …]
-
获取:geopos key member [member …]
-
获取地理位置的直线距离:geodist key member1 member2 [m|km|ft|mi]
-
给定以经纬度为中心,指定半径内所有的地理位置:georadius key longitude latitude radius [m|km|ft|mi]
7、Jedis操作Redis
8、SpringBoot集成Redis
1、导入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!--SpringBoot 2.x集成redis所用的连接池-->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
2、application.yml配置
spring:
redis:
host: 主机ip
port: 端口
timeout: 超时时间(毫秒)
lettuce:
pool:
# 最大连接数
max-active: 20
# 最大阻塞等待时间(负数表示没有限制)
max-wait: -1
# 连接池最大空闲连接
max-idle: 5
# 连接池最小空闲连接
min-idle: 0
3、config配置类
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
@Configuration
@EnableCaching
public class RedisConfig {
@Bean
public RedisTemplate<String,Object> redisTemplate(RedisConnectionFactory factory){
RedisTemplate<String,Object> template = new RedisTemplate<>();
template.setConnectionFactory(factory);
//采用json序列化并对其作出配置
Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<Object>(Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
//该方法是指定序列化输入的类型,就是将数据库里的数据安装一定类型存储到redis缓存中。
om.activateDefaultTyping(LaissezFaireSubTypeValidator.instance,
ObjectMapper.DefaultTyping.NON_FINAL,
JsonTypeInfo.As.WRAPPER_ARRAY);
//完成配置,放在jackson2JsonRedisSerializer序列化中
jackson2JsonRedisSerializer.setObjectMapper(om);
//创建一个String类型的序列化对象
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
//key采用String的序列化方式
template.setKeySerializer(stringRedisSerializer);
//value采用上面定义的json序列化方式
template.setValueSerializer(jackson2JsonRedisSerializer);
//hash采用上面定义的json序列化方式
template.setHashKeySerializer(jackson2JsonRedisSerializer);
//hash的value采用上面定义的json序列化方式
template.setHashValueSerializer(jackson2JsonRedisSerializer);
template.afterPropertiesSet();
return template;
}
}
9、Redis事务
redis事务是一个单独的隔离操作,事务中的所有命令都会序列化,按顺序执行。
事务在执行过程中不会被打断
redis事务最主要的作用就是==串联多个命令,防止别的命令插队==
1、Multi、Exec、Discard
输入multi开始,后面输入的命令会放入队列中,但命令不会执行。直到输入exec,命令会按顺序执行。
组队过程中可以通过discard放弃组队
192.168.40.128:6380> multi
OK
192.168.40.128:6380> set age 21
QUEUED
192.168.40.128:6380> set name zhangsan
QUEUED
192.168.40.128:6380> incr age
QUEUED
192.168.40.128:6380> exec
1) OK
2) OK
3) (integer) 22
==注意:redis的事务并不保证原子性,执行过程中有执行错误的命令并不影响其它命令执行成功==
2、WATCH key [key …]
watch与multi配合使用可以实现乐观锁
通过watch命令,我们可以在执行multi之前监视一个或多个key。==当事务执行之前,这些key如果被其它命令改动,那么事务将被打断。==
3、UNWATCH key
取消对key的监视
4、秒杀案列实现
1、centos7安装ab压力测试工具
yum install httpd-tools
2、命令
ab -n 1000 -c 100 -p /opt/postfile -T application/x-www-form-urlencoded http://192.168.182.1:8080/seckill/start/0101/6
ab -n 1000 -c 100 http://192.168.182.1:8080/lock/
10、Redis持久化
1、RDB
RDB(Redis Database):在指定时间间隔内将内存中的数据集快照写入磁盘,也就是行话讲的Snapshot快照,它恢复时是将快照文件直接读取到内存
RDB的缺点:==最后一次持久化的数据可能丢失==
2、AOF
AOF(Append Only File):以日志的形式记录每个写操作(增量保存),将Redis执行过所有写操作的命令记录下来(读操作不记录)。只需追加文件,但不可以改文件。但redis重启之后,就会根据日志文件的内容将写指令从前到后执行一次,以完成数据的恢复操作。
注意:AOF默认是不开启的,当AOF和RDB同时开启时,Redis是默认使用AOF。
AOF不会照成数据的丢失
11、主从复制
优势:1.读写分离,性能扩展
2.容灾快速恢复
1、主从复制配置文件需要修改的属性
多个配置文件有相同内容时,可以选择用:==include redis.conf==命令导入文件作为相同的内用,不同的内容再做覆盖
pidfile: 进程文件
port: 端口
dir: redis安装目录
dbfilename: rdb文件名
logfile: 日志文件路径
replicaof: 从机
示例:
port 6379
pidfile /var/run/redis_6379.pid
logfile "/usr/local/bin/log/redis6379.log"
dbfilename dump6379.rdb
dir "/usr/local/bin"
2、查看是主机还是从机的命令
info replication
3、配从(库)不配主(库)
1、使用命令配置
slaceof 主机ip 端口
2、在配置文件配置
replicaof 主机ip 端口
4、主从复制原理
从服务器:当从服务器连接到主服务器时,它会向主服务器发送要进行数据同步的消息
主服务器:当接收到从服务器发送过来的数据同步消息后,主服务器会把数据持久化到rdb文件,再把rdb文件发送给从服务器,从服务器再读取rdb文件进行数据同步。
之后每次主服务器进行写操作的时候,会和从服务器进行数据同步。
12、薪火相传和反客为主
1、薪火相传
原理:从服务器下还可以允许有从服务器
缺点:但某个从服务器节点挂掉以后,它下面的从服务器不能直接跟主服务器先连
2、反客为主
原理:但主服务器挂掉以后,从服务器可以自动上位做主服务器
1、在从机上输入命令:
slaveof no one
13、哨兵模式
作用:能监视Redis服务是否宕机,如果主服务器宕机,哨兵会通过投票机制选出一台主服务器
==原主机重启后会变成从机==
1、创建sentonel.conf配置文件,内容如下
sentinel monitor myredis 127.0.0.1 6380 1
sentinel:代表哨兵
monitor:监视
myredis:为监控对象起的服务名称
127.0.0.1:主服务器ip
6380:主服务器端口号
1:至少有多少个哨兵同意迁移的数量
2、启动哨兵命令:redis-sentinel sentinel.conf
3、哨兵选举服务器规则:
-
选择优先级靠前的
-
选择偏移量最大的
-
选择runid最小的服务器
优先级在redis.conf中默认:replica-priority 100,值越小,优先级越高
偏移量:从服务器数据与主服务器数据的相似度,相似度越高,偏移量越大
runid:每个redis实例启动后都会随机生成一个40位的runid
4、Java连接哨兵模式的redis:只需要连哨兵启动的端口
14、Redis集群
问题:在主从模式,薪火相传模式中,主机宕机,导致ip地址发生变化,应用配置中需要修改对应的主机、端口
解决:在Redis3.0中提供了解决方案。就是无中心化集群配置。
1、Redis cluster 配置修改
-
打开集群模式:cluster-enabled yes
-
设置节点配置文件:cluster-config-file nodes-6379.conf
-
设置节点失联时间,超过该时间(毫秒),集群自动进行主从切换:cluster-node-timeout 15000
2、将所有节点合成一个集群
组合之前,请确保所有redis实例启动成功后,nodes-xxxx.conf都生成正常。
-
进入redis原安装目录的src文件目录下:cd /opt/redis-6.0.6/src/
-
组合命令:redis-cli –cluster create –cluster-replicas 1 主机ip1:端口号1 主机ip2:端口号2 [主机ip3:端口号3 …]
-
-replicas 1 :采用最简单的方式配置集群,一台主机,一台从机
-
注意:主机ip不能用127.0.0.1
-
-
连接客户端时要以集群的方式连接,加上==-c==:redis-cli -c -h 主机ip -p 端口号
-
查看节点中的信息:cluster nodes
-
查看key的插槽值:cluster keyslot key
-
查看插槽有多少个key:cluster countkeysinslot 插槽值,==注意:只能看自己主机插槽范围的==
-
返回插槽中指定数量的key:cluster getkeysinslot 插槽值 count
==集群启动后,会显示集群一共有多少插槽。==
==每台主机分配有固定的插槽个数,redis会根据特定的算法算出key存放在哪台主机的插槽==
集群中批量添加问题:
在集群中,如果我们使用过去的方法:mset key1 value1 [key2 value2 …]来批量添加key,这时我们会发现报错。
原因:多个key的插入集群无法根据多个key来计算插槽
解决:我们可以使用组的方式进行插入,示例:mset id{user} 1 name{user} zhangsan age{user} 23
故障恢复:
1、如果某个主节点挂掉,它的从节点会变成主机。我们通过配置文件再次启动挂掉的节点,这时候这个节点会变成从机。
2、但某一段插槽的主从都挂掉:
-
redis.conf配置文件中的参数:cluster-require-full-coverage
-
如果cluster-require-full-coverage为yes时,那么整个集群都挂掉。
-
如果cluster-require-full-coverage为no时,该插槽数据全部不能用,也无法储存。但其它插槽都可以用。
15、Java使用Redis集群
public static void main(String[] args) {
// 连接集群中任意一台服务器
HostAndPort hostAndPort = new HostAndPort("192.168.0.1",6379);
JedisCluster jedisCluster = new JedisCluster(hostAndPort);
String value = jedisCluster.set("key","value");
jedisCluster.close();
}
16、缓存穿透
问题描述:当对一个不存在的数据进行大量的访问时,在redis里面拿不到,那么就会访问数据库获取,数据库查询为空则不进行缓存。这导致这个不存在的数据每次请求都要到数据库去查,最终导致数据库压力变大甚至奔溃。
解决:
-
对空值进行缓存:在数据库不存在,把null在redis进行缓存,并设置个过期时间,最长不超过5分钟。
-
设置可访问的白名单:用bitmaps设置一个白名单,用id作为bitmaps的偏移量,每次访问与bitmaps的id进行比较,如果不存在,则进行拦截,不允许访问。
-
采用布隆过滤器:
-
进行实时监控:当发现redis的命中率开始急速降低,需要排查访问对象和访问数据,和运维人员配合,设置黑名单限制服务。
17、缓存击穿
问题描述:但redis中某个热门的key过期了,但有大量的请求访问这个key,这时候,redis中无法命中,所以这大量的请求落到了数据库上,给数据库照成压力。
解决:
-
预先设置热门数据:将一些热门数据提前存入redis中,加大这些热门数据key的时长。
-
实时调整:现场监控哪些数据热门,实时调整key的过期时间。
-
使用锁:缓存失效的时候(判断拿出来的值为),不是立即去load db。而是设置锁,过一段时间再访问。
18、缓存雪崩
问题:在极少时间段,大量key集中过期的情况,请求的访问落到数据库,照成数据库奔溃。
解决:
-
构建多级缓存架构:Nginx缓存 + Redis缓存 + 其它缓存(ehcache缓存等)
-
使用锁或队列:使用加锁和队列方式保证不会有大量的访问,但效率也会变低。
-
设置过期标志更新缓存:记录缓存数据是否过期(设置提前量),如果过期会触发通知另外线程在后台去更新实际key的缓存。
-
将缓存失效的时间分开:比如在原来的失效时间的基础上增加一个随机值,比如随机1-5分钟。
19、Redis分布式锁
1、分布式锁必须满足的4个条件
-
互斥性:任意时刻,只能有一个客户端持有锁。
-
不会发生死锁:即使一个客户端在持有锁的时候发生奔溃无法释放锁,也能保证其它客户端能正常加锁
-
解铃还须系铃人:加锁和解锁必须是同一个客户端,客户端自己不能把别人的锁给解了。
-
加锁和解锁必须具有原子性
20、Redis6.0新功能
1、ACL
设置哪些命令的操作权限
2、IO多线程
3、工具支持Cluster
原创文章,作者:奋斗,如若转载,请注明出处:https://blog.ytso.com/276489.html