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复用
String类型是一个二进制安全的,意味着Redis的String类型可以储存任何类型的数据
String类型是Redis中最常用的类型,其Value最多可以存储==512M==
List是一个简单的字符串列表
底层是双向链表
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
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
redis发布订阅(pub/sub)是一种消息通信模式:发布者(pub)发布消息,订阅者(sub)订阅消息
redis客户端可以订阅任意数据的频道
订阅频道:subscribe channel [channel ...]
发布消息:publish channel message
退订频道:unsubscribe channel [channel ...]
Bitmaps本身并不是新的数据类型,底层就是key-value形式的字符串
它是对字符串进行位操作,正因为它是操作位的,所以它的==value只有0和1==
设置值:setbit key offset value
取值:getbit key offset
统计个数:bitcount key [start end]
对地理位置和经纬度的操作,能通过添加地理位置实现地理位置的直线距离
添加: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]
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; } }
redis事务是一个单独的隔离操作,事务中的所有命令都会序列化,按顺序执行。
事务在执行过程中不会被打断
redis事务最主要的作用就是==串联多个命令,防止别的命令插队==
输入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的事务并不保证原子性,执行过程中有执行错误的命令并不影响其它命令执行成功==
watch与multi配合使用可以实现乐观锁
通过watch命令,我们可以在执行multi之前监视一个或多个key。==当事务执行之前,这些key如果被其它命令改动,那么事务将被打断。==
取消对key的监视
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/
RDB(Redis Database):在指定时间间隔内将内存中的数据集快照写入磁盘,也就是行话讲的Snapshot快照,它恢复时是将快照文件直接读取到内存
RDB的缺点:==最后一次持久化的数据可能丢失==
AOF(Append Only File):以日志的形式记录每个写操作(增量保存),将Redis执行过所有写操作的命令记录下来(读操作不记录)。只需追加文件,但不可以改文件。但redis重启之后,就会根据日志文件的内容将写指令从前到后执行一次,以完成数据的恢复操作。
注意:AOF默认是不开启的,当AOF和RDB同时开启时,Redis是默认使用AOF。
AOF不会照成数据的丢失
优势:1.读写分离,性能扩展
2.容灾快速恢复
多个配置文件有相同内容时,可以选择用:==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"
info replication
1、使用命令配置
slaceof 主机ip 端口
2、在配置文件配置
replicaof 主机ip 端口
从服务器:当从服务器连接到主服务器时,它会向主服务器发送要进行数据同步的消息
主服务器:当接收到从服务器发送过来的数据同步消息后,主服务器会把数据持久化到rdb文件,再把rdb文件发送给从服务器,从服务器再读取rdb文件进行数据同步。
之后每次主服务器进行写操作的时候,会和从服务器进行数据同步。
原理:从服务器下还可以允许有从服务器
缺点:但某个从服务器节点挂掉以后,它下面的从服务器不能直接跟主服务器先连
原理:但主服务器挂掉以后,从服务器可以自动上位做主服务器
1、在从机上输入命令:
slaveof no one
作用:能监视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:只需要连哨兵启动的端口
问题:在主从模式,薪火相传模式中,主机宕机,导致ip地址发生变化,应用配置中需要修改对应的主机、端口
解决:在Redis3.0中提供了解决方案。就是无中心化集群配置。
打开集群模式:cluster-enabled yes
设置节点配置文件:cluster-config-file nodes-6379.conf
设置节点失联时间,超过该时间(毫秒),集群自动进行主从切换:cluster-node-timeout 15000
组合之前,请确保所有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时,该插槽数据全部不能用,也无法储存。但其它插槽都可以用。
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(); }
问题描述:当对一个不存在的数据进行大量的访问时,在redis里面拿不到,那么就会访问数据库获取,数据库查询为空则不进行缓存。这导致这个不存在的数据每次请求都要到数据库去查,最终导致数据库压力变大甚至奔溃。
解决:
对空值进行缓存:在数据库不存在,把null在redis进行缓存,并设置个过期时间,最长不超过5分钟。
设置可访问的白名单:用bitmaps设置一个白名单,用id作为bitmaps的偏移量,每次访问与bitmaps的id进行比较,如果不存在,则进行拦截,不允许访问。
采用布隆过滤器:
进行实时监控:当发现redis的命中率开始急速降低,需要排查访问对象和访问数据,和运维人员配合,设置黑名单限制服务。
问题描述:但redis中某个热门的key过期了,但有大量的请求访问这个key,这时候,redis中无法命中,所以这大量的请求落到了数据库上,给数据库照成压力。
解决:
预先设置热门数据:将一些热门数据提前存入redis中,加大这些热门数据key的时长。
实时调整:现场监控哪些数据热门,实时调整key的过期时间。
使用锁:缓存失效的时候(判断拿出来的值为),不是立即去load db。而是设置锁,过一段时间再访问。
问题:在极少时间段,大量key集中过期的情况,请求的访问落到数据库,照成数据库奔溃。
解决:
构建多级缓存架构:Nginx缓存 + Redis缓存 + 其它缓存(ehcache缓存等)
使用锁或队列:使用加锁和队列方式保证不会有大量的访问,但效率也会变低。
设置过期标志更新缓存:记录缓存数据是否过期(设置提前量),如果过期会触发通知另外线程在后台去更新实际key的缓存。
将缓存失效的时间分开:比如在原来的失效时间的基础上增加一个随机值,比如随机1-5分钟。
互斥性:任意时刻,只能有一个客户端持有锁。
不会发生死锁:即使一个客户端在持有锁的时候发生奔溃无法释放锁,也能保证其它客户端能正常加锁
解铃还须系铃人:加锁和解锁必须是同一个客户端,客户端自己不能把别人的锁给解了。
加锁和解锁必须具有原子性
设置哪些命令的操作权限