Redis学习笔记
1、Redis安装目录
-
redis-cli:客户端,操作入口
2、redis相关知识
2、Key的操作
3、基本数据类型
1、String
String类型是一个二进制安全的,意味着Redis的String类型可以储存任何类型的数据
String类型是Redis中最常用的类型,其Value最多可以存储==512M==
2、List
List是一个简单的字符串列表
底层是双向链表
3、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是一个有序的不重复的列表
==集合中的成员是唯一的,但分数是可以重复的。==
Zset的底层类似于hash<String,Double>,列表的member就是hash的key,列表的score就类似于hash的value
Zset的底层还是一个跳跃表
-
显示集合中的元素:zrange key start end ,例如:zrange users 0 -1
-
分数增加:zincrby key increment member
-
删除元素:zrem key member1 member2 ...
-
根据分数范围统计个数:zcount key min max
-
返回指定成员的排名:zrank key member
4、Redis配置
5、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 ...]
-
给定以经纬度为中心,指定半径内所有的地理位置: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服务是否宕机,如果主服务器宕机,哨兵会通过投票机制选出一台主服务器
==原主机重启后会变成从机==
sentinel monitor myredis 127.0.0.1 6380 1
2、启动哨兵命令:redis-sentinel sentinel.conf
3、哨兵选举服务器规则:
-
选择优先级靠前的
-
选择偏移量最大的
-
选择runid最小的服务器
优先级在redis.conf中默认:replica-priority 100,值越小,优先级越高
偏移量:从服务器数据与主服务器数据的相似度,相似度越高,偏移量越大
4、Java连接哨兵模式的redis:只需要连哨兵启动的端口
14、Redis集群
问题:在主从模式,薪火相传模式中,主机宕机,导致ip地址发生变化,应用配置中需要修改对应的主机、端口
1、Redis cluster 配置修改
-
打开集群模式:cluster-enabled yes
-
设置节点失联时间,超过该时间(毫秒),集群自动进行主从切换:cluster-node-timeout 15000
2、将所有节点合成一个集群
-
组合命令:redis-cli --cluster create --cluster-replicas 1 主机ip1:端口号1 主机ip2:端口号2 [主机ip3:端口号3 ...]
-
-replicas 1 :采用最简单的方式配置集群,一台主机,一台从机
-
注意:主机ip不能用127.0.0.1
-
-
查看节点中的信息: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、但某一段插槽的主从都挂掉:
-
如果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里面拿不到,那么就会访问数据库获取,数据库查询为空则不进行缓存。这导致这个不存在的数据每次请求都要到数据库去查,最终导致数据库压力变大甚至奔溃。
解决:
-
设置可访问的白名单:用bitmaps设置一个白名单,用id作为bitmaps的偏移量,每次访问与bitmaps的id进行比较,如果不存在,则进行拦截,不允许访问。
-
采用布隆过滤器:
-
进行实时监控:当发现redis的命中率开始急速降低,需要排查访问对象和访问数据,和运维人员配合,设置黑名单限制服务。
17、缓存击穿
问题描述:但redis中某个热门的key过期了,但有大量的请求访问这个key,这时候,redis中无法命中,所以这大量的请求落到了数据库上,给数据库照成压力。
解决:
-
预先设置热门数据:将一些热门数据提前存入redis中,加大这些热门数据key的时长。
-
实时调整:现场监控哪些数据热门,实时调整key的过期时间。
-
使用锁:缓存失效的时候(判断拿出来的值为),不是立即去load db。而是设置锁,过一段时间再访问。
18、缓存雪崩
解决:
-
使用锁或队列:使用加锁和队列方式保证不会有大量的访问,但效率也会变低。
19、Redis分布式锁
1、分布式锁必须满足的4个条件
-
互斥性:任意时刻,只能有一个客户端持有锁。
-
不会发生死锁:即使一个客户端在持有锁的时候发生奔溃无法释放锁,也能保证其它客户端能正常加锁
-
解铃还须系铃人:加锁和解锁必须是同一个客户端,客户端自己不能把别人的锁给解了。
-
加锁和解锁必须具有原子性
20、Redis6.0新功能
1、ACL
设置哪些命令的操作权限
2、IO多线程
3、工具支持Cluster
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。