• Redis主从复制原理详解

    众所周知,一个数据库系统想要实现高可用,主要从以下两个方面来考虑: 保证数据安全不丢失 系统可以正常提供服务 而 Redis 作为一个提供高效缓存服务的数据库,也不例外。 上期我们提到的 Redis 持久化策略,其实就是为了减少服务宕机后数据丢失,以及快速恢复数据,也算是支持高可用的一种实现。 除此之外,Redis 还提供了其它几种方式来保证系统高可用,业务中最常用的莫过于主从同步(也称作主从复制)、Sentinel 哨兵机制以及 Cluster 集群。 同时,这也是面试中出现频率最高的几个主题,这期我们先来讲讲 Redis 的主从复制。 2. 主从复制简介 Redis 同时支持主从复制和读写分离:一个 Redis 实例作为主节点 Master,负责写操作。 其它实例(可能有 1 或多个)作为从节点 Slave,负责复制主节点的数据。 2.1 架构组件 主节点Master 数据更新:Master 负责处理所有的写操作,包括写入、更新和删除等。 数据同步:写操作在 Master 上执行,然后 Master 将写操作的结果同步到所有从节点 Slave 上。 从节点Slave 数据读取:Slave 负责处理读操作,例如获取数据、查询等。 数据同步:Slave 从 Master 复制数据,并在本地保存一份与主节点相同的数据副本。 2.2 为什么要读写分离 1)防止并发 从上图我们可以看出,数据是由主节点向从节点单向复制的,如果主、从节点都可以写入数据的话,那么数据的一致性如何保证呢? 有聪明的小伙伴可能已经想到了,那就是加锁! 但是主、从节点分布在不同的服务器上,数据跨节点同步时又会出现分布式一致性的问题。而在高频并发的场景下,解决加锁后往往又会带来其它的分布式问题,例如写入效率低、吞吐量大幅下降等。 而对于 Redis 这样一个高效缓存数据库来说,性能降低是难以忍受的,所以加锁不是一个优秀的方案。 那如果不加锁,使用最终一致性方式呢? 这样 Redis 在主、从库读到的数据又可能会不一致,带来业务上的挑战,用户也是难以接受的。 业务为用户服务,技术为业务服务。 所以,为了权衡数据的并发问题和用户体验,我们只允许在主节点上写入数据,从节点上读取数据。 2)易于扩展 我们都知道,大部分使用 Redis 的业务都是读多写少的。所以,我们可以根据业务量的规模来确定挂载几个从节点 Slave,当缓存数据增大时,我们可以很方便的扩展从节点的数量,实现弹性扩展。 同时,读写分离还可以实现数据备份和负载均衡,从而提高可靠性和性能。 3)高可用保障 不仅如此,Redis 还可以手动切换主从节点,来做故障隔离和恢复。这样,无论主节点或者从节点宕机,其他节点依然可以保证服务的正常运行。 3. 主从复制实现 3.1 开启主从复制 要开启主从复制,我们需要用到 replicaof 命令。 当我们确定好主节点的 IP 地址和端口号,在从库执行 replicaof <masterIP> <masterPort> 这个命令,就可以开启主从复制。 注意,在 Redis5.0 之前,该命令为 slaveof 开启主从复制后,应用层采用读写分离,所有的写操作在主节点进行,所有读操作在从节点进行。 主从节点会保持数据的最终一致性:主库更新数据后,会同步给从库。 3.2 主从复制过程 那主从库同步什么时候开始和结束呢? 是一次性传输还是分批次写入?Redis 主从节点在同步过程中网络中断了,没传输完成的怎么办? 带着这些疑问我们来分析下,首先,Redis 第一次数据同步时分 3 个阶段。 1)建立连接,请求数据同步 主从节点建立连接,从库请求数据同步。 从服务器从 replicaof 配置项中获取主节点的 IP 和 Port,然后进行连接。 连接成功后,从服务器会向主服务器发送 PSYNC 命令,表示要进行同步。同时,命令中包含 runID 和 offset 两个关键字段。 runID:每个 Redis 实例的唯一标识,当主从复制进行时,该值为 Redis 主节点实例的ID。由于首次同步时还不知道主库的实例ID,所以该值第一次为 ? offset:从库数据同步的偏移量,当第一次复制时,该值为 -1,表示全量复制 主服务器收到 PSYNC 命令后,会创建一个专门用于复制的后台线程(replication thread),然后记录从节点的 offset 参数并开始进行 RDB 同步。 2)RDB 同步 主库生成 RDB 文件,同步给从库。 当从服务器连接到主服务器后,主服务器会将自己的数据发送给从服务器,这个过程叫做全量复制。主服务器会执行 bgsave 命令,然后 fork 出一个子进程来遍历自己的数据集并生成一个 RDB 文件,将这个文件发送给从服务器。 在这期间,为了保证 Redis 的高性能,主节点的主进程不会被阻塞,依旧对外提供服务并接收数据写入缓冲区中。 从服务器接收到 RDB 文件后,会清空自身数据,然后加载这个文件,将自己的数据集替换成主服务器的数据集。 3)命令同步 在第一次同步过程中,由于是全量同步,所以用时可能比较长,这期间主库依旧会写入新数据。 但是,在数据同步一开始就生成的 RDB 文件中显然是没有这部分新增数据的,所以第一次数据同步后需要再发送一次这部分新增数据。 这样,主服务器需要在发送完 RDB 文件后,将期间的写操作重新发送给从服务器,以保证从服务器的数据集与主服务器保持一致。 3.3 增量同步 1)命令传播 在完成全量复制后,主从服务器之间会保持一个 TCP 连接,主服务器会将自己的写操作发送给从服务器,从服务器执行这些写操作,从而保持数据一致性,这个过程也称为基于长连接的命令传播(command propagation)。 增量复制的数据是异步复制的,但通过记录写操作,主从服务器之间的数据最终会达到一致状态。 2)网络断开后数据同步 命令传播的过程中,由于网络抖动或故障导致连接断开,此时主节点上新的写命令将无法同步到从库。 即便是抖动瞬间又恢复网络连接,但 TCP 连接已经断开,所以数据需要重新同步。 从 Redis 2.8 开始,从库已支持增量同步,只会把断开的时候没有发生的写命令,同步给从库。 详细过程如下: 网络恢复后,从库携带之前主库返回的 runid,还有复制的偏移量 offset 发送 psync runid offset 命令给主库,请求数据同步; 主库收到命令后,核查 runid 和 offset,确认没问题将响应 continue 命令; 主库发送网络断开期间的写命令,从库接收命令并执行。 这时,有细心的小伙伴可能要问了,网络断开后,主库怎么知道哪些数据是新写入的呢? 这是个好问题,接下来我们详细说明一下。 3)增量复制的关键 Master 在执行写操作时,会将这些命令记录在 repl_backlog_buffer (复制积压缓冲区)里面,并使用 master_repl_offset 记录写入的位置偏移量。 而从库在执行同步的写命令后,也会用 slave_repl_offset 记录写入的位置偏移量。正常情况下,从库会和主库的偏移量保持一致。 但是,当网络断开后,主库继续写入,而从库没有收到新的同步命令,所以偏移量就停止了。所以,master_repl_offset 会大于 slave_repl_offset。 注意:主从库实现增量复制时,都是在 repl_backlog_buffer 缓冲区上进行。 网络断开前后,主从库的同步图如下:   repl_backlog_buffer 复制积压缓冲区是一个环形缓冲区,如果缓冲区慢了(比如超过 1024),则会从头覆盖掉前面的内容。 所以,当网络恢复以后,主节点只需将 master_repl_offset 和 slave_repl_offset 之间的内容同步给从库即可(图中 256~512 这部分数据)。 需要注意的是,主库的积压缓冲区默认为 1M,如果从库网络断开太久,缓冲区之前的内容已经被覆盖,这时主从的数据复制就只能采取全量同步了。 所以我们需要根据业务量和实际情况来设置 repl_backlog_buffer 的值。 4. 小结 面让架构易于扩展,另一方面防止单体故障:当主库挂了,可以立即拉起从库,不至于让业务停滞太久。 而首次主从复制包括建立连接,RDB 同步和命令同步三个阶段。 为了保证同步的效率,除了第一次需要全量同步以外,例如当主从节点断连后,则只需要增量同步,这是由主从库的复制偏移量以及主库的 repl_backlog_buffer 复制积压缓冲区来控制的。 好了,以上就是本文的所有内容了,希望今天的文章能让大家更深入地了解 Redis 主从复制,并在面试或者实际工作中学以致用,探索更多的细节。 ...

    2023-11-07 值得一看 48
  • NTP时间同步过程

    NTP通过时间戳和网络延迟计算来调整本地时钟,以确保系统时钟与NTP服务器的时钟尽可能一致,实现高精度的时间同步。 第一步、NTP客户端发起时间请求 NTP客户端向NTP服务器发起时间请求,请求服务器的准确时间。这个请求通常包括客户端的当前时间戳。 通常,这是通过UDP协议的端口123完成的。NTP客户端可以是计算机、路由器、交换机或其他网络设备。 第二步、NTP服务器响应 NTP服务器收到客户端的请求,并在响应中包括自己的时间戳。服务器的时间通常比客户端的时间更准确。服务器的响应包括四个时间戳:T1、T2、T3、T4。 T1:客户端发送请求的时间。 T2:服务器接收到请求的时间。 T3:服务器发送响应的时间。 T4:客户端接收响应的时间。 NTP服务器可以是Stratum 1服务器(通常是高精度时间源,如原子钟或GPS时钟)或Stratum 2服务器,依次类推。 第三步、计算网络延迟 客户端使用T1、T2、T3、T4时间戳来计算网络延迟和时钟偏移。根据这些时间戳,客户端可以计算出网络延迟,即信号从客户端发送到服务器再返回所需的时间。你在示例中计算了延迟,这在NTP中非常重要,因为网络延迟会对时钟同步产生影响。 第四步、调整本地时钟 客户端使用计算得到的网络延迟和服务器的时间戳来调整自己的本地时钟。这个调整会将客户端的时钟与服务器的时钟对齐,以减小时钟偏移。 ?请记住:时间同步不是一次性事件,而是定期进行的。 客户端设备通常每隔一段时间(通常是每10分钟或每小时)与NTP服务器进行一次时间同步,以确保时钟的准确性。 此后的时间同步交换通常只需要一次消息交换,因为客户端已经与NTP服务器建立了时间校准。 ...

    2023-11-07 值得一看 56
  • 为什么要同步网络时间

    说白了,同步网络时间就是为了应对许多应用和系统对时间的准确性要求非常高的问题,简单罗列一下原因就是: 许多应用程序和系统使用时间戳来记录事件的发生顺序。即使是微小的时间差异,如毫秒级别的差异,都可能导致事件顺序错误,对于事务的准确性和可靠性非常关键。 在一些关键应用中,如金融交易和网络通信,即使是短暂的停机都可能导致巨大的损失。通过同步网络时间,可以确保各种网络设备和应用的时间保持一致,从而避免因时间不同步而导致的问题。 在网络故障排除和恢复中,准确的时间信息对于确定问题的根本原因和追踪故障非常重要。同步网络时间可以帮助精确地记录事件时间戳,有助于快速诊断和修复问题。 许多行业和组织面临合规性和法规要求,其中要求保持时间同步以确保数据的准确性和完整性。同步网络时间有助于满足这些法规要求。 在科学研究和实验中,时间的准确性对于数据采集和分析至关重要。同步网络时间可确保实验结果的可重复性和准确性 ...

    2023-11-07 值得一看 44
  • InnoDB引擎与MyISAM引擎的区别

    1.数据存储的方式不同,MyISAM 中的数据和索引是分开存储的,而 InnoDB 是把索引和数据存储在同一个文件里面。 2.对于事务的支持不同,MyISAM 不支持事务,而 InnoDB 支持 ACID 特性的事务处理 3.对于锁的支持不同,MyISAM 只支持表锁,而 InnoDB 可以根据不同的情况,支持行锁,表锁,间隙锁,临键锁 4.MyISAM 不支持外键,InnoDB 支持外键 当然也可以从索引结构、存储限制等方面,更加深入的回答。 具体参考如下官方文档:https://dev.mysql.com/doc/refman/8.0/en/innodb-introduction.htm ...

    2023-11-06 值得一看 57
  • Memory存储引擎的特点

    Memory介绍 Memory引擎的表数据时存储在内存中的,由于受到硬件问题、或断电问题的影响,只能将这些表作为 临时表或缓存使用。 Memory特点 数据存储在内存中,读取速度非常快。 不支持事务和持久性,数据在数据库重启时丢失。 适合用作缓存或临时存储。 表级锁定 Memory文件 xxx.sdi:存储表结构信息创建表 my_memory , 指定Memory存储引擎 create table my_memory( id int, name varchar(10) ) engine = Memory ; ...

    2023-11-06 值得一看 51
  • 存储引擎区别及特点有哪些

    特点 InnoDB MyISAM Memory 存储限制 64TB 有 有 事务安全 支持 – – 锁机制 行锁 表锁 表锁 B+tree索引 支持 支持 支持 Hash索引 – – 支持 全文索引 支持(5.6版本之后) 支持 – 空间使用 高 低 n/a 内存使用 高 低 中等 批量插入速度 低 高 高 支持外键 支持 – – ...

    2023-11-06 值得一看 49
  • MyISAM存储引擎的特点

    MyISAM介绍 MyISAM是MySQL早期的默认存储引擎。 MyISAM特点 不支持事务,不提供ACID特性。 支持表级锁定,性能较差于InnoDB在高并发环境中。 较快的读取性能,适用于只读或读写很少的应用。 没有外键约束。 MyISAM文件 xxx.sdi:存储表结构信息 xxx.MYD: 存储数据 xxx.MYI: 存储索引创建表 my_myisam , 并指定MyISAM存储引擎 create table my_myisam( id int, name varchar(10) ) engine = MyISAM ; ...

    2023-11-06 值得一看 55
  • innodb存储引擎特点

    InnoDB介绍 InnoDB是一种兼顾高可靠性和高性能的通用存储引擎,在 MySQL 5.5 之后,InnoDB是默认的 MySQL 存储引擎。 InnoDB特点 支持事务,提供ACID(原子性、一致性、隔离性、持久性)特性。 支持行级锁定,适用于高并发环境。 支持外键约束,确保数据一致性。 具有自动崩溃恢复和日志文件,以确保数据的持久性。 InnoDB文件 xxx.ibd:xxx代表的是表名,innoDB引擎的每张表都会对应这样一个表空间文件,存储该表的表结 构(frm-早期的 、sdi-新版的)、数据和索引。参数:innodb_file_per_table show variables like 'innodb_file_per_table' 如果该参数开启,代表对于InnoDB引擎的表,每一张表都对应一个ibd文件。我们直接打开MySQL的 数据存放目录, 这个目录下有很多文件 夹,不同的文件夹代表不同的数据库. 注意:idb是二进制文件,不可以使用记事本直接打开,可以使用mysql提供指令打开 以从ibd文件中提取sdi信息,而sdi数据字典信息中就包含该表的表结构。 注意:使用cmd名称窗口查看 ibd2sdi tb_account.ibd ...

    2023-11-06 值得一看 49
  • MySQL体系结构详解

    客户端应用程序:客户端应用程序是与MySQL数据库交互的用户或应用程序。这些应用程序使用MySQL客户端库来建立连接、发送SQL查询和接收查询结果。 SQL解释器:SQL解释器负责解析客户端应用程序发送的SQL查询语句,将其转换为内部数据结构,然后将其传递给查询优化器。 查询优化器:查询优化器是MySQL的核心组件之一。它分析SQL查询,确定最佳执行计划,并生成一组执行操作,以便从数据库中检索所需的数据。查询优化器考虑了表的索引、表之间的关系以及其他因素来提高查询性能。 存储引擎:MySQL支持多个存储引擎,每个存储引擎负责数据的物理存储和检索。常见的存储引擎包括: InnoDB:支持事务、行级锁定、外键和高并发性。 MyISAM:不支持事务,但具有快速读取性能。 Memory:将数据存储在内存中,用于快速读取和临时存储。 连接池:连接池是用于管理数据库连接的组件。它负责创建、维护和分配数据库连接,以降低连接建立和断开的开销,提高性能。 查询缓存:查询缓存用于存储已执行查询的结果集,以便在将来相同查询的情况下能够快速检索结果。不过,在高并发写入环境中,查询缓存可能会降低性能,因此有时会被禁用。 MySQL服务器:MySQL服务器是数据库管理系统的核心。它接收来自客户端应用程序的SQL查询,通过SQL解释器和查询优化器处理查询,然后将查询委托给适当的存储引擎执行。MySQL服务器还负责安全性、权限管理、事务控制、并发控制、崩溃恢复和日志记录等任务。 日志文件:MySQL使用多种日志文件来记录数据库活动,包括: 二进制日志(Binary Logs):记录所有更改数据的SQL语句,用于复制和恢复。 错误日志(Error Log):记录数据库错误和警告信息。 查询日志(Query Log):记录所有SQL查询,通常用于调试目的。 数据文件和表空间:数据文件是用于存储表数据和索引的物理文件。这些文件通常被组织成表空间,不同的存储引擎可以在不同的表空间中存储数据。 表和索引:表是MySQL数据库中的主要数据存储单元,它们包含了数据行。索引用于加速数据检索操作,提高查询性能。 系统变量和参数文件:MySQL具有一组系统变量,允许管理员配置数据库的行为。这些变量的配置信息通常存储在参数文件中,以便进行高级配置。 ...

    2023-11-06 值得一看 60
  • 什么是NTP

    NTP,英文全称:Network Time Protocol,中文全名网络时间协议,是一种用于在计算机网络中同步设备时钟的协议。 它的主要目标是确保网络中的各个设备都具有一致的时间参考,以便它们可以协同工作,进行时间戳记录、数据同步和各种计算任务。 NTP采用分层结构来确保时间同步,使网络中的所有设备都能获得准确的时间信息。 ...

    2023-11-06 值得一看 55
  • Linux Shell脚本监控磁盘利用率

    这是一个用于监控服务器磁盘利用率的shell脚本,它的功能和意义如下: 第一行是一个特殊的注释,用于指定执行这个脚本的解释器,这里是bash。 第三行到第十行是一些变量的定义,用于设置监控的参数,比如要监控哪些磁盘分区,报警的阈值是多少,检测的频率是多少,日志文件的位置和名称是什么等。 第十二行到第二十四行是一个函数的定义,叫做send_mail,它的作用是发送邮件给指定的收件人,告知他们哪些磁盘分区已经超过了阈值。这个函数需要一个参数,就是超过阈值的分区名称和利用率。 第二十六行到第四十八行是另一个函数的定义,叫做monitor_disk,它是主循环函数,它的作用是不断地检测磁盘利用率,并且如果发现有超过阈值的情况,就调用send_mail函数发送邮件,并且记录日志文件。这个函数没有参数,但是会使用前面定义的一些变量。 第五十行是调用monitor_disk函数的语句,这样就可以开始执行监控任务了。 #!/bin/bash # 监控服务器磁盘利用率的shell脚本 # 定义要监控的磁盘分区,可以有多个,用空格隔开 PARTITIONS="/dev/sda1 /dev/sdb1" # 定义报警阈值,单位为百分比 THRESHOLD=80 # 定义检测频率,单位为秒 INTERVAL=60 # 定义日志文件的路径和名称 LOGFILE=/tmp/disk_monitor.log # 定义邮件发送函数,需要安装mailx命令 send_mail(){ # 定义收件人邮箱地址,可以有多个,用空格隔开 MAILTO="user1@example.com user2@example.com" # 定义邮件主题 SUBJECT="Disk Usage Alert" # 定义邮件正文 MESSAGE="The following partitions have reached the threshold of $THRESHOLD%: $1" # 发送邮件 echo $MESSAGE | mailx -s "$SUBJECT" $MAILTO } # 定义主循环函数 monitor_disk(){ while true do # 获取当前时间 DATE=$(date "+%Y-%m-%d %H:%M:%S") # 遍历要监控的磁盘分区 for PARTITION in $PARTITIONS do # 获取磁盘利用率,去掉百分号 USAGE=$(df -h | grep $PARTITION | awk '{print $5}' | sed 's/%//') # 判断是否超过阈值 if [ $USAGE -ge $THRESHOLD ] then # 记录日志文件 echo "$DATE $PARTITION usage: $USAGE%" >> $LOGFILE # 调用邮件发送函数,传入超过阈值的分区名称和利用率 send_mail "$PARTITION usage: $USAGE%" fi done # 等待一定时间后再次检测 sleep $INTERVAL done } # 调用主循环函数 monitor_disk </div> ...

    2023-11-05 值得一看 53
  • MySQL有哪些锁

    大家好,我是不念,这次,来说说 MySQL 的锁,主要是 Q&A 的形式,看起来会比较轻松。 在 MySQL 里,根据加锁的范围,可以分为全局锁、表级锁和行锁三类。 全局锁 全局锁是怎么用的? 要使用全局锁,则要执行这条命令: flush tables with read lock 执行后,整个数据库就处于只读状态了,这时其他线程执行以下操作,都会被阻塞: 对数据的增删改操作,比如 insert、delete、update等语句; 对表结构的更改操作,比如 alter table、drop table 等语句。 如果要释放全局锁,则要执行这条命令: unlock tables 当然,当会话断开了,全局锁会被自动释放。 全局锁应用场景是什么? 全局锁主要应用于做全库逻辑备份,这样在备份数据库期间,不会因为数据或表结构的更新,而出现备份文件的数据与预期的不一样。 举个例子大家就知道了。 在全库逻辑备份期间,假设不加全局锁的场景,看看会出现什么意外的情况。 如果在全库逻辑备份期间,有用户购买了一件商品,一般购买商品的业务逻辑是会涉及到多张数据库表的更新,比如在用户表更新该用户的余额,然后在商品表更新被购买的商品的库存。 那么,有可能出现这样的顺序: 先备份了用户表的数据; 然后有用户发起了购买商品的操作; 接着再备份商品表的数据。 也就是在备份用户表和商品表之间,有用户购买了商品。 这种情况下,备份的结果是用户表中该用户的余额并没有扣除,反而商品表中该商品的库存被减少了,如果后面用这个备份文件恢复数据库数据的话,用户钱没少,而库存少了,等于用户白嫖了一件商品。 所以,在全库逻辑备份期间,加上全局锁,就不会出现上面这种情况了。 加全局锁又会带来什么缺点呢? 加上全局锁,意味着整个数据库都是只读状态。 那么如果数据库里有很多数据,备份就会花费很多的时间,关键是备份期间,业务只能读数据,而不能更新数据,这样会造成业务停滞。 既然备份数据库数据的时候,使用全局锁会影响业务,那有什么其他方式可以避免? 有的,如果数据库的引擎支持的事务支持可重复读的隔离级别,那么在备份数据库之前先开启事务,会先创建 Read View,然后整个事务执行期间都在用这个 Read View,而且由于 MVCC 的支持,备份期间业务依然可以对数据进行更新操作。 因为在可重复读的隔离级别下,即使其他事务更新了表的数据,也不会影响备份数据库时的 Read View,这就是事务四大特性中的隔离性,这样备份期间备份的数据一直是在开启事务时的数据。 备份数据库的工具是 mysqldump,在使用 mysqldump 时加上 –single-transaction 参数的时候,就会在备份数据库之前先开启事务。这种方法只适用于支持「可重复读隔离级别的事务」的存储引擎。 InnoDB 存储引擎默认的事务隔离级别正是可重复读,因此可以采用这种方式来备份数据库。 但是,对于 MyISAM 这种不支持事务的引擎,在备份数据库时就要使用全局锁的方法。 表级锁 MySQL 表级锁有哪些?具体怎么用的。 MySQL 里面表级别的锁有这几种: 表锁; 元数据锁(MDL); 意向锁; AUTO-INC 锁; 表锁 先来说说表锁。 如果我们想对学生表(t_student)加表锁,可以使用下面的命令: //表级别的共享锁,也就是读锁; lock tables t_student read; //表级别的独占锁,也就是写锁; lock tables t_stuent write; 需要注意的是,表锁除了会限制别的线程的读写外,也会限制本线程接下来的读写操作。 也就是说如果本线程对学生表加了「共享表锁」,那么本线程接下来如果要对学生表执行写操作的语句,是会被阻塞的,当然其他线程对学生表进行写操作时也会被阻塞,直到锁被释放。 要释放表锁,可以使用下面这条命令,会释放当前会话的所有表锁: unlock tables 另外,当会话退出后,也会释放所有表锁。 不过尽量避免在使用 InnoDB 引擎的表使用表锁,因为表锁的颗粒度太大,会影响并发性能,InnoDB 牛逼的地方在于实现了颗粒度更细的行级锁。 元数据锁 再来说说元数据锁(MDL)。 我们不需要显示的使用 MDL,因为当我们对数据库表进行操作时,会自动给这个表加上 MDL: 对一张表进行 CRUD 操作时,加的是 MDL 读锁; 对一张表做结构变更操作的时候,加的是 MDL 写锁; MDL 是为了保证当用户对表执行 CRUD 操作时,防止其他线程对这个表结构做了变更。 当有线程在执行 select 语句( 加 MDL 读锁)的期间,如果有其他线程要更改该表的结构( 申请 MDL 写锁),那么将会被阻塞,直到执行完 select 语句( 释放 MDL 读锁)。 反之,当有线程对表结构进行变更( 加 MDL 写锁)的期间,如果有其他线程执行了 CRUD 操作( 申请 MDL 读锁),那么就会被阻塞,直到表结构变更完成( 释放 MDL 写锁)。 MDL 不需要显示调用,那它是在什么时候释放的? MDL 是在事务提交后才会释放,这意味着事务执行期间,MDL 是一直持有的。 那如果数据库有一个长事务(所谓的长事务,就是开启了事务,但是一直还没提交),那在对表结构做变更操作的时候,可能会发生意想不到的事情,比如下面这个顺序的场景: 首先,线程 A 先启用了事务(但是一直不提交),然后执行一条 select 语句,此时就先对该表加上 MDL 读锁; 然后,线程 B 也执行了同样的 select 语句,此时并不会阻塞,因为「读读」并不冲突; 接着,线程 C 修改了表字段,此时由于线程 A 的事务并没有提交,也就是 MDL 读锁还在占用着,这时线程 C 就无法申请到 MDL 写锁,就会被阻塞, 那么在线程 C 阻塞后,后续有对该表的 select 语句,就都会被阻塞,如果此时有大量该表的 select 语句的请求到来,就会有大量的线程被阻塞住,这时数据库的线程很快就会爆满了。 为什么线程 C 因为申请不到 MDL 写锁,而导致后续的申请读锁的查询操作也会被阻塞? 这是因为申请 MDL 锁的操作会形成一个队列,队列中写锁获取优先级高于读锁,一旦出现 MDL 写锁等待,会阻塞后续该表的所有 CRUD 操作。 所以为了能安全的对表结构进行变更,在对表结构变更前,先要看看数据库中的长事务,是否有事务已经对表加上了 MDL 读锁,如果可以考虑 kill 掉这个长事务,然后再做表结构的变更。 意向锁 接着,说说意向锁。 在使用 InnoDB 引擎的表里对某些记录加上「共享锁」之前,需要先在表级别加上一个「意向共享锁」; 在使用 InnoDB 引擎的表里对某些纪录加上「独占锁」之前,需要先在表级别加上一个「意向独占锁」; 也就是,当执行插入、更新、删除操作,需要先对表加上「意向独占锁」,然后对该记录加独占锁。 而普通的 select 是不会加行级锁的,普通的 select 语句是利用 MVCC 实现一致性读,是无锁的。 不过,select 也是可以对记录加共享锁和独占锁的,具体方式如下: //先在表上加上意向共享锁,然后对读取的记录加共享锁 select ... lock in share mode; //先表上加上意向独占锁,然后对读取的记录加独占锁 select ... for update; 意向共享锁和意向独占锁是表级锁,不会和行级的共享锁和独占锁发生冲突,而且意向锁之间也不会发生冲突,只会和共享表锁(lock tables … read)和独占表锁(lock tables … write)发生冲突。 表锁和行锁是满足读读共享、读写互斥、写写互斥的。 如果没有「意向锁」,那么加「独占表锁」时,就需要遍历表里所有记录,查看是否有记录存在独占锁,这样效率会很慢。 那么有了「意向锁」,由于在对记录加独占锁前,先会加上表级别的意向独占锁,那么在加「独占表锁」时,直接查该表是否有意向独占锁,如果有就意味着表里已经有记录被加了独占锁,这样就不用去遍历表里的记录。 所以,意向锁的目的是为了快速判断表里是否有记录被加锁。 AUTO-INC 锁 表里的主键通常都会设置成自增的,这是通过对主键字段声明 AUTO_INCREMENT 属性实现的。 之后可以在插入数据时,可以不指定主键的值,数据库会自动给主键赋值递增的值,这主要是通过 AUTO-INC 锁实现的。 AUTO-INC 锁是特殊的表锁机制,锁不是再一个事务提交后才释放,而是再执行完插入语句后就会立即释放。 在插入数据时,会加一个表级别的 AUTO-INC 锁,然后为被 AUTO_INCREMENT 修饰的字段赋值递增的值,等插入语句执行完成后,才会把 AUTO-INC 锁释放掉。 那么,一个事务在持有 AUTO-INC 锁的过程中,其他事务的如果要向该表插入语句都会被阻塞,从而保证插入数据时,被 AUTO_INCREMENT 修饰的字段的值是连续递增的。 但是, AUTO-INC 锁再对大量数据进行插入的时候,会影响插入性能,因为另一个事务中的插入会被阻塞。 因此, 在 MySQL 5.1.22 版本开始,InnoDB 存储引擎提供了一种轻量级的锁来实现自增。 一样也是在插入数据的时候,会为被 AUTO_INCREMENT 修饰的字段加上轻量级锁,然后给该字段赋值一个自增的值,就把这个轻量级锁释放了,而不需要等待整个插入语句执行完后才释放锁。 InnoDB 存储引擎提供了个 innodb_autoinc_lock_mode 的系统变量,是用来控制选择用 AUTO-INC 锁,还是轻量级的锁。 当 innodb_autoinc_lock_mode = 0,就采用 AUTO-INC 锁,语句执行结束后才释放锁; 当 innodb_autoinc_lock_mode = 2,就采用轻量级锁,申请自增主键后就释放锁,并不需要等语句执行后才释放。 当 innodb_autoinc_lock_mode = 1: 普通 insert 语句,自增锁在申请之后就马上释放; 类似 insert … select 这样的批量插入数据的语句,自增锁还是要等语句结束后才被释放; 当 innodb_autoinc_lock_mode = 2 是性能最高的方式,但是当搭配 binlog 的日志格式是 statement 一起使用的时候,在「主从复制的场景」中会发生数据不一致的问题。 举个例子,考虑下面场景: session A 往表 t 中插入了 4 行数据,然后创建了一个相同结构的表 t2,然后两个 session 同时执行向表 t2 中插入数据。 如果 innodb_autoinc_lock_mode = 2,意味着「申请自增主键后就释放锁,不必等插入语句执行完」。那么就可能出现这样的情况: session B 先插入了两个记录,(1,1,1)、(2,2,2); 然后,session A 来申请自增 id 得到 id=3,插入了(3,5,5); 之后,session B 继续执行,插入两条记录 (4,3,3)、 (5,4,4)。 可以看到,session B 的 insert 语句,生成的 id 不连续。 当「主库」发生了这种情况,binlog 面对 t2 表的更新只会记录这两个 session 的 insert 语句,如果 binlog_format=statement,记录的语句就是原始语句。记录的顺序要么先记 session A 的 insert 语句,要么先记 session B 的 insert 语句。 但不论是哪一种,这个 binlog 拿去「从库」执行,这时从库是按「顺序」执行语句的,只有当执行完一条 SQL 语句后,才会执行下一条 SQL。因此,在从库上「不会」发生像主库那样两个 session 「同时」执行向表 t2 中插入数据的场景。所以,在备库上执行了 session B 的 insert 语句,生成的结果里面,id 都是连续的。这时,主从库就发生了数据不一致。 要解决这问题,binlog 日志格式要设置为 row,这样在 binlog 里面记录的是主库分配的自增值,到备库执行的时候,主库的自增值是什么,从库的自增值就是什么。 所以,当 innodb_autoinc_lock_mode = 2 时,并且 binlog_format = row,既能提升并发性,又不会出现数据一致性问题。 行级锁 InnoDB 引擎是支持行级锁的,而 MyISAM 引擎并不支持行级锁。 前面也提到,普通的 select 语句是不会对记录加锁的,因为它属于快照读。如果要在查询时对记录加行锁,可以使用下面这两个方式,这种查询会加锁的语句称为锁定读。 //对读取的记录加共享锁 select ... lock in share mode; //对读取的记录加独占锁 select ... for update; 上面这两条语句必须在一个事务中,因为当事务提交了,锁就会被释放,所以在使用这两条语句的时候,要加上 begin、start transaction 或者 set autocommit = 0。 共享锁(S锁)满足读读共享,读写互斥。独占锁(X锁)满足写写互斥、读写互斥。 行级锁的类型主要有三类: Record Lock,记录锁,也就是仅仅把一条记录锁上; Gap Lock,间隙锁,锁定一个范围,但是不包含记录本身; Next-Key Lock:Record Lock + Gap Lock 的组合,锁定一个范围,并且锁定记录本身。 Record Lock Record Lock 称为记录锁,锁住的是一条记录。而且记录锁是有 S 锁和 X 锁之分的: 当一个事务对一条记录加了 S 型记录锁后,其他事务也可以继续对该记录加 S 型记录锁(S 型与 S 锁兼容),但是不可以对该记录加 X 型记录锁(S 型与 X 锁不兼容); 当一个事务对一条记录加了 X 型记录锁后,其他事务既不可以对该记录加 S 型记录锁(S 型与 X 锁不兼容),也不可以对该记录加 X 型记录锁(X 型与 X 锁不兼容)。 举个例子,当一个事务执行了下面这条语句: mysql > begin; mysql > select * from t_test where id = 1 for update; 就是对 t_test 表中主键 id 为 1 的这条记录加上 X 型的记录锁,这样其他事务就无法对这条记录进行修改了。 当事务执行 commit 后,事务过程中生成的锁都会被释放。 Gap Lock Gap Lock 称为间隙锁,只存在于可重复读隔离级别,目的是为了解决可重复读隔离级别下幻读的现象。 假设,表中有一个范围 id 为(3,5)间隙锁,那么其他事务就无法插入 id = 4 这条记录了,这样就有效的防止幻读现象的发生。 间隙锁虽然存在 X 型间隙锁和 S 型间隙锁,但是并没有什么区别,间隙锁之间是兼容的,即两个事务可以同时持有包含共同间隙范围的间隙锁,并不存在互斥关系,因为间隙锁的目的是防止插入幻影记录而提出的。 Next-Key Lock Next-Key Lock 称为临键锁,是 Record Lock + Gap Lock 的组合,锁定一个范围,并且锁定记录本身。 假设,表中有一个范围 id 为(3,5] 的 next-key lock,那么其他事务即不能插入 id = 4 记录,也不能修改 id = 5 这条记录。 所以,next-key lock 即能保护该记录,又能阻止其他事务将新纪录插入到被保护记录前面的间隙中。 next-key lock 是包含间隙锁+记录锁的,如果一个事务获取了 X 型的 next-key lock,那么另外一个事务在获取相同范围的 X 型的 next-key lock 时,是会被阻塞的。 比如,一个事务持有了范围为 (1, 10] 的 X 型的 next-key lock,那么另外一个事务在获取相同范围的 X 型的 next-key lock 时,就会被阻塞。 虽然相同范围的间隙锁是多个事务相互兼容的,但对于记录锁,我们是要考虑 X 型与 S 型关系,X 型的记录锁与 X 型的记录锁是冲突的。 插入意向锁 一个事务在插入一条记录的时候,需要判断插入位置是否已被其他事务加了间隙锁(next-key lock 也包含间隙锁)。 如果有的话,插入操作就会发生阻塞,直到拥有间隙锁的那个事务提交为止(释放间隙锁的时刻),在此期间会生成一个插入意向锁,表明有事务想在某个区间插入新记录,但是现在处于等待状态。 举个例子,假设事务 A 已经对表加了一个范围 id 为(3,5)间隙锁。 当事务 A 还没提交的时候,事务 B 向该表插入一条 id = 4 的新记录,这时会判断到插入的位置已经被事务 A 加了间隙锁,于是事物 B 会生成一个插入意向锁,然后将锁的状态设置为等待状态(PS:MySQL 加锁时,是先生成锁结构,然后设置锁的状态,如果锁状态是等待状态,并不是意味着事务成功获取到了锁,只有当锁状态为正常状态时,才代表事务成功获取到了锁),此时事务 B 就会发生阻塞,直到事务 A 提交了事务。 插入意向锁名字虽然有意向锁,但是它并不是意向锁,它是一种特殊的间隙锁,属于行级别锁。 如果说间隙锁锁住的是一个区间,那么「插入意向锁」锁住的就是一个点。因而从这个角度来说,插入意向锁确实是一种特殊的间隙锁。 插入意向锁与间隙锁的另一个非常重要的差别是:尽管「插入意向锁」也属于间隙锁,但两个事务却不能在同一时间内,一个拥有间隙锁,另一个拥有该间隙区间内的插入意向锁(当然,插入意向锁如果不在间隙锁区间内则是可以的)。 ...

    2023-11-05 值得一看 51
  • 什么是网络数据包代理(NPB),特点及其类型有哪些

    网络数据包代理(NPB)是一种主动设备,它设计用于接收、处理和分发网络流量,以实现更高级的网络可视性和优化。 NPB通常包括多个输入端口和输出端口,允许管理员配置规则,以根据特定的标准选择性地将数据包从输入端口传递到输出端口。 NPB特点 高级流量处理:NPB可以根据预定义的规则和策略对流量进行处理,例如过滤、负载均衡、数据包修复、流量切片等。 智能流量分发:NPB具有智能流量分发功能,根据特定的规则将数据包引导到适当的监视或安全工具,以确保工具的高效利用。 多源流量处理:NPB能够同时处理来自多个网络源的流量,例如网络链路、交换机、路由器或TAP。这使得它们在大型网络中特别有用。 灵活性和可扩展性:NPB通常提供了更大的灵活性,管理员可以根据需要配置规则和策略,以适应不同的监控和分析要求。此外,它们可以在多个监视工具之间均匀分发流量,以防止工具过载,从而确保最佳的工具性能。 NPB类型 固定网络数据包代理: 适用情况:固定网络数据包代理通常适用于具有明确定义网络拓扑的情况,其中网络结构相对简单且不经常更改。这种类型的NBP适合于聚合外部无源分路器、SPAN(Switched Port Analyzer)端口以及安全/监控设备。 特点:它通常是较小的设备,专门用于特定任务,例如连接到特定交换机端口的监控设备。这些设备通常不支持模块化设计,而是为特定用途而构建。 模块化网络数据包代理: 适用情况:模块化网络数据包代理是一种多用途平台,适用于各种网络拓扑和可见性场景。它们可以适应不同的需求,包括旁路、被动和代理功能。 特点:这些NBP通常具有可配置的模块化设计,允许用户根据其特定需求进行自定义配置。它们通常支持多种功能,包括流量聚合、过滤、镜像和负载平衡。这种灵活性使其适用于不同的网络环境。 混合数据包代理/旁路: 适用情况:混合数据包代理/旁路设备是一种组合式一体化设备,它融合了旁路交换机和数据包代理的功能和优点。它可以用于各种网络部署,为不同的网段提供广泛的数据包过滤、分发、聚合和镜像功能。 特点:这些设备结合了旁路交换机的特性,例如高可用性和快速故障转移,以及数据包代理的功能,如流量过滤和负载平衡。这使其成为一个多功能工具,可满足各种网络监控需求。 NPB应用领域 网络性能优化:NPB可以帮助优化网络性能,通过负载均衡、流量切片和过滤,确保监控工具获得最相关的数据,提高性能分析的效率。 安全监控:NPB在安全监控中发挥重要作用,通过检测异常活动、入侵检测和威胁分析来提高网络安全性。 数据包修复:NPB能够修复损坏的数据包,以确保分析工具不会因数据包损坏而受到干扰。 合规性:NPB可以满足合规性监控的需求,通过提供高级流量控制和数据包分析来满足合规性要求。 尽管NPB在网络监控和优化中提供了许多高级功能,但它们也需要更多的配置和管理。 管理员需要定义规则和策略,以确保NPB按预期工作。 此外,NPB通常是较昂贵的解决方案,适用于对高级流量管理和处理有需求的组织。 ...

    2023-11-04 值得一看 52
  • 流量接入点(TAP)特点及其类型有哪些

    流量接入点(TAP)是一种被动设备,用于监控和捕获网络流量,而不干扰网络的正常运行,部署在网络基础设施内的战略位置,以拦截和复制网络数据包。 它的主要工作是将通过特定链路或网段传输的数据包复制到监视设备,如网络分析仪、数据包捕获工具或安全设备。 1.1 TAP特点 非侵入性:TAP以非侵入性的方式工作,不会中断网络流量的传输,也不会引入延迟。 数据包完整性:TAP提供对网络通信的完整可见性,捕获所有流经链路或网段的数据包,包括入站和出站流量。 网络监控:TAP可用于链路监控、网络性能监测、故障排除以及安全事件检测。 数据复制:TAP复制原始数据包,将其传递给连接的监视设备,以便进行进一步的分析和处理。 1.2 TAP类型 TAP可以分为有源网络TAP和无源网络TAP,这两种类型的TAP在网络流量监控中有不同的应用和特点。 有源网络TAP: 特点:有源网络TAP是一种主动设备,它接收来自网络链路的数据流,然后复制并转发这些数据流到监控或分析设备。它在数据流经过时会放大信号,以确保数据的完整性和可见性。 应用:有源网络TAP适用于大型或复杂网络中,需要扩展信号以维持数据完整性的情况。它们通常用于支持高速链路、远距离传输或需要信号放大的环境。 无源网络TAP: 特点:无源网络TAP是一种被动设备,它不引入延迟、不放大信号,而只复制数据包。它的工作方式类似于网络的“看客”,不对数据流做任何干预。 应用:无源网络TAP适用于大多数网络监控场景,特别是当需要非侵入性监控网络链路或网段时。它们通常部署在网络拓扑中的战略点,以捕获和复制流经的数据包,而不影响原始流量。 1.3 TAP的应用领域 网络性能监控:通过捕获网络流量,TAP有助于检测网络性能问题,例如带宽利用率、延迟、数据包丢失等。 安全监控:TAP可用于监视网络中的异常活动、潜在的安全威胁和攻击,以及入侵检测系统(IDS)和入侵预防系统(IPS)的操作。 合规性:许多组织需要满足合规性要求,TAP提供了对网络通信的全面可见性,以满足合规性监控的需求。 数据包捕获:网络管理员和安全专业人员可以使用TAP来捕获网络数据包以进行离线分析,以便进行深入调查和故障排除。 然而,尽管TAP在网络监控中发挥着重要作用,但它也存在一些局限性。 TAP不能对流量进行处理或过滤,而只是复制原始数据包。 此外,需要在网络中的多个位置部署TAP才能全面覆盖网络。 ...

    2023-11-04 值得一看 50
  • Garuda Linux “Spizaetus” 发布,可以体验KDE Plasma 6了!

    Garuda Linux,作为一款 用户友好且基于 Arch Linux 的发行版,由于其可高度定制和可扩展性,近期已经吸引了大批用户。 Garuda Linux 提供了众多选项以满足不同的使用场景,无论是编程还是游戏。 目前,Garuda Linux 的最新发布版,Garuda Linux “Spizaetus”现已可用。 下面,让我来引导你了解一下这个版本。 ? Garuda Linux “Spizaetus”:有哪些新变化? 这个版本的代号“Spizaetus” 是来源于一种通常在美洲热带地区发现的鹰鹞。此次发布的主要亮点包括: 提供 Hyprland ISO Ugrep 取代了 Grep 提供了实验性的 KDE Plasma 6 仓库 提供 Hyprland ISO 在这个 Garuda Linux 的版本中,推出了带有 Hyprland动态平铺 Wayland 组合器的新 ISO,这让流畅的动画和轻松的窗口平铺成为可能。 在此,开发者之一的 dr460nf1r3表示: 关注精美的界面和模糊的窗口,Hyprland 无疑是 Garuda 的完美搭配。 ? 然而,不幸的是,他们不得不停止一些其它变体的更新,因为这些变体并未得到妥善维护。受影响的变体包括:MATE、LXQt-Kwin、KDE-git和Wayfire。 Ugrep 取代了 Grep grep命令行工具已被性能更强的ugrep文件模式搜索器所取代,后者声称自己是“超快速且用户友好的 Grep 替代品”。 这是一个令人感兴趣的改变,我们期待看到用户的反馈。 实验性的 KDE Plasma 6 仓库(请谨慎!) 开发者们还引入了一个名为 chaotic-aur-kde的实验性仓库,以提供早期版本的 Plasma 6。 请注意,这是为那些想提前体验 Plasma 6 设计的用户而设,并不建议将其用于生产环境。 一位开发者补充道: 我们一直在努力通过特定的 chaotic-aur-kde 仓库,提供 Plasma 6 的早期构建。 这可以让我们初步探索未来的 Plasma 6 将会是什么样子 – 它的首个版本计划在 2024 年 2 月发布。无需多说,这些都是来自主分支的实验性构建版,因此只适合喜欢接受挑战认的人去体验。 ?️ 其它的变化和改进 除了上述的亮点之外,还有些其他值得一提的细化调整: garuda-update 工具已更新用于处理近期由于包名称变更引发的冲突。 Plymouth已被移除,现在在启动时,会显示终端的输出内容。 对他们的基础设施进行了各种更新,以服务用户。 为 Garuda Linux 安装了一个专用的 Lemmy 实例。 你可以查阅 官方公告来获取更多详细信息。 ...

    2023-11-04 值得一看 50
  • Skiff Mail 添加了方便的“快速别名”功能

    Skiff Mail 是一款开源的端到端加密电子邮件服务,非常注重隐私。在各方面,包括用户体验方面,它都是 Gmail 和 Proton mail 的不错替代品。 虽然与竞争对手相比,它相当新,但它的一些注重隐私的功能可能会给你留下深刻的印象。 此外,还推出了一项新的快速别名功能。我试用了一下,感觉非常方便。 快速别名:一次性无忧设置 一般来说,你可以使用一些 电子邮件保护工具(例如 SimpleLogin)或从你的电子邮件提供商(无论是谁)创建电子邮件别名。 你可以选择记住电子邮件别名以供使用,或者在每次注册服务、新闻通讯或向你不认识的人提供联系信息时生成唯一的别名。 换句话说,大多数情况下,需要你进行多次交互才能使用多个电子邮件别名。 在这里,Skiff Mail允许你为自己声明一个完整的唯一子域,例如gojo.maskmy.id(正如我在测试用例中所做的那样): 接下来,你所要做的就是 – 在激活它时将其视为你的网站地址,并在其之前添加任何内容作为电子邮件地址,例如 xyz@gojo.maskmy.id或demo@gojo.maskmy.id。 如上面的截图所示,你也可以选择生成一个随机名称来声明。 你可以从“设置Settings”菜单访问“快速别名Quick Aliases”功能: 因此,你不再需要生成电子邮件别名,但仍然可以通过这种方式拥有无限的别名。使其成为一次性设置解决方案,可供在线和离线使用。 我认为这些类型的别名应该有几个好处: 它使你无需访问该工具即可轻松创建新别名 使电子邮件别名看起来比垃圾邮件更真实 根据你的订阅,每人最多可以申请 3 个域名(Essential:1、Pro:2、Business:3)。并且,使用它们创建无限的电子邮件别名。 ...

    2023-11-04 值得一看 49
  • 什么是主从延时?

    有时候我们遇到从数据库中获取不到信息的诡异问题时,会纠结于代码中是否有一些逻辑会把之前写入的内容删除,但是你又会发现,过了一段时间再去查询时又可以读到数据了,这基本上就是主从延迟在作怪。 主从延迟,其实就是“从库回放” 完成的时间,与 “主库写 binlog” 完成时间的差值,会导致从库查询的数据,和主库的不一致。 ...

    2023-11-03 值得一看 55
  • 主从延迟的原因

    探讨这个问题前,我们需要知道主从复制的原理。 主从复制原理 MySQL 的主从复制是依赖于 binlog,也就是记录 MySQL 上的所有变化并以二进制形式保存在磁盘上二进制日志文件。 主从复制就是将 binlog 中的数据从主库传输到从库上,一般这个过程是异步的,即主库上的操作不会等待 binlog 同步地完成。 详细流程如下: 主库写 binlog:主库的更新 SQL(update、insert、delete) 被写到 binlog; 主库发送 binlog:主库创建一个 log dump 线程来发送 binlog 给从库; 从库写 relay log:从库在连接到主节点时会创建一个 IO 线程,以请求主库更新的 binlog,并且把接收到的 binlog 信息写入一个叫做 relay log 的日志文件; 从库回放:从库还会创建一个 SQL 线程读取 relay log 中的内容,并且在从库中做回放,最终实现主从的一致性。 主从延时原因 我们分析一下主从复制的过程。 MySQL 的主从复制都是单线程的操作,主库对所有 DDL 和 DML 产生 binlog,binlog 是顺序写,所以效率很高。 Slave 的 Slave_IO_Running 线程会到主库取日志,放入 relay log,效率会比较高。 Slave 的 Slave_SQL_Running 线程将主库的 DDL 和 DML 操作都在 Slave 实施,DML 和 DDL 的 IO 操作是随机的,不是顺序的,因此成本会很高。 还可能是 Slave 上的其他查询产生 lock 争用,由于 Slave_SQL_Running 也是单线程的,所以一个 DDL 卡住了,需要执行 10 分钟,那么所有之后的 DDL 会等待这个 DDL 执行完才会继续执行,这就导致了延时。 总结一下主从延迟的主要原因:主从延迟主要是出现在 “relay log 回放” 这一步,当主库的 TPS 并发较高,产生的 DDL 数量超过从库一个 SQL 线程所能承受的范围,那么延时就产生了,当然还有就是可能与从库的大型 query 语句产生了锁等待。 ...

    2023-11-03 值得一看 46
  • 编程语言排行榜及其特点、优缺点

    无论你是正在学习编程,还是已经是一位经验丰富的开发者,对于选择合适的编程语言都是一个不可回避的问题。 在这篇文章中,不念将比较并探讨八种常见的编程语言,帮助你选择最适合你的编程语言。 下图是2023年11月,由全球知名编程语言社区TIOBE公布的榜单,排在前5名的分别为Python,C,C++,Java,C#. 但我并不打算按照排名逐个介绍,而是从我的角度,我自认为的学习复杂度,由简单到复杂开始。这里排除了C语言,因为这个大家都太熟悉了,作为程序员,大学肯定都会学过C语言,即使非计算机专业,也都多少会了解一些C语言。 这里主要介绍其他的几个常用的高级语言,介绍其特点,优缺点以及使用场景等。 1. Python Python是一种高级、通用、解释型的编程语言。 它具有以下特点: 简洁易读:Python采用简洁的语法和明确的代码排版风格,使得代码具有良好的可读性,降低了学习和阅读代码的难度。 多用途:Python适用于各种领域的开发,包括Web开发、数据分析、人工智能、科学计算等,成为了非常通用的编程语言。 强大的库支持:Python拥有丰富的第三方库和框架,如Django、Flask、NumPy、Pandas等,为开发者提供了快速、高效的开发工具。 Python的主要优点有: 简单易学:Python的语法简洁清晰,初学者可以很快上手。 高效开发:Python提供了大量的库和开发工具,可以帮助开发者快速高效地完成项目。 广泛应用:Python可用于各种领域的开发,非常受前沿技术领域的青睐。 然而,Python也有一些缺点: 运行速度相对较慢:与编译型语言相比,Python的运行速度较慢,特别是在处理大规模数据时。 全局解释器锁(GIL):Python的GIL限制了多线程的并行执行,可能影响多线程应用的性能。 Python适合用于: Web开发:使用Django、Flask等框架可以快速构建稳定可靠的Web应用。 数据分析:Python拥有强大的数据处理和分析库,如NumPy、Pandas、Matplotlib等,适用于数据探索和分析。 人工智能:Python成为了深度学习、机器学习、自然语言处理等领域的主流语言,配合人工智能库如TensorFlow、PyTorch等可以进行模型训练与应用开发。 典型的开源软件和框架: Django:一个强大的Python Web框架,用于构建高效的Web应用程序。 NumPy:一个高性能科学计算库,提供了强大的多维数组对象和相关函数。 TensorFlow:一个流行的深度学习框架,用于构建和训练神经网络模型。 Python拥有一个活跃的社区,有大量的在线资源、各种教程和社区论坛,开发者可以方便地获取帮助和交流经验。 2. Java Java是一种高级、面向对象的编程语言。 它具有以下特点: 平台无关性:Java使用Java虚拟机(JVM)作为中间层,在不同的平台上都可以运行,这使得Java具备了平台无关性的特点。 强类型语言:Java是一种静态类型的语言,变量需提前声明并指定类型。 强大的生态系统:Java拥有庞大、稳定且成熟的生态系统,包括丰富的开发工具、框架和库。 Java的主要优点有: 可靠性和稳定性:Java的设计注重可靠性和稳定性,具备异常处理机制、垃圾回收等特性,提供了更高的代码健壮性和稳定性。 多线程支持:Java提供了多线程支持,开发者可以轻松实现多线程并发编程。 大型应用开发:Java适用于开发大型应用和企业级应用,如JavaEE,可以构建高可用、高性能的分布式系统。 然而,Java也有一些缺点: 冗长的语法:相比其他语言,Java的语法相对冗长,需要更多的代码量来完成相同的功能。 相对较慢的运行速度:与一些编译型语言相比,Java的运行速度较慢。 Java适合用于: 企业级应用开发:Java的稳定性、可靠性和强大的生态系统使其成为开发大型企业级应用的首选语言。 Android应用开发:Java是Android平台的主要开发语言,可以用于开发各种类型的Android应用。 大数据处理:Java拥有大量的开源框架,如Hadoop、Spark等,适合处理大规模数据和分布式计算。 典型的开源软件和框架: Spring Framework:一个全功能的Java开发框架,用于构建企业级应用程序。 Hibernate:一个强大的对象关系映射(ORM)框架,用于简化Java应用程序与数据库之间的交互。 Apache Hadoop:一个可扩展的大数据处理框架,对于大规模数据的分布式处理非常有效。 Java拥有广泛的社区支持和活跃的开发者社区,在线教程、文档和社区论坛等资源丰富,对于学习和解决问题都非常有帮助。 3. JavaScript JavaScript是一种脚本语言,主要用于在网页上实现交互功能。它具有以下特点: 动态性:JavaScript是一种动态类型的语言,变量的类型在运行时可以自动推断。 客户端脚本语言:JavaScript主要在浏览器中执行,用于增强用户界面的交互性。 事件驱动:JavaScript通过事件机制响应用户的操作,并进行相应处理。 JavaScript的主要优点有: 前端开发:JavaScript是前端开发的核心语言,用于构建交互性的网页应用,丰富用户体验。 灵活性:JavaScript具有灵活性,可以方便地修改和调试,适合快速迭代开发。 强大的库支持:JavaScript拥有众多的开源库和框架,如React、Vue.js等,可以提高开发效率。 然而,JavaScript也有一些缺点: 兼容性问题:不同浏览器对JavaScript的支持并不完全一致,需要注意兼容性问题。 安全性:由于JavaScript运行在浏览器端,存在一些安全性的考虑,需要注意防止恶意代码注入。 JavaScript适合用于: 网页交互:JavaScript用于网页中的表单验证、用户行为追踪等交互功能的实现。 前端框架:JavaScript的框架和库如React、Angular、Vue.js等用于构建现代化的前端应用。 后端开发:通过Node.js,JavaScript也可用于后端开发,构建高性能、可扩展的服务器应用。 典型的开源软件和框架: React:一个流行的JavaScript库,用于构建用户界面。 Vue.js:一个轻量级、易用的JavaScript框架,适用于构建交互式Web界面。 Node.js:一个基于Chrome V8引擎的JavaScript运行环境,用于构建高性能的服务器端应用。 JavaScript拥有一个非常活跃的社区,开发者可以在GitHub上找到许多优秀的开源项目,也可以通过在线文档和社区论坛获取帮助和交流经验。 4. C++ C++是一种通用的、编译型的、静态类型的编程语言。它具有以下特点: 高效性:C++是一种性能卓越的语言,可以直接操作硬件,提供了更高的运行效率。 面向对象:C++支持面向对象编程,具有封装、继承、多态等特性。 强大的库支持:C++有丰富的标准库和第三方库,利于程序员开发高效的应用。 C++的主要优点有: 高效性:C++具备高效的运行速度和低内存消耗,适用于开发对性能要求高的应用,如游戏、图形、嵌入式系统等。 与C语言兼容:C++源代码可以与C语言混合编译,方便现有C代码的重用。 强大的控制能力:C++提供了底层的内存控制和强大的指针操作能力,使得程序员可以更精细地控制程序的执行。 然而,C++也有一些缺点: 语法复杂:C++的语法相对复杂,对初学者来说学习难度较大。 内存管理:C++需要手动管理内存,容易出现内存泄漏和指针悬挂等问题。 C++适合用于: 系统和游戏开发:C++的高效性使得它成为系统级程序和游戏开发的首选语言。 性能关键的应用:C++适用于需要高性能和低延迟的领域,如金融、科学计算等。 底层开发:C++的底层控制能力使其适合开发驱动程序和嵌入式系统。 典型的开源软件和框架: Boost:一个功能强大且广泛使用的C++库集合,提供了许多工具和组件,可帮助开发者提高开发效率。 Qt:一个跨平台的C++应用程序开发框架,用于构建图形用户界面和嵌入式应用。 C++拥有庞大的开发者社区和活跃的社区资源,不仅有众多的在线文档、教程和论坛,还有许多优秀的开源项目可以供开发者参考和学习。 5. C# C#(读作C-Sharp)是一种通用的、编译型的、面向对象的编程语言。它具有以下特点: 与.NET紧密集成:C#是.NET平台的核心语言,与.NET框架紧密集成,使得开发过程更加高效。 简单易学:C#的语法类似于Java和C++,易于理解和上手。 跨平台:C#不仅可以在Windows上运行,还支持跨平台开发,如使用.NET Core可在Linux、macOS等上运行。 C#的主要优点有: 简单易学:C#的语法简洁,类似于其他主流语言,使得开发人员能够快速上手。 强大的.NET生态系统:C#在.NET平台上拥有丰富的类库和框架,提供了大量的功能和工具,方便开发人员进行应用开发。 面向对象:C#支持面向对象编程,提供了封装、继承、多态等特性,可以更好地组织和管理代码。 然而,C#也有一些缺点: Windows依赖:C#最初是为Windows开发的,虽然现在也支持跨平台开发,但在一些特定领域内的使用可能存在限制。 生态系统相对局限:与一些其他编程语言相比,C#的开源库和框架相对较少,选择范围相对较小。 C#适合用于: Windows应用开发:C#具有与Windows紧密集成的特点,适合用于开发Windows应用程序和游戏。 Web开发:通过ASP.NET,C#也可以用于Web开发,构建可靠且高性能的Web应用。 Unity游戏开发:C#是Unity游戏引擎的主要脚本语言,用于开发跨平台的游戏。 典型的开源软件和框架: ASP.NET:一个用于构建Web应用的框架,具有强大的性能和安全性。 Entity Framework:一个面向对象的数据库访问框架,简化了与数据库的交互。 C#拥有活跃的社区和大量的学习资源,开发者可以通过微软官方文档、在线教程和社区论坛等途径获取帮助和交流经验。 6. PHP PHP(Hypertext Preprocessor)是一种通用的脚本语言,主要用于服务器端编程。它具有以下特点: 强大的Web开发能力:PHP最初设计用于处理动态网页,因此在Web开发方面具备强大的能力。 面向对象:PHP支持面向对象编程,具有类、继承、封装等特性。 容易入门:PHP的语法类似于C语言,相对易于学习和上手。 PHP的主要优点有: 广泛应用:PHP被广泛用于Web开发,特别是动态网页的开发,如CMS、电子商务网站等。 快速开发:PHP提供了许多内置函数和扩展,使开发人员能够快速构建功能丰富的网站和应用。 跨平台:PHP可以运行在主流的操作系统上,如Windows、macOS、Linux等。 然而,PHP也有一些缺点: 性能相对较低:相比一些编译型语言,PHP的性能较低,尤其对于大规模并发和高负载的场景。 代码可维护性差:PHP在语法灵活性上强调了开发速度,但也容易导致代码可读性和可维护性的问题。 PHP适合用于: Web开发:PHP是一种强大的Web开发语言,用于构建各种类型的网站、应用和系统。 动态网页:通过与HTML混编,PHP可以实现动态网页的生成和内容交互。 数据库操作:PHP提供了丰富的数据库操作支持,如MySQL、SQLite等。 典型的开源软件和框架: WordPress:一个流行的开源CMS(内容管理系统),采用PHP开发。 Laravel:一个功能强大且易于使用的PHP框架,用于构建高效的Web应用程序。 Symfony:一个用于构建复杂Web应用的PHP框架,提供了大量的组件和工具。 PHP有一个庞大的开发者社区,有许多在线文档、教程和社区论坛可以供开发者学习和交流。 7. Swift 特点 高性能:Swift在编译时进行优化,生成高效的本机代码,因此具有出色的性能。 安全性:Swift引入了许多安全机制,如类型检查、内存安全和错误处理,可以帮助开发者避免一些常见的编程错误和安全漏洞。 现代化语言特性:Swift支持诸如类型推断、闭包、泛型等现代化语言特性,使开发者能够更加高效地编写代码。 优点 易学易用:Swift的语法简洁易懂,类似于英语,使得入门门槛较低。 强大的开发工具:Xcode是一款功能强大的集成开发环境,提供了许多有用的工具和调试功能,可以极大地提高开发效率。 多平台支持:Swift可以编写 iOS、macOS、watchOS和tvOS等平台上的应用程序,方便开发者进行跨平台开发。 缺点: 相对较新:Swift相比其他语言来说相对较新,因此社区和生态系统相对较小。 代码兼容性:由于Swift语言不断演进,代码迁移可能会带来一些兼容性问题。 适用场景: iOS开发:Swift是开发iOS应用程序的首选语言,具有强大的开发工具和丰富的iOS生态系统。 macOS开发:Swift也可以用于开发macOS应用程序,享受到其语法简洁和高效性能的优势。 典型的开源软件或框架: Alamofire:一款非常受欢迎的Swift网络请求框架,提供了简单易用的API,方便进行网络数据交互。 SwiftUI:一个现代化的用户界面框架,用于构建iOS和macOS应用程序,提供了声明式语法和直观的可视化工具。 Swift具有一个活跃的社区,有许多在线论坛、博客和代码库,为开发者提供了丰富的资源和交流机会。开发者可以从中获取帮助、分享经验和学习最新的Swift技术。除此之外,苹果公司也在不断推动Swift的发展,发布了大量的教程和文档,致力于提供最佳的开发体验和支持。 8. Go 特点: 并发性:Go语言具有原生支持并发的特性,通过goroutine和通道机制,可以更轻松地实现并发编程。 高效性:Go语言的编译速度非常快,同时也具有高效的执行性能,适合用于构建高性能的分布式系统。 简洁性:Go语言的语法简洁明了,强调可读性和简单性,对于快速开发和维护代码非常便捷。 优点: 并发编程:通过goroutine和通道机制,Go语言可以轻松实现高并发的并行任务,处理大规模的并发问题非常高效。 内置工具支持:Go语言带有丰富的标准库和内置工具,例如测试框架、性能分析工具等,方便开发者进行开发、测试和性能优化。 跨平台:Go语言可以在多个平台上进行编译,适用于开发跨平台的应用程序。 缺点: 代码冗长:相比起其他语言,Go语言的代码可能会显得冗长,一些简单的功能可能需要较多的代码行数来实现。 生态系统相对较小:虽然Go的生态系统正在不断发展壮大,但与其他一些编程语言相比,它的生态系统相对较小一些。 适用场景: 分布式系统:Go的高效性和并发性特点使其非常适合用于构建分布式系统,如微服务架构。 网络编程:Go语言设计用于处理网络通信,通过其原生的并发和协程机制,可以轻松实现高性能的网络应用程序。 典型的开源软件或框架: Gin:一款轻量级且高性能的Web框架,用于构建RESTful API。 Docker:一个开源的容器化平台,使用Go语言开发,广泛用于部署和管理容器。 Kubernetes:一种用于自动化部署、扩展和管理容器化应用程序的开源平台,也是用Go语言开发。 Go语言拥有一个活跃的社区,吸引了许多开发者和公司的关注,提供了丰富的资源和交流机会。开发者可以从社区获得教程、文档、示例代码等,同时也可以积极参与社区的讨论和贡献。 在选择编程语言时,关键是要考虑你的目标和项目需求。 不同的语言在不同的应用场景下有其优势和限制。 因此,建议你根据自己的兴趣和需求进行选择,并相应地学习和提升。 无论你选择哪种编程语言,持续学习和实践都是成为一名优秀开发者的关键。 ...

    2023-11-03 值得一看 46
  • 红黑树的原理和应用场景

    红黑树(Red Black Tree)是一种平衡的排序二叉树,如图: 所有的红黑树都满足如下性质: 每个节点要么是红色,要么是黑色的; 根节点和叶子节点(即 NIL 空节点)一定是黑色; 红色节点的父节点,或者子节点一定为黑色; 对每个节点,从该节点到叶子节点的所有路径上,包含的黑节点数目相同。 根据性质4,我们可以得出:从根节点到叶子节点的可能路径,最长不超过最短路径的两倍。 红黑树的主要应用场景: java8 hashmap 中链表转红黑树优势:时间复杂度从O(n) –> O(logn),且自旋开销较其他树较低(不用整体平衡)。 epoll 在内核中的实现,用红黑树管理 fd 文件描述符 优势: 因为内核态需要维护一个长久存放 fd 的数据结构,而 fd 的变动十分频繁,且需要支持快速查询,所以红黑树很适合 红黑树可以判断是否是重复的 fd 3.Linux 进程调度 Completely Fair Scheduler,用红黑树管理进程控制块;nginx 中,用红黑树管理 timer 等 。 ...

    2023-11-03 值得一看 50

联系我们

在线咨询:点击这里给我发消息

QQ交流群:KirinBlog

工作日:8:00-23:00,节假日休息

扫码关注