- 博客(7590)
- 资源 (9)
- 收藏
- 关注
原创 - 为什么LRU算法原理和代码实现不一样?
你好,我是程序员贵哥。从这节课开始,我们就进入了课程的第三个模块:缓存模块。在接下来的三节课当中,我会给你详细介绍LRU、LFU算法在Redis源码中的实现,以及Redis惰性删除对缓存的影响。学习这部分内容,一方面可以让你掌握这些经典缓存算法在一个实际系统中该如何设计和实现;另一方面,你也可以学习到在计算机系统设计实现中的一个重要原则,也就是在进行系统设计开发的过程中,需要均衡算法复杂度和实现复杂度。另外,你还可以学习到缓存替换、惰性删除是如何释放Redis内存的。
2025-08-15 13:27:56
595
原创 从代码实现看分布式锁的原子性保证
你好,我是程序员贵哥。分布式锁是Redis在实际业务场景中的一个重要应用。当有多个客户端并发访问某个共享资源时,比如要修改数据库中的某条记录,为了避免记录修改冲突,我们可以让所有客户端从Redis上获取分布式锁,只有拿到锁的客户端才能操作共享资源。那么,对于分布式锁来说,它实现的关键就是要保证加锁和解锁两个操作是原子操作,这样才能保证多客户端访问时锁的正确性。而通过前面课程的学习,你知道Redis能通过事件驱动框架同时捕获多个客户端的可读事件,也就是命令请求。
2025-08-15 13:18:12
462
原创 - Redis 6.0多IO线程的效率提高了吗?
你好,我是程序员贵哥。通过上节课的学习,我们知道Redis server启动后的进程会以单线程的方式,执行客户端请求解析和处理工作。但是,Redis server也会通过bioInit函数启动三个后台线程,来处理后台任务。也就是说,Redis不再让主线程执行一些耗时操作,比如同步写、删除等,而是交给后台线程异步完成,从而避免了对主线程的阻塞。
2025-08-15 13:09:23
637
原创 - Redis真的是单线程吗?
你好,我是程序员贵哥。今天这节课,我们来聊聊Redis的执行模型。所谓的执行模型,就是指Redis运行时使用的进程、子进程和线程的个数,以及它们各自负责的工作任务。你在实际使用Redis的时候,可能经常会听到类似“Redis是单线程”“Redis的主IO线程”,“Redis包含多线程”等不同说法。其实,彻底理解这个问题,有助于指导我们保持Redis高性能、低延迟的特性。如果说Redis就是单线程程序,那么,我们就需要避免所有容易引起线程阻塞的操作;
2025-08-15 11:52:09
618
原创 - Redis事件驱动框架(下):Redis有哪些事件?
/时间事件ID//事件到达的秒级时间戳//事件到达的毫秒级时间戳//时间事件触发后的处理函数//事件结束后的处理函数//事件相关的私有数据//时间事件链表的前向指针//时间事件链表的后向指针时间事件结构体中主要的变量,包括以秒记录和以毫秒记录的时间事件触发时的时间戳when_sec和when_ms,以及时间事件触发后的处理函数*timeProc。另外,在时间事件的结构体中,还包含了前向和后向指针*prev和*next,这表明时间事件是以链表的形式组织起来的。
2025-08-15 11:42:20
356
原创 Redis事件驱动框架(中):Redis实现了Reactor模型吗?
首先,我们要明确一点,就是在Redis事件驱动框架的实现当中,事件的数据结构是关联事件类型和事件处理函数的关键要素。IO事件和时间事件,分别对应了客户端发送的网络请求和Redis自身的周期性操作。这也就是说,不同类型事件的数据结构定义是不一样的。不过,由于这节课我们主要关注的是事件框架的整体设计与实现,所以对于不同类型事件的差异和具体处理,我会在下节课给你详细介绍。那么在今天的课程中,为了让你能够理解事件数据结构对框架的作用,我就以IO事件aeFileEvent为例,给你介绍下它的数据结构定义。
2025-08-15 11:35:12
597
原创 Redis事件驱动框架(上):何时使用select、poll、epoll?
你好,我是程序员贵哥。Redis作为一个Client-Server架构的数据库,其源码中少不了用来实现网络通信的部分。而你应该也清楚,通常系统实现网络通信的基本方法是,包括创建Socket、监听端口、处理连接请求和读写请求。但是,由于基本的Socket编程模型一次只能处理一个客户端连接上的请求,所以当要处理高并发请求时,一种方案就是使用多线程,让每个线程负责处理一个客户端的请求。
2025-08-15 11:08:55
263
原创 - 为什么Stream使用了Radix Tree?
你好,我是程序员贵哥。这节课,我们继续从底层数据结构的视角出发,来聊聊Redis中的Stream数据类型是如何保存消息的。Redis从5.0版本开始支持提供Stream数据类型,它可以用来保存消息数据,进而能帮助我们实现一个带有消息读写基本功能的消息队列,并用于日常的分布式程序通信当中。我在讲的时候,曾介绍过Stream。当时,有不少同学就说想学习了解下Stream的实现,以便掌握Stream内部结构的操作特点,但自己对Stream类型不太熟悉,不知道Stream底层是采用怎样的数据结构来保存消息数据的。
2025-08-14 11:17:54
669
原创 - 从ziplist到quicklist,再到listpack的启发
你好,我是程序员贵哥。在前面的,我介绍Redis优化设计数据结构来提升内存利用率的时候,提到可以使用压缩列表(ziplist)来保存数据。所以现在你应该也知道,ziplist的最大特点,就是它被设计成一种内存紧凑型的数据结构,占用一块连续的内存空间,以达到节省内存的目的。但是,。对于ziplist来说,这个道理同样成立。虽然ziplist节省了内存开销,可它也存在两个设计代价:一是不能保存过多的元素,否则访问性能会降低;二是不能保存过大的元素,否则容易导致内存重新分配,甚至可能引发连锁更新的问题。
2025-08-14 11:01:36
346
原创 - 有序集合为何能同时支持点查询和范围查询?
如果你想要了解学习Sorted Set的模块和操作,注意要从t_zset.c和server.h这两个文件中查找。好,在知道了Sorted Set所在的代码文件之后,我们可以先来看下它的结构定义。Sorted Set结构体的名称为zset,其中包含了两个成员,分别是哈希表dict和跳表zsl,如下所示。
2025-08-14 10:42:25
903
原创 - 内存友好的数据结构该如何细化设计?
redisObject结构体是在server.h文件中定义的,主要功能是用来保存键值对中的值。这个结构一共定义了4个元数据和一个指针。type:redisObject的数据类型,是应用程序在Redis中保存的数据类型,包括String、List、Hash等。encoding:redisObject的编码类型,是Redis内部实现各种数据类型所用的数据结构。lru:redisObject的LRU时间。refcount:redisObject的引用计数。ptr:指向值的指针。
2025-08-13 13:14:15
297
原创 如何实现一个性能优异的Hash表?
实际上,一个最简单的Hash表就是一个数组,数组里的每个元素是一个哈希桶(也叫做Bucket),第一个数组元素被编为哈希桶0,以此类推。当一个键值对的键经过Hash函数计算后,再对数组元素个数取模,就能得到该键值对对应的数组元素位置,也就是第几个哈希桶。如下图所示,key1经过哈希计算和哈希值取模后,就对应哈希桶1,类似的,key3和key16分别对应哈希桶7和桶4。
2025-08-13 12:57:13
724
原创 - 带你快速攻略Redis源码的整体架构
你好,我是程序员贵哥。从今天这节课开始,我们将开启“Redis代码之旅”,一起来掌握Redis的核心设计思想。不过,在正式开始我们的旅程之前,还需要先做个“攻略”,也就是要了解和掌握Redis代码的整体架构。这是因为,一旦掌握了Redis代码的整体架构,就相当于给Redis代码画了张全景图。有了这张图,我们再去学习Redis不同功能模块的设计与实现时,就可以从图上快速查找和定位这些功能模块对应的代码文件。
2025-08-13 11:35:18
933
原创 MySQL源码分析和GDB调试器的应用
这一讲中,我们就以当前8.0系列中最新的Release版本8.0.40为例,下载代码并解压。我们先简单看一下MySQL源码文件的组织(只是为了看结构,下面的输出中,把很多内容删减掉了)。...├── mysys├── plugin│ ├── auth......│ └── x......├── sql│ ├── auth│ ├── dd│ ├── gis│ ├── raii│ └── xa│ └── oci......└── vio我们先对源码中的一部分目录做一个简单的介绍。
2025-08-12 10:41:16
333
原创 -如何搭建一个 MySQL 监控平台?
监控是运维很重要的一部分工作。这一讲里我们介绍了MySQL中需要监控的一些关键指标。这一讲还介绍了几种监控MySQL的开源工具。真实环境中,要保证监控系统自身的可用性。而且采集的监控指标越多,监控的服务数量越多,监控系统的压力就越大。监控数据怎么存储、怎么处理,也是建设一个监控系统时需要重点考虑的。比如PMM,用VictoriaMetrics存储指标数据,用Clickhouse存储SQL信息。
2025-08-12 10:14:33
1098
原创 -ProxySQL:数据库高可用了,应用高可用怎么做?
在应用程序和后端MySQL之间,增加一层Proxy,可以向应用屏蔽掉后端MySQL主备切换的一些细节。这样对应用程序而言,使用起来更加方便。同时,Proxy还可以起到连接池的作用。这里,其实还有一个问题没有解决,就是后端的MySQL怎么切换?早期比较有名的是MHA工具。在云上,各个云厂商提供的RDS高可用版本,一般都标配了数据库自动切换的功能。如果是自建的环境,你可以调研下一些开源的工具,比如MHA、Orchestrator等。如果数据库的数量有一定的规模,你也可以考虑自己实现一个数据库自动切换的工具。
2025-08-11 10:42:37
839
原创 -MySQL 8.0 组复制技术的应用(下)
组复制技术通过Paxos算法,保证了事务在一个节点提交时,事务消息被集群中的大多数节点接收到。在读写分离的架构下,为了确保在备节点上能读到一致的数据,可以在备节点上将参数group_replication_consistency设置成BEFORE。虽然MGR集群支持多主模式,但是整个集群的写入能力受流控机制的限制。和单主模式相比,多主模式并没有特别大的优势。从架构的简单性考虑,如果使用MGR,建议使用单主模式。
2025-08-11 10:31:37
1254
原创 -MySQL 8.0 Clone 插件的应用和内部原理
MySQL 8.0.17版本引入了clone插件。使用Clone插件可以对本地或远程的mysql实例进行克隆操作。Clone插件会拷贝InnoDB存储引擎表,克隆得到的是数据库的一个一致的快照,可以使用这个快照数据来启动新的数据库实例。Clone插件还会记录数据库的Binlog位点,可以将克隆得到的实例作为源实例的备库。Clone插件支持本地克隆和远程克隆这两种模式。本地克隆将数据存放在源数据库所在主机上。
2025-08-11 10:13:30
779
原创 -数据误操作了如何快速恢复?
在备份系统的设计中,要把Binlog备份也考虑进去,有了完整的Binlog,你可以将数据库恢复到任意一个时间点。在有些场景下,使用Binlog回滚的方案,能加快数据恢复的速度,减少业务的故障时长。针对可能存在的数据丢失故障,你可以有计划地进行恢复演练,这不仅能验证备份和数据恢复方案的有效性,还能给恢复时长建立一个基线。这样,当需要紧急恢复数据时,你可以比较精确地估算出恢复需要多少时间。
2025-08-11 10:03:49
742
原创 -备库服务器异常重启,备库损坏了该如何修复?
数据库和服务器有时难免会出现异常,如果备库异常重启了,怎么保证数据复制还能正常进行下去呢?建议的做法是使用GTID Auto Position,这样,即使slave_master_info表里的位点信息没及时更新也没有影响,relay log损坏了也没有关系。否则,你需要将参数sync_source_info设置为1,确保读取主库Binlog的位点是准确的。使用多线程复制时,还要将参数sync_relay_log设置为1,保证Relay log及时刷新,这对性能会有比较大的影响。
2025-08-08 14:09:29
552
原创 -备库有延迟怎么办?
使用MySQL的数据复制功能时,要监控好备库的状态和延迟情况。很多原因都会导致备库延迟,这一讲中提供了一些基本的方法。有一些延迟问题是可以避免的。如果是因为主库写入并发高引起的延迟,使用多线程复制能在一定程度上降低延迟。主库上参数binlog_transaction_dependency_tracking设置为WRITESET,能提升事务在备库的可并行度。如果你使用了级联复制架构,中间层的实例上,也要将 binlog_transaction_dependency_tracking设置为WRITESET。
2025-08-08 13:46:41
750
原创 -MySQL半同步能提高主备数据的一致性吗?
好了,这一讲中,我们分析了MySQL事务的二阶段提交。使用默认的异步复制,在极端情况下,主备数据可能会出现不一致。sync_binlog设置为1时,可以保障主库的数据一致性。半同步可以部分提升主备之间的数据一致性,开启半同步会有一些性能开销,使用半同步需要做好监控。
2025-08-08 13:24:12
752
原创 MySQL数据库高可用架构部署和维护
数据复制是MySQL一直以来最受欢迎的功能之一。应用程序访问主库,对主库的修改操作都记录到Binlog中。备库从主库同步Binlog、执行Binlog,这样,备库和主库始终保持一致。基于数据复制,可以实现多种高可用架构。高可用应用程序只访问主库,备库作为主库的热备。当主库发生故障,或者主库需要停机维护时,将业务流量切到备库上,减少停机时间。在备库上进行数据库备份等运维操作。读写分离将应用的一部分读流量分发(select)到备库上执行。
2025-08-08 12:58:02
913
原创 隔离级别对应用程序有什么影响?
锁是数据库中很重要的一个机制。MySQL中,我们主要会关注元数据锁和InnoDB的行锁。这一讲中,我们对行锁做了比较详细的介绍。REPEATABLE READ隔离级别下,使用了Gap锁、Next-key锁,锁的范围更大,因此也更容易引起死锁。应用程序遇到锁的问题时,首先要确定是锁超时还是死锁。你可以查询data_locks、data_lock_waits表来分析锁等待关系。
2025-08-08 11:35:03
645
原创 隔离级别对应用程序有什么影响?
MVCC是InnoDB的一个重要机制,通过MVCC,MySQL实现了读不阻塞写,写不阻塞读。当然,由于MySQL的实现机制,如果事务一直没提交,Read View一直开着,会导致Undo一直不能清理,Undo表空间就会一直增长,影响数据库的性能,所以需要做好监控。
2025-08-08 11:16:25
958
原创 -事务怎么回滚?(下)
通过上一讲和这一讲,你应该已经知道MySQL中Undo的原理和作用了。在写入特别繁忙的数据库中,清理(Purge)Undo日志可能会成为制约数据库性能的一个重要因素。建议把History链表长度监控起来。有一些Purge相关的参数可以配置,具体信息可以参考官方文档。Undo还在事务的一致性读取(MVCC)中起到重要的作用,我们在下一讲中再介绍。
2025-08-08 11:06:38
968
原创 事务怎么回滚?(上)
MySQL中,事务的行为受参数autocommit影响。如果autocommit设置为ON(这个参数默认就是ON),那么每个SQL语句会组成单独的事务,SQL语句执行完成时,InnoDB自动提交或回滚事务。autocommit设置为ON时,你也可以使用BEGIN或START TRANSACTION语句开启事务,开启事务后,可以在一个事务中执行多条SQL语句,你需要执行COMMIT语句提交事务,或使用ROLLBACK语句回滚事务。如果事务中的SQL执行时报错了,MySQL会怎么处理呢?
2025-08-07 12:58:11
572
原创 -数据都在内存里修改,服务器或数据库宕机会丢数据吗?
这一讲中我们对InnoDB的REDO机制做了一些基本的介绍,其中有几个参数需要注意。innodb_flush_log_at_trx_commit:设置为1的时候,才能保证数据不丢。innodb_log_buffer_size:Log Buffer一般设置几十M到几百M。
2025-08-07 12:52:45
869
原创 InnoDB Buffer Pool如何提高数据库性能?(下)
这一讲中,我们介绍了执行DROP TABLE、TRUNCATE TABLE、DROP INDEX等DDL操作时,InnoDB内部进行的一些处理,包括清理AHI、删除表空间、回收索引段的空间。如果你使用的版本小于8.0.23,那么执行这些DDL时对性能可能会有比较大的影响,特别是把Buffer Pool设置得比较大的实例。InnoDB还使用了自适应hash索引、Change Buffer来提升性能,我们也做了一些介绍。Double Write Buffer是用来保证数据一致性的,有一定的性能开销。
2025-08-07 12:49:30
816
原创 -InnoDB Buffer Pool 如何提高数据库性能?(上)
这一讲中我们对InnoDB Buffer的结构做了一些介绍。在实践中,要正确地设置相关的参数。对性能影响最大的参数应该是innodb_buffer_pool_size和innodb_buffer_pool_instances,你可以参考第4讲中的相关内容。为了保证数据库的事务ACID属性,修改Buffer Pool中的数据时,要生成REDO和UNDO日志,修改记录时还需要先获取行锁,这是接下来几节课要介绍的内容。
2025-08-07 12:46:35
986
原创 -数据库无法启动,如何读取InnoDB文件中的数据?(下)
这一讲中,我们通过一个具体的例子,解析了InnoDB聚簇索引和二级索引的存储格式,你可以看到,我们之前关于InnoDB表和索引结构的描述,都是有依据的。我们还看到了InnoDB管理段和空间的一些数据结构,包括段描述符、区描述符、Inode页面。InnoDB数据文件中,藏着很多链表结构,有单向链表,还有双向链表,后续的课程中,还有更多的链表结构等我们去发现。
2025-08-07 11:55:51
399
原创 数据库无法启动,如何读取InnoDB文件中的数据?(上)
解读ibd文件的内容,需要借助一些工具,以十六进制的方式查看文件的内容。这类工具很多,比如UltraEdit。这里我使用了Mac系统下的Hex Fiend。下面这个图就是使用Hex Fiend打开t_dynamic.ibd文件后显示的内容。上面这个图里面,最左侧和最上方是地址栏,标注了文件内容的偏移量。右侧是提示区,以文本的形式展示文件内容。我们建的测试表里,存的都是文本数据,在提示区里能看到这些数据。
2025-08-07 10:55:35
290
原创 SQL执行性能不佳的真实案例(下)
SQL优化是一项基本的技能。你需要掌握索引的特点,了解不同表连接算法的特点和适用场景,还需要了解优化器的一些工作原理。有的时候你可能需要改写SQL,或者使用SQL提示,来获得更好的性能。这两讲的十几个例子,都是从真实的业务场景中挑选出来的,当时使用的版本包括5.5、5.6、5.7。可以看到,在8.0中,有一些SQL实际上优化器已经能自动优化得更好了。这也是我们要使用新版本的一个重要的原因。
2025-08-07 10:52:02
400
原创 SQL执行性能不佳的真实案例(上)
这一讲的六个案例,在平时工作中比较常见,通常也比较容易解决。首先要理解索引的选择性,为查询中过滤性高的条件创建合适的索引。对于隐式类型转换,最重要的是要在建表的时候就选择精确的数据类型,避免使用varchar来存储数字类的、日期时间类的数据。字符集也要保持一致。如果表已经建好,系统已经上线运行了,那就要在应用代码里使用和字段类型匹配的数据类型。
2025-08-07 10:42:26
372
原创 MySQL子查询优化策略
按官方文档的说法,MySQL 8.0.17开始,对于满足半连接转换条件的not in、not exists查询,MySQL还会使用反查询(ANTI Join)转换。但是在我的测试中,not in的执行计划中仍旧是相关子查询(DEPENDENT SUBQUERY)。给主查询的not in字段加上not null条件后,查询才转换成了反连接。Not exists;Code: 1003关于反连接,有一点需要注意,就是not in和not exists并不完全等价。
2025-08-06 13:10:42
549
原创 -表连接如何执行?
这一讲中,我们学习了MySQL中表连接的几种方法。优化器会评估不同的连接顺序和连接方法的成本,从中选择一个成本最低的执行计划。在有些情况下,优化器选择的执行计划,在执行时并不是效率最高的,这时就需要我们分析SQL中相关表的索引结构和统计信息,查看表的数据分布情况,想办法让优化器选择效率更高的执行计划。子查询、半连接(Semi Join)、反连接(Anti Join)的内容呢,我们放到下一节课再讨论。
2025-08-06 12:54:00
602
原创 单表查询:如何评估单表访问成本?
结合上一讲的内容,我们已经把单个表的访问做了比较全面地介绍。索引在SQL优化中有非常重要的作用。平时在建索引时,有几个问题需要考虑,一是应该把哪些字段加到索引中,二是索引中字段的顺序如何排列。我们需要考虑索引的过滤性,这里是指索引前缀字段组合的过滤性。还要根据业务的数据分布情况和访问需求,综合考虑。每新增一个索引都会带来额外的维护成本,因此我们要避免创建重复的索引。尽量使用一些精炼的索引来满足业务的查询需求。
2025-08-06 12:52:58
895
原创 -优化器成本模型:优化器为什么选择这个执行计划?
这一讲中,我们学习了MySQL优化器的一些工作原理。优化器会选择成本最低的执行计划。我们介绍了全表扫描和索引范围扫描这两种最基本,也是最重要的访问路径的成本计算方法。实际工作中优化SQL时,我们并不需要真的知道某个执行计划的成本,那是优化器要计算的。但是我们需要理解全表扫描和索引访问大致的原理,理解这两种执行计划的开销来自哪里。统计信息对优化器很重要,如果统计信息不准确,优化器很可能会选择错误的执行计划。我们还可以通过优化器参数、SQL提示来影响优化器。
2025-08-06 12:50:08
775
原创 读懂MySQL中的执行计划(下)
出于完整性的考虑,这一讲中我们使用了四十多个SQL语句,演示并解释了MySQL执行计划的各种输出。在实际工作中,一般也不会遇到这里的每一种情况。通过ID、SELECT_TYPE、TABLE这几列可以了解语句整体的连接、嵌套结构。TYPE列为ref、range时,才是我们平时说的用到了索引。type为index时,实际上是使用了全索引扫描。ROWS列是优化器评估的需要从到存储引擎里访问的记录的数量,这个数量对性能有直接的影响。
2025-08-06 12:47:00
1000
Linux系统技术可以学习一下
2024-01-26
播为主播提供一站式直播必备工具 包含弹幕助手、屏幕美化、语音播报、弹幕点歌等主播必备核心功能,目前已支持虎牙、斗鱼,抖音等、平台
2023-10-13
TestSyncMethods.java
2021-07-25
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人