Redis学习笔记


Redis学习笔记

1、Redis安装目录

  • redis-benchmark:性能测试工具

  • redis-check-aof:修复有问题的aof文件

  • redis-check-rdb:修复有问题的rdb文件

  • redis-sentinel:redis集群使用,启动哨兵

  • redis-server:redis启动命令

  • redis-cli:客户端,操作入口

 

2、redis相关知识

  1. redis有16个库,类似数组下标从开始,初始默认==0号数据库==

  2. 使用 “select 数据库编号” 切换数据库,例如:select 1

  3. dbsize:查看当前数据库key的数量

  4. flushdb:清空当前数据库所有key

  5. flushall:清空所有数据库所有key

  6. redis是单线程 + 多路IO复用

 

 

2、Key的操作

 

3、基本数据类型

1、String

String类型是一个二进制安全的,意味着Redis的String类型可以储存任何类型的数据

String类型是Redis中最常用的类型,其Value最多可以存储==512M==

 

 

2、List

List是一个简单的字符串列表

底层是双向链表

 

3、Set

Set提供的功能与List列表相似,但与之不同的是Set可以自动排重

  1. 添加:sadd key value

  2. 查看所有元素:smembers key

  3. 查看集合是否有某个元素:sismember key elem

  4. 查看集合的元素个数:scard key

  5. 删除元素:srem key elem1 elem2 …

  6. 两个集合的差集:sdiff key1 key2(key1中的,不包含key2中的)

  7. 两个集合的交集:sinter key1 key2

  8. 两个集合的并集:sunion key1 key2

  9. 随机从集合中弹出n个值:spop key count

  10. 从集合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的底层还是一个跳跃表

  1. 添加:zadd key1 score1 value1 key2 score2 value2 …

  2. 显示集合中的元素:zrange key start end ,例如:zrange users 0 -1

  3. 显示集合中的元素并带上分数:zrange key start end withscores

  4. 根据分数范围显示元素并带上分数:zrangebysocre key min max withscores

  5. 元素从大到小排序并显示分数:zrevrangebyscore key max min withscores

  6. 分数增加:zincrby key increment member

  7. 删除元素:zrem key member1 member2 …

  8. 根据分数范围统计个数:zcount key min max

  9. 返回指定成员的排名:zrank key member

 

4、Redis配置

 

 

5、Redis发布订阅

redis发布订阅(pub/sub)是一种消息通信模式:发布者(pub)发布消息,订阅者(sub)订阅消息

redis客户端可以订阅任意数据的频道

  1. 订阅频道:subscribe channel [channel …]

  2. 发布消息:publish channel message

  3. 退订频道:unsubscribe channel [channel …]

 

6、新数据类型

1、Bitmaps

Bitmaps本身并不是新的数据类型,底层就是key-value形式的字符串

它是对字符串进行位操作,正因为它是操作位的,所以它的==value只有0和1==

  1. 设置值:setbit key offset value

  2. 取值:getbit key offset

  3. 统计个数:bitcount key [start end]

 

 

3、Geospatial

对地理位置和经纬度的操作,能通过添加地理位置实现地理位置的直线距离

  1. 添加:geoadd key longitude latitude member [longitude latitude member …]

  2. 获取:geopos key member [member …]

  3. 获取地理位置的直线距离:geodist key member1 member2 [m|km|ft|mi]

  4. 给定以经纬度为中心,指定半径内所有的地理位置: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
  1. sentinel:代表哨兵

  2. monitor:监视

  3. myredis:为监控对象起的服务名称

  4. 127.0.0.1:主服务器ip

  5. 6380:主服务器端口号

  6. 1:至少有多少个哨兵同意迁移的数量

 

2、启动哨兵命令:redis-sentinel sentinel.conf

 

3、哨兵选举服务器规则:

  1. 选择优先级靠前的

  2. 选择偏移量最大的

  3. 选择runid最小的服务器

优先级在redis.conf中默认:replica-priority 100,值越小,优先级越高

偏移量:从服务器数据与主服务器数据的相似度,相似度越高,偏移量越大

runid:每个redis实例启动后都会随机生成一个40位的runid

 

4、Java连接哨兵模式的redis:只需要连哨兵启动的端口

 

14、Redis集群

问题:在主从模式,薪火相传模式中,主机宕机,导致ip地址发生变化,应用配置中需要修改对应的主机、端口

解决:在Redis3.0中提供了解决方案。就是无中心化集群配置。

1、Redis cluster 配置修改

  1. 打开集群模式:cluster-enabled yes

  2. 设置节点配置文件:cluster-config-file nodes-6379.conf

  3. 设置节点失联时间,超过该时间(毫秒),集群自动进行主从切换:cluster-node-timeout 15000

 

2、将所有节点合成一个集群

组合之前,请确保所有redis实例启动成功后,nodes-xxxx.conf都生成正常。

  1. 进入redis原安装目录的src文件目录下:cd /opt/redis-6.0.6/src/

  2. 组合命令:redis-cli –cluster create –cluster-replicas 1 主机ip1:端口号1 主机ip2:端口号2 [主机ip3:端口号3 …]

    • -replicas 1 :采用最简单的方式配置集群,一台主机,一台从机

    • 注意:主机ip不能用127.0.0.1

  3. 连接客户端时要以集群的方式连接,加上==-c==:redis-cli -c -h 主机ip -p 端口号

  4. 查看节点中的信息:cluster nodes

  5. 查看key的插槽值:cluster keyslot key

  6. 查看插槽有多少个key:cluster countkeysinslot 插槽值,==注意:只能看自己主机插槽范围的==

  7. 返回插槽中指定数量的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里面拿不到,那么就会访问数据库获取,数据库查询为空则不进行缓存。这导致这个不存在的数据每次请求都要到数据库去查,最终导致数据库压力变大甚至奔溃。

解决:

  1. 对空值进行缓存:在数据库不存在,把null在redis进行缓存,并设置个过期时间,最长不超过5分钟。

  2. 设置可访问的白名单:用bitmaps设置一个白名单,用id作为bitmaps的偏移量,每次访问与bitmaps的id进行比较,如果不存在,则进行拦截,不允许访问。

  3. 采用布隆过滤器

  4. 进行实时监控:当发现redis的命中率开始急速降低,需要排查访问对象和访问数据,和运维人员配合,设置黑名单限制服务。

 

17、缓存击穿

问题描述:但redis中某个热门的key过期了,但有大量的请求访问这个key,这时候,redis中无法命中,所以这大量的请求落到了数据库上,给数据库照成压力。

解决

  1. 预先设置热门数据:将一些热门数据提前存入redis中,加大这些热门数据key的时长。

  2. 实时调整:现场监控哪些数据热门,实时调整key的过期时间。

  3. 使用锁:缓存失效的时候(判断拿出来的值为),不是立即去load db。而是设置锁,过一段时间再访问。

 

18、缓存雪崩

问题:在极少时间段,大量key集中过期的情况,请求的访问落到数据库,照成数据库奔溃。

解决

  1. 构建多级缓存架构:Nginx缓存 + Redis缓存 + 其它缓存(ehcache缓存等)

  2. 使用锁或队列:使用加锁和队列方式保证不会有大量的访问,但效率也会变低。

  3. 设置过期标志更新缓存:记录缓存数据是否过期(设置提前量),如果过期会触发通知另外线程在后台去更新实际key的缓存。

  4. 将缓存失效的时间分开:比如在原来的失效时间的基础上增加一个随机值,比如随机1-5分钟。

 

 

19、Redis分布式锁

1、分布式锁必须满足的4个条件

  1. 互斥性:任意时刻,只能有一个客户端持有锁。

  2. 不会发生死锁:即使一个客户端在持有锁的时候发生奔溃无法释放锁,也能保证其它客户端能正常加锁

  3. 解铃还须系铃人:加锁和解锁必须是同一个客户端,客户端自己不能把别人的锁给解了。

  4. 加锁和解锁必须具有原子性

 

 

20、Redis6.0新功能

1、ACL

设置哪些命令的操作权限

 

2、IO多线程

 

3、工具支持Cluster

原创文章,作者:奋斗,如若转载,请注明出处:https://blog.ytso.com/276489.html

(0)
上一篇 2022年7月23日
下一篇 2022年7月23日

相关推荐

发表回复

登录后才能评论