- 博客(7620)
- 资源 (15)
- 收藏
- 关注
原创 - 分布式环境下如何快速定位问题?
今天我们讲解了在分布式环境下如何快速定位问题。这里面的难点就是分布式系统有着较为复杂的依赖关系,我们很难判断出是哪个环节出现的问题,而且在大型的分布式系统中,往往会有跨部门、跨团队合作的情况,在排查问题的时候会面临非常高的沟通成本。为了在分布式环境下能够快速地定位问题,RPC框架应该对框架自身的异常进行详细地封装,每类异常都要有明确的异常标识码,并将其整理成一份简明的文档,异常信息中要尽量包含服务接口名、服务分组、调用端与服务端的IP,以及产生异常的原因等信息,这样对于使用方来说就非常便捷了。
2025-08-22 11:25:27
629
原创 - 异步RPC:压榨单机吞吐量
今天我们主要讲解了如果通过RPC的异步去压榨单机的吞吐量。影响到RPC调用的吞吐量的主要原因就是服务端的业务逻辑比较耗时,并且CPU大部分时间都在等待而没有去计算,导致CPU利用率不够,而提升单机吞吐量的最好办法就是使用异步RPC。RPC框架的异步策略主要是调用端异步与服务端异步。
2025-08-22 10:54:06
395
原创 - 业务分组:如何隔离流量?
今天我们通过一个道路划分的案例,引出了在RPC里面我们可以通过分组的方式人为地给不同的调用方划分出不同的小集群,从而实现调用方流量隔离的效果,保障我们的核心业务不受非核心业务的干扰。但我们在考虑问题的时候,不能顾此失彼,不能因为新加一个的功能而影响到原有系统的稳定性。其实我们不仅可以通过分组把服务提供方划分成不同规模的小集群,我们还可以利用分组完成一个接口多种实现的功能。正常情况下,为了方便我们自己管理服务,我一般都会建议每个接口完成的功能尽量保证唯一。
2025-08-22 10:31:00
619
原创 - 熔断限流:业务如何实现自我保护?
今天我们主要讲解了RPC框架是如何实现业务的自我保护。服务端主要是通过限流来进行自我保护,我们在实现限流时要考虑到应用和IP级别,方便我们在服务治理的时候,对部分访问量特别大的应用进行合理的限流;服务端的限流阈值配置都是作用于单机的,而在有些场景下,例如对整个服务设置限流阈值,服务进行扩容时,限流的配置并不方便,我们可以在注册中心或配置中心下发限流阈值配置的时候,将总服务节点数也下发给服务节点,让RPC框架自己去计算限流阈值;
2025-08-21 13:35:39
828
原创 - 优雅启动:如何避免流量打到没有启动完成的节点?
你好,我是程序员贵哥。上一讲我们介绍了优雅停机,就是为了让服务提供方在停机应用的时候,保证所有调用方都能“安全”地切走流量,不再调用自己,从而做到对业务无损。其中实现的关键点就在于,让正在停机的服务提供方应用有状态,让调用方感知到服务提供方正在停机。接着上一讲的内容,今天我们来聊聊优雅启动。是不是很诧异?应用启动居然也要这么“讲究”吗?这就好比我们日常生活中的热车,行驶之前让发动机空跑一会,可以让汽车的各个部件都“热”起来,减小磨损。换到应用上来看,原理也是一样的。运行了一段时间后的应用,执行速度会比刚启动
2025-08-21 13:30:52
545
原创 - 优雅关闭:如何避免服务停机带来的业务损失?
在RPC里面,关闭虽然看似不属于RPC主流程,但如果我们不能处理得很好的话,可能就会导致调用方业务异常,从而需要我们加入很多额外的运维工作。一个好的关闭流程,可以确保使用我们框架的业务实现平滑的上下线,而不用担心重启导致的问题。其实“优雅关闭”这个概念除了在RPC里面有,在很多框架里面也都挺常见的,比如像我们经常用的应用容器框架Tomcat。Tomcat关闭的时候也是先从外层到里层逐层进行关闭,先保证不接收新请求,然后再处理关闭前收到的请求。
2025-08-21 13:26:04
733
原创 - 异常重试:在约定时间内安全可靠地重试
今天我们讲解了RPC框架的重试机制,还有如何在约定时间内进行安全可靠地重试。这个机制是当调用端发起的请求失败时,如果配置了异常重试策略,RPC框架会捕捉异常,对异常进行判定,符合条件则进行重试,重新发送请求。在重试的过程中,为了能够在约定的时间内进行安全可靠地重试,在每次触发重试之前,我们需要先判定下这个请求是否已经超时,如果超时了会直接返回超时异常,否则我们需要重置下这个请求的超时时间,防止因多次重试导致这个请求的处理时间超过用户配置的超时时间,从而影响到业务处理的耗时。
2025-08-21 13:21:53
787
原创 - 负载均衡:节点负载差距这么大,为什么收到的流量还一样?
我先来简单地介绍下负载均衡。当我们的一个服务节点无法支撑现有的访问量时,我们会部署多个节点,组成一个集群,然后通过负载均衡,将请求分发给这个集群下的每个服务节点,从而达到多个服务节点共同分担请求压力的目的。负载均衡主要分为软负载和硬负载,软负载就是在一台或多台服务器上安装负载均衡的软件,如LVS、Nginx等,硬负载就是通过硬件设备来实现的负载均衡,如F5服务器等。负载均衡的算法主要有随机法、轮询法、最小连接法等。
2025-08-21 13:16:03
882
原创 - 路由策略:怎么让请求按照设定的规则发到不同的节点上?
在日常工作中,我们几乎每天都在做线上变更,每次变更都有可能带来一次事故,为了降低事故发生的概率,我们不光要从流程上优化操作步骤,还要使我们的基础设施能支持更低的试错成本。灰度发布功能作为RPC路由功能的一个典型应用场景,我们可以通过路由功能完成像定点调用、黑白名单等一些高级服务治理功能。在RPC里面,不管是哪种路由策略,其核心思想都是一样的,就是让请求按照我们设定的规则发送到目标节点上,从而实现流量隔离的效果。
2025-08-21 13:05:49
638
原创 健康检测:这个节点都挂了,为啥还要疯狂发请求?
这一讲我给你分享了RPC框架里面的一个核心的功能——健康检测,它能帮助我们从连接列表里面过滤掉一些存在问题的节点,避免在发请求的时候选择出有问题的节点而影响业务。但是在设计健康检测方案的时候,我们不能简单地从TCP连接是否健康、心跳是否正常等简单维度考虑,因为健康检测的目的就是要保证“业务无损”,所以在设计方案的时候,我们可以加入业务请求可用率因素,这样能最大化地提升RPC接口可用率。正常情况下,我们大概30S会发一次心跳请求,这个间隔一般不会太短,如果太短会给服务节点造成很大的压力。
2025-08-21 11:32:16
499
原创 - 服务发现:到底是要CP还是AP?
今天我分享了RPC框架服务发现机制,以及如何用ZooKeeper完成“服务发现”,还有ZooKeeper在超大规模集群下作为注册中心所存在的问题。通常我们可以使用ZooKeeper、etcd或者分布式缓存(如Hazelcast)来解决事件通知问题,但当集群达到一定规模之后,依赖的ZooKeeper集群、etcd集群可能就不稳定了,无法满足我们的需求。注册中心负载过高;各节点数据不一致;服务下发不及时或下发错误的服务节点列表。
2025-08-21 11:20:10
343
原创 - 架构设计:设计一个灵活的RPC框架
我们都知道软件开发的过程很复杂,不仅是因为业务需求经常变化,更难的是在开发过程中要保证团队成员的目标统一。我们需要用一种可沟通的话语、可“触摸”的愿景达成目标,我认为这就是软件架构设计的意义。但仅从功能角度设计出的软件架构并不够健壮,系统不仅要能正确地运行,还要以最低的成本进行可持续的维护,因此我们十分有必要关注系统的可扩展性。只有这样,才能满足业务变化的需求,让系统的生命力不断延伸。
2025-08-21 11:03:48
386
原创 - 动态代理:面向接口编程,屏蔽RPC处理流程
今天我们介绍了动态代理在RPC里面的应用,虽然它只是一种具体实现的技术,但我觉得只有理解了方法调用是怎么被拦截的,才能厘清在RPC里面我们是怎么做到面向接口编程,帮助用户屏蔽RPC调用细节的,最终呈现给用户一个像调用本地一样去调用远程的编程体验。既然动态代理是一种具体的技术框架,那就会涉及到选型。因为代理类是在运行中生成的,那么代理框架生成代理类的速度、生成代理类的字节码大小等等,都会影响到其性能——生成的字节码越小,运行所占资源就越小。
2025-08-20 13:17:43
891
原创 - 网络通信:RPC框架在网络通信上更倾向于哪种网络IO模型?
刚才讲阻塞IO的时候我讲到,系统内核处理IO操作分为两个阶段——等待数据和拷贝数据。等待数据,就是系统内核在等待网卡接收到数据后,把数据写到内核中;而拷贝数据,就是系统内核在获取到数据后,将数据拷贝到用户进程的空间中。以下是具体流程:应用进程的每一次写操作,都会把数据写到用户空间的缓冲区中,再由CPU将数据拷贝到系统内核的缓冲区中,之后再由DMA将这份数据拷贝到网卡中,最后由网卡发送出去。
2025-08-20 11:35:16
936
原创 - 核心原理:能否画张图解释下RPC的通信流程?
我知道你肯定不喜欢听概念,我也是这样,看书的时候一看到概念就直接略过。不过,到后来,我才发现,“定义”是一件多么伟大的事情。当我们能够用一句话把一个东西给定义出来的时候,侧面也说明你已经彻底理解这事了,不仅知道它要解决什么问题,还要知道它的边界。所以,你可以先停下来想想,什么是RPC。RPC的全称是Remote Procedure Call,即远程过程调用。
2025-08-20 11:21:25
654
原创 - 如何在一个系统中实现单元测试?
test_helper.tcl脚本首先使用source关键字,引入tests目录下support子目录中的redis.tcl、server.tcl等脚本文件。这些脚本文件实现了单元测试框架所需的部分功能,比如server.tcl脚本文件中,就实现了启动Redis测试实例的子函数start_server,而redis.tcl脚本中实现了向测试用Redis实例发送命令的子函数。而除了引入脚本文件之外,第一步操作还包括了定义全局变量。比如,测试框架定义了一个全局变量。
2025-08-19 18:22:31
657
原创 - 从Module的实现学习动态扩展功能
你好,我是程序员贵哥。Redis本身已经给我们提供了丰富的数据类型和数据读写功能,而且,Redis实现了基于IO复用的网络框架、数据主从复制和故障恢复机制,以及数据切片集群,这些功能通常都是后端系统所需的核心功能。那么,当我们在实际应用中,既希望能用上Redis已经实现的核心功能,又需要新增一些额外的命令或是数据类型时,该怎么办呢?其实,Redis从4.0版本开始,就提供了扩展模块(Module)的功能。
2025-08-19 18:21:30
947
原创 - 如何在系统中实现延迟监控?
latencyAddSample函数会实际记录当前的采样结果。不过在这一步,如果它发现当前的采样结果,和前一个采样结果是在同一秒中获得的,并且如果当前采样结果的事件执行时长,大于前一个采样结果的话,那么latencyAddSample函数就会直接更新前一个采样结果中记录的执行时长了,而不是新插入一个采样结果。否则的话,latencyAddSample函数才会新插入一个采样结果。这样设计的目的,也是为了避免在同一秒中记录过多的采样结果。
2025-08-19 18:19:51
610
原创 - 如何正确实现循环缓冲区?
feedReplicationBacklog函数在每轮循环的最后,会更新循环缓冲区的状态信息,包括repl_backlog_idx和repl_backlog_histlen。对于repl_backlog_idx来说,它会增加刚才写入的数据长度thislen。不过因为缓冲区总长度repl_backlog_size的大小固定,所以,如果repl_backlog_idx的值等于repl_backlog_size的值了,那么,repl_backlog_idx的值会被置为0。
2025-08-19 18:15:42
760
原创 从Ping-Pong消息学习Gossip协议的实现
你好,我是程序员贵哥。从这节课开始,我们又将进入一个新的模块:“Redis Cluster”模块。在这个模块中,我会带你了解Redis Cluster的关键功能实现,包括了Gossip协议通信、集群关键命令和数据迁移等机制的设计与实现。通过这些课程的学习,一方面,你可以深入了解Redis是如何完成集群关系维护、请求转发和数据迁移的。当你遇到集群问题时,这些知识可以帮助你排查问题。
2025-08-19 18:03:55
561
原创 - 从哨兵Leader选举学习Raft协议实现(下)
你好,我是程序员贵哥。上节课,我给你介绍了Raft协议的基本流程,以及哨兵实例工作的基本过程。哨兵是通过serverCron函数的周期性执行,进而在serverCron中调用sentinelTimer函数,实现周期性处理哨兵相关的时间事件。而sentinelTimer函数处理的时间事件,就包括了对哨兵监听的每个主节点,它会通过调用sentinelHandleRedisInstance函数,来检查主节点的在线状态,并在主节点客观下线时进行故障切换。
2025-08-19 17:50:26
859
原创 - 从哨兵Leader选举学习Raft协议实现(上)
你好,我是程序员贵哥。在上节课,我们了解了哨兵实例的初始化过程。哨兵实例一旦运行后,会周期性地检查它所监测的主节点的运行状态。当发现主节点出现客观下线时,哨兵实例就要开始执行故障切换流程了。不过,我们在部署哨兵实例时,通常会部署多个哨兵来进行共同决策,这样就避免了单个哨兵对主节点状态的误判。但是这同时也给我们带来了一个问题,即实际上,这就和有关了。而哨兵Leader选举,又涉及到分布式系统中经典的共识协议:Raft协议。
2025-08-19 17:46:46
570
原创 - 哨兵也和Redis实例一样初始化吗?
你好,我是程序员贵哥。这节课,我们一起来看看Redis是如何在源码中实现哨兵机制的。我们知道,Redis主从复制是保证Redis可用性的一个重要手段。而一旦Redis主节点发生故障,哨兵机制就会执行故障切换。这个故障切换过程实现起来其实比较复杂,涉及了哨兵Leader选举、新主节点选举和故障切换等关键操作。但同时,这个故障切换过程又是我们在实现高可用系统时经常要面对的开发需求。所以从这节课开始,我就来给你逐一介绍下,Redis哨兵机制及其实现故障切换的关键技术设计与实现。
2025-08-19 11:09:51
614
原创 - 主从复制:基于状态机的设计与实现?
你好,我是程序员贵哥。这节课,我想跟你聊聊Redis是如何基于状态机的设计思路,来实现主从复制的。主从复制技术我们应该都比较熟悉,因为在使用Redis或MySQL数据库时,我们经常会使用主从复制来实现主从节点间的数据同步,以此提升服务的高可用性。从原理上来说,Redis的主从复制主要包括了三种情况。全量复制传输RDB文件,增量复制传输主从断连期间的命令,而长连接同步则是把主节点正常收到的请求传输给从节点。
2025-08-19 10:50:16
1036
原创 - AOF重写(下):重写时的新写操作记录在哪里?
你好,我是程序员贵哥。在上节课,我给你介绍了AOF重写过程,其中我带你重点了解了AOF重写的触发时机,以及AOF重写的基本执行流程。现在你已经知道,AOF重写是通过重写子进程来完成的。但是在上节课的最后,我也提到了在AOF重写时,主进程仍然在接收客户端写操作,今天这节课,我就来带你了解下AOF重写过程中所使用的管道机制,以及主进程和重写子进程的交互过程。这样一方面,你就可以了解AOF重写日志包含的写操作的完整程度,当你要使用AOF日志恢复Redis数据库时,就知道AOF能恢复到的程度是怎样的。
2025-08-19 10:47:46
915
原创 - 如何生成和解读RDB文件?
你好,我是程序员贵哥。从今天这节课开始,我们又将进入一个新的模块,也就是可靠性保证模块。在这个模块中,我会先带你了解Redis数据持久化的实现,其中包括Redis内存快照RDB文件的生成方法,以及AOF日志的记录与重写。了解了这部分内容,可以让你掌握RDB文件的格式,学习到如何制作数据库镜像,并且你也会进一步掌握AOF日志重写对Redis性能的影响。然后,我还会围绕Redis主从集群的复制过程、哨兵工作机制和故障切换这三个方面,来给你介绍它们的代码实现。
2025-08-18 11:29:59
710
原创 - Lazy Free会影响缓存替换吗?
你好,我是程序员贵哥。Redis缓存淘汰算法的目的,其实是为了在Redis server内存使用量超过上限值的时候,筛选一些冷数据出来,把它们从Redis server中删除,以保证server的内存使用量不超出上限。我们在前两节课,已经分别学习了Redis源码对LRU算法和LFU算法的实现,这两种算法在最后淘汰数据的时候,都会删除被淘汰的数据。不过,无论是LRU算法还是LFU算法,它们在删除淘汰数据时,实际上都会根据Redis server的,来决定是否使用Lazy Free,也就是惰性删除。
2025-08-18 10:46:41
1073
原创 - LFU算法和其他算法相比有优势吗?
你好,我是程序员贵哥。上节课我给你介绍了Redis对缓存淘汰策略LRU算法的近似实现。其实,Redis在4.0版本后,还引入了LFU算法,也就是(Least Frequently Used,LFU)算法。LFU算法在进行数据淘汰时,会把最不频繁访问的数据淘汰掉。而LRU算法是把最近最少使用的数据淘汰掉,看起来也是淘汰不频繁访问的数据。那么,其实,如果只是从基本定义来看的话,我们是不太容易区分出这两个算法的。所以,今天这节课,我就带你从源码层面来学习了解下LFU算法的设计与实现。
2025-08-18 10:25:06
629
原创 - 为什么LRU算法原理和代码实现不一样?
你好,我是程序员贵哥。从这节课开始,我们就进入了课程的第三个模块:缓存模块。在接下来的三节课当中,我会给你详细介绍LRU、LFU算法在Redis源码中的实现,以及Redis惰性删除对缓存的影响。学习这部分内容,一方面可以让你掌握这些经典缓存算法在一个实际系统中该如何设计和实现;另一方面,你也可以学习到在计算机系统设计实现中的一个重要原则,也就是在进行系统设计开发的过程中,需要均衡算法复杂度和实现复杂度。另外,你还可以学习到缓存替换、惰性删除是如何释放Redis内存的。
2025-08-15 13:27:56
899
原创 从代码实现看分布式锁的原子性保证
你好,我是程序员贵哥。分布式锁是Redis在实际业务场景中的一个重要应用。当有多个客户端并发访问某个共享资源时,比如要修改数据库中的某条记录,为了避免记录修改冲突,我们可以让所有客户端从Redis上获取分布式锁,只有拿到锁的客户端才能操作共享资源。那么,对于分布式锁来说,它实现的关键就是要保证加锁和解锁两个操作是原子操作,这样才能保证多客户端访问时锁的正确性。而通过前面课程的学习,你知道Redis能通过事件驱动框架同时捕获多个客户端的可读事件,也就是命令请求。
2025-08-15 13:18:12
700
原创 - Redis 6.0多IO线程的效率提高了吗?
你好,我是程序员贵哥。通过上节课的学习,我们知道Redis server启动后的进程会以单线程的方式,执行客户端请求解析和处理工作。但是,Redis server也会通过bioInit函数启动三个后台线程,来处理后台任务。也就是说,Redis不再让主线程执行一些耗时操作,比如同步写、删除等,而是交给后台线程异步完成,从而避免了对主线程的阻塞。
2025-08-15 13:09:23
722
原创 - Redis真的是单线程吗?
你好,我是程序员贵哥。今天这节课,我们来聊聊Redis的执行模型。所谓的执行模型,就是指Redis运行时使用的进程、子进程和线程的个数,以及它们各自负责的工作任务。你在实际使用Redis的时候,可能经常会听到类似“Redis是单线程”“Redis的主IO线程”,“Redis包含多线程”等不同说法。其实,彻底理解这个问题,有助于指导我们保持Redis高性能、低延迟的特性。如果说Redis就是单线程程序,那么,我们就需要避免所有容易引起线程阻塞的操作;
2025-08-15 11:52:09
1000
原创 - Redis事件驱动框架(下):Redis有哪些事件?
/时间事件ID//事件到达的秒级时间戳//事件到达的毫秒级时间戳//时间事件触发后的处理函数//事件结束后的处理函数//事件相关的私有数据//时间事件链表的前向指针//时间事件链表的后向指针时间事件结构体中主要的变量,包括以秒记录和以毫秒记录的时间事件触发时的时间戳when_sec和when_ms,以及时间事件触发后的处理函数*timeProc。另外,在时间事件的结构体中,还包含了前向和后向指针*prev和*next,这表明时间事件是以链表的形式组织起来的。
2025-08-15 11:42:20
546
原创 Redis事件驱动框架(中):Redis实现了Reactor模型吗?
首先,我们要明确一点,就是在Redis事件驱动框架的实现当中,事件的数据结构是关联事件类型和事件处理函数的关键要素。IO事件和时间事件,分别对应了客户端发送的网络请求和Redis自身的周期性操作。这也就是说,不同类型事件的数据结构定义是不一样的。不过,由于这节课我们主要关注的是事件框架的整体设计与实现,所以对于不同类型事件的差异和具体处理,我会在下节课给你详细介绍。那么在今天的课程中,为了让你能够理解事件数据结构对框架的作用,我就以IO事件aeFileEvent为例,给你介绍下它的数据结构定义。
2025-08-15 11:35:12
950
原创 Redis事件驱动框架(上):何时使用select、poll、epoll?
你好,我是程序员贵哥。Redis作为一个Client-Server架构的数据库,其源码中少不了用来实现网络通信的部分。而你应该也清楚,通常系统实现网络通信的基本方法是,包括创建Socket、监听端口、处理连接请求和读写请求。但是,由于基本的Socket编程模型一次只能处理一个客户端连接上的请求,所以当要处理高并发请求时,一种方案就是使用多线程,让每个线程负责处理一个客户端的请求。
2025-08-15 11:08:55
581
原创 - 为什么Stream使用了Radix Tree?
你好,我是程序员贵哥。这节课,我们继续从底层数据结构的视角出发,来聊聊Redis中的Stream数据类型是如何保存消息的。Redis从5.0版本开始支持提供Stream数据类型,它可以用来保存消息数据,进而能帮助我们实现一个带有消息读写基本功能的消息队列,并用于日常的分布式程序通信当中。我在讲的时候,曾介绍过Stream。当时,有不少同学就说想学习了解下Stream的实现,以便掌握Stream内部结构的操作特点,但自己对Stream类型不太熟悉,不知道Stream底层是采用怎样的数据结构来保存消息数据的。
2025-08-14 11:17:54
772
原创 - 从ziplist到quicklist,再到listpack的启发
你好,我是程序员贵哥。在前面的,我介绍Redis优化设计数据结构来提升内存利用率的时候,提到可以使用压缩列表(ziplist)来保存数据。所以现在你应该也知道,ziplist的最大特点,就是它被设计成一种内存紧凑型的数据结构,占用一块连续的内存空间,以达到节省内存的目的。但是,。对于ziplist来说,这个道理同样成立。虽然ziplist节省了内存开销,可它也存在两个设计代价:一是不能保存过多的元素,否则访问性能会降低;二是不能保存过大的元素,否则容易导致内存重新分配,甚至可能引发连锁更新的问题。
2025-08-14 11:01:36
363
Linux系统技术可以学习一下
2024-01-26
播为主播提供一站式直播必备工具 包含弹幕助手、屏幕美化、语音播报、弹幕点歌等主播必备核心功能,目前已支持虎牙、斗鱼,抖音等、平台
2023-10-13
TestSyncMethods.java
2021-07-25
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人