当前位置: 首页 > news >正文

银川公司网站建设集美区网站建设

银川公司网站建设,集美区网站建设,建设网站多久,网页设计html成品免费Redis redis持久化机制#xff1a;RDB和AOF Redis 持久化 Redis 提供了不同级别的持久化方式: RDB持久化方式能够在指定的时间间隔能对你的数据进行快照存储. AOF持久化方式记录每次对服务器写的操作,当服务器重启的时候会重新执行这些命令来恢复原始的数据,AOF命令以redi…Redis redis持久化机制RDB和AOF Redis 持久化 Redis 提供了不同级别的持久化方式: RDB持久化方式能够在指定的时间间隔能对你的数据进行快照存储. AOF持久化方式记录每次对服务器写的操作,当服务器重启的时候会重新执行这些命令来恢复原始的数据,AOF命令以redis协议追加保存每次写的操作到文件末尾.Redis还能对AOF文件进行后台重写,使得AOF文件的体积不至于过大. 如果你只希望你的数据在服务器运行的时候存在,你也可以不使用任何持久化方式. 你也可以同时开启两种持久化方式, 在这种情况下, 当redis重启的时候会优先载入AOF文件来恢复原始的数据,因为在通常情况下AOF文件保存的数据集要比RDB文件保存的数据集要完整. 最重要的事情是了解RDB和AOF持久化方式的不同,让我们以RDB持久化方式开始: RDB的优点 RDB是一个非常紧凑的文件,它保存了某个时间点得数据集,非常适用于数据集的备份,比如你可以在每个小时报保存一下过去24小时内的数据,同时每天保存过去30天的数据,这样即使出了问题你也可以根据需求恢复到不同版本的数据集. RDB是一个紧凑的单一文件,很方便传送到另一个远端数据中心或者亚马逊的S3可能加密非常适用于灾难恢复. RDB在保存RDB文件时父进程唯一需要做的就是fork出一个子进程,接下来的工作全部由子进程来做父进程不需要再做其他IO操作所以RDB持久化方式可以最大化redis的性能. 与AOF相比,在恢复大的数据集的时候RDB方式会更快一些. RDB的缺点 如果你希望在redis意外停止工作例如电源中断的情况下丢失的数据最少的话那么RDB不适合你.虽然你可以配置不同的save时间点(例如每隔5分钟并且对数据集有100个写的操作),是Redis要完整的保存整个数据集是一个比较繁重的工作,你通常会每隔5分钟或者更久做一次完整的保存,万一在Redis意外宕机,你可能会丢失几分钟的数据. RDB 需要经常fork子进程来保存数据集到硬盘上,当数据集比较大的时候,fork的过程是非常耗时的,可能会导致Redis在一些毫秒级内不能响应客户端的请求.如果数据集巨大并且CPU性能不是很好的情况下,这种情况会持续1秒,AOF也需要fork,但是你可以调节重写日志文件的频率来提高数据集的耐久度. AOF 优点 使用AOF 会让你的Redis更加耐久: 你可以使用不同的fsync策略无fsync,每秒fsync,每次写的时候fsync.使用默认的每秒fsync策略,Redis的性能依然很好(fsync是由后台线程进行处理的,主线程会尽力处理客户端请求),一旦出现故障你最多丢失1秒的数据. AOF文件是一个只进行追加的日志文件,所以不需要写入seek,即使由于某些原因(磁盘空间已满写的过程中宕机等等)未执行完整的写入命令,你也也可使用redis-check-aof工具修复这些问题. Redis 可以在 AOF 文件体积变得过大时自动地在后台对 AOF 进行重写 重写后的新 AOF 文件包含了恢复当前数据集所需的最小命令集合。 整个重写操作是绝对安全的因为 Redis 在创建新 AOF 文件的过程中会继续将命令追加到现有的 AOF 文件里面即使重写过程中发生停机现有的 AOF 文件也不会丢失。 而一旦新 AOF 文件创建完毕Redis 就会从旧 AOF 文件切换到新 AOF 文件并开始对新 AOF 文件进行追加操作。 AOF 文件有序地保存了对数据库执行的所有写入操作 这些写入操作以 Redis 协议的格式保存 因此 AOF 文件的内容非常容易被人读懂 对文件进行分析parse也很轻松。 导出export AOF 文件也非常简单 举个例子 如果你不小心执行了 FLUSHALL 命令 但只要 AOF 文件未被重写 那么只要停止服务器 移除 AOF 文件末尾的 FLUSHALL 命令 并重启 Redis 就可以将数据集恢复到 FLUSHALL 执行之前的状态。 AOF 缺点 对于相同的数据集来说AOF 文件的体积通常要大于 RDB 文件的体积。 根据所使用的 fsync 策略AOF 的速度可能会慢于 RDB 。 在一般情况下 每秒 fsync 的性能依然非常高 而关闭 fsync 可以让 AOF 的速度和 RDB 一样快 即使在高负荷之下也是如此。 不过在处理巨大的写入载入时RDB 可以提供更有保证的最大延迟时间latency。 4.X版本的整合策略 在AOF重写策略上做了优化 在重写AOF文件时4.x版本以前是把内存数据集的操作指令落地而新版本是把内存的数据集以rdb的形式落地 这样重写后的AOF依然追加的是日志但是在恢复的时候是先rdb再增量的日志性能更优秀 Redis做分布式锁用什么命令 SETNX 格式setnx key value 将 key 的值设为 value 当且仅当 key 不存在。 若给定的 key 已经存在则 SETNX 不做任何动作,操作失败。 SETNX 是『SET if Not eXists』(如果不存在则 SET)的简写。 加锁set key value nx ex 10s 释放锁delete key Redis做分布式锁死锁有哪些情况如何解决 情况1加锁没有释放锁。需要加释放锁的操作。比如delete key。 情况2加锁后程序还没有执行释放锁程序挂了。需要用的key的过期机制。 Redis如何做分布式锁 假设有两个服务A、B都希望获得锁执行过程大致如下: Step1 服务A为了获得锁向Redis发起如下命令: SET productId:lock 0xx9p03001 NX EX 30000 其中productId由自己定义可以是与本次业务有关的id0xx9p03001是一串随机值必须保证全局唯一“NX指的是当且仅当key(也就是案例中的productId:lock”)在Redis中不存在时返回执行成功否则执行失败。EX 30000指的是在30秒后key将被自动删除。执行命令后返回成功表明服务成功的获得了锁。 Step2: 服务B为了获得锁向Redis发起同样的命令: SET productId:lock 0000111 NX EX 30000 由于Redis内已经存在同名key且并未过期因此命令执行失败服务B未能获得锁。服务B进入循环请求状态比如每隔1秒钟(自行设置)向Redis发送请求直到执行成功并获得锁。 Step3: 服务A的业务代码执行时长超过了30秒导致key超时因此Redis自动删除了key。此时服务B再次发送命令执行成功假设本次请求中设置的value值为0000222。此时需要在服务A中对key进行续期watch dog。 Step4: 服务A执行完毕为了释放锁服务A会主动向Redis发起删除key的请求。注意: 在删除key之前一定要判断服务A持有的value与Redis内存储的value是否一致。比如当前场景下Redis中的锁早就不是服务A持有的那一把了而是由服务2创建如果贸然使用服务A持有的key来删除锁则会误将服务2的锁释放掉。此外由于删除锁时涉及到一系列判断逻辑因此一般使用lua脚本具体如下: if redis.call(get, KEYS[1])ARGV[1] thenreturn redis.call(del, KEYS[1]) elsereturn 0 end Redis作为异步队列及延时队列 Redis 可以被用作异步队列Async Queue和延时队列Delayed Queue提供了可靠且高效的消息队列解决方案。下面分别说明 Redis 如何作为异步队列和延时队列 ### 1. 异步队列Async Queue 使用 Redis 作为异步队列时通常采用 List 数据结构来实现。生产者向 List 中 Push 消息而消费者则通过 Pop 或者 Blocking Pop 的方式来获取消息实现生产者和消费者之间的解耦和异步处理。 - **生产者Producer**   1. 生产者将任务或消息 Push 到 Redis 的 List 中作为队列的尾部。   2. 生产者可以根据需要向队列中不断 Push 新的消息。 - **消费者Consumer**   1. 消费者通过 Pop 命令或 BRPOPBlocking Pop命令从队列的头部获取消息。   2. 消费者处理完消息后可以继续获取下一个消息。 通过 Redis List 实现的异步队列生产者和消费者之间实现了解耦可以提高系统整体的可靠性和性能。 ### 2. 延时队列Delayed Queue 使用 Redis 作为延时队列时通常需要借助 Redis 的 Sorted Set 数据结构和一些定时任务处理的机制来实现延时消息的投递和消费。 - **生产者Producer**   1. 生产者将消息 Push 到 Redis 的 Sorted Set 中将消息的到期时间作为 Score。   2. 消息即时加入 Sorted Set 中但在到达到期时间之前不会被取出。 - **消费者Consumer**   1. 消费者定时轮询 Sorted Set获取 Score 小于当前时间的消息。   2. 消费者根据到期时间取出消息开始处理延时消息。 通过 Redis 的 Sorted Set 结构延时队列可以实现消息的有序存储和自动过期消费者可以按照一定规则获取到期的消息实现延时消息的可靠处理。 总之Redis 作为异步队列和延时队列的解决方案通过合理地使用 List 和 Sorted Set 数据结构结合生产者和消费者的配合可以实现高效、可靠的消息队列系统提高系统的性能和可靠性。 redis的过期键有哪些删除策略 过期精度 在 Redis 2.4 及以前版本过期期时间可能不是十分准确有0-1秒的误差。 从 Redis 2.6 起过期时间误差缩小到0-1毫秒。 过期和持久 Keys的过期时间使用Unix时间戳存储(从Redis 2.6开始以毫秒为单位)。这意味着即使Redis实例不可用时间也是一直在流逝的。 要想过期的工作处理好计算机必须采用稳定的时间。 如果你将RDB文件在两台时钟不同步的电脑间同步有趣的事会发生所有的 keys装载时就会过期。 即使正在运行的实例也会检查计算机的时钟例如如果你设置了一个key的有效期是1000秒然后设置你的计算机时间为未来2000秒这时key会立即失效而不是等1000秒之后。 Redis如何淘汰过期的keys Redis keys过期有两种方式被动和主动方式。 当一些客户端尝试访问它时key会被发现并主动的过期。 当然这样是不够的因为有些过期的keys永远不会访问他们。 无论如何这些keys应该过期所以定时随机测试设置keys的过期时间。所有这些过期的keys将会从密钥空间删除。 具体就是Redis每秒10次做的事情 测试随机的20个keys进行相关过期检测。 删除所有已经过期的keys。 如果有多于25%的keys过期重复步奏1. 这是一个平凡的概率算法基本上的假设是我们的样本是这个密钥控件并且我们不断重复过期检测直到过期的keys的百分百低于25%,这意味着在任何给定的时刻最多会清除1/4的过期keys。 在复制AOF文件时如何处理过期 为了获得正确的行为而不牺牲一致性当一个key过期DEL将会随着AOF文字一起合成到所有附加的slaves。在master实例中这种方法是集中的并且不存在一致性错误的机会。 然而当slaves连接到master时不会独立过期keys会等到master执行DEL命令他们任然会在数据集里面存在所以当slave当选为master时淘汰keys会独立执行然后成为master。 Redis 红锁 Redis 红锁Redis RedLock是一种分布式锁解决方案主要用于在分布式环境下实现互斥访问保护防止多个客户端同时修改共享资源而引发的数据一致性问题。 红锁的概念是由 Redis 的作者 Antirez 在他的博客中提出的它通过对多个独立的 Redis 实例进行加锁操作来提供更高的可靠性和安全性。 下面是红锁的基本原理 选择 N 个 Redis 实例为了提高可靠性红锁使用了多个独立的 Redis 实例。实例之间可以在不同的主机或集群中部署。 加锁操作 客户端根据要锁定的资源生成一个唯一的标识例如资源的名称或 ID。 对于每个 Redis 实例客户端尝试使用 SETNX 命令来将一个带有唯一标识的锁键设置为一个特定的值同时设置一个过期时间。 如果 SETNX 操作成功即说明该实例成功获取到了锁客户端记录成功获取锁的实例数量。 如果 SETNX 操作失败即说明该实例的锁已经被其他客户端持有客户端尝试获取其他实例的锁。 锁的有效性 客户端需要计算获取锁操作所花费的时间确保在获取锁的过程中没有超过最大有效性时间的一半。这是为了避免在获取到锁后锁突然失效时出现不一致的情况。 续约过程 为了防止锁在某个进程意外崩溃或网络故障导致无法释放Redis红锁通过续约机制来保证锁的有效性。 续约过程包含以下几个步骤 1.获取当前时间戳(timestamp)。 2.使用比较并交换(compare-and-swap)的方式更新锁的过期时间。 3.检查锁是否已经超时。如果超时则继续下一步;否则等待一段时间再重试 解锁操作 客户端对所有成功获取锁的实例使用 DEL 命令删除锁键释放锁资源。 判断锁的获取情况 客户端统计成功删除锁键的实例数量如果数量超过半数即大多数实例则认为客户端成功获取了锁。 通过使用红锁客户端可以通过多个独立的 Redis 实例来实现分布式锁的高可靠性和安全性。但需要注意红锁并不是一个由 Redis 官方提供的内置实现而是一个由社区推广的解决方案需要根据具体的业务场景和需求进行实现和安全性评估。 扩展 绝对时间点过期 相对时间点过期 时钟轮算法 redis线程模型有哪些单线程为什么快 IO模型维度的特征 IO模型使用了多路复用器在linux系统中使用的是EPOLL 类似netty的BOSS,WORKER使用一个EventLoopGroup(threads1) 单线程的Reactor模型每次循环取socket中的命令然后逐一操作可以保证socket中的指令是按顺序的不保证不同的socket也就是客户端的命令的顺序性 命令操作在单线程中顺序操作没有多线程的困扰不需要锁的复杂度在操作数据上相对来说是原子性质的 架构设计模型 自身的内存存储数据读写操作不设计磁盘IO redis除了提供了Value具备类型还为每种类型实现了一些操作命令 实现了计算向数据移动而非数据想计算移动这样在IO的成本上有一定的优势 且在数据结构类型上丰富了一些统计类属性读写操作中写操作会O(1)负载度更新length类属性使得读操作也是O(1)的 说一下你知道的redis高可用方案 主从 哨兵模式 sentinel哨兵是 redis 集群中非常重要的一个组件主要有以下功能 集群监控负责监控 redis master 和 slave 进程是否正常工作。 消息通知如果某个 redis 实例有故障那么哨兵负责发送消息作为报警通知给管理员。 故障转移如果 master node 挂掉了会自动转移到 slave node 上。 配置中心如果故障转移发生了通知 client 客户端新的 master 地址。 哨兵用于实现 redis 集群的高可用本身也是分布式的作为一个哨兵集群去运行互相协同工作。 故障转移时判断一个 master node 是否宕机了需要大部分的哨兵都同意才行涉及到了分布 式选举 即使部分哨兵节点挂掉了哨兵集群还是能正常工作的 哨兵通常需要 3 个实例来保证自己的健壮性。 哨兵 redis 主从的部署架构是不保证数据零丢失的只能保证 redis 集群的高可用性。 对于哨兵 redis 主从这种复杂的部署架构尽量在测试环境和生产环境都进行充足的测试和演 练。 Redis Cluster是一种服务端Sharding技术3.0版本开始正式提供。采用slot(槽)的概念一共分成 16384个槽。将请求发送到任意节点接收到请求的节点会将查询请求发送到正确的节点上执行 方案说明 通过哈希的方式将数据分片每个节点均分存储一定哈希槽(哈希值)区间的数据默认分配了 16384 个槽位 每份数据分片会存储在多个互为主从的多节点上 数据写入先写主节点再同步到从节点(支持配置为阻塞同步) 同一分片多个节点间的数据不保持强一致性 读取数据时当客户端操作的key没有分配在该节点上时redis会返回转向指令指向正确的节点 扩容时需要需要把旧节点的数据迁移一部分到新节点 在 redis cluster 架构下每个 redis 要放开两个端口号比如一个是 6379另外一个就是 加1w 的端 口号比如 16379。 16379 端口号是用来进行节点间通信的也就是 cluster bus 的通信用来进行故障检测、配置更新、 故障转移授权。 优点 无中心架构 支持动态扩容 对业务透明 具备Sentinel的监控和自动Failover(故障转移)能力 客户端不需要连接集群所有节点连接集群中任何一个可用节点即可 高性能客户端直连redis服务免去了proxy代理的损耗 缺点 运维也很复杂 数据迁移需要人工干预 布式逻辑和存储模块耦合等 缓存预热 缓存预热指在用户请求数据前先将数据加载到缓存系统中用户查询事先被预热的缓存数据以提高系统查询效率。缓存预热一般有系统启动加载、定时加载等方式。 缓存雪崩、缓存穿透、缓存击穿在实际中如何处理 缓存穿透 缓存穿透是指查询一个一定不存在的数据由于缓存是不命中时被动写的并且出于容错考虑如果从存储层查不到数据则不写入缓存这将导致这个不存在的数据每次请求都要到存储层去查询失去了缓存的意义。在流量大时可能DB就挂掉了要是有人利用不存在的key频繁攻击我们的应用这就是漏洞。 解决方案 有很多种方法可以有效地解决缓存穿透问题最常见的则是采用布隆过滤器将所有可能存在的数据哈希到一个足够大的bitmap中一个一定不存在的数据会被 这个bitmap拦截掉从而避免了对底层存储系统的查询压力。 另外也有一个更为简单粗暴的方法我们采用的就是这种如果一个查询返回的数据为空不管是数 据不存在还是系统故障我们仍然把这个空结果进行缓存但它的过期时间会很短最长不超过五分钟。 缓存击穿 对于一些设置了过期时间的key如果这些key可能会在某些时间点被超高并发地访问是一种非常“热点”的数据。这个时候需要考虑一个问题缓存被“击穿”的问题这个和缓存雪崩的区别在于这里针对某一key缓存前者则是很多key。 缓存在某个时间点过期的时候恰好在这个时间点对这个Key有大量的并发请求过来这些请求发现缓存过期一般都会从后端DB加载数据并回设到缓存这个时候大并发的请求可能会瞬间把后端DB压垮。 解决方案 设置热点数据永不过期对于一些热点数据可以将其设置为永不过期确保这部分数据不会因缓存失效而导致频繁访问数据库。可以在缓存层或应用层逻辑中识别出热点数据并确保其始终处于有效状态。 延迟双删策略当一个请求发现缓存失效时可以先去查询数据库若数据库中存在该数据则主动更新缓存并返回结果。若数据库中不存在该数据也需要进行缓存更新但缓存的值为一个短暂的占位符如null或空字符串并设置一个较短的过期时间避免其他请求同时击穿到数据库。 互斥锁Mutex Lock机制在缓存失效的时候对于请求来说先去获取一个互斥锁只允许一个线程或进程访问数据库其他线程或进程等待该请求的结果。当第一个线程完成数据库查询后再更新缓存并释放锁。这样可以保证只有一个请求能够访问数据库其他请求则从缓存中获取数据。 限流和降级通过限流和降级策略当缓存失效时可以限制对数据库的访问量保护数据库不至于被大量请求压垮。可以通过限流算法、熔断机制等手段来控制请求量。 缓存雪崩 缓存雪崩是指在我们设置缓存时采用了相同的过期时间导致缓存在某一时刻同时失效请求全部转发到DBDB瞬时压力过重雪崩。 解决方案 Redis 缓存雪崩是指由于大量缓存同时失效或因其他原因导致请求直接落到数据库上对数据库造成瞬间的压力增大甚至宕机。为了防止缓存雪崩可以采取以下方案 设置合理的过期时间合理设置缓存的过期时间避免出现大量缓存同时失效的情况。可以使用随机过期时间来分散缓存失效的时间点减少缓存同时失效的概率。 使用热点数据永不过期对于一些热点数据可以设置永不过期确保这部分数据不会在同一时间大规模失效从而减轻缓存雪崩的影响。 限流和降级通过限流和降级策略当缓存失效时可以限制对数据库的访问量保护数据库不至于被大量请求压垮。可以通过限流算法、熔断机制等手段来控制请求量。 多级缓存策略引入多级缓存例如使用本地缓存和分布式缓存相结合可以降低缓存失效的风险。即使分布式缓存发生失效本地缓存还可以提供一定程度的缓解。 预热缓存系统启动时可以预先加载部分热点数据到缓存中避免出现大量缓存失效后导致的压力突增。 通过以上方案的综合应用可以有效地减少缓存雪崩对系统的影响保障系统的稳定性和性能。 总结 穿透缓存不存在数据库不存在高并发少量key 击穿缓存不存在数据库存在高并发少量key 雪崩缓存不存在数据库存在高并发大量key 语义有些许差异但是都可以使用限流的互斥锁保障数据库的稳定 redis事务是怎么实现的 MULTI 、 EXEC 、 DISCARD 和 WATCH 是 Redis 事务相关的命令。事务可以一次执行多个命令 并且带有以下两个重要的保证 事务是一个单独的隔离操作事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程中不会被其他客户端发送来的命令请求所打断。 ​ 事务是一个原子操作事务中的命令要么全部被执行要么全部都不执行。 EXEC 命令负责触发并执行事务中的所有命令 如果客户端在使用 MULTI 开启了一个事务之后却因为断线而没有成功执行 EXEC 那么事务中的所有命令都不会被执行。 另一方面如果客户端成功在开启事务之后执行 EXEC 那么事务中的所有命令都会被执行。 当使用 AOF 方式做持久化的时候 Redis 会使用单个 write(2) 命令将事务写入到磁盘中。 然而如果 Redis 服务器因为某些原因被管理员杀死或者遇上某种硬件故障那么可能只有部分事务命令会被成功写入到磁盘中。 如果 Redis 在重新启动时发现 AOF 文件出了这样的问题那么它会退出并汇报一个错误。 使用redis-check-aof程序可以修复这一问题它会移除 AOF 文件中不完整事务的信息确保服务器可以顺利启动。 从 2.2 版本开始Redis 还可以通过乐观锁optimistic lock实现 CAS check-and-set操作具体信息请参考文档的后半部分。 事务中的错误 使用事务时可能会遇上以下两种错误 事务在执行 EXEC 之前入队的命令可能会出错。比如说命令可能会产生语法错误参数数量错误参数名错误等等或者其他更严重的错误比如内存不足如果服务器使用 maxmemory 设置了最大内存限制的话。 命令可能在 EXEC 调用之后失败。举个例子事务中的命令可能处理了错误类型的键比如将列表命令用在了字符串键上面诸如此类。 对于发生在 EXEC 执行之前的错误客户端以前的做法是检查命令入队所得的返回值如果命令入队时返回 QUEUED 那么入队成功否则就是入队失败。如果有命令在入队时失败那么大部分客户端都会停止并取消这个事务。 不过从 Redis 2.6.5 开始服务器会对命令入队失败的情况进行记录并在客户端调用 EXEC 命令时拒绝执行并自动放弃这个事务。 在 Redis 2.6.5 以前 Redis 只执行事务中那些入队成功的命令而忽略那些入队失败的命令。 而新的处理方式则使得在流水线pipeline中包含事务变得简单因为发送事务和读取事务的回复都只需要和服务器进行一次通讯。 至于那些在 EXEC 命令执行之后所产生的错误 并没有对它们进行特别处理 即使事务中有某个/某些命令在执行时产生了错误 事务中的其他命令仍然会继续执行。 为什么 Redis 不支持回滚roll back 如果你有使用关系式数据库的经验 那么 “Redis 在事务失败时不进行回滚而是继续执行余下的命令”这种做法可能会让你觉得有点奇怪。 以下是这种做法的优点 Redis 命令只会因为错误的语法而失败并且这些问题不能在入队时发现或是命令用在了错误类型的键上面这也就是说从实用性的角度来说失败的命令是由编程错误造成的而这些错误应该在开发的过程中被发现而不应该出现在生产环境中。 因为不需要对回滚进行支持所以 Redis 的内部可以保持简单且快速。 有种观点认为 Redis 处理事务的做法会产生 bug 然而需要注意的是 在通常情况下 回滚并不能解决编程错误带来的问题。 举个例子 如果你本来想通过 INCR 命令将键的值加上 1 却不小心加上了 2 又或者对错误类型的键执行了 INCR 回滚是没有办法处理这些情况的。 redis集群方案有哪些 常见集群分类 主从复制集群 分片集群 redis有那些 主从复制集群手动切换 带有哨兵的HA的主从复制集群 客户端实现路由索引的分片集群 使用中间件代理层的分片集群 redis自身实现的cluster分片集群 redis主从复制的原理是什么 主从复制机制 当一个 master 实例和一个 slave 实例连接正常时 master 会发送一连串的命令流来保持对 slave 的更新以便于将自身数据集的改变复制给 slave 包括客户端的写入、key 的过期或被逐出等等。 ​ 当 master 和 slave 之间的连接断开之后因为网络问题、或者是主从意识到连接超时 slave 重新连接上 master 并会尝试进行部分重同步这意味着它会尝试只获取在断开连接期间内丢失的命令流。 ​ 当无法进行部分重同步时 slave 会请求进行全量重同步。这会涉及到一个更复杂的过程例如 master 需要创建所有数据的快照将之发送给 slave 之后在数据集更改时持续发送命令流到 slave 。 主从复制的关注点 Redis 使用异步复制slave 和 master 之间异步地确认处理的数据量 ​ 一个 master 可以拥有多个 slave ​ slave 可以接受其他 slave 的连接。除了多个 slave 可以连接到同一个 master 之外 slave 之间也可以像层叠状的结构cascading-like structure连接到其他 slave 。自 Redis 4.0 起所有的 sub-slave 将会从 master 收到完全一样的复制流。 ​ Redis 复制在 master 侧是非阻塞的。这意味着 master 在一个或多个 slave 进行初次同步或者是部分重同步时可以继续处理查询请求。 ​ 复制在 slave 侧大部分也是非阻塞的。当 slave 进行初次同步时它可以使用旧数据集处理查询请求假设你在 redis.conf 中配置了让 Redis 这样做的话。否则你可以配置如果复制流断开 Redis slave 会返回一个 error 给客户端。但是在初次同步之后旧数据集必须被删除同时加载新的数据集。 slave 在这个短暂的时间窗口内如果数据集很大会持续较长时间会阻塞到来的连接请求。自 Redis 4.0 开始可以配置 Redis 使删除旧数据集的操作在另一个不同的线程中进行但是加载新数据集的操作依然需要在主线程中进行并且会阻塞 slave 。 ​ 复制既可以被用在可伸缩性以便只读查询可以有多个 slave 进行例如 O(N) 复杂度的慢操作可以被下放到 slave 或者仅用于数据安全。 ​ 可以使用复制来避免 master 将全部数据集写入磁盘造成的开销一种典型的技术是配置你的 master Redis.conf 以避免对磁盘进行持久化然后连接一个 slave 其配置为不定期保存或是启用 AOF。但是这个设置必须小心处理因为重新启动的 master 程序将从一个空数据集开始如果一个 slave 试图与它同步那么这个 slave 也会被清空。 任何时候数据安全性都是很重要的所以如果 master 使用复制功能的同时未配置持久化那么自动重启进程这项应该被禁用。 Redis 复制功能是如何工作的 每一个 Redis master 都有一个 replication ID 这是一个较大的伪随机字符串标记了一个给定的数据集。每个 master 也持有一个偏移量master 将自己产生的复制流发送给 slave 时发送多少个字节的数据自身的偏移量就会增加多少目的是当有新的操作修改自己的数据集时它可以以此更新 slave 的状态。复制偏移量即使在没有一个 slave 连接到 master 时也会自增所以基本上每一对给定的 Replication ID, offset 都会标识一个 master 数据集的确切版本。 当 slave 连接到 master 时它们使用 PSYNC 命令来发送它们记录的旧的 master replication ID 和它们至今为止处理的偏移量。通过这种方式 master 能够仅发送 slave 所需的增量部分。但是如果 master 的缓冲区中没有足够的命令积压缓冲记录或者如果 slave 引用了不再知道的历史记录replication ID则会转而进行一个全量重同步在这种情况下 slave 会得到一个完整的数据集副本从头开始。 下面是一个全量同步的工作细节 master 开启一个后台保存进程以便于生产一个 RDB 文件。同时它开始缓冲所有从客户端接收到的新的写入命令。当后台保存完成时 master 将数据集文件传输给 slave slave将之保存在磁盘上然后加载文件到内存。再然后 master 会发送所有缓冲的命令发给 slave。这个过程以指令流的形式完成并且和 Redis 协议本身的格式相同。 你可以用 telnet 自己进行尝试。在服务器正在做一些工作的同时连接到 Redis 端口并发出 SYNC 命令。你将会看到一个批量传输并且之后每一个 master 接收到的命令都将在 telnet 回话中被重新发出。事实上 SYNC 是一个旧协议在新的 Redis 实例中已经不再被使用但是其仍然向后兼容但它不允许部分重同步所以现在 PSYNC 被用来替代 SYNC。 之前说过当主从之间的连接因为一些原因崩溃之后 slave 能够自动重连。如果 master 收到了多个 slave 要求同步的请求它会执行一个单独的后台保存以便于为多个 slave 服务。 无需磁盘参与的复制 正常情况下一个全量重同步要求在磁盘上创建一个 RDB 文件然后将它从磁盘加载进内存然后 slave以此进行数据同步。 如果磁盘性能很低的话这对 master 是一个压力很大的操作。Redis 2.8.18 是第一个支持无磁盘复制的版本。在此设置中子进程直接发送 RDB 文件给 slave无需使用磁盘作为中间储存介质。 redis缓存如何回收 回收策略 noeviction:返回错误当内存限制达到并且客户端尝试执行会让更多内存被使用的命令大部分的写入指令但DEL和几个例外 allkeys-lru: 尝试回收最少使用的键LRU使得新添加的数据有空间存放。 volatile-lru: 尝试回收最少使用的键LRU但仅限于在过期集合的键,使得新添加的数据有空间存放。 allkeys-random: 回收随机的键使得新添加的数据有空间存放。 volatile-random: 回收随机的键使得新添加的数据有空间存放但仅限于在过期集合的键。 volatile-ttl: 回收在过期集合的键并且优先回收存活时间TTL较短的键,使得新添加的数据有空间存放。 volatile-lfu从所有配置了过期时间的键中驱逐使用频率最少的键 allkeys-lfu从所有键中驱逐使用频率最少的键 如果没有键满足回收的前提条件的话策略volatile-lru, volatile-random以及volatile-ttl就和noeviction 差不多了。 选择正确的回收策略是非常重要的这取决于你的应用的访问模式不过你可以在运行时进行相关的策略调整并且监控缓存命中率和没命中的次数通过RedisINFO命令输出以便调优。 一般的经验规则: 使用allkeys-lru策略当你希望你的请求符合一个幂定律分布也就是说你希望部分的子集元素将比其它其它元素被访问的更多。如果你不确定选择什么这是个很好的选择。. 使用allkeys-random如果你是循环访问所有的键被连续的扫描或者你希望请求分布正常所有元素被访问的概率都差不多。 使用volatile-ttl如果你想要通过创建缓存对象时设置TTL值来决定哪些对象应该被过期。 allkeys-lru 和 volatile-random策略对于当你想要单一的实例实现缓存及持久化一些键时很有用。不过一般运行两个实例是解决这个问题的更好方法。 为了键设置过期时间也是需要消耗内存的所以使用allkeys-lru这种策略更加高效因为没有必要为键取设置过期时间当内存有压力时。 Redis热点数据如何处理 怎么发现热key 方法一:凭借业务经验进行预估哪些是热key 其实这个方法还是挺有可行性的。比如某商品在做秒杀那这个商品的key就可以判断出是热key。缺点很明显并非所有业务都能预估出哪些key是热key。 方法二:在客户端进行收集 这个方式就是在操作redis之前加入一行代码进行数据统计。那么这个数据统计的方式有很多种也可以是给外部的通讯系统发送一个通知信息。缺点就是对客户端代码造成入侵。 方法三:在Proxy层做收集 有些集群架构是下面这样的Proxy可以是Twemproxy是统一的入口。可以在Proxy层做收集上报但是缺点很明显并非所有的redis集群架构都有proxy。 方法四:用redis自带命令 (1)monitor命令该命令可以实时抓取出redis服务器接收到的命令然后写代码统计出热key是啥。当然也有现成的分析工具可以给你使用比如redis-faina。但是该命令在高并发的条件下有内存增暴增的隐患还会降低redis的性能。 (2)hotkeys参数redis 4.0.3提供了redis-cli的热点key发现功能执行redis-cli时加上–hotkeys选项即可。但是该参数在执行的时候如果key比较多执行起来比较慢。 方法五:自己抓包评估 Redis客户端使用TCP协议与服务端进行交互通信协议采用的是RESP。自己写程序监听端口按照RESP协议规则解析数据进行分析。缺点就是开发成本高维护困难有丢包可能性 (1)利用jvm本地缓存 比如利用ehcache或者一个HashMap都可以。在你发现热key以后把热key加载到系统的JVM中。 针对这种热key请求会直接从jvm中取而不会走到redis层。 假设此时有十万个针对同一个key的请求过来,如果没有本地缓存这十万个请求就直接怼到同一台redis上了。 现在假设你的应用层有50台机器OK你也有jvm缓存了。这十万个请求平均分散开来每个机器有2000个请求会从JVM中取到value值然后返回数据。避免了十万个请求怼到同一台redis上的情形。 (2)备份热key 这个方案也很简单。不要让key走到同一台redis上不就行了。我们把这个key在多个redis上都存一份不就好了。接下来有热key请求进来的时候我们就在有备份的redis上随机选取一台进行访问取值返回数据。 假设redis的集群数量为N步骤如下图所示 回收进程如何工作 理解回收进程如何工作是非常重要的: 一个客户端运行了新的命令添加了新的数据。 Redi检查内存使用情况如果大于maxmemory的限制, 则根据设定好的策略进行回收。 一个新的命令被执行等等。 所以我们不断地穿越内存限制的边界通过不断达到边界然后不断地回收回到边界以下。 如果一个命令的结果导致大量内存被使用例如很大的集合的交集保存到一个新的键不用多久内存限制就会被这个内存使用量超越。 双写一致性问题如何解决 先做一个说明从理论上来说给缓存设置过期时间是保证最终一致性的解决方案。这种方案下我们可以对存入缓存的数据设置过期时间所有的写操作以数据库为准对缓存操作只是尽最大努力更新即可。也就是说如果数据库写成功缓存更新失败那么只要到达过期时间则后面的读请求自然会从数据库中读取新值然后回填缓存。因此接下来讨论的思路不依赖于给缓存设置过期时间这个方案。 在这里我们讨论三种更新策略 先更新缓存再更新数据库。不可取 先更新数据库再更新缓存。不可取 先删除缓存再更新数据库。不可取 先更新数据库再删除缓存。可取有问题待解决 大前提 先读缓存如果缓存没有才从数据库读取。 (1)先更新数据库再更新缓存 这套方案大家是普遍反对的。为什么呢有如下两点原因。 原因一线程安全角度 同时有请求A和请求B进行更新操作那么会出现 1线程A更新了数据库 2线程B更新了数据库 3线程B更新了缓存 4线程A更新了缓存 这就出现请求A更新缓存应该比请求B更新缓存早才对但是因为网络等原因B却比A更早更新了缓存。这就导致了脏数据因此不考虑。 原因二业务场景角度 有如下两点 1如果你是一个写数据库场景比较多而读数据场景比较少的业务需求采用这种方案就会导致数据压根还没读到缓存就被频繁的更新浪费性能。 2如果你写入数据库的值并不是直接写入缓存的而是要经过一系列复杂的计算再写入缓存。那么每次写入数据库后都再次计算写入缓存的值无疑是浪费性能的。显然删除缓存更为适合。 接下来讨论的就是争议最大的先删缓存再更新数据库。还是先更新数据库再删缓存的问题。 (2)先删缓存再更新数据库 该方案会导致不一致的原因是。同时有一个请求A进行更新操作另一个请求B进行查询操作。那么会出现如下情形: 1请求A进行写操作删除缓存 2请求B查询发现缓存不存在 3请求B去数据库查询得到旧值 4请求B将旧值写入缓存 5请求A将新值写入数据库 上述情况就会导致不一致的情形出现。而且如果不采用给缓存设置过期时间策略该数据永远都是脏数据。 那么如何解决呢采用延时双删策略 1先淘汰缓存 2再写数据库这两步和原来一样 3休眠1秒再次淘汰缓存 这么做可以将1秒内所造成的缓存脏数据再次删除。 那么这个1秒怎么确定的具体该休眠多久呢 针对上面的情形读者应该自行评估自己的项目的读数据业务逻辑的耗时。然后写数据的休眠时间则在读数据业务逻辑的耗时基础上加几百ms即可。这么做的目的就是确保读请求结束写请求可以删除读请求造成的缓存脏数据。 如果你用了mysql的读写分离架构怎么办 ok在这种情况下造成数据不一致的原因如下还是两个请求一个请求A进行更新操作另一个请求B进行查询操作。 1请求A进行写操作删除缓存 2请求A将数据写入数据库了 3请求B查询缓存发现缓存没有值 4请求B去从库查询这时还没有完成主从同步因此查询到的是旧值 5请求B将旧值写入缓存 6数据库完成主从同步从库变为新值 上述情形就是数据不一致的原因。还是使用双删延时策略。只是睡眠时间修改为在主从同步的延时时间基础上加几百ms。 采用这种同步淘汰策略吞吐量降低怎么办 ok那就将第二次删除作为异步的。自己起一个线程异步删除。这样写的请求就不用沉睡一段时间后了再返回。这么做加大吞吐量。 第二次删除,如果删除失败怎么办 这是个非常好的问题因为第二次删除失败就会出现如下情形。还是有两个请求一个请求A进行更新操作另一个请求B进行查询操作为了方便假设是单库 1请求A进行写操作删除缓存 2请求B查询发现缓存不存在 3请求B去数据库查询得到旧值 4请求B将旧值写入缓存 5请求A将新值写入数据库 6请求A试图去删除请求B写入对的缓存值结果失败了。 ok,这也就是说。如果第二次删除缓存失败会再次出现缓存和数据库不一致的问题。 如何解决呢 (3)先更新数据库再删缓存 首先先说一下。老外提出了一个缓存更新套路名为《Cache-Aside pattern》。其中就指出 失效应用程序先从cache取数据没有得到则从数据库中取数据成功后放到缓存中。 命中应用程序从cache中取数据取到后返回。 更新先把数据存到数据库中成功后再让缓存失效。 另外知名社交网站facebook也在论文《Scaling Memcache at Facebook》中提出他们用的也是先更新数据库再删缓存的策略。 这种情况不存在并发问题么 不是的。假设这会有两个请求一个请求A做查询操作一个请求B做更新操作那么会有如下情形产生 1缓存刚好失效 2请求A查询数据库得一个旧值 3请求B将新值写入数据库 4请求B删除缓存 5请求A将查到的旧值写入缓存 ok如果发生上述情况确实是会发生脏数据。 然而发生这种情况的概率又有多少呢 发生上述情况有一个先天性条件就是步骤3的写数据库操作比步骤2的读数据库操作耗时更短才有可能使得步骤4先于步骤5。可是大家想想数据库的读操作的速度远快于写操作的不然做读写分离干嘛做读写分离的意义就是因为读操作比较快耗资源少因此步骤3耗时比步骤2更短这一情形很难出现。 假设有人非要抬杠有强迫症一定要解决怎么办 如何解决上述并发问题 首先给缓存设有效时间是一种方案。其次采用策略2里给出的异步延时删除策略保证读请求完成以后再进行删除操作。 还有其他造成不一致的原因么 有的这也是缓存更新策略2和缓存更新策略3都存在的一个问题如果删缓存失败了怎么办那不是会有不一致的情况出现么。比如一个写数据请求然后写入数据库了删缓存失败了这会就出现不一致的情况了。这也是缓存更新策略2里留下的最后一个疑问。 如何解决 提供一个保障的重试机制即可这里给出两套方案。 方案一 如下图所示 流程如下所示 1更新数据库数据 2缓存因为种种问题删除失败 3将需要删除的key发送至消息队列 4自己消费消息获得需要删除的key 5继续重试删除操作直到成功 然而该方案有一个缺点对业务线代码造成大量的侵入。于是有了方案二在方案二中启动一个订阅程序去订阅数据库的binlog获得需要操作的数据。在应用程序中另起一段程序获得这个订阅程序传来的信息进行删除缓存操作。 方案二 流程如下图所示 1更新数据库数据 2数据库会将操作信息写入binlog日志当中 3订阅程序提取出所需要的数据以及key 4另起一段非业务代码获得该信息 5尝试删除缓存操作发现删除失败 6将这些信息发送至消息队列 7重新从消息队列中获得该数据重试操作。 备注说明上述的订阅binlog程序在mysql中有现成的中间件叫canal可以完成订阅binlog日志的功能。至于oracle中博主目前不知道有没有现成中间件可以使用。另外重试机制博主是采用的是消息队列的方式。如果对一致性要求不是很高直接在程序中另起一个线程每隔一段时间去重试即可这些大家可以灵活自由发挥只是提供一个思路。 redis和MongoDB的区别 Redis和MongoDB是两种不同类型的数据库它们在很多方面有所不同 数据存储方式 RedisRedis是一种基于内存的数据存储系统数据通常存储在内存中可以持久化到硬盘上但主要用于缓存、会话存储和快速访问数据。 MongoDBMongoDB是一种文档型数据库数据以文档的形式存储在集合中支持丰富的查询操作和灵活的数据结构。 数据模型 RedisRedis支持键值对存储提供丰富的数据结构如字符串、列表、集合、有序集合和哈希表等。 MongoDBMongoDB是文档型数据库数据以JSON格式的文档存储一个文档可以容纳各种类型的数据。 持久化 RedisRedis提供多种持久化方式如快照snapshotting和AOFAppend Only File但主要用于缓存和临时数据存储。 MongoDBMongoDB默认将数据持久化到硬盘上保证数据的持久性和安全性。 查询语言 RedisRedis提供简单的键值对查询和部分数据结构的查询操作。 MongoDBMongoDB支持丰富的查询语言如基本的查询、范围查询、聚合操作等支持复杂的查询需求。 适用场景 Redis适用于需要高性能的缓存和计数器等场景对读写速度要求很高的场景。 MongoDB适用于需要复杂查询和数据分析的场景适合存储半结构化数据和大量文档数据的场景。 数据一致性 RedisRedis是单线程的可以通过事务和管道操作来确保数据的一致性但在分布式环境下需要额外的处理来处理数据一致性。 MongoDBMongoDB支持副本集和分片集群可以提供数据的高可用性和数据一致性能够满足更高级别的数据一致性需求。 扩展性 RedisRedis支持主从复制和集群模式可以通过横向扩展来提高性能和容量。 MongoDBMongoDB支持副本集和分片集群并且能够自动处理数据分片和负载均衡支持海量数据存储和高并发访问。 ACID特性 RedisRedis是内存数据库不支持事务的ACID特性。 MongoDBMongoDB支持事务操作可以确保数据的原子性、一致性、隔离性和持久性支持复杂的事务操作。 总体来说Redis更注重性能和速度适用于需要快速存取数据的场景而MongoDB更注重数据结构和查询能力适用于需要复杂查询和数据分析的场景。在选择数据库时需要根据具体的业务需求和数据特点来进行权衡和选择。 总的来说Redis更适合作为缓存或会话存储使用而MongoDB更适合作为存储大量文档型数据和进行复杂查询操作。根据具体的需求和场景选择合适的数据库系统是非常重要的。 Kafka 什么是kafka Kafka 最初是由 LinkedIn 即领英公司基于 Scala 和 Java 语言开发的分布式消息发布-订阅系统现已捐献给Apache 软件基金会。其具有高吞吐、低延迟的特性许多大数据实时流式处理系统比如 Storm、Spark、Flink等都能很好地与之集成。 总的来讲Kafka 通常具有 3 重角色 • 存储系统通常消息队列会把消息持久化到磁盘防止消息丢失保证消息可靠性。Kafka 的消息持久化机制和多副本机制使其能够作为通用数据存储系统来使用。 • 消息系统Kafka 和传统的消息队列比如 RabbitMQ、RocketMQ、ActiveMQ 类似支持流量削峰、服务解耦、异步通信等核心功能。 • 流处理平台Kafka 不仅能够与大多数流式计算框架完美整合并且自身也提供了一个完整的流式处理库即 Kafka Streaming。Kafka Streaming 提供了类似 Flink 中的窗口、聚合、变换、连接等功能。 一句话概括**Kafka** 是一个分布式的基于发布**/订阅模式的消息中间件在业界主要应用于大数据实时流式计算领域起解耦合和削峰填谷的作用。** Kafka kafka的几个特色 消息系统具有系统解耦冗余存储流量消峰缓存可恢复的功能Mq的作用解耦异步削峰 存储系统可以把消息持久化到磁盘保证消息不丢失 特点 快单个kafka服务每秒可处理数以千计客户端发来的几百MB数据。 可扩展性一个单一集群可作为一个大数据处理中枢集中处理各种类型业务 持久化消息被持久化到磁盘可处理TB数据级别数据但仍保持极高数据处理效率并且有备份容错机制 分布式着眼于大数据领域支持分布式集群可处理每秒百万级别消息 实时性生产出的消息可立即被消费者消费 Kafka的组件 topic消息存放的目录即主题 Producer生产消息到topic的一方负责创建消息然后投递到kafka环境中 Consumer订阅topic消费消息的一方连接到kafka然后消费消息 BrokerKafka的服务实例就是一个broker大多数情况下可以认为broker就是一台kafka服务器。 如下图所示Producer生产的消息通过网络发送给Kafka cluster而Consumer从其中消费消息 topickafka中的消息是以主题为单位进行归类生产者负责将消息发送到特定的主题topic消费者负责订阅主题进行消费。 主题是一个逻辑上的概念它可以分成很多的分区也就是partitions一个分区只属于一个主题很多时候也把分区叫做主题分区同一个主题下的不同分区的内容是不同分区在存储层面可以看做是一个可以追加的日志文件消息在被追加到分区日志文件的时候会分配一个偏移量offset。offset是消息在分区中的唯一标识kafka通过offset保证消息在分区中的顺序offset不跨域分区 kafka保证的是分区有序而不是主题有序 消息发送时都被发送到一个topic其本质就是一个目录而topic由是由一些Partition Logs(分区日志)组成,其组织结构如下图所示 主题有4个分区消息被顺序写入到每个分区文件的末尾kafka的分区跨域分布在不同的broker上面也就是一个topic可以横跨多个broker。 我们可以看到每个Partition中的消息都是有序的生产的消息被不断追加到Partition log上其中的每一个消息都被赋予了一个唯一的offset值。 每条消息在发送到kafka之前会根据分区规则选择存储到哪个具体的分区如果分区规则设置的合理所有的消息都可以均匀的分配到不同的分区中。如果一个主题只对应一个文件那么这个文件所在的机器的IO将会成为这个主题的瓶颈分区解决了这个问题。在创建主题的时候可以指定分区的个数当然也可以在创建完主题之后修改分区的数量通过增加分区的数量可以进行水平的扩展。 kafka为分区引入了多副本的机制通过增加副本数量可以提高容灾能力同一个分区的不同副本中保存的消息是相同的同一时刻副本之间的消息并非完全一致副本之间是 一主多从的关系其中leader副本负责处理读写请求follower副本只负责与leader副本的消息同步副本处于不同的broker中当leader副本发送故障会从follower副本中重新选择新的leader副本对外提供服务。 kafka通过多副本机制实现了故障自动转移当kafka集群中的某个broker失效依然能保证对外提供服务。 。 下图中kafka集群有4个broker某个主题有3个分区而且副本因子也是3个因此每个分区便有了一个leader副本和两个follower 副本。生产者和消费者只与leader副本进行交互follower副本只负责消息的同步但是很多时候follower副本的消息会滞后于leader副本。 kafka消费者也具备容灾的能力当消费者使用pull从服务端拉去消息并且保存了消费的具体offset当消费者宕机恢复后会根据之前保存的消费者位置重新进行消费这样就不会造成消息丢失。 分区中的所有副本统称AR(Assigned Replicas),所有与leader副本保持一定程度同步的副本包括leader副本组成ISR(In-Sync Replicas),ISR是AR集合的一个子集。消息会先发送到leader副本然后follower副本才能从leader副本中拉取消息进行同步同步期间内follower副本相对于leader副本有一定程度的滞后这里说的一定程度是指可以忍受的范围内这个参数可以通过配置。与leader副本同步滞后过多的副本不包含leader副本组成OSR(Out-of-Snyc-Replicas),也就是ARISROSR正常情况下所有的follower副本都应该与该leader副本保持一定程度的同步也就是ARISR。 leader副本负责维护和跟踪ISR集合中所有follower副本的滞后状态当follower落后太多或者失效时leader副本会把它从ISR中删除如果OSR中的follower副本追上了leader副本那么leader副本会把它从OSR移到ISR中。默认情况下在leader副本发送故障只有在ISR集合中副本才有机会被选中为leader在OSR集合中的副本没有任何机会。 ISR和HW和LEO也有密切关系HW是高水位标识了一个特定的消息的偏移量消费者只能拉取到这个offset之前的消息 它代表一个日志文件的一个分区这个日志文件分区中有9条消息第一条消息的offset为0最后一条消息的offset为8offset为9的消息用虚线表示代表下一条待输入的消息的offset日志文件的HW为6表示消费者只能拉去到offset为0至5之间的消息而offset为6的消息对消费者是不可见的。 LEO是log end offset它标识当前日志文件中下一条待写入消息的offset上图中的9为LEO位置。分区ISR集合中的每个副本都会维护自身的LEO而ISR集合中最小的LEO为分区的HW对消费者而言只能消费HW之前的消息。 为了更好理解ISR集合以及HW和LEO之间的关系通过下图说明 假设某个分区的ISR集合中有3个副本也就是一个leader副本和两个follower副本此时分区的LEO和HW都是3消息3和消息4从生产者发出之后先被存入leader副本在消息写入leader之后follower副本会发送拉去消息请求。 在同步过程中不同的follower副本同步的效率也不同如下图 在某一时刻follower1完全跟上了leader但是follower2只同步了消息3因此leader副本的LEO值为5 follower1的LEO为5follower2的LEO为4那么当前的HW为4所以消费者只能消费offset为0-3的消息。 所有的副本都成功的写入了消息3和消息4这个分区的Hw和LEO都是5因此消费者可以消费到offset为0-4之间的消息了。 Broker 和 Controller 的区别 在 Kafka 中Broker 和 Controller 是不同的概念它们代表着 Kafka 集群中的不同角色和职责。 Broker代理Broker 是 Kafka 集群中的基本组件指的是运行在实际硬件节点上的 Kafka 服务器实例。每个 Broker 都负责存储和管理一部分数据接收客户端的生产者和消费者请求并参与消息的复制和分发。多个 Broker 组成一个 Kafka 集群共同构成了一个高可用、高性能的分布式消息系统。 Controller控制器Controller 是 Kafka 集群中的一个特殊角色负责协调和管理整个集群的状态包括分区的分配、副本的调度、故障检测和恢复等。一个 Kafka 集群中只有一个 Controller它与其他 Broker 区别开来扮演着集群管理者的角色。Controller 负责监测集群的健康状态处理节点故障执行重新平衡操作等。 因此Broker 和 Controller 是 Kafka 集群中两个不同的概念和角色。Broker 是 Kafka 集群中实际运行的服务器节点负责存储数据并处理消息传输而 Controller 是一个特殊的 Kafka 服务器角色负责管理和协调整个 Kafka 集群的状态和操作。在一个 Kafka 集群中每个 Broker 都可以扮演普通节点和 Controller 的角色。 简述kafka架构设计是什么样 语义概念 1 broker Kafka 集群包含一个或多个服务器服务器节点称为broker。 ​ broker存储topic的数据。如果某topic有N个partition集群有N个broker那么每个broker存储该topic的一个partition。 ​ 如果某topic有N个partition集群有(NM)个broker那么其中有N个broker存储该topic的一个partition剩下的M个broker不存储该topic的partition数据。 ​ 如果某topic有N个partition集群中broker数目少于N个那么一个broker存储该topic的一个或多个partition。在实际生产环境中尽量避免这种情况的发生这种情况容易导致Kafka集群数据不均衡。 ​ 2 Topic 每条发布到Kafka集群的消息都有一个类别这个类别被称为Topic。物理上不同Topic的消息分开存储逻辑上一个Topic的消息虽然保存于一个或多个broker上但用户只需指定消息的Topic即可生产或消费数据而不必关心数据存于何处 ​ 类似于数据库的表名 ​ 3 Partition topic中的数据分割为一个或多个partition。每个topic至少有一个partition。每个partition中的数据使用多个segment文件存储。partition中的数据是有序的不同partition间的数据丢失了数据的顺序。如果topic有多个partition消费数据时就不能保证数据的顺序。在需要严格保证消息的消费顺序的场景下需要将partition数目设为1。 ​ 4 Producer 生产者即数据的发布者该角色将消息发布到Kafka的topic中。broker接收到生产者发送的消息后broker将该消息追加到当前用于追加数据的segment文件中。生产者发送的消息存储到一个partition中生产者也可以指定数据存储的partition。 ​ 5 Consumer 消费者可以从broker中读取数据。消费者可以消费多个topic中的数据。 ​ 6 Consumer Group 每个Consumer属于一个特定的Consumer Group可为每个Consumer指定group name若不指定group name则属于默认的group。这是kafka用来实现一个topic消息的广播发给所有的consumer和单播发给任意一个consumer的手段。一个topic可以有多个CG。topic的消息会复制-给consumer。如果需要实现广播只要每个consumer有一个独立的CG就可以了。要实现单播只要所有的consumer在同一个CG。用CG还可以将consumer进行自由的分组而不需要多次发送消息到不同的topic。 ​ 7 Leader 每个partition有多个副本其中有且仅有一个作为LeaderLeader是当前负责数据的读写的partition。 ​ 8 Follower Follower跟随Leader所有写请求都通过Leader路由数据变更会广播给所有FollowerFollower与Leader保持数据同步。如果Leader失效则从Follower中选举出一个新的Leader。当Follower与Leader挂掉、卡住或者同步太慢leader会把这个follower从“in sync replicas”ISR列表中删除重新创建一个Follower。 ​ 9 Offset kafka的存储文件都是按照offset.kafka来命名用offset做名字的好处是方便查找。例如你想找位于2049的位置只要找到2048.kafka的文件即可。当然the first offset就是00000000000.kafka KAFKA天生是分布式的满足AKF的XYZ轴特点扩展性可靠性高性能是没得说 而且kafka具备自己的特色比如动态ISR集合是在强一致性过半一致性之外的另一个实现手段 Kafka 保持高可靠性 Kafka 保持高可靠性的主要机制和策略包括 副本机制ReplicationKafka 使用副本机制来确保数据的可靠性和容错能力。每个主题的分区会配置多个副本这些副本会分布在不同的 Broker 上形成 Leader-Follower 结构。Leader 负责处理所有的读写请求Followers 负责与 Leader 保持数据同步。当 Leader 失效时Kafka 会从 Followers 中选举一个新的 Leader确保数据的连续性和可用性。 ISRIn-Sync Replica机制Kafka 使用 ISR 机制来处理副本间的同步问题。ISR 是与 Leader 副本保持同步的一组副本只有 ISR 中的副本才会参与数据的读写操作。如果某个副本无法与 Leader 保持同步该副本会被剔除出 ISR直到恢复正常同步。 故障检测和自愈Kafka 实时监控 Broker 节点的健康状态包括 Leader 和 ISR 的状态以及副本的同步情况。一旦检测到节点的异常Kafka 会快速做出响应比如进行副本重新选择、故障转移等操作确保集群在故障发生时能够快速自愈。 复制数据和数据恢复Kafka 在多个 Broker 之间复制数据确保数据的备份和冗余。即使某个 Broker 出现故障也可以通过其他副本上的数据来进行数据恢复保证数据的持久性和可靠性。 ZooKeeper 的协调和选举Kafka 使用 ZooKeeper 来实现分布式协调和一致性包括 Controller 选举、重新选举、节点注册和状态管理等。ZooKeeper 保证了 Kafka 集群中各节点之间的正确协同操作确保集群的稳定性和可靠性。 通过以上机制和策略Kafka 能够保持高可靠性即使在节点故障、网络分区等异常情况下依然能够保证数据的完整性和可用性从而满足高性能、高吞吐量的消息传输和数据处理需求。 Kafka中的ISR、AR又代表什么 在 Apache Kafka 中ISR 和 AR 分别代表以下概念 分区中的所有副本统称为ARAssigned Replicas。所有与leader副本保持一定程度同步的副本包括leader副本在内组成ISRIn-Sync ReplicasISR集合是AR集合中的一个子集。 在 Kafka 中ISR 和 AR 是数据复制和高可用性的重要概念对确保消息传递的可靠性和完整性起着关键作用。 消息会先发送到leader副本然后follower副本才能从leader副本中拉取消息进行同步同步期间内follower副本相对于leader副本而言会有一定程度的滞后。前面所说的“一定程度的同步”是指可忍受的滞后范围这个范围可以通过参数进行配置。与leader副本同步滞后过多的副本不包括leader副本组成OSROut-of-Sync Replicas由此可见ARISROSR。 Kafka生产者设计 Kafka消费者设计 Kafka中有那些地方需要选举这些地方的选举策略又有哪些 partition leaderISRcontroller先到先得 失效副本是指什么有那些应对措施 不能及时与leader同步暂时踢出ISR等其追上leader之后再重新加入 Kafka消息丢失的场景有哪些 生产者在生产过程中的消息丢失 broker在故障后的消息丢失 消费者在消费过程中的消息丢失 Kafka 是一种高可靠的消息系统但在特定情况下仍可能发生消息丢失的情况。以下是一些可能导致 Kafka 消息丢失的场景 生产者发送消息失败如果生产者在发送消息时发生错误比如网络故障、生产者应用程序崩溃等导致消息未成功发送到 Kafka 服务器这可能会导致消息丢失。 不可恢复的副本丢失如果 Kafka 中某个分区的所有副本都发生了不可恢复的故障且没有足够的副本进行数据恢复那么该分区的消息可能会永久丢失。 消费者提交偏移量失败如果消费者在消费消息后没有正确提交偏移量或者提交偏移量时发生错误那么在消费者重启或重新加入消费组时可能会出现消息重复消费或消息丢失的情况。 配置错误导致消息被丢弃如果 Kafka 的配置不当比如设置了消息过期时间、缓冲区大小不足、消息压缩设置不正确等可能会导致消息被系统自动丢弃。 磁盘故障如果 Kafka 的数据存储磁盘发生故障可能会导致部分或全部消息数据丢失。 为了尽量避免消息丢失可以采取一些措施如 配置正确的副本数量和副本策略以确保数据的高可靠性。 生产者设置消息的可靠性保证级别如设置为“all”以确保消息在发送到服务器之后被持久化。 消费者正确提交偏移量确保消费者状态跟踪正确。 监控 Kafka 集群状态及时发现并处理潜在的故障问题。 ACK机制 ack有3个可选值分别是10-1。 ack0生产者在生产过程中的消息丢失 简单来说就是producer发送一次就不再发送了不管是否发送成功。 ack1broker在故障后的消息丢失 简单来说就是producer只要收到一个分区副本成功写入的通知就认为推送消息成功了。这里有一个地方需要注意这个副本必须是leader副本。只有leader副本成功写入了producer才会认为消息发送成功。 注意ack的默认值就是1。这个默认值其实就是吞吐量与可靠性的一个折中方案。生产上我们可以根据实际情况进行调整比如如果你要追求高吞吐量那么就要放弃可靠性。 ack-1生产侧和存储侧不会丢失数据 简单来说就是producer只有收到分区内所有副本的成功写入的通知才认为推送消息成功了。 Offset机制 kafka消费者的三种消费语义 at-most-once最多一次可能丢数据 at-least-once最少一次可能重复消费数据 exact-once message精确一次 Kafka是pullpush以及优劣势分析 Kafka最初考虑的问题是customer应该从brokes拉取消息还是brokers将消息推送到consumer也就是pull还push。 Kafka遵循了一种大部分消息系统共同的传统的设计producer将消息推送到brokerconsumer从broker拉取消息。 一些消息系统比如Scribe和Apache Flume采用了push模式将消息推送到下游的consumer。 这样做有好处也有坏处由broker决定消息推送的速率对于不同消费速率的consumer就不太好处理了。 消息系统都致力于让consumer以最大的速率最快速的消费消息但不幸的是push模式下当broker推送的速率远大于consumer消费的速率时consumer恐怕就要崩溃了。 最终Kafka还是选取了传统的pull模式。 Pull模式的另外一个好处是consumer可以自主决定是否批量的从broker拉取数据。 Push模式必须在不知道下游consumer消费能力和消费策略的情况下决定是立即推送每条消息还是缓存之后批量推送。 如果为了避免consumer崩溃而采用较低的推送速率将可能导致一次只推送较少的消息而造成浪费。 Pull模式下consumer就可以根据自己的消费能力去决定这些策略。 Pull有个缺点是如果broker没有可供消费的消息将导致consumer不断在循环中轮询直到新消息到达。 为了避免这点Kafka有个参数可以让consumer阻塞知道新消息到达(当然也可以阻塞知道消息的数量达到某个特定的量这样就可以批量发 Kafka中zk的作用是什么 Zookeeper是分布式协调注意它不是数据库 在 Kafka 集群中ZooKeeper 扮演着重要的角色用于存储集群的元数据信息、协调分布式节点之间的一致性并提供可靠的选举机制。因此在 Kafka 中的重新选举过程通常会通过 ZooKeeper 来实现。 kafka中使用了zookeeper的分布式锁和分布式配置及统一命名的分布式协调解决方案 在kafka的broker集群中的controller的选择是通过zk的临时节点争抢获得的 brokerID等如果自增的话也是通过zk的节点version实现的全局唯一 kafka中broker中的状态数据也是存储在zk中不过这里要注意zk不是数据库所以存储的属于元数据 而新旧版本变化中就把曾经的offset从zk中迁移出了zk 在 Kafka 中通常需要进行选举的地方主要包括 Controller 选举Kafka 集群中的 Controller 是负责协调和管理整个集群的节点包括分区的分配、副本的调度、故障检测和恢复等。当当前的 Controller 节点发生故障或失效时会触发 Controller 选举重新选举一个新的 Controller 节点来接管集群管理工作。 分区的 Leader 选举每个分区在 Kafka 中都会有一个 Leader 副本负责处理读写请求。当 Leader 副本发生故障或失效时会触发分区的 Leader 选举选择一个新的 Leader 副本来接替原 Leader 的工作。 ISRIn-Sync Replica集合的选举在 Kafka 中每个分区的副本集合中包含了 ISRIn-Sync Replica集合即处于同步状态的副本。当 Leader 副本无法和 ISR 集合中的大多数副本保持同步时需要进行 ISR 集合的选举选择新的同步副本集合继续保证数据的一致性。 Kafka 使用 ZooKeeper 来进行选举算法的协调和管理。选举策略主要包括以下几种 Controller 选举策略Kafka 通过 ZooKeeper 原生提供的顺序节点和临时节点特性来实现 Controller 的选举。当多个节点竞争成为 Controller 时通过 ZooKeeper 的顺序节点机制来保证选举的顺序性和唯一性。 Leader 选举策略Kafka 中的 Leader 选举采用的是基于副本的选举策略即在副本集合中选择一个最合适的副本作为新的 Leader。Kafka 使用 ISR 集合和 LEOLog End Offset等信息来选择合适的 Leader。 ISR 集合的选举策略ISR 集合的选举策略主要包括了最佳副本优先选择与 Leader 最接近的副本、副本同步延迟等指标来选择新的同步副本。 这些选举策略通过 ZooKeeper 实现了分布式协调和一致性确保 Kafka 集群能够在节点故障或动态变化时正常运行并保持数据一致性。 Kafka中高性能如何保障 首先性能的最大瓶颈依然是IO这个是不能逾越的鸿沟 虽然broker在持久化数据的时候已经最大努力的使用了磁盘的顺序读写 更进一步的性能优化是零拷贝的使用也就是从磁盘日志到消费者客户端的数据传递因为kafka是mq对于msg不具备加工处理所以得以实现 然后就是大多数分布式系统一样总要做tradeoff在速度与可用性/可靠性中挣扎 ACK的01-1级别就是在性能和可靠中权衡 Kafka中是怎么体现消息顺序性的 每个分区内每条消息都有一个offset故只能保证分区内有序。 在 Kafka 中消息的顺序性是通过分区Partition以及分区内消息的顺序保证来实现的 分区Partition Kafka 中的每个主题Topic都可以划分为多个分区每个分区都是一个有序的消息队列。 生产者写入消息时根据分区策略选择将消息写入哪个分区不同分区之间的消息是并发写入的但同一个分区内的消息是有序的。 分区内消息顺序保证 在同一个分区内消息的顺序是保证的即消息按照写入的顺序依次排列。 Kafka 保证针对同一个分区内的消息无论是生产者写入还是消费者消费消息都是有序的。 通过上述机制Kafka 在分区级别实现了消息的顺序性保证。如果业务对消息的顺序性要求非常高可以将相关消息发送到同一个分区中来确保消息的顺序不被打乱。值得注意的是要实现消息的全局顺序性即跨分区的消息也要保持顺序性可能需要在应用层进行额外的处理和控制。 Kafka如何实现高性能io? 一、批量消息 虽然我们是一笔一笔消息的发送给kafka但是kafka并不是立即就发送出去的而是先将消息缓存起来再一批一起等个合适的时机一起发送出去。 消费端收到消息不是一个个拆出来一个个处理而是直接作为一批一起处理一起读写磁盘io一起复制这都大大加快了io的速度。 二、顺序读写 磁盘io分为顺序读写和随机读写而顺序读写的速度要比随机读写的速度要快得多。所以kafka采用顺序读写的机制收到消息的时候在日志文件顺序中写下多条消息发送的时候又是顺序的读出多条消息。 三、page cache page cache也就是os cache只有page cache中没有才会到磁盘中进行读写这就减少了一些与磁盘io的次数。 四、零拷贝 如果要读写的消息不在page cache中那么就会发生多次拷贝。从磁盘到page cache再从page cache到用户缓存再从用户缓存到socket缓存最后再发送。 为了减少不必要的拷贝kafka通过零拷贝技术直接将page cache中的数据复制到socket缓存中。 “消费组中的消费者个数如果超过topic的分区那么就会有消费者消费不到数据”这句话是否正确 这句话是基本正确的。在 Kafka 中每个消费者组Consumer Group可以有多个消费者实例每个消费者实例可以订阅一个或多个分区。消费者组内的消费者个数如果超过了订阅主题的分区数量会导致部分消费者无法消费数据。 具体来说如果消费者组中的消费者个数大于订阅主题的分区数量超出的消费者将无法获得分配给它们的分区因为每个分区只能分配给一个消费者实例来消费。这样就会导致超出分区数量的消费者无法消费任何数据从而产生“消费者消费不到数据”的现象。 为了充分利用 Kafka 的并行处理能力和保证数据的完整性通常建议消费者组内的消费者个数不要超过订阅主题的分区数量以确保每个分区都有对应的消费者来消费数据。如果希望增加消费者实例以提高消费速度可以考虑增加主题的分区数量来匹配消费者组内的消费者个数以实现更好的负载均衡和性能表现。 kafka的rebalance机制是什么 rebalance时read和wite 消费者分区分配策略 Range 范围分区(默认的) RoundRobin 轮询分区 Sticky策略 触发 Rebalance 的时机 Rebalance 的触发条件有3个。 consumer group组成员个数发生变化。例如有新的 consumer 实例加入该消费组或者离开组。 订阅的 Topic 个数发生变化。 订阅 Topic 的分区数发生变化。 consumer消费超时 Coordinator协调过程 消费者如何发现协调者 消费者如何确定分配策略 如果需要再均衡分配策略的影响 RabbitMQ 保证消息不丢失 RabbitMQ 通过持久化和确认机制来保证消息不丢失。 以下是 RabbitMQ 保证消息不丢失的关键方式 消息持久化在发送消息时可以设置消息的 delivery mode 为 2即 PERSISTENT使消息变为持久化消息。持久化消息会被写入磁盘即使 RabbitMQ 服务器重启消息也能够恢复。但需要注意持久化消息会导致性能略有降低因为需要将消息写入磁盘。 生产者确认机制在生产者发送消息到队列时可以开启生产者确认机制Publisher Confirms。生产者发送消息后等待 RabbitMQ 发送确认信息给生产者告知消息是否已经成功写入队列。如果收到确认信息生产者可以确定消息已经安全地发送到了队列中。如果未收到确认信息则可以重发消息确保消息不丢失。 消费者确认机制在消费者从队列中获取消息并处理后可以开启消费者确认机制Consumer Acknowledgements。消费者在处理消息后向 RabbitMQ 确认消息已经处理完毕。当 RabbitMQ 收到确认后会将消息标记为已消费然后删除消息。如果消费者未发送确认信息消息将会被重新投递到队列中。 高可用和镜像队列RabbitMQ 支持镜像队列Mirrored Queues功能可以将队列的消息在多个节点间同步实现高可用的队列。当某个节点故障时消息依然可以从其他节点中获取。镜像队列可以提高系统的可用性防止消息丢失。 确保消息的顺序RabbitMQ 本身是支持消息顺序的在单个队列中消息的顺序是得到保证的。但在分布式系统中默认情况下无法保证多个队列之间消息的顺序可能会导致发送和接收消息的顺序不一致。需要根据业务需求利用单队列保证消息顺序或采用其他机制来解决。 综上所述通过消息持久化、生产者和消费者确认机制、高可用和镜像队列等方式RabbitMQ 可以有效地保证消息不丢失。在使用过程中根据实际业务场景和需求选择合适的策略和配置以确保消息传递的可靠性和完整性。 RabbitMQ的架构设计是什么样的 是AMQP的实现相关概念语义 Broker:它提供一种传输服务,它的角色就是维护一条从生产者到消费者的路线保证数据能按照指定的方式进行传输 Exchange消息交换机,它指定消息按什么规则,路由到哪个队列。 Queue:消息的载体,每个消息都会被投到一个或多个队列。 Binding:绑定它的作用就是把exchange和queue按照路由规则绑定起来. Routing Key:路由关键字,exchange根据这个关键字进行消息投递。 vhost:虚拟主机,一个broker里可以有多个vhost用作不同用户的权限分离。 Producer:消息生产者,就是投递消息的程序. Consumer:消息消费者,就是接受消息的程序. Channel:消息通道,在客户端的每个连接里,可建立多个channel. 核心概念 在mq领域中producer将msg发送到queue然后consumer通过消费queue完成P.C解耦 kafka是由producer决定msg发送到那个queue rabbitmq是由Exchange决定msg应该怎么样发送到目标queue这就是binding及对应的策略 Exchange Direct Exchange:直接匹配,通过Exchange名称RountingKey来发送与接收消息. Fanout Exchange:广播订阅,向所有的消费者发布消息,但是只有消费者将队列绑定到该路由器才能收到消息,忽略Routing Key. Topic Exchange主题匹配订阅,这里的主题指的是RoutingKey,RoutingKey可以采用通配符,如:*或#RoutingKey命名采用.来分隔多个词,只有消息这将队列绑定到该路由器且指定RoutingKey符合匹配规则时才能收到消息; Headers Exchange:消息头订阅,消息发布前,为消息定义一个或多个键值对的消息头,然后消费者接收消息同时需要定义类似的键值对请求头:(如:x-mactchall或者x_matchany)只有请求头与消息头匹配,才能接收消息,忽略RoutingKey. 默认的exchange:如果用空字符串去声明一个exchange那么系统就会使用”amq.direct”这个exchange我们创建一个queue时,默认的都会有一个和新建queue同名的routingKey绑定到这个默认的exchange上去 复杂与精简 在众多的MQ中间件中首先学习Rabbitmq的时候就理解他是一个单机的mq组件为了系统的解耦可以自己在业务层面做AKF 其在内卷能力做的非常出色这得益于AMQP也就是消息的传递形式、复杂度有exchange和queue的binding实现这对于P.C有很大的帮助 RabbitMQ如何确保消息发送和消息接收 消息发送确认 1 ConfirmCallback方法 ConfirmCallback 是一个回调接口消息发送到 Broker 后触发回调确认消息是否到达 Broker 服务器也就是只确认是否正确到达 Exchange 中。 2 ReturnCallback方法 通过实现 ReturnCallback 接口启动消息失败返回此接口是在交换器路由不到队列时触发回调该方法可以不使用因为交换器和队列是在代码里绑定的如果消息成功投递到 Broker 后几乎不存在绑定队列失败除非你代码写错了。 消息接收确认 RabbitMQ 消息确认机制ACK默认是自动确认的自动确认会在消息发送给消费者后立即确认但存在丢失消息的可能如果消费端消费逻辑抛出异常假如你用回滚了也只是保证了数据的一致性但是消息还是丢了也就是消费端没有处理成功这条消息那么就相当于丢失了消息。 消息确认模式有 AcknowledgeMode.NONE自动确认。 AcknowledgeMode.AUTO根据情况确认。 AcknowledgeMode.MANUAL手动确认。 消费者收到消息后手动调用 Basic.Ack 或 Basic.Nack 或 Basic.Reject 后RabbitMQ 收到这些消息后才认为本次投递完成。 Basic.Ack 命令用于确认当前消息。 Basic.Nack 命令用于否定当前消息注意这是AMQP 0-9-1的RabbitMQ扩展 。 Basic.Reject 命令用于拒绝当前消息。 Nack,Reject后都有能力要求是否requeue消息或者进入死信队列 RabbitMQ事务消息原理是什么 事务V.S确认 确认是对一件事的确认 事务是对批量的确认 增删改查中事务是对于增删改的保证 发送方事务 开启事务发送多条数据事务提交或回滚是原子的要么都提交要么都回滚 消费方事务 消费方是读取行为那么事务体现在哪里呢 rabbitmq的消费行为会触发queue中msg的是否删除、是否重新放回队列等行为类增删改 所以消费方的ack是要手动提交的且最终确定以事务的提交和回滚决定 RabbitMQ死信队列、延时队列分别是什么 死信队列 DLXDead Letter Exchange死信交换器。 当队列中的消息被拒绝、或者过期会变成死信死信可以被重新发布到另一个交换器这个交换器就是DLX与DLX绑定的队列称为死信队列。 造成死信的原因 信息被拒绝 信息超时 超过了队列的最大长度 过期消息 在 rabbitmq 中存在2种方可设置消息的过期时间第一种通过对队列进行设置这种设置后该队列中所有的消息都存在相同的过期时间第二种通过对消息本身进行设置那么每条消息的过期时间都不一样。如果同时使用这2种方法那么以过期时间小的那个数值为准。当消息达到过期时间还没有被消费那么那个消息就成为了一个 死信 消息。 ​ 队列设置在队列申明的时候使用 x-message-ttl 参数单位为 毫秒 ​ 单个消息设置是设置消息属性的 expiration 参数的值单位为 毫秒 延迟队列 延迟队列存储的是延迟消息 延迟消息指的是当消息被发发布出去之后并不立即投递给消费者而是在指定时间之后投递。如 在订单系统中订单有30秒的付款时间在订单超时之后在投递给消费者处理超时订单。 rabbitMq没有直接支持延迟队列可以通过死信队列实现。 在死信队列中可以为普通交换器绑定多个消息队列假设绑定过期时间为5分钟10分钟和30分钟3个消息队列然后为每个消息队列设置DLX为每个DLX关联一个死信队列。 当消息过期之后被转存到对应的死信队列中然后投递给指定的消费者消费。 ZOOKeeper ZooKeeper数据模型 ZooKeeper的数据模型在结构上和标准文件系统的非常相似拥有一个层次的命名空间都是采用树形层次结构ZooKeeper树中的每个节点被称为—Znode。 和文件系统的目录树一样ZooKeeper树中的每个节点可以拥有子节点。但也有不同之处 Znode兼具文件和目录两种特点。既像文件一样维护着数据、元信息、ACL、时间戳等数据结构又像目录一样可以作为路径标识的一部分并可以具有子Znode。用户对Znode具有增、删、改、查等操作权限允许的情况下Znode具有原子性操作读操作将获取与节点相关的所有数据写操作也将替换掉节点的所有数据。另外每一个节点都拥有自己的ACL(访问控制列表)这个列表规定了用户的权限即限定了特定用户对目标节点可以执行的操作Znode存储数据大小有限制。ZooKeeper虽然可以关联一些数据但并没有被设计为常规的数据库或者大数据存储相反的是它用来管理调度数据比如分布式应用中的配置文件信息、状态信息、汇集位置等等。这些数据的共同特性就是它们都是很小的数据通常以KB为大小单位。ZooKeeper的服务器和客户端都被设计为严格检查并限制每个Znode的数据大小至多1M当时常规使用中应该远小于此值Znode通过路径引用如同Unix中的文件路径。路径必须是绝对的因此他们必须由斜杠字符来开头。除此以外他们必须是唯一的也就是说每一个路径只有一个表示因此这些路径不能改变。在ZooKeeper中路径由Unicode字符串组成并且有一些限制。字符串/zookeeper用以保存管理信息比如关键配额信息。 节点类型 Znode有两种分别为临时节点和永久节点。 节点的类型在创建时即被确定并且不能改变。 临时节点该节点的生命周期依赖于创建它们的会话。一旦会话结束临时节点将被自动删除当然可以也可以手动删除。临时节点不允许拥有子节点。 永久节点该节点的生命周期不依赖于会话并且只有在客户端显示执行删除操作的时候他们才能被删除。    Znode还有一个序列化的特性如果创建的时候指定的话该Znode的名字后面会自动追加一个不断增加的序列号。序列号对于此节点的父节点来说是唯一的这样便会记录每个子节点创建的先后顺序。它的格式为“%10d”(10位数字没有数值的数位用0补充例如“0000000001”) 在ZooKeeper中每个数据节点都是有生命周期的其生命周期的长短取决于数据节点的节点类型。 1、持久节点PERSISTENT 该数据节点别创建后就会一直存在于ZooKeeper服务器上直到有删除操作来主动删除该节点。 2、持久顺序节点PERSISTENT_SEQUENTIAL 持久顺序节点的基本特性和持久节点是一致的额外的特性表现在顺序性上。在ZooKeeper中每个父节点都会为它的第一级子节点维护一份顺序用于记录每个子节点创建的先后顺序。 3、临时节点EPHEMERAL 临时节点的生命周期和客户端的回话绑定在一起如果客户端会话失效那么这个节点就会被自动地清理掉。 ZooKeeper规定了不能基于临时节点来创建子节点即临时节点只能作为叶子节点。 4、临时顺序节点EPHEMERAL_SEQUENTIAL zookeeper提供了什么 Apache ZooKeeper 是一个开源的分布式协调服务它提供了以下主要功能 分布式配置管理ZooKeeper 可以用于集中管理分布式系统的配置信息。它提供了一个共享的、高可用的目录结构可以在其中存储和更新配置数据并且能够实时通知客户端配置的变化。 命名服务ZooKeeper 的目录结构可以作为一个命名空间用于存储和查询分布式系统中的节点信息。使用目录结构开发人员可以在分布式环境中方便地注册、查找和发现服务。 分布式锁ZooKeeper 提供了分布式锁的实现可以用于协调多个节点之间的互斥访问。通过在 ZooKeeper 上创建临时有序节点可以实现分布式锁的获取和释放。 选举机制ZooKeeper 提供了一种分布式选举机制可以帮助协调多个节点之间的领导者选举过程。通过 ZooKeeper 的顺序节点机制节点可以按序创建和监听节点从而实现选举算法。 时间管理ZooKeeper 提供了一个基于时间的机制可以为分布式系统提供高可用、实时可信的时钟。它使用了 Paxos 算法保证所有的写操作是按照全局的顺序进行的。 四种类型的数据节点 Znode 在ZooKeeper中有四种类型的数据节点Znode 持久节点Persistent Znode持久节点创建后就一直存在于ZooKeeper中除非显式删除。持久节点适合存储重要的配置信息、状态数据等它们不会因为客户端的断开或重新连接而被删除。 临时节点Ephemeral Znode临时节点的生命周期与创建它的客户端会话相关联。当与创建临时节点的客户端会话断开时该节点会被自动删除。临时节点通常用于表示临时状态、临时任务等例如在线用户、临时服务实例等。 有序节点Sequential Znode有序节点是在创建节点时自动追加一段唯一递增的序列号。有序节点可用于实现全局唯一的标识、顺序访问等场景。持久节点、临时节点都可以是有序节点。 持久顺序节点Persistent Sequential Znode持久顺序节点是持久节点的有序版本它会在创建节点时自动追加序列号。与持久节点类似持久顺序节点会一直存在于ZooKeeper中除非显式删除。 通过这四种节点类型的组合可以构建出复杂的数据结构和场景实现节点的注册、监听、查找等分布式协调任务。 Zookeeper watch机制是什么 ZooKeeper是用来协调同步分布式进程的服务提供了一个简单高性能的协调内核用户可以在此之上构建更多复杂的分布式协调功能。 多个分布式进程通过ZooKeeper提供的API来操作共享的ZooKeeper内存数据对象ZNode来达成某种一致的行为或结果这种模式本质上是基于状态共享的并发模型与Java的多线程并发模型一致他们的线程或进程都是”共享式内存通信“。 Java没有直接提供某种响应式通知接口来监控某个对象状态的变化只能要么浪费CPU时间毫无响应式的轮询重试或基于Java提供的某种主动通知Notif机制内置队列来响应状态变化但这种机制是需要循环阻塞调用。 而ZooKeeper实现这些分布式进程的状态ZNode的Data、Children共享时基于性能的考虑采用了类似的异步非阻塞的主动通知模式即Watch机制使得分布式进程之间的“共享状态通信”更加实时高效其实这也是ZooKeeper的主要任务决定的—协调。Consul虽然也实现了Watch机制但它是阻塞的长轮询。 ZooKeeper的Watch特性 Watch是一次性的每次都需要重新注册并且客户端在会话异常结束时不会收到任何通知而快速重连接时仍不影响接收通知。 Watch的回调执行都是顺序执行的并且客户端在没有收到关注数据的变化事件通知之前是不会看到最新的数据另外需要注意不要在Watch回调逻辑中阻塞整个客户端的Watch回调 Watch是轻量级的WatchEvent是最小的通信单元结构上只包含通知状态、事件类型和节点路径。ZooKeeper服务端只会通知客户端发生了什么并不会告诉具体内容。 Zookeeper状态 Disconnected客户端是断开连接的状态不能连接服务集合中的任意一个 SyncConnected客户端是连接状态连接其中的一个服务 AuthFailed鉴权失败 ConnectedReadOnly客户端连接只读的服务器 SaslAuthenticatedSASL认证 Expired服务器已经过期了该客户端的Session Zookeeper事件类型 None无 NodeCreated节点创建 NodeDeleted节点删除 NodeDataChanged节点数据改变 NodeChildrenChanged子节点改变添加/删除 ZABZooKeeper Atomic Broadcast协议 ZABZooKeeper Atomic Broadcast协议是Apache ZooKeeper使用的一种原子广播协议用于实现分布式一致性。ZooKeeper是一个分布式协调服务它使用ZAB协议来保证分布式环境中的数据一致性和可靠性。 ZAB协议主要包括两个阶段崩溃恢复阶段和消息广播阶段。 崩溃恢复阶段Crash Recovery 在崩溃恢复阶段ZooKeeper 通过选举算法选出一个Leader节点来负责协调和管理数据的更新。Leader节点负责将事务请求转化为事务Proposal并进行广播。Follower节点和Observer节点则负责接收并复制Leader节点发送的事务Proposal。在崩溃恢复阶段中Zookeeper会使用类似于Paxos算法的过程来选举Leader节点确保选出的Leader节点具有多数派支持。 消息广播阶段Message Broadcast 在消息广播阶段Leader节点将广播事务Proposal给所有Follower节点和Observer节点。一旦超过一半节点成功将事务Proposal写入本地存储Leader节点就会广播Commit消息这意味着事务已经成功提交。Follower和Observer节点会将Commit消息应用到自身数据状态上并且返回成功响应给Leader节点。Leader节点收到多数派的响应后会继续广播下一个事务Proposal。这个过程实现了事务的强一致性保证了多个节点之间的数据视图是一致的。 ZAB协议通过保证Leader节点的强一致性写入来达到数据一致性的目的。当客户端向ZooKeeper发送修改数据的请求时ZooKeeper会将请求转化为事务Proposal通过ZAB协议进行广播和复制最终保证所有节点上的数据视图是一致的。 总结来说ZAB协议是ZooKeeper用于实现分布式一致性的核心协议通过Leader节点的选举与事务广播保证了分布式环境下数据的可靠性和一致性。 Watcher使用的注意事项 Watcher是一次触发器假如需要持续监听数据变更需要在每次获取时设置Watcher 会话过期当客户端会话过期时该客户端注册的Watcher会失效 事件丢失在接收通知和注册监视点之间可能会丢失事件,但Zookeeper的状态变更和数据变化都会记录在状态元数据信息和ZK数据节点上所以能够获取最终一致的ZK信息状态 避免Watcher过多服务器会对每一个注册Watcher事件的客户端发送通知通知通过Socket连接的方式发送当Watcher过多时会产生一个尖峰的通知 zk的命名服务、配置管理、集群管理分别是什么 分布式协调 大于等于一的情况下才会有协调在协调的事务进行分类得到一些名词语义能够接受就可以 命名服务 通过使用有序节点的特性做到协调命名规则 通过zk的事务ID递增做到有序行命名规则 通过使用自己点做map映射做到1:N的命名映射比如DNS 顺序关系、映射关系 配置管理 配置、元数据、状态等语义可以通过ZK的节点1MB存储或者通过zk的节点目录结构特性存储 并且通过watch机制满足配置变化的全局通知能力 配置管理是指对分布式系统中的配置参数进行集中管理和动态更新的过程。ZooKeeper可以用作分布式配置管理的中心通过在ZooKeeper中创建持久化的节点并将节点的值设置为配置参数可以实现对配置的集中存储和管理。同时客户端可以注册Watcher来监听配置节点的变化以便在配置更新时及时获取新的配置信息并进行相应的调整。 集群管理 通过zk的排他性有序性 满足分布式锁、分布式选主、队列锁 串行化回调调度 分布式调度等 集群管理是指对分布式系统中的节点集群进行监控、管理和协调的过程。ZooKeeper可以作为集群管理的工具通过节点的注册和心跳机制实现对节点的监控和故障检测。同时可以使用ZooKeeper来维护集群的状态和协调集群中的各个节点。例如可以使用ZooKeeper进行主节点选举、节点的动态加入和退出、分布式锁的管理等。
http://www.zqtcl.cn/news/15980/

相关文章:

  • 如何用dw做旅游网站目录a4网站建设
  • 模板建网站费用创意设计师是做什么的
  • 做网站上市的公司win10优化大师官网
  • 中英文双语网站站点兴城做网站推广的
  • 怎么让自己做的网站别人可以访问上海福州路附近做网站的公司
  • 台州网站专业制作做网站学习什么
  • wordpress可以做下载站吗网站建设代码容易出错
  • 三水建设网站夏天做那个网站能致富
  • 扎金花网站怎么做百度有什么办法刷排名
  • 许昌购物网站开发设计oa办公平台
  • 自建网站 备案科普重庆网站
  • 建外贸网站费用wordpress编辑器保留word格式
  • 网站建设合同的要素及签订注意事项中英文外贸网站模板 生成静态html
  • 打开网站是空白页面优秀的网站建设
  • 贵州做网站找谁做网站的学什么代码
  • 网站建设属于软件开发吗怎么做视频直播网站
  • 南京专业网站设计公司价格太原找工作网站
  • 网站建设论坛fantodowordpress swf
  • 做网站要注册公司么哪家网站游戏做的比较好的
  • 智能建站模板专业做网站的公司有没有服务器
  • 石家庄做网站制作各大网址收录查询
  • 做网站需要搭建服务器么ui设计学校
  • 广州市南沙区基本建设办公室网站虹口网站开发培训课程
  • 网站如何能让百度收录建设银行光明支行网站
  • 建外文网站网站好坏标准
  • 济南免费做网站怎么样让百度搜到自己的网站
  • 医疗号网站开发竹子林附近网站建设
  • 黑客钓鱼网站的制作wordpress内页长尾词排名
  • 青岛网站设计公司哪家好wordpress手机中文版下载地址
  • 南头专业企业网站建设公司制作网站river