网站seo推广优化,工业厂房设计,中山骏域网站建设,js开发安卓app一、Redis的线程模型 Redis是基于非阻塞的IO复用模型#xff0c;内部使用文件事件处理器#xff08;file event handler#xff09;#xff0c;这个文件事件处理器是单线程的#xff0c;所以Redis才叫做单线程的模型#xff0c;它采用IO多路复用机制同时监听多个socket内部使用文件事件处理器file event handler这个文件事件处理器是单线程的所以Redis才叫做单线程的模型它采用IO多路复用机制同时监听多个socket根据socket上的事件来选择对应的事件处理器进行处理。 文件事件处理器的结构包括四个部分 1、多个socket 2、IO多路复用程序 3、文件事件分排器 4、事件处理器连接应答处理器、命令请求处理器、命令回复处理器 多个 socket 可能会并发产生不同的操作每个操作对应不同的文件事件但是 IO 多路复用程 序会 监听多个 socket会将 socket 产生的事件放入队列中排队事件分派器每次从队列中取出一个事件把该事件交给对应的事件处理器进行处理
二、客户端与Redis服务器的一次通讯过程 一次通讯的过程如下图所示 1、客户端socket01发起建立连接的请求此时Server Socket会产生一个AE_READABLE事件IO多路复用程序监听到这个事件后把事件压入事件队列中 2、文件事件分派器从队列中拿到事件根据事件的类型分发给连接应答处理器创建socket01并将socket01的AE_READABLE事件与命令请求处理器关联这样下次的AE_READABLE事件就不是由连接应答处理器处理而是由命令请求处理器处理 3、连接建立成功后客户端发送set key value 请求Server Socket会再产生一个AE_READABLE事件IO多路复用程序监听到这个事件后把事件压入事件队列中文件事件分派器从队列中拿到事件交由命令请求处理器处理 4、命令请求处理器从socket01中的读取key value请求并完成key value的设置将socket01的AE_WRITABLE事件与命令回复处理器关联 5、如果此时客户端准备好接收返回结果了那么Server Socket会产生AE_WRITABLE事件同样压入队列中事件分派器找到相关联的命令回复处理器向socket01输出本次操作的一个结果最后将AE_WRITABLE事件与命令回复处理器解除关联 本次请求完成
三、Redis Cluster的原理 Redis集群中内置了16384个哈希槽当需要在Redis集群中放置一个key-value时redis先对key使用crc16算法算出一个结果然后把结果对16384求余数这样每个key都会对应一个编号0-16384之间的哈希槽redis会根据节点数量大致均等的将哈希槽映射到不同的节点上。 1、所有节点相互是连接的客户端连接任意节点都可以操作所有的数据 2、集群消息通信通过集群总线通信集群总线端口大小为客户端服务端口 10000
3、 节点与节点之间通过二进制协议进行通信 4、数据按照 Slot 存储分布在多个 Redis 实例上 5、集群节点挂掉会自动故障转移 6、可以相对平滑扩/ 缩容节点 四、如果有大量的key需要设置同一时间过期需要注意什么 如果有大量的 key 在同一时间过期那么可能同一秒都从数据库获取数据给数据库造成很大的压力导致数据库崩溃系统出现 502 问题。也有可能同时失效那一刻不用都访问数据库压力不够大的话那么 Redis 会出现短暂的卡顿问题。所以为了预防这种问题的发生最好给 数据的过期 时间加一个随机值让过期时间更加分散。 五、缓存和数据库的读写一致性问题 这里比较简单的方法就是当一个更新请求过来的时候先删除缓存数据再更新数据库最后再更新缓存。 写请求删除缓存成功则更新数据库如果更新数据库失败则直接返回写请求结束此 时数据库中的值依旧是旧值读请求过来后发现缓存中没有数据 则会直接向数据库中请求 同时将数据写入到缓存中此时也不会出现数据一致性的问题。 更新数据成功之后再更新缓存如果此时更新缓存失败则缓存中没有数据数据库中是 新值写请求结束此时读请求还是一样发现缓存中没有数据同样会从数据库中读取数据 并且存入到缓存中其实这里不管更新缓存成功还是失败都不会出现数据一致性的问题。 以上其实没啥问题问题在于如果一个更新请求还没有结束比如刚删了缓存读请求进来了此时数据库还没有更新那么读取的就是老的数据这就要看是否容忍这种问题。如果不能容忍那么就必须要针对同id数据的读写请求进行排队写请求进来先进入队列读请求排在后面等写请求完成了再处理读请求。 六、缓存雪崩、缓存穿透、缓存预热 缓存雪崩 缓存雪崩就是大量的key在同一时间过期此时大部分请求都打到了数据库上造成了数据库CPU和内存的压力过大可能成为数据库宕机此时会造成更大面积的系统瘫痪就好像雪崩一样。 解决的方法第一种就是在读数据的时候先加一层锁比如redis的分布式锁只让一个请求进入数据库去查询。第二种方法就是尽量不让大量的key在同一时间过期比如过期时间上增加一个随机时间 缓存穿透 缓存穿透就是指查询一个在缓存中不存在的key由于不存在会去查询数据库如果大量的查询不存在的key还是会对数据库造成大量的压力。 解决的方法第一种是如果发现数据库中不存在的key也在redis中缓存一份过期时间5分钟这样5分种内同样的key查询就不会进入数据库了第二种方式是使用布隆过滤器这需要将所有可能的数据都存到了一个足够大的bitmap中通过布隆过滤器可以确定请求的key是否合法 缓存预热 缓存预热就是系统上线后将相关的缓存数据直接加载到缓存系统。这样就可以避免在用户 请求的时候先查询数据库然后再将数据缓存的问题用户直接查询事先被预热的缓存数据 七、过期策略以及内存淘汰机制 过期策略 针对Key过期的情况redis采用了定期删除配合惰性删除的策略 定期删除每个100ms检查过期的key如果由过期的key就删除但每次不是全量的检查而是随机抽取进行检查比如抽取100个发现其中由20个过期了就把这20个key删除掉。如果过期 key 的占比超过可接受的过期 key 的百分比比如20%则重复删除的过程直到过期key的比例降至可接受的过期 key 的百分比以下。 惰性删除惰性删除是指当客户端请求某个key的时候会检查这个key是否过期如果过期了就删除掉 内存淘汰机制 内存总会有用完的时候如果内存已经占满了怎么办呢这就需要淘汰一部分的key那么怎么淘汰呢 8种内存淘汰策略 1.noeviction默认策略 不会删除任何数据拒绝所有写入操作并返回客户端错误消息errorOOM command not allowed when used memory此时 Redis 只响应删和读操作 2.allkeys-lru 从所有 key 中使用 LRU 算法进行淘汰LRU 算法最近最少使用算法 3.allkeys-lfu 从所有 key 中使用 LFU 算法进行淘汰LFU 算法最不常用算法根据使用频率计算4.0 版本新增 4.volatile-lru 从设置了过期时间的 key 中使用 LRU 算法进行淘汰 5.volatile-lfu 从设置了过期时间的 key 中使用 LFU 算法进行淘汰 6.allkeys-random 从所有 key 中随机淘汰数据 7.volatile-random 从设置了过期时间的 key 中随机淘汰数据 8.volatile-ttl 在设置了过期时间的key中淘汰过期时间剩余最短的。 注意 当使用 volatile-lru、volatile-lfu、volatile-random、volatile-ttl 这四种淘汰策略时如果没有 key 可以淘汰则和 neoviction 一样返回错误。 怎么选择淘汰策略 一般根据经验来说 使用 allkeys-lru 策略场景 1.当你期望元素的子集将比其他元素更频繁地被访问时比如幂律分布20%的数据占有80%的使用次数 2.当你不确定使用哪种策略时。 使用 allkeys-random 策略场景 1.当你有一个循环访问其中所有 key 进行会被连续地访问 2.当你希望所有 key 的分布比较均匀。 使用 volatile-ttl 策略场景 1.当你大部分缓存都设有不同的 ttl 值向 Redis 提供过期候选的提示时。 八、Redis的数据类型及使用场景 1、字符串 String类型是一种最基本的数据类型它是一个键值对的存储结构其中键和值都是字符串类型。String类型的特点是快速存储和读取适用于存储一些简单的数据如字符串、整数或浮点数等。 使用场景 缓存经典使用场景把常用信息字符串图片或者视频等信息放到Redis中Redis作为缓存层MySQL做持久化层降低MySQL的读写压力计数器Redis是单线程模型一个命令执行完才会执行下一个同时数据可以一步落地到其他的数据源。Session常见方案Spring Session Redis实现Session共享。 2、List 列表是简单的字符串列表按照插入顺序排序底层是双向列表压缩列表一种快速、高效、可靠的数据存储结构适用于实现队列、栈等常见的数据结构。 消息队列:List类型的lpop和rpush(或者反过来,lpush和rpop能实现队列的功能故而可以用Redis的List类型实现简单的点对点的消息队列。 排行榜:List类型的range命令可以分页查看队列中的数据但是只有顶式计算的排行榜才适合使用List类型存储。 最新列表:List类型的lpush命令和range命令能实现最新列表的功能.每次通过lpush的命令往列表里插入新的元素,然后通过lrange命令读取最新元素列表,如朋友圈的点赞列表、评论列表。 3、Set Set对外提供的功能与List类似是一个列表的功能特殊之处在于Set是可以自动排重的当你需要存储一个列表数据又不希望出现重复数据时Set是一个很好的选择并且Set提供了判断某个成员是否在一个Set集合内的重要接口这个也是List所不能提供的。Redis的Set是String类型的无序集合。它底层其实是一个Value为Null的Hash表所以添加删除查找的复杂度都是O(1) 推荐通过sinter命令计算交集,比如美团给你推荐附近外卖时就可以根据你的外卖记录与附近商家计算交集推送安全提示集合保存微信群成员保存在一个set中,用户好友也保存在Set中。当用户加入群聊时可以提醒非好友用户注意安全 4、Hash hash是一个string类型的field和value的映射表hash特别适合用于存储对象。 结构化存储场景一个hash结构中存储某个商品所有sku 5、ZSetsortedSet Zset与普通集合Set非常相似是一个没有重复元素的字符串集合。不同之处是有序集合的每个成员都关联了一个评分score,这个评分score被用来按照从最低分到最高分的方式排序集合中的成员。集合的成员是唯一的但是评分是可以重复的 。因为元素是有序的, 所以你也可以很快的根据评分score或者次序position来获取一个范围的元素。访问有序集合的中间元素也是非常快的,因此你能够使用有序集合作为一个没有重复成员的智能列表。 排行榜一个销量排行榜,就可以使用店家的订单做score,这个查询出来的结果就是有序的权重队列score作为优先级,这样取出来的数据权重都是最大优先执行的 延时任务score作为任务启动执行时间,取值时判断该值执行即可。 参考 Redis学习六8种内存淘汰机制_redis淘汰策略-CSDN博客 redis的过期键删除策略_redis过期键删除策略-CSDN博客