redis高级篇(学习版)

一、redis的安装

1、下载redis的tar.gz文件

2、解压后进入到redis文件夹安装

make && make install PREFIX=/usr/local/redis install(redis是需要gcc环境的)

3、redis的安装目录在/usr/local/bin下,相关文件说明:

1)、redis-benchmark:性能测试工具,可以在自己本子运行,看看自己本子性能如何,
2)、redis-check-aof:修复有问题的 AOF 文件,
3)、redis-check-dump:修复有问题的dump.rdb文件
4)、redistsentinel : Rdis 集群使用。
5)、redis-server:Redis 服务器启动命令,
6)、redis-ci:客户端,操作入口。

4、redis是单线程+多路io复用

二、redis常用五大数据类型

1、字符串String

String类型是二进制安全的,value最大值512MB

2、列表list

底层是一个双向链表,将普通链表和压缩链表结合起来,形成快速链表,操作两边的性能高于操作中间的

3、集合set

set提供的是和list一样的功能,特殊之处是可以自动重排,进行去重,并且set提供某个成员是否在集合中的接口,该接口是list没有的;
set是String类型的无需集合,它的底层是value为null的hash表,所以其的操作时间复杂度为o(1),即不会因为数据的多少而导致操作时间的变化;
set底层是hash结构,所有hash都指向同一个内部值

4、哈希hash

hash类型对应的数据类型是两种,当field-value长度较短且个数较少时,使用ziplist,否则使用

5、有序集合zset

zset 底层使用两个数据结构:
hash:hash的作用是关联元素value和权重score,保障元素value的唯一性,可以通过元素value找到相应的score值;
跳跃表:跳跃表的目的在与给元素value排序,根据score的范围获取元素列表

三、配置文件

redis提供远程访问时执行1、2:
1、注释掉bind行
2、protected-mode 保护模式:no(关掉)
3、timeout:超时时间,默认为0,即为永不超时
4、tcp-keepalive:tcp连接每300s检测一次是否还有有效连接,即心跳
5、daemonize:后台启动
6、requirepass:设置密码
7、maxclients:客户连接数
8、maxmemory:最大内存,建议设置
9、maxmomery-policy:内存占完时使用的移除规则
1)、volatile-Iru:使用LRU算法移除key,只对设置了过期时间的键:(最近最少使用)。
2)、allkeys-lru :在所有集合 key 中,使用 LRU 算法移除key
3)、volatile-random:在过期集合中移除随机的key,只对设置了过期时间的键,
4)、allkeysrandom :在所有集合ley中 ,移除随机的key 5)、volatile-ttl:移除那些TIL值最小的key,即那些最近要过期的 key
6)、noeviction:不进行移除。针对写操作,只是返回错误信息

四、发布订阅

1、客户端订阅一个或多个频道
subscribe channel1、channel2
2、另一个客户端给channel发消息
publish channel message
返回的1 是订阅数量

五、新数据类型

1、bitmaps:不是数据类型,是一个字符串,他可以对字符串的位进行操作;bitmaps只能存储0和1,方便与活跃用户较大的项目
2、HyperLogLog:用于统计基数问题
3、Geospatial:用于存储二维坐标信息,可以查看两个坐标之间的距离,也可以查看某一坐标范围内的坐标点数据

六、项目实践

1、RedisConfig

@Configuration
public class RedisTemplateConfig {
    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(redisConnectionFactory);
        //配置序列化方式
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        ObjectMapper obm = new ObjectMapper();
        // 指定要序列化的域,field,get和set,以及修饰符范围,ANY是都有包括private和public
        obm.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        // 指定序列化输入的类型,类必须是非final修饰的,final修饰的类,比如String,Integer等会跑出异常
        obm.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL);

        jackson2JsonRedisSerializer.setObjectMapper(obm);

        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
        //key 采用String的序列化方式
        template.setKeySerializer(stringRedisSerializer);
        //hash
        template.setHashKeySerializer(stringRedisSerializer);
        //value
        template.setValueSerializer(jackson2JsonRedisSerializer);
        template.afterPropertiesSet();
        return template;
    }
}

2、application.yml配置

spring:
  redis:
    host: 47.103.156.42
    port: 6379
    database: 0
    connect-timeout: 300000
    #连接池最大连接数
    lettuce:
      pool:
        #最大连接数
        max-active: 20
        #最大阻塞时间(-1表示没有限制)
        max-wait: -1
        #空闲数
        max-idle: 5

七、redis事务

1、事务详解:

Redis 事务是一个单独的隔离操作:事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程中,不会被其他客户端送来的命令请求所打断。Redis事务的主要作用就是串联多个命令防止别的命令插队

2、事务命令:

multi: 开启事务,便可添加所要执行的命令
exec:执行队列中的命令
discard:放弃执行

3、事务错误:

1)、在组队时,发生错,执行时所有命令都不会成功
2)、组队时,都成功,执行时,哪个有问题,哪个执行失败

4、redis乐观锁:

watch 和 unwatch
在开启事务之前,西安监听一个或多个key,命令为:watch key
如果有一个客户端对这个key做了操作,那么其他的事务操作不成功,因为他们的版本号不一致

5、redis事务三大特性

1)、单独的隔离操作

事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断。

2)没有隔离级别的概念

队列中的命令没有提交之前都不会实际被执行,因为事务提交前任何指令都 不会被实际执行。

3)不保证原子性

事务中如果有一条命令执行失败,其后的命令仍然会被执行,没有回滚

八、秒杀解决方案:

linux中使用并发工具:httpd-tools

解决库存超卖问题

1、开启乐观锁,使用watch来监听需要秒杀的商品数量
2、开启事务,对商品数量-1,以及添加秒杀成功的用户
3、对事务执行的结果进行判断

解决库存遗留问题(乐观锁导致的)

使用lua脚本替换掉redis秒杀逻辑,因位redis是单线程的,lua脚本执行过程中,不会被中断,所以使用redis调用lua脚本,redis2.6以上支持lua脚本

九、redis持久化

1、RDB(redis database)

1)、定义:

在指定的时间间隔内将内存中的数据集快照写入磁盘,它恢复时是将快照文件直接读到内存里

2)、RDB备份是如何执行的

Redis 会单独创建(fok)一个子进程来进行持久化,会先将数据写到一个临时文件中,待持久化过程都结束了,再用这个临时文件替换上次持久化好的文件。整个过程中,主进程是不进行任何IO操作的,这就确保了极高的性能 如果需要进行大规模数 据的恢复,且对于数据恢复的完整性不是非常敏感,那RDB 方式要比 AOF方式更加的高效。RDB的缺点是最后一次持久化后的数据可能丢失。

3)、优势:

a、适合大规模的数据恢复; b、对数据完整性和一致性要求不高更适合使用;
c、节省磁盒空间;
d、恢复速度快。

4)、缺点:

a、Fork 的时候,内存中的数据被克隆了一份,大致2倍的膨账性 需要考志;
b、虽然Redis在fork时使用了写时拷贝技术,,但是如果数据庞大 时还是比较消耗性能
c、在一定的时间间隔做一次备份,如果redis意外宕机,就会丢 掉最后一次快照后的所有数据

2、AOF(Append Only File)

1)、定义:

以日志的形式来记录每个写操作(增量保存),将Redis执行过的所有写指令记录下来(读操作不记录),只许追加文件但不可以改写文件,redis 启动之初会读取该文件重新构建数据,换言之,
redis 重启的话就根据日志文件的内容将写指令从前到后执行一次以完成数据的恢复工作

2)、持久化流程

(1)、客户端的请求写命令会被append 追加到 AOF 缓冲区内;
(2)、AOF缓冲区根据AOF持久化策略[always,everysec,no]将操作 sync 同步到磁盘的 AOF 文件中;
(3)、AOF 文件大小超过重写策略或手动重写时,会对AOF文件rewrite 重写,压缩 AOF 文件容量;
(4)、Redis服务重启时,会重新load加载AOF文件中的写操作达到数据恢复的目的;

3)、AOF同步频率

修改appendfsync:
always 每一次写入redis都会同步
everysec 每一秒进行同步
no redis不主动同步,将同步时机交给操作系统

4)、优势

(1)、备份机制更稳健,丢失数据率更低
(2)、可读的日志文本,通过操作AOF文件,可以处理误操作

5)、劣势

(1)、比RDB占用更多的磁盘空间
(2)、恢复备份速度要慢
(3)、每次读写都要同步的话,对性能有一定的压力
(4)、存在潜在的bug

3、AOF默认是不开启的,RDB和AOF二者都打开,redis以AOF数据为主

4、异常修复:

1)、RDB修复: redis-check-rdb --fix 需要修复的文件名
2)、AOF修复: redis-check-aof --fix 需要修复的文件名

十、主从复制

1、一主二从搭建

1)、启动三个redis,可以使用include引用公共配置文件

include /usr/local/redis/bin/redis.conf
pidfile /usr/local/redis/bin/6379.pid
port 6379
dbfilename dump6379.rdb

2)、slaveof ip port 指定主节点
3)、info replication 查看各节点状态

注:继续添加从节点或者从节点重启,它会重新同步主节点的key,该类型的主节点挂掉后,从节点不会变成主节点,等主节点重启后,会根据rdb文件进行数据恢复

2、主从复制原理:

1)、在从节点连上主节点后,从节点会向主节点发送请求,然后主节点会将rdb文件发送给从节点,从节点进行数据读取
2)、在主节点每次数据写入后,主节点会将数据同步给从节点

3、哨兵模式;

开启:新建sentinel.conf文件,内容为;sentinel monitor mymaster 127.0.0.1 6379 1
mymaster为监控对象名称,1为至少有多少个哨兵同意迁移模式

4、从节点选举

(1)、首先根据个节点的replica-priority属性判断,值越小,优先级越高
(2)、根据各从节点的偏移量,也就是同步主节点的数据量进行比较,越多的,优先级越高
(3)、redis启动时会随机生成runid,runid越小,优先级越高

十一、redis集群

cluster-require-full-coverage为yes时:当集群中一个节点挂掉,整个集群都不能访问,为no的话,其余节点还可以正常访问

1、新建配置文件:

include /usr/local/redis/bin/redis.conf
pidfile /usr/local/redis/bin/6380.pid
port 6380
dbfilename dump6380.rdb
cluster-enabled yes
cluster-config-file node-6380.conf
cluster-node-timeout 15000

2、启动各个节点,检查所有节点的node-6379.conf文件是否生成

3、把各节点生成一个集群(最少为3主3从)

首先进入到redis安装目录的src下:cd /usr/local/redis/src
然后执行:redis-cli --cluster create --cluster-replicas 1 各节点的ip:port
该命令中的1 为使用最简单的方式生成集群

4、集群命令:

1)、集群连接:./redis-cli -p 6379 -c
2)、集群信息查看:cluster nodes
3)、查看key的slot;cluster keyslot key

5、优点;

1)实现扩容
2)分摊压力
3)无中心配置相对简单

6、缺点

1)多键操作是不支持的,因为需要通过key计算插槽的值
2)多键的redis事务不被支持,lua脚本不被支持

十二、Redis常见问题

1、缓存穿透:

缓存穿透(cache penetration)是用户访问的数据既不在缓存当中,也不在数据库中。出于容错的考虑,如果从底层数据库查询不到数据,则不写入缓存。这就导致每次请求都会到底层数据库进行查询,缓存也失去了意义。当高并发或有人利用不存在的Key频繁攻击时,数据库的压力骤增,甚至崩溃,这就是缓存穿透问题。

解决方案:

(1)缓存空值(null)或默认值
(2)业务逻辑前置校验
(3)使用布隆过滤器请求白名单
(4)用户黑名单限制

2、缓存雪崩:

在使用缓存时,通常会对缓存设置过期时间,一方面目的是保持缓存与数据库数据的一致性,另一方面是减少冷缓存占用过多的内存空间。但当缓存中大量热点缓存采用了相同的实效时间,就会导致缓存在某一个时刻同时实效,请求全部转发到数据库,从而导致数据库压力骤增,甚至宕机。从而形成一系列的连锁反应,造成系统崩溃等情况,这就是缓存雪崩(Cache Avalanche)。

解决方案:

(1)通常的解决方案是将key的过期时间后面加上一个随机数(比如随机1-5分钟),让key均匀的失效。
(2)考虑用队列或者锁的方式,保证缓存单线程写,但这种方案可能会影响并发量。
(3)热点数据可以考虑不失效,后台异步更新缓存,适用于不严格要求缓存一致性的场景。
(4)双key策略,主key设置过期时间,备key不设置过期时间,当主key失效时,直接返回备key值。
(5)构建缓存高可用集群(针对缓存服务故障情况)。
(6)当缓存雪崩发生时,服务熔断、限流、降级等措施保障。

3、缓存击穿:

从定义上可以看出,缓存击穿和缓存雪崩很类似,只不过是缓存击穿是一个热点key失效,而缓存雪崩是大量热点key失效。因此,可以将缓存击穿看作是缓存雪崩的一个子集。

解决方案

(1)使用互斥锁(Mutex Key),只让一个线程构建缓存,其他线程等待构建缓存执行完毕,重新从缓存中获取数据。单机通过synchronized或lock来处理,分布式环境采用分布式锁。
(2)热点数据不设置过期时间,后台异步更新缓存,适用于不严格要求缓存一致性的场景。
(3)”提前“使用互斥锁(Mutex Key):在value内部设置一个比缓存(Redis)过期时间短的过期时间标识,当异步线程发现该值快过期时,马上延长内置的这个时间,并重新从数据库加载数据,设置到缓存中去。

十三、Redis分布式锁

1、命令实现:

setnx key value ex:设置key并设置其过期时间
分布式环境下可能会导致加锁时的key和释放时的key不一致,便可以使用uuid当做key,释放时比较uuid的值,保证释放的key与加锁时一致

2、为了确保分布式锁可用,我们至少要确保锁的实现同时满足以下四个条件:

(1)互斥性。在任意时刻,只有一个客户端能持有锁。
(2)不会发生死锁。即使有一个客户端在持有锁的期间朋溃而没有主动解锁, 能保证后续其他客户端能加锁。
(3)解铃还须系铃人。加锁和解锁必须是同一个客户端,客户端自己不能把别人 加的锁给解了。
(4)加锁和解锁必须具有原子性。

十四、Redis新功能

1、acl更细粒度的权限控制

(1)接入权限,用户名和密码
(2)设置用户可以执行的命令
(3)可以操作的key
详细可见:ACL | Docs

2、Redis支持多线程

(1)该多线程指的是客户端交互部分的网络IO交互处理模块多线程,执行命令依旧是单线程
(2)多线程默认是关闭的,开启需要设置配置文件:io-threads-do-reads no ,io-threads 4

Redis相关命令:

1、切换库: select db
2、查看当前数据库key的数量:dbsize
3、清空当前库:flushdb
4、清空所有库:flushall
5、判断key是否存在;exist key
6、查看key的类型: type key
7、设置key过期时间: expire key time
8、查看还有多久过期;ttl key ,-1:永不过期,-2已经过期
9、异步删除: unlink key ,String类型不会做异步删除

以下是string类型的命令:

1、将值添加到已有key后边;append key value
2、获得值的长度:strlen key
3、只有可不存在的情况下设置:setnx key value
4、数字类型的值+/- 1: incr/decr key
5、自定义加的数值: incrby/decrby key value
6、设置多个key-value:mset key1 value key2 value
7、获取多个key的值:mget key1 key2
8、设置多个库中没有的key-value:
msetnx k1 v1 k2 v2 该设置为原子性,同时成功或同时失败
9、获取范围值:getrange key 起始位置 结束位置
10、从某一个位置设置值:setrange key 起始位置 索要设置的值
11、设置key同时设置过期时间:setex key expire value
12、新值换旧值:getset key value 返回原有值,设置新值

以下是list类型的命令

1、从左边/右边插入值: lpush/rpush key v1 v2 v3
2、获取值: lrange key start end(lrange k1 0 -1 表示获取所有值)
3、从左边、右边吐出值:lpop/rpop key 值在键在,值光键无
4、从k1左边取值插到k2右边:lpoprpush k1 k2
5、按照索引下表获取值:lindex key index
6、获取长度:llen key
7、在key的值的前后插入值:linset key before/after value
8、从左边删除n个值: lrem key n value
9、根据index替换值: lset key index value

以下是set类型的命令

1、将一个或多个值添加到key中:sadd key v1 v2
2、获取所有值:smembers key
3、判断key中有无改值,1有0无:sismember key value
4、查询个数:scard key
5、删除集合中的某个元素:srem key value
6、随机从集合中吐出值:spop key
7、随机取出n个值,不会删除key:srandmember key n
8、从k1集合取值到k2集合:smove k1 k2 value
9、返回两个集合的交集元素:sinter key1 key2
10、返回两个集合的并集:sunion key1 key2
11、返回两个元素的差集(key1中的不包含key2的):sdiff key1 key2

以下是hash类型的命令

1、给集合key赋值:hset key field value
2、从集合中取值:hget key filed
3、批量添加多个值:hmet key field value field value
4、查看key中是否存在field:hexists key field
5、列出集合所有field: hkeys key
6、列出集合所有value: hvals key
7、给集合的某个field加值:hincrby key field increment
8、将key中的field设置值(当filed不存在时可设置成功):hsetnx key field value

以下是zset类型的命令

1、一个或多个添加到集合中:zadd key score1 value1 score2 value2
2、取出集合中的值:zrange key start stop <withscores>(加withscores 可以使分数和值一起返回)
3、取出范围内的值,依据score由小到大:zrangebyscore key start stop
4、取出范围内的值,依据score由大到小:zrevrangeByscore key start stop
5、为元素的score加上增量:zincrby key increment value
6、删除集合中指定元素:zrem key value
7、统计分数间的总数:zcount key min max
8、返回集合中的排名:zrank key value

以下是Bitmaps类型的命令

1、添加值到bitmaps:setbit key offset value
2、获取值:getbit key offset
3、统计值为1的数量:bitcount key
4、符合操作;bittop

以下是HyperLogLog类型的命令

1、添加数据到HyperLogLog中:pfadd key ele [ele ele]
2、统计基数数量: pfcount key
3、将一个或者多个合并到一个HLL中:pfmerge new o [o o]

以下是geospatial类型的命令

1、添加坐标信息:geoadd key 经度 纬度 城市名字
2、获取某一城市的坐标:geopos key 城市名字
3、获取两地之间的直线距离:geodist key cityname cityname 单位(m/km/英尺) 默认单位是米
4、给定坐标半径内的城市:georadius key 经度 纬度 距离 单位

  • 30
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值