关于redis:面试必备一线大厂Redis设计规范与性能优化

说在后面你是否在应用Redis时,不分明Redis应该遵循的设计规范而苦恼? 你是否在Redis呈现性能问题时,不晓得该如何优化而发愁? 你是否被面试官拷问过Redis的设计规范和性能优化而答复不进去 别慌,看这篇文章就行了 本文,已收录于,我的技术网站 aijiangsir.com,有大厂残缺面经,工作技术,架构师成长之路,等教训分享注释一、Redis Key-Value设计规范&性能优化1. key名设计规范(1)【倡议】: 可读性和可管理性 以业务名(或数据库名)为前缀(避免key抵触),用冒号分隔,比方业务名:表名:id(2)【倡议】:简洁性 保障语义的前提下,管制key的长度,当key较多时,内存占用也不容忽视,例如:(3)【强制】:不要蕴含特殊字符 反例:蕴含空格、换行、单双引号以及其余转义字符2. Value设计规范(1)【强制】:回绝bigkey(避免网卡流量、慢查问) 在Redis中,一个字符串最大512MB,一个二级数据结构(例如hash、list、set、zset)能够存储大概40亿个(2^32-1)个元素,但理论中如果上面两种状况,我就会认为它是bigkey。 字符串类型:它的big体现在单个value值很大,个别认为超过10KB就是bigkey。非字符串类型:哈希、列表、汇合、有序汇合,它们的big体现在元素个数太多。一般来说,string类型管制在10KB以内; hash、list、set、zset元素个数不要超过5000。 反例:一个蕴含200万个元素的list。 3. bigkey性能优化bigkey的危害:导致redis阻塞网络拥塞bigkey也就意味着每次获取要产生的网络流量较大; 假如一个bigkey为1MB,客户端每秒访问量为1000,那么每秒产生1000MB的流量,对于一般的千兆网卡(依照字节算是128MB/s)的服务器来说几乎是灭顶之灾,而且个别服务器会采纳单机多实例的形式来部署,也就是说一个bigkey可能会对其余实例也造成影响,其结果不堪设想。 过期删除有个bigkey,它奉公守法(只执行简略的命令,例如hget、lpop、zscore等),但它设置了过期工夫,当它过期后,会被删除,如果没有应用Redis 4.0的过期异步删除(lazyfree-lazy- expire yes),就会存在阻塞Redis的可能性。bigkey的产生:一般来说,bigkey的产生都是因为程序设计不当,或者对于数据规模意料不分明造成的,来看几个例子:  社交类: 粉丝列表,如果某些明星或者大v不精心设计下,必是bigkey。统计类: 例如按天存储某项性能或者网站的用户汇合,除非没几个人用,否则必是bigkey。缓存类: 将数据从数据库load进去序列化放到Redis里,这个形式十分罕用,但有两个中央须要留神,第一,是不是有必要把所有字段都缓存;第二,有没有相干关联的数据,有的同学为了图不便把相干数据都存一个key下,产生bigkey。如何优化bigkey1、拆 如果是大List(big list),那么就能够拆成多个List:比方拆成:list1、list2、...listN如果是一个大的哈希表(big hash),能够将数据分段存储:比方一个大的key,假如存了1百万的用户数据,能够拆分成 200个key,每个key上面寄存5000个用户数据如果bigkey不可避免,也要思考一下要不要每次把所有元素都取出来(例如有时候仅仅须要 hmget,而不是hgetall),删除也是一样,尽量应用优雅的形式来解决。 2、抉择适合的数据类型【举荐】 最好的优化计划其实是在设计阶段,所以咱们在应用Redis时,在设计阶段就应该尽量避免bigkey,所以抉择适合的数据类型尤为重要。 例如:实体类型(要正当管制和应用数据结构,但也要留神节俭内存和性能质检的均衡) 谬误的做法: 1set user:1:name tom2set user:1:age 193set user:1:favor football正确的做法: hmset user:1 name tom age 19 favor football3、管制key的生命周期,redis不是垃圾桶,当不须要应用的数据,及时过期清理【举荐】 倡议应用Expire设置过期工夫 条件容许能够打散过期工夫,避免几种过期 比方:设置key的过期工夫时,采纳固定过期工夫+肯定范畴内的随机数 二、Redis命令的应用标准&性能优化1、应用O(N)类型的命令要留神关注N的数量【举荐】比方hgetall、lrange、smembers、zrange、sinter等并非不能应用。 然而在应用的时候肯定要明确N的值,不然就可能因为查问数据太大导致redis阻塞。 倡议:有遍历的需要时能够应用hscan、sscan、zscan代替2、生产环境禁用局部高危命令【举荐】禁止线上应用keys、flushall、flushdb等,通过redis的rename机制禁掉命令。 当有须要扫描的须要时,倡议应用scan形式渐进式解决3、正当应用select【举荐】redis的多数据库较弱,应用数字进行辨别,很多客户端反对较差,同时多业务用多数据库理论还是单线程解决,会有烦扰 所以倡议redis应用数据库只用序号0的数据库即可,在0数据库里采纳key前缀辨别业务即可4、应用批量操作提高效率【举荐】当咱们要插入多个key时,能够采纳一些批量命令代替单个命令,进步查问效率,例如: 1原生命令:例如mget、mset。2非原生命令:能够应用pipeline提高效率。但要留神管制一次批量操作的元素个数(例如500以内,理论也和元素字节数无关)。 留神两者不同: 11. 原生命令是原子操作,pipeline是非原子操作。22. pipeline能够打包不同的命令,原生命令做不到33. pipeline须要客户端和服务端同时反对。5、redis事务性能较弱,不倡议过多应用redis的事务命令如果业务上有须要,能够应用lua代替【倡议】 三、客户端应用标准&性能优化1、防止多个利用应用同一个Redis实例【举荐】谬误的做法: 多个业务线专用同一个redis实例,比方订单、库存、权限都用同一个redis实例,只有有一块业务有阻塞,所有业务都会受影响。 正确的做法: 不相干的业务拆分为独立的redis实例,比方订单、库存、权限拆分为3个redis实例。 ...

February 29, 2024 · 2 min · jiezi

关于redis:Redis能保证数据不丢失吗

数据分片:实现了数据的主动分片,便于管理大规模数据。高可用性:集群中的节点能够互相备份,即便局部节点失败,也不会影响整个集群的可用性。配置示例: 配置Redis集群波及到启动多个Redis实例,可应用redis-cli工具创立集群:启动Redis实例(假如启动6个实例作为示例)redis-server --port 7000 --cluster-enabled yes --cluster-config-file nodes-7000.conf --cluster-node-timeout 5000 --appendonly yes --appendfilename appendonly-7000.aof --dbfilename dump-7000.rdb --logfile 7000.log反复上述命令,批改端口为7001-7005应用redis-cli创立集群redis-cli --cluster create <ip1>:7000 <ip2>:7001 <ip3>:7002 <ip4>:7003 <ip5>:7004 <ip6>:7005 --cluster-replicas 1--cluster-enabled yes:启用Redis集群模式。--cluster-config-file nodes-7000.conf:指定集群的配置文件。这个文件由Redis主动保护,记录了集群中所有节点的信息。--cluster-node-timeout 5000:设置节点超时工夫,单位是毫秒。如果一个节点在这段时间内没有响应,集群会认为该节点曾经下线。--appendonly yes:启用AOF长久化模式。在集群模式下,举荐应用AOF长久化来保障数据安全。--appendfilename appendonly-7000.aof:指定AOF文件的名字。这里依据不同的端口号,为每个实例指定了不同的AOF文件名,以防止抵触。--dbfilename dump-7000.rdb:指定RDB文件的名字。同样地,依据不同的端口号为每个实例指定了不同的RDB文件名。--logfile 7000.log:指定日志文件的名字。这有助于在呈现问题时进行故障排查。通过主从架构、哨兵零碎和集群架构,能够无效地实现数据的多正本保留、故障转移和数据冗余,进步零碎的可靠性和可用性,基本上能够防止单机零碎的数据失落问题。跨机房部署服务器所在的机房也可能呈现问题,比方光缆被挖断了、空调零碎坏了、机房着火了等理论呈现过的情况,为了解决这些问题,咱们还能够通过跨机房的办法来晋升Redis的数据可靠性和可用性。在不同机房间部署主从复制架构。在一个数据中心内设置主节点,在另一个或多个数据中心设置从节点。Sentinel(哨兵)集群也应跨机房部署,以防止单点故障。应用Redis Cluster进行跨机房部署,每个机房都能够有多个分片(shard),并且每个分片的主节点和从节点别离位于不同的地理位置,这样即便一个机房齐全不可用,其余机房的正本依然可能提供服务。跨机房部署时须要自行解决网络的通信问题,让各个节点之间能够无障碍的互相拜访,机房间最好应用低提早、高带宽的专线连贯,以减速数据同步过程并升高网络问题导致的数据不统一危险。还有面试中常常提及的两地三核心的多活架构,也能够安顿上。每个机房都部署一套残缺的、独立解决读写申请的Redis集群,并通过分布式锁或者数据同步中间件等技术保障各个集群间数据的一致性。分布式锁能够采纳ZooKeeper、etcd、redis等,确保在多个数据中心进行同步更新时,只有一个数据中心的Redis集群在给定工夫内对某个资源领有写权限。数据同步中间件次要用于实时或近实时地将一个数据中心的写入操作同步到另一个数据中心。能够应用音讯队列、业余的数据同步工具(比方阿里巴巴开源的Canal)等。多活架构还要设计数据分片策略、数据路由机制以及事务处理形式,比方依据地区或者一致性Hash分片来辨别用户,而后应用客户端驱动路由或者网关路由来把用户导向不同的机房,最初应用分布式事务提交数据。多活架构比较复杂,我也没有理论搞过,这里就不多说了。其余运维措施日常运维中的定期检查和文件备份,尽管平时看起来不起眼,但在关键时刻却能施展巨大作用。运维工具检测就像咱们用手表监测心率一样,应用业余的运维工具能够帮忙咱们实时监控Redis服务器的状态,包含性能指标、资源应用状况、可能的瓶颈等。具体做法:抉择适合的工具:市面上有许多优良的运维监控工具,如Prometheus联合Grafana、Zabbix等,能够依据本人的需要和环境抉择。定制监控项:依据你的具体需要,定制监控项。比方,内存使用率、磁盘使用率、命令执行提早、连接数等,这些都是常见的监控指标。设置告警:设置阈值,一旦监控到的数据超过这个阈值,就会触发告警。这就像是你的手表在你心率异样时揭示你,帮忙你及时发现并解决问题。定期备份数据备份就是咱们给文件买了一份保险,无论是误操作还是系统故障,都可能确保数据不会失落,能够疾速复原到备份时的状态。具体做法:定期执行:设定一个正当的备份频率,比方每天凌晨进行一次。频率的抉择取决于你的业务需要和数据变动的频繁水平。自动化:利用crontab等工具自动化备份流程,让备份工作自动化进行,缩小人为忘记的危险。近程存储:将备份文件存储在近程服务器或云存储服务上。这样做的益处是,即便本地产生灾难性事件,数据依然是平安的。通过施行这些惯例措施,咱们能够大大提高数据的安全性和零碎的稳定性。总结说了这么多,让咱们做一个总结。如果你的业务对数据的完整性要求十分高,倡议开启AOF长久化,并设置正当的fsync策略(如每秒同步一次)。同时,配合应用主从复制和哨兵零碎,以确保数据的高可用性和安全性。对于读写性能有极高要求的场景,能够思考只应用RDB长久化或者RDB与AOF联合的形式(数据完整性要求高,AOF用于故障复原,RDB用于重启减速)。同时,通过减少从节点和正当调配读写负载,能够进一步晋升性能、进步数据安全性。如果业务数据量微小,单个Redis实例难以满足存储需要,那么Redis集群是一个不错的抉择。它通过分片来实现数据的分布式存储,同时放弃高可用性。日常的监控和备份也要搞起来,如果服务和数据及其重要,跨机房部署能够提供极大的数据安全性和零碎稳定性。至于传说中的多活架构,不到万不得已不要轻易尝试,极为简单,老本很高。

February 28, 2024 · 1 min · jiezi

关于redis:不可不知的Redis秘籍事务命令全攻略

在数据处理的世界里,事务(Transaction)是一个不可或缺的概念。它们确保了在一系列操作中,要么所有的操作都胜利执行,要么都不执行。这就像是一个“全有或全无”的规定,保障了数据的一致性和完整性。 明天,咱们就来聊聊Redis事务的应用,看看如何通过它来晋升咱们的数据操作效率和安全性。 一、Redis事务的概念Redis 事务的实质是一组命令的汇合。事务反对一次执行多个命令,一个事务中所有命令都会被序列化。在事务执行过程,会依照程序串行化执行队列中的命令,其余客户端提交的命令申请不会插入到事务执行命令序列中。 总结来说: redis事务就是一次性、程序性、排他性的执行一个队列中的一系列命令。 Redis事务没有隔离级别的概念批量操作在发送 EXEC 命令前被放入队列缓存,并不会被理论执行,也就不存在事务内的查问要看到事务里的更新,事务外查问不能看到。 Redis不保障原子性Redis中,单条命令是原子性执行的,但事务不保障原子性,且没有回滚。事务中任意命令执行失败,其余的命令仍会被执行。redis事务的执行阶段开始事务(multi)。命令入队。执行事务(exec) 二、Redis事务优缺点对于Redis事务的概念咱们曾经有了根本的理解,上面咱们再来看看它都有哪些优缺点。 长处: 一次性按程序执行多个Redis命令,不受其余客户端命令申请影响;事务中的命令要么都执行(命令间执行失败相互不影响),要么都不执行(比方两头有命令语法错误);毛病: 事务执行时,不能保障原子性;命令入队每次都须要和服务器进行交互,减少带宽;留神: 当事务中命令语法应用谬误时,最终会导致事务执行不胜利,即事务内所有命令都不执行;当事务中命令常识逻辑谬误,就比方给字符串做加减乘除操作时,只能在执行过程中发现错误,这种事务执行中失败的命令不影响其余命令的执行。三、Redis事务相干命令Redis事务能够通过一系列命令来执行多个操作,并确保这些操作能够原子性地执行。以下是Redis事务的相干命令及其作用: MULTI: 开启一个事务。在调用此命令后,Redis 会将后续的命令一一放入队列中,直到接管到 EXEC 命令为止。 EXEC: 执行事务中的所有操作命令。一旦调用 EXEC 命令,Redis 会原子性地执行队列中的所有命令。 DISCARD: 勾销事务,放弃执行事务块中的所有命令。如果不想继续执行事务中的操作,能够应用 DISCARD 命令来革除以后事务队列。 WATCH: 监督一个或多个键,如果在事务执行之前这些键被其余命令所改变,那么事务将会被打断。 UNWATCH: 勾销所有由 WATCH 命令监督的键。如果不想持续监督某些键,能够应用 UNWATCH 命令来勾销监督。 须要留神的是,在事务执行过程中,其余客户端提交的命令申请不会插入到事务执行命令序列中,这保障了事务的隔离性。同时,Redis 事务提供了批量操作缓存的性能,即在发送 EXEC 命令前,所有操作都会被放入队列缓存。 你还在苦恼找不到真正收费的编程学习平台吗?能够试试【云端源想】!课程视频、知识库、微实战、云实验室、一对一征询……你想要的全副学习资源这里都有,重点是当初还是收费的!点这里即可查看!四、Redis事务的应用应用Redis事务的步骤如下: 应用MULTI命令开启一个事务。在事务中执行须要的命令,如SET、GET等。应用EXEC命令提交事务,将事务中的命令一次性发送给Redis服务器执行。如果须要勾销事务,能够应用DISCARD命令。 上面通过一些示例来解说一下这些命令的应用办法: 1、失常执行192.168.xxx.21:6379> multiOK192.168.xxx.21:6379> set aa AAQUEUED192.168.xxx.21:6379> set bb BBQUEUED192.168.xxx.21:6379> set cc CCQUEUED192.168.xxx.21:6379> set dd DDQUEUED192.168.xxx.21:6379> exec1) OK2) OK3) OK4) OK192.168.xxx.21:6379> get aa"AA"首先,通过执行multi命令开始一个事务块。而后,顺次执行了四个set命令,将键"aa"、“bb”、“cc"和"dd"别离设置为对应的值"AA”、“BB”、“CC"和"DD”。 每个set命令执行后返回的后果为"QUEUED",示意该命令已被退出到事务队列中期待执行。 接下来,通过执行exec命令来提交事务,一次性执行事务队列中的所有命令。执行后果为每个命令的返回值,即"OK"。最初,通过执行get aa命令获取键"aa"的值,返回后果为"AA"。 2、勾销事务192.168.xxx.21:6379> multiOK192.168.xxx.21:6379> set aa 11QUEUED192.168.xxx.21:6379> set ee EEQUEUED192.168.xxx.21:6379> discardOK192.168.xxx.21:6379> get aa"AA"192.168.xxx.21:6379> get ee(nil)192.168.xxx.21:6379>示例代码中,首先,通过执行multi命令开始一个事务块。而后,顺次执行了两个set命令,将键"aa"设置为值"11",将键"ee"设置为值"EE"。每个set命令执行后返回的后果为"QUEUED",示意该命令已被退出到事务队列中期待执行。 ...

February 23, 2024 · 2 min · jiezi

关于redis:掌握Redis核心常用数据类型的高效运用秘籍

在数据驱动的时代,高效地存储和解决数据成为了开发者们的重要工作。Redis,作为一个开源的高性能键值对(key-value)数据库,以其独特的数据结构和丰盛的性能,成为了泛滥我的项目的首选。 明天,咱们就来揭开Redis的神秘面纱,看看它是如何通过不同的数据类型,为咱们提供高效、灵便的数据存储和解决能力的。 一、字符串(String):数据的基石String类型简介字符串是Redis最根本的数据类型,它能够存储文本、数字或者二进制数据。应用字符串类型,你能够执行原子性的操作,如追加(APPEND)、设置(SET)和获取(GET)。例如,你能够将用户信息作为字符串存储,并通过键疾速检索。 一个key对应一个value。String类型是二进制平安的。只有内容能够应用字符串示意就能够存储到string中。比方jpg图片或者序列化的对象。一个Redis中字符串value最多能够是512M。 常用命令set key value: 增加键值对。 get key: 查问key对应的键值。 留神:如果设置了两次雷同的key,后设置的就会把之前的key笼罩掉。append key value: 将给定的value追加到原值的开端。 strlen key: 取得值的长度。 setnx key value: 只有在key 不存在时 ,能力设置 key 的值。 incr key: 将 key 中贮存的数字值增1(只能对数字值操作,如果为空,新增值为1)。 decr key: 将 key 中贮存的数字值减1(只能对数字值操作,如果为空,新增值为-1)。 incrby / decrby key 步长: 通过自定义步长形式增减 key 中贮存的数字值。 mset key1 value1 key2 value2 …: 同时设置一个或多个键值对。 mget key1 key2 key3 …: 同时获取一个或多个value。 msetnx key1 value1 key2 value2 …: 所有给定 key 都不存在时,同时设置一个或多个 key-value 对。 留神:此操作有原子性,只有有一个不符合条件的key。其余的也都不能设置胜利。如下图: ...

February 22, 2024 · 2 min · jiezi

关于redis:认识Redis不只是缓存还有这些厉害的功能

在当今数据驱动的世界中,疾速存取信息成为了技术倒退的要害。而在泛滥存储解决方案中,Redis以其独特的魅力和弱小的性能,成为了开发者们的宠儿。明天,就让咱们一起来认识一下Redis。一、Redis是什么,能够用来干什么?Redis,英文全称是Remote Dictionary Server(近程字典服务),是一个开源的应用ANSI C语言编写、反对网络、可基于内存亦可长久化的日志型、Key-Value数据库,并提供多种语言的API。 与MySQL数据库不同的是,Redis的数据是存在内存中的。它的读写速度十分快,每秒能够解决超过10万次读写操作。因而redis被广泛应用于缓存,另外,Redis也常常用来做分布式锁、计数器、排行榜等。 Redis的常见利用1.缓存这是Redis利用最宽泛中央,根本所有的Web利用都会应用Redis作为缓存,来升高数据源压力,进步响应速度。 2.计数器Redis人造反对计数性能,而且计数性能十分好,能够用来记录浏览量、点赞量等等。 3.排行榜Redis提供了列表和有序汇合数据结构,正当地应用这些数据结构能够很不便地构建各种排行榜零碎。 4.社交网络赞/踩、粉丝、独特好友/爱好、推送、下拉刷新。 5. 音讯队列Redis提供了公布订阅性能和阻塞队列的性能,能够满足个别音讯队列性能。 6. 分布式锁分布式环境下,利用Redis实现分布式锁,也是Redis常见的利用。 7. 位操作用于数据量上亿的场景下,例如几亿用户零碎的签到,去重登录次数统计,某用户是否在线状态等等。这里要用到位操作——应用setbit、getbit、bitcount命令。 原理是:redis内构建一个足够长的数组,每个数组元素只能是0和1两个值,而后这个数组的下标index用来示意用户id(必须是数字哈),那么很显然,这个几亿长的大数组就能通过下标和元素值(0和1)来构建一个记忆系统。二、Redis 有哪些数据结构类型?Redis有五种根本类型和三种非凡的数据结构类型,上面咱们别离来看一些都有哪些类型。 2.1 Redis的五种根本数据结构string字符串最根底的数据结构。字符串类型的值理论能够是字符串(简略的字符串、简单的字符串(例如JSON、XML))、数字 (整数、浮点数),甚至是二进制(图片、音频、视频),然而值最大不能超过512MB。 字符串次要有以下几个典型应用场景: 缓存性能计数共享Session限速hash哈希类型是指键值自身又是一个键值对构造。 哈希次要有以下典型利用场景: 缓存用户信息缓存对象list列表(list)类型是用来存储多个有序的字符串。列表是一种比拟灵便的数据结构,它能够充当栈和队列的角色。 列表次要有以下几种应用场景: 音讯队列文章列表set汇合(set)类型也是用来保留多个的字符串元素,但和列表类型不一 样的是,汇合中不容许有反复元素,并且汇合中的元素是无序的。 汇合次要有如下应用场景: 标签(tag)独特关注sorted set有序汇合中的元素能够排序。然而它和列表应用索引下标作为排序根据不同的是,它给每个元素设置一个权重(score)作为排序的根据。 有序汇合次要利用场景: 用户点赞统计用户排序2.2 Redis 的三种非凡数据类型Geo:  Redis3.2推出的,地理位置定位,用于存储地理位置信息,并对存储的信息进行操作。 HyperLogLog: 用来做基数统计算法的数据结构,如统计网站的UV。 Bitmaps: 用一个比特位来映射某个元素的状态,在Redis中,它的底层是基于字符串类型实现的,能够把bitmaps成作一个以比特位为单位的数组。 三、Redis为什么这么快?3.1 基于内存存储实现咱们都晓得内存读写是比在磁盘快很多的,Redis基于内存存储实现的数据库,绝对于数据存在磁盘的MySQL数据库,省去磁盘I/O的耗费。 3.2 高效的数据结构咱们晓得,Mysql索引为了提高效率,抉择了B+树的数据结构。其实正当的数据结构,就是能够让你的利用/程序更快。先看下Redis的数据结构&外部编码图: SDS简略动静字符串 字符串长度解决: Redis获取字符串长度,工夫复杂度为O(1),而C语言中,须要从头开始遍历,复杂度为O(n); 空间预调配: 字符串批改越频繁的话,内存调配越频繁,就会耗费性能,而SDS批改和空间裁减,会额定调配未应用的空间,缩小性能损耗。 惰性空间开释: SDS 缩短时,不是回收多余的内存空间,而是free记录下多余的空间,后续有变更,间接应用free中记录的空间,缩小调配。 二进制平安: Redis能够存储一些二进制数据,在C语言中字符串遇到’\0’会完结,而 SDS中标记字符串完结的是len属性。 字典Redis 作为 K-V 型内存数据库,所有的键值就是用字典来存储。字典就是哈希表,比方HashMap,通过key就能够间接获取到对应的value。而哈希表的个性,在O(1)工夫复杂度就能够取得对应的值。 跳跃表跳跃表是Redis特有的数据结构,就是在链表的根底上,减少多级索引晋升查找效率。 跳跃表反对均匀 O(logN),最坏 O(N)复杂度的节点查找,还能够通过程序性操作批量解决节点。 3.3 正当的数据编码Redis 反对多种数据数据类型,每种根本类型,可能对多种数据结构。什么时候,应用什么样数据结构,应用什么样编码,是redis设计者总结优化的后果。 String: 如果存储数字的话,是用int类型的编码;如果存储非数字,小于等于39字节的字符串,是embstr;大于39个字节,则是raw编码。 List: 如果列表的元素个数小于512个,列表每个元素的值都小于64字节(默认),应用ziplist编码,否则应用linkedlist编码。 Hash: 哈希类型元素个数小于512个,所有值小于64字节的话,应用ziplist编码,否则应用hashtable编码。 Set: 如果汇合中的元素都是整数且元素个数小于512个,应用intset编码,否则应用hashtable编码。 Zset: 当有序汇合的元素个数小于128个,每个元素的值小于64字节时,应用ziplist编码,否则应用skiplist(跳跃表)编码。 ...

February 20, 2024 · 1 min · jiezi

关于redis:真Redis缓存优化97的优化率你见过嘛-京东云技术团队

本文通过一封618前的R2M(公司外部缓存组件,能够认为等同于Redis)告警,由浅入深的剖析了该告警的间接起因与根本原因,并依据起因提出相应的解决办法,心愿可能给大家在排查相似问题时提供相应的思路。 一、问题排查1.1 邮件告警正值618值班前夕,某天收到了邮件告警,告警内容如下: 您好,R2M监控报警,请您及时追踪一下! 报警信息:告警ID:6825899, 利用:zr\_credit\_portal, 负责人:zhangsan, 告警类型:内存使用率, 工夫:2023-06-15 16:00:04。实例:(10.0.0.0:5011-slave), 以后:9212MB 超过戒备值:8748MB 实例最大内存:10800 MB,内存使用率:85 % ;实例:(10.0.0.0:5023-master), 以后:9087MB 超过戒备值:8748MB 实例最大内存:10800 MB,内存使用率:84 % ;实例:(10.0.0.0:5017-master), 以后:9214MB 超过戒备值:8748MB 实例最大内存:10800 MB,内存使用率:85 % ;大略内容是说,R2M集群使用率曾经达到85%,须要紧急解决下。 咱们的缓存集群配置如下,总共32400MB容量,三主三从,每个主节点10800M容量,目前应用最高的曾经达到9087M。R2M应用集群模式进行部署。 首先的思路就是应用大key统计,查看是哪些缓存占用了容量。因为大key统计是从节点进行扫描,所以不必放心会影响线上主流程。 1.2 代码剖析大key次要分为两类,一类是xxx\_data,一类是xxx\_interfacecode_01,依照此法则去代码中寻找寄存key的中央 String dataKey = task.getTaskNo() + "_data";cacheClusterClient.setex(dataKey.getBytes(), EXPIRATION, DataUtil.objectToByte(paramList));key = task.getTaskNo() + "_" + item.getInterfaceCode() + "_" + partCount;cacheClusterClient.setex(key.getBytes(), EXPIRATION,DataUtil.objectToByte(dataList));找到了代码地位后,剖析其业务流程: 1.3 告警起因综合上图剖析,此次占用率过高的起因能够分为间接起因与根本原因: 1.3.1 间接起因查看经营后盾的确发现有用户在此前三天创立了大量的跑批工作,导致缓存中样本与后果数量减少,从而导致缓存使用率过高。 1.3.2 根本原因剖析代码后,依据上文形容缓存中次要有两块数据:样本与后果 首先是样本在缓存中存了一下随机又取出,本操作毫无意义,只会占用缓存容量。后果分批分片存储,此步骤有意义,次要是为了避免在多任务并行处理时,如果不将数据分片存入缓存,很有可能导致数据在JVM中占用大量空间,进而导致FULL GC的问题。(之前文章已剖析)跑批完结后,两头数据失常来说曾经无用,然而业务流程并没有被动删除无用数据,而是期待超时后主动删除,本操作会导致数据在缓存中额定存储较长时间。至此,曾经剖析出了本次缓存使用率过高的起因(其实还没有,间接起因只剖析出了表象,间接起因的“根本原因”还未有论断)。 二、问题解决上文剖析了本次告警的排查过程,以下是如何解决问题,也是分为如何解决间接起因与解决根本原因。 2.1 间接起因2.1.1 起因剖析正值618前夕,最好不思考操作会对系统产生的影响,因而只能先思考让对应的用户临时进行创立跑批,免得持续占用内存导致影响线上业务。 此时察看监控图又发现: 用户是从三天前就开始创立跑批工作的(对应缓存开始增长的工夫点),然而缓存的有效期只有一天,按情理来说从第二天开始每天的缓存都应该降落不少才对(因为前一天的曾经过期了),为什么看监控图这三天的缓存使用率近乎直线回升呢? ...

September 27, 2023 · 1 min · jiezi

关于redis:使用HHDBCS管理Redis

Redis是一款内存高速缓存数据库,可用于缓存,事件公布或订阅,高速队列等场景。因而,依据须要,HHDBCS在主页设置了“公布窗口”及“订阅窗口”。 1 连贯redis关上HHDBCS,在数据库类型中抉择Redis,填入相干信息,点击“登陆”即可。 2 订阅性能点击“订阅窗口”,在弹出框中填入信息,点击订阅; 弹出对话框,点击确定。 留神,此时的“订阅”选项变为“勾销订阅”。 3. 公布性能点击“公布性能”,在弹出框的频道名称中,输出方才订阅的频道名称,可抉择“文本公布”及“文件公布”;笔者这里测试的是文本公布,因而抉择在上面的文本输入框中输出内容,随后点击文本公布。 弹出对话框,同时能够看到公布信息。 同时在订阅窗口,能够同步接管到信息;点击“查看”,即可显示。 能够对信息进行导出。 4. 树状构造双击对象,后面呈现“+”;点击即可关上树形构造框架。 右键可进行操作。 5. 命令窗口点击命令窗口,能够对数据库收回指令。 依据集体习惯,能够对命令窗口进行设置 还能够抉择各种格局。 点击加载,能够间接调用脚本等。 6. 对象搜寻对象搜寻性能能轻松搜寻到数据库对象并对其进行相应操作。点击导航栏“对象搜寻”按钮,弹出查找界面,输出查找的名称,点击“查问”按钮。备注:“*”可用于含糊搜寻。

September 26, 2023 · 1 min · jiezi

关于redis:Redis内存碎片深度解析与优化策略

本文已收录至GitHub,举荐浏览 Java随想录 微信公众号:Java随想录 原创不易,重视版权。转载请注明原作者和原文链接在咱们探索和优化Redis性能的过程中,「Redis内存碎片」是一个不可漠视的话题。 这篇文章将深入研究这个看似微不足道,但实际上对Redis运行效率产生重要影响的问题。首先,让咱们揭开Redis内存碎片的神秘面纱,了解它的实质及其为何成为咱们必须面对的挑战。 内存碎片如何产生的Redis内存碎片次要是因为Redis数据存储和回收过程中的内存治理问题导致的。 Redis分配内存时,会依据须要申请一段间断的内存空间。但当Redis删除或批改数据时,开释的内存空间并不一定能被立刻从新利用,尤其是当这些闲暇内存空间大小不统一时,就可能导致内存碎片的呈现。 为了进步内存应用的效率,Redis外部应用内存分配器来对内存的申请和开释进行治理。Redis应用的内存分配器默认是「jemalloc」。 而内存分配器是依照固定大小来分配内存的,并不是齐全依照程序申请的内存大小来进行调配。 比方程序申请一个20字节的内存,内存分配器会调配一个32字节的内存空间,这么做是为了缩小调配次数。redis会申请不同大小的内存空间来存储不同业务不同类型的数据,因为内存依照固定大小调配且会比理论申请的内存要大一些,这个过程中会产生内存碎片。 举个生存中的例子,帮忙大家了解: 假如你正在整顿一间图书馆。图书馆的书架就像是Redis贮存数据的内存空间。每本书都代表不同大小的数据。刚开始时,你把所有的书都依照大小放好。小书在一侧,大书在另一侧。这样你能够无效地利用书架的空间,也不便找书。 然而,如果你须要移除一些书(删除某些数据),而后又退出新的书(新增数据),就可能呈现问题了。例如,你移除了一些大书,把它们的地位空进去,而后把新的小书放进去。这样下来,本来属于大书的空间,当初只被小书局部占用,残余的空白就成了“内存碎片”。 又或者你有一堆新的大书要放,但书架上只有扩散的小书的空位,无奈包容这些大书。这个时候你可能须要重新排列整个书架(相似于Redis的内存整理)去腾出间断的大片空间来摆放这些新的大书。 总结来说:当数据一直删除和新增时,内存中空出的地位可能无奈齐全匹配新数据的大小,导致产生未被利用的“碎片”空间,这就是内存碎片。 内存分配器Redis 应用内存分配器来治理其在运行期间须要应用的内存资源。能够是libc、jemalloc、tcmalloc。默认是jemalloc。 要指定 Redis 应用哪个内存分配器,你须要在编译 Redis 时做出抉择。通常在执行 make 命令时能够通过 MALLOC 参数来指定。例如,如果你想应用 jemalloc,你能够像这样编译 Redis:make MALLOC=jemalloc。 jemalloc在64位零碎中,将内存空间划分为小、大、微小三个范畴。每个范畴内又划分了许多小的内存块单位,存储数据的时候,会抉择大小最合适的内存块进行存储。 jemalloc划分的内存单元如下图所示: 也就是说Redis是以指定大小的块为单位进行间断内存调配的,而不是按需分配的,Redis 会依据申请的内存最靠近的固定值调配相应大小的空间。 这就像你有不同的箱子,为了装货色,你须要找一个体积最靠近的箱子来装。然而装进去后,你发现还有空间能够放一些小东西,就无需再找箱子了。 然而,这种调配空间的形式会带来肯定水平的内存碎片。咱们能够把固定大小的划分空间看成不同体积的箱子,每种箱子里的空间不同水平上都会有残余。这些残余的空间就是内存碎片。 怎么看是否有内存碎片咱们登陆到Redis服务器上,执行以下命令,这会返回一段形容Redis内存应用状况的文本。 redis> info memory咱们会看到相似如下的信息: 在这里,咱们次要关注的是名为mem_fragmentation_ratio的字段,它显示了Redis内存碎片的比例。 如果mem_fragmentation_ratio大于1,那就示意存在内存碎片。这个值越大,内存碎片就越多。如果该值十分靠近1或者小于1,则示意内存碎片很少或者没有。 计算公式为: mem_fragmentation_ratio = used_memory_rss / used_memory其中: used_memory_rss:代表Redis过程占用的总物理内存大小(包含码区、数据区和堆栈等),单位是字节。used_memory:代表Redis分配器申请的内存总量,也就是从操作系统角度看过程理论应用的虚拟内存空间,单位是字节。碎片率的意义mem_fragmentation_ratio的不同值,阐明不同的状况。 大于1:阐明内存有碎片,通常在1到1.5之间是失常的。大于1.5:阐明内存碎片率比拟大,须要思考是否要进行内存碎片清理,要引起器重。小于1:阐明曾经开始应用替换内存,也就是应用硬盘了,失常的内存不够用了,须要思考是否要进行内存的扩容,应用swap是相当影响性能的。清理内存碎片低于4.0-RC3版本的RedisRedis 4.0-RC3之前的版本并没有内置的内存碎片整顿工具。如果你想要清理内存碎片,能够通过重启的形式。 当Redis重新启动时,它会通过RDB长久化性能将数据存储到磁盘,而后再从磁盘加载数据到内存,这个过程能够无效地清理内存碎片。但这种办法会导致服务的长期中断。 高于4.0-RC3版本的RedisRedis4.0-RC3版本开始,引入了active-defrag 个性。能够在不重启的状况下,主动进行碎片清理。 开启配置如下,此选项的默认值是敞开的,激活碎片整顿可能会占据一些 CPU 工夫。 redis> config set activedefrag yes 留神:主动清理内存碎片的性能须要该Redis的内存分配器是jemalloc时能力启用。 启用后须要同时满足上面2个参数的设置条件时才会触发主动清理 active-defrag-ignore-bytes 100mb # 默认100MB,示意内存碎片空间达到100MB时active-defrag-threshold-lower 10 # 默认10,示意内存碎片空间占OS调配给redis的物理内存空间的比例达到10%时redis是单过程模型,内存碎片主动清理是通过主线程操作的,也会耗费肯定的CPU资源。为了防止主动清理升高Redis的解决性能,如下两个参数能够管制清理动作耗费的CPU工夫比例的上上限: ...

September 26, 2023 · 1 min · jiezi

关于redis:LFU一文让你弄清-Redis-LFU-页面置换算法

上一次,置信大家曾经晓得对于 LRU 页面置换算法的思维和实现了,这里能够一键中转: 【LRU】一文让你弄清 Redis LRU 页面置换算法Redis 的淘汰策略中,对于 LFU 页面置换算法,明天咱们来捋一捋到底思维是啥,能够如何去实现它 这就让咱们进入状态吧 ✔LFU 的思维和实现LFU 全称为:Least frequently used 含意为:应用频次起码的,即为 最不常常应用的 思维是:如果数据在一段时间被拜访的次数较少,那么在将来的一段时间,这段数据被拜访的几率就会更小 能够看到 LRU 和 LFU 思维上的区别是非常明显的 LRU 强调最近起码应用,关注的是最近有没有应用过<!----> LFU 强调的是一段时间的应用次数,关注的是频次实际上, LRU 和 LFU 在实现上也是挺类似的,都要应用到双向链表和 hashmap,只不过,咱们须要思考如何很好的解决好频次这个数据 LRU 查问数据的时候,为了将工夫复杂度从 O(n) 升高到 O(1),抉择了应用 hashmap 来寄存具体的 key 和对应的 数据节点 那么 LFU 中,也能够如法炮制,能够应用 hashmap 寄存 频次 和 对应的该频次的节点组成的链表 简略来看 LRU 的实现时用一个双向链表,插入数据应用头插法,从尾部淘汰数据<!----> 那么 LFU 的实现实际上是应用了 2 个 hashmap 和 多个 双向链表,插入数据应用尾插法,淘汰数据从链表头淘汰✔举例时刻还是同样的办法,咱们举个例子,就能很好的明确这个思维了 例如,咱们还是要插入这些数据 set(0,0),set(1,1),set(2,2),set(3,3),set(4,4),get(3) ,set(5,5) ,链表的容量为 3 ...

September 25, 2023 · 2 min · jiezi

关于redis:Redis学习之aof

开启aof配置文件批改appendonly yes 追加形式应用 Always 策略appendfsync always在每次写入操作实现后都会执行同步操作。这是最平安的选项,因为它确保写入操作被长久化到磁盘,但它也可能会导致性能降落,因为每个写入操作都须要期待同步实现。应用 Everysec 策略appendfsync everysecRedis 将每秒执行一次同步操作,将在该秒内产生的所有写入操作写入 AOF 文件。这种策略在性能和持久性之间提供了一种均衡,因为它能够缩小同步操作的次数,但依然提供了绝对高的数据持久性。应用 No 策略appendfsync noRedis 不执行显式同步操作,而是依赖操作系统来将数据异步刷新到磁盘。这是性能最高的选项,因为它不会在每次写入操作时执行同步,但这也意味着在某些状况下,数据可能会在产生故障时失落。multi part aof它是一种对 AOF 文件进行拆分和合并的技术,旨在进步 AOF 文件的备份和复原性能。6和7两者都是通过配置来决定长久化文件地位, 配置 appendfilename "appendonly.aof"dir /redis/data Redis 6会将aof文件保留在 /redis/data/appendonly.aofRedis 7须要再配置一个参数appenddirname "aofdir"会将aof文件保留在 /redis/data/aofdir/xxx.aof修复aof文件谬误命令redis-check-aof --fix

September 25, 2023 · 1 min · jiezi

关于redis:Redis的底层类型之sort-set

sorted sets有序汇合 ZADDZCARDZCOUNTZDIFFZINCRBYZINTERZINTERCARD下面这些命令都是根底的 ZLEXCOUNT计算有序汇合中指定字典区间内的成员数量 ZLEXCOUNT key min maxZMPOPZMSCORE这里是POP和SCORE的操作多个key的指令ZPOPMAXZPOPMINZRANDMEMBERZRANGEZRANGEBYLEXZRANGEBYSCOREZRANGEBYSCORE 这个要被遗弃的的指令,用ZRANGE代替(加上BYSCROE)ZRANGESTOREBZMPOPBZPOPMAXBZPOPMIN这三个命令都是阻塞模式的。

September 25, 2023 · 1 min · jiezi

关于redis:Redis的底层类型之list

listsRedis lists are linked lists of string values. Redis lists are frequently used to:Redis 列表是由字符串值组成的链接列表。Redis 列表常常用于: Implement stacks and queues.实现堆栈和队列。Build queue management for background worker systems.构建后盾工作者零碎的队列治理。常用命令LPUSHadds a new element to the head of a list; RPUSH adds to the tail. LPOPremoves and returns an element from the head of a list; RPOP does the same but from the tails of a list. LLENLMOVELMOVE source destination <LEFT | RIGHT> <LEFT | RIGHT>atomically moves elements from one list to another. ...

September 25, 2023 · 1 min · jiezi

关于redis:Redis的底层类型之json

对于redisjsonThe JSON capability of Redis Stack provides JavaScript Object Notation (JSON) support for Redis. 能够看到redis json是输出RedisStack的一部分。 那么RedisStack又是什么呢?Redis Stack is the best starting point for working with Redis. We've bundled together the best of the technology that we have to offer into an easy-to-use package. Redis Stack extends the core features of Redis OSS and provides a complete developer experience for debugging and more. RedisStack 是应用 Redis 的最佳终点。咱们曾经把咱们必须提供的最好的技术捆绑在一起,造成一个易于应用的软件包。Redis Stack 扩大了 Redis OSS 的外围个性,并为调试等提供了残缺的开发人员体验。 ...

September 25, 2023 · 2 min · jiezi

关于redis:Redis的底层类型之string

stringSETstores a string value. SET key value [NX | XX] [GET] [EX seconds | PX milliseconds | EXAT unix-time-seconds | PXAT unix-time-milliseconds | KEEPTTL]KEEPTTL: 用于在应用 SET 命令设置键的值时,保留键的 TTL(Time To Live)信息。当你应用 SET 命令来更新一个曾经存在的键时,默认状况下会重置键的 TTL,也就是键的生存工夫会被从新计算。然而如果你心愿保留原有的 TTL,能够应用 KEEPTTL 选项。 SETEX等价于 SET key value EX seconds PSETEXPSETEX works exactly like SETEX with the sole difference that the expire time is specified in milliseconds instead of seconds. 跟SETEX相似,区别就是这个是毫秒。 SETNXstores a string value only if the key doesn't already exist. Useful for implementing locks. ...

September 25, 2023 · 2 min · jiezi

关于redis:Redis的底层类型之set

setsA Redis set is an unordered collection of unique strings (members).无序的字符串汇合 相干命令: SADDSADD key member [member ...]SREMSREM key member [member ...]SMEMBERSReturns all the members of the set value stored at key. SISMEMBERSISMEMBER key memberReturns if member is a member of the set stored at key.1 if the element is a member of the set.0 if the element is not a member of the set, or if key does not exist. ...

September 25, 2023 · 2 min · jiezi

关于redis:Redis的底层类型之hash

hashHSETHDELHEXISTSHGETHGETALLHINCRBYHINCRBYFLOATHKEYSHLENHMGETHMSETHRANDFIELDHRANDFIELD key [count [WITHVALUES]]When called with just the key argument, return a random field from the hash value stored at key.随机返回指定数量的key HSCANRedis HSCAN 命令用于迭代哈希表中的键值对。 HSCAN key cursor [MATCH pattern] [COUNT count]HSETNXHSTRLEN返回值得长度 HVALS返回所有的值,没有key

September 25, 2023 · 1 min · jiezi

关于redis:Redis的底层类型之stream

streamRedis Stream 次要用于音讯队列(MQ,Message Queue),Redis 自身是有一个 Redis 公布订阅 (pub/sub) 来实现音讯队列的性能,但它有个毛病就是音讯无奈长久化,如果呈现网络断开、Redis 宕机等,音讯就会被抛弃。 简略来说公布订阅 (pub/sub) 能够散发音讯,但无奈记录历史音讯。 而 Redis Stream 提供了音讯的长久化和主备复制性能,能够让任何客户端拜访任何时刻的数据,并且能记住每一个客户端的拜访地位,还能保障音讯不失落。 XADDXADD key [NOMKSTREAM] [<MAXLEN | MINID> [= | ~] count] <* | id> field value [field value ...]如果 mystream 不存在,NOMKSTREAM 选项将阻止主动创立新的 Stream count: 是阈值,限度音讯的数量 <stream>:指定要增加条目标流的名称。 MAXLEN [~|=] <count>:(可选)用于限度流的长度。~ 示意不包含最新的条目,| 示意包含最新的条目,<count> 指定要保留的最大条目数量。例如,MAXLEN ~ 100 示意保留最新的 100 个条目,MAXLEN | 100 示意保留最新的 101 个条目(包含最新的一个)。 ID <id>:(可选)指定新条目标 ID。如果省略,Redis 会主动生成一个惟一的 ID。 <field> <value>:指定要增加到条目标字段和值。 XGROUPXGROUP 是 Redis 中用于治理 Stream 消费者组的命令。它容许您创立、治理和配置 Stream 消费者组,以便多个消费者可能合作解决 Stream 中的音讯。 ...

September 25, 2023 · 1 min · jiezi

关于redis:Redis的底层类型之bitmapbitfields

bitmapBitmap能够状态记录或统计,如每日登录 SETBITSETBIT key offset valueGETBITGETBIT key offsetBITFIELDBITFIELD key [GET encoding offset | [OVERFLOW <WRAP | SAT | FAIL>] <SET encoding offset value | INCRBY encoding offset increment> [GET encoding offset | [OVERFLOW <WRAP | SAT | FAIL>] <SET encoding offset value | INCRBY encoding offset increment> ...]] key:指定要操作的 Redis 键。GET:用于获取指定类型的位字段值。SET:用于设置指定类型的位字段值。INCRBY:用于递增或递加指定类型的位字段值。encoding:指定位字段的数据类型,能够是 u8、i8、u16、i16、u32、i32,具体取决于您心愿的位字段类型。offset:指定位字段的偏移量。value:用于设置或递增/递加的值。OVERFLOW:指定溢出解决形式,能够是 WRAP(循环)、SAT(饱和)或 FAIL(失败)。设置一个 8 位的无符号整数:BITFIELD mykey SET u8 0 42这将在名为 mykey 的位字段中的偏移量 0 处设置一个无符号 8 位整数为 42。获取一个 16 位的有符号整数:BITFIELD mykey GET i16 8这将从 mykey 中的偏移量 8 处获取一个有符号 16 位整数的值。减少一个 32 位的无符号整数:BITFIELD mykey INCRBY u32 16 5这将在 mykey 的偏移量 16 处的无符号 32 位整数上减少 5。一次执行多个操作:BITFIELD mykey GET u8 0 GET i16 8 INCRBY u32 16 5BITFIELD_ROBITFIELD_RO 命令是 BITFIELD 命令的只读变体,它仅承受 GET 子命令,并且能够平安地在只读正本中应用。这个命令的目标是在不毁坏命令标记的状况下,在只读正本中容许 BITFIELD 的行为。 ...

September 25, 2023 · 1 min · jiezi

关于redis:Redis的底层类型之haperloglog

haperloglogHyperLogLog is a probabilistic data structure that estimates the cardinality of a set.The Redis HyperLogLog implementation uses up to 12 KB and provides a standard error of 0.81%.haperloglgo是一个概率性的数据结构,用于预计汇合的基数,Redis HyperLogLog 实现最多应用12 KB,并提供0.81% 的规范谬误。 能够用作统计一些PV,UV等。 PFADDAdds all the element arguments to the HyperLogLog data structure stored at the variable name specified as first argument. PFADD key [element [element ...]]PFADDPFCOUNT key [key ...]redis> PFADD hll foo bar zap(integer) 1redis> PFADD hll zap zap zap(integer) 0redis> PFADD hll foo bar(integer) 0redis> PFCOUNT hll(integer) 3redis> PFADD some-other-hll 1 2 3 bar(integer) 1redis> PFCOUNT hll some-other-hll(integer) 6When called with a single key, returns the approximated(近似的) cardinality computed by the HyperLogLog data structure stored at the specified variable, which is 0 if the variable does not exist. ...

September 25, 2023 · 1 min · jiezi

关于redis:Redis学习之rdb

保留rdbSAVESAVE会阻塞以后redis服务器,直至长久化工作实现,线上最好不要应用这个命令 BGSAVERedis会在后盾异步进行快照操作,不阻塞redis,redis还能够相应客户端申请,该形式会fork一个子过程,由子过程进行复制长久化过程 LASTSVAE最初一次save的的工夫戳。 FLUSHALL/FLUSHDB会触发保留rdb,然而rdb是清空后的。 SHUTDOWN执行shutdown命令,如果没有开启aof也会登程长久化到rdb文件。 修复rdb文件redis-check-rdb redis-check-rdb xxx.rdb 禁用rdbsave "" 参数优化stop-writes-on-basave-error yes如果长久化失败,是不是要持续承受客户端写申请 rdb-compression是否压缩 redbchecksumrdb-del-sync-files在没有长久化的状况下删除复制中应用的rdb文件启用。

September 25, 2023 · 1 min · jiezi

关于redis:一文了解Redis常用命令

前言本文包含Redis中罕用的一些命令,包含针对所有的键相干的命令,以及5种罕用数据类型:字符串、哈希、列表、汇合以及有序汇合的一些命令。 鉴于集体程度无限,文章中若有不对之处,烦请大家留言斧正。 键相干查看所有的键keys会遍历所有的键,它的工夫复杂度是O(n),因而当Redis保留了大量的键时,这个命令会十分耗时,因而生产环境下禁止应用该命令。 keys *//初始化数据study:0>set zhangsan 20"OK"study:0>get zhangsan"20"study:0>set lisi 25"OK"study:0>set wangwu 30"OK"//应用study:0>keys * 1) "lisi" 2) "zhangsan" 3) "wangwu"keys命令也反对含糊匹配,比方咱们想获取所有以zhang结尾的键,能够这样写: keys zhang*study:0>keys zhang* 1) "zhangsan"获取键的总数dbsizestudy:0>dbsize"3"dbsize命令在计算键总数时不会遍历所有的键,而是间接获取Redis内置的键总数变量,所以dbsize命令的工夫复杂度是O(1) 查看键是否存在exists key这个命令返回1或者0,1示意键存在,0示意键不存在 study:0>exists zhangsan"1"study:0>exists dalao"0"删除键del key [key2, key3....]这个命令返回删除胜利的键总数,如果删除的键都不存在,则返回0 study:0>del zhangsan"1"study:0>del dalao"0"设置键的过期工夫Redis反对给键设置过期工夫,当键过期后,该键会在Redis中被主动删除。 //初始化键study:0>set hello world"OK"//给键设置50秒的过期工夫study:0>expire hello 50"1"设置过期工夫之后,咱们也能够通过ttl命令返回键的残余过期工夫,ttl命令有3种返回值: 大于等于0的整数:键的残余过期工夫-1示意键没有设置过期工夫-2示意键不存在(有可能是最开始就不存在,有可能是键的过期工夫到了被主动删除了)study:0>ttl hello"10"study:0>ttl hello"3"study:0>ttl hello"-2"键的数据类型type keystudy:0>set hello world"OK"study:0>type hello"string"若key的类型是字符串类型,则返回string。若key的类型是列表类型,则返回list。 若key不存在,则返回none study:0>type abc"none"字符串类型设置值set key value [ex seconds] [px milliseconds] [nx|xx]study:0>set me water76016"OK"set命令的选项阐明 ex seconds:为键设置秒级过期工夫px milliseconds:为键设置毫秒级过期工夫nx:键必须不存在能力设置胜利,用于新增xx:键必须存在能力设置胜利,用于更新其余set命令 Redis提供了setnx和setex两个命令,作用和ex和nx参数是一样的。 //命令格局setex key seconds valuesetnx key value//setex应用范例(设置键为hello,20秒的过期工夫)study:0>setex hello 20 world"OK"//setnx应用范例(第一次键不存在设置胜利,第二次键曾经存在设置失败)study:0>setnx me water76016"1"study:0>setnx me water76016"0"获取值get key如果获取的键不存在,则会返回null(空) ...

September 23, 2023 · 3 min · jiezi

关于redis:2分钟内完成2000万key数据的迁移

Redis是目前最风行的键值对存储数据库,凭借高性能和丰盛的数据类型的个性,不仅能够作为缓存,还能够作为一个可长久化的数据库存储。随着业务的倒退和版本的迭代,必然会遇到内存不足、集群节点不够和BUG等一系列问题。为了避免这些问题导致的系统故障,经常会把对内存、集群节点扩缩容和版本升级等操作作为工作考核的重要一项。这些操作都波及了数据的迁徙,所以,提供高效、平安的不停机数据迁徙计划是十分有必要的。 当初,NineData 在反对业务不中断的前提下,实现了配置简略、稳固、高效、平安的数据迁徙服务,很好地满足版本升级、扩容、缩容等场景下对数据迁徙和同步的需要。经实测,NineData 可在 2分钟内实现2000万个 key(5GB)数据的迁徙,均匀 迁徙速度为 164398 个key/秒,性能是开源工具的2倍多。 1、传统的迁徙计划目前,数据迁徙次要的形式有:应用 RDB 迁徙,或一些开源工具进行数据迁徙。对于这些形式的迁徙,会存在一些问题: 须要停机,对于拷贝 RDB 文件形式的迁徙,不能保障在线业务,并且也不能兼容大版本升级。准确性难保障,不反对数据检测能力,迁徙后的数据品质难以保障。可靠性差,对于开源工具,迁徙异样后,过程间接退出。运维性差,不能进行暂停、限流、告警等操作。2、高性能的迁徙计划NineData 提供的数据复制同时蕴含了数据迁徙和数据同步的能力,在不影响业务的前提下,提供了高效、稳固、平安的迁徙能力。相较于传统迁徙比,NineData 的 Redis 数据迁徙能力有如下劣势: ▶︎ 简略易用 一分钟即可实现工作配置,并全自动化实现工作迁徙。 ▶︎ 强劲性能 通过动静攒批、队列优化、流式内存治理等核心技术,迁徙性能达到16万key/秒,性能是开源迁徙工具的2倍,无效保障迁徙效率。 ▶︎ 高牢靠 联合新型断点、异样诊断及丰盛的修复伎俩,对于迁徙过程中可能呈现软硬件故障,提供欠缺的容灾能力,大大提高了迁徙的成功率。 通过上述劣势,保障了 NineData 在 Redis 迁徙场景下的当先性。另外,NineData 还提供了比照性能,蕴含全量、疾速和不统一复检的比照形式,并且也反对不同的比照频率。 在迁徙或复制完结后,通过比照,无效地保障数据的品质。 3、操作应用NineData 在提供弱小迁徙能力的同时,也保障了应用的简略性,只需1分钟就能实现迁徙工作的配置,实现齐全自动化的数据迁徙过程。上面咱们来看下整个工作的配置过程: 3.1 迁徙链路的配置 迁徙链路的配置 配置工作名称,抉择要迁徙的源和指标实例。抉择复制类型,数据迁徙抉择构造和全量复制(数据迁徙)。依据须要,抉择适合的抵触解决策略。3.2 抉择迁徙对象 抉择迁徙对象 抉择迁徙对象:可抉择不同 DB 进行迁徙。 3.3 配置映射对象 配置映射对象 配置映射:能够把源实例的多个数据库(0~15)映射到指标实例的指定1个或多个数据库,通过该映射能力能够实现相似于 MySQL 多源复制的场景。 3.4 预查看 预查看 通过欠缺的查看项,保障了迁徙工作的稳定性。到此,咱们就实现了一个高效、平安的 Redis 迁徙工作的配置,当实现配置并启动工作后,NineData 会主动启动全量复制及增量复制过程,实现全自动化的数据迁徙。 同时,为了提供更好的迁徙体验,NineData 针对迁徙过程提供了欠缺的观测、干涉能力。 其岂但提供对象迁徙的具体状态、停顿、详情,还通过监控和日志走漏后盾线程的外部执行状况,帮忙用户全方位追踪迁徙停顿。同时,还针对运行过程中可能呈现的异常情况,提供根底诊断和迁徙限流能力,让用户可能自主疾速地诊断并修复链路,保障迁徙稳定性。迁徙期间的信息: NineData针对迁徙过程提供了欠缺的观测能力 NineData提供欠缺的可干涉能力 NineData提供根底诊断和迁徙限流能力 4、总结NineData 基于全量复制、增量日志复制技术,提供了高效、安全可靠的 Redis 不停机迁徙计划。当然,除了 Redis,NineData 曾经反对数十种常见数据库的迁徙复制,实现数据库迁徙、数据容灾、数据双活、数据仓库实时集成等业务场景。同时,除了 SAAS 模式外,还提供了企业专属集群模式,满足企业最高的数据安全合规要求。 目前,NineData已在运营商、金融、制造业、地产、电商等多个行业实现大规模利用实际。如果您感兴趣的话,能够登录官网:数据迁徙-迁徙工具-数据传输-NineData-玖章算术,立刻开始应用。 ...

September 12, 2023 · 1 min · jiezi

关于redis:我是如何用-redis-分布式锁来解决线上历史业务问题的

近期发现,开发性能的时候发现了一个 mq 生产程序错乱(历史遗留问题),导致业务异样的问题,看看我是如何解决的 问题抛出首先,简略介绍一下状况: 线上 k8s 有多个 pod 会去生产 mq 中的音讯,可是生产者发送的音讯是冀望肯定要有序去生产,此时要表白的是,例如 生产者如果发送了 3 个告诉音讯,别离是 1 零碎曾经在 / 组上面增加 a 组,你记得绑定策略 (例如 / 组绑定的是策略是:容许看视频类型的网站)<!----> 2 零碎曾经在 /a 组下增加了 b 组, 你记得绑定策略(冀望绑定的策略和他的父组策略一样)<!----> 3 零碎曾经在 b 组上面增加 小 d 用户,你的绑定策略(冀望绑定的策略和他的所在组一样)此处,若有 3 个 pod 的别离拿到了上述 3 条音讯,然而本身理论生产结束的程序可能是 先实现了 3 音讯对应的业务逻辑,再是 2 音讯 的业务逻辑,最初是 1 音讯的业务逻辑 那么这个时候,小 d 用户就没有绑定上 容许看视频类型的网站 这一条策略,天然 b组 和 a 组也没有绑定上这条策略,这就和咱们预期的齐全不统一了 当然,理论状况对于单条单条的音讯解决根本不会呈现这种偏差,然而在批量解决的时候,就会呈现理论业务解决程序与冀望不统一的状况,那么就是妥妥的线上问题了(小 d 上网的时候想看视频,可是始终看不了,于是就疯狂投诉。。。) 思考解决对于这个问题如何解决呢? 咱们晓得,咱们应用 mq 的目标是为了做到去解决咱们的异步逻辑,还能对流量进行削峰,服务间解耦 对于咱们的 A 服务,曾经解决了对于增加用户的,增加组的逻辑,发送告诉音讯给到 B 服务的时候,B 服务本身的解决程序,未依照既定的程序实在依照程序生产结束,导致呈现了业务问题 ...

September 11, 2023 · 2 min · jiezi

关于redis:redis分布式锁setnxlua脚本的java实现-京东物流技术团队

1 前言在当初工作中,为保障服务的高可用,应答单点故障、负载量过大等单机部署带来的问题,生产环境罕用多机部署。为解决多机房部署导致的数据不统一问题,咱们常会抉择用分布式锁。 目前其余比拟常见的实现计划我列举在上面: 基于缓存实现分布式锁(本文次要应用redis实现)基于数据库实现分布式锁基于zookeeper实现分布式锁本文是基于redis缓存实现分布式锁,其中应用了setnx命令加锁,expire命令设置过期工夫并lua脚本保障事务一致性。Java实现局部基于JIMDB提供的接口。JIMDB是京东自主研发的基于Redis的分布式缓存与高速键值存储服务。 2 SETNX根本语法:SETNX KEY VALUE SETNX 是示意 SET ifNot eXists, 即命令在指定的 key 不存在时,为 key 设置指定的值。 KEY 是示意待设置的key名 VALUE是设置key的对应值 若设置胜利,则返回1;若设置失败(key存在),则返回0。 由此,咱们会抉择用SETNX来进行分布式锁的实现,当Key存在时,会返回加锁失败的信息。 SET 与 SETNX 区别: SET 如果key曾经存在,则会笼罩原值,且忽视类型 SETNX 如果key曾经存在,则会返回0,示意设置key失败 Redis 2.6.12版本前后比照: 2.6.12版本前:分布式锁并不能只用SETNX实现,须要搭配EXPIRE命令设置过期工夫,否则,key将永远无效。其中,为保障SETNX和EXPIRE在同一个事务里,咱们须要借助LUA脚本来实现事务实现。(因为在写这篇文章时,JIMDB还未反对**SET key value [EX seconds|PX milliseconds] [NX|XX] [KEEPTTL]**语法,故本文仍然用lua事务) 2.6.12版本后:SET key value [EX seconds|PX milliseconds] [NX|XX] [KEEPTTL] 语法糖可用于分布式锁并反对原子操作,无需EXPIRE命令设置过期工夫。 3 LUA脚本什么是LUA脚本?Lua是一种轻量玲珑的脚本语言,用规范C语言编写并以源代码模式凋谢,其设计目标是为了嵌入应用程序种,从而为程序提供灵便的扩大和定制性能。 为什么须要用到LUA脚本?本文的锁实现是基于两个Redis命令 - SETNX 和 EXPIRE。 为保障命令的原子性,咱们将这两个命令写入LUA脚本,并上传至Redis服务器。Redis服务器会单线程执行LUA脚本,以确保两个命令在执行期间不被其余申请打断。 LUA脚本的劣势缩小网络开销。若干命令的屡次申请,可组合成一个脚本进行一次申请高复用性。脚本编辑一次后,雷同代码逻辑可多处应用,只需将不同的参数传入即可。原子性。若期望多个命令执行期间不被其余申请打断,或呈现竞争状态,能够用LUA脚本实现,同时保障了事务的一致性。分布式锁LUA脚本的实现假如在同一时刻只能创立一个订单,咱们能够将orderId作为key值,uuid作为value值。过期工夫设置为3秒。 LUA脚本如下,通过Redis的eval/evalsha命令实现: -- lua加锁脚本-- KEYS[1],ARGV[1],ARGV[2]别离对应了orderId,uuid,3-- 如果setnx胜利,则持续expire命令逻辑if redis.call('setnx',KEYS[1],ARGV[1]) == 1 then -- 则给同一个key设置过期工夫 redis.call('expire',KEYS[1],ARGV[2]) return 1 else -- 如果setnx失败,则返回0 return 0 end-- lua解锁脚本-- KEYS[1],ARGV[1]别离对应了orderId,uuid-- 若无奈获取orderId缓存,则认为曾经解锁if redis.call('get',KEYS[1]) == false then return 1 -- 若获取到orderId,并value值对应了uuid,则执行删除命令 elseif redis.call('get',KEYS[1]) == ARGV[1] then -- 删除缓存中的key return redis.call('del',KEYS[1]) else -- 若获取到orderId,且value值与存入时不统一,则返回非凡值,不便进行后续逻辑 return 2 end【注】依据Redis的版本,在LUA脚本中,当应用redis.call('get',key)断定缓存key不存在时,须要留神对比值为布尔类型的false,还是null。 ...

August 29, 2023 · 2 min · jiezi

关于redis:Redis-List-设计与实现

前言之前咱们曾经探讨过 Sorted Set 在 Redis 的实现,学习到了 Redis 在不同数据量的时候应用了不同的构造来优化存储和性能,并且应用两种不同的数据结构的组合来进一步优化。而明天要探讨的 List 也一模一样。 ListList 就是咱们常见的列表,在很多语言中都有实现,无论是数组还是链表,它最终的表现形式都差不多,都是一个“长长的数据”,而对于不同的底层实现,所对应的操作带来的性能也不同。比方在 java 中就有 LinkedList 和 ArrayList。而 Redis 是如何做的呢? 如果你对 Redis 的 List 应用并不是很相熟,倡议下查看一下它所有反对的命令 https://redis.io/commands/?group=list老版本在 Redis 的老版本中 list 的实现和 Sorted Set 策略相似,对于不同数据量的状况下实现是不一样的。在数据量小的时候,应用的也是 ziplist 也就是压缩列表(能够看做数组),而当数据质变大触发条件时,就变成了 linkedlist 也就是双向链表。 ziplist 就是通过数据的长度来定位前一个和后一个数据,从而缩小了双向链表中的前后指针。而新版本中 Redis 应用了 quicklist 来实现,所以咱们次要探讨的是 quicklist 是如何实现的。 quicklist数据结构首先要看的必定是构造定义 /* quicklist is a 40 byte struct (on 64-bit systems) describing a quicklist. * 'count' is the number of total entries. * 'len' is the number of quicklist nodes. * 'compress' is: 0 if compression disabled, otherwise it's the number * of quicklistNodes to leave uncompressed at ends of quicklist. * 'fill' is the user-requested (or default) fill factor. * 'bookmarks are an optional feature that is used by realloc this struct, * so that they don't consume memory when not used. */typedef struct quicklist { quicklistNode *head; quicklistNode *tail; unsigned long count; /* total count of all entries in all listpacks */ unsigned long len; /* number of quicklistNodes */ signed int fill : QL_FILL_BITS; /* fill factor for individual nodes */ unsigned int compress : QL_COMP_BITS; /* depth of end nodes not to compress;0=off */ unsigned int bookmark_count: QL_BM_BITS; quicklistBookmark bookmarks[];} quicklist;咱们抓重点: ...

August 29, 2023 · 4 min · jiezi

关于redis:Redis-事件机制是如何实现的

前言咱们都晓得,Redis 是单线程(非谨严),你是否想过,一个线程要如何解决来自各个客户端的各种申请呢?它忙的过去吗?没错,它还真的能忙过去,并且还东倒西歪。其中多亏了 IO 多路复用,而不仅仅是它,事件机制在其中也是一个不错的设计。 之前我提到过有对于 IO 多路复用对于 Redis 的影响,IO多路复用和多线程会影响Redis分布式锁吗? 其中有局部内容其实曾经提到了,所以本文会更加关注于事件机制自身。 PS:Redis 高版本曾经反对多线程解决某些事件,为了简化,这里不做探讨,故下文呈现的单线程仅是形容那些必须单线程执行的场景。 前置常识IO 多路复用尝试思考首先,让咱们来思考一下,如果是咱们本人来实现,会尝试如何去做。 对于申请连贯解决的思考最笨的办法,那么就是来一个客户端 accept 一次,而后给什么申请做什么事件,先来先做,做完走人,对吧。那显然这样太慢了,要晓得作为一个缓存,这样设计要把人给急死。 当然,咱们也能够说,来一个我开一个线程独自解决你,相当于你一来我就独自找人为你服务,而服务的人最终会将申请给到一个解决核心,让解决核心对立去解决,而后将后果返回。但显然 Redis 没有那么多资源让你节约。 于是要找人帮忙,那就是 IO 多路复用,至多它能帮我解决后面服务的问题,fd 我就不论了,间接通知我哪些人来了,并且通知我有事的是那些人。 反观机制的思考既然 epoll_wait 能 通知咱们有那些 socket 曾经就绪,那么咱们就解决就绪的这些就能够了。但咱们须要一个正当的机制来帮咱们来优雅的解决他们,毕竟 Redis 前面只有个单线程在解决。因为解决没这么快,必定须要一个中央来寄存未解决的这些事件,那很正当就能想到须要一个相似 buffer 的货色。 所以,对于这个事件机制,我第一个想法就是弄个队列,或者 ringbuffer 来搞,那不就是一个生产消费者模型吗? 事件机制那么上面咱们就来看看 Redis 它是如何设计。 分类首先 Redis 分了两类事件 fileEvents 文件事件,就是咱们之前提到的申请的解决,咱们也次要探讨这个timedEvents 定时事件,没错必定有一些定时工作触发的事件在外面文件事件解决 OK,看完图咱们就有了一个大抵的印象,为了灵便的解决不同的事件,须要将事件调配给处理器去解决,这里也是咱们之前思考的时候没有想到的一个设计。通常来说对于任何的解决往往都有这样一个分配器去调配所有的工作,这样能够让扩大更加灵便,如果后续有新的类型,只须要扩大出一个新的处理器就能够了。 源码剖析https://github.com/redis/redis/blob/9b1d4f003de1b141ea850f01e7104e7e5c670620/src/ae.c#L493首先入口在 aeMain 这个简略,就是循环,也正是这个循环解决着所有的事件,咱们能够看到,只有不停(stop),就会始终循环解决 void aeMain(aeEventLoop *eventLoop) { eventLoop->stop = 0; while (!eventLoop->stop) { aeProcessEvents(eventLoop, AE_ALL_EVENTS| AE_CALL_BEFORE_SLEEP| AE_CALL_AFTER_SLEEP); }}而后就是咱们重点的 aeProcessEvents 办法,其中重点就是调用 aeApiPoll 获取以后就绪的事件,而后你就能看到咱们的 aeFileEvent 也就是文件事件了,最初还有 processTimeEvents 解决定时事件。那么事件自身,是如何解决的呢?就是 rfileProc 和 wfileProc 一个解决读一个解决写。那么问题来了,这两个办法具体是什么呢?卖个关子,咱们先瞅一眼 aeApiPoll ...

August 28, 2023 · 3 min · jiezi

关于redis:Redis-Sorted-Set-实现与应用

前言在没有真正意识 Redis 之前,你可能都低估了它一开始对于 Redis 咱们的意识都是一个 key:value 的缓存,当然用的最多的也就是这个作用。但随着 Redis 的一直倒退,缓缓的我就发现它有的性能越来越多,它可能在肯定水平上帮咱们疾速简化一些高并发场景下的开发。我感觉它其中最重要的设计是它的 <mark style="background: #FFB86CA6;">数据结构</mark> 。通过几个根底的数据结构的组合,就能实现一些高性能的构造。比方咱们明天要探讨的 Sorted Set 就是这样一个构造。因为 Redis 中称为 zset 所以后文中为了简化间接也叫 zset。 什么是 Sorted Set我感觉可能很多同学还没有用过,其实非常容易了解,就是一个有序的汇合,无论你以什么程序增加元素,最终都会依据分数排成一个有序的汇合。通过它咱们能够疾速取得一个组数据的最高的几个值。 猜想实现堆?没错,我的第一反馈也是这个,要实现一个这样的构造最先想到的就是堆或者说是优先队列的实现,完满匹配。 但,不对,咱们晓得,对于堆,咱们只能疾速失去最大或最小值。而对于 zset 其中有一个办法是 ZRANGE key start stop 也就是能够获取一个范畴,比方获取排序后的第 3 位开始后的 5 个元素。而且它能够疾速获取到一个某个元素的地位 ZRANK key,也就是疾速查问到某个元素的排名。 所以,这显然不能简略的用“堆”搞定了。 前置常识ziplist 压缩列表 redis 中为了压缩数据大小来实现的一种数据结构,通过数据长度来定位下一个数据和前一个数据skiplist 跳表 一种 “重叠”(这个概念是我脑补的)的数据结构,通过不同层级的的标记能疾速进行元素地位的定位,思路上有点相似二分这两个构造我在这里不具体开展了,不然篇幅太长。如有须要,请查看参考链接: redis-ziplistredis-skiplist具体实现废话不多说,间接开代码最间接。 typedef struct zset { dict *dict; zskiplist *zsl;} zset;所以 zset 的构造就是一个字典(hash 表)+ 一个 skiplist(跳表)就完事了呗?简略,走了走了。别急~ 其实并不是这样。 数据结构的变动我来看一下元素的 add 办法就明确了外面的玄机 int zsetAdd(robj *zobj, double score, sds ele, int in_flags, int *out_flags, double *newscore) { // 重点 1 if (zobj->encoding == OBJ_ENCODING_LISTPACK) { unsigned char *eptr; if ((eptr = zzlFind(zobj->ptr,ele,&curscore)) != NULL) { ................... } else if (!xx) { /* check if the element is too large or the list * becomes too long *before* executing zzlInsert. */ if (zzlLength(zobj->ptr)+1 > server.zset_max_listpack_entries || sdslen(ele) > server.zset_max_listpack_value || !lpSafeToAdd(zobj->ptr, sdslen(ele))) { // 重点 2 zsetConvertAndExpand(zobj, OBJ_ENCODING_SKIPLIST, zsetLength(zobj) + 1); } else { zobj->ptr = zzlInsert(zobj->ptr,ele,score); if (newscore) *newscore = score; *out_flags |= ZADD_OUT_ADDED; return 1; } } else { *out_flags |= ZADD_OUT_NOP; return 1; } } /* Note that the above block handling listpack would have either returned or * converted the key to skiplist. */ // 重点 3 if (zobj->encoding == OBJ_ENCODING_SKIPLIST) { ............... } else { serverPanic("Unknown sorted set encoding"); } return 0; /* Never reached. */}依据以后 encoding 不同,有两种不同的实现,别离是:ziplist 和咱们下面提到的 `dict + skiplist触发数据结构变动的条件是元素数量超过 zset_max_listpack_entries 默认 128,还有一个条件是,有序汇合保留的所有元素成员的长度都小于 zset_max_listpack_value(64) 字节咱们能够通过 OBJECT ENCODING key 命令查看对象的编码方式(数据结构)127.0.0.1:6379> OBJECT ENCODING linkinstar"listpack"127.0.0.1:6379> OBJECT ENCODING linkinstars"skiplist"为什么须要 dict这是十分常见的一种查问优化策略,就是用空间换工夫,为了实现疾速用 key 查问该元素的分数和地位就能用到 dict(ZRANK) ...

August 26, 2023 · 2 min · jiezi

关于redis:redis持久化AOF和RDB的区别分别解决什么场景问题

什么是Redis长久化?长久化就是把内存的数据写到磁盘中去,避免服务宕机了内存数据失落。 Redis 提供了两种长久化形式: RDB(默认) 和AOF 。 RDB快照rdb是Redis DataBase缩写。 性能外围函数rdbSave(生成RDB文件)和rdbLoad(从文件加载内存)两个函数。 RBD长久化通过保留数据库中的键值对来记录数据库状态。 RBD配置文件的开启save 900 1 // 900s内,有1条写入,则产生快照save 300 1000 // 如果300秒内有1000次写入,则产生快照save 60 10000 // 如果60秒内有10000次写入,则产生快照(这3个选项都屏蔽,则rdb禁用)stop-writes-on-bgsave-error yes // 后盾备份过程出错时,主过程是否进行写入rdbcompression yes // 导出的rdb文件是否压缩。倡议没有必要开启,毕竟Redis自身就属于CPU密集型服务器,再开启压缩会带来更多的CPU耗费,相比硬盘老本,CPU更值钱。rdbchecksum yes // 导入rbd复原数据时,是否验证rdb的完整性dbfilename dump.rdb //导出来的rdb文件名dir ./ //rdb的搁置门路RDB原理针对RDB形式的长久化,手动触发能够应用: save:会阻塞以后Redis服务器,直到长久化实现,线上应该禁止应用。 bgsave:该触发形式会fork一个子过程,由子过程负责长久化过程,因而阻塞只会产生在fork子过程的时候。 而主动触发的场景次要是有以下几点: 依据咱们的 save m n 配置规定主动触发;从节点全量复制时,主节点发送rdb文件给从节点实现复制操作,主节点会触发 bgsave;执行 debug reload 时;执行 shutdown时,如果没有开启aof,也会触发。因为 save 根本不会被应用到,咱们重点看看 bgsave 这个命令是如何实现RDB的长久化的。 这里留神的是 fork 操作会阻塞,导致Redis读写性能降落。咱们能够管制单个Redis实例的最大内存,来尽可能升高Redis在fork时的事件耗费。以及下面提到的主动触发的频率缩小fork次数,或者应用手动触发,依据本人的机制来实现长久化。 BGSAVE命令执行时的服务器状态首先,在BGSAVE命令执行期间,客户端发送的SAVE命令会被服务器回绝,服务器禁止SAVE命令和BGSAVE命令同时执行是为了防止父过程(服务器过程)和子过程同时执行两个rdbSave调用,避免产生竞争条件。 其次,在BGSAVE命令执行期间,客户端发送的BGSAVE命令会被服务器回绝,因为同时执行两个BGSAVE命令也会产生竞争条件。 最初, BGREWRITEAOF和BGSAVE两个命令不能同时执行: 如果BGSAVE命令正在执行,那么客户端发送的BGREWRITEAOF命令会被提早到BGSAVE命令执行结束之后执行。如果BGREWRITEAOF命令正在执行,那么客户端发送的BGSAVE命令会被服务器回绝。因为BGREWRITEAOF和BGSAVE两个命令的理论工作都由子过程执行,所以这两个命令在操作方面并没有什么抵触的中央,不能同时执行它们只是一个性能方面的思考-并收回两个子过程,并且这两个子过程都同时执行大量的磁盘写入操作,这怎么想都不会是一个好主见。 AOFAof是Append-only file缩写。 AOF长久化通过保留redis服务器所执行的写命令来记录数据库状态。 AOF长久化的实现: AOF长久化可分为命令追加、文件写入、文件同步三个步骤。 从长久化中复原数据RDB文件的载入工作是在服务器启动时主动执行的,所以Redis并没有专门用于载入RDB文件的命令,只有Redis服务器在启动时检测到RDB文件存在,它就会主动载入RDB文件。 服务器在载入RDB文件期间,会始终处于阻塞状态 ,直到载入实现。 ...

August 23, 2023 · 1 min · jiezi

关于redis:Redis-的-set-nx-底层怎么实现的

审题这个问题其实自身很"简略",那么只有两种可能一种你看过 Redis 的源码,一种是没看过进行猜想。不过首先咱们能够说一些前奏: Redis 一开始是有 setnx 这个命令的,起初废除了,而将 nx 作为 set 的一个参数项,同时也就反对指定过期工夫这个命令的性能就是 set 一个 kv,如果 k 存在则失败,如果 k 不存在就胜利 set 这个 kv咱们经常会用 Redis 的 set nx 来实现分布式锁,所以预计提问者想确保你理解原理,从而应用分布式锁的时候更加安心,或者想通过这个问题来引出分布式锁的问题猜想咱们首先能够大胆猜想一下实现形式。能够间接先简化一下问题,实质就是给你一个 map,而后实现一个 setnx 办法,当 k 存在则间接失败。最要害的问题就是解决并发问题。 那解决并发的问题,能想到的就是要么锁,要么 cas,要么间接队列卡死,对吧。 而后,联合所晓得的,redis 自身执行命令就是单线程,不须要锁,没有并发,那么间接查一把,而后解决就完事了。如果不看源码应该没有别的坑了吧。 解答话不多说,间接上源码: /* Forward declaration */static int getExpireMillisecondsOrReply(client *c, robj *expire, int flags, int unit, long long *milliseconds);void setGenericCommand(client *c, int flags, robj *key, robj *val, robj *expire, int unit, robj *ok_reply, robj *abort_reply) { long long milliseconds = 0; /* initialized to avoid any harmness warning */ int found = 0; int setkey_flags = 0; if (expire && getExpireMillisecondsOrReply(c, expire, flags, unit, &milliseconds) != C_OK) { return; } if (flags & OBJ_SET_GET) { if (getGenericCommand(c) == C_ERR) return; } found = (lookupKeyWrite(c->db,key) != NULL); if ((flags & OBJ_SET_NX && found) || (flags & OBJ_SET_XX && !found)) { if (!(flags & OBJ_SET_GET)) { addReply(c, abort_reply ? abort_reply : shared.null[c->resp]); } return; } /* When expire is not NULL, we avoid deleting the TTL so it can be updated later instead of being deleted and then created again. */ setkey_flags |= ((flags & OBJ_KEEPTTL) || expire) ? SETKEY_KEEPTTL : 0; setkey_flags |= found ? SETKEY_ALREADY_EXIST : SETKEY_DOESNT_EXIST; setKey(c,c->db,key,val,setkey_flags); server.dirty++; notifyKeyspaceEvent(NOTIFY_STRING,"set",key,c->db->id); if (expire) { setExpire(c,c->db,key,milliseconds); /* Propagate as SET Key Value PXAT millisecond-timestamp if there is * EX/PX/EXAT flag. */ if (!(flags & OBJ_PXAT)) { robj *milliseconds_obj = createStringObjectFromLongLong(milliseconds); rewriteClientCommandVector(c, 5, shared.set, key, val, shared.pxat, milliseconds_obj); decrRefCount(milliseconds_obj); } notifyKeyspaceEvent(NOTIFY_GENERIC,"expire",key,c->db->id); } if (!(flags & OBJ_SET_GET)) { addReply(c, ok_reply ? ok_reply : shared.ok); } /* Propagate without the GET argument (Isn't needed if we had expire since in that case we completely re-written the command argv) */ if ((flags & OBJ_SET_GET) && !expire) { int argc = 0; int j; robj **argv = zmalloc((c->argc-1)*sizeof(robj*)); for (j=0; j < c->argc; j++) { char *a = c->argv[j]->ptr; /* Skip GET which may be repeated multiple times. */ if (j >= 3 && (a[0] == 'g' || a[0] == 'G') && (a[1] == 'e' || a[1] == 'E') && (a[2] == 't' || a[2] == 'T') && a[3] == '\0') continue; argv[argc++] = c->argv[j]; incrRefCount(c->argv[j]); } replaceClientCommandVector(c, argc, argv); }}看到代码间接吓坏了吧,不敢看了对吧?间接来看答案了对吧?其实这代码挺好懂的,没啥坑点与想的差不多。抓住 OBJ_SET_NX 示意用户输出的命令带有 NX 示意,其余一律不论。 ...

August 23, 2023 · 2 min · jiezi

关于redis:Redis-主从复制的机制浅析

前言明天持续来看看无关 Redis 的一个问题,主从复制。通常,对于大多数的场景来说,读比写更多,于是对于缓存的程度扩大,其中的一个形式 “主从复制” 就是一个常见的思路。有了主从复制,那么能够扩大出很多从节点来应答大量的读申请。那么问题来了 Redis 的主从复制是如何实现的呢? PS:本文仅关怀复制的机制,不关怀主节点下线从新选等等异常情况 前置常识你须要晓得 Redis 的长久化形式,RDB 和 AOFRedis 执行命令的基本思路审题题目自身不简单,提问者问这个问题的想法可能会有上面几个方面 理解 Redis 的主从复制机制的话,如果在理论应用过程中呈现问题就更容易排查在设计复制机制的时候须要留神和思考什么问题这样的设计是否能利用在别的场景中尝试思考假如你齐全没有看过 Redis 源码来思考这个问题,能够从上面几个角度去尝试剖析,并猜想答案。 首先,想到一个关系户,也就是咱们罕用的 Mysql,它也有主从复制,如果你理解 binlog 那么能够尝试从这里着手,尽管不同,但思路应该是差不多的。而后,简化问题,主从复制,无非就是将数据发送过来,对方承受保留不可能每次都复制的是全量数据,那么必定须要有机制去确保如何每次复制增量的数据复制的是什么? 复制的是数据自身?数据只有变动就将变动的 kv 间接扔给从节点?复制的是执行命令?将客户端执行的命令发送给子节点执行一次?解决有了下面的思考,其实理论也就有思路的。首先主从复制必定有两种状况,一种就是第一次复制,也就是要执行一次全量复制,将主节点的所有数据到复制到从节点下来;另一种就是增量复制,在数据同步之后后续的增量数据放弃同步。 全量同步长久化数据因为须要全量同步所有数据,咱们晓得 Redis 数据在内存外面,既然要发送,那势必须要先长久化一次。也就是先 SYNC 一遍,通过办法 startBgsaveForReplication 来实现的代码地位在:https://github.com/redis/redis/blob/14f802b360ef52141c83d477ac626cc6622e4eda/src/replication.c#L855这个问题不大, 就是保留一个 RDB 文件。 发送数据这个也很不难,就是将数据间接扔过来就好了。代码地位在:https://github.com/redis/redis/blob/14f802b360ef52141c83d477ac626cc6622e4eda/src/replication.c#L1402 增量同步后续的工作就是增量同步后续产生的数据了。在猜想时咱们想到有两种复制形式,一种是间接复制数据,这种形式复制 RDB 是可行,在全量同步的时候用这个必定更好,如果同步命令那么从节点还需再执行一次过于简单和麻烦,还耗时。而对于后续的增量同步来说,必定是同步命令来的更高效(不过还是得看理论)。 上面就是流传命令的办法: /* Propagate the specified command (in the context of the specified database id) * to AOF and Slaves. * * flags are an xor between: * + PROPAGATE_NONE (no propagation of command at all) * + PROPAGATE_AOF (propagate into the AOF file if is enabled) * + PROPAGATE_REPL (propagate into the replication link) * * This is an internal low-level function and should not be called! * * The API for propagating commands is alsoPropagate(). * * dbid value of -1 is saved to indicate that the called do not want * to replicate SELECT for this command (used for database neutral commands). */static void propagateNow(int dbid, robj **argv, int argc, int target) { if (!shouldPropagate(target)) return; /* This needs to be unreachable since the dataset should be fixed during * replica pause (otherwise data may be lost during a failover) */ serverAssert(!(isPausedActions(PAUSE_ACTION_REPLICA) && (!server.client_pause_in_transaction))); if (server.aof_state != AOF_OFF && target & PROPAGATE_AOF) feedAppendOnlyFile(dbid,argv,argc); if (target & PROPAGATE_REPL) replicationFeedSlaves(server.slaves,dbid,argv,argc);}这个办法就是将增量命令流传给 AOF 和 Slaves,AOF 就是长久化的另一种形式,而 Slaves 就是咱们须要同步的从节点了。具体 replicationFeedSlaves 办法就不具体看了。 ...

August 21, 2023 · 2 min · jiezi

关于redis:Redis

Redis概述REmote DIctionary Server(Redis) 是一个高性能的key-value存储系统。是内存存储的数据结构服务器,可用作数据库,高速缓存和音讯队列代理。 其中value能够是字符串(String), 哈希表(Hash), 列表(List), 汇合(Set), 有序汇合(SortedSet又称zset), 位图(bitmap), 基数统计(HyperLogLog)等数据类型。 Redis的所有操作都是原子性,单线程的。反对数据长久化数据类型String(字符串)string是redis最根本的类型,你能够了解成与Memcached截然不同的类型,一个key对应一个value。 string类型是二进制平安的。意思是redis的string能够蕴含任何数据。比方jpg图片或者序列化的对象 。 string类型是Redis最根本的数据类型,一个键最大能存储512MB。 实例redis 127.0.0.1:6379> SET name "redis.net.cn"OKredis 127.0.0.1:6379> GET name"redis.net.cn"在以上实例中咱们应用了 Redis 的 SET 和 GET 命令。键为 name,对应的值为redis.net.cn。 留神:一个键最大能存储512MB。 Hash(哈希)Redis hash 是一个键值对汇合。 Redis hash是一个string类型的field和value的映射表,hash特地适宜用于存储对象。 实例redis 127.0.0.1:6379> HMSET user:1 username redis.net.cn password redis.net.cn points 200OKredis 127.0.0.1:6379> HGETALL user:11) "username"2) "redis.net.cn"3) "password"4) "redis.net.cn"5) "points"6) "200"redis 127.0.0.1:6379>以上实例中 hash 数据类型存储了蕴含用户脚本信息的用户对象。 实例中咱们应用了 Redis HMSET, HEGTALL 命令,user:1 为键值。 每个 hash 能够存储 232 - 1 键值对(40多亿)。 ...

August 21, 2023 · 4 min · jiezi

关于redis:浅谈Redis-热点key问题-京东云技术团队

热key问题形容热key问题就是忽然有几十万的申请去拜访redis上的某个特定key,那么这样会造成流量过于集中,达到物理网卡下限,从而导致这台redis服务器间接宕机。 如何发现热点key凭借业务教训,进行预估哪些是热key。比方某些商品要做秒杀,则商品key就能够判断为热key,但并非所有业务都能预估出热key。在客户端进行收集。比方在redis客户端执行redis命令之前,退出一行代码进行命令数据收集,而后通过网络将收集的命令发送进来,毛病是对客户端代码有入侵。在Proxy层做收集,然而并非所有的redis集群都有proxy。用redis自带命令,monitor命令能够实时抓取出redis服务器接管到的命令,而后写代码统计出热key是啥,不过高并发条件下,有内存暴增的隐患,影响redis的性能。redis4.0.3提供了客户端热点key发现性能,如果key比拟多,执行比较慢。本人抓包评估,redis客户端应用TCP协定与服务端进行交互,通信协议采纳RESP,本人写程序监听端口,依照RESP协定规定解析数据进行剖析,不过开发成本较高,不易保护。如何解决热key减少二级缓存,发现热key当前,能够把热key数据加载到零碎JVM并设置适合的缓存过期工夫,针对热key的申请就会间接扩散到各业务服务器上,避免所有申请同时拜访同一台redis。备份热key。能够把热点key的数据备份到所有redis的集群节点中,能够通过在热点key前面拼接集群节点编号,而后将这些备份key扩散到所有集群节点中,客户端拜访热点key的时候也在热点key前面随机拼接集群节点编号,将热点key的申请扩散到不同集群节点上。作者:京东批发 曹志飞 起源:京东云开发社区 转载请注明起源

August 21, 2023 · 1 min · jiezi

关于redis:数据库和缓存一致性

数据库和缓存一致性个别分为两类,最终一致性和强一致性。 最终一致性名词解释:db更新后通过一段时间后要求能拜访到更新后的数据,是最终一致性。实用场景:对于实时性要求不是很高的业务。 计划一:读取:先从缓存读取,读取不到则读取db,而后写入缓存。 写入/更新/删除:先写db,再写入/更新/删除缓存。 可能遇到的问题:T0时刻申请A读取的时候缓存为空,从db读取数据,T1时刻申请B更新了DB和缓存,T2时刻更新了缓存,T3时刻申请A将老数据写入缓存,此时缓存数据为脏数据。 计划二读取:先从缓存读取,读取不到则读取db,而后写入缓存。 写入/更新/删除:先写入/更新/删除缓存,再更新db。 可能遇到的问题:T0时刻申请A读取的时候缓存为空,从db读取数据,T1时刻申请B删除了缓存,T2时刻申请A将老数据写入缓存,T3时刻申请B更新了缓存,此时缓存数据为脏数据。 对于计划一二,既然先更新缓存和数据库都不行,那是否给更新db和缓存的整体操作中加上锁呢,确实能够,然而这样读取也须要加锁,会影响性能,除非是一致性要求很高的场景,不然不倡议这样应用。 计划三:读取:从缓存读取,读取不到则返回空。写入/更新/删除:更新db再更新缓存,仍然会有不同申请造成的并发问题,除非把更新db和缓存的整个操作加锁,不过会有性能问题,而且若更新db胜利,更新缓存失败,会有脏数据。 计划四:读取:从缓存读取,读取不到则返回空。 写入/更新/删除:先更新db,异步音讯更新缓存,音讯里加上数据更新工夫作为版本号,消费者加锁生产音讯,缓存数据也存储工夫戳,依据工夫戳判断是否须要进行更新,若缓存为空则间接写入。 可能遇到的问题:1.若先更新再删除,消费者先生产到了删除申请,再生产到更新申请,则缓存为脏数据。2.工夫戳精度不够示意版本号。3.更新db胜利,发送音讯失败。 解决方案:1.加上isDel字段,删除操作视为更新操作,只是将isDel字段置为true。待缓存主动过期删除。2.须要依据业务场景选取字段,或者在db加上版本号。3.发送音讯失败记录音讯到本地音讯表,定时工作轮询重发。 强一致性:名词解释:对于关系型数据库,要求更新过的数据能被后续的拜访都能看到,是强一致性。实用场景:对于实时性要求比拟高的业务。 计划一:读取:先从缓存读取,读取不到则读取db,而后写入缓存。写入/更新/删除:先写入/更新/db,再删除缓存。可能遇到的问题: 1.如图,查问操作在db更新后查问的还是老数据。 2.和最终一致性的计划一一样,查问操作查问数据时缓存不存在,从db写入老缓存缓存,导致缓存存在脏数据。 计划二:新增/批改/删除: 将更新db和删除缓存整体操作加锁lock1。查问:查问时先判断锁lock1是否存在,若锁存在则读取db并返回数据,锁不存在间接查问缓存,若缓存存在则间接返回后果,缓存不存在同样加锁lock1,执行查问db和更新缓存操作,这样能够保障强一致性。

August 21, 2023 · 1 min · jiezi

关于redis:redis-存储结构原理-2

我正在参加掘金创作者训练营第4期,点击理解流动详情,一起学习吧! 咱们接着上一部分来进行分享,咱们能够在如下地址下载 redis 的源码: https://redis.io/download 此处我下载的是 redis-6.2.5 版本的,xdm 能够间接下载上图中的 redis-6.2.6 版本, redis 中 hash 表的数据结构redis hash 表的数据结构定义在: redis-6.2.5\src\dict.h 哈希表的构造,每一个字典都有两个实现从旧表到新表的增量重哈希 typedef struct dictht { dictEntry **table; unsigned long size; unsigned long sizemask; unsigned long used;} dictht;table: table 是一个二级指针,对应这一个数组,数组中的每个元素都是指向了一个 dictEntry 构造体指针的,dictEntry 具体的数据结构是保留一个键值对 具体的 dictEntry 数据结构是这样的: size: size 属性是记录了整个 hash 表的大小,也能够了解为上述 table 数组的大小 sizemask: sizemask 属性,和具体的 hash 值来一起决定键要放在 table 数组的哪个地位 sizemask 的值,总是会比 size 小 1 ,咱们能够来演示一下 应用取余的形式,实际上是很低效的,咱们的计算机是不会做乘除法的,同样都是用加减法来进行解决的,为了高效解决,咱们能够应用二进制的形式 应用二进制的形式,就会用到该字段 sizemask ,次要是用来 和 具体的 hash 值做按位与操作 ...

August 19, 2023 · 2 min · jiezi

关于redis:redis-存储结构原理-1

对于 redis 置信大家都不生疏了,之前有从 0 -1 分享过 redis 的根本应用形式,用起来倒是都没有啥问题了,不过还是那句话,会利用之后,咱们必须要究其原理,知其然知其所以然 明天咱们来分享一下对于 redis 的存储构造的原理 redis 的存储构造的原理咱们都晓得 redis 是一个 K-V 内存数据库,相似于 memcache ,那么个别存储这种 K-V 键值对的数据结构是什么呢? 是 红黑树 , 那么咱们对于红黑树的增删改查的工夫复杂度是 O(logN),对于红黑树而言,只有内存足够,那么这个 N 是能够无限大的 这对于 redis 来说是没有方法满足 redis 的需要,那么咱们是否能够将复杂度升高到 O(1) 呢,感兴趣的,咱们能够来摸索一下? hash 表能满足 O(1) 工夫复杂度的数据结构有啥呢?咱们是不是能够想到 hash 表 具体 hash 表是怎么的一种构造,后面有文章曾经分享过一些,redis 基础性的数据结构能够查看历史文章:【Redis 系列】redis 学习四,set 汇合,hash 哈希,zset 有序汇合初步 redis 的 key 反对哪些类型?redis 反对的 key 有: longdoubleintstring - 可见的字符串和二进制字符串,key 都是 string 类型实际上最终到 redis 解决的时候,上述类型,都是对应依照 sring 类型进行存储的 这个 key 是有法则的 key,并且是强随机性的 ...

August 18, 2023 · 1 min · jiezi

关于redis:Redis双向数据同步

简述本文次要介绍 CloudCanal 如何做 Redis 双向同步并防循环,计划特点包含: 反对 Redis 单节点、主备、分片集群反对数据初始化防循环反对防循环辅助指令超时或永不超时设置技术点防循环事件CloudCanal Redis 双向同步采纳辅助指令进行循环断定,当收到失常指令,计算其hash值,构建辅助指令key,反向查问辅助指令是否存在,如果存在则为循环,过滤即可。 对于辅助指令对端写入以及源端查问,CloudCanal 进行了批量和多线程优化,同步性能失去无效晋升。 防循环兼容 分片集群、单节点、主备节点任意组合之间的数据迁徙同步。 单任务多节点事件订阅Redis 集群广泛具备多个节点,为了简化工作配置,CloudCanal 采纳单任务多 Redis 节点订阅形式,实现数据迁徙和同步,整个过程更加便当牢靠。 操作示例筹备 CloudCanal下载安装 CloudCanal 公有部署版本增加数据源本案例采纳 阿里云云市场购买的 2 个 Redis 集群, 均位于杭州区域登录 CloudCanal 平台 ,数据源治理 -> 增加数据源 , 增加 2 个 Redis 集群倡议对数据源进行形容批改,避免配置正反链路时,辨认错数据库 创立正向同步工作工作治理->新建工作双向同步中,正向工作个别指源端有数据,指标端无数据的链路,波及对端数据初始化第一个页面,抉择源端和指标端数据源和相干信息,点击下一步 第二个页面 抉择 数据同步,并且勾选 全量数据初始化置灰主动启动,以便创立工作后设置双向同步参数点击 下一步 第三个页面,点击确认创立工作详情 -> 参数设置 设置源端数据源配置 deCycle 参数为 true设置源端数据源配置 deCycleEventExpireSec 参数为 1200 秒 (防循环辅助指令超时事件,超过后防循环即有效)失效配置并启动 期待正向同步工作初始化完数据并失常同步 此处不倡议在正向同步工作创立后立刻创立反向工作,波及到 repl-backlog-size 设置有余时,反向工作启动强制走 FULL SYNC 导致新数据被老数据笼罩问题 创立反向同步工作工作治理->新建工作第一个页面,抉择源端和指标端抉择数据源(请和正向工作所选数据源对调)和相干信息,点击下一步 ...

August 18, 2023 · 1 min · jiezi

关于redis:深入解析Redis的LRU与LFU算法实现

作者:vivo 互联网服务器团队 - Luo Jianxin重点介绍了Redis的LRU与LFU算法实现,并剖析总结了两种算法的实现成果以及存在的问题。 一、前言Redis是一款基于内存的高性能NoSQL数据库,数据都缓存在内存里, 这使得Redis能够每秒轻松地解决数万的读写申请。 绝对于磁盘的容量,内存的空间个别都是无限的,为了防止Redis耗尽宿主机的内存空间,Redis外部实现了一套简单的缓存淘汰策略来管控内存使用量。 Redis 4.0版本开始就提供了8种内存淘汰策略,其中4种都是基于LRU或LFU算法实现的,本文就这两种算法的Redis实现进行了具体的介绍,并论述其优劣个性。 二、Redis的LRU实现在介绍Redis LRU算法实现之前,咱们先简略介绍一下原生的LRU算法。 2.1 LRU算法原理LRU(The Least Recently Used)是最经典的一款缓存淘汰算法,其原理是 :如果一个数据在最近一段时间没有被拜访到,那么在未来它被拜访的可能性也很低,当数据所占据的空间达到肯定阈值时,这个起码被拜访的数据将被淘汰掉。 现在,LRU算法广泛应用在诸多零碎内,例如Linux内核页表替换,MySQL Buffer Pool缓存页替换,以及Redis数据淘汰策略。 以下是一个LRU算法示意图: 向一个缓存空间顺次插入三个数据A/B/C,填满了缓存空间;读取数据A一次,依照拜访工夫排序,数据A被挪动到缓存头部;插入数据D的时候,因为缓存空间已满,触发了LRU的淘汰策略,数据B被移出,缓存空间只保留了D/A/C。一般而言,LRU算法的数据结构不会如示意图那样,仅应用简略的队列或链表去缓存数据,而是会采纳Hash表 + 双向链表的构造,利用Hash表确保数据查找的工夫复杂度是O(1),双向链表又能够使数据插入/删除等操作也是O(1)。 如果你很相熟Redis的数据类型,你会发现这个LRU的数据结构与ZSET类型OBJ\_ENCODING\_SKIPLIST编码构造类似,只是LRU数据排序形式更简略一些。 2.2 Redis LRU算法实现依照官网文档的介绍,Redis所实现的是一种近似的LRU算法,每次随机选取一批数据进行LRU淘汰,而不是针对所有的数据,通过就义局部准确率来进步LRU算法的执行效率。 Redis外部只应用Hash表缓存了数据,并没有创立一个专门针对LRU算法的双向链表,之所以这样解决也是因为以下几个起因: 筛选规定,Redis是随机抽取一批数据去依照淘汰策略排序,不再须要对所有数据排序;性能问题,每次数据拜访都可能波及数据移位,性能会有少许损失;内存问题,Redis对内存的应用一贯很“抠门”,数据结构都很精简,尽量不应用简单的数据结构治理数据;策略配置,如果线上Redis实例动静批改淘汰策略会触发全副数据的结构性扭转,这个Redis零碎无奈接受的。redisObject是Redis外围的底层数据结构,成员变量lru字段用于记录了此key最近一次被拜访的LRU时钟(server.lruclock),每次Key被拜访或批改都会引起lru字段的更新。 #define LRU_BITS 24 typedef struct redisObject { unsigned type:4; unsigned encoding:4; unsigned lru:LRU_BITS; /* LRU time (relative to global lru_clock) or * LFU data (least significant 8 bits frequency * and most significant 16 bits access time). */ int refcount; void *ptr;} robj;默认的LRU时钟单位是秒,能够批改LRU\_CLOCK\_RESOLUTION宏来扭转单位,LRU时钟更新的频率也和server.hz参数无关。 ...

July 6, 2023 · 2 min · jiezi

关于redis:redis-主从-哨兵-集群-の安装

0.装置vmware15.x+centos7.x+redis相干配置哨兵日志解读 0.1 下载redis源码包https://redis.io/0.2下载对应版本redis-5.0.10.tar.gz0.3上传并编译装置# 装置gcc- yum install -y gcc# 进入解压缩目录执行如下命令- make MALLOC=libc# 编译实现后执行如下命令- make install PREFIX=/usr/redis# 进入/usr/redis目录启动redis服务 - ./redis-server 1.搭建redis主从主从复制架构仅仅用来解决数据的冗余备份,从节点仅仅用来同步数据无奈解决: 1.master节点呈现故障的主动故障转移 1.1 筹备三台机器并批改配置master port 6379 bind 0.0.0.0 protected-mode no daemonize yesslave1 port 6380 bind 0.0.0.0 slaveof masterip masterport masterauth masterPassword # 如果master没有配置明码能够不填 pidfile "/var/run/redis_6381.pid" # 同一台机器上测试 这个要写成不同的文件 protected-mode no daemonize yesslave2 port 6381 bind 0.0.0.0 slaveof masterip masterport masterauth masterPassword # 如果master没有配置明码能够不填 pidfile "/var/run/redis_6381.pid" # 同一台机器上测试 这个要写成不同的文件 protected-mode no daemonize yes1.2 启动3台机器进行测试cd /usr/redis/bin./redis-server /root/master/redis.conf./redis-server /root/slave1/redis.conf./redis-server /root/slave2/redis.conf2.搭建redis哨兵     Sentinel(哨兵)是Redis 的高可用性解决方案:由一个或多个Sentinel 实例 组成的Sentinel 零碎能够监督任意多个主服务器,以及这些主服务器属下的所有从服务器,并在被监督的主服务器进入下线状态时,主动将下线主服务器属下的某个从服务器降级为新的主服务器。简略的说哨兵就是带有主动故障转移性能的主从架构。 ...

July 5, 2023 · 2 min · jiezi

关于redis:Redis-Issue-分析流数据读写导致的死锁问题1

Redis 我的项目中,一个名为 "[BUG] Deadlock with streams on redis 7.2" 的 issue 12290 吸引了我的留神。这个 bug 中,redis 服务器在解决特定的客户端申请时陷入了死循环,这个景象在 redis 这样的高性能、高可靠性的数据库系统中是极为常见的。 这个 Issue 不仅仅是一个一般的 bug 报告,它实际上是一次深刻摸索 Redis 外部机制的学习过程。从问题的发现,到复现步骤的详细描述,再到问题的深入分析,最初到解决方案的提出,每一步都充斥了挑战和发现。无论你是 Redis 的使用者,还是对数据库外部机制感兴趣的开发者,我置信你都能从这个 issue 中取得有价值的启发。 在开始钻研这个 bug 之前,咱们先简略理解下这里的背景常识:redis 的流数据类型。 Redis streams 介绍为了反对更弱小和灵便的流解决能力,Redis 在 5.0 反对了流数据类型, 蕴含 XADD, XREAD 和 XREADGROUP。 XADD 命令容许用户向 Redis 流中增加新的音讯。每个音讯都有一个惟一的 ID 和一组字段-值对。这种数据结构非常适合示意工夫序列数据,例如日志、传感器读数等。通过 XADD,用户能够将这些数据存储在 Redis 中,而后应用其余命令进行查问和解决。XREAD 命令用于从一个或多个流中读取数据。你能够指定从每个流的哪个地位开始读取,以及最多读取多少条音讯。这个命令适宜于简略的流解决场景,例如,你只须要从流中读取数据,而不须要跟踪读取的进度。XREADGROUP 命令是 Redis 消费者组性能的一部分。消费者组容许多个消费者共享对同一个流的拜访,同时还能跟踪每个消费者的进度。这种性能对于构建可扩大的流解决零碎十分有用。例如,你能够有多个消费者同时读取同一个流,每个消费者解决流中的一部分音讯。通过 XREADGROUP,每个消费者都能够记住它曾经读取到哪里,从而在下次读取时从正确的地位开始。咱们能够用 XREADGROUP 命令从一个特定的流中读取数据,如果这个流以后没有新的数据,那么收回 XREADGROUP 命令的客户端就会进入一种阻塞期待状态,直到流中有新的数据为止。同样的,咱们能够用 XADD 命令向流中增加新的数据,当新的数据被增加到流中后,所有在这个流上"期待"的客户端就会被唤醒,而后开始解决新的数据。 留神这里的"期待"并不是咱们通常了解的那种让整个服务器停下来的阻塞。实际上,只有收回 XREADGROUP 命令的那个客户端会进入"期待"状态,而 Redis 服务器还能够持续解决其余客户端的申请。这就意味着,即便有一些客户端在期待新的数据,Redis 服务器也能放弃高效的运行。 ...

July 5, 2023 · 2 min · jiezi

关于redis:AOF和RDB

背景咱们都晓得,Redis是一个内存数据库,数据保留在内存中,访问速度是相当快的。然而内存中的数据,服务器每次重启之后就会失落,redis是如何做到长久化的呢?redis长久化设计有哪些奇妙之处呢?目前,Redis 的长久化次要有两大机制,即 AOF(Append Only File)日志和 RDB 快照。 AOF格局咱们以 Redis 收到“set testkey testvalue”命令后记录的日志为例,看看 AOF 日志的内容。其中,“*3”示意以后命令有三个局部,每局部都是由“$+数字”结尾,前面紧跟着具体的命令、键或值。这里,“数字”示意这部分中的命令、键或值一共有多少字节。例如,“$3 set”示意这部分有 3 个字节,也就是“set”命令。 写入形式AOF 里记录的是 Redis 收到的每一条命令,这些命令是以文本模式保留的,也就是说每一条命令都会生成一条AOF日志。那么如果说这条命令是语法有误的命令呢?也会记录吗?Redis 是先执行命令,把数据写入内存,而后才记录日志,如下图所示:Redis 应用写后日志这一形式的一大益处是,能够避免出现记录谬误命令的状况 这样的AOF还是有危险的,执行完命令后宕机了,AOF失落,如果redis作为数据库就会有数据失落的危险 三种回写策略Always:同步写回:每个命令执行完,立马同步到磁盘Everysec:缓冲区每秒写回磁盘No:操作系统管制AOF重写AOF重写后果其实就是 对旧日志文件中的多条命令,在重写后的新日志中变成了一条命令。 重写会影响主线程?AOF日志是由主线程写的,然而AOF重写的 过程是由后台子过程 bgrewriteaof 来实现的,这也是为了防止阻塞主线程,然而fork子过程有可能会使主线程阻塞 Redis主线程fork子过程时,内核须要创立用于治理子过程的相干数据结构,子过程要拷贝父过程的页表,这个过程耗时与redis实例的内存大小无关子过程会和主线程共享内存。当主线程收到新写或批改的操作时,主线程会申请新的内存空间,用来保留新写或批改的数据,如果操作的是bigkey,主线程会因为申请大空间而面临阻塞危险RDBRDB是redis内存快照两个命令来生成 RDB 文件:save、bgsave save:在主线程中执行,会导致阻塞bgsave:创立一个子过程,专门用于写入 RDB 文件,防止了主线程的阻塞写时复制bgsave子过程是由主线程fork生成的,共享主线程的所有内存数据。bgsave子过程运行后,开始读取主线程的内存数据,并把它们写入RDB文件采纳写时复制策略,主线程更新数据会拷贝数据正本,在正本批改数据 fork期间会阻塞父过程?fork实现之前,会阻塞父过程,次要是父过程须要拷贝过程中的内存页表给子过程,每个过程都要有本人的内存页表拷贝内存页表也须要破费工夫,过程占用的内存越大,拷贝工夫越久个别采纳混合模式:快照+AOF模式

July 4, 2023 · 1 min · jiezi

关于redis:Redis超时阻塞问题排查

原理剖析从原理层面,咱们能够将此类问题分为内因和外因 内因长久化带来的阻塞问题(AOF重写和生成RDB)redis在做AOF或生成RDB的时候,须要fork操作创立子过程,fork过程,尽管不会间接拷贝父过程的物理内存空间,但回复制父过程的内存页表.从教训来说,如果redis有10G内存,那么复制大略20MB的内存页表 CPU饱和如果redis的cpu跑到近100%,是比拟危险的,能够应用top命令查看,或者应用redis-cli --stat命令查看 慢查问和大key应用keys* 或者hgetall等命令,工夫复杂度是O(n)大key的读写和写入须要更大内存空间,容易阻塞 外因应用SWAP内存替换如果操作系统的内存不够,将一部分内存数据换出到磁盘,那么Redis的拜访无疑会受到影响,因为内存和磁盘的访问速度,差了好几个数量级。因而,应用Redis的机器上,尽量敞开swap,并设置Redis的maxmemory,防止Redis内存的无限度上涨。 网络问题这个就十分常见了,网络抖动,网络闪断,网络提早,网卡软中断等。这里给出查看网络延时的方法,通常状况下,能够应用redis-cli --latency命令来查看Redis的提早状况。

July 4, 2023 · 1 min · jiezi

关于redis:Redis分布式锁实现方式

为了避免分布式系统中的多个过程之间互相烦扰,须要一种分布式协调技术来对这些过程进行调度。而这个分布式协调技术的外围就是来实现这个分布式锁。Redis加锁原理很简略,set 一个 锁-key,如果胜利则阐明加锁胜利,反之则失败。为了确保分布式锁可用,咱们至多要确保锁的实现同时满足以下几个条件: 互斥性。在任意时刻,只有一个客户端能持有锁。不会产生死锁。即便有一个客户端在持有锁的期间解体而没有被动解锁,也能保障后续其余客户端能加锁。解铃还须系铃人。加锁和解锁必须是同一个客户端,客户端本人不能把他人加的锁给解了。基于以上条件,采纳set扩大参数,保障原子性操作:SET lock-key "lock-client" EX 10086 NXlock-key "lock-client" 指定 加锁client,解锁时用于判断。EX 10010 指定过期工夫NX 只在键不存在时,才对键进行设置操作。成果等同于SETNX 命令。 只不过晚期版本redis不反对set的扩大参数,这就须要用到 lua 脚本了。加锁能够在高版本借助set命令实现原子操作,但解锁就不能够了,仍然得用到lua脚本。 Redis+LuaRedis在2.6版本推出了 lua 脚本性能,容许开发者应用Lua语言编写脚本传到Redis中执行。应用脚本的益处如下: 缩小网络开销:能够将多个申请通过脚本的模式一次发送,缩小网络时延。原子操作:Redis会将整个脚本作为一个整体执行,两头不会被其余申请插入。因而在脚本运行过程中无需放心会呈现竞态条件,无需应用事务。复用:客户端发送的脚本会永恒存在redis中,这样其余客户端能够复用这一脚本,而不须要应用代码实现雷同的逻辑。Redis 解锁须要在取得 lock-key 后判断加锁对象是否为以后client,是,则解锁。Lua 脚本如下:if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end执行形式:eval;eval 参数列表:eval lua-script key-num [key1 key2 key3 ....] [value1 value2 value3 ....],参数解析: eval, 代表执行Lua脚本的命令;lua-script, Lua语言脚本;key-num, 示意参数key的个数,须要留神的是,LUA的key下标从1开始,如果没有key参数,则写0;[key1 key2 key3…], 参数字段名列表(cmd模式以空格宰割),总数量等于下面的 key-num 个数;[value1 value2 value3 …], 参数字段对应的值(cmd模式以空格宰割),总数量等于下面的 key-num 个数;eval执行示例:eval "redis.call('set',KEYS[1],ARGV[1])" 1 lua-key lua-val; ...

July 2, 2023 · 1 min · jiezi

关于redis:使用Redis是并发安全的吗

大家都分明,Redis 是一个开源的高性能键值对存储系统,被开发者广泛应用于缓存、音讯队列、排行榜、计数器等场景。因为其高效的读写性能和丰盛的数据类型,Redis 受到了越来越多开发者的青眼。然而,在并发操作下,Redis 是否可能保证数据的一致性和安全性呢?接下来小岳将跟大家一起来探讨 Redis 并发安全性的问题。 一. Redis 的并发安全性 在 Redis 中,每个客户端都会通过一个独立的连贯与 Redis 服务器进行通信,每个命令的执行都是原子性的。在单线程的 Redis 服务器中,一个客户端的申请会顺次被执行,不会被其余客户端的申请打断,因而不须要思考并发安全性的问题。然而,在多线程或多过程环境中,多个客户端的申请会同时达到 Redis 服务器,这时就须要思考并发安全性的问题了。Redis 提供了一些并发管制的机制,能够保障并发操作的安全性。其中最罕用的机制是事务和乐观锁, 接下来就让咱们一起来看看吧! 1.事务 Redis的事务是一组命令的汇合,这些命令会被打包成一个事务块(transaction block),而后一次性执行。在执行事务期间,Redis 不会中断执行事务的客户端,也不会执行其余客户端的命令,这保障了事务的原子性。如果在执行事务的过程中呈现谬误,Redis 会回滚整个事务,保证数据的一致性。 事务的应用形式很简略,只须要应用 MULTI 命令开启事务,而后将须要执行的命令增加到事务块中,最初应用 EXEC 命令提交事务即可。上面是一个简略的事务示例: Jedis jedis = new Jedis("localhost", 6379);Transaction tx = jedis.multi();tx.set("key1", "value1");tx.set("key2", "value2");tx.exec();在下面的示例中,咱们应用 Jedis 客户端开启了一个事务,将两个 SET 命令增加到事务块中,而后应用 EXEC 命令提交事务。如果在执行事务的过程中呈现谬误,能够通过调用tx.discard()办法回滚事务。 事务尽管能够保障并发操作的安全性,然而也存在一些限度。首先,事务只能保障事务块内的命令是原子性的,事务块之外的命令不受事务的影响。其次,Redis 的事务是乐观锁机制,即在提交事务时才会查看事务块内的命令是否抵触,因而如果在提交事务前有其余客户端批改了事务块中的数据,就会导致事务提交失败。 2.乐观锁 在多线程并发操作中,为了保证数据的一致性和可靠性,咱们须要应用锁机制来协调线程之间的拜访。传统的加锁机制是乐观锁,它会在每次拜访数据时都加锁,导致线程之间的竞争和期待。乐观锁则是一种更为轻量级的锁机制,它假设在并发操作中,数据的抵触很少产生,因而不须要每次都加锁,而是在更新数据时检查数据版本号或者工夫戳,如果版本号或工夫戳不统一,则阐明其余线程曾经更新了数据,此时须要回滚操作。 在Java中,乐观锁的实现形式有两种:版本号机制和工夫戳机制。 上面别离介绍这两种机制的实现形式和代码案例。 2.1 版本号机制的实现形式 版本号机制是指在数据表中新增一个版本号字段,每次更新数据时,将版本号加1,并且在更新数据时判断版本号是否统一。如果版本号不统一,则阐明其余线程曾经更新了数据,此时须要回滚操作。上面是版本号机制的代码实现: public void updateWithVersion(int id, String newName, long oldVersion) { String sql = "update user set name = ?, version = ? where id = ? and version = ?"; try { Connection conn = getConnection(); // 获取数据库连贯 PreparedStatement ps = conn.prepareStatement(sql);        ps.setString(1, newName);        ps.setLong(2, oldVersion + 1); // 版本号加1        ps.setInt(3, id);        ps.setLong(4, oldVersion); int i = ps.executeUpdate(); // 执行更新操作 if (i == 0) { System.out.println("更新失败"); } else { System.out.println("更新胜利"); } } catch (SQLException e) {        e.printStackTrace(); }}2.2 工夫戳机制的实现形式 工夫戳机制是指在数据表中新增一个工夫戳字段,每次更新数据时,将工夫戳更新为以后工夫,并且在更新数据时判断工夫戳是否统一。如果工夫戳不统一,则阐明其余线程曾经更新了数据,此时须要回滚操作。上面是工夫戳机制的代码实现: public void updateWithTimestamp(int id, String newName, Timestamp oldTimestamp) { String sql = "update user set name = ?, update_time = ? where id = ? and update_time = ?"; try { Connection conn = getConnection(); // 获取数据库连贯 PreparedStatement ps = conn.prepareStatement(sql);        ps.setString(1, newName);        ps.setTimestamp(2, new Timestamp(System.currentTimeMillis())); // 更新工夫戳为以后工夫        ps.setInt(3, id);        ps.setTimestamp(4, oldTimestamp); int i = ps.executeUpdate(); // 执行更新操作 if (i == 0) { System.out.println("更新失败"); } else { System.out.println("更新胜利"); } } catch (SQLException e) {        e.printStackTrace(); }}通过以上两种形式的实现,咱们就能够实现Java乐观锁的机制,并且在多线程并发操作中保证数据的一致性和可靠性。 ...

June 30, 2023 · 1 min · jiezi

关于redis:Redis数据结构一之对象的介绍及各版本对应实现

本文首发于公众号:Hunter后端原文链接:Redis数据结构一之对象的介绍及各版本对应实现本篇笔记开始介绍 Redis 数据结构的底层实现。 当咱们被问到 Redis 中有什么数据结构,或者说数据类型,咱们可能会说有字符串、列表、哈希、汇合、有序汇合。 其实这几种数据类型在 Redis 中都由对象形成,而且是两个对象,一个键对象,一个值对象。 在这些数据类型中,它们的键都是字符串对象,而值能够是后面说的字符串对象、列表对象、哈希对象、汇合对象、有序汇合对象中的一种,这个取决于键值对的数据类型。 而在 Redis 中,这些对象都有其更底层的实现形式,也就是说这一篇笔记咱们要介绍的,更底层的数据结构,而且不同的 Redis 版本有不一样的数据结构,最根底的数据结构包含简略动静字符串、字典、跳跃表、整数汇合等, 接下来咱们先介绍一下 Redis 中对象的形成,而后介绍一下不同 Redis 版本中每个对象所应用的的底层数据结构,之后再一一介绍这些数据结构的实现原理,以下是本篇笔记的目录: Redis 对象的介绍不同版本的 Redis 对象的数据结构留神:本篇文章的主体框架内容是基于书籍《Redis设计与实现》进行形容的,局部过期内容都基于网上查问的相应材料与最新版本进行了对齐,如有其余疏漏,还望斧正。 1、Redis 对象的介绍举一个例子,当咱们设置一个字符串类型的数据: set msg "hello world"这样,咱们就创立了两个对象,且两个都是字符串对象,因为键值对的 key 和 value 都是字符串。 如果咱们创立了一个列表数据,那么 key 是字符串对象,而值 value 是列表对象。 在 Redis 中,每个对象都由一个 redisObject 构造来示意: typedef struct redisObject{ //类型 unsigned type:4; //编码 unsigned encoding:4; //指向底层实现数据结构的指针 void *ptr //...} robj;type 在下面的构造中,type 指的是这个对象的类型,比方咱们创立了一个列表数据,那么这个数据的 key 就是一个字符串对象,由这个构造里的 type 来指定,这个数据的 value 就是一个列表对象,也是由 type 来进行指定辨别。 然而,当咱们想要晓得一条数据的数据类型是字符串、列表、哈希、汇合、有序汇合的哪一种时,咱们经常是须要晓得的这条数据的 value 的类型,个别也是指的 value 的类型,因为数据的 key 的类型总是字符串对象。 ...

June 21, 2023 · 1 min · jiezi

关于redis:分布式锁的实现

因为 setnx 这个指令自身无奈设置超时工夫,所以个别会采纳两种方法来做这件事: 1、采纳 lua 脚本,在应用 setnx 指令之后,再应用 expire 命令去给 key 设置过期工夫。 if redis.call("SETNX", "lock", "true") == 1 then local expireResult = redis.call("expire", "lock", "10") if expireResult == 1 then return "success" else return "expire failed" endelse return "setnx not null"end2、间接应用 set(key,value,NX,PX,timeout) 指令,同时设置锁和超时工夫。 redis.call("SET", "lock", "true", "NX", "PX", "10000")以上两种办法,应用哪种形式都能够。 开释锁的脚本两种形式都一样,间接调用 Redis 的 del 指令即可。

June 17, 2023 · 1 min · jiezi

关于redis:Redis基础命令汇总看这篇就够了

本文首发于公众号:Hunter后端原文链:Redis根底命令汇总,看这篇就够了本篇笔记将汇总 Redis 根底命令,包含几个罕用的通用命令,和各个类型的数据的操作,包含字符串、哈希、列表、汇合、有序汇合等在内的基本操作。 以下是本篇笔记目录: 通用命令字符串命令哈希命令列表命令汇合命令有序汇合命令1、通用命令keys *返回所有 key,能够应用通配符来查问。 # 查看所有 key keys *# 查看以 hel 结尾的 keykeys hel*# 查看 ph + 一个字符keys ph?留神:个别不要应用 keys 这个操作,Redis 是单线程,执行之后如果耗时过久会造成阻塞。 dbsize统计以后 db key 的总数: select 1dbsizeexists key查看某个 key 是否存在,存在则返回 1,不存在返回 0 exists key# 1del key [key ...]删除一个或多个 key: # 删除 keydel key1# 删除 key1、key2del key1 key2胜利删除 n 个 key,返回整数 n expire key n给 key 设置 n 秒后过期 假如给 key 为 hello 的数据设置 3 秒后过期: expire hello 3三秒后,咱们尝试获取 hello 数据,就会发现返回空了。 ...

June 5, 2023 · 4 min · jiezi

关于redis:图解Redis和Zookeeper分布式锁-京东云技术团队

1.基于Redis实现分布式锁 Redis分布式锁原理如上图所示,当有多个Set命令发送到Redis时,Redis会串行解决,最终只有一个Set命令执行胜利,从而只有一个线程加锁胜利 2:SetNx命令加锁利用_Redis的setNx_命令在Redis数据库中创立一个<Key,Value>记录,_这条命令只有当Redis中没有这个Key的时候才执行胜利,当曾经有这个Key的时候会返回失败_ 利用如上的_setNx_命令便能够简略的实现加锁性能,当多个线程去执行这个加锁命令时,_只有一个线程执行胜利,而后执行业务逻辑,其余线程加锁失败返回或者重试_ 3:死锁问题下面的_setNx_命令实现了根本的加锁性能,但存在一个致命的问题是,_当程序在执行业务代码解体时,无奈再执行到上面的解锁指令,从而导致呈现死锁问题_ 为了解决死锁问题,这里就须要_引入过期工夫的概念_,过期工夫是给以后这个_key设置肯定的存活工夫,当存活工夫到期后,Redis就会主动删除这个过期的Key_,从而使得程序在解体时也能_到期主动开释锁_ 如上图所示,应用Redis的_expire命令_来为锁设置过期工夫,从而实现到期主动解锁的性能,但这里依然还存在一个问题就是_加锁与给锁设置过期工夫这两个操作命令并不是原子命令_ 思考上面这种状况: 当程序在加锁实现后,在设置过期工夫前解体,这时依然会造成锁无奈主动开释,从而产生死锁景象 4:应用原子命令针对下面加锁与设置过期工夫不是原子命令的问题,Redis为咱们提供了一个原子命令如下: 通过_SetNx(key,value,timeOut)_这个_联合加锁与设置过期工夫的原子命令_就能残缺的实现基于Redis的分布式锁的加锁步骤 5:解锁原理解锁原理就是基于Redis的_del删除key指令_ 6:谬误删除锁问题下面间接删除key来解锁形式会存在一个问题,思考上面这种状况: (1)线程1执行业务工夫过长导致本人加的锁过期 (2)这时线程2进来加锁胜利 (3)而后线程1业务逻辑执行结束开始执行del key命令 (4)_这时就会呈现谬误删除线程2加的锁_ (5)谬误删除线程2的锁后,线程3又能够加锁胜利,导致有两个线程执行业务代码 7:退出锁标识为了解决这种谬误删除其余线程的锁的问题,在这里须要对加锁命令进行革新,_须要在value字段里退出以后线程的id_,在这里能够应用uuid来实现。线程在删除锁的时候,用本人的uuid与Redis中锁的uuid进行比拟,_如果是本人的锁就进行删除,不是则不删除_ 如上图所示,加锁时_在value字段中存入以后线程的id,而后在解锁时通过比拟以后的锁是否是本人的来判断是否加锁胜利,_这样就解决了谬误删除他人的锁的问题,_但这里同样存在原子命令问题,比拟并删除_这个操作并不是原子命令,思考上面这种状况 (1)线程1获取uuid并判断锁是本人的 (2)_筹备解锁时呈现GC或者其余起因导致程序卡顿无奈立刻执行Del命令_,导致线程1的锁过期 (3)线程2就会在这个时候加锁胜利 (4)线程1卡顿完结继续执行解锁指令,就会谬误删除线程2的锁 这个问题呈现的根本原因还是_比拟并删除这两个操作并不是原子命令,只有两个命令被打断就有可能呈现并发问题,如果将两个命令变为原子命令就能解决这个问题_ 8:引入lua脚本实现原子删除操作_lua脚本_是一个十分轻量级的脚本语言,Redis底层天生反对lua脚本的执行,一个lua脚本中能够蕴含多条Redis命令,Redis会将整个lua脚本当作原子操作来执行,从而实现聚合多条Redis指令的原子操作,其原理如下图所示: 这里在解锁时,应用lua脚本将_比拟并删除_操作变为原子操作 //lua脚本如下luaScript = " if redis.call('get',key) == value then return redis.call('del',key) else return 0 end;"如下面的lua脚本所示,Redis会将整个lua脚本当作一个独自的命令执行,从而实现多个命令的原子操作,防止多线程竞争问题,最终联合lua脚本实现了一个残缺的分布式的加锁和解锁过程,伪代码如下: uuid = getUUID();//加锁lockResut = redisClient.setNx(key,uuid,timeOut);if(!lockResult){ return;}try{ //执行业务逻辑}finally{ //解锁 redisClient.eval(delLuaScript,keys,values)}//解锁的lua脚本delLuaScript = " if redis.call('get',key) == value then return redis.call('del',key) else return 0 end;"到此,咱们最终实现了一个加锁和解锁性能较为残缺的redis分布式锁了,当然作为一个锁来说,还有一些其余的性能须要进一步欠缺,例如_思考锁生效问题,可重入问题等_ ...

May 31, 2023 · 2 min · jiezi

关于redis:终于卷完了Redis-打怪升级进阶成神之路2023-最新版

Nosql 数据库介绍是一种非关系型数据库服务,它能解决惯例数据库的并发能力,比方传统的数据库的IO与性能的瓶颈,同样它是关系型数据库的一个补充,有着比拟好的高效率与高性能。专一于key-value查问的redis、memcached、ttserver。 解决以下问题: 对数据库的高并发读写需要大数据的高效存储和拜访需要高可扩展性和高可用性的需要Redis 数据库Redis 是一款内存高速缓存数据库。Redis全称为:Remote Dictionary Server(近程数据服务),应用C语言编写,Redis是一个key-value存储系统(键值存储系统),反对丰盛的数据类型,如:String、list、set、zset、hash。 Redis是一种反对key-value等多种数据结构的存储系统。可用于缓存,事件公布或订阅,高速队列等场景。反对网络,提供字符串,哈希,列表,队列,汇合构造直接存取,基于内存,可长久化。 官网材料Redis官网:http://redis.io/Redis官网文档:http://redis.io/documentationRedis教程:http://www.w3cschool.cn/redis/redis-intro.htmlRedis下载:http://redis.io/download为什么要应用 Redis一个产品的应用场景必定是须要依据产品的个性,先列举一下Redis的特点: 读写性能优异Redis能读的速度是110000次/s,写的速度是81000次/s (测试条件见下一节)。数据类型丰盛Redis反对二进制案例的 Strings, Lists, Hashes, Sets 及 Ordered Sets 数据类型操作。原子性Redis的所有操作都是原子性的,同时Redis还反对对几个操作全并后的原子性执行。丰盛的个性Redis反对 publish/subscribe, 告诉, key 过期等个性。长久化Redis反对RDB, AOF等长久化形式公布订阅Redis反对公布/订阅模式分布式Redis Cluster所以,无论是运维还是开发、测试,对于 NoSQL 数据库之一的 Redis 也是必学常识体系之一。 再卷也得学起来,搞起来!!! 从第一篇文章开始,咱们逐渐具体介绍了 Redis 基础理论与装置配置、9 种数据类型和利用场景、罕用治理命令、公布与订阅、事件、事务机制、长久化、主从复制与数据恢复实际、哨兵模式原理与数据恢复、Redis Cluster 集群分片技术、穿插复制与故障切换、自动化部署集群实战、集群的扩容与膨胀、与 Java\Php\Springboot 等利用的连贯与应用、罕用运维脚本、Redis 缓存问题(一致性、击穿、穿透、雪崩、净化)、内存耗费及回收、Key 过期工夫相干的命令、注意事项、回收策略、 性能优化与问题排查、性能测试及相干工具应用、运维监控(指标、体系建设、工具应用)、开发标准等常识。 死磕 NoSQL 数据库系列(一):Redis 基础理论与装置配置 死磕 NoSQL 数据库系列(二):Redis 9 种数据类型和利用场景 死磕 NoSQL 数据库系列(三):Redis 罕用治理命令 死磕 NoSQL 数据库系列(四):Redis 公布与订阅(pub/sub) 死磕 NoSQL 数据库系列(五):Redis 事件机制详解 死磕 NoSQL 数据库系列(六):Redis 事务详解 ...

May 26, 2023 · 1 min · jiezi

关于redis:NineData高效高质量的-Redis-可视化管理工具

Redis 是一个内存数据结构存储系统,它被宽泛用于缓存、队列、实时剖析等多种利用场景中,目前曾经成为 Key-value 数据存储系统中的佼佼者,依据 DB-Engine 网站提供的最新数据,Redis 在 Key-value stores 类别中排名第一,在整体数据库类别中排名第六,有着十分高的市场占有率。 随着 Redis 数据库的风行和广泛应用,Redis 的开发、治理需要日益增多,数据管理产品的好用与否将间接影响研发效力的高下。在 Redis 官网提供的 RedisInsight、Redis CLI 提供肯定的可视化治理、命令执行及语法提醒等能力,但不足人员操作权限管控(6.0以前的低版本)、人员操作审计、高危命令限制性应用等一系列平安保障。基于企业对立管控全副数据库类型的诉求,Ninedata 在关系型数据库类型反对的根底上,进一步拓展了可视化治理 Redis 数据库类型的反对。 1. 产品劣势NineData 的 SQL 窗口(Redis)是一个反对自建、多云、混合云平台等多种数据起源的数据管理工具,采纳了更加容纳的商业模式,提供集体版本收费应用,同时还提供企业版以满足企业协同需要。能够帮忙用户零门槛治理 Redis 数据库,通过 NineData,用户能够以图形化的形式查看、编辑和治理 Redis 数据以及数据库,无需再摸黑操作。 NineData SQL 窗口(Redis)的劣势: 性能残缺: 简直涵盖了所有 Redis 的性能,反对对各种 Redis 数据结构进行可视化治理。即开即用: NineData 采纳即开即用的 SaaS(软件即服务)状态,领有疾速启动、无需保护、低系统资源占有率等长处,您能够专一于 Redis 数据库的开发和优化,进步工作效率和开发体验。AI 合作: 集成了先进的自然语言解决技术和机器学习算法,能够将您输出的自然语言转换成相应的 Redis 命令。界面敌对: 领有直观、易用的用户界面,提供敌对的操作界面和可视化工具,帮忙开发人员更轻松地治理和监控 Redis 数据库。多云、多部署架构反对: 反对单机、高可用、哨兵模式下的 Redis 部署形式,同时反对多个云厂商的云数据库 Redis,笼罩多个不同的应用场景。性能弱小: 领有疾速的界面响应,给您带来良好的用户体验。企业协同: 不仅反对对 Redis 数据库的开发和治理,还具备弱小的企业协同能力。反对多用户协同、细粒度权限治理、记录和审计等企业级能力,进步团队的合作效率和数据安全性。2. 操作示例可视化编辑器:提供可视化的数据库操作界面,是您轻松治理 Redis 数据库的不二之选。 创立 Key 查看、编辑 Key 配置 Key 的过期工夫(TTL)、删除 Key ...

May 17, 2023 · 1 min · jiezi

关于redis:redis-命令行客户端列出-hset-下面所有的-key-的数量

Q:redis 命令行客户端,列出 hset 上面所有的 key 的数量 A:要列出 Redis 中 HSET 命令下的所有键的数量,你能够应用 HLEN 命令。以下是应用 Redis 命令行客户端列出 HSET 下所有键的数量的步骤: 关上终端或命令行界面。启动 Redis 命令行客户端,连贯到你的 Redis 服务器。如果 Redis 服务器在本地运行,并应用默认端口 6379,能够间接运行 redis-cli 命令连贯到 Redis 服务器。如果 Redis 服务器在不同的主机上或应用不同的端口,请应用以下命令格局连贯:redis-cli -h <host> -p <port>,将 <host> 替换为 Redis 服务器的主机名或 IP 地址,<port> 替换为 Redis 服务器的端口号。输出以下命令来获取 HSET 下所有键的数量: HLEN <key>将 <key> 替换为你要获取键数量的 HSET 的名称。 按下 Enter 键执行命令。Redis 将返回 HSET 下所有键的数量。请留神,你须要将 <key> 替换为你理论应用的键的名称。 Q:redis 命令行客户端,列出 hset 上面所有的 key A:要列出 Redis 中 HSET 命令下的所有键(key),你能够应用 HKEYS 命令。以下是应用 Redis 命令行客户端列出 HSET 下所有键的步骤: ...

May 15, 2023 · 1 min · jiezi

关于redis:redis存储结构

一个RedisDb蕴含键值空间字典dict、键过期字典expires。其中dict蕴含了理论存储数据的字典表,而expires蕴含了dict中具备过期工夫的key和无效工夫戳。redis通过expires字典键值表保留键的过期工夫,其中键指针指向理论键值(dict)中的键,值为long long 类型的工夫戳。如下图:

May 8, 2023 · 1 min · jiezi

关于redis:解决redis多表更新的事务一致性问题

前言因为对接的零碎越来越多,接口拜访并发量日渐减少,遂决定在我的项目中退出redis。 意识redisredis做为一个缓存中间件常常被用于进步接口并发量来应用。你能够把他看做数据库的缓存来应用,相似于上次咱们说的mybatis的缓存机制。也能够把他作为一个高性能数据库来应用,反对长久化。类比于mybatis的缓存机制不同的是,咱们应用redis作为缓存不会呈现查一次做批改不保留再去查就是新值的问题,也比mybatis的缓存机制可操作性更强。比方当更新一个表时,mybatis本人会把所有缓存全副清空,保障时效性。而redis更新一个表时,你能够去只更新对应的一条数据,可操作性更强,同时反对设置生效工夫,如10分钟,10分钟后主动删除。 redis外部将key-value保留到了内存中,查问时,通过key返回value值。解决value,也就是String类型,还反对同时还提供list,set,zset,hash等数据结构的存储。最罕用的就是String类型。认为保留在内存中,所以比数据库读写速度快。 装置能够参考菜鸟教程装置。他的应用相似于mysql,提供命令行操作,反对可视化软件链接。 应用redisspringboot我的项目接入redis,同样须要引入redis包,在yaml文件中退出配置连贯。 我的项目中应用redis两种形式,一种是应用缓存注解模式,一种是应用RedisTemplate的办法操作。注解模式首先在我的项目启动类上退出@EnableCaching注解示意启用缓存 @Cacheable注解,在查询方法上增加,调用此办法前先通过key查问缓存,若查不到,则再执行此办法,并将返回后果和key保留到缓存中。若查失去,间接返回value,不在执行此办法。其中参数cacheNames指定缓存组件名,此名字在yaml文件中定义,key代表key-value中的key,应用spEL表达式去编写,如果入参是对象,可写作key = "#user.usrNo"。 @Cacheable(cacheNames = "XXX", key = "#usrNo")public User queryByUsrNo(String usrNo) {}须要留神的是,这里的key是不辨别表的,如果两个表的key值雷同,那么就会产生抵触,所以咱们的key值前要加上表明前缀,格局为表名:key,写作key = "'user:' + '#usrNo'" 。这里的:号有分组的意思,相似于文件门路的/,这个能够在可视化redis工具中看到。 @CachePut注解,在变更办法上增加,在执行完指标办法后,缓存中的数据也会更新。 @CacheEvict注解,删除缓存,在执行完指标办法后,革除对应的key-value。 代码模式以上性能手动在代码中增加,应用RedisTemplate中的办法实现。例如须要手动在查询方法上加查询数据库的判断操作和查问完数据库的保留操作。 解决redis多表更新的事务一致性问题redis反对事务,然而跟mysql的事务并不一样,redis事务没有回滚机制。那么如果一个变更交易更新两个表,当更新第一个表时mysql胜利更新,redis也更新,当更新第二个表时报错mysql回滚,第一个表还是原来的数据,然而redis无奈回滚之前的数据,导致数据不统一的问题。 解决这个问题其实咱们要保障redis在所有表都胜利更新后再去对立更新。这个我想到了前段时间接触的spring event机制。其中有一个公布多个事件,监听事件者能够在事务提交后执行。利用此原理。切面数据库更新删除办法,每当更新删除一个表时,把key公布进来。同时设置一个监听者,退出@TransactionalEventListener注解,当整个事务提交时,删除公布的所有key-value。具体可参考spring event机制这里须要咱们着重留神一下key的设置,咱们须要给每一个表设置一个业务因素。业务因素能够简略了解为咱们查问次数最多的条件。如学生表的话就是学生编号,学生班级关联表也是学生编号。这样保障每一个表的key对应的字段雷同,删除缓存时才不会漏删。 总结redis实用于一些不常常变的数据或者对变动时效性要求不高的数据缓存,如果对时效性要求高并且又不得不加redis,能够应用我上边提到的解决办法。

May 7, 2023 · 1 min · jiezi

关于redis:Redis的安装使用

一、装置前环境检测PS:Linux环境装置redis必须具备gcc编译环境查看gcc环境 gcc -v装置gcc yum -y install gcc-c++二、Linux版装置2.1 Linux版下载找到redis官网,抉择版本进行下载 Linux历史版本2.2 装置步骤在/opt目录下解压redis tar -zxvf redis-7.0.8.tar.gz进入redis-7.0.8目录,执行make命令 make && make install查看默认装置目录: usr/local/bin备份一份默认的redis.conf mkdir /myrediscp /opt/redis/redis/redis.conf /myredis/redis7.conf批改redis.conf配置文件做初始化设置编辑redis7.conf配置文件,正文bind 127.0.0.1(ps:容许所有ip拜访redis),批改daemonize为yes,protected-mode为no vim /myredis/redis7.conf2.3查看redis是否启动查看6379端口号是否被占用 ps -ef|grep redis|grep -v grep

April 26, 2023 · 1 min · jiezi

关于redis:吃透Redis面试八股文

Redis连环40问,相对够全! Redis是什么?Redis(Remote Dictionary Server)是一个应用 C 语言编写的,高性能非关系型的键值对数据库。与传统数据库不同的是,Redis 的数据是存在内存中的,所以读写速度十分快,被广泛应用于缓存方向。Redis能够将数据写入磁盘中,保障了数据的平安不失落,而且Redis的操作是原子性的。 Redis优缺点?长处: 基于内存操作,内存读写速度快。反对多种数据类型,包含String、Hash、List、Set、ZSet等。反对长久化。Redis反对RDB和AOF两种长久化机制,长久化性能能够无效地防止数据失落问题。反对事务。Redis的所有操作都是原子性的,同时Redis还反对对几个操作合并后的原子性执行。反对主从复制。主节点会主动将数据同步到从节点,能够进行读写拆散。Redis命令的解决是单线程的。Redis6.0引入了多线程,须要留神的是,多线程用于解决网络数据的读写和协定解析,Redis命令执行还是单线程的。毛病: 对结构化查问的反对比拟差。数据库容量受到物理内存的限度,不适宜用作海量数据的高性能读写,因而Redis适宜的场景次要局限在较小数据量的操作。Redis 较难反对在线扩容,在集群容量达到下限时在线扩容会变得很简单。Redis为什么这么快?基于内存:Redis是应用内存存储,没有磁盘IO上的开销。数据存在内存中,读写速度快。IO多路复用模型:Redis 采纳 IO 多路复用技术。Redis 应用单线程来轮询描述符,将数据库的操作都转换成了事件,不在网络I/O上节约过多的工夫。高效的数据结构:Redis 每种数据类型底层都做了优化,目标就是为了谋求更快的速度。本文曾经收录到Github仓库,该仓库蕴含计算机根底、Java根底、多线程、JVM、数据库、Redis、Spring、Mybatis、SpringMVC、SpringBoot、分布式、微服务、设计模式、架构、校招社招分享等外围知识点,欢送star~ Github地址 如果拜访不了Github,能够拜访gitee地址。 gitee地址 既然Redis那么快,为什么不必它做主数据库,只用它做缓存?尽管Redis十分快,但它也有一些局限性,不能齐全代替主数据库。有以下起因: 事务处理:Redis只反对简略的事务处理,对于简单的事务无能为力,比方跨多个键的事务处理。 数据长久化:Redis是内存数据库,数据存储在内存中,如果服务器解体或断电,数据可能失落。尽管Redis提供了数据长久化机制,但有一些限度。 数据处理:Redis只反对一些简略的数据结构,比方字符串、列表、哈希表等。如果须要解决简单的数据结构,比方关系型数据库中的表,那么Redis可能不是一个好的抉择。 数据安全:Redis没有提供像主数据库那样的平安机制,比方用户认证、访问控制等等。 因而,尽管Redis十分快,但它还有一些限度,不能齐全代替主数据库。所以,应用Redis作为缓存是一种很好的形式,能够进步应用程序的性能,并缩小数据库的负载。 讲讲Redis的线程模型?Redis基于Reactor模式开发了网络事件处理器,这个处理器被称为文件事件处理器。它的组成构造为4局部:多个套接字、IO多路复用程序、文件事件分派器、事件处理器。因为文件事件分派器队列的生产是单线程的,所以Redis才叫单线程模型。 文件事件处理器应用I/O多路复用(multiplexing)程序来同时监听多个套接字, 并依据套接字目前执行的工作来为套接字关联不同的事件处理器。当被监听的套接字筹备好执行连贯accept、read、write、close等操作时, 与操作绝对应的文件事件就会产生, 这时文件事件处理器就会调用套接字之前关联好的事件处理器来解决这些事件。尽管文件事件处理器以单线程形式运行, 但通过应用 I/O 多路复用程序来监听多个套接字, 文件事件处理器既实现了高性能的网络通信模型, 又能够很好地与 redis 服务器中其余同样以单线程形式运行的模块进行对接, 这放弃了 Redis 外部单线程设计的简略性。 Redis利用场景有哪些?缓存热点数据,缓解数据库的压力。利用 Redis 原子性的自增操作,能够实现计数器的性能,比方统计用户点赞数、用户拜访数等。分布式锁。在分布式场景下,无奈应用单机环境下的锁来对多个节点上的过程进行同步。能够应用 Redis 自带的 SETNX 命令实现分布式锁,除此之外,还能够应用官网提供的 RedLock 分布式锁实现。简略的音讯队列,能够应用Redis本身的公布/订阅模式或者List来实现简略的音讯队列,实现异步操作。限速器,可用于限度某个用户拜访某个接口的频率,比方秒杀场景用于避免用户疾速点击带来不必要的压力。好友关系,利用汇合的一些命令,比方交加、并集、差集等,实现独特好友、共同爱好之类的性能。Memcached和Redis的区别?MemCached 数据结构繁多,仅用来缓存数据,而 Redis 反对多种数据类型。MemCached 不反对数据长久化,重启后数据会隐没。Redis 反对数据长久化。Redis 提供主从同步机制和 cluster 集群部署能力,可能提供高可用服务。Memcached 没有提供原生的集群模式,须要依附客户端实现往集群中分片写入数据。Redis 的速度比 Memcached 快很多。Redis 应用单线程的多路 IO 复用模型,Memcached应用多线程的非阻塞 IO 模型。(Redis6.0引入了多线程IO,用来解决网络数据的读写和协定解析,然而命令的执行依然是单线程)value 值大小不同:Redis 最大能够达到 512M;memcache 只有 1mb。最初给大家分享一个Github仓库,下面有大彬整顿的300多本经典的计算机书籍PDF,包含C语言、C++、Java、Python、前端、数据库、操作系统、计算机网络、数据结构和算法、机器学习、编程人生等,能够star一下,下次找书间接在下面搜寻,仓库继续更新中~ ...

April 24, 2023 · 4 min · jiezi

关于redis:Redis设计与实现

概述字符串SDC(Simple Dynamic String,简略动静字符串)作为字符串示意每个sds.h/sdshdr构造示意一个SDS值 struct sdshdr{ ... } len free buff 劣势常数复杂度获取字符串长度 数据结构中有len属性用于保留字符串的长度杜绝缓冲区溢出在字符串进行扩大前,会先检查一下buff的长度是否足够,如果不够的话就会进行扩大,而后再执行增加字符的操作缩小内存调配次数SDS通过两种策略来实现3.1 空间预调配如果对SDS进行批改之后,len属性小于1MB,那么程序调配和len同样大小的未应用空间,即len和free属性值雷同;如果大于1MB,那么将调配1MB未应用空间3.2 惰性空间开释当SDS的API须要缩短保留的字符串时,内存重调配不会立刻开释未应用的空间,而是将其作为free的数量二进制平安首先须要理解C,C的字符串必须合乎某种编码,例如如果一开始读入空格将被辨认为结尾 SDS以二进制模式存储,文本存进去是什么内容,拿进去就还是什么内容兼容局部C字符串函数SDS遵循C字符串以空字符结尾,这样就能重用/<string.h>的stracasecmp函数 strcasecpm(sds->buff,"hello world!")链表数据结构双向链表 typedef struct list{ ... }listlistNode * head; 温习一下结点的数据结构 typedef struct listNode{ struct ListNode * prev; struct ListNode * next; void * value; } listNode * tail;unsigned long len;//节点复制函数void (dup)(void *ptr) 个性双端、无环、带表头和表尾指针、带链表长度计数器和多态对于多态这里解释一下,以复制函数为例,应用的void*指针来保留节点值,所以能够保留各种不同类型的值 用处列表键、公布与订阅、慢查问、监视器等列表键临时不知公布与订阅容易音讯失落,实用于要求不高的场景,能够从确保音讯不失落的问题从延长慢查问临时不知监视器临时不知 字典哈希表节点与哈希表数据结构键值节点构造哈希表构造字典构造 从下面的图里能够看到,字典中有哈希表构造,而哈希表中有key-value键值节点 哈希算法通过键来计算出哈希值和索引值(通过哈希值和哈希掩码计算出来),将蕴含新键值对的哈希表节点放在置顶索引下面 解决键抵触(哈希抵触)链表法 rehash(从新散列)说人话就是为了在字典外面的数据减少或者缩小的时候将哈希表的长度管制在肯定范畴内,防止不够用或者过于节约 当哈希表减少或者缩减到肯定水平时就会触发rehash操作 如果是减少,那么ht[1]的大小等于ht[0].used*2的2^n^ 如果是缩小,那么ht[1]的大小等于ht[0].used的2^n^将ht[0]的所有键值都放到ht[1]中,这个过程会从新计算hash值和索引值开释ht[0],而后将ht[1]设置为ht[0],并且在ht[1]新创建一个空白哈希表,为下一次的rehash做筹备 渐进式rehash先定义一个rehashindex变量,初始值为0,在执行新增、删除、查问时都会将对应ht[0]的redisindex索引处的key-value从新散列到ht[1],并且在渐进式rehash期间,新增的结点不会进入到ht[0]中,就保障了ht[0]最终会成为空表 跳跃表几个重要的概念 后退指针每个跳跃表结点都有指向下一个结点的指针层每个跳跃表结点都会有很多层,至于具体是干什么的当初还不太分明后退指针最初一个跳跃表结点指向前一个结点跨度就是从头结点开始到指标结点经验的门路,有点想图的权分值和成员分值是一个double类型的浮点数,跳跃表中的所有的结点的分值依照从小大来排序 对象是一个指针,它指向一个字符串对象,而字符串对象中则保留一个SDS值 不太分明一个跳跃表结点是不是只能寄存一个对象,然而我猜想是这样的 总结Redis的跳跃表实现是由zkiplist和zkiplistNode两个构造组成,其中zkiplist用于保留跳跃表信息(比方表头节点、表尾节点、长度),而zskiplistNode则用于跳跃表节点多个跳跃表节点的分值能够雷同,然而对象必须惟一 整数汇合整数汇合是汇合键的底层实现之一,当一个汇合只蕴含整数值元素,并且这个汇合的元素数量不多时,Redissadd numbers 1 3 5 7 9下面的命令用的是sadd,阐明用的汇合set的根本类型(Redis对外提供的) ...

April 17, 2023 · 1 min · jiezi

关于redis:redis-集群常见问题-QA

数据分片Q:redis 集群是怎么做数据分片的?A:Redis集群是通过数据分片(sharding)来实现数据在不同节点间的调配。Redis集群中有16384个hash slot(槽位),每个节点能够解决其中的一部分槽位,不同节点之间能够独特解决这16384个槽位。当一个键值对须要被放到Redis集群中时,Redis会先计算该键值对的key对应的hash值,而后将其放到对应的槽位中。Redis集群的每个节点都晓得本人负责解决哪些槽位,所以可能疾速定位数据在哪个节点上。 具体来说,Redis集群应用哈希槽分片(hash slot sharding)来将所有数据分成16384个哈希槽。当客户端连贯Redis集群时,会失去集群中任意一个节点的IP和端口信息,而后将客户端的申请路由到正确的节点上。每个节点都负责解决一部分哈希槽,这些哈希槽的范畴通过分布式哈希算法(比方CRC16)来计算,而后调配到不同的节点上。当一个客户端申请须要操作某个key时,Redis会先依据key计算出该key对应的哈希槽,而后将申请路由到负责该哈希槽的节点上。这样就实现了数据的分片存储和拜访。 Q:一个槽位,能够被多个 redis 主节点独特持有吗?A:在 Redis 集群中,一个槽位只能被一个 Redis 节点持有,即每个槽位只能被调配给 Redis 集群中的一个主节点。在 Redis 集群中,槽位会被平均地调配给各个主节点,确保每个主节点都调配了肯定数量的槽位,从而实现数据的分布式存储。如果一个槽位被多个主节点持有,那么可能会导致数据抵触和数据一致性问题。因而,Redis 集群的设计保障了一个槽位只被一个主节点持有。 Q:一个 redis 主节点,怎么晓得本人持有哪些槽位?持有的槽位是离散的,还是间断的?A:在 Redis 集群中,一个 Redis 主节点会持有一部分槽位,具体是哪些槽位是由集群的节点管理器指定的。一个槽位只会被调配给一个 Redis 主节点,而不会被多个主节点独特持有。每个 Redis 主节点都会记录本人持有的槽位信息,能够通过命令 CLUSTER SLOTS 来获取以后节点所持有的槽位信息,例如: 127.0.0.1:6379> CLUSTER SLOTS1) 1) (integer) 0 2) (integer) 5460 3) 1) "127.0.0.1" 2) (integer) 6379 3) "f2b5a96e2e79d08ce5d5a5b1d64b5a31f07a734f" 4) 1) "127.0.0.1" 2) (integer) 6380 3) "92d24c0209384f4c4c9abef7adff0f129b73e7b6"2) 1) (integer) 5461 2) (integer) 10922 3) 1) "127.0.0.1" 2) (integer) 6380 3) "92d24c0209384f4c4c9abef7adff0f129b73e7b6" 4) 1) "127.0.0.1" 2) (integer) 6379 3) "f2b5a96e2e79d08ce5d5a5b1d64b5a31f07a734f"...上述命令返回了以后节点所持有的所有槽位信息。其中,每个槽位由一个起始槽号和一个完结槽号组成,例如 (integer) 0 到 (integer) 5460 示意第一个槽位的起始编号为 0,完结编号为 5460。对于间断的槽位,它们的起始和完结编号是间断的,而对于离散的槽位,它们的编号是不间断的。 ...

April 14, 2023 · 1 min · jiezi

关于redis:bind-127001-1-和-bind-127001-有什么区别

bind 127.0.0.1 示意 Redis 只会监听 IPv4 地址 127.0.0.1,即只能承受来自本地主机的连贯。 bind 127.0.0.1 ::1 示意 Redis 会同时监听 IPv4 地址 127.0.0.1 和 IPv6 地址 ::1,即既能承受来自本地主机的 IPv4 连贯,也能承受来自本地主机的 IPv6 连贯。 在这两者之间,如果 Redis 同时要反对 IPv4 和 IPv6 的话,第二种设置会更加灵便。 Q:bind 127.0.0.1 ::1 批改为容许所有 ipv4 和 ipv6 的拜访,应该怎么改? A:将配置文件中的 bind 127.0.0.1 ::1 批改为 bind 0.0.0.0 :: 即可容许所有 IPv4 和 IPv6 地址的拜访。

April 14, 2023 · 1 min · jiezi

关于redis:三-从servermain再次看redis启动流程

三 从server.main再次看redis启动流程明天呢,咱们从整体的角度来看看redis的启动过程,后面两章内容曾经将redis启动时重要的过程具体的讲了一遍,当初呢,咱们从整体的过程来看看redis的启动。 main函数是程序启动的入口,当初呢,咱们一步一步的去剖析他,开掘他。 1 变量定义main函数的前三行 struct timeval tv; int j; char config_from_stdin = 0;这段代码定义了一个名为 tv 的 timeval 构造体变量和一个 int 类型的变量 j,以及一个 char 类型的变量 config_from_stdin,初值为 0。 timeval 是 C 语言规范库中的一个构造体,示意工夫值,由两个成员组成:tv_sec 示意秒数,tv_usec 示意微秒数。在这段代码中,咱们定义了一个 timeval 类型的变量 tv,通常用于计算时间差和设置超时等场景。 int 类型的变量 j 能够用于计数,或者存储整数值。 char 类型的变量 config_from_stdin 用于标记程序是否须要从规范输出读取配置。该变量的初值为 0,示意程序不须要从规范输出读取配置。当该变量的值为 1 时,示意程序须要从规范输出读取配置。 NAME timeval - time in seconds and microsecondsLIBRARY Standard C library (libc)SYNOPSIS #include <sys/time.h> struct timeval { time_t tv_sec; /* Seconds */ suseconds_t tv_usec; /* Microseconds */ };DESCRIPTION Describes times in seconds and microseconds.看到这里,你是不是想起后面读取配置的三种形式了,其中是否从终端中读取就在此处定义了。 ...

April 10, 2023 · 16 min · jiezi

关于redis:Redis缓存高可用集群

作者:京东批发 王雷 1、Redis集群计划比拟• 哨兵模式 在redis3.0以前的版本要实现集群个别是借助哨兵sentinel工具来监控master节点的状态,如果master节点异样,则会做主从切换,将某一台slave作为master,哨兵的配置稍微简单,并且性能和高可用性等各方面体现个别。 特地是在主从切换的霎时存在拜访瞬断的状况,而且哨兵模式只有一个主节点对外提供服务,没法反对很高的并发,且单个主节点内存也不宜设置得过大,否则会导致长久化文件过大,影响数据恢复或主从同步的效率。 • 高可用集群模式 redis集群是一个由多个主从节点群组成的分布式服务器群,它具备复制、高可用和分片个性。Redis集群不须要sentinel哨兵也能实现节点移除和故障转移的性能。 须要将每个节点设置成集群模式,这种集群模式没有核心节点,可程度扩大,据官网文档称能够线性扩大到上万个节点(官网举荐不超过1000个节点)。redis集群的性能和高可用性均优于之前版本的哨兵模式,且集群配置非常简单。 2、Redis高可用集群搭建• redis集群搭建 redis集群须要至多三个master节点,咱们这里搭建三个master节点,并且给每个master再搭建一个slave节点,总共6个redis节点,这里用三台机器部署6个redis实例,每台机器一主一从,搭建集群的步骤如下: 第一步:在第一台机器的/usr/local下创立文件夹redis-cluster,而后在其上面别离创立2个文件夾如下(1)mkdir -p /usr/local/redis-cluster(2)mkdir 8001 8004第二步:把之前的redis.conf配置文件copy到8001下,批改如下内容:(1)daemonize yes(2)port 8001(别离对每个机器的端口号进行设置)(3)pidfile /var/run/redis_8001.pid # 把pid过程号写入pidfile配置的文件(4)dir /usr/local/redis-cluster/8001/(指定数据文件寄存地位,必须要指定不同的目录地位,不然会失落数据)(5)cluster-enabled yes(启动集群模式)(6)cluster-config-file nodes-8001.conf(集群节点信息文件,这里800x最好和port对应上)(7)cluster-node-timeout 10000 (8)# bind 127.0.0.1(bind绑定的是本人机器网卡的ip,如果有多块网卡能够配多个ip,代表容许客户端通过机器的哪些网卡ip去拜访,内网个别能够不配置bind,正文掉即可) (9)protected-mode no (敞开保护模式) (10)appendonly yes如果要设置明码须要减少如下配置: (11)requirepass test (设置redis拜访明码) (12)masterauth test (设置集群节点间拜访明码,跟下面统一)第三步:把批改后的配置文件,copy到8004,批改第2、3、4、6项里的端口号,能够用批量替换::%s/源字符串/目标字符串/g 第四步:另外两台机器也须要做下面几步操作,第二台机器用8002和8005,第三台机器用8003和8006第五步:别离启动6个redis实例,而后查看是否启动胜利(1)/usr/local/redis-5.0.3/src/redis-server /usr/local/redis-cluster/800*/redis.conf(2)ps -ef | grep redis 查看是否启动胜利 第六步:用redis-cli创立整个redis集群(redis5以前的版本集群是依附ruby脚本redis-trib.rb实现)# 上面命令里的1代表为每个创立的主服务器节点创立一个从服务器节点# 执行这条命令须要确认三台机器之间的redis实例要能互相拜访,能够先简略把所有机器防火墙关掉,如果不敞开防火墙则须要关上redis服务端口和集群节点gossip通信端口16379(默认是在redis端口号上加1W)# 敞开防火墙# systemctl stop firewalld # 长期敞开防火墙# systemctl disable firewalld # 禁止开机启动# 留神:上面这条创立集群的命令大家不要间接复制,外面的空格编码可能有问题导致创立集群不胜利(1)/usr/local/redis-5.0.3/src/redis-cli -a test --cluster create --cluster-replicas 1 192.168.0.61:8001 192.168.0.62:8002 192.168.0.63:8003 192.168.0.61:8004 192.168.0.62:8005 192.168.0.63:8006 第七步:验证集群:(1)连贯任意一个客户端即可:./redis-cli -c -h -p (-a拜访服务端明码,-c示意集群模式,指定ip地址和端口号) 如:/usr/local/redis-5.0.3/src/redis-cli -a test -c -h 192.168.0.61 -p 800*(2)进行验证: cluster info(查看集群信息)、cluster nodes(查看节点列表)(3)进行数据操作验证(4)敞开集群则须要一一进行敞开,应用命令:/usr/local/redis-5.0.3/src/redis-cli -a test -c -h 192.168.0.60 -p 800* shutdown 3、Java操作redis集群借助redis的java客户端jedis能够操作以上集群,援用jedis版本的maven坐标如下: ...

April 10, 2023 · 2 min · jiezi

关于redis:三天吃透Redis八股文

Redis连环40问,相对够全! Redis是什么?Redis(Remote Dictionary Server)是一个应用 C 语言编写的,高性能非关系型的键值对数据库。与传统数据库不同的是,Redis 的数据是存在内存中的,所以读写速度十分快,被广泛应用于缓存方向。Redis能够将数据写入磁盘中,保障了数据的平安不失落,而且Redis的操作是原子性的。 Redis优缺点?长处: 基于内存操作,内存读写速度快。反对多种数据类型,包含String、Hash、List、Set、ZSet等。反对长久化。Redis反对RDB和AOF两种长久化机制,长久化性能能够无效地防止数据失落问题。反对事务。Redis的所有操作都是原子性的,同时Redis还反对对几个操作合并后的原子性执行。反对主从复制。主节点会主动将数据同步到从节点,能够进行读写拆散。Redis命令的解决是单线程的。Redis6.0引入了多线程,须要留神的是,多线程用于解决网络数据的读写和协定解析,Redis命令执行还是单线程的。毛病: 对结构化查问的反对比拟差。数据库容量受到物理内存的限度,不适宜用作海量数据的高性能读写,因而Redis适宜的场景次要局限在较小数据量的操作。Redis 较难反对在线扩容,在集群容量达到下限时在线扩容会变得很简单。Redis为什么这么快?基于内存:Redis是应用内存存储,没有磁盘IO上的开销。数据存在内存中,读写速度快。最全面的Java面试网站IO多路复用模型:Redis 采纳 IO 多路复用技术。Redis 应用单线程来轮询描述符,将数据库的操作都转换成了事件,不在网络I/O上节约过多的工夫。高效的数据结构:Redis 每种数据类型底层都做了优化,目标就是为了谋求更快的速度。本文曾经收录到Github仓库,该仓库蕴含计算机根底、Java根底、多线程、JVM、数据库、Redis、Spring、Mybatis、SpringMVC、SpringBoot、分布式、微服务、设计模式、架构、校招社招分享等外围知识点,欢送star~ Github地址 如果拜访不了Github,能够拜访gitee地址。 gitee地址 既然Redis那么快,为什么不必它做主数据库,只用它做缓存?尽管Redis十分快,但它也有一些局限性,不能齐全代替主数据库。有以下起因: 事务处理:Redis只反对简略的事务处理,对于简单的事务无能为力,比方跨多个键的事务处理。 数据长久化:Redis是内存数据库,数据存储在内存中,如果服务器解体或断电,数据可能失落。尽管Redis提供了数据长久化机制,但有一些限度。 数据处理:Redis只反对一些简略的数据结构,比方字符串、列表、哈希表等。如果须要解决简单的数据结构,比方关系型数据库中的表,那么Redis可能不是一个好的抉择。 数据安全:Redis没有提供像主数据库那样的平安机制,比方用户认证、访问控制等等。 因而,尽管Redis十分快,但它还有一些限度,不能齐全代替主数据库。所以,应用Redis作为缓存是一种很好的形式,能够进步应用程序的性能,并缩小数据库的负载。 讲讲Redis的线程模型?Redis基于Reactor模式开发了网络事件处理器,这个处理器被称为文件事件处理器。它的组成构造为4局部:多个套接字、IO多路复用程序、文件事件分派器、事件处理器。因为文件事件分派器队列的生产是单线程的,所以Redis才叫单线程模型。 文件事件处理器应用I/O多路复用(multiplexing)程序来同时监听多个套接字, 并依据套接字目前执行的工作来为套接字关联不同的事件处理器。当被监听的套接字筹备好执行连贯accept、read、write、close等操作时, 与操作绝对应的文件事件就会产生, 这时文件事件处理器就会调用套接字之前关联好的事件处理器来解决这些事件。尽管文件事件处理器以单线程形式运行, 但通过应用 I/O 多路复用程序来监听多个套接字, 文件事件处理器既实现了高性能的网络通信模型, 又能够很好地与 redis 服务器中其余同样以单线程形式运行的模块进行对接, 这放弃了 Redis 外部单线程设计的简略性。 Redis利用场景有哪些?缓存热点数据,缓解数据库的压力。利用 Redis 原子性的自增操作,能够实现计数器的性能,比方统计用户点赞数、用户拜访数等。分布式锁。在分布式场景下,无奈应用单机环境下的锁来对多个节点上的过程进行同步。能够应用 Redis 自带的 SETNX 命令实现分布式锁,除此之外,还能够应用官网提供的 RedLock 分布式锁实现。简略的音讯队列,能够应用Redis本身的公布/订阅模式或者List来实现简略的音讯队列,实现异步操作。限速器,可用于限度某个用户拜访某个接口的频率,比方秒杀场景用于避免用户疾速点击带来不必要的压力。好友关系,利用汇合的一些命令,比方交加、并集、差集等,实现独特好友、共同爱好之类的性能。Memcached和Redis的区别?MemCached 数据结构繁多,仅用来缓存数据,而 Redis 反对多种数据类型。MemCached 不反对数据长久化,重启后数据会隐没。Redis 反对数据长久化。Redis 提供主从同步机制和 cluster 集群部署能力,可能提供高可用服务。Memcached 没有提供原生的集群模式,须要依附客户端实现往集群中分片写入数据。Redis 的速度比 Memcached 快很多。Redis 应用单线程的多路 IO 复用模型,Memcached应用多线程的非阻塞 IO 模型。(Redis6.0引入了多线程IO,用来解决网络数据的读写和协定解析,然而命令的执行依然是单线程)value 值大小不同:Redis 最大能够达到 512M;memcache 只有 1mb。为什么要用 Redis 而不必 map/guava 做缓存?应用自带的 map 或者 guava 实现的是本地缓存,最次要的特点是轻量以及疾速,生命周期随着 jvm 的销毁而完结,并且在多实例的状况下,每个实例都须要各自保留一份缓存,缓存不具备一致性。 ...

April 10, 2023 · 4 min · jiezi

关于redis:redis缓存常见问题场景总结

在应用redis缓存时,咱们大略都听过缓存击穿、缓存雪崩之类的场景和计划,这也是个别常见面试题的内容。但在这些年的理论开发中,确实亲身经历了这类场景之后,对这类场景和解决方案就更加粗浅,这类再对立总结一下。 当然计划不是惟一的,后续如果我用到更好的计划,仍然会基于本文档补充。 1. 缓存击穿1.1. 定义缓存击穿,也就是说当redis缓存中有一个key是大量申请同时拜访的热点数据,如果忽然这个key工夫到了,那么大量的申请在缓存中获取不到该key,穿过缓存间接来到数据库导致数据库解体,这样因为单个key生效而穿过缓存到数据库称为缓存击穿。 1.2. 计划1.2.1. 计划一:被动更新key这里问题在于key是被动刷新的,即key过期后主动删除,当流量申请进来了才去读db更新缓存。如果场景容许,咱们能够被动控制性的刷新key。key仍然能够设置过期工夫,但咱们能够通过后盾job等形式,从db拿最新的值更新key对应的value,更新的同时天然对key进行续期。 这样以达到能定时更新redis值,又保障redis key永远不生效,突发大流量也走不到db。 1.2.2. 计划二:更新缓存加锁缓存击穿的场景在压测中常常可见,当没有缓存预热时,redis 缓存key一开始不存在。假如jmeter 100个线程并发拜访时,都发现缓存key不存在,100个申请都会去查问db,而后更新redis值。 其实咱们在发现key不存在之后,能够对于“查db更新redis缓存”这个过程加上分布式锁,保障只有有一个申请去读db、更新缓存。其余的申请在期待锁开释后,再去查下redis缓存。此时缓存有值就间接拜访缓存。 2. 缓存雪崩2.1. 定义当大量申请在拜访都会先从缓存查问,如果此时大部分缓存同时过期生效,那么这些申请都查问不到缓存,此时他们会全副将申请到数据库,当申请数量足够大时此时将会把数据库压垮,这就是缓存雪崩。比方:在凌晨十二点搞促销,大概有10000个用户发动申请,此时缓存过期,则这10000个申请间接打到数据库上,把数据库压垮,即便重启数据库申请仍然会打到数据库上。 这里和“缓存击穿”不同的中央在于: 缓存击穿:单个key过期,单个key的大量申请进来。缓存雪崩:多个key同时过期,多个key的大量申请进来。2.2. 计划2.2.1. 计划一:过期工夫扩散问题在于key同时过期。首先,如果业务上key的生成工夫不是同时的,那么过期工夫也就不是同时的,这类问题能够防止。 如果key的生成工夫是同时的,例如:缓存是通过job或其余触发条件批量一起生成的,那么在定义每个key的过期工夫时,能够基于原定的工夫再加上一个随机时间段,以保障最终的过期工夫不统一。 2.2.2. 计划二:集群架构redis的集群架构中,可依据写入命令依照不同slot,调配在不同master上。因为这些key是不同的,针对缓存雪崩场景,写入的申请就能够调配在不同master节点上,能缓解一部分压力。 当然,成果无限,但至多比单体架构抗压强。 2.2.3. 计划三:降级限流可评估数据库能承受的最大申请量,做限流。那么被限住的申请就要做服务降级,可在队列中期待异步更新redis值。 3. 缓存穿透3.1. 定义指当申请查问缓存和数据库都不存在的数据时,先查问缓存为空,再查询数据库仍然为空,向申请返回空,如果大量申请同时拜访这些不存在key那么这些申请仍然会造成压垮数据库的景象,这种通常是歹意查问和被攻打几率较大。 缓存穿透 和 缓存击穿 名字听起来很像,但不是一回事。缓存穿透 是针对缓存中不存在的key。而 缓存击穿 是本来存在某个缓存key,等生效后忽然大批量拜访这个key。 3.2. 计划3.2.1. 缓存null值当拜访一些不存在的key时,因为在db中查到的值为null,就不会缓存下来,所以下次访问仍然会走db。 那么当在db中查到的值为null时,咱们罗唆就创立一个缓存key,存的值就为null等。当下次访问的时候,就会走缓存中取,而不必走db。 然而这个计划有局限性,得看具体场景。假如第一次拜访的时候不存在,咱们缓存了一个null的key,很快db中对应的key就有值了,可咱们拜访时仍然是从缓存中获取了null。 有两种改良策略: 能够针对null的值,咱们的过期工夫能够设短一点。(上策)当db中值新建、更新时,可能被动革除对应的缓存key。(上策)3.2.2. 布隆过滤器详见 《布隆过滤器 与 Redis BitMap》 4. 热点key(缓存击穿)4.1. 定义这里 (缓存击穿),是因为和缓存击穿场景有点像。后面说的缓存击穿,单指key过期,大流量击穿db。而这里不必等到key过期,间接更大的流量,击穿redis,再击穿db。 热点key,就是霎时有大量的申请去拜访redis上某个固定的key。例如一些热搜词条:IG夺冠、梅西夺冠,一瞬间会有大量的用户申请都拜访固定的词条,如果这些词条内容存在redis中,那么拜访的就是某个固定的key。 咱们晓得,就算是redis的集群机构,针对某个固定的key,也是被调配某个固定的哈希槽上,对应redis某单个节点。而redis单个节点的性能无限,此时就容易被击溃,带来的危害有: 1. 流量集中,达到物理网卡下限当某一热点Key的申请在某一节点所在的主机上超过该主机网卡流量下限时,因为流量的适度集中,会导致该节点的服务器中其它服务无奈进行 2. 申请过多,缓存分片服务被打垮Redis单点查问性能是无限的,单节点QPS差不多也就几万,当热点key的查问超过Redis节点的性能阈值时,申请会占用大量的CPU资源,影响其余申请并导致整体性能升高;重大时会导致缓存分片服务被打垮,表现形式之一就是Redis节点自重启,此时该节点存储的所有key的查问都是不可用状态,会把影响辐射到其余业务上。 3. 集群架构下,产生拜访歪斜即某个数据分片被大量拜访,而其余数据分片处于闲暇状态,可能引起该数据分片的连接数被耗尽,新的连贯建设申请被回绝等问题。 4. DB 击穿,引起业务雪崩热Key的申请压力数量超出Redis的承受能力易造成缓存击穿,当缓存挂掉时,此时再有申请产生,可能间接把大量申请间接打到DB层上,因为DB层绝对缓存层查问性能更弱,在面临大申请时很容易产生DB雪崩景象,重大影响业务。 4.2. 辨认热点key4.2.1. 业务教训评估比方热搜关键词、秒杀商品的词条等等,可能提前辨认到可能是热点key的,就提前做筹备。 4.2.2. 业务侧监控在操作redis之前,退出一行代码进行数据统计,异步上报行为;如相似日志采集,将单次redis命令的操作/后果/耗时等统计,异步音讯发送给采集音讯队列,毛病就是对代码造成入侵,个别能够交给中间件加在本人包的redis二方包中;如果有做的好一点的Daas平台,能够在proxy层做监控,业务无需感知,对立在Daas平台查看redis监控。 ...

April 9, 2023 · 1 min · jiezi

关于redis:一文讲透-Redis-事务-事务模式-VS-Lua-脚本

精确的讲,Redis 事务蕴含两种模式 : 事务模式 和 Lua 脚本。 先说论断: Redis 的事务模式具备如下特点: 保障隔离性;无奈保障持久性;具备了肯定的原子性,但不反对回滚;一致性的概念有一致,假如在一致性的外围是束缚的语意下,Redis 的事务能够保障一致性。但 Lua 脚本更具备实用场景,它是另一种模式的事务,他具备肯定的原子性,但脚本报错的状况下,事务并不会回滚。Lua 脚本能够保障隔离性,而且能够完满的反对前面的步骤依赖后面步骤的后果。 Lua 脚本模式的身影简直无处不在,比方分布式锁、提早队列、抢红包等场景。 1 事务原理Redis 的事务蕴含如下命令: 序号命令及形容1MULTI 标记一个事务块的开始。2EXEC 执行所有事务块内的命令。3DISCARD 勾销事务,放弃执行事务块内的所有命令。4WATCH key [key ...] 监督一个(或多个) key ,如果在事务执行之前这个(或这些) key 被其余命令所改变,那么事务将被打断。5UNWATCH 勾销 WATCH 命令对所有 key 的监督。事务蕴含三个阶段: 事务开启,应用 MULTI , 该命令标记着执行该命令的客户端从非事务状态切换至事务状态 ;命令入队,MULTI 开启事务之后,客户端的命令并不会被立刻执行,而是放入一个事务队列 ;执行事务或者抛弃。如果收到 EXEC 的命令,事务队列里的命令将会被执行 ,如果是 DISCARD 则事务被抛弃。上面展现一个事务的例子。 redis> MULTI OK redis> SET msg "hello world" QUEUED redis> GET msg QUEUED redis> EXEC 1) OK 1) hello world这里有一个疑难?在开启事务的时候,Redis key 能够被批改吗?在事务执行 EXEC 命令之前 ,Redis key 仍然能够被批改。在事务开启之前,咱们能够 watch 命令监听 Redis key 。在事务执行之前,咱们批改 key 值 ,事务执行失败,返回 nil 。 通过下面的例子,watch 命令能够实现相似乐观锁的成果 。 ...

April 9, 2023 · 4 min · jiezi

关于redis:redis是如何加载配置文件的源码阅读详细介绍

一 从一条命令说起之配置文件当咱们谈到 Redis 服务端启动程序时,可能有很多人会想到 redis-server 这个命令。作为 Redis 的外围组件,redis-server 不仅仅是 Redis 服务端启动的命令,还包含了 Redis 的许多配置选项和性能。在这篇博客中,咱们将从这个简略的命令动手,一步步理解 Redis 服务端启动的过程和相干的配置选项。无论你是 Redis 初学者还是有肯定教训的开发者,置信这篇博客都会对你有所启发和帮忙。 1 redis-serverredis-server 是 Redis 的服务端启动程序。它通过监听端口,接管客户端发送的申请,并执行相应的 Redis 命令。在默认状况下,redis-server 启动后会监听 127.0.0.1:6379 这个地址和端口,这意味着只有本地可能连贯到 Redis 服务器。 redis-server 命令能够带有多个参数和选项,用于配置 Redis 服务器的不同性能和行为。例如,你能够通过 -p 选项来指定 Redis 监听的端口,通过 -a 选项来设置 Redis 拜访明码等等。这些选项和参数将在后续的博客中逐个介绍。 在启动 redis-server 命令之前,你须要确保曾经装置了 Redis,并且 Redis 的配置文件曾经正确配置。如果你还没有装置 Redis,能够参考官网文档进行装置和配置。 1.1 redis配置文件(简略介绍)Redis 配置文件是一个文本文件,蕴含了 Redis 服务器的配置选项和参数。在启动 Redis 服务器时,能够通过命令行参数指定配置文件的门路,例如: ┌──(root㉿kali)-[/opt/local/myconfig]└─# redis-server redis.conf┌──(root㉿kali)-[/opt/local/myconfig]└─# ps aux |grep redis-serverroot 8632 0.5 0.1 55480 10268 ? Ssl 14:59 0:00 redis-server 127.0.0.1:6379通过ps aux命令咱们能够很分明的看到redis服务器曾经启动且其监听在本机的6379的端口号上。 ...

April 8, 2023 · 11 min · jiezi

关于redis:Redis部署方案

筹备工作1、创立用户和配置环境参数(1)、创立用户和创立所需目录[root@redis ~]# groupadd redis[root@redis ~]# useradd -d /home/redis -g redis -m redis[root@redis ~]# chmod 755 /home/redis[root@redis ~]# mkdir -p /home/redis/software[root@redis ~]# mkdir -p /home/redis/yunwei[root@redis ~]# chown -R redis:redis /home/redis[root@redis ~]# mkdir -p /logs/redis[root@redis ~]# chown -R redis:redis /logs/redis2、下载https://github.com/redis/redis/archive/7.0.10.tar.gz3、部署(0)、配置Python3环境https://segmentfault.com/a/1190000043636349(1)、解压安装包[redis@redis ~]$ tar zxf $HOME/software/redis-7.0.10.tar.gz -C $HOME/software[redis@redis ~]$ cd $HOME/software/redis-7.0.10/[redis@redis redis-7.0.10]$ make[redis@redis redis-7.0.10]$ make install PREFIX=$HOME/redis-7.0.10(2)、创立所需目录并拷贝配置文件[redis@redis ~]$ mkdir -p /logs/redis/7379/{logs,data}[redis@redis ~]$ touch /logs/redis/7379/logs/redis_7379.log[redis@redis ~]$ mkdir $HOME/redis-7.0.10/conf[redis@redis ~]$ cp $HOME/software/redis-7.0.10/redis.conf $HOME/redis-7.0.10/conf/[redis@redis ~]$ cp $HOME/redis-7.0.10/conf/redis.conf $HOME/redis-7.0.10/conf/redis.conf_init4、调整配置文件(0)、调整零碎参数# 须要依据理论状况调整sysctl.conf文件参数[root@redis ~]# vi /etc/sysctl.conf vm.overcommit_memory = 1net.core.somaxconn = 1024# 刷新sysctl配置[root@redis ~]# sysctl -p# 调整零碎分页参数[root@redis ~]# vi /etc/security/limits.confredis soft nofile 10032redis hard nofile 10032redis soft nproc 65535redis hard nproc 65535(1)、依据理论状况调整 redis.conf 配置文件[redis@redis ~]$ vi $HOME/redis-7.0.10/conf/redis.confbind 192.168.19.150port 7379# 内存大小依据理论状况设置maxmemory 8gdaemonize yeslogfile "/logs/redis/7379/logs/redis_7379.log"pidfile /logs/redis/7379/redis_6379.pid# 明码请设置强明码masterauth *******requirepass *******(2)、启动命令[redis@redis ~]$ cd redis-7.0.10/bin/[redis@redis bin]$ ./redis-server ../conf/redis.conf5、起停服务与创立对应脚本(1)、 创立启动服务脚本[redis@redis ~]$ vi $HOME/yunwei/redis-7.0.10_start.sh#!/bin/bashcd $HOME/redis-7.0.10/bin/./redis-server ../conf/redis.conf(2)、 创立进行服务脚本[redis@redis ~]$ vi $HOME/yunwei/redis-7.0.10_stop.sh#!/bin/bashredis_pid=`ps -ef|grep redis-server|grep -v grep|awk '{print $2}'`kill -9 $redis_pid

April 8, 2023 · 1 min · jiezi

关于redis:Redis入门

历史倒退MySQL单机演变单机读写压力,次要是读压力,所以须要多台服务器。 当今企业架构数据服务也是以集群模式存在 NoSQL键值文档图社交、搜寻 列数据阿里巴巴的架构演进Redis简介key-value存储系统,非关系型数据库,由ANSI C (动静C语言)编写。 特点装置Redisubuntu18.04装置间接参照菜鸟教程即可 Redis下的配置文件redis.conf在启动时须要应用命令redis-server xxx.confxxx.conf就是咱们的配置文件,前面尝试主从复制时须要复制一份原文件(单机伪集群)我将这个文件放在了/usr/local/bin目录下通过 nstat -ntlp|grep 6379来查看端口号通过 ps -f|grep redis 性能测试redis-benchmarkredis-benchmark -n 10000 -q 近程连贯redis-cli -h host -p port -a password Redis 数据类型键抉择数据库默认有16个数据库,select index 查看以后数据库大小dbsize 分明以后数据库清空以后数据库 flushdb|清空所有数据库 flushall 查看是否存在EXIST key 查看所有键key * 删除keydel key1 设置生效工夫expire key 10 查看以后key的剩余时间ttl key 查看指定key的类型type key String应用场景计数器统计多单位的数量粉丝数对象缓存存储 设置值set k1 v1 取得值get k1 追加字符串append k1 hello 如果不存在就相当于set 获取字符串长度strlen k1 自增和自减incr views|decr views 设置步长自增自减incrby views 10| decrby views 10 截取字符串getrang k1 0 3(获取字符串[0,3]的元素) ...

April 5, 2023 · 2 min · jiezi

关于redis:Redis持久化

Redis作为一个内存数据库数据都存储在内存中,如果服务器重启那么内存中的数据将会失落。如果Redis作为缓存失落了数据没关系,能够从新加载;但如果是作为数据库,数据是相对不能失落的。那么存储层的长久化无非两种,一种是快照/正本,另外一种就是日志。Redis同样为了防止数据失落提供了不同级别的的长久化形式,别离是RDB和AOF。上面咱们对两种长久化形式剖析了解。 RDBRDB是一种全量的数据快照,是可能在指定工夫距离对你的数据进行快照存储,默认的存储文件是dump.rdb 。在Redis服务重启时,会加载该文件将数据恢复到内存中。 应用RDB应用的形式有三种。第一种是应用save命令生成dump.rdb 文件;第二种是应用bgsave 命令生成dump.rdb 文件;第三种则是在配置文件中进行配置条件触发生成dump.rdb文件。 save命令客户端输出save命令进行长久化申请是一种同步形式。这种形式的毛病在于当执行该命令时,Redis服务端会阻塞其余写申请直至实现同步。因而不倡议在生产环境应用,因为若数据量较大,同步则会耗时很久。罕用在后续不会再接管写申请时应用,例如服务停机保护等场景。 bgsave命令bgsave 命令看起来和save 命令很类似,但bgsave命令是一种异步形式。这种形式不同于save的是Redis会forks出一个子过程进行数据长久化,父过程持续接管申请,当执行结束同步子线程敞开。 配置文件触发配置文件(redis.conf)中配置条件触发生成dump.rdb文件实际上也是执行bgsave 命令,换句话说就是 配置触发bgsave的规定,咱们看看默认的规定: ## 900秒至多1次写的命令save 900 1## 300秒至多10次写的命令save 300 10## 60秒至多10000次写的命令save 60 10000这种形式的毛病就是如果工夫距离管制太大会造成数据失落,但太小又会导致频繁长久化,影响性能。配置文件除了触发配置,rdb文件还存在一些根底配置,如下所示: ## 是否压缩rdb文件rdbcompression yes## 如果为yes则示意,当备份过程出错的时候,主过程就进行进行承受新的写入操作## 这样是为了爱护长久化的数据一致性的问题。stop-writes-on-bgsave-error yes## rdb文件的名称(单机不同端口启动服务器)dbfilename dump.rdb## rdb文件保留目录dir /path/to/dump工作形式当 Redis 须要保留dump.rdb 文件时, 服务器执行以下操作: Redis 调用forks同时领有父过程和子过程。子过程将数据集写入到一个长期 RDB 文件中。当子过程实现对新 RDB 文件的写入时,Redis 用新 RDB 文件替换原来的 RDB 文件,并删除旧的 RDB 文件。这种工作形式使得 Redis 能够从写时复制(copy-on-write)机制中获益。 Copy-On-Write:如果有多个调用者同时要求雷同资源(如内存或磁盘上的数据存储),他们会独特获取雷同的指针指向雷同的资源,直到某个调用者试图批改资源的内容时,零碎才会真正复制一份专用正本给调用者,而其它调用者所见到的最后的资源依然放弃不变。长处RDB文件十分紧凑,它保留了某个工夫点的数据集,适宜数据备份;应用fork出子过程,能够最大水平的应用redis的性能;RDB长久化相似java中的序列化,复原速度相比AOF来的快。 毛病会造成数据失落,因为在两个存储工夫点A和B之间Redis宕机,那么这个工夫窗口内的数据就会因为还没来得及存储而造成失落;bgsave 命令须要fork出子过程,当数据集较大时,fork的过程是十分耗时的,可能会导致Redis在一些毫秒级内不能响应客户端的申请。AOFAOF是一种增量的模式追加记录每次对服务器写的操作,默认的存储文件appendonly.aof,是当服务器重启的时候会从新执行这些命令来复原原始的数据。 留神这里并不是间接存储Redis的写命令,而是这些写入操作以 Redis 协定的格局保留, 因而 AOF 文件的内容非常容易被人读懂, 对文件进行剖析(parse)也很轻松。应用AOF的应用须要在配置文件中开启,默认是不开启AOF长久化的形式,配置文件对于AOF的配置如下所示: ## 是否开启AOF yes为开启 no为不开启appendonly yes## aof文件的名称appendfilename appendonly.aof## 三种写入策略## always 每一个写申请写入AOF文件 即时将缓冲区内容写入AOF文件appendfsync always## everysec 每隔一秒写入AOF文件 每隔一秒将缓冲区内容写入AOF文件 默认策略appendfsync everysec## no 不负责写入AOF文件 交由操作系统决定 ## 一般来说,操作系统思考效率问题,会期待缓冲区被填满再将缓冲区数据写入AOF文件中appendfsync no长处Redis能够应用三种不同的fsync策略,数据不容易失落。AOF文件是一个只进行追加的日志文件,对服务器性能影响小。 ...

March 30, 2023 · 2 min · jiezi

关于redis:Redis高频40问

Redis连环40问,相对够全! Redis是什么?Redis(Remote Dictionary Server)是一个应用 C 语言编写的,高性能非关系型的键值对数据库。与传统数据库不同的是,Redis 的数据是存在内存中的,所以读写速度十分快,被广泛应用于缓存方向。Redis能够将数据写入磁盘中,保障了数据的平安不失落,而且Redis的操作是原子性的。 Redis优缺点?长处: 基于内存操作,内存读写速度快。反对多种数据类型,包含String、Hash、List、Set、ZSet等。反对长久化。Redis反对RDB和AOF两种长久化机制,长久化性能能够无效地防止数据失落问题。反对事务。Redis的所有操作都是原子性的,同时Redis还反对对几个操作合并后的原子性执行。反对主从复制。主节点会主动将数据同步到从节点,能够进行读写拆散。Redis命令的解决是单线程的。Redis6.0引入了多线程,须要留神的是,多线程用于解决网络数据的读写和协定解析,Redis命令执行还是单线程的。毛病: 对结构化查问的反对比拟差。数据库容量受到物理内存的限度,不适宜用作海量数据的高性能读写,因而Redis适宜的场景次要局限在较小数据量的操作。Redis 较难反对在线扩容,在集群容量达到下限时在线扩容会变得很简单。Redis为什么这么快?基于内存:Redis是应用内存存储,没有磁盘IO上的开销。数据存在内存中,读写速度快。IO多路复用模型:Redis 采纳 IO 多路复用技术。Redis 应用单线程来轮询描述符,将数据库的操作都转换成了事件,不在网络I/O上节约过多的工夫。高效的数据结构:Redis 每种数据类型底层都做了优化,目标就是为了谋求更快的速度。本文曾经收录到Github仓库,该仓库蕴含计算机根底、Java根底、多线程、JVM、数据库、Redis、Spring、Mybatis、SpringMVC、SpringBoot、分布式、微服务、设计模式、架构、校招社招分享等外围知识点,欢送star~ Github地址:https://github.com/Tyson0314/Java-learning 如果拜访不了Github,能够拜访gitee地址。 gitee地址:https://gitee.com/tysondai/Java-learning 既然Redis那么快,为什么不必它做主数据库,只用它做缓存?尽管Redis十分快,但它也有一些局限性,不能齐全代替主数据库。有以下起因: 事务处理:Redis只反对简略的事务处理,对于简单的事务无能为力,比方跨多个键的事务处理。 数据长久化:Redis是内存数据库,数据存储在内存中,如果服务器解体或断电,数据可能失落。尽管Redis提供了数据长久化机制,但有一些限度。 数据处理:Redis只反对一些简略的数据结构,比方字符串、列表、哈希表等。如果须要解决简单的数据结构,比方关系型数据库中的表,那么Redis可能不是一个好的抉择。 数据安全:Redis没有提供像主数据库那样的平安机制,比方用户认证、访问控制等等。 因而,尽管Redis十分快,但它还有一些限度,不能齐全代替主数据库。所以,应用Redis作为缓存是一种很好的形式,能够进步应用程序的性能,并缩小数据库的负载。 讲讲Redis的线程模型?Redis基于Reactor模式开发了网络事件处理器,这个处理器被称为文件事件处理器。它的组成构造为4局部:多个套接字、IO多路复用程序、文件事件分派器、事件处理器。因为文件事件分派器队列的生产是单线程的,所以Redis才叫单线程模型。 文件事件处理器应用I/O多路复用(multiplexing)程序来同时监听多个套接字, 并依据套接字目前执行的工作来为套接字关联不同的事件处理器。当被监听的套接字筹备好执行连贯accept、read、write、close等操作时, 与操作绝对应的文件事件就会产生, 这时文件事件处理器就会调用套接字之前关联好的事件处理器来解决这些事件。尽管文件事件处理器以单线程形式运行, 但通过应用 I/O 多路复用程序来监听多个套接字, 文件事件处理器既实现了高性能的网络通信模型, 又能够很好地与 redis 服务器中其余同样以单线程形式运行的模块进行对接, 这放弃了 Redis 外部单线程设计的简略性。 Redis利用场景有哪些?缓存热点数据,缓解数据库的压力。利用 Redis 原子性的自增操作,能够实现计数器的性能,比方统计用户点赞数、用户拜访数等。分布式锁。在分布式场景下,无奈应用单机环境下的锁来对多个节点上的过程进行同步。能够应用 Redis 自带的 SETNX 命令实现分布式锁,除此之外,还能够应用官网提供的 RedLock 分布式锁实现。简略的音讯队列,能够应用Redis本身的公布/订阅模式或者List来实现简略的音讯队列,实现异步操作。限速器,可用于限度某个用户拜访某个接口的频率,比方秒杀场景用于避免用户疾速点击带来不必要的压力。好友关系,利用汇合的一些命令,比方交加、并集、差集等,实现独特好友、共同爱好之类的性能。最全面的Java面试网站Memcached和Redis的区别?MemCached 数据结构繁多,仅用来缓存数据,而 Redis 反对多种数据类型。MemCached 不反对数据长久化,重启后数据会隐没。Redis 反对数据长久化。Redis 提供主从同步机制和 cluster 集群部署能力,可能提供高可用服务。Memcached 没有提供原生的集群模式,须要依附客户端实现往集群中分片写入数据。Redis 的速度比 Memcached 快很多。Redis 应用单线程的多路 IO 复用模型,Memcached应用多线程的非阻塞 IO 模型。(Redis6.0引入了多线程IO,用来解决网络数据的读写和协定解析,然而命令的执行依然是单线程)value 值大小不同:Redis 最大能够达到 512M;memcache 只有 1mb。为什么要用 Redis 而不必 map/guava 做缓存?应用自带的 map 或者 guava 实现的是本地缓存,最次要的特点是轻量以及疾速,生命周期随着 jvm 的销毁而完结,并且在多实例的状况下,每个实例都须要各自保留一份缓存,缓存不具备一致性。 ...

March 28, 2023 · 4 min · jiezi

关于redis:Redis五种值类型

Redis中存在五种值类型,别离是string(字符串),list(列表),hash(散列),set(汇合)和sorted set(有序汇合)。上面咱们对每一种值类型进行剖析了解。 RedisObject在介绍redis值类型之前,咱们得先理解一下redisObject。redisObject是redis中封装value对象的数据结构。任何一个value都会被包装成一个redisObject。redisObject能指定value的类型,编码格局,内存回收,数据指针等。这样设计的益处是在5种罕用类型设置多种不同的的数据结构实现,优化对象在不同场景下的效率。 typedef struct redisObject { // 刚刚好32 bits // 对象的类型,字符串/列表/汇合/哈希表 unsigned type:4; // 未应用的两个位 unsigned notused:2; /* Not used */ // 编码的形式,Redis 为了节俭空间,提供多种形式来保留一个数据 // 譬如:“123456789” 会被存储为整数123456789 unsigned encoding:4; // 当内存缓和,淘汰数据的时候用到 unsigned lru:22; /* lru time (relative to server.lruclock) */ // 援用计数 int refcount; // 数据指针 void *ptr;} robj这里介绍几个比拟要害的属性: type:标记了value对象的数据类型,应用type 命令来获取。所有数据类型如下所示: /* Object types */#define REDIS_STRING 0#define REDIS_LIST 1#define REDIS_SET 2#define REDIS_ZSET 3#define REDIS_HASH 4encoding:标记了value对象的编码,也就是应用了什么数据结构,应用 object encoding 命令来获取。编码如下所示:/* Objects encoding. Some kind of objects like Strings and Hashes can be* internally represented in multiple ways. The 'encoding' field of the object* is set to one of this fields for this object. */#define REDIS_ENCODING_INT /* Encoded as integer */#define REDIS_ENCODING_EMBSTR /* Encoded as embstr */#define REDIS_ENCODING_RAW /* Raw representation */#define REDIS_ENCODING_HT /* Encoded as hash table */#define REDIS_ENCODING_LINKEDLIST /* Encoded as regular linked list */#define REDIS_ENCODING_ZIPLIST /* Encoded as ziplist */#define REDIS_ENCODING_INTSET /* Encoded as intset */#define REDIS_ENCODING_SKIPLIST /* Encoded as skiplist */ redis为优化内存,对数据类型提供了多种底层实现形式,type和encoding对应关系如下表格所示: ...

March 27, 2023 · 9 min · jiezi

关于redis:故障分析-Redis-主从复制风暴

作者:贲绍华 爱可生研发核心工程师,负责我的项目的需要与保护工作。其余身份:柯基铲屎官。 本文起源:原创投稿 *爱可生开源社区出品,原创内容未经受权不得随便应用,转载请分割小编并注明起源。 一、主从复制简介Redis 主从架构下,应用默认的异步复制模式来同步数据,其特点是低提早和高性能。当 Redis master 下有多个 slave 节点,且 slave 节点无奈进行局部重同步时, slave 会申请进行全量数据同步,此时 master 须要创立 RDB 快照快照发送给 slave ,从节点收到 RDB 快照到开始解析与加载。 二、主从复制风暴在复制重建的过程中,slave 节点加载 RDB 还未实现,却因为一些起因导致失败了,slave 节点此时又会再次发动全量同步 RDB 的申请,周而复始。当多个 slave 节点同时循环申请时,导致了复制风暴的呈现。 三、问题景象3.1 CPU:master 节点会异步生成 RDB 快照,数据量十分大时 fork 子过程十分耗时,同时 CPU 会飙升,且会影响业务失常响应。 3.2 磁盘:从 Redis 2.8.18 版本开始,反对无磁盘复制,异步生成的RDB快照将在子过程中间接发送 RDB 快照至 slave 节点,多个 slave 节点共享同一份快照。所以磁盘 IO 并不会出现异常。 3.3 内存与网络:因为 RDB 是在内存中创立与发送,当复制风暴发动时,master 节点创立RDB快照后会向多个 slave 节点进行发送,可能使 master 节点内存与网络带宽耗费重大,造成主节点的提早变大,极其状况会产生主从节点之间连贯断开,导致复制失败。slave 节点在失败重连后再次发动新一轮的全量复制申请,陷入恶性循环。 四、呈现的场景单master节点(主机上只有一台redis实例)当机器产生故障导致网络中断或重启复原时。多master节点在同一台机器上,当机器产生故障导致网络中断或重启复原时。大量slave节点同时重启复原。复制缓冲区过小,缓冲区的下限是由client-output-buffer-limit配置项决定的,当slave还在复原RDB快照时,master节点继续产生数据,缓冲区如果被写满了,会导致slave节点连贯断开,再次发动重建复制申请。发动全量复制->复制缓冲区溢出->连贯中断->重连->发动全量复制->复制缓冲区溢出->连贯中断->重连...网络长时间中断导致的连贯异样:跨机房、跨云、DNS解析异样等导致的主从节点之间连贯失落。主从节点判断超时(触发了repl-timeout),且失落的数据过多,超过了复制积压缓冲区所能存储的范畴。数据量过大,生成RDB快照的fork子过程操作耗时过长,导致slave节点长时间收不到数据而触发超时,此时slave节点会重连master节点,再次申请进行全量复制,再次超时,再次重连。五、解决方案5.1 升高存储下限Redis 实例的存储数据的下限不要过大,过高的状况下会影响 RDB 落盘速度、向 slave 节点发送速度、slave 节点复原速度。 ...

March 23, 2023 · 1 min · jiezi

关于redis:当你对-redis-说你中意的女孩是-Mia

作者:京东科技 周新智 一、Redis家喻户晓,Redis = Remote Dictionary Server,即近程字典服务。 是一个开源的应用ANSI C语言编写、反对网络、可基于内存亦可长久化的日志型、Key-Value数据库,并提供多种语言的API。 二、当你对 redis 说你中意的女孩是 Mia 时1、set myLove Miaredis 会将 key:myLove value:Mia 包装成一个 dictEntry 对象、一个 redisObject 对象,如下图所示: •dictEntry:家喻户晓,Redis是Key-Value数据库,因而对每个键值对都会有一个dictEntry,外面存储了指向Key和Value的指针;next指向下一个dictEntry,与本Key-Value无关。 •Key:图中右上角可见,Key("myLove")并不是间接以字符串存储,而是存储在SDS构造中。 •redisObject:Value("Mia")既不是间接以字符串存储,也不是像Key一样间接存储在SDS中,而是存储在redisObject中。实际上,不管Value是5种类型的哪一种,都是通过redisObject来存储的;而redisObject中的type字段指明了Value对象的类型,ptr字段则指向对象所在的地址。不过能够看出,字符串对象尽管通过了redisObject的包装,但依然须要通过SDS存储。 1.1、对 myLove 进行对象封装1.1.1、dictEntryredis外部整体的存储构造是一个大的hashmap,外部是数组实现的hash,key抵触通过挂链表去实现,每个dictEntry为一个key/value对象,value为定义的redisObject。 结构图如下: dictEntry是存储key->value的中央,再让咱们看一下dictEntry构造体 /* * 字典 */typedef struct dictEntry { // 键 void *key; // 值 union { // 指向具体redisObject void *val; // uint64_t u64; int64_t s64; } v; // 指向下个哈希表节点,造成链表 struct dictEntry *next;} dictEntry;1.1.2、对象封装 redisObject咱们接着再往下看redisObject到底是什么构造的 /* * Redis 对象 */typedef struct redisObject { // 类型 4bits unsigned type:4; // 编码方式 4bits unsigned encoding:4; // LRU 工夫(绝对于 server.lruclock) 24bits unsigned lru:22; // 援用计数 Redis外面的数据能够通过援用计数进行共享 32bits int refcount; // 指向对象的值 64-bit void *ptr;} robj;*ptr指向具体的数据结构的地址;type示意该对象的类型,即String,List,Hash,Set,Zset中的一个,但为了进步存储效率与程序执行效率,每种对象的底层数据结构实现都可能不止一种,encoding 示意对象底层所应用的编码。 ...

March 23, 2023 · 2 min · jiezi

关于redis:硬核推荐知乎上万转发的102W字Redis高手心法笔记

天下文治,⽆坚不可摧,唯快不破!学习⼀个技术,通常只接触了零散的技术点,没有在脑海⾥建⽴⼀个残缺的常识框架和架构体系,没有零碎观。这样会很吃力,而且会呈现⼀看如同本人会,过后就遗记,一脸懵逼。 明天跟着小编⼀起吃透 Redis,深层次的把握 Redis 核⼼原理以及实战技巧。⼀起搭建⼀套残缺的常识框架,学会全局观去整顿整个常识体系。 零碎观其实是⾄关重要的,从某种程度上说,在解决问题时,领有了零碎观,就意味着你能有根据、有章法地定位和解决问题 Redis 全景图全景图能够围绕两个纬度开展,别离是: 应⽤维度:缓存使⽤、集群运⽤、数据结构的奇妙使⽤ 零碎维度:能够归类为三⾼ 1. ⾼性能:线程模型、⽹络 IO 模型、数据结构、长久化机制;2. ⾼可⽤:主从复制、哨兵集群、Cluster 分⽚集群;3. ⾼拓展:负载平衡Redis 系列篇章围绕如下思维导图开展,这次从 《Redis 唯快不破的机密》⼀起摸索 Redis 的外围知识点 思维导图及以下内容收费分享,感兴趣的话请帮忙点赞转发下,【点击此处】即可收费获取残缺文档! Redis高可用主从架构同步原理Sentinel哨兵集原理分析Cstes反对的数据最有下限么?原理 Redis 6/6.xSentinel哨兵集群搭建Cluster集群搭建带你100%把握多线程模型客户端缓存个性实现二级缓存 Redis实战篇巧用Bitmap实现亿级海量数据统计GEO数据类型实现左近的人缓存击穿(生效)、缓存穿透、 缓存雪崩如何解决? Redis面霸从高频问题透视外围原理 其余Redis很弱小,不懂应用标准就糟践了Redis事务反对ACID么?Redis分布式锁,从小白进化为大神计划都经验了什么?Redis应用List实现音讯队列能保障音讯可靠性么?Redis突然变慢了如何排查并解决?Redis为什么这么快Redis长久化: AOF和RDB实现长久化并保证数据牢靠巧用Redis数据结构实现亿级数据统计Redis List实现音讯队列Out了,Redis Stream专为队列而生Redis布隆(Bloom Filter)过滤器原理与实战解说Redis HyperLogLog是什么?这些场景应用它,让我枪出如龙,一笑破天穹 笔记内容过多,为了不影响大家的浏览体验,展现到这里就完结了,想要获取学习的搭档,能够点赞转发下,【点击此处】即可收费获取残缺文档!

March 22, 2023 · 1 min · jiezi

关于redis:Redis四种部署模式的介绍及其优缺点

一、前言说到Redis的部署模式,很多同学第一工夫想到的就是Redis Cluster集群模式,因为它可能是当初的支流模式。但其实这几种模式各有优劣,理论环境中咱们应该抉择适合的部署模式,否则事与愿违,接下来简略介绍一下这几种部署模式 二、部署模式2.1 单机模式单机模式就是只有单个redis提供服务,如下图 长处: 架构简略,易于保护毛病: 单台服务器内存空间无限,无奈寄存太多的数据量存在单点故障读写压力较大单机模式实用于内部测试、我的项目规模小的场景 2.2 主从模式因为单个redis节点的读写压力较大,所以引出了主从复制形式,可实现读写拆散,读操作能够由slave节点来反对,升高master节点的压力。如下图 主从复制是redis实现高可用的基石,后续的两种高可用计划 哨兵模式 或者 cluster集群模式 都须要有主从复制的撑持。长处: 读写拆散。通过读写拆散来升高master节点的压力领有多个数据正本毛病: 单个master内存空间无限,无奈寄存太多的数据量仍然只有master节点能够解决写申请,存在瓶颈当master节点产生故障下线时,须要人工地将某个slave节点切换为新的master节点,并且客户端须要切换到连贯新的master节点主从模式实用于外部性能测试、我的项目规模小的场景 2.3 哨兵模式哨兵模式是在主从复制的根底上,增加哨兵(实际上就是个redis的利用过程)来监控master节点和slave节点,当master节点产生故障下线时,哨兵主动地将某个slave节点切换为master节点,且客户端不须要去切换连贯新的master节点。(个别须要部署哨兵集群,避免哨兵的单点故障) 长处: 读写拆散。通过读写拆散来升高master节点的压力领有多个数据正本主动故障转移。当master节点产生故障下线时,哨兵主动地将某个slave节点切换为新的master节点,并且客户端不须要切换连贯新的master节点(因为客户端连贯哨兵集群,而不间接连贯master节点)毛病: 单个master内存空间无限,无奈寄存太多的数据量仍然只有master节点能够解决写申请,存在瓶颈哨兵模式实用于生产环境、我的项目规模中等的场景 2.3.1 故障转移 failover当master节点下线之后,哨兵主动将slave节点切换为新的master节点,这一过程称为故障转移(failover)。故障转移的大抵步骤如下: 检测master是否主观下线sentinel每隔1秒钟,向所有的master、slave、sentinel发送ping命令,通过其余服务器的回复来判断是否在线(当ping的实例在间断down-after-milliseconds配置的工夫内返回有效命令或无响应,则以后sentinel认为其主观下线,对所有master、slave、sentinel都实用)检测master是否主观下线以后sentinel要想判断master是否主观下线,须要询问其余sentinel,并且认为master主观下线的总数须要达到quorum配置的值,则以后sentinel将该master标记为主观下线选举哨兵leader以后sentinel将该master标记为主观下线后,会给其余sentinel再发送命令,其余sentinel收到申请后将其设置为leader(这个设置是先到先得的,sentinel先收到谁的设置申请,就将谁设置为leader)。发送命令的sentinel会依据其余sentinel回复的后果来判断本人是否被该sentinel设置为leader,如果以后sentinel被其余sentinel设置为leader的数量超过半数sentinel,那么以后sentinel会认为本人曾经成为leader,并开始后续故障转移工作。如果没有任何一个sentinel达到成为leader的要求,将会从新选举直到产生leader为止故障转移由哨兵leader全权负责从slave列表中抉择最佳的slave作为新的master。让其余slave复制新的master,并且持续监听旧master,如果其上线,将其设置为新的master的slave2.4 集群模式既然哨兵模式曾经具备了高可用性,为什么还须要cluster模式?因为哨兵模式还是没有解决只有master节点能够解决写的问题,仍然存在写瓶颈。而cluster集群模式应用"分片"(每个master解决一部分slot)的模式来解决所有key,能够有多个master来解决写操作,从而来解决写瓶颈问题。如下图 长处: 主动故障转移。当某个master节点产生故障下线时,集群主动地将其对应的某个slave节点代替它当现有redis集群不足以撑持整个零碎的压力时,能够横向拓展集群毛病: 无奈执行批量操作,如mget当redis节点很多的时候,因为每个节点都须要跟其余节点通信,整个集群的性能会升高保护老本较高redis cluster模式实用于生产环境、我的项目规模大型的场景 2.4.1 故障转移 failover与哨兵模式一样,从节点的故障并不会影响集群工作,对应的主节点只会记住本人的哪个从节点下线了,当从节点重连后,会持续复制主节点的数据。 只有主节点故障才须要故障转移。cluster集群模式不须要哨兵,本身已具备了故障转移性能。因为集群内的每个节点都会相互进行通信,节点之间通过gossip协定进行通信,通过这种机制来发现故障并进行故障转移。然而要达到故障转移,须要解决几个问题? 故障发现:如何判断某个master节点故障了?redis采纳少数投票的计划选取slave节点:master有多个slave节点的时候,应该抉择哪个slave节点成为新的master故障发现和哨兵模式相似,故障发现也经验两个阶段:PFAIL(主观下线)和FAIL(主观下线)。假如当初有3个master节点,别离为节点1,节点2,节点3。比方节点1判断节点3下线,那么它会标记节点3的状态为PFAIL,节点1会通过gossip协定把这个信息发送给其余节点,接管到信息的节点会进行对节点3主观下线的状态断定。当集群中有超过半数的节点认为节点3处于PFAIL,那么节点1就断定节点3为FAIL,并立刻向集群所有节点(包含节点3的子节点)播送这个信息。 故障转移当节点3的slave发现自己的master变为fail状态时,便尝试进行故障转移failover,以成为新的master。因为一个master可能有多个slave,所以这些slave须要竞争成为master节点,过程如下: slave1、slave2都发现自己的master状态变为fail它们将本人记录的集群currentEpoch(选举周期)加1,并应用gossip协定播送failover_auth_request信息其余master节点收到slave1和slave2的音讯,会给slave1或slave2发送failover_auth_ack,在一个选举周期中,一个master只会响应第一个给它发消息的slaveslave们收集返回的failover_auth_ack,当收到超过半数的master的ack音讯后变成新的master最初向整个集群播送当初本人是master,同时负责旧master所有slots的信息其余节点接管到信息后,更新本人的保护状态三、总结redis的部署模式介绍到这里,总体看下来redis cluster集群模式的利大于弊,所以在较大规模的我的项目中个别应用该模式,但在中小规模的我的项目中,抉择主从模式 或 哨兵模式亦可。

March 16, 2023 · 1 min · jiezi

关于redis:IO多路复用和多线程会影响Redis分布式锁吗

前言前置常识 Redis 尽管是单线程的,然而它利用了内核的 IO 多路复用,从而能同时监听多个连贯Redis6 呈现了能够利用多个 IO 线程并发进行的操作那么问题来了,这两者会导致咱们的分布式锁的原子性有影响吗? 咱们晓得当咱们应用 redis 作为分布式锁的时候,通常会应用 SET key value EX 10 NX 命令来加锁,取得锁的客户端能力胜利 SET 这个 key,那么问题来了,这条命令在多线程的状况下是一个原子操作吗? 其实答案是不言而喻的,因为 redis 的设计者必定思考到了向前兼容的问题,并且也不会让这样的个性隐没,所以在问这个问题以前,我尽管不能必定,然而还是能自信的答复,但没有足够的底气。 明天的指标就是找到真正的起因。问题的两个方面上锁上锁,没啥多说的间接 SET key value EX 10 NX 就能够了 解锁解锁,有两种: 一种是客户端自行保障锁只有本人拿本人解,那么间接让本人去 DEL 就能够了另一种是不信赖客户端,那么能够应用 lua 脚本,先通过 get 确定对应 key 的值是否正确,如果正确再 del,整个 lua 脚本通过 EVAL 执行只有上锁和解锁操作都能保障,就能解决问题。 执行命令的过程那么问题的要害就是命令的执行过程,Redis 执行命令也是须要有过程的,客户端一个命令过去,不会间接就啪的执行了,而是有很多前置条件和步骤。 大抵可分为: 读取解析执行返回其中,命令读取和解析显然是不会影响数据的,所以当然多线程执行也没有问题。最要害的步骤也就是执行了。 IO 多路复用先来看看 IO 多路复用会有影响吗? 代码来自: https://github.com/redis/redis/blob/074e28a46eb2646ab33002731fac6b4fc223b0bb/src/ae_epoll.c#L109 static int aeApiPoll(aeEventLoop *eventLoop, struct timeval *tvp) { aeApiState *state = eventLoop->apidata; int retval, numevents = 0; retval = epoll_wait(state->epfd,state->events,eventLoop->setsize, tvp ? (tvp->tv_sec*1000 + (tvp->tv_usec + 999)/1000) : -1); if (retval > 0) { int j; numevents = retval; for (j = 0; j < numevents; j++) { int mask = 0; struct epoll_event *e = state->events+j; if (e->events & EPOLLIN) mask |= AE_READABLE; if (e->events & EPOLLOUT) mask |= AE_WRITABLE; if (e->events & EPOLLERR) mask |= AE_WRITABLE|AE_READABLE; if (e->events & EPOLLHUP) mask |= AE_WRITABLE|AE_READABLE; eventLoop->fired[j].fd = e->data.fd; eventLoop->fired[j].mask = mask; } } else if (retval == -1 && errno != EINTR) { panic("aeApiPoll: epoll_wait, %s", strerror(errno)); } return numevents;}没事,不要放心看不懂,只有抓住最要害的中央 epoll_wait 这个咱们很相熟对吧,咱们就能够看到这里一次循环拿出了一组 events,这些事件都是一股脑儿过去的。 ...

March 14, 2023 · 3 min · jiezi

关于redis:挑战大型系统的缓存设计应对一致性问题

在实在的业务场景中,咱们业务的数据——例如订单、会员、领取等——都是长久化到数据库中的,因为数据库能有很好的事务保障、长久化保障。然而,正因为数据库要可能满足这么多优良的性能个性,使得数据库在设计上通常难以兼顾到性能,因而往往不能满足大型流量下的性能要求,像是 MySQL 数据库只能承当“千”这个级别的 QPS,否则很可能会不稳固,进而导致整个零碎的故障。 然而主观上,咱们的业务规模很可能要求着更高的 QPS,有些业务的规模自身就十分大,也有些业务会遇到一些流量顶峰,比方电商会遇到大促的状况。 而这时候大部分的流量实际上都是读申请,而且大部分数据也是没有那么多变动的,如热门商品信息、微博的内容等常见数据就是如此。此时,缓存就是咱们应答此类场景的利器。 缓存的意义所谓缓存,实际上就是用空间换工夫,精确地说是用更高速的空间来换工夫,从而整体上晋升读的性能。 何为更高速的空间呢? 1、更快的存储介质。通常状况下,如果说数据库的速度慢,就得用更快的存储介质去代替它,目前最常见的就是Redis。Redis 单实例的读 QPS 能够高达 10w/s,90% 的场景下只须要正确应用 Redis 就能应答。2、就近应用本地内存。就像 CPU 也有高速缓存一样,缓存也能够分为一级缓存、二级缓存。即使 Redis 自身性能曾经足够高了,但拜访一次 Redis 毕竟也须要一次网络 IO,而应用本地内存无疑有更快的速度。不过单机的内存是非常无限的,所以这种一级缓存只能存储十分大量的数据,通常是最热点的那些 key 对应的数据。这就相当于额定耗费贵重的服务内存去换取高速的读取性能。 引入缓存后的一致性挑战用空间换工夫,意味着数据同时存在于多个空间。最常见的场景就是数据同时存在于 Redis 与 MySQL 上(为了问题的普适性,前面举例中若没有特地阐明,缓存均指 Redis 缓存)。 实际上,最权威最全的数据还是在 MySQL 里的,只有 Redis 数据没有失去及时的更新而导致最新数据没有同步到 Redis 中,就呈现了数据不统一。 大部分状况下,只有应用了缓存,就必然会有不统一的状况呈现,只是说这个不统一的工夫窗口是否能做到足够的小。有些不合理的设计可能会导致数据继续不统一,这是咱们须要改善设计去防止的。 缓存不一致性无奈主观地齐全毁灭为什么咱们简直没方法做到缓存和数据库之间的强统一呢? 失常状况下,咱们须要在数据库更新完后,把对应的最新数据同步到缓存中,以便在读申请的时候,能读到新的数据而不是旧的数据(脏数据)。然而很惋惜,因为数据库和 Redis 之间是没有事务保障的,所以咱们无奈确保写入数据库胜利后,写入 Redis 也是肯定胜利的;即使 Redis 写入能胜利,在数据库写入胜利后到 Redis 写入胜利前的这段时间里,Redis 数据也必定是和 MySQL 不统一的。如下图: 所以说这个工夫窗口是没方法齐全毁灭的,除非咱们付出极大的代价,应用分布式事务等各种伎俩去维持强统一,然而这样会使得零碎的整体性能大幅度降落,甚至比不必缓存还慢,这样不就与咱们应用缓存的指标南辕北辙了吗? 不过尽管无奈做到强统一,然而咱们能做到的是缓存与数据库达到最终统一,而且不统一的工夫窗口咱们能做到尽可能短,依照教训来说,如果能将工夫优化到 1ms 之内,这个一致性问题带来的影响咱们就能够忽略不计。 更新缓存的伎俩data = queryDataRedis(key);if (data ==null) { data = queryDataMySQL(key); //缓存查问不到,从MySQL做查问 if (data!=null) { updateRedis(key, data);//查问完数据后更新到MySQL }}也就是说优先查问缓存,查问不到才查询数据库。如果这时候数据库查到数据了,就将缓存的数据进行更新。 这样的逻辑是正确的,而一致性的问题个别不来源于此,而是呈现在解决写申请的时候。所以咱们简化成最简略的写申请的逻辑,此时你可能会面临多个抉择,到底是间接更新缓存,还是生效缓存?而无论是更新缓存还是生效缓存,都能够抉择在更新数据库之前,还是之后操作。 ...

March 12, 2023 · 1 min · jiezi

关于redis:Redis-数据库-介绍安装常用命令

一、概念Redis是一种无关联的、非SQL的、BASE的、以内存为存储形式的、程度扩大的非关系型数据库。而MySQL的数据库是一种关联的、SQL查问的、ACID的、以磁盘存储的、垂直扩大的关系型数据库。 非SQL:各种非关系型数据库没有固定的语法。 无关联的:与关系型数据库不同,关系型数据库表会主动的保护表中的逻辑关系,而Redis不会主动保护,然而能够通过内部逻辑解决来保护表之间的逻辑关系。 BASE:Available(根本可用)、Soft state(软状态)和Eventually consistent(最终一致性)。1、根本可用:产生不可预知的故障时,容许损失局部可用性(工夫、性能)。2、软状态:容许零碎中的数据存在中间状态,且不会影响零碎的整体可用,容许在不同节点的数据正本之间在数据同步的过程中存在提早。3、最终一致性:所有的数据正本,通过一段时间的同步后,最终达到一个统一的状态,不须要实时保障。 内存的存储形式:能够更快的读取数据,但一经断电,内存中的数据会失落,但为了避免这种状况,每隔一段时间,内存中的数据就会写入到磁盘中进行保留。 程度扩大:Redis从设计之初就思考到了分布式数据的状况,通过惟一标识,来进行Hash运算,依据Hash运算的后果来确认数据寄存在那个节点,与关系型数据库不同,关系型数据库中的数据只对本机负责。 Redis数据库的value有5个根本类型和3个非凡类型根本类型:String、Hash、List、Set、SortedSet非凡类型:GEO、BitMap、HyperLog 二、特色1、键值型(key-value)型,value反对多种数据结构,功能丰富2、单线程,每个命令具备原子型。3、低提早,速度快(基于内存、IO多路复用、良好的编码,其中基于内存是使Redis低提早速度快的次要因素)。4、反对主从集群、分片集群(将数据拆分、程度扩大)5、反对多种语言客户端 三、装置Redis数据库是在Linux上开源的,在Windows操作系统中的Redis数据库并不是官网公布的,而是微软编译的,所以咱们间接在Linux服务器上部署Redis数据库。 1、应用ssh命令连贯上近程服务器ssh 你的用户名@近程服务器的IP地址2、进入Linux服务器后(演示的发行版是Ubuntu),执行sudo apt-get install redis-server命令下载Redis,能够应用service redis status命令来查看Redis的状态。装置结束之后,要进入Redis的配置文件中,批改配置文件。将配置改成开机自启、禁用默认IP、禁用保护模式、增加明码,以不便日后应用(批改前记得备份一下)。 daemonize yes 开机自启 ,个别默认状况下就是yesbind 127.0.0.1 -::1 应用#正文掉protect-mode yes 这里批改成no 禁用保护模式requirepass "" 在""中设置本人的明码应用命令sudo vim /etc/redis/redis.conf进入Redis配置文件,在浏览模式(默认是浏览模式,摁i进入编辑模式,摁ESC退出编辑模式)中应用命令/word来搜寻要批改的配置(word的地位填要搜寻的单词,比方/daemonize)。 批改实现后重启Redissystemctl restar redis 四、登录Redis数据库执行命令redis-cli -h 近程服务端的IP -p 6379其中-p 前面跟着的是默认端口号。而后执行auth命令,输出刚刚设置的明码就胜利进入Redis数据库中了。 五、常用命令keys * :查看所有的keyhelp@___ :获取Redis数据库中某个类型的帮忙文档help _ :获取某个类中,某个命令的帮忙文档 在String类型中,有以下几个常用命令:1、set:增加或批改String类型的键值对2、get:依据key获取String类型的value3、mset:批量增加多个String类型的键值对4、mget:批量获取多个String类型的value5、INCR:让一个整型的key自增16、INCRBY:让一个整型的key减少指定步长7、INCRBYFLOAT:让一个Float类型的key减少指定步长8、SETEX:设置键值对的生命周期,秒为单位9、SETNX:增加不存在的String类型的键值对,存在则不增加

March 11, 2023 · 1 min · jiezi

关于redis:配运基础数据缓存瘦身实践

作者:京东物流 张仲良一、背景:在古代物流的理论作业流程中,会有大量关系到经营相干信息的数据产生,如商家,车队,站点,分拣核心,客户等等相干的信息数据,这些数据间接撑持齐了物流的整个业务流转,具备非常重要的位置,那么对于这一类数据咱们须要提供根本的增删改查存的能力,目前京东物流的根底数据是由中台配运组来整体负责。 在根底数据的惯例能力当中,数据的存取是最根底也是最重要的能力,为了整体进步数据的读取能力,缓存技术在根底数据的场景中失去了宽泛的应用,上面会重点展现一下配运组近期针对数据缓存做的瘦身实际。 二、计划:这次优化咱们筛选了商家根底材料和C后盾2个零碎进行了缓存数据的优化试点,从后果看获得了十分显著的成绩,节俭了大量的硬件资源老本,上面的数据是优化前后的缓存应用状况比照: 商家根底材料Redis数据量由45G降为8G; C后盾Redis数据量由132G降为7G; 从后果看这个优化的力度太大了,置信大家对如何实现的更加好奇了,那接下来就让咱们一步步来看是如何做到的吧! 首先目前的商家根底材料应用@Caceh注解组件作为缓存形式,它会将从db中查出的值放入本地缓存及jimdb中,因为该组件晚期的版本没有jimdb的默认过期工夫且应用注解时也未显式申明,造成晚期大量的key没有过期工夫,从而造成了大量的僵尸key。 所以如果咱们能够找到这些僵尸key并进行优化,那么就能够将缓存进行一个整体的瘦身,那首先要怎么找出这些key呢? 2.1 keys命令可能很多同学会想到简略粗犷的keys命令,遍历出所有的key顺次判断是否有过期工夫,但Redis是单线程执行,keys命令会以阻塞的形式执行,遍历形式实现的复杂度是O(n),库中的key越多,阻塞的工夫会越长,通常咱们的数据量都会在几十G以上,显然这种形式是无奈承受的。 2.2 scan命令redis在2.8版本提供了scan命令,相较于keys命令的劣势: scan命令的工夫复杂度尽管也是O(N),但它是分次进行的,不会阻塞线程。scan命令提供了相似sql中limit参数,能够管制每次返回后果的最大条数。当然也有毛病: 返回的数据有可能会反复,至于起因能够看文章最初的扩大局部。scan命令只保障在命令开始执行前所有存在的key都会被遍历,在执行期间新增或删除的数据,是不确定的即可能返回,也可能不返回。2.3根本语法目前看来这是个不错的抉择,让咱们来看下命令的根本语法: SCAN cursor [MATCH pattern] [COUNT count] cursor:游标pattern:匹配的模式count:指定从数据集里返回多少元素,默认值为102.4 实际首先感觉上就是依据游标进行增量式迭代,让咱们实际操作下: 看来咱们只须要设置好匹配的key的前缀,循环遍历删除key即可。 能够通过Controller或者调用jsf接口来触发,应用云redis-API,demo如下: 好的,功败垂成.在治理端执行randomkey命令查看.发现仍然存在大量的无用key,貌似还有不少漏网之鱼,这里又是怎么回事呢? 上面又到了脍炙人口的踩坑环节。 2.5 避坑指南通过减少日发现,返回的后果集为空,但游标并未完结! 其实不难发现scan命令跟咱们在数据库中按条件分页查问是有别的,mysql是依据条件查问出数据,scan命令是按字典槽数顺次遍历,从后果中再匹配出符合条件的数据返回给客户端,那么很有可能在屡次的迭代扫描时没有符合条件的数据。 咱们批改代码应用scanResult.isFinished()办法判断是否曾经迭代实现。 至此程序运行失常,之后通过传入不同的匹配字符,达到分明缓存的目标。 三、课后扩大这里咱们探讨反复数据的问题:为什么遍历出的数据可能会反复? 3.1 反复的数据首先咱们看下scan命令的遍历程序: Redis中有3个key,咱们用scan命令查看发现遍历顺为0->2->1->3,是不是感到奇怪,为什么不是按0->1->2->3的程序? 咱们都晓得HashMap中因为存在hash抵触,当负载因子超过某个阈值时,出于对链表性能的思考会进行Resize操作.Redis也一样,底层的字典表会有动静变换,这种扫描程序也是为了应答这些简单的场景。 3.1.1 字典表的几种状态及应用程序扫描会呈现的问题 字典表没有扩容 字段tablesize放弃不变,程序扫描没有问题字典表已扩容实现 假如字典tablesize从8变为16,之前曾经拜访过3号桶,当初0~3号桶的数据曾经rehash到8~11号桶,若果按程序持续拜访4~15号桶,那么这些元素就反复遍历了。 字典表已缩容实现 假如字典tablesize从16放大到8,同样曾经拜访过3号桶,这时8~11号桶的元素被rehash到0号桶,若按程序拜访,则遍历会进行在7号桶,则这些数据就遗漏掉了。 字典表正在Rehashing Rehashing的状态则会呈现以上两种问题即要么反复扫描,要么脱漏数据。3.1.2 反向二进制迭代器算法思维 咱们将Redis扫描的游标与程序扫描的游标转换成二进制作比照: 高位程序拜访是依照字典sizemask(掩码),在无效位上高位加1。 举个例子,咱们看下Scan的扫描形式: 1.字典tablesize为8,游标从0开始扫描; 2.返回客户端的游标为6后,字典tablesize扩容到之前的2倍,并且实现Rehash; 3.客户端发送命令scan 6; 这时scan命令会将6号桶中链表全副取出返回客户端,并且将以后游标的二进制高位加一计算出下次迭代的起始游标.通过上图咱们能够发现扩容后8,12,10号槽位的数据是从之前0,4,2号槽位迁徙过来的,这些槽位的数据曾经遍历过,所以这种遍历程序就防止了反复扫描。 字典扩容的状况相似,但反复数据的呈现正是在这种状况下: 还以上图为例,再看下缩容时Scan的扫描形式: 1.字典tablesize的初始大小为16,游标从0开始扫描; 2.返回客户端的游标为14后,字典tablesize缩容到之前的1/2,并实现Rehash; 3.客户端发送命令scan 14; 这时字典表已实现缩容,之前6和14号桶的数据曾经Rehash到新表的6号桶中,那14号桶都没有了,要怎么解决呢?咱们持续在源码中找答案: 即在找指标桶时总是用以后hashtaba的sizemask(掩码)来计算,v=14即二进制000 1110,以后字典表的掩码从15变成了7即二进制0000 0111,v&m0的值为6,也就是说在新表上还要扫一遍6号桶.然而缩容后旧表6和14号桶的数据都已迁徙到了新表的6号桶中,所以这时扫描的后果就呈现了反复数据,反复的局部为上次未缩容前已扫描过的6号桶的数据。 ...

March 8, 2023 · 1 min · jiezi

关于redis:redis中bitmap使用场景结束员工统计打卡

Redis 的 Bitmap 是一种非凡的数据结构,它能够存储一组二进制位,并对这些二进制位进行位运算。Bitmap 在 Redis 中被宽泛用于计数器、统计、排重等场景。 一、命令介绍1、SETBIT key offset value将指定偏移量的二进制位设置为给定的值(0 或 1)。例如,SETBIT mybitmap 1001 1 将 mybitmap 中偏移量为 1001 的二进制位设置为 1。 2、GETBIT key offset获取指定偏移量的二进制位的值(0 或 1)。例如,GETBIT mybitmap 1001 将返回 mybitmap 中偏移量为 1001 的二进制位的值。 3、BITCOUNT key [start end]计算指定范畴内所有二进制位被设置为 1 的个数。例如,BITCOUNT mybitmap 0 1023 将返回 mybitmap 中偏移量从 0 到 1023 的所有二进制位中被设置为 1 的个数。 4、BITOP operation destkey key [key ...]对多个指定的 bitmap 进行位运算,并将后果存储到 destkey 中。operation 参数能够是 AND、OR、XOR、NOT 四种运算之一。例如,BITOP AND myresult mybitmap1 mybitmap2 将 mybitmap1 和 mybitmap2 中的所有二进制位进行 AND 运算,并将后果存储到 myresult 中。 ...

March 7, 2023 · 2 min · jiezi

关于redis:Redis-缓存一致性思考

概述一致性缓存一致性,指的是缓存中的数据,与数据库中的数据是否统一能够了解为数据的快照与实时数据是否相等,在实时数据变动的过程中以及数据快照同步中产生的问题,即缓存一致性问题(也能够归类于数据双写问题) 业务场景生产中面临数据的高频读取,为了升高数据库压力,就能够思考将数据放入缓存中,缓存又可分为本地缓存与分布式缓存 本地缓存 & 分布式缓存本地缓存指的是机器上的缓存,如Guava和Ehcache,此类缓存多受限于机器内存与分布式部署同步艰难等问题分布式缓存指的是数据寄存在服务端,应用方拜访同一份数据,如Redis,MemCache,此类缓存存在丢数据,数据延时,服务宕机等问题分布式缓存一致性问题承接上述,已知分布式缓存的实质是将数据库的数据写入到缓存服务端,当数据库产生变更,将变更同步至缓存服务端的过程中,缓存与数据库的数据是不统一的,就波及到了缓存一致性问题(本地缓存一致性问题不在此处探讨) 解决方案读数据面临强一致性场景时,能够思考将数据放入缓存(过期或永不过期都可),服务端只能从缓存读取数据,当发现缓存中没有数据时,服务端加锁读取数据库,此时只有一个申请能够拜访数据库,查问完结后将后果写入缓存,其余申请阻塞至缓存写入实现,再从缓存中读取数据 服务端解决查问申请,尝试从缓存中查问数据缓存中存在数据,则间接返回缓存中不存在数据,则加锁查询数据库,查库完结将数据放入缓存其余申请间接读取缓存 写数据写数据时可后行批改数据库,再将缓存更新或删除(删除时,直到下一次查问申请到来时,新数据才会写入缓存),此计划在数据写入到缓存更新的过程中,其余查问申请仍然将拜访到旧的数据,无奈保障相对的一致性 若须要强一致性计划,则可间接将缓存删除,并阻塞所有读取申请,而后加锁写数据,再将数据放入缓存中,相似于读写锁的概念,读写互斥,此计划因为强一致性束缚,相上述计划性能会差一些,须要联合具体场景应用

March 2, 2023 · 1 min · jiezi

关于redis:三天吃透Redis面试八股文

本文曾经收录到Github仓库,该仓库蕴含计算机根底、Java根底、多线程、JVM、数据库、Redis、Spring、Mybatis、SpringMVC、SpringBoot、分布式、微服务、设计模式、架构、校招社招分享等外围知识点,欢送star~ Github地址:https://github.com/Tyson0314/Java-learning Redis是什么?Redis(Remote Dictionary Server)是一个应用 C 语言编写的,高性能非关系型的键值对数据库。与传统数据库不同的是,Redis 的数据是存在内存中的,所以读写速度十分快,被广泛应用于缓存方向。Redis能够将数据写入磁盘中,保障了数据的平安不失落,而且Redis的操作是原子性的。 Redis优缺点?长处: 基于内存操作,内存读写速度快。反对多种数据类型,包含String、Hash、List、Set、ZSet等。反对长久化。Redis反对RDB和AOF两种长久化机制,长久化性能能够无效地防止数据失落问题。反对事务。Redis的所有操作都是原子性的,同时Redis还反对对几个操作合并后的原子性执行。反对主从复制。主节点会主动将数据同步到从节点,能够进行读写拆散。Redis命令的解决是单线程的。Redis6.0引入了多线程,须要留神的是,多线程用于解决网络数据的读写和协定解析,Redis命令执行还是单线程的。毛病: 对结构化查问的反对比拟差。数据库容量受到物理内存的限度,不适宜用作海量数据的高性能读写,因而Redis适宜的场景次要局限在较小数据量的操作。Redis 较难反对在线扩容,在集群容量达到下限时在线扩容会变得很简单。Redis为什么这么快?基于内存:Redis是应用内存存储,没有磁盘IO上的开销。数据存在内存中,读写速度快。IO多路复用模型:Redis 采纳 IO 多路复用技术。Redis 应用单线程来轮询描述符,将数据库的操作都转换成了事件,不在网络I/O上节约过多的工夫。高效的数据结构:Redis 每种数据类型底层都做了优化,目标就是为了谋求更快的速度。讲讲Redis的线程模型?Redis基于Reactor模式开发了网络事件处理器,这个处理器被称为文件事件处理器。它的组成构造为4局部:多个套接字、IO多路复用程序、文件事件分派器、事件处理器。因为文件事件分派器队列的生产是单线程的,所以Redis才叫单线程模型。 文件事件处理器应用I/O多路复用(multiplexing)程序来同时监听多个套接字, 并依据套接字目前执行的工作来为套接字关联不同的事件处理器。当被监听的套接字筹备好执行连贯accept、read、write、close等操作时, 与操作绝对应的文件事件就会产生, 这时文件事件处理器就会调用套接字之前关联好的事件处理器来解决这些事件。尽管文件事件处理器以单线程形式运行, 但通过应用 I/O 多路复用程序来监听多个套接字, 文件事件处理器既实现了高性能的网络通信模型, 又能够很好地与 redis 服务器中其余同样以单线程形式运行的模块进行对接, 这放弃了 Redis 外部单线程设计的简略性。 Redis利用场景有哪些?缓存热点数据,缓解数据库的压力。利用 Redis 原子性的自增操作,能够实现计数器的性能,比方统计用户点赞数、用户拜访数等。分布式锁。在分布式场景下,无奈应用单机环境下的锁来对多个节点上的过程进行同步。能够应用 Redis 自带的 SETNX 命令实现分布式锁,除此之外,还能够应用官网提供的 RedLock 分布式锁实现。简略的音讯队列,能够应用Redis本身的公布/订阅模式或者List来实现简略的音讯队列,实现异步操作。限速器,可用于限度某个用户拜访某个接口的频率,比方秒杀场景用于避免用户疾速点击带来不必要的压力。好友关系,利用汇合的一些命令,比方交加、并集、差集等,实现独特好友、共同爱好之类的性能。Memcached和Redis的区别?MemCached 数据结构繁多,仅用来缓存数据,而 Redis 反对多种数据类型。MemCached 不反对数据长久化,重启后数据会隐没。Redis 反对数据长久化。Redis 提供主从同步机制和 cluster 集群部署能力,可能提供高可用服务。Memcached 没有提供原生的集群模式,须要依附客户端实现往集群中分片写入数据。Redis 的速度比 Memcached 快很多。Redis 应用单线程的多路 IO 复用模型,Memcached应用多线程的非阻塞 IO 模型。(Redis6.0引入了多线程IO,用来解决网络数据的读写和协定解析,然而命令的执行依然是单线程)value 值大小不同:Redis 最大能够达到 512M;memcache 只有 1mb。为什么要用 Redis 而不必 map/guava 做缓存?应用自带的 map 或者 guava 实现的是本地缓存,最次要的特点是轻量以及疾速,生命周期随着 jvm 的销毁而完结,并且在多实例的状况下,每个实例都须要各自保留一份缓存,缓存不具备一致性。 ...

March 1, 2023 · 4 min · jiezi

关于redis:redis

redis的五种数据类型 1、string(字符串);2、hash(哈希);3、list(列表);4、set(汇合);5、sort set (有序汇合)。其中,string(字符串)是redis中最根本的数据类型,一个key对应一个value,string 能够蕴含任何数据。Redis为什么这么快?(1)齐全基于内存,数据存在内存中,绝大部分申请是纯正的内存操作,十分疾速,跟传统的磁盘文件数据存储相比,防止了通过磁盘IO读取到内存这部分的开销。 (2)数据结构简略,对数据操作也简略。Redis中的数据结构是专门进行设计的,每种数据结构都有一种或多种数据结构来反对。Redis正是依赖这些灵便的数据结构,来晋升读取和写入的性能。 (3)采纳单线程,省去了很多上下文切换的工夫以及CPU耗费,不存在竞争条件,不必去思考各种锁的问题,不存在加锁开释锁操作,也不会呈现死锁而导致的性能耗费。 (4)应用基于IO多路复用机制的线程模型,能够解决并发的链接。 Redis 基于 Reactor 模式开发了本人的网络事件处理器,这个处理器被称为文件事件处理器 file event handler。因为这个文件事件处理器是单线程的,所以Redis才叫做单线程的模型,然而它采纳IO多路复用机制同时监听多个Socket,并依据Socket上的事件来抉择对应的事件处理器进行解决。文件事件处理器的构造蕴含4个局部 redis分布式锁怎么应用? 原理:基于setNX命令,避免死锁须要设置过期工夫,避免过期时程序未实现,须要主动续期。主动续期能够应用redision的watchdog实现。应用流程:先上锁,如果上锁胜利则执行业务,最初开释锁。如果上锁失败则返回或重试等,依据业务状况而定。什么是Redis的脑裂景象 当Redis主从集群环境呈现两个主节点为客户端提供服务,这时客户端申请命令可能会产生数据失落的状况。脑裂带来的影响 脑裂呈现后带来最重大的结果就是数据失落,为什么会呈现数据失落的问题呢,次要起因是新主库确定后会向所有的实例发送slave of命令,让所有实例从新进行全量同步,而全量同步首先就会将实例上的数据先清空,所以在主从同步期间在原主库执行的命令将会被清空(下面场景二是同样的情理,在网络分区复原后原主节点将被降级为从节点,并且执行全量同步导致数据失落),所以这就是数据失落的具体起因。如何应答脑裂 脑裂的次要起因其实就是哨兵集群认为主节点曾经呈现故障了,从新选举其它从节点作为主节点,而原主节点其实是假故障,从而导致短暂的呈现两个主节点,那么在主从切换期间客户端一旦给原主节点发送命令,就会造成数据失落。所以应答脑裂的解决办法应该是去限度原主库接管申请,Redis提供了两个配置项。min-slaves-to-write:与主节点通信的从节点数量必须大于等于该值主节点,否则主节点回绝写入。min-slaves-max-lag:主节点与从节点通信的ACK音讯提早必须小于该值,否则主节点回绝写入。这两个配置项必须同时满足,不然主节点回绝写入。在假故障期间满足min-slaves-to-write和min-slaves-max-lag的要求,那么主节点就会被禁止写入,脑裂造成的数据失落状况天然也就解决了。总结 Redis脑裂能够采纳min-slaves-to-write和min-slaves-max-lag合理配置尽量躲避,但无奈彻底解决,Redis脑裂最实质的问题是主从集群外部没有共识算法来保护多个节点的强一致性,它不像Zookeeper那样,每次写入必须大多数节点胜利后才算胜利,当脑裂产生时,Zookeeper节点被孤立,此时无奈写入大多数节点,写申请会间接失败,因而Zookeeper能力保障集群的强一致性。Redis的各种集群计划、及优缺点比照1.主从模式 redis单节点尽管有通过RDB和AOF长久化机制能将数据长久化到硬盘上,但数据是存储在一台服务器上的,如果服务器呈现硬盘故障等问题,会导致数据不可用,而且读写无奈拆散,读写都在同一台服务器上,申请量大时会呈现I/O瓶颈。为了防止单点故障 和 读写不拆散,Redis 提供了复制(replication)性能实现master数据库中的数据更新后,会主动将更新的数据同步到其余slave数据库上。如上redis主从构造特点:一个master能够有多个salve节点;salve节点能够有slave节点,从节点是级联构造。主从模式优缺点 1.长处: 主从构造具备读写拆散,提高效率、数据备份,提供多个正本等长处。2.有余: 最大的有余就是主从模式不具备主动容错和复原性能,主节点故障,集群则无奈进行工作,可用性比拟低,从节点升主节点须要人工手动干涉。 一般的主从模式,当主数据库解体时,须要手动切换从数据库成为主数据库:1.在从数据库中应用SLAVE NO ONE命令将从数据库晋升成主数据持续服务。 2.启动之前解体的主数据库,而后应用SLAVEOF命令将其设置成新的主数据库的从数据库,即可同步数据。2.哨兵模式第一种主从同步/复制的模式,当主服务器宕机后,须要手动把一台从服务器切换为主服务器,这就须要人工干预,麻烦费劲,还会造成一段时间内服务不可用,这时候就须要哨兵模式退场了。哨兵模式是从Redis的2.6版本开始提供的,然而过后这个版本的模式是不稳固的,直到Redis的2.8版本当前,这个哨兵模式才稳定下来。 哨兵模式外围还是主从复制,只不过在绝对于主从模式在主节点宕机导致不可写的状况下,多了一个竞选机制:从所有的从节点竞选出新的主节点。竞选机制的实现,是依赖于在零碎中启动一个sentinel过程。如上图,哨兵自身也有单点故障的问题,所以在一个一主多从的Redis零碎中,能够应用多个哨兵进行监控,哨兵不仅会监控主数据库和从数据库,哨兵之间也会互相监控。每一个哨兵都是一个独立的过程,作为过程,它会独立运行。(1)哨兵模式的作用:监控所有服务器是否失常运行:通过发送命令返回监控服务器的运行状态,解决监控主服务器、从服务器外,哨兵之间也互相监控。 故障切换:当哨兵监测到master宕机,会主动将slave切换成master,而后通过公布订阅模式告诉其余的从服务器,批改配置文件,让它们切换master。同时那台有问题的旧主也会变为新主的从,也就是说当旧的主即便复原时,并不会复原原来的主身份,而是作为新主的一个从。 (2)哨兵实现原理哨兵在启动过程时,会读取配置文件的内容,通过如下的配置找出须要监控的主数据库: sentinel monitor master-name ip port quorum master-name是主数据库的名字ip和port 是以后主数据库地址和端口号quorum示意在执行故障切换操作前,须要多少哨兵节点批准。这里之所以只须要连贯主节点,是因为通过主节点的info命令,获取从节点信息,从而和从节点也建设连贯,同时也能通过主节点的info信息晓得新增从节点的信息。 一个哨兵节点能够监控多个主节点,然而并不提倡这么做,因为当哨兵节点解体时,同时有多个集群切换会产生故障。 哨兵启动后,会与主数据库建设两条连贯。 1.订阅主数据库_sentinel_:hello频道以获取同样监控该数据库的哨兵节点信息 2.定期向主数据库发送info命令,获取主数据库自身的信息。 跟主数据库建设连贯后会定时执行以下三个操作: (1)每隔10s向master和 slave发送info命令。作用是获取以后数据库信息,比方发现新增从节点时,会建设连贯,并退出到监控列表中,当主从数据库的角色发生变化进行信息更新。 (2)每隔2s向主数据里和从数据库的_sentinel_:hello频道发送本人的信息。作用是将本人的监控数据和哨兵分享。每个哨兵会订阅数据库的_sentinel:hello频道,当其余哨兵收到音讯后,会判断该哨兵是不是新的哨兵,如果是则将其退出哨兵列表,并建设连贯。 (3)每隔1s向所有主从节点和所有哨兵节点发送ping命令,作用是监控节点是否存活。 (3)主观下线和主观下线哨兵节点发送ping命令时,当超过肯定工夫(down-after-millisecond)后,如果节点未回复,则哨兵认为主观下线。主观下线示意以后哨兵认为该节点曾经上面,如果该节点为主数据库,哨兵会进一步判断是够须要对其进行故障切换,这时候就要发送命令(SENTINEL is-master-down-by-addr)询问其余哨兵节点是否认为该主节点是主观下线,当达到指定数量(quorum)时,哨兵就会认为是主观下线。 当主节点主观下线时就须要进行主从切换,主从切换的步骤为: (1)选出领头哨兵。(2)领头哨兵所有的slave选出优先级最高的从数据库。优先级能够通过slave-priority选项设置。(3)如果优先级雷同,则从复制的命令偏移量越大(即复制同步数据越多,数据越新),越优先。(4)如果以上条件都一样,则抉择run ID较小的从数据库。选出一个从数据库后,哨兵发送slave no one命令降级为主数据库,并发送slaveof命令将其余从节点的主数据库设置为新的主数据库。 (4)哨兵模式优缺点 1.长处哨兵模式是基于主从模式的,解决可主从模式中master故障不能够主动切换故障的问题。 2.有余-问题(1)是一种中心化的集群实现计划:始终只有一个Redis主机来接管和解决写申请,写操作受单机瓶颈影响。 (2)集群里所有节点保留的都是全量数据,节约内存空间,没有真正实现分布式存储。数据量过大时,主从同步重大影响master的性能。 (3)Redis主机宕机后,哨兵模式正在投票选举的状况之外,因为投票选举完结之前,谁也不晓得主机和从机是谁,此时Redis也会开启爱护机制,禁止写操作,直到选举出了新的Redis主机。 主从模式或哨兵模式每个节点存储的数据都是全量的数据,数据量过大时,就须要对存储的数据进行分片后存储到多个redis实例上。此时就要用到Redis Sharding技术。4.Redis ClusterRedis 的哨兵模式尽管曾经能够实现高可用,读写拆散 ,然而存在几个方面的有余: ...

February 28, 2023 · 1 min · jiezi

关于redis:Redis70最新系列教程基础入门

大家好,我是二条。一位从事服务端研发的程序猿。 从明天开始,我会不间断的开始给大家分享Redis7.0版本的常识。 从2022年1月31开始,官网就公布了 Redis7.0-rc1,至今曾经公布到 7.0.5 版本。很多的开发者,还对Redis意识停留在5.x的版本或者6.x的版本,对Redis7.0还不足较少的意识。本系列教程,将率领大家残缺的学习Redis7.0相干的知识点。从环境的搭建、10大数据类型、事务、公布订阅、主从复制、哨兵、集群等等常识。本教程最大的特点是,不会单纯的总结一些枯燥乏味的理论知识,而是理论知识+根底工夫+场景面试题剖析,同时也会分享一些Redis相干技术栈等等内容。 明天给大家分享的是Redis相干的根底意识,以及它适宜在什么场景下应用,如何疾速搭建Redis环境。 Redis是什么Redis是一款基于内存,采纳 key => vlaue 形式存储的高性能内存型nosql数据库。Redis 提供数据结构,例如字符串、哈希、列表、集、带有范畴查问的排序集、位图、超日志日志、天文空间索引和流。 Redis 具备内置复制、Lua 脚本、LRU 逐出、事务和不同级别的磁盘持久性,并通过 Redis Sentinel 和 Redis 集群的主动分区提供高可用性。 为什么会呈现Redis这样一款内存型数据库呢。这就要从Redis的作者antirezs说起。 2008年的时候有一个意大利西西里岛的小伙子,笔名antirez,创立了一个访客信息网站LLOOGG.COM。有的时候咱们须要晓得网站的拜访状况,比方访客的IP、操作系统、浏览器、应用的搜寻关键词、所在地区、拜访的网页地址等等。在国内,有很多网站提供了这个性能,比方CNZZ,百度统计,国外也有谷歌的GoogleAnalytics。咱们不必本人写代码去实现这个性能,只须要在全局的footer 外面嵌入一段JS 代码就行了,当页面被拜访的时候,就会主动把访客的信息发送到这些网站统计的服务器,而后咱们登录后盾就能够查看数据了。 LLOOGG.COM 提供的就是这种性能,它能够查看最多10000 条的最新浏览记录。这样的话,它须要为每一个网站创立一个列表(List),不同网站的拜访记录进入到不同的列表。如果列表的长度超过了用户指定的长度,它须要把最早的记录删除(先进先出)。 当LLOOGG.COM 的用户越来越多的时候,它须要保护的列表数量也越来越多,这种记录最新的申请和删除最早的申请的操作也越来越多。LLOOGG.COM 最后应用的数据库是MySQL,可想而知,因为每一次记录和删除都要读写磁盘,因为数据量和并发量太大,在这种状况下无论怎么去优化数据库都不论用了。 思考到最终限度数据库性能的瓶颈在于磁盘,所以antirez 打算放弃磁盘,本人去实现一个具备列表构造的数据库的原型,把数据放在内存而不是磁盘,这样能够大大地晋升列表的push 和pop 的效率。antirez 发现这种思路的确能解决这个问题,所以用C 语言重写了这个内存数据库,并且加上了长久化的性能,09 年,Redis 横空出世了。从最开始只反对列表的数据库,到当初反对多种数据类型,并且提供了一系列的高级个性,Redis 曾经成为一个在全世界被宽泛应用的开源我的项目。 Redis的全称是 REmote DIctionary Server。其默认的服务端口是 6379。对于Redis的端口号抉择 6379,有这么一种说法。6379在是手机按键上MERZ对应的号码,而MERZ取自意大利歌女Alessia Merz的名字。Alessia Merz 是一位意大利舞女、女演员。 Redis 作者 Antirez(意大利人) 早年看电视节目,感觉 Merz 在节目中的一些话愚昧可笑,Antirez 喜爱造“梗”用于平时和敌人们交换,于是造了一个词 "MERZ",形容愚昧,与 "stupid" 含意雷同。起初 Antirez 从新定义了 "MERZ" ,形容”具备很高的技术价值,蕴含技能、急躁和劳动,但依然放弃简略实质“。到了给 Redis 抉择一个数字作为默认端口号时,Antirez 没有多想,把 "MERZ" 在手机键盘上对应的数字 6379 拿来用了。 ...

February 27, 2023 · 3 min · jiezi

关于redis:深入理解跳表及其在Redis中的应用

前言跳表能够达到和红黑树一样的工夫复杂度 O(logN),且实现简略,Redis 中的有序汇合对象的底层数据结构就应用了跳表。其作者威廉·普评估:跳跃链表是在很多利用中有可能代替均衡树的一种数据结构。本篇文章将对跳表的实现及在Redis中的利用进行学习。** 一. 跳表的根底概念跳表,即跳跃链表(Skip List),是基于并联的链表数据结构,操作效率能够达到O(logN),对并发敌对,跳表的示意图如下所示。 跳表的特点,能够概括如下。 •跳表是多层(level)链表构造; •跳表中的每一层都是一个有序链表,并且依照元素升序(默认)排列; •跳表中的元素会在哪一层呈现是随机决定的,然而只有元素呈现在了第 k 层,那么 k 层以下的链表也会呈现这个元素; •跳表的底层的链表蕴含所有元素; •跳表头节点和尾节点不存储元素,且头节点和尾节点的层数就是跳表的最大层数; •跳表中的节点蕴含两个指针,一个指针指向同层链表的后一节点,一个指针指向上层链表的同元素节点。 以上图中的跳表为例,如果要查找元素 71,那么查找流程如下图所示。 从顶层链表的头节点开始查找,查找到元素71的节点时,一共遍历了4个节点,然而如果依照传统链表的形式(即从跳表的底层链表的头节点开始向后查找),那么就须要遍历7个节点,所以跳表以空间换工夫,缩短了操作跳表所须要破费的工夫。跳跃列表的算法有同均衡树一样的渐进的预期工夫边界,并且更简略、更疾速和应用更少的空间。这种数据结构是由William Pugh(音译为威廉·普)创造的,最早呈现于他在1990年发表的论文《Skip Lists: A Probabilistic Alternative to Balanced Trees》。 谷歌上找到一篇作者对于跳表的论文,感兴趣强烈建议下载浏览: https://epaperpress.com/sorts...跳表在动静查找过程中应用了一种非严格的均衡机制来让插入和删除都更加便当和快捷,这种非严格均衡是基于概率的,而不是均衡树的严格均衡。说到非严格均衡,首先想到的是红黑树RbTree,它同样采纳非严格均衡来防止像AVL那样调整树的构造,这里就不开展讲红黑树了,看来跳表也是相似的路子,然而是基于概率实现的。 二. 跳表的节点已知跳表中的节点,须要有指向以后层链表后一节点的指针,和指向上层链表的同元素节点的指针,所以跳表中的节点,定义如下。 public class SkiplistNode { public int data; public SkiplistNode next; public SkiplistNode down; public int level; public SkiplistNode(int data, int level) { this.data = data; this.level = level; }上述是跳表中的节点的最简略的定义形式,存储的元素 data 为整数,节点之间进行比拟时间接比拟元素 data 的大小。 三. 跳表的初始化跳表初始化时,将每一层链表的头尾节点创立进去并应用汇合将头尾节点进行存储,头尾节点的层数随机指定,且头尾节点的层数就代表以后跳表的层数。初始化后,跳表构造如下所示。 ...

February 23, 2023 · 6 min · jiezi

关于redis:linux-配置Redis单机版

本文指标 在一台virtualbox创立的虚构机上安装单机的redis1.如果没有wget,请先装置 yum -y install wget2.在Linux根目录下顺次执行以下命令 yum -y install gcc automake autoconf libtool makemkdir /datacd /data/wget https://download.redis.io/releases/redis-6.2.0.tar.gztar xzvf redis-6.2.0.tar.gz -C /data/mv redis-6.2.0/ rediscd redis/3.批改配置文件办法能够应用传统做法,用vim关上,而后编辑保留也能够间接用一些ssh工具去批改,比拟不便先找到文件,而后双击批改实现后ctrl+s保留即可 4.批改配置文件(文件在redis装置目录下) bind 0.0.0.0 #开启外网拜访daemonize yes #redis后盾运行5.启动 #加&代表后盾启动cd /src./redis-server &

February 22, 2023 · 1 min · jiezi

关于redis:一图读懂阿里云RDS架构与选型

在去年5月,在云数据库技术公众号公布了“一张图读懂阿里云数据库架构与选型”。过来了大概10个月工夫,往年,阿里云数据库RDS也公布了很多新的个性与能力,包含RDS集群版、Serverless、ARM反对等,另外,之前的版本也短少了数据库代理,云盘类型等。这里一并进行更新,公布了新的v2版本如下: 原图公众号「云数据库技术」:一图读懂阿里云RDS架构与选型在v1版本公布的时候,具体的介绍了阿里云数据库RDS的次要的架构类型、资源复用与规格、数据库专属集群、对于本地盘与云盘版、通用型与独享型、超配比等内容,这里不再赘述,如果感兴趣能够参考:一张图读懂阿里云数据库架构与选型。 一、新增了ARM架构实例反对阿里云数据库在去年11月发表推出基于ARM架构的RDS实例,能够向用户提供更高性价比。依据ARM芯片的定位,个别性价比更高,然而性能下限相比于x86的芯片要差一些。所以,如果数据库实例压力不是很大,而又思考老本升高,则能够思考尝试ARM架构的RDS。 另外,zhoujy在去年11月份对该实例进行测试,相干的数据库能够参考:MySQL该用哪种CPU架构服务器。 以后,基于ARM的RDS实例上线工夫还不是很长,如果是生产环境的话,倡议做较为全面的测试后再上线。 二、RDS MySQL新增了集群版在去年年底,阿里云RDS MySQL公布了集群版。该产品状态相似于AWS提供的”Multi-AZ Cluster”(参考),场景也比拟相似。比照最罕用的双节点高可用版本,该”集群版”将其备库的连贯地址提供了进去,间接能够用于用户业务,帮忙用户升高应用老本。另外,也能够思考将主库的局部流量间接迁徙到备节点,升高主库压力,晋升主库的可用性。 如果,在业务场景中,应用了1~2个只读实例的,则能够思考间接应用该集群版本来代替原有的只读实例。老本能够失去十分大的升高。 三、Serverless实例RDS Serverless是一种优于按量付费、包年包月的资源应用的模式。它提供了自动化的弹性扩缩容,用户无需提前选定规格,后端会依据零碎压力进行主动升降配,并依据理论应用计费,当然,用户能够设置Serverless实例的最大和最小规格,限度资源最大使用量和最低的服务能力。 对于峰谷显著的业务零碎,该模式一方面能够在须要时提供很高的资源规格应答压力,另一方面能够在低峰时升高资源使用量,最终降低成本。 也留神到,最近阿里云数据库数据库也介绍了客户“微财”应用Serverless实例构建云上灾备的案例(参考)。应用Serverless构建云端低成本的灾备,的确是一个十分好的场景,一方面满足了客户底层本的诉求,另一方面客户本地的实例如果真的出问题,仍旧能够十分疾速的接管。 对于更多Serverless测试能够参考:实测阿里云RDS Serverless。 四、其余本架构图次要反映阿里云数据库RDS的次要架构ARM CPU仅局部数据库局部规格反对,以后仅MySQL、PostgreSQL反对“集群版”仅MySQL和SQL Server反对不同数据库的不同的版本,反对的架构和规格都有不同,这里并没有体现进去不同的区域反对的数据库、版本均可能不同该图的实现失去了阿里云RDS团队的帮忙,在此一并表示感谢v1版本公布于2022年5月;v2版本公布于2023年2月问题反馈:orczhou@ninedata.cloud五、对于作者orczhou 是来自 NineData 的工程师。NineData 向企业、开发者提供高效、平安的数据库 SQL 开发、数据库备份、数据复制/迁徙/集成、数据比照等性能,是一个 SaaS 服务开箱即用,能够疾速晋升企业 SQL 开发效率,保障企业数据安全。NineData 官网地址:www.ninedata.cloud 感激点赞、转发一下,你们的反对会激励咱们继续输入更多高质量的技术文章!欢送关注咱们的公众号「云数据库技术」,晋升数据库技能,让每个人用好数据和云。

February 21, 2023 · 1 min · jiezi

关于redis:redis-rebloom-报错-Maximum-expansions-reached

应用 rebloom 遇到了报错:redis.exceptions.ResponseError: Maximum expansions reached 具体内容如下: File "/usr/local/lib/python3.10/site-packages/redisbloom/client.py", line 411, in cfAddNX return self.execute_command(self.CF_ADDNX, *params) │ │ │ │ └ ['crawler', 'https://power.in-en.com/html/power-2402142.shtml'] │ │ │ └ 'CF.ADDNX' │ │ └ Client<ConnectionPool<Connection<host=172.16.36.108,port=6379,db=0>>> │ └ <function Redis.execute_command at 0x7f49110785e0> └ Client<ConnectionPool<Connection<host=172.16.36.108,port=6379,db=0>>> File "/usr/local/lib/python3.10/site-packages/redis/client.py", line 901, in execute_command return self.parse_response(conn, command_name, **options) │ │ │ │ └ {} │ │ │ └ 'CF.ADDNX' │ │ └ Connection<host=172.16.36.108,port=6379,db=0> │ └ <function Redis.parse_response at 0x7f4911078670> └ Client<ConnectionPool<Connection<host=172.16.36.108,port=6379,db=0>>> File "/usr/local/lib/python3.10/site-packages/redis/client.py", line 915, in parse_response response = connection.read_response() │ └ <function Connection.read_response at 0x7f49111f3c70> └ Connection<host=172.16.36.108,port=6379,db=0> File "/usr/local/lib/python3.10/site-packages/redis/connection.py", line 756, in read_response raise response └ ResponseError('Maximum expansions reached')redis.exceptions.ResponseError: Maximum expansions reached问题起因:布隆过滤器的容量满了 ...

February 18, 2023 · 1 min · jiezi

关于redis:DocArray-0210版本发布新增OpenSearch后端存储支持Redis后端存储的多语言文本搜索

DocArray 是一个用于解决、传输和存储多模态数据的 Python 工具包。DocArray 提供便捷的多模态数据处理性能,具备基于 Protobuf 提供高性能的网络传输性能,同时也为多种向量存储计划提供对立的 API 接口。 DocArray 于 2022 年 1 月在开源 Apache 许可证 2.0 下公布。目前,它是 LF AI \& Data Foundation 下的沙盒我的项目。 GitHub: https://github.com/docarray Discord社区: https://discord.gg/WaMp6PVPgR 官网文档:https://docarray.jina.ai/此版本蕴含 3 项新性能,7 项谬误修改和 5 项文档改良。 新性能 OpenSearch 后端存储(#853)当初 DocArray 减少了一个新的后端存储:OpenSearch!您能够应用 OpenSearch 后端存储对 Document 进行索引,并对它们进行 ANN 搜寻。 from docarray import Document, DocumentArray import numpy as np # Connect to OpenSearch instance n_dim = 3 da = DocumentArray(     storage='opensearch',     config={'n_dim': n_dim}, ) # Index Documents with da:     da.extend(         [             Document(id=f'r{i}', embedding=i * np.ones(n_dim))             for i in range(10)         ]     ) # Perform ANN search np_query = np.ones(n_dim) * 8 results = da.find(np_query, limit=10) 此外,OpenSearch 后端存储还反对 过滤查问,按文本搜寻 和 按标签搜寻。无关其用法的更多信息,请参阅 官网文档。 ...

February 17, 2023 · 1 min · jiezi

关于redis:故障分析-redis-cluster-从库无法自动恢复同步案例一则

作者:任坤 现居珠海,先后负责专职 Oracle 和 MySQL DBA,当初次要负责 MySQL、mongoDB 和 Redis 保护工作。 本文起源:原创投稿 *爱可生开源社区出品,原创内容未经受权不得随便应用,转载请分割小编并注明起源。 背景线上有一套6节点 redis cluster ,6分片 * 2正本,每个节点上2个实例,端口号别离为7000和7001。 腊月29凌晨,有个节点硬件故障导致主动重启,重启后该节点上的实例变成从库,却迟迟无奈实现和新主库的同步进而触发报警。 redis 版本为5.0。 诊断登录该节点,查看 redis 的日志 22996:S 20 Jan 2023 07:27:15.091 * Connecting to MASTER 172.18.2.46:700122996:S 20 Jan 2023 07:27:15.091 * MASTER <‐> REPLICA sync started22996:S 20 Jan 2023 07:27:15.106 * Non blocking connect for SYNC fired the event.22996:S 20 Jan 2023 07:27:15.106 * Master replied to PING, replication can continue...22996:S 20 Jan 2023 07:27:15.106 * Trying a partial resynchronization (request 174e5c92c731090d3c9a05f6364ffff5a70e61d9:7180528579709).22996:S 20 Jan 2023 07:35:29.263 * Full resync from master: 174e5c92c731090d3c9a05f6364ffff5a70e61d9:718073438045122996:S 20 Jan 2023 07:35:29.263 * Discarding previously cached master state.22996:S 20 Jan 2023 07:44:47.717 * MASTER <‐> REPLICA sync: receiving 22930214160 bytes from master实例启动后和主库进行连贯,先尝试 partial resync 失败,后进行 full resync ...

February 16, 2023 · 3 min · jiezi

关于redis:一文读懂-Redis-架构演化之路

导语|近年来,Redis 变得越来越风行。Redis 长久化、主从复制、哨兵、分片集群是开发者常遇到的、看似容易了解的概念。它们存在什么分割?Redis 为什么会演化出几种架构模式?腾讯云后盾开发工程师谭帅将带你一步步构建出稳固、高性能的 Redis 集群。理解 Redis 做了哪些计划来实现稳固与高性能之后,你在日常应用 Redis 时,可能更加熟能生巧。 目录 1 情境引入:单机版 Redis 2 数据长久化:有恃无恐 3 主从复制:多正本 4 哨兵:故障主动切换 5 分片集群:横向扩大 6 总结 现如今 Redis 变得越来越风行,在很多我的项目中被用到。开发者们在应用 Redis 时,经常思考一个问题:Redis 是如何稳固、高性能地提供服务的?各位开发者也能够尝试答复一下以下这些问题: ● 我应用 Redis 的场景很简略,只应用单机版 Redis 会有什么问题吗? ● 我的 Redis 故障宕机了,数据失落了怎么办? ● 如何能保障我的业务、利用不受影响? ● 为什么须要主从集群?它有什么劣势? ● 什么是分片集群?我真的须要分片集群吗? 如果你曾经对 Redis 有些许理解,必定据说过数据长久化、主从复制、哨兵这些概念。它们之间又有什么区别和分割呢?如果你存在这样的纳闷,这篇文章会从 0 到 1、再从 1 到 N,带你一步步构建出一个稳固、高性能的 Redis 集群。 在这个过程中,你能够理解到 Redis 为了做到稳固、高性能所采取的优化计划及其起因。把握了这些原理,你在日常应用 Redis 时,可能做到加倍熟能生巧。 01、情境引入:单机版 Redis首先,咱们从最简略的场景来假如,以便各位由浅入深了解。当初你有一个业务、利用,须要引入 Redis 来进步利用的性能。你能够抉择部署一个单机版的 Redis 来应用。就像这样: 这个架构非常简单,你的业务、利用能够把 Redis 当做缓存来应用。从 MySQL 中查问数据,写入到 Redis 中。业务、利用再从 Redis 中读取这些数据。Redis 的数据都存储在内存中,所以速度飞快。 ...

February 16, 2023 · 2 min · jiezi

关于redis:Redis分布式锁正确打开方式

作者:京东保险 张江涛1、为什么要有分布式锁?JUC提供的锁机制,能够保障在同一个JVM过程中同一时刻只有一个线程执行操作逻辑; 多服务多节点的状况下,就意味着有多个JVM过程,要做到这样,就须要有一个中间人; 分布式锁就是用来保障在同一时刻,仅有一个JVM过程中的一个线程在执行操作逻辑; 换句话说,JUC的锁和分布式锁都是一种爱护系统资源的措施。尽可能将并发带来的不确定性转换为同步的确定性; 2、分布式锁个性(五大个性 十分重要)个性1:互斥性。在任意时刻,只有一个客户端能持有锁。 个性2: 不会产生死锁。即便有一个客户端在持有锁的期间解体而没有被动解锁,也能保障后续其余客户端能加锁。 个性3: 解铃还须系铃人。加锁和解锁必须是同一个客户端(线程),客户端本人不能把他人加的锁给解了。 个性4:可重入性。同一个现线程曾经获取到锁,可再次获取到锁。 个性5: 具备容错性。只有大部分的分布式锁节点失常运行,客户端就能够加锁和解锁。 2-1 常见分布式锁的三种实现形式1. 数据库锁;2. 基于ZooKeeper的分布式锁;3. 基于Redis的分布式锁。 2-2 本文咱们次要聊 redis实现分布式锁:一个 setnx 就行了?value没意义?还有人认为 incr 也能够?再加个超时工夫就行了? 3、分布式锁个性2之不会产生死锁很多线程去上锁,谁锁胜利谁就有权力执行操作逻辑,其余线程要么间接走抢锁失败的逻辑,要么自旋尝试抢锁; • 比方说 A线程竞争到了锁,开始执行操作逻辑(代码逻辑演示中,应用 Jedis客户端为例); public static void doSomething() { // RedisLock是封装好的一个类 RedisLock redisLock = new RedisLock(jedis); // 创立jedis实例的代码省略,不是重点 try { redisLock.lock(); // 上锁 // 解决业务 System.out.println(Thread.currentThread().getName() + " 线程解决业务逻辑中..."); Thread.sleep(2000); System.out.println(Thread.currentThread().getName() + " 线程解决业务逻辑结束"); redisLock.unlock(); // 开释锁 } catch (Exception e) { e.printStackTrace(); }}• 失常状况下,A 线程执行完操作逻辑后,应该将锁开释。如果说执行过程中抛出异样,程序不再持续走失常的开释锁流程,没有开释锁怎么办?所以咱们想到: ...

February 14, 2023 · 6 min · jiezi

关于redis:详解Redisson分布式限流的实现原理

 咱们目前在工作中遇到一个性能问题,咱们有个定时工作须要解决大量的数据,为了晋升吞吐量,所以部署了很多台机器,但这个工作在运行前须要从别的服务那拉取大量的数据,随着数据量的增大,如果同时多台机器并发拉取数据,会对上游服务产生十分大的压力。之前曾经减少了单机限流,但无奈解决问题,因为这个数据工作运行中只有不到10%的工夫拉取数据,如果单机限流限度太狠,尽管集群总的申请量管制住了,但工作吞吐量又降下来。如果限流阈值太高,多机并发的时候,还是有可能压垮上游。 所以目前惟一可行的解决方案就是分布式限流。 我目前是抉择间接应用Redisson库中的RRateLimiter实现了分布式限流,对于Redission可能很多人都有所耳闻,它其实是在Redis能力上构建的开发库,除了反对Redis的根底操作外,还封装了布隆过滤器、分布式锁、限流器……等工具。明天要说的RRateLimiter及时其实现的限流器。接下来本文将具体介绍下RRateLimiter的具体应用形式、实现原理还有一些注意事项,最初简略谈谈我对分布式限流底层原理的了解。 RRateLimiter应用 RRateLimiter的应用形式异样的简略,参数也不多。只有创立出RedissonClient,就能够从client中获取到RRateLimiter对象,间接看代码示例。 RedissonClient redissonClient = Redisson.create();RRateLimiter rateLimiter = redissonClient.getRateLimiter("xindoo.limiter");rateLimiter.trySetRate(RateType.OVERALL, 100, 1, RateIntervalUnit.HOURS); rateLimiter.trySetRate就是设置限流参数,RateType有两种,OVERALL是全局限流 ,PER_CLIENT是单Client限流(能够认为就是单机限流),这里咱们只探讨全局模式。而前面三个参数的作用就是设置在多长时间窗口内(rateInterval+IntervalUnit),许可总量不超过多少(rate),下面代码中我设置的值就是1小时内总许可数不超过100个。而后调用rateLimiter的tryAcquire()或者acquire()办法即可获取许可。 rateLimiter.acquire(1); // 申请1份许可,直到胜利boolean res = rateLimiter.tryAcquire(1, 5, TimeUnit.SECONDS); // 申请1份许可,如果5s内未申请到就放弃 应用起来还是很简略的嘛,以上代码中的两种形式都是同步调用,但Redisson还同样提供了异步办法acquireAsync()和tryAcquireAsync(),应用其返回的RFuture就能够异步获取许可。 RRateLimiter的实现 接下来咱们顺着tryAcquire()办法来看下它的实现形式,在RedissonRateLimiter类中,咱们能够看到最底层的tryAcquireAsync()办法。 private <T> RFuture<T> tryAcquireAsync(RedisCommand<T> command, Long value) { byte[] random = new byte[8]; ThreadLocalRandom.current().nextBytes(random); return commandExecutor.evalWriteAsync(getRawName(), LongCodec.INSTANCE, command, "——————————————————————————————————————" + "这里是一大段lua代码" + "____________________________________", Arrays.asList(getRawName(), getValueName(), getClientValueName(), getPermitsName(), getClientPermitsName()), value, System.currentTimeMillis(), random); } 映入眼帘的就是一大段lua代码,其实这段Lua代码就是限流实现的外围,我把这段lua代码摘出来,并加了一些正文,咱们来具体看下。 local rate = redis.call("hget", KEYS[1], "rate") # 100 local interval = redis.call("hget", KEYS[1], "interval") # 3600000local type = redis.call("hget", KEYS[1], "type") # 0assert(rate ~= false and interval ~= false and type ~= false, "RateLimiter is not initialized")local valueName = KEYS[2] # {xindoo.limiter}:value 用来存储残余许可数量local permitsName = KEYS[4] # {xindoo.limiter}:permits 记录了所有许可收回的工夫戳 # 如果是单实例模式,name信息前面就须要拼接上clientId来辨别进去了if type == "1" then valueName = KEYS[3] # {xindoo.limiter}:value:b474c7d5-862c-4be2-9656-f4011c269d54 permitsName = KEYS[5] # {xindoo.limiter}:permits:b474c7d5-862c-4be2-9656-f4011c269d54end# 对参数校验 assert(tonumber(rate) >= tonumber(ARGV[1]), "Requested permits amount could not exceed defined rate")# 获取以后还有多少许可 local currentValue = redis.call("get", valueName) local res# 如果有记录以后还残余多少许可 if currentValue ~= false then # 回收已过期的许可数量 local expiredValues = redis.call("zrangebyscore", permitsName, 0, tonumber(ARGV[2]) - interval) local released = 0 for i, v in ipairs(expiredValues) do local random, permits = struct.unpack("Bc0I", v) released = released + permits end # 清理已过期的许可记录 if released > 0 then redis.call("zremrangebyscore", permitsName, 0, tonumber(ARGV[2]) - interval) if tonumber(currentValue) + released > tonumber(rate) then currentValue = tonumber(rate) - redis.call("zcard", permitsName) else currentValue = tonumber(currentValue) + released end redis.call("set", valueName, currentValue) end # ARGV permit timestamp random, random是一个随机的8字节 # 如果残余许可不够,须要在res中返回下个许可须要期待多长时间 if tonumber(currentValue) < tonumber(ARGV[1]) then local firstValue = redis.call("zrange", permitsName, 0, 0, "withscores") res = 3 + interval - (tonumber(ARGV[2]) - tonumber(firstValue[2])) else redis.call("zadd", permitsName, ARGV[2], struct.pack("Bc0I", string.len(ARGV[3]), ARGV[3], ARGV[1])) # 减小可用许可量 redis.call("decrby", valueName, ARGV[1]) res = nil endelse # 反之,记录到还有多少许可,阐明是首次应用或者之前已记录的信息曾经过期了,就将配置rate写进去,并缩小许可数 redis.call("set", valueName, rate) redis.call("zadd", permitsName, ARGV[2], struct.pack("Bc0I", string.len(ARGV[3]), ARGV[3], ARGV[1])) redis.call("decrby", valueName, ARGV[1]) res = nilendlocal ttl = redis.call("pttl", KEYS[1])# 重置if ttl > 0 then redis.call("pexpire", valueName, ttl) redis.call("pexpire", permitsName, ttl)endreturn res 即使是加了正文,置信你还是很难一下子看懂这段代码的,接下来我就以其在Redis中的数据存储模式,然辅以流程图让大家彻底理解其实现实现原理。 ...

February 11, 2023 · 2 min · jiezi

关于redis:故障分析-Redis-AOF-重写源码分析

作者:朱鹏举 新人 DBA ,会点 MySQL ,Redis ,Oracle ,在常识的陆地中挣扎,活下来就算胜利... 本文起源:原创投稿 *爱可生开源社区出品,原创内容未经受权不得随便应用,转载请分割小编并注明起源。 AOF 作为 Redis 的数据长久化形式之一,通过追加写的形式将 Redis 服务器所执行的写命令写入到 AOF 日志中来记录数据库的状态。但当一个键值对被多条写命令重复批改时,AOF 日志会记录相应的所有命令,这也就意味着 AOF 日志中存在反复的"有效命令",造成的后果就是 AOF 日志文件越来越大,应用 AOF 日志来进行数据恢复所需的工夫越来越长。为了解决这个问题,Redis 推出了 AOF 重写性能 什么是 AOF 重写简略来说,AOF 重写就是依据过后键值对的最新状态,为它生成对应的写入命令,而后写入到长期 AOF 日志中。在重写期间 Redis 会将产生更改的数据写入到重写缓冲区 aof_rewrite_buf_blocks 中,于重写完结后合并到长期 AOF 日志中,最初应用长期 AOF 日志替换原来的 AOF 日志。当然,为了防止阻塞主线程,Redis 会 fork 一个过程来执行 AOF 重写操作。 如何定义 AOF 重写缓冲区我晓得你很急,然而你先别急,在理解AOF重写流程之前你会先遇到第一个问题,那就是如何定义AOF重写缓冲区。 一般来说咱们会想到用malloc函数来初始化一块内存用于保留AOF重写期间主过程收到的命令,当残余空间有余时再用realloc函数对其进行扩容。然而Redis并没有这么做,Redis定义了一个aofrwblock构造体,其中蕴含了一个10MB大小的字符数组,当做一个数据块,负责记录AOF重写期间主过程收到的命令,而后应用aof_rewrite_buf_blocks列表将这些数据块连接起来,每次调配一个aofrwblock数据块。 //AOF重写缓冲区大小为10MB,每一次调配一个aofrwblocktypedef struct aofrwblock {unsigned long used, free;char buf[AOF_RW_BUF_BLOCK_SIZE]; //10MB} aofrwblock;那么问题来了,为什么 Redis 的开发者要抉择本人保护一个字符数组呢,答案是在应用 realloc 函数进行扩容的时候,如果此时客户端的写申请波及到正在长久化的数据,那么就会触发 Linux 内核的大页机制,造成不必要的内存空间节约,并且申请内存的工夫变长。 ...

February 9, 2023 · 5 min · jiezi

关于redis:Redis-异步客户端选型及落地实践

作者:京东科技 王晨Redis异步客户端选型及落地实际可视化服务编排零碎是可能通过线上可视化拖拽、配置的形式实现对接口的编排,可在线实现服务的调试、测试,实现业务需要的交付,具体内容可参考:https://mp.weixin.qq.com/s/5oN9JqWN7n-4Zv6B9K8kWQ。 为了反对更加宽泛的业务场景,可视化编排零碎近期须要反对对缓存的操作性能,为保障编排零碎的性能,服务的执行过程采纳了异步的形式,因而咱们思考应用Redis的异步客户端来实现对缓存的操作。 Redis客户端Jedis/LettuceRedis官网举荐的Redis客户端有Jedis、Lettuce等等,其中Jedis 是老牌的 Redis 的 Java 实现客户端,提供了比拟全面的 Redis 命令的反对,在spring-boot 1.x 默认应用Jedis。 然而Jedis应用阻塞的 IO,且其办法调用都是同步的,程序流须要等到 sockets 解决完 IO 能力执行,不反对异步,在并发场景下,应用Jedis客户端会消耗较多的资源。 此外,Jedis 客户端实例不是线程平安的,要想保障线程平安,必须要应用连接池,每个线程须要时从连接池取出连贯实例,实现操作后或者遇到异样偿还实例。当连接数随着业务一直上升时,对物理连贯的耗费也会成为性能和稳定性的潜在危险点。因而在spring-boot 2.x中,redis客户端默认改用了Lettuce。 咱们能够看下 Spring Data Redis 帮忙文档给出的比照表格,外面具体地记录了两个支流Redis客户端之间的差别。 异步客户端LettuceSpring Boot自2.0版本开始默认应用Lettuce作为Redis的客户端。Lettuce客户端基于Netty的NIO框架实现,对于大多数的Redis操作,只须要维持繁多的连贯即可高效反对业务端的并发申请 —— 这点与Jedis的连接池模式有很大不同。同时,Lettuce反对的个性更加全面,且其性能体现并不逊于,甚至优于Jedis。 Netty是由JBOSS提供的一个java开源框架,现为 Github上的独立我的项目。Netty提供异步的、事件驱动的网络应用程序框架和工具,用以疾速开发高性能、高可靠性的网络服务器和客户端程序。 也就是说,Netty 是一个基于NIO的客户、服务器端的编程框架,应用Netty 能够确保你疾速和简略的开发出一个网络应用,例如实现了某种协定的客户、服务端利用。Netty相当于简化和流线化了网络应用的编程开发过程,例如:基于TCP和UDP的socket服务开发。 上图展现了Netty NIO的外围逻辑。NIO通常被了解为non-blocking I/O的缩写,示意非阻塞I/O操作。图中Channel示意一个连贯通道,用于承载连贯治理及读写操作;EventLoop则是事件处理的外围形象。一个EventLoop能够服务于多个Channel,但它只会与繁多线程绑定。EventLoop中所有I/O事件和用户工作的解决都在该线程上进行;其中除了选择器Selector的事件监听动作外,对连贯通道的读写操作均以非阻塞的形式进行 —— 这是NIO与BIO(blocking I/O,即阻塞式I/O)的重要区别,也是NIO模式性能优异的起因。 Lettuce凭借繁多连贯就能够反对业务端的大部分并发需要,这依赖于以下几个因素的独特作用: 1.Netty的单个EventLoop仅与繁多线程绑定,业务端的并发申请均会被放入EventLoop的工作队列中,最终被该线程程序解决。同时,Lettuce本身也会保护一个队列,当其通过EventLoop向Redis发送指令时,胜利发送的指令会被放入该队列;当收到服务端的响应时,Lettuce又会以FIFO的形式从队列的头部取出对应的指令,进行后续解决。 2.Redis服务端自身也是基于NIO模型,应用繁多线程解决客户端申请。尽管Redis能同时维持成千盈百个客户端连贯,然而在某一时刻,某个客户端连贯的申请均是被程序解决及响应的。 3.Redis客户端与服务端通过TCP协定连贯,而TCP协定自身会保障数据传输的程序性。 如此,Lettuce在保障申请解决程序的根底上,人造地应用了管道模式(pipelining)与Redis交互 —— 在多个业务线程并发申请的状况下,客户端不用期待服务端对以后申请的响应,即可在同一个连贯上收回下一个申请。这在减速了Redis申请解决的同时,也高效地利用了TCP连贯的全双工个性(full-duplex)。而与之绝对的,在没有显式指定应用管道模式的状况下,Jedis只能在解决完某个Redis连贯上以后申请的响应后,能力持续应用该连贯发动下一个申请。 在并发场景下,业务零碎短时间内可能会收回大量申请,在管道模式中,这些申请被对立发送至Redis服务端,待处理实现后对立返回,可能大大晋升业务零碎的运行效率,突破性能瓶颈。R2M采纳了Redis Cluster模式,在通过Lettuce连贯R2M之前,应该先对Redis Cluster模式有肯定的理解。 Redis Cluster模式在redis3.0之前,如果想搭建一个集群架构还是挺简单的,就算是基于一些第三方的中间件搭建的集群总感觉有那么点差强人意,或者基于sentinel哨兵搭建的主从架构在高可用上体现又不是很好,尤其是当数据量越来越大,单纯主从构造无奈满足对性能的需要时,矛盾便产生了。 随着redis cluster的推出,这种海量数据+高并发+高可用的场景真正从根本上失去了无效的反对。 cluster 模式是redis官网提供的集群模式,应用了Sharding 技术,不仅实现了高可用、读写拆散、也实现了真正的分布式存储。 集群外部通信在redis cluster集群外部通过gossip协定进行通信,集群元数据扩散的存在于各个节点,通过gossip进行元数据的替换。 不同于zookeeper分布式协调中间件,采纳集中式的集群元数据存储。redis cluster采纳分布式的元数据管理,优缺点还是比拟显著的。在redis中集中式的元数据管理相似sentinel主从架构模式。集中式有点在于元数据更新实效性更高,但容错性不如分布式治理。gossip协定长处在于大大加强集群容错性。 redis cluster集群中单节点个别配置两个端口,一个端口如6379对外提供api,另一个个别是加1w,比方16379进行节点间的元数据交换即用于gossip协定通信。 ...

February 8, 2023 · 1 min · jiezi

关于redis:Redis核心技术3638

36 秒杀秒杀场景能够分成秒杀前、秒杀中和秒杀后三个阶段。 次要特色: 刹时并发高(数据库千级并发,Redis万级并发)读多写少,读数据比较简单秒杀过程:1.秒杀前:尽量把商品详情页的页面元素动态化,而后应用 CDN 或是浏览器把这些动态化的元素缓存起来。无需应用Redis。 2.秒杀中:这个阶段的操作就是三个:库存查验、库存扣减和订单解决,并发压力在库存查验上。 应用Redis保留库存量,这样一来,申请能够间接从 Redis 中读取库存并进行查验。应用Redis进行库存扣减应用数据库进行订单解决(保障事务)注:为了防止申请查问到旧的库存值,库存查验和库存扣减这两个操作须要保障原子性(lua脚本)。 3.秒杀完结后:失败用户刷新商品详情,胜利用户刷新订单详情。无需应用Redis。 原子操作在秒杀场景中,一个商品的库存对应了两个信息,别离是总库存量和已秒杀量。其中,itemID 是商品的编号,total 是总库存量,ordered 是已秒杀量。 key: itemIDvalue: {total: N, ordered: M}办法1:lua脚本 #获取商品库存信息 local counts = redis.call("HMGET", KEYS[1], "total", "ordered");#将总库存转换为数值local total = tonumber(counts[1])#将已被秒杀的库存转换为数值local ordered = tonumber(counts[2]) #如果以后申请的库存量加上已被秒杀的库存量依然小于总库存量,就能够更新库存 if ordered + k <= total then #更新已秒杀的库存量 redis.call("HINCRBY",KEYS[1],"ordered",k) return k; end return 0办法2:分布式锁先让客户端向 Redis 申请分布式锁,只有拿到锁的客户端能力执行库存查验和库存扣减。 //应用商品ID作为keykey = itemID//应用客户端惟一标识作为valueval = clientUniqueID//申请分布式锁,Timeout是超时工夫lock =acquireLock(key, val, Timeout)//当拿到锁后,能力进行库存查验和扣减if(lock == True) { //库存查验和扣减 availStock = DECR(key, k) //库存曾经扣减完了,开释锁,返回秒杀失败 if (availStock < 0) { releaseLock(key, val) return error } //库存扣减胜利,开释锁 else{ releaseLock(key, val) //订单解决 }}//没有拿到锁,间接返回else return留神:应用分布式锁时,客户端须要先向 Redis 申请锁,只有申请到了锁,能力进行库存查验等操作,这样一来,客户端在争抢分布式锁时,大部分秒杀申请自身就会因为抢不到锁而被拦挡。 ...

February 8, 2023 · 2 min · jiezi

关于redis:Redis核心技术3135

31 事务机制Redis 提供了 MULTI、EXEC 两个命令来实现事务。 原子性原子性的要求就是一个事务中的多个操作必须都实现,或者都不实现。 状况1:在执行EXEC命令前,客户端发送的命令有谬误,且Redis实例检出了(如语法错误)。后果:执行EXEC时拒绝执行所有命令,返回事务失败。 状况2:在执行EXEC命令前,命令有谬误但Redis实例没有检出(如操作数据类型不匹配)。后果:Redis会对谬误命令报错,但还是会把正确的命令执行完。影响:事务的原子性无奈保障。留神:Redis没有提供回滚机制。 DISCARD命令:被动放弃事务执行,把暂存的命令队列清空。 状况3:执行EXEC时实例故障,导致事务执行失败。后果1:如果开启了AOF,会有局部日志记录到AOF中,须要应用redis-check-aof命令,将未实现的事务操作剔除,保障原子性。后果2:如果没有开启AOF,实例重启后数据无奈复原。 因为 RDB 不会在事务执行时执行,所以 RDB 文件中不会记录只执行了一部分的后果数据。之后用 RDB 复原实例数据,复原的还是事务之前的数据。 一致性数据库中的数据在事务执行前后是统一的。 状况1:命令入队时就报错后果:事务放弃执行,能够保障一致性。 状况2:命令入队时没报错,执行时报错后果:谬误命令不会执行,能够保障一致性解析:统一的概念是数据合乎数据库自身的定义和要求,没有蕴含非法或者有效的谬误数据,只有没有执行谬误的命令,那么就保障了一致性。 状况3:EXEC命令执行时实例故障后果1:没有开启RDB或AOF,数据失落,能够保障一致性。后果2:应用RDB快照,RDB不会在事务中执行,能够保障一致性。后果3:应用AOF日志,须要应用redis-check-aof清理事务中已实现的操作,清理后数据一致性。 总结:Redis能够保障事务一致性。 隔离性数据库在执行一个事务时,其它操作无奈存取到正在执行事务拜访的数据。 事务的隔离性受并发操作的影响,分为EXEC执行前和执行后两个阶段。 EXEC执行前并发:须要应用WATCH机制保障隔离性;EXEC执行后并发:能够保障隔离性。WATCH机制在事务执行前,监控一个或多个键的值变动状况,当事务调用 EXEC 命令执行时,WATCH 机制会先查看监控的键是否被其它客户端批改了。 如果批改了,就放弃事务执行,防止事务的隔离性被毁坏。客户端能够再次执行事务,如果没有并发批改事务数据的操作了,事务就能失常执行,保障了隔离性。Redis 是用单线程执行命令,EXEC 命令执行后,Redis 会保障先把命令队列中的所有命令执行完。所以,在这种状况下,并发操作不会毁坏事务的隔离性。 持久性数据库执行事务后,数据的批改要被长久化保留下来。当数据库重启后,数据的值须要是被批改后的值。 状况1:未开启AOF和RDB,重启数据失落,没有持久性。状况2:RDB模式,如果在事务执行后,RDB快照执行前宕机,数据会失落。状况3:AOF三种配置都存在数据失落状况(always会失落一个事件循环的数据)。解析:每次执行客户端命令的时候操作并没有写到aof文件中,只是写到了aof_buf内存当中,当进行下一个事件循环(event_loop)的时候执行beforeSleep之时,才会去fsync到disk中。 论断:Redis无奈保障事务的持久性。 32 主从同步与故障切换Redis 的主从同步机制不仅能够让从库服务更多的读申请,分担主库的压力,而且还能在主库产生故障时,进行主从库切换,提供高牢靠服务。 主从数据不统一主从数据不统一,指的是客户端从库中读取到的值和主库中的最新值不统一。 起因:主从库的命令复制是异步进行的。 主库收到新的写命令,发送给从库;主库在本地执行命令后,向客户端返回后果如果从库没有执行命令,主从数据就不统一了从库滞后执行命令起因: 网络传输提早从库阻塞(执行汇合操作等简单命令)解决方案:内部程序监控 Redis的INFO replication命令,能够查看主库接管写命令的进度信息(master_repl_offset)和从库复制写命令的进度信息(slave_repl_offset)开发监控程序监控master_repl_offset和slave_repl_offset的差值,超过阈值客户端不再读该从库读取过期数据应用Redis主从集群时,有时会读取到过期数据,这是由Redis的过期数据删除策略引起的。 Redis过期数据删除策略: 惰性删除:数据过期后不会立刻删除,而是等到有申请读写该数据时进行查看,发现过期时再删除。 长处:缩小CPU资源应用。毛病:占用内存。定期删除:每隔一段时间(默认100ms)随机选出一些数据判断是否过期,删除过期数据。状况1:如果客户端从主库读取过期数据,主库会触发删除操作;如果客户端从库读取过期数据,从库不会触发删除操作,会返回空值(3.2以上版本)。 状况2:Redis设置过期工夫命令在从库上可能被延后,此时可能读取到过期数据。 过期工夫命令: EXPIRE:设置存活工夫x秒PEXPIRE:设置存活工夫x毫秒EXPIREAT:设置过期工夫戳(秒)PEXPIREAT:设置过期工夫戳(毫秒)倡议: 在业务利用中应用 EXPIREAT/PEXPIREAT 命令,把数据的过期工夫设置为具体的工夫点,防止读到过期数据。留神主从节点时钟要统一,让主从节点和雷同的NTP(工夫)服务器进行时钟同步。不合理配置项protected-mode 配置项:限定哨兵是否被其它服务器拜访,设置yes时哨兵间无奈通信,无奈判断主库下线,造成redis不可用。 留神将protected-mode设置为nobing配置项设置为其它哨兵实例的IP地址cluster-node-timeout配置项:设置集群实例响应心跳音讯超时工夫。如果主从且切换工夫较长,会导致实例心跳超时;如切换实例超过半数,会被Redis Cluster判断为异样,导致集群挂掉。 倡议设置为10~20秒slave-server-stale-data配置项:设置从库是否解决数据读写命令,yes可能解决到过期数据,倡议设置为no,在主从失去链接或信息同步时,slave会对除了INFO和SLAVEOF外的所有命令回复"SYNC with master in progress"slave-read-only配置项:从库是否解决写命令(只读),yes时只能解决读申请,无奈解决写申请。33 脑裂脑裂指主从集群中,同时有两个主节点,都能接管读写申请,导致不同客户端向不同主节点写入数据,导致数据失落。 数据失落起因:从库降级为主库后,原主库和新主库从新进行全量同步,须要清空本地数据,加载新主库的RDB文件,切换期间原主库写入的数据就失落了。 查找起因1.确认数据同步:主从集群数据失落最常见起因是主库的数据还没有同步到从库时,主库产生故障,从库降级为主库后,未同步数据失落。判断办法:计算master_repl_offset 和 slave_repl_offset 的差值,如果slave小于master,则数据失落是因为同步未实现导致的。 2.排查客户端操作日志:如果主从切换后,有客户端仍在和原主库通信,则认为产生了脑裂。 3.脑裂起因:原主库假故障主库下线起因:超过(quorum配置)的哨兵实例和主库心跳都超时了,判断主库主观下线,哨兵开始执行切换。切换实现后,客户端和新主库进行通信。主库假故障:主库没有响应哨兵心跳,被判断为主观下线,在没有实现主从切换时,又重新处理申请了,此时客户端仍能够和原主库通信,写入数据。 ...

February 8, 2023 · 2 min · jiezi

关于redis:R2M分布式锁原理及实践

作者:京东科技 张石磊 1 案例引入名词简介: 资源:能够了解为一条内容,或者图+文字+链接的载体。 档位ID: 资源的分类组,资源必须归属于档位。 问题形容:当同一个档位下2条资源同时审批通过时,收到擎天审批零碎2条音讯,消费者利用部署了2台机器,此时正好由2台机器别离生产,在并发生产时,先更新资源状态,而后写缓存,每次取前100条资源,相似select * from resource where gear_id=xxx limit 100 order by id desc; 在写档位缓存,此时事务未提交,并发查问时依据档位Id查问时查问不到对方的数据,全量写缓存时导致后写的缓存笼罩了先写的缓存,即缓存被笼罩,导致投放资源缺失。 计划思考 : 计划1:一台机器生产mq–单点问题 计划2:将同档位ID的资源路由到同一个queue,须要审批零碎配合依据档位Id做路由,审批零碎发的音讯不只是cms审批数据,此计划不实用。 计划3:在档位级别加分布式锁。 经比拟,最终采纳计划3是适合的计划. 2 锁阐明和分布式锁抉择synchronized锁的粒度是JVM过程维度,集群模式下,不能对共享资源加锁,此时须要跨JVM过程的分布式锁。 分布式锁形式外围实现形式长处毛病剖析 1 数据库: 乐观锁,lock 乐观锁,通过版本号实现version 实现简略,不依赖中间件 数据库IO瓶颈,性能差 单实例存在单点问题,主从架构存在数据不统一,主从切换时其余客户端可反复加锁。 2 zookeeper 创立长期节点 CP模型,可靠性高,不存在主从切换不统一问题 频繁创立和销毁长期节点,且 集群模式下,leader数据须要同步到follower才算加锁胜利,性能不如redis 主从切换服务不可用 3 redis集群 setnx+expire 性能高 有封装好的框架redission 反对超时主动删除锁 集群反对高可用,AP模型 主从切换时其余客户端可反复加锁。 R2M是基于开源的Redis cluster(Redis 3.0以上版本)构建的高性能分布式缓存零碎,咱们零碎始终在应用,3.2.5版本开始反对分布式锁。 3 r2m分布式锁原理示例代码: String lockKey = CacheKeyHelper.getGearLockKey(EnvEnum.getEnvFlagEnum(envCode),resource.getGearId());R2mLock lock = (R2mLock) r2mClusterClient.getLock(lockKey);//获取锁,锁的默认有效期30s,获取不到锁就阻塞lock.lock();try { //业务代码 resourceService.afterApprovedHandle(resource);} finally { //开释锁 lock.unlock();}1 加锁外围流程:加锁流程图: ...

February 7, 2023 · 3 min · jiezi

关于redis:Redis主从复制

Redis 是如何基于状态机的设计思路来实现主从复制的? (1) Redis主从复制从原理上来说,Redis 的主从复制次要包含了全量复制、增量复制和长连贯同步三种状况。 全量复制传输 RDB 文件;增量复制传输主从断连期间的命令;长连贯同步则是把主节点失常收到的申请传输给从节点。(2) 为什么须要主从复制为了进步服务的分区容错性,个别都会通过冗余来进步分区容错性。 主从复制技术相似于冗余,是进步分区容错性的一种方法。 在应用 Redis 或 MySQL 数据库时,常常会应用主从复制来实现主从节点间的数据同步,以此晋升服务的高可用性。 (3) Redis主从复制原理从库设置主库主从建设连贯主从握手并判断复制类型复制类型判断与执行(3.1) 从库设置主库次要是取得了主库的 IP 和端口号。 能够用三种形式来设置。 形式一:在实例 A 上执行 replicaof masterip masterport 的主从复制命令,指明实例 B 的 IP(masterip)和端口号(masterport)。 形式二:在实例 A 的配置文件中设置 replicaof masterip masterport,实例 A 能够通过解析文件取得主库 IP 和端口号。 形式三:在实例 A 启动时,设置启动参数–replicaof [masterip] [masterport]。实例 A 解析启动参数,就能取得主库的 IP 和端口号。 (3.2) 主从建设连贯从库取得了主库的IP和端口号,就会尝试和主库建设TCP网络连接,并且会在建设好的网络连接上,监听是否有主库发送的命令。 (3.3) 主从握手当从库和主库建设好连贯之后,从库就开始和主库进行握手。 简略来说,握手过程就是主从库间互相发送PING-PONG音讯,同时从库依据配置信息向主库进行验证。 从库把本人的 IP、端口号,以及对无盘复制和 PSYNC 2 协定的反对状况发给主库。 (3.4) 复制类型判断与执行等到主从库之间的握手实现后,从库就会给主库发送 PSYNC 命令。主库会依据从库发送的命令参数作出相应的三种回复,别离是执行全量复制、执行增量复制、产生谬误。 最初,从库在收到上述回复后,就会依据回复的复制类型,开始执行具体的复制操作。 (4) 主从复制源码解读主从复制中的状态机具体对应的是什么呢? // file: src/server.h/* */struct redisServer { // ... /* 复制相干 */ char *masterauth; // 用于和主库进行验证的明码 char *masterhost; // 主库主机名 int masterport; // 主库端口号 int repl_timeout; // client *master; // 从库上用来和主库连贯的客户端 client *cached_master; // 从库上缓存的主库信息 int repl_state; // 从库的复制状态 off_t repl_transfer_size; off_t repl_transfer_read; off_t repl_transfer_last_fsync_off; connection *repl_transfer_s; int repl_transfer_fd; char *repl_transfer_tmpfile; time_t repl_transfer_lastio; int repl_serve_stale_data; int repl_slave_ro; int repl_slave_ignore_maxmemory; time_t repl_down_since; int repl_disable_tcp_nodelay; int slave_priority; int slave_announce_port; char *slave_announce_ip; // ...}(4.1) 从库设置主库// file: src/server.cvoid initServerConfig(void) { // 初始化复制状态 默认为没有 server.repl_state = REPL_STATE_NONE; }实例执行了 replicaof masterip masterport 命令 ...

February 5, 2023 · 14 min · jiezi

关于redis:Redis-AOF

问大家一个问题,如果Redis宕机,内存中的数据全副失落,怎么复原数据? Redis 别离提供了 RDB 和 AOF 两种长久化机制: RDB将数据库的快照(snapshot)以二进制的形式保留到磁盘中。 AOF则以协定文本的形式,将所有对数据库进行过写入的命令(及其参数)记录到AOF文件,以此达到记录数据库状态的目标。 (1) AOF日志是什么AOF(Append Only File)日志是一种写后日志,在Redis先执行命令,把数据写入内存后,而后才记录日志,日志会追加到文件开端,所以叫AOF日志。 和咱们常见的WAL日志不同,WAL(Write Ahead Log)是写前日志,在理论写数据前,先把批改的数据记到日志文件中,再去执行命令,这个就要求数据库须要额定的查看命令是否正确。 (2) 为什么要用AOFAOF日志的作用次要有2个: 1.用来在redis宕机后复原数据;2.能够用来主从数据同步。 (3) AOF原理(3.1) AOF命令同步原理Redis将所有对数据库进行过写入的命令(及其参数)记录到 AOF 文件, 以此达到记录数据库状态的目标。 redis> RPUSH list 1 2 3 4(integer) 4redis> LRANGE list 0 -11) "1"2) "2"3) "3"4) "4"redis> KEYS *1) "list"redis> RPOP list"4"redis> LPOP list"1"redis> LPUSH list 1(integer) 3redis> LRANGE list 0 -11) "1"2) "2"3) "3"那么其中四条对数据库有批改的写入命令就会被同步到 AOF 文件中: RPUSH list 1 2 3 4RPOP listLPOP listLPUSH list 1(3.2) Reids AOF数据存储形式为了解决的不便, AOF文件应用网络通讯协定的格局来保留这些命令。 ...

February 3, 2023 · 4 min · jiezi

关于redis:Lazy-Free会影响缓存替换吗

无论是 LRU 算法还是 LFU 算法,它们在删除淘汰数据时,实际上都会依据 Redis server 的 lazyfree-lazy-eviction 配置项,来决定是否应用 Lazy Free,也就是惰性删除。 (1) 惰性删除是什么惰性删除是 Redis 4.0 版本后提供的性能,它会应用后盾线程来执行删除数据的工作 (2) 为什么要用惰性删除能够防止了删除操作对主线程的阻塞。 https://github.com/redis/redi... (3) 惰性删除怎么用(3.1) 惰性删除的配置当 Redis server 须要启动惰性删除时,须要在redis.conf配置文件中设置和惰性删除相干的配置项。其中包含了四个配置项,别离对应了如下的四种场景。lazyfree-lazy-eviction:对应缓存淘汰时的数据删除场景。lazyfree-lazy-expire:对应过期 key 的删除场景。lazyfree-lazy-server-del:对应会隐式进行删除操作的 server 命令执行场景。replica-lazy-flush:对应从节点实现全量同步后,删除原有旧数据的场景。 这四个配置项的默认值都是 no。所以,如果要在缓存淘汰时启用,就须要将 lazyfree-lazy-eviction 设置为 yes。 (4) 惰性删除原理(4.1) 被淘汰数据的删除过程freeMemoryIfNeeded 函数(在evict.c文件中)会负责执行数据淘汰的流程。 该函数在筛选出被淘汰的键值对后,就要开始删除被淘汰的数据,这个删除过程次要分成两步。 第一步,freeMemoryIfNeeded 函数会为被淘汰的 key 创立一个 SDS 对象,而后调用 propagateExpire 函数 第二步,freeMemoryIfNeeded 函数会依据 server 是否启用了惰性删除,别离执行 // file: src/evict.c/* This function is periodically called to see if there is memory to free * according to the current "maxmemory" settings. In case we are over the * memory limit, the function will try to free some memory to return back * under the limit. * * The function returns C_OK if we are under the memory limit or if we * were over the limit, but the attempt to free memory was successful. * Otherwise if we are over the memory limit, but not enough memory * was freed to return back under the limit, the function returns C_ERR. */int freeMemoryIfNeeded(void) { int keys_freed = 0; // 省略局部代码 ... // 曾经开释的内存大小 < 打算要开释的内存大小 while (mem_freed < mem_tofree) { int j, k, i; // sds sds bestkey = NULL; // 省略局部代码 // 最终移除抉择要淘汰的key if (bestkey) { // 抉择对应的db db = server.db+bestdbid; // 创立redisObject robj *keyobj = createStringObject(bestkey,sdslen(bestkey)); // 删除 propagateExpire(db,keyobj,server.lazyfree_lazy_eviction); /* We compute the amount of memory freed by db*Delete() alone. * It is possible that actually the memory needed to propagate * the DEL in AOF and replication link is greater than the one * we are freeing removing the key, but we can't account for * that otherwise we would never exit the loop. * * Same for CSC invalidation messages generated by signalModifiedKey. * * AOF and Output buffer memory will be freed eventually so * we only care about memory used by the key space. */ delta = (long long) zmalloc_used_memory(); latencyStartMonitor(eviction_latency); // 是否惰性删除 if (server.lazyfree_lazy_eviction) dbAsyncDelete(db,keyobj); // 异步删除 else dbSyncDelete(db,keyobj); // 同步删除 latencyEndMonitor(eviction_latency); latencyAddSampleIfNeeded("eviction-del",eviction_latency); delta -= (long long) zmalloc_used_memory(); mem_freed += delta; server.stat_evictedkeys++; signalModifiedKey(NULL,db,keyobj); notifyKeyspaceEvent(NOTIFY_EVICTED, "evicted", keyobj, db->id); decrRefCount(keyobj); keys_freed++; /* When the memory to free starts to be big enough, we may * start spending so much time here that is impossible to * deliver data to the slaves fast enough, so we force the * transmission here inside the loop. */ if (slaves) flushSlavesOutputBuffers(); /* Normally our stop condition is the ability to release * a fixed, pre-computed amount of memory. However when we * are deleting objects in another thread, it's better to * check, from time to time, if we already reached our target * memory, since the "mem_freed" amount is computed only * across the dbAsyncDelete() call, while the thread can * release the memory all the time. */ if (server.lazyfree_lazy_eviction && !(keys_freed % 16)) { if (getMaxmemoryState(NULL,NULL,NULL,NULL) == C_OK) { /* Let's satisfy our stop condition. */ mem_freed = mem_tofree; } } } else { goto cant_free; /* nothing to free... */ } } result = C_OK;cant_free: /* We are here if we are not able to reclaim memory. There is only one * last thing we can try: check if the lazyfree thread has jobs in queue * and wait... */ if (result != C_OK) { latencyStartMonitor(lazyfree_latency); while(bioPendingJobsOfType(BIO_LAZY_FREE)) { if (getMaxmemoryState(NULL,NULL,NULL,NULL) == C_OK) { result = C_OK; break; } usleep(1000); } latencyEndMonitor(lazyfree_latency); latencyAddSampleIfNeeded("eviction-lazyfree",lazyfree_latency); } latencyEndMonitor(latency); latencyAddSampleIfNeeded("eviction-cycle",latency); return result;}(4.1.1) 流传过期key-propagateExpire// file: src/evict.c/* * 流传 过期keys 到 从节点 和 AOF 文件。 * 当主节点中的key过期时,如果启用(),则会将对此key的DEL操作发送到 所有从节点 和 AOF 文件。 * * 这样key过期集中在一个中央,并且因为 AOF 和 主->从 链接保障操作程序, * 即便咱们容许对过期key进行写操作,所有也会保持一致。 * * @param *db redisDb * @param *key 过期key对象(redisObject格局) * @param lazy 过期策略 */void propagateExpire(redisDb *db, robj *key, int lazy) { robj *argv[2]; argv[0] = lazy ? shared.unlink : shared.del; argv[1] = key; // 援用计数 +1 incrRefCount(argv[0]); // 援用计数 +1 incrRefCount(argv[1]); // AOF未敞开 if (server.aof_state != AOF_OFF) feedAppendOnlyFile(server.delCommand,db->id,argv,2); // 把删除命令追加到AOF缓存 // 将删除操作同步给从节点 replicationFeedSlaves(server.slaves,db->id,argv,2); // 援用计数 -1 decrRefCount(argv[0]); // 援用计数 -1 decrRefCount(argv[1]);}(4.1.2) 惰性删除-dbAsyncDelete// file: src/evict.c/**/int freeMemoryIfNeeded(void) { // 省略局部代码 // 是否惰性删除 if (server.lazyfree_lazy_eviction) dbAsyncDelete(db,keyobj); // 异步删除 else dbSyncDelete(db,keyobj); // 同步删除 // 省略局部代码} ...

February 1, 2023 · 6 min · jiezi

关于redis:Redis的设计与实现总结

集体真的很喜爱这本书, 从对C语言无所不通, 到发现C语言居然如此简洁, 以至于我喜爱上了C! 对此后面的底层数据结构也读了几次, 大抵整顿了书里的内容, 前面的就粗略看了一下, 不再细细整顿了. Redis的设计与实现(1)-SDS简略动静字符串Redis的设计与实现(2)-链表Redis的设计与实现(3)-字典Redis的设计与实现(4)-跳跃表Redis的设计与实现(5)-整数汇合Redis的设计与实现(6)-压缩列表 整体的感悟吧, 感觉 Redis 的作者, 对每一块内存十分悭吝, 为了节俭内存而制作出各种各样的编码和技巧. 浏览源码的过程中, 也学习到了宏的技巧, 比如说: #define ZIP_ENTRY_ENCODING(ptr, encoding) do { \ (encoding) = (ptr[0]); \ if ((encoding) < ZIP_STR_MASK) (encoding) &= ZIP_STR_MASK; \} while(0)大量的应用 do { ... } while(0) , 上网找过, 说这样写宏开展后就不会编译谬误, 当然情理是浅显易懂的. 有些函数, 比方下面的 ZIP_ENTRY_ENCODING , 如果写成真真正正的函数, 会减少函数调用栈的开销, 据说 << C 和指针 >> 这本书会提及, 筹备有工夫好好看看. 源码的正文版, 真的很好, Redis的代码读起来也还是比拟亲切. 工作上, 已经排查线上 Nginx 的 bug , 精确来说, 应该是 API 网关 kong, 它联合了 OpenResty, 对于 URL 字符串的编码问题, 具体的记不清了, 但外面对字符串的 URL 编码, 用的是查表法和位运算, 这样的转换函数真的是艰涩难懂. 程度真的无限, 我也是求教了共事, 他在 DevCPP 外面逐行调试才晓得的. ...

February 1, 2023 · 1 min · jiezi

关于redis:LFU算法和其他算法相比有优势吗

(1) LFU源码解读LFU 算法的启用,是通过设置 Redis 配置文件 redis.conf 中的 maxmemory 和 maxmemory-policy。 LFU 算法的实现能够分成三局部内容,别离是键值对拜访频率记录、键值对拜访频率初始化和更新,以及LFU算法淘汰数据。 (1.1) 键值对拜访频率记录每个键值对的值都对应了一个 redisObject 构造体,其中有一个 24 bits 的 lru 变量。 LRU 算法和 LFU 算法并不会同时应用。为了节俭内存开销,Redis 源码就复用了 lru 变量来记录 LFU 算法所需的拜访频率信息。 记录LFU算法的所需信息时,它会用24 bits中的低8 bits作为计数器,来记录键值对的拜访次数,同时它会用24 bits中的高16 bits,记录拜访的工夫戳。 |<---拜访工夫戳--->|< 计数器 >| 16 bits 8 bits +----------------+--------+ + Last decr time | LOG_C | +----------------+--------+ (1.2) 键值对拜访频率初始化和更新(1.2.1) 初始化键值对 lru变量初始化是在 创立redisObject调用 createObject 函数时实现的。 次要分2步:第一部是 lru 变量的高16位,是以1分钟为精度的 UNIX 工夫戳。(LFUGetTimeInMinutes) 第二部是 lru 变量的低8位,被设置为宏定义 LFU_INIT_VAL,默认值为 5。 ...

January 31, 2023 · 4 min · jiezi