Java-Redis
文章目录基础基础内容使用场景/功能常见数据类型下载与安装可视化多个发布订阅功能事务两种持久化主从模式哨兵模式集群模式Cluster缓存淘汰过期删除缓存一致 Cache Aside缓存击穿缓存穿透缓存雪崩分布式锁实战内容配置文件配置Redis的BeanRedis为什么这么快Hash冲突怎么办Redis和本地Cache存储的区别项目与redis服务配置方式不同Promise和Futrue多种redis配置模式基础基础内容概念Redis全称为RemoteDictionaryServer远程数据服务是开源的、基于内存的、键值对存储系统是非关系型、日志型数据库 特点 性能高 数据类型丰富单键值对最大支持512M大小的数据 简单易用支持所有主流编程语言 支持数据持久化、主从复制、哨兵模式等使用场景/功能高性能缓存服务器 用于减轻数据库服务器的压力项目运行将所必须内容加载到Redis中提高项目对数据的获取速度 数据共享Redis是分布式的独立服务可以多个项目使用相同的Redis 分布式锁 实现对某操作的原子性执行推荐使用redisson第三方库实现 全局id incrby 利用原子性incrby userid1000分库分表的场景一次性拿一段 计数器 incr方法实现目前涉及到的内容集中在计费操作通过incr记次数实现 限流 incr 本质还是统计次数然后利用最大值限制 位统计 用于大数据量的统计通过二进制表示数据 还有很多不做详细介绍了 用到哪种学习哪种 参考博客https://blog.csdn.net/agonie201218/article/details/123640871常见数据类型字符串Stringkey是区分大小写的 默认使用String类型存储键值对 get获取的key对应的value是不存在那么会输出nil 不支持中文存储value只是通过二进制形式存储若想正常实现存储内容需要在登录的时候采用redis-cli--raw登录TTL查询key对应的过期时间值为-1则表示该键没有过期时间值为-2表示该key已经过期了列表List存储和操作一组有顺序的数据 输入输出可以类比栈单向输入输出 lPush在左侧输入输出RPush在右侧输入输出输入元素是abc 那么输出是cba lPop 和RPop也是类似的操作Llen获取 长度 可以重复的 相关命令以l开头集合Set不可以重复 smembers course 假设该set集合没有元素则返回empty list or set 相关命令以S开头有序集合 SortedSet每一个key都会关联一个浮点类型的分数会按照这个分数排序从小到大来排序 有序集合的元素是唯一的但是分数是可以重复的 相关命令都是z开头哈希hash键值对的集合适合存储对象 相关命令都以h开头消息队列 Stream可以解决发布订阅功能的缺点 相关命令都以x开头 涉及到消费者组、以及消息的多次读取地理空间 Geospatial存储地理位置信息的数据结构同时对地理位置进行计算操作 相关命令都以Geo开头 如果key-value存储地点-经纬度那么通过查询key得到的是一个数组 如果计算两个value之间的距离返回结果默认是米 查询某个key在指定半径内的其他key 命令GEOSEARCHCityFROMMEMBERshanghaiBYRADIUS1000KM查询key上海1000千米范围内的key城市HyperLogLog是一种用来做基数统计的算法基于随机算法牺牲一些精确度的角度来减轻内存消耗 基数如果集合中的元素都不重复那么基数集合中元素的个数 例如集合12345它的基数是5集合1122334455它的基数仍旧是5 优点占用内存小缺点精度不高 适用场景数据量大且不需要精确度的情况 相关命令都以pf开头位图Bitmap字符串类型的扩展可以使用字符串模拟一个数组 数组的下标就是偏移量值只有0和1也支持位运算与 或 非 异或等 相关命令有bit开头或bit结尾位域Bitfield将小的整数存储到一个较大的位图中可以高校的使用内存下载与安装三种方式实现linux系统 windows系统的压缩包安装 windows系统的docker desktop 镜像安装停止终端的方式按下ctrlc 或者 关闭终端页面可视化多个参考链接https://blog.csdn.net/WeiHao0240/article/details/123423230参考博客https://blog.csdn.net/boboJon/article/details/135073969发布订阅功能订阅频道 subscribe xxx 发布消息到频道 publish xxx 消息内容 订阅频道的终端可以有多个 缺点 消息无法持久化 无法记录历史消息事务概念在一次请求中执行多条命令 通过MULTI开启事务将后续所有命令放入队列中通过EXEC执行队列中命令 并不能保证事务中的所有命令都执行成功 可以保证的内容 执行EXEC命令之前会将所有命令都缓存起来不立即执行 执行EXEC命令事务中的某个命令执行失败其余命令不会受到影响 执行EXEC命令过程中其他用户提交的命令不会插入得到命令的执行序列中 通过MULTI启动事务指令会多TX标识符 再次输入命令会返回QUEUED表示已经放入命令执行队列两种持久化是一个重要的功能Redis是基于内存的如果断点则会导致数据丢失所以必须有持久化操作 两种方式RDB和AOF方式RDBRedisDatabase在指定时间间隔内将内存中的数据快照写入磁盘中 某个时间点上完整副本 通过save参数配置 save 参数1参数2--》参数1时间间隔 参数2修改次数 更适合用来做备份因为如果服务宕机那么快照最后一次后的所有修改就会丢失 思考1 由于正式环境中 redis都会给分配较大的内存空间通过RDB进行备份的时候redis是不能进行处理的会影响业务 通过提供bgsave命令处理会创建一个子进程专门处理备份主进程处理业务但是在创建子进程的过程中仍旧不能处理业务AOF:执行追加文件在执行写命令的过程中不仅会将结果写入数据库中而且会将写命令写入追加文件中AOF文件 redis执行写操作时会重新执行AOF文件重新构建数据库 开启AOF方式配置文件中将appendonly参数值改成yes主从模式将主节点数据复制到从节主节点-master从节点slave 从节点可以有很多每个从节点只能有一个主节点 数据的复制是单向的只能从主节点到从节点 主节点负责写操作从节点负责读操作 主节点通过异步的方式向从节点发送数据从节点收到后更新自己的数据 一台主机上可以配置多个redis 通过不同的端口号进行区分配置主节点 不需要配置因为默认就是主节点 设置从节点的方式两种命令 以及 配置文件修改 命令 role--》 查看当前节点角色 replicaf host port--》配置所属主节点 配置文件是redis.conf文件 修改端口号port pidfile 都要修改端口号 dbfilename 配置也要加上端口号 rplicaof host port 配置主节点Redis默认是以守护进程的方式运行系统默认会将pid写入文件中 redis-cli登录 info replication 查看配置信息哨兵模式主从模式存在问题当主节点宕机之后需要人工干预将从节点提升为主节点哨兵模式哨兵以一个独立的进程运行在一个Redis集群中用来监控Redis集群中的节点是否运行正常 作用 监控会不断向各个节点发送指令检查各个节点的是否正常运行 通知发现某个节点不能正常工作会通过发布订阅模式通知其他节点 自动故障转移会将从节点变成新的主节点再将其他从节点指向该主节点 哨兵模式配置 配置文件sentinel.conf 内容 sentinel monitor master ip port1ip 和 port都是主节点的1使用一个哨兵来实现故障转移 正式环境中一般都采用3个哨兵防止哨兵节点宕机 启动哨兵模式 redis-sentinel sentinel.conf集群模式Cluster解决问题 采用主从复制、哨兵机制每台机子上完整存储所有数据当数据量特别大的时候这种情况是无效的 定义 cluster是redis提供的分布式数据库解决方案将所有数据分片节点进行领取即使某些节点宕机也还可以执行操作 数据分片 将key通过CRC16校验函数计算再对16384取模运算再决定数据分配到哪个槽位也即是片、slot 每个redis的cluster节点负责一部分槽数据的存储槽数据存储在特定槽上的所有键值对 这些节点再结合主从复制模式对数据进行备份 查询策略 每个节点都会存储整个集群节点信息这些叫元信息 元信息各节点存储的槽数据、master和slave状态、节点存活状态 两次查询实现数据查询 元信息传递 gossip协议每个节点把自己的数据信息通过协议传递出去 具体过程周期性执行所有被感染的节点选择k个相邻的节点散播消息 扩容缩容 当数据量大时增加节点数据量少减少节点缓存淘汰淘汰策略常用的三个默认是LRU先进先出FIFO 类似一个队列淘汰最早载入缓存的数据 最近最早使用LRU 老数据按照最近被访问的时间排序末端节点删除 实现思路-双向链表哈希表双向链表存储键值对哈希表存储key和双向链表的node节点的指针引用 具体执行 当某个key被访问到会将其对应的node节点放到双向链表的头部 最不经常使用LFU 多一个 被访问次数 这个属性 keyvalue 结合被访问次数组成新的数据结构 将该数据结构放入双向链表中按照次数从大到小的排序方式先替换排在最后的元素过期删除默认采用定期删除 目前有三种策略主动删除、惰性删除、定期删除 主动删除 设置错误间隔时间在指定时间后进行主动删除 缺点当redis比较忙删除时间刚好到了则会增加服务器的负担 惰性删除 程序访问某个数据先判断是否已经过期没过期则返回反之则删除 缺点只有当被访问到的时候才进行删除会导致内存中存在大量无效数据造成资源的浪费 定期删除 主动删除惰性删除 每个一段时间执行主动删除其余时间采用惰性删除缓存一致 Cache Aside定义 后端缓存数据数据库数据并不是时时刻刻保持一致允许在一定小范围内出现不一致的情况 采用策略CacheAside策略 模式1删除缓存、更新数据库 模式2更新数据库、更新缓存Read/WriteThrough将缓存作为主要的数据读取方式如果缓存中没有数据则更新缓存再从缓存中取数WriteBehind更新数据库与更新缓存都采用异步的形式 结合mysql的主从复制模式将mysql作为主服务redis作为从服务模式1模式2Read/Write ThroughWrite Behind缓存击穿定义 查询某个数据的值缓存中没有而数据库中有 危害 如果访问该key的量特别大且缓存中没有则请求全部会访问数据库 redis的性能是mysql数据库的10-100倍当访问量redis可以承受时转到mysql上可能就会导致mysql宕机 解决 mysql角度加锁控制redis击穿之后数据库的并发访问量 redis角度热点数据永不过期异步线程将重要数据、已经过期的 进行过期时间重置缓存穿透定义 一条查询数据缓存中没有数据库中也没有 解决方法 拦截非法请求 缓存空对象 布隆过滤器布隆过滤器缓存雪崩定义 一大批缓存数据都失效故此这批请求都会被打到数据库上导致数据库宕机 与缓存击穿的区别 缓存击穿是单点缓存雪崩是多点 解决方式 mysql角度加锁减少数据库并发量 redis角度 热点数据永不过期 让失效时间分散点 缓存预热即在上线前根据当天的情况将数据直接加载到缓存系统分布式锁实战内容配置文件单机模式spring: redis: enable: true // 意图是控制是否启用Redis功能 host: localhost port: 6379 database: 0 // redis数据库的索引表示第一个数据库 timeout: 10000ms // Redis服务器的超时时间单位ms也就是10秒 lettuce: // spring data redis默认使用的客户端 pool: // 配置lettuce的连接池配置 max-active: 8 // 最大活动连接数 max-idle: 8 // 最大空闲连接数 min-idle: 0 // 最小空闲连接数 max-wait: -1ms // 获取连接的最大等待时间主从模式// 通过spring.redis.sentinel来配置 spring: redis: sentinel: // 配置使用主从复制模式 master: mymaster // 指定主服务器组 nodes: - sentinel1:26379 - sentinel2:26379 - sentinel3:26379 // seninel实例的主机名或ip 以及端口号 database: 0 timeout: 10000ms password: yourpassword Sentinel配置文件哨兵模式 # Sentinel配置文件位置 /etc/redis/sentinel.conf 具体内容sentinel monitor mymaster 192.168.1.100 6379 2 # 监控名为mymaster # 监控主机的ip和port 192.168.1.100 6379 # 至少有2个sentinel确认服务器宕机后才进行故障转移 sentinel down-after-milliseconds mymaster 30000 # 如果sentinel在3,0000毫秒内没有收到主服务器的有效回复则认为主服务器宕机 sentinel failover-timeout mymaster 180000 # 故障转移等待新主机启动的超时时间为18,0000毫秒 sentinel parallel-syncs mymaster 1 # 故障转移过程中同时复制给从服务器的数量限制为1集群模式spring: redis: cluster: // 指定redis采用集群模式 nodes: // 集群中的节点列表每个节点都是集群中的一个成员 - node1:7000 - node2:7000 - node3:7000 - node4:7000 - node5:7000 - node6:7000 password: yourpassword timeout: 10000ms配置Redis的BeanpublicclassRedisConfig{AutowiredprivateStringRedisTemplatecommonStringRedisTemplate;// 自动注入StringRedisTemplate实例// 是 Spring Data Redis 提供的一个模板类专门用于处理字符串类型的键值对Bean// 将返回一个可以被 Spring 管理的 Bean。publicRedisOperationscommonRedisOperations(){RedisOperationsredisOperationsnewDefaultRedisOperations(commonStringRedisTemplate);// 创建了一个 DefaultRedisOperations 实例这是一个自定义的类假设它是存在的它接受 StringRedisTemplate 作为构造函数的参数。// 用于封装 Redis 操作并初始化分布式锁机制。DistributedLock.init(redisOperations);// 初始化一个分布式锁机制接受一个 RedisOperations 参数用于设置内部的 Redis 操作实例。同时在应用程序启动时分布式锁就会准备好使用。log.info({},Redis分布式锁初始化完成);returnredisOperations;}}Redis为什么这么快原因 基于内存操作持久化需要手动操作到本地 属于高效数据结构对数据的操作比较简单key-value结构 是单线程模型避免多线程中上下文频繁切换的操作 使用多路I/O复用模型非阻塞I/O 底层模型不同底层实现方式以及客户端之间通信的应用协议不一样redis有自己的vm机制一般的系统调用系统函数会消耗一定的时间移动和请求 参考 https://blog.csdn.net/CSDN2497242041/article/details/120755188Hash冲突怎么办定义 hash冲突不同的键所对应的哈希值相同导致它们存储在哈希表的同一个桶中 解决 通过链式哈希解决冲突即同一个桶里面的元素使用链表保存但当链表过长就会导致查找性能变差 所以为追究快使用两个全局哈希表用于rehash操作增加现有的哈希桶数量减少哈希冲突 两个全局哈希表 初始开始使用hash1存储键值对数据hash2没有分配空间当数据越来越多时触发rehash操作 给hash2分配更大的存储空间hash1数据重新映射拷贝到hash2中释放hash1表空间Redis和本地Cache存储的区别本地缓存存储在本地而redis缓存储存在远程服务器 访问本地缓存速度更快但受限于本地资源redis缓存可以跨多个节点共享数据实现分布式缓存。项目与redis服务配置方式不同问题描述 项目配置redis采用单机模式配置 redis服务采用集群方式 导致项目启动异常 分析Redis服务是按照集群cluster模式部署的而应用程序却以单机standalone模式尝试连接到该集群中的某一个节点这通常不会直接导致Redis服务本身启动异常。但会遇到连接或者操作失败的问题。Promise和FutrueVert.x4.x当前主流 明确分离职责PromiseT仅用于写入complete()/fail()FutureT仅用于读取注册回调多种redis配置模式场景1 存在单机模式和哨兵模式的配置时由于哨兵模式的优先级较高会直接使用哨兵模式。