Redis

1、什么是Redis

  • NoSql数据库
  • 分布式缓存中间件
  • key-value存储
  • 提供海量数据存储访问
  • 数据存储在内存里,读取更快

2、缓存方案对比

缓存方案 优点 缺点
Ehcache
  1. 基于Java开发
  2. 基于JVM缓存
  3. 简单、轻巧、方便
  1. 集群不支持(缓存不共享)
  2. 分布式不支持
Memcache
  1. 简单的key-value存储(单一String类型)
  2. 内存使用率比较高
  3. 多核处理,多线程
  1. 无法容灾
  2. 无法持久化
Redis
  1. 丰富的数据结构
  2. 持久化
  3. 主从同步、故障转移
  4. 内存数据库
  1. 单线程(6.0加入多线程)
  2. 单核

3、Redis的数据类型

3.1 string

string:最简单的字符串类型键值对缓存。

key相关

keys * : 查看所有的key(不建议在生产环境上使用,有性能影响)

type key: key的类型

string类型

  • get/set/del:查询/设置/删除
  • set key value: 设置key(已存在,则覆盖)
  • setnx key value: 设置key(已存在,不覆盖)
  • set key value ex time: 设置带过期时间的数据
  • expire key: 设置过期时间
  • ttl: 查看过期时间, -1-永不过期, -2已过期
  • append key: 追加字符串
  • strlen key:字符串长度
  • incr key: 数字值累加一
  • decr key:数字值累减一
  • incrby key num: 累加给定数值
  • decrby key num: 累减给定数值
  • getrange key start end: 截取数据, end=-1 代表最后
  • setrange key start newdata: 从start位置开始替换数据
  • mset: 连续设值
  • mget: 连续取值
  • msetnx: 连续设值不覆盖

3.2 list

list:列表,[a,b,c,d,…]

  • lpush userList 1 2 3 4 5:构建一个list,从左边开始存入数据
  • rpush userList 1 2 3 4 5:构建一个list,从右边开始存入数据
  • lrange list start end:获得数据
  • lpop:从左侧开始拿出一个数据
  • rpop:从右侧开始拿出一个数据
  • llen list:list长度
  • lindex list index:获取list下标的值
  • lset list index value:把某个下标的值替换
  • linsert list before/after value:插入一个新的值
  • lrem list num value:删除几个相同数据
  • ltrim list start end:截取值,替换原来的list

3.3 hash

hash:类似map,存储结构化数据结构,比如存储一个对象(不能有嵌套对象)

  • hset key property value:
    -> hset user name xybh
    -> 创建一个user对象,这个对象中包含name属性,name值为xybh
  • hget user name:获得用户对象中name的值
  • hmset:设置对象中的多个键值对
    -> hset user age 18 phone 139123123
  • hmsetnx:设置对象中的多个键值对,存在则不添加
    -> hset user age 18 phone 139123123
  • hmget:获得对象中的多个属性
    -> hmget user age phone
  • hgetall user:获得整个对象的内容
  • hincrby user age 2:累加属性
  • hincrbyfloat user age 2.2:累加属性
  • hlen user:有多少个属性
  • hexists user age:判断属性是否存在
  • hkeys user:获得所有属性
  • hvals user:获得所有值
  • hdel user:删除对象

3.4 set

set 是 String 类型的无序集合。集合成员是唯一的,这就意味着集合中不能出现重复的数据。

  • sadd: 增加新元素
  • sismember: 判断元素是否在set中
  • sinter: 查看多个set的交集
  • spop: 随机删除一个或多个元素并返回
  • srandmember:随机获取一个元素
  • scard: 获取set的成员数
  • key: 返回集合中的所有成员

3.5 zset

sorted set:排序的set,可以去重可以排序,比如可以根据用户积分做排名,积分作为set的一个数值,根据数值可以做排序。

  • zadd zset 10 value1 20 value2 30 value3:设置member和对应的分数
  • zrange zset 0 -1:查看所有zset中的内容
  • zrange zset 0 -1 withscores:带有分数
  • zrank zset value:获得对应的下标
  • zscore zset value:获得对应的分数
  • zcard zset:统计个数
  • zcount zset 分数1 分数2:统计个数
  • zrangebyscore zset 分数1 分数2:查询分数之间的member(包含分数1 分数2)
  • zrangebyscore zset (分数1 (分数2:查询分数之间的member(不包含分数1 和 分数2)
  • zrangebyscore zset 分数1 分数2 limit start end:查询分数之间的member(包含分数1 分数2),获得的结果集再次根据下标区间做查询
  • zrem zset value:删除member

redis sorted sets里面当items内容大于64的时候同时使用了hash和skiplist两种设计实现。这也会为了排序和查找性能做的优化。所以如上可知:

添加和删除都需要修改skiplist,所以复杂度为O(log(n))。

但是如果仅仅是查找元素的话可以直接使用hash,其复杂度为O(1)

其他的range操作复杂度一般为O(log(n))

当然如果是小于64的时候,因为是采用了ziplist的设计,其时间复杂度为O(n)

4、Redis线程模型

请求过程:

Redis-cli发送Readable/Writable事件,使用Socket与Redis-server通信,Redis-server使用多路复用器(同步非阻塞)将事件发送到文件事件分配器,文件事件分配器根据请求类型转发至连接应答处理器/命令请求处理器/命令应答处理器

5、发布与订阅

5.1 发布

publish channel messgae: 将消息发送到指定的频道。

5.2 订阅

psubscribe pattern 订阅一个获多个符合给定模式的频道

pubsub subcommand 查看订阅和发布系统状态

subscribe channel 订阅给定的一个或多个频道的信息

unsubscibe channel 退订给定的频道

6、Redis读写分离(主从架构)

6.1 主从架构

Redis主从架构: master节点做到一个分发命令的功能,主节点将数据复制给从库节点。(水平扩展,通过增加服务器来提高性能)

6.2 主从原理

  1. 从Redis第一次连接主Redis,使用全量复制
  • 从服务器连接主服务器,发送SYNC命令;
  • 主服务器接收到SYNC命名后,开始执行BGSAVE命令生成RDB文件并使用缓冲区记录此后执行的所有写命令;
  • 服务器BGSAVE执行完后,向所有从服务器发送快照文件,并在发送期间继续记录被执行的写命令;
  • 从服务器收到快照文件后丢弃所有旧数据,载入收到的快照;
  • 主服务器快照发送完毕后开始向从服务器发送缓冲区中的写命令;
  • 从服务器完成对快照的载入,开始接收命令请求,并执行来自主服务器缓冲区的写命令;
  1. 增量同步
    Redis增量复制是指Slave初始化后开始正常工作时主服务器发生的写操作同步到从服务器的过程。
    增量复制的过程主要是主服务器每执行一个写命令就会向从服务器发送相同的写命令,从服务器接收并执行收到的写命令。

Redis主从同步策略
主从刚刚连接的时候,进行全量同步;全同步结束后,进行增量同步。当然,如果有需要,slave 在任何时候都可以发起全量同步。redis的策略是,无论如何,首先会尝试进行增量同步,如不成功,要求从机进行全量同步。(Master必须要开启持久化)

6.3 主从模式

一般采用一主二从,一主多从比较少,因为主从同步需要占用带宽,较多从节点可能会占用较多带宽。

7、Redis缓存过期机制

  1. (主动)定期删除

    • 定时随机的检查过期的key,如果过期则清理删除。(每秒检查次数在redis.conf中的hz配置)
  2. (被动)惰性删除
    • 当客户端请求一个已经过期的key的时候,那么redis会检查这个可以是否过期,如果过期了,则删除,然后返回一个nil。

如果内存被Redis缓存占用满了怎么办?

​ 当内存占用满了后,redis提供了一套缓存淘汰机制:MEMORY MANAGEMENT

  • noevivcation:旧缓存永不过期,新缓存设置不了,直接返回错误
  • allkeys-lru:清除所有键中最少使用的旧缓存,然后保存新缓存(推荐使用)
  • allkeys-random:在所有缓存中随机删除(不推荐)
  • volatile-lru:在设置了过期时间的缓存中,清除最少用的旧缓存,然后保存新的缓存
  • volatile-random:在设置了过期时间的缓存中,随机删除缓存
  • volatile-ttl:在设置了过期时间的缓存中,删除即将过期的缓存

8、Redis哨兵模式

  1. 配置sentinel.conf(默认端口 26379)
  2. sentinel monitor master_name ip_address port quorum(quorum 哨兵检测数量)
  3. sentinel auth-pass master_name password

9、Redis异常

9.1 缓存穿透

缓存穿透是指缓存和数据库中都没有的数据,而用户不断发起请求,如发起为id为“-1”的数据或id为特别大不存在的数据。这时的用户很可能是攻击者,攻击会导致数据库压力过大。

解决方案:

  1. 接口层增加校验,异常请求直接拦截
  2. 在缓存和数据库都取不到数据的情况下,可以增加key-null的短期缓存(如30秒,5分钟)
  3. 设置布隆过滤器(存在误判率,返回无数据必为无数据,有数据不一定有数据)

9.2 缓存雪崩

缓存雪崩是指缓存中数据大批量到过期时间,而查询数据量巨大,引起数据库压力过大甚至宕机。和缓存击穿不同的是,缓存击穿指并发查同一条数据,缓存雪崩是不同数据都过期了,很多数据都查不到从而查数据库。

解决方案:

  1. 设置不同的过期时间
  2. 设置热点信息永不过期
  3. 多缓存结合
  4. 使用分布式Redis,热点信息存储在不同的Redis中

9.3 缓存击穿

缓存击穿是指缓存中没有但数据库中有的数据(一般是缓存时间到期),这时由于并发用户特别多,同时读缓存没读到数据,又同时去数据库去取数据,引起数据库压力瞬间增大,造成过大压力

解决方案:

  1. 设置热点信息永不过期
  2. 加互斥锁

工具类

RedisOperator.java

public class RedisOperator {@Autowiredprivate StringRedisTemplate redisTemplate;// 键 操作/*** 实现 TTL key, 以秒为单位,返回过期时间** @param key 键* @return 过期时间*/public long ttl(String key) {return redisTemplate.getExpire(key);}/*** 设置过期时间,单位: 秒** @param key     键* @param timeout 过期时间*/public void expire(String key, long timeout) {redisTemplate.expire(key, timeout, TimeUnit.SECONDS);}/*** 设置过期时间** @param key      键* @param timeout  过期时间* @param timeUnit 时间单元*/public void expire(String key, long timeout, TimeUnit timeUnit) {redisTemplate.expire(key, timeout, timeUnit);}/*** 增加key1次** @param key 键*/public void incr(String key) {redisTemplate.opsForValue().increment(key);}/*** 增加<ref>num</ref>次** @param key 键* @param num 值*/public void incyByNum(String key, long num) {redisTemplate.opsForValue().increment(key, num);}/*** 减少key1次** @param key 键*/public void decr(String key) {redisTemplate.opsForValue().decrement(key);}public void decrByNum(String key, long num) {redisTemplate.opsForValue().decrement(key, num);}public Set<String> keys(String pattern) {return redisTemplate.keys(pattern);}public void del(String key) {redisTemplate.delete(key);}// string 操作/*** 设置值** @param key* @param value*/public void set(String key, String value) {redisTemplate.opsForValue().set(key, value);}/*** 设置值和过期时间** @param key* @param value* @param timeout*/public void setAndExpire(String key, String value, long timeout) {redisTemplate.opsForValue().set(key, value, timeout, TimeUnit.SECONDS);}/*** 获取值** @param key* @return*/public String get(String key) {return redisTemplate.opsForValue().get(key);}/*** 获取一段范围内的字符** @param key* @param start* @param end* @return*/public String getRange(String key, long start, long end) {return redisTemplate.opsForValue().get(key, start, end);}/*** 设置不存在的键** @param key* @param value*/public void setn(String key, String value) {redisTemplate.opsForValue().setIfAbsent(key, value);}/*** 批量查询, 对应mget** @param keys* @return*/public List<String> mget(List<String> keys) {return redisTemplate.opsForValue().multiGet(keys);}// hash 操作public void hset(String key, String filed, String value) {redisTemplate.opsForHash().put(key, filed, value);}public String hget(String key, String filed) {return (String) redisTemplate.opsForHash().get(key, filed);}public void hdel(String key, Object... filed) {redisTemplate.opsForHash().delete(key, filed);}public Map<Object, Object> hgetAll(String key) {return redisTemplate.opsForHash().entries(key);}// list 操作public void lpush(String key, String value) {redisTemplate.opsForList().leftPush(key, value);}public void lpush(String key, String... value) {redisTemplate.opsForList().leftPushAll(key, value);}public void rpush(String key, String value) {redisTemplate.opsForList().rightPush(key, value);}public void rpush(String key, String... value) {redisTemplate.opsForList().rightPushAll(key, value);}public String lpop(String key) {return redisTemplate.opsForList().leftPop(key);}public String rpop(String key) {return redisTemplate.opsForList().rightPop(key);}
}

思维导图

Redis基础(思维导图)附Redis工具类相关推荐

  1. 中职教材计算机应用基础思维导图,思维导图在中职《计算机应用基础》教学中应用.doc...

    思维导图在中职<计算机应用基础>教学中应用 思维导图在中职<计算机应用基础>教学中应用摘 要:本文阐述了思维导图的涵义及特点,并结合中职<计算机应用基础>教学的现状 ...

  2. 国产的markdown 语法的思维导图和大纲工具!

    MarkMind 简介 MarkMind 是一款支持markdown语法的思维导图和大纲工具,主要特色就是在节点内部直接支持markdown语法. Markdown是一种纯文本格式的标记语言.通过简单 ...

  3. Linux入门基础思维导图

    Linux入门基础思维导图 01 发行版本 02 系统目录 欢迎关注微信公众号[厦门微思网络].www.xmws.cn专业IT认证培训19周年 03 环境安装 04 SSH服务 05 启动模式策略 / ...

  4. 40张最全计算机网络基础思维导图

    hi,大家好,今天的网络基础思维导图主要是二,三层网络协议,再配合之前的文章(四层以上互联网核心协议): TCP/IP协议精华指南pdf发布 非常适合对网络感兴趣的同学,同时也让大家对整个网络架构有一 ...

  5. MySQL基础思维导图

    MySQL基础思维导图 PDF清晰版本下载地址

  6. python基础思维导图

    python基础思维导图

  7. 【收藏】最全计算机网络基础思维导图

    最全计算机网络基础思维导图 传输介质简介 以太网帧结构 IP编址 ICMP协议 ARP协议 传输层协议 路由基础 静态路由基础 距离矢量路由协议--RIP 链路状态协议--OSPF HDLC& ...

  8. 什么是思维导图  绘制思维导图用什么工具

    思维导图作为一种工具.思想表达方式,已经越来越被人们接受和使用,但是有的人用思维导图方便了自己的工作.生活,而有的人就只限于随便涂抹. 思维导图能否真正的为人们所用,关键在于人们有没有思考,有没有行动 ...

  9. 项目管理大法归档 - 思维导图、原型工具、接口测试、设计模式、版本管理、单元测试、持续集成、代码审查、Bug 跟踪

    项目管理大法归档 - 思维导图.原型工具.接口测试.设计模式.版本管理.单元测试.持续集成.代码审查.Bug 跟踪 太阳火神的美丽人生 (http://blog.csdn.net/opengl_es) ...

最新文章

  1. 前端不为人知的一面--前端冷知识集锦
  2. 联合国隐私监督机构:大规模信息监控并非行之有效
  3. 【线上分享】互动协作白板与音视频实时同步技术实践
  4. 第四节:EF Core的并发处理
  5. 自由软件基金会庆祝成立35周年
  6. Linux Shell 文本处理工具集锦 zz
  7. 怎样呵护友谊_家长怎样与孩子有效的交流沟通
  8. 电大计算机网络技术基础,电大--2016年电大 计算机与网络技术基础小抄已排版.doc...
  9. Field userManageService in com....
  10. android recover 系统代码分析 -- 选择进入
  11. 2020职场自顾自说
  12. 火山图 volcano
  13. bootstrap导航栏.nav和.navbar区别
  14. 苹果“教主”乔布斯:一个人的世界
  15. 联想G40-70旧物改造小总结——替换固态硬盘电池光驱啥的
  16. CoAP协议及开源实现
  17. Javascript变量名混淆细节
  18. matlab loglog
  19. 【顺序表】顺序表定位
  20. 我终于刷完了《觉醒年代》,对PMP有了新的思考...

热门文章

  1. xftp/xshell中文乱码
  2. 《JavaScript忍者秘籍》(第二版)- 第5章 -精通函数:闭包和作用域
  3. 天津理工大学计算机考研资料汇总
  4. 汽车UDS诊断之读取DTC信息服务(0x19)深度剖析
  5. python colorbar范围_python-在matplotlib中设置colorbar范围
  6. 全新部署蓝鲸社区版6.0(1)
  7. 使用mfc设计长方形的类
  8. 浙江高考VB之排序系列
  9. 【精讲】2022年PHP中高级面试题
  10. 为满足安全标准而提供的ADAS Inspector Solution