Kun

Kun

IT学徒、技术民工、斜杠青年,机器人爱好者、摄影爱好 PS、PR、LR、达芬奇潜在学习者


共 279 篇文章


  数据库有关的知识,学习后端必备。

MySQL

MVCC

MVCC在MySQL InnoDB中的实现主要是为了提高数据库并发性能,用更好的方式去处理读-写冲突,做到即使有读写冲突时,也能做到不加锁,非阻塞并发读

  • 当前读

像select lock in share mode(共享锁), select for update ; update, insert ,delete(排他锁)这些操作都是一种当前读,为什么叫当前读?就是它读取的是记录的最新版本,读取时还要保证其他并发事务不能修改当前记录,会对读取的记录进行加锁

  • 快照读

像不加锁的select操作就是快照读,即不加锁的非阻塞读;快照读的前提是隔离级别不是串行级别,串行级别下的快照读会退化成当前读;之所以出现快照读的情况,是基于提高并发性能的考虑,快照读的实现是基于多版本并发控制,即MVCC,可以认为MVCC是行锁的一个变种,但它在很多情况下,避免了加锁操作,降低了开销;既然是基于多版本,即快照读可能读到的并不一定是数据的最新版本,而有可能是之前的历史版本

  • 准确的说,MVCC多版本并发控制指的是 “维持一个数据的多个版本,使得读写操作没有冲突” 这么一个概念。仅仅是一个理想概念
  • 而在MySQL中,实现这么一个MVCC理想概念,我们就需要MySQL提供具体的功能去实现它,而快照读就是MySQL为我们实现MVCC理想模型的其中一个具体非阻塞读功能。而相对而言,当前读就是悲观锁的具体功能实现
  • 要说的再细致一些,快照读本身也是一个抽象概念,再深入研究。MVCC模型在MySQL中的具体实现则是由 4个隐式字段undo日志Read View 等去完成的,具体可以看下面的MVCC实现原理

有三种, 分别为:

  • 读-读:不存在任何问题,也不需要并发控制
  • 读-写:有线程安全问题,可能会造成事务隔离性问题,可能遇到脏读,幻读,不可重复读
  • 写-写:有线程安全问题,可能会存在更新丢失问题,比如第一类更新丢失,第二类更新丢失

多版本并发控制(MVCC)是一种用来解决读-写冲突的无锁并发控制,也就是为事务分配单向增长的时间戳,为每个修改保存一个版本,版本与事务时间戳关联,读操作只读该事务开始前的数据库的快照。 所以MVCC可以为数据库解决以下问题

在并发读写数据库时,可以做到在读操作时不用阻塞写操作,写操作也不用阻塞读操作,提高了数据库并发读写的性能 同时还可以解决脏读,幻读,不可重复读等事务隔离问题,但不能解决更新丢失问题

总之,MVCC就是因为大牛们,不满意只让数据库采用悲观锁这样性能不佳的形式去解决读-写冲突问题,而提出的解决方案,所以在数据库中,因为有了MVCC,所以我们可以形成两个组合:

  • MVCC + 悲观锁 MVCC解决读写冲突,悲观锁解决写写冲突
  • MVCC + 乐观锁 MVCC解决读写冲突,乐观锁解决写写冲突

这种组合的方式就可以最大程度的提高数据库并发性能,并解决读写冲突,和写写冲突导致的问题

每行记录除了我们自定义的字段外,还有数据库隐式定义的DBTRXID,DBROLLPTR,DBROWID等字段

  • DBROWID 6byte, 隐含的自增ID(隐藏主键),如果数据表没有主键,InnoDB会自动以DBROWID产生一个聚簇索引
  • DBTRXID 6byte, 最近修改(修改/插入)事务ID:记录创建这条记录/最后一次修改该记录的事务ID
  • DBROLLPTR 7byte, 回滚指针,指向这条记录的上一个版本(存储于rollback segment里)
  • DELETED_BIT 1byte, 记录被更新或删除并不代表真的删除,而是删除flag变了

https://pdai.tech/md/db/sql-mysql/sql-mysql-mvcc.html

主从同步

随着用户和数据的增多,单机的数据库往往支撑不住快速发展的业务,所以数据库集群就产生了

读写分离顾名思义就是读和写分离,对应到数据库集群一般都是一主一从(一个主库,一个从库)或者一主多从(一个主库,多个从库),业务服务器把需要写的操作都写到主数据库中,读的操作都去从库查询。主库会同步数据到从库保证数据的一致性。

这种集群方式的本质是把访问的压力从主库转移到从库**,**也就是在单机数据库无法支撑并发读写,并且读的请求很多的情况下适合这种读写分离的数据库集群。如果写的操作很多的话不适合这种集群方式,因为你的数据库压力还是在写操作上,即使主从了之后压力还是在主库上,这样和单机的区别就不大了。

在单机的情况下,一般我们做数据库优化都会加索引,但是加了索引对查询有优化,但会影响写入,因为写入数据会更新索引。所以做了主从之后,我们可以单独地针对从库(读库)做索引上的优化,而主库(写库)可以减少索引而提高写的效率。

初始状态时,master 和 slave 的数据要保持一致。

  1. master 提交完事务后,写入 binlog。
  2. slave 连接到 master,获取 binlog。
  3. master创建 dump 线程,推送 binlog 到 slave。
  4. slave 启动一个 I/O 线程读取同步过来的 master 的 binlog,记录到 relay log(中继日志)中。
  5. slave 再开启一个 SQL 线程从 relay log 中读取内容并在 slave 执行(从 ExecMasterLog_Pos 位置开始执行读取到的更新事件),完成同步。
  6. slave 记录自己的 binlog。

由于 MySQL 默认的复制方式是异步的,主库把日志发送给从库后不关心从库是否已经处理。这样会产生一个问题,假设主库挂了,从库处理失败了,这时从库升为主库后,日志就丢失了。由此产生以下两个概念

全同步复制

主库写入 binlog 后,强制同步日志到从库,等所有的从库都执行完成后,才返回结果给客户端,显然这个方式的性能会受到严重影响。

半同步复制

从库写入日志成功后返回 ACK(确认)给主库,主库收到至少一个从库的确认就可以认为写操作完成,返回结果给客户端。

主从同步延迟

主库有数据写入之后,同时也写入在 binlog(二进制日志文件)中,从库是通过 binlog 文件来同步数据的,这期间会有一定时间的延迟,可能是 1 秒,如果同时有大量数据写入的话,时间可能更长。

这会导致什么问题呢?比如有一个付款操作,你付款了,主库是已经写入数据,但是查询是到从库查,从库里还没有你的付款记录,所以页面上查询的时候你还没付款。那可不急眼了啊,吞钱了这还了得!打电话给客服投诉!

所以为了解决主从同步延迟的问题有以下几个方法:

1)二次读取

二次读取的意思就是读从库没读到之后再去主库读一下,只要通过对数据库访问的 API 进行封装就能实现这个功能。很简单,并且和业务之间没有耦合。但是有个问题,如果有很多二次读取相当于压力还是回到了主库身上,等于读写分离白分了。而且如有人恶意攻击,就一直访问没有的数据,那主库就可能爆了。

2)写之后的马上的读操作访问主库

也就是写操作之后,立马的读操作指定为访问主库,之后的读操作则访问从库。这就等于写死了,和业务强耦合了。

3)关键业务读写都由主库承担,非关键业务读写分离

类似付钱的这种业务,读写都到主库,避免延迟的问题,但是例如改个头像啊,个人签名这种比较不重要的就读写分离,查询都去从库查,毕竟延迟一下影响也不大,不会立马打客服电话投诉。

分配机制

分配机制的考虑也就是怎么制定写操作是去主库写,读操作是去从库读。

一般有两种方式:代码封装、数据库中间件。

代码封装

代码封装的实现很简单,就是抽出一个中间层,让这个中间层来实现读写分离和数据库连接。讲白点就是搞个 provider 封装了 save、select 等通常数据库操作,内部 save 操作的 dataSource 是主库的,select 操作的 dataSource 是从库的。

优点:

  1. 实现简单。
  2. 可以根据业务定制化变化,随心所欲。

缺点:

  1. 如果哪个数据库宕机了,发生主从切换了之后,就得修改配置重启。
  2. 如果系统很大,一个业务可能包含多个子系统,一个子系统是 java 写的,一个子系统用 go 写的,这样的话得分别为不同语言实现一套中间层,重复开发。

数据库中间件

就是有一个独立的系统,专门来实现读写分离和数据库连接管理,业务服务器和数据库中间件之间是通过标准的 SQL 协议交流的,所以在业务服务器看来数据库中间件其实就是个数据库。

优点:

  1. 因为是通过 SQL 协议的所以可以兼容不同的语言不需要单独写一套。
  2. 由中间件来实现主从切换,业务服务器不需要关心这点。

缺点:

  1. 多了一个系统其实就等于多了一个关心,比如数据库中间件挂了。
  2. 多了一个系统就等于多了一个瓶颈,所以对中间件的性能要求也高,因为所有的数据库操作都要先经过它。
  3. 中间件实现较为复杂,难度比代码封装高多了。

常用的开源数据库中间件有 Mysql Proxy、Atlas、LVS 等。

为什么使用 MySQL-Proxy 而不是 LVS?

  • LVS:分不清读还是写;不支持事务。
  • MySQL-Proxy:自动区分读操作和写操作;支持事务(注意在 MySQL-Proxy 中不要使用嵌套查询,否则会造成读和写的混乱)。

解决单点故障

MySQL-Proxy 实际上非常不稳定,在高并发或有错误连接的情况下,进程很容易自动关闭,因此打开 --keepalive 参数让进程自动恢复是个比较好的办法,但还是不能从根本上解决问题,通常最稳妥的做法是在每个应用服务器(如 Tomcat)上安装一个 MySQL-Proxy 供自身使用(解决 Proxy 单点故障问题),虽然比较低效但却能保证稳定性。

Proxy 之后搭 LVS,LVS 为两台主数据库做负载均衡,从数据库从两台主数据库同步。此方案旨在解决:

  • 主数据库的单点故障问题(服务不可用、备份问题)
  • 分担写操作的访问压力。

不过多主需要考虑自增长 ID 问题,这个需要特别设置配置文件,比如双主可以使用奇偶。总之,主之间设置自增长 ID 相互不冲突就能解决自增长 ID 冲突问题。

主从同步的方式也分很多种,一主多从、链式主从、多主多从,根据你的需要来进行设置。

方式

一主多从,提高系统的读性能

一主一从和一主多从是最常见的主从架构,实施起来简单并且有效,不仅可以实现HA,而且还能读写分离,进而提升集群的并发能力。

多主一从可以将多个mysql数据库备份到一台存储性能比较好的服务器上。

双主复制,也就是互做主从复制,每个master既是master,又是另外一台服务器的slave。这样任何一方所做的变更,都会通过复制应用到另外一方的数据库中。

级联复制模式下,部分slave的数据同步不连接主节点,而是连接从节点。因为如果主节点有太多的从节点,就会损耗一部分性能用于replication,那么我们可以让3~5个从节点连接主节点,其它从节点作为二级或者三级与从节点连接,这样不仅可以缓解主节点的压力,并且对数据一致性没有负面影响。

备份

mysqldump是MySQL数据库自带的一个很好用的备份命令。是逻辑备份,导出 的是SQL语句。也就是把数据从MySQL库中以逻辑的SQL语句的形式直接输出或生成备份的文件的过程

# 备份
mysqldump -uroot -p‘123456’ mytest > /mnt/mytest_bak_$(date +%F).sql

# 恢复操作
# 删除student表(库必须要保留,空库都行)
mysql -uroot -p'123456' -e "use mytest;drop table student;"
# 恢复数据
mysql -uroot -p'123456' mytest < /mnt/mytest_bak.sql 
# 查看数据
mysql -uroot -p'123456' -e "select * from mytest.student;"

Xtrabackup

MySQL冷备、mysqldump、MySQL热拷贝都无法实现对数据库进行增量备份。在实际生产环境中增量备份是非常实用的,如果数据大于50G或100G,存储空间足够的情况下,可以每天进行完整备份,如果每天产生的数据量较大,需要定制数据备份策略。例如每周实用完整备份,周一到周六实用增量备份。而Percona-Xtrabackup就是为了实现增量备份而出现的一款主流备份工具,xtrabakackup有2个工具,分别是xtrabakup、innobakupe。

Percona-xtrabackup是 Percona公司开发的一个用于MySQL数据库物理热备的备份工具,支持MySQL、Percona server和MariaDB,开源免费,是目前较为受欢迎的主流备份工具。xtrabackup只能备份innoDB和xtraDB两种数据引擎的表,而不能备份MyISAM数据表。

优点:

(1)备份速度快,物理备份可靠

(2)备份过程不会打断正在执行的事务(无需锁表)

(3)能够基于压缩等功能节约磁盘空间和流量

(4)自动备份校验

(5)还原速度快

(6)可以流传将备份传输到另外一台机器上

(7)在不增加服务器负载的情况备份数据

归档

随着业务快速增长,MySQL 数据量不断增加,会带来如下两个问题:

  1. 磁盘空间吃紧:数据库数据最终将会保存在本地磁盘中,数据记录越多,磁盘占用空间就会越多,对应剩余可用空间就会越少。
  2. 查询效率降低:MySQL 的 InnoDB 存储引擎的存储结构是 B+ 树,查找的时间复杂度是 O(log n)。随着数据量的增大,B+ 树自然也会变的很大,查找效率也会随之下降。

所以,解决海量数据导致存储系统慢的问题,一般思路就是进行数据拆分,即分片。拆开之后,每个分片里的数据就没那么多了,然后让查找尽量落在某一个分片上,这样来提升查找性能。

当单表的数据太多,多到影响性能的时候,首选的方案是:归档历史数据

数据归档的解决思路非常简单,就是将生产库的数据转移到拥有相同表结构的数据库中,通过减少生产库记录数量,从而提高数据查询等操作的效率。

数据归档分为三个流程:

  • 创建一个新的数据库作为归档库,然后在归档库创建与生产库相同的表;
  • 不断查询生产库数据记录,同步复制到归档库;
  • 生产库删除已经复制的数据记录;

数据归档需要考虑的问题:

  1. 确定需要归档的数据范围;
  2. 确定归档的执行方案:使用工具归档(pt-archiver)、自定义程序进行归档;
  3. 确定数据归档后带来的问题的预案;

归档需要考虑的问题

1. 生产库备份 在进行数据归档之前,一定要确保生产库的数据进行了备份。如果在归档过程中出现一些意想不到的问题,可以使用备份数据进行还原。

2. 何时进行归档 数据归档过程需要不断的读写生产库,这个过程将会大量使用的网络、IO。为了防止对线上业务造成压力,数据归档一般只在业务低峰期执行。另外,我们需要尽可能调优数据,尽量降低对线上业务的影响。

3. 删除已复制数据 数据归档之后,将会删除生产库的数据,这些数据删除之后,将会造成数据空洞。即数据删除之后,表空间并未及时的释放,当长时间没有新的数据填充,会造成空间浪费的情况。所以数据删除之后,需要及时优化数据空洞,释放这些被浪费的空间。

4. 历史数据还原 数据归档之后,生产库就会缺失这部分数据,如果业务上正好需要使用这些数据,那就会造成业务上异常。所以,我们需要提供数据逆向接口,反向将归档数据库的记录重新还原到生产库。

5. 数据一致性问题 如果在进行数据归档的过程中,生产库中已复制的数据存在更新操作,那么会造成归档库与生产库的数据出现不一致的情况。所以,在进行数据归档时,需要保证历史数据没有更新操作。

还有一个很重要的细节问题:如何从原表中删除已经迁走的历史数据?直接执行一个删除历史数据的 SQL 行不行?比如:

DELETE FROM orders WHERE createTime < SUBDATE(CURDATE(),INTERVAL 3 month);

这样肯定是不行,如果删除的数据量比较大,会造成 SQL 语句占用时间长,锁的时间也比较长(即大事务),影响数据库性能; 而正确的方式是进行多次分批删除,并且最好在每次删除之间停顿一会儿,避免给数据库造成太大的压力。

DELETE FROM orders WHERE createTime < SUBDATE(CURDATE(),INTERVAL 3 month) ORDER BY id LIMIT 1000;

由于会对原表已归档的数据进行删除,会造成数据空洞,也就是表碎片。所以需要定期对表碎片进行清理,即重建表,以释放磁盘空间。

我们可以使用 alter table A engine=InnoDB 命令来重建表。重建表的过程中,索引也会重建,这样表数据和索引数据都会更紧凑,不仅占用磁盘空间更小,查询效率也会有提升。在 MySQL 8.0.26 或 8.0.29 这些高版本的数据库,执行此命令时,加锁时间很短,基本不会阻塞增删改操作

pt-archiver

pt-archiver是Percona-Toolkit工具集中的一个组件,可以用于对MySQL表数据进行归档和清除。它可以实现将数据归档到另一张表或者是一个文件中,在清除表数据的过程中并不会影响OLTP事务的查询性能,可以细粒度的控制每次迁移事务的大小,同时免去编写应用程序进行数据迁移的麻烦。

https://developer.aliyun.com/article/859219

存储引擎

https://www.biaodianfu.com/tokudb.html

在 MySQL 最流行的支持全事务的引擎为 INNODB。其特点是数据本身是用 B-TREE 来组织,数据本身即是庞大的根据主键聚簇的 B-TREE 索引。所以在这点上,写入速度就会有些降低,因为要每次写入要用一次 IO 来做索引树的重排。特别是当数据量本身比内存大很多的情况下,CPU 本身被磁盘 IO 纠缠的做不了其他事情了。这时我们要考虑如何减少对磁盘的 IO 来排解 CPU 的处境,常见的方法有:

  • 把 INNODB 个 PAGE 增大(默认 16KB),但增大也就带来了一些缺陷。比如,对磁盘进行 CHECKPOINT 的时间将延后。
  • 把日志文件放到更快速的磁盘上,比如 SSD。

TokuDB 是一个支持事务的“新”引擎,有着出色的数据压缩功能,由美国 TokuTek 公司(现在已经被Percona 公司收购)研发。拥有出色的数据压缩功能,如果您的数据写多读少,而且数据量比较大,强烈建议您使用 TokuDB,以节省空间成本,并大幅度降低存储使用量和 IOPS 开销,不过相应的会增加 CPU 的压力。

tokuDB的特性

1.丰富的索引类型以及索引的快速创建

TokuDB 除了支持现有的索引类型外,还增加了(第二)集合索引,以满足多样性的覆盖索引的查询,在快速创建索引方面提高了查询的效率2.(**第二)集合索引**

也可以称作非主键的集合索引,这类索引也包含了表中的所有列,可以用于覆盖索引的查询需要,比如以下示例,在 where 条件中直接命中 index_b 索引,避免了从主键中再查找一次。

3.索引在线创建(Hot Index Creation)

TokuDB 允许直接给表增加索引而不影响更新语句(insert,update 等)的执行。可以通过变量 tokudbcreateindex_online 来控制是否开启该特性,不过遗憾的是目前还只能通过 CREATE INDEX 语法实现在线创建,不能通过 ALTER TABLE 实现.这种方式比通常的创建方式慢了许多,创建的过程可以通过 show processlist 查看。不过 tokudb 不支持在线删除索引,删除索引的时候会对标加全局锁。

4.在线更改列(Add, Delete, Expand, Rename)

TokuDB 可以在轻微阻塞更新或查询语句的情况下,允许实现以下操作:

  • 增加或删除表中的列
  • 扩充字段:char, varchar, varbinary 和 int 类型的列
  • 重命名列,不支持字段类型:TIME, ENUM, BLOB, TINYBLOB, MEDIUMBLOB, LONGBLOB

这些操作通常是以表锁级别阻塞(几秒钟时间)其他查询的执行,当表记录下次从磁盘加载到内存的时候,系统就会随之对记录进行修改操作(add,delete 或 expand),如果是 rename 操作,则会在几秒钟的停机时间内完成所有操作。

TokuDB 的这些操作不同于 InnoDB,对表进行更新后可以看到 rows affected 为 0,即更改操作会放到后台执行,比较快速的原因可能是由于 Fractal-tree 索引的特性,将随机的 IO 操作替换为顺序 IO 操作,Fractal-tree 的特性中,会将这些操作广播到所有行,不像 InnoDB,需要 open table 并创建临时表来完成.

5.数据压缩

TokuDB 中所有的压缩操作都在后台执行,高级别的压缩会降低系统的性能,有些场景下会需要高级别的压缩.按照官方的建议:6 核数以下的机器建议标准压缩,反之可以使用高级别的压缩。

6.Read free**复制特性**

得益于 FracalTree 索引的特性,TokuDB 的 slave 端能够以低于读 IO 的消耗来应用 master 端的变化,其主要依赖 FractalTree 索引的特性,可以在配置里启用特性

  • insert/delete/update 操作部分可以直接插入到合适的 FractalTree 索引中,避免 read-modify-write 行为的开销;
  • delete/update 操作可以忽略唯一性检查带来的 IO 方面的开销

不好的是, 如果启用了 Read Free Replication 功能, Server 端需要做如下设置:

  • master:复制格式必须为 ROW,因为 tokudb 还没有实现对 auto-increment 函数进行加锁处理, 所以多个并发的插入语句可能会引起不确定的 auto-increment 值, 由此造成主从两边的数据不一致.
  • slave:开启 read-only; 关闭唯一性检查(set tokudbrpluniquechecks=0); 关闭查找(read-modify-write) 功能(set tokudbrpllookuprows=0);

TokuDB 的优点:

  • 高压缩比,默认使用 zlib 进行压缩,尤其是对字符串(varchar,text 等) 类型有非常高的压缩比,比较适合存储日志、原始数据等。官方宣称可以达到 1:12。
  • 在线添加索引,不影响读写操作
  • HCADER 特性,支持在线字段增加、删除、扩展、重命名操作,(瞬间或秒级完成)
  • 支持完整的 ACID 特性和事务机制
  • 非常快的写入性能,Fractal-tree 在事务实现上有优势, 无 undo log,官方称至少比 innodb 高 9 倍。
  • 支持 show processlist 进度查看
  • 数据量可以扩展到几个 TB;
  • 不会产生索引碎片;
  • 支持 hot column addition, hot indexing, mvcc

TokuDB 缺点:

  • 不支持外键(foreign key) 功能,如果您的表有外键,切换到 TokuDB 引擎后,此约束将被忽略。
  • TokuDB 不适大量读取的场景,因为压缩解压缩的原因。CPU 占用会高 2-3 倍,但由于压缩后空间小,IO 开销低,平均响应时间大概是 2 倍左右。
  • online ddl 对 text,blob 等类型的字段不适用
  • 没有完善的热备工具,只能通过 mysqldump 进行逻辑备份

适用场景:

  • 访问频率不高的数据或历史数据归档
  • 数据表非常大并且时不时还需要进行 DDL 操作

分形树

TokuDB 和 InnoDB 最大的不同在于 TokuDB 采用了一种叫做 Fractal Tree 的索引结构,使其在随机写数据的处理上有很大提升。目前无论是 SQL Server,还是 MySQL 的 innodb,都是用的 B+Tree(SQL Server 用的是标准的 B-Tree)的索引结构。InnoDB 是以主键组织的 B+Tree 结构,数据按照主键顺序排列。对于顺序的自增主键有很好的性能,但是不适合随机写入,大量的随机 I/O 会使数据页分裂产生碎片,索引维护开销很多大。TokuDB 解决随机写入的问题得益于其索引结构,Fractal Tree 和 B-Tree 的差别主要在于索引树的内部节点上,B-Tree 索引的内部结构只有指向父节点和子节点的指针,而 Fractal Tree 的内部节点不仅有指向父节点和子节点的指针,还有一块 Buffer 区。当数据写入时会先落到这个 Buffer 区上,该区是一个 FIFO 结构,写是一个顺序的过程,和其他缓冲区一样,满了就一次性刷写数据。所以 TokuDB 上插入数据基本上变成了一个顺序添加的过程。

灰色区域表示ft-index分形树的一个页,绿色区域表示一个键值,两格绿色区域之间表示一个儿子指针。BlockNum表示儿子指针指向的页的偏移量。Fanout表示分形树的扇出,也就是儿子指针的个数。NodeSize表示一个页占用的字节数。NonLeafNode表示当前页是一个非叶子节点,LeafNode表示当前页是一个叶子节点,叶子节点是最底层的存放Key-value键值对的节点,非叶子节点不存放value。Heigth表示树的高度,根节点的高度为3,根节点下一层节点的高度为2,最底层叶子节点的高度为1。Depth表示树的深度,根节点的深度为0,根节点的下一层节点深度为1。

分形树的树形结构非常类似于B+树, 它的树形结构由若干个节点组成(我们称之为Node或者Block,在InnoDB中,我们称之为Page或者页)。每个节点由一组有序的键值组成。假设一个节点的键值序列为[3,8], 那么这个键值将(-00,+00)整个区间划分为(-00,3), [3,8), [8,+00)这样3个区间,每一个区间就对应着一个儿子指针(Child指针)。在B+树中,Child指针一般指向一个页,而在分形树中,每一个Child指针除了需要指向一个Node的地址(BlockNum)之外,还会带有一个MessageBuffer (msg_buffer),这个MessageBuffer是一个先进先出(FIFO)的队列,用来存放Insert/Delete/Update/HotSchemaChange这样的更新操作。

RocksDB

RocksDB是由 Facebook 基于 LevelDB 开发的一款提供键值存储与读写功能的 LSM-tree 架构引擎。用户写入的键值对会先写入磁盘上的 WAL (Write Ahead Log),然后再写入内存中的跳表(SkipList,这部分结构又被称作 MemTable)。LSM-tree 引擎由于将用户的随机修改(插入)转化为了对 WAL 文件的顺序写,因此具有比 B 树类存储引擎更高的写吞吐。内存中的数据达到一定阈值后,会刷到磁盘上生成 SST 文件 (Sorted String Table),SST 又分为多层(默认至多 6 层),每一层的数据达到一定阈值后会挑选一部分 SST 合并到下一层,每一层的数据是上一层的 10 倍(因此 90% 的数据存储在最后一层)。RocksDB 允许用户创建多个 ColumnFamily ,这些 ColumnFamily 各自拥有独立的内存跳表以及 SST 文件,但是共享同一个 WAL 文件,这样的好处是可以根据应用特点为不同的 ColumnFamily 选择不同的配置,但是又没有增加对 WAL 的写次数。

优点

  • innodb空间浪费, B tree分裂导致page内有较多空闲,page利用率不高。innodb现有的压缩效率也不高,压缩以block为单位,也会造成浪费。
  • 写入放大:innodb 更新以页为单位,最坏的情况更新N行会更新N个页。RocksDB append only方式 另外,innodb开启double write也会增加写入。
  • RocksDB对齐开销小:SST file (默认2MB)需要对齐,但远大于4k, RocksDBblocksize(默认4k) 不需要对齐,因此对齐浪费空间较少
  • RocksDB索引前缀相同值压缩存储,节省空间
  • RocksDB占总数据量90%的最底层数据,行内不需要存储系统列seqid (innodb聚簇索引列包含trxid,roll_ptr等信息)

缺点

  • 大value的场景不友好
  • 不适于大规模数据的存取

适用场景

  • 对写性能要求很高,同时有较大内存来缓存SST块以提供快速读的场景;
  • SSD等对写放大比较敏感以及磁盘等对随机写比较敏感的场景;
  • 需要变长kv存储的场景;
  • 小规模元数据的存取;

Oracel

pgbouncer

数据库连接是一个很关键的有限的昂贵的资源,也容易对数据库造成安全隐患。因此,在程序初始化时,预先创建一定数量的数据库连接,并对其进行集中管理,就构成了数据库连接池,由程序动态地对池中的连接进行申请、使用和释放,既保证了较快的数据库读写速度,又提高了安全可靠性。

数据库连接池

  • 从连接池获取/创建可用连接
  • 使用完后,把连接归还给连接池
  • 在系统关闭前,断开所有连接并释放占用的系统资源

如果不使用数据库连接池,则操作流程如下:

  • TCP三次握手建立连接
  • MySQL认证的三次握手
  • SQL执行
  • MySQL关闭
  • TCP四次挥手关闭连接

使用数据库连接池,其流程如下:

只有第一次访问需要建立连接,之后的访问,复用之前创建的连接,直接执行SQL语句

使用数据库连接池好处:

  • 资源重用:避免了频繁的创建、释放连接引起的性能开销,在减少系统消耗的基础上,也增进了系统运行环境的平稳性(减少内存碎片以及数据库临时进程/线程的数量)
  • 更快的系统响应速度:数据库连接池在初始化过程中,往往已创建了若干数据库连接于池中备用,此时连接的初始化工作均已完成,对于业务请求处理而言,直接利用现有可用连接,避免了从数据库连接初始化和释放过程的开销,从而缩减了系统整体响应时间
  • 统一的连接管理,避免连接数据库连接泄漏:在较为完备的数据库连接池实现中,可根据预先的连接占用超时设定,强制收回被占用连接。从而避免了常规数据库连接操作中可能出现的资源泄漏。

连接池:被动分配,用完放回。

线程池:主动干活,有任务到来,线程不断取出任务执行。

proxysql

https://github.com/sysown/proxysql

Pg for K8s

https://portworx.com/blog/choosing-a-kubernetes-operator-for-postgresql/

https://github.com/CrunchyData/postgres-operator/

https://github.com/zalando/postgres-operator

https://github.com/ankane/pgsync

PostGreSQL

https://www.sjkjc.com/postgresql/drop-index/

Ubuntu

apt-get install postgresql-client
apt-get install postgresql
## 图形化界面安装和启动
apt-get install pgadmin4
pgadmin4

启动

/etc/init.d/postgresql start

切换到数据库自动创建的用户

su - postgres
## 进入数据库,要求输入密码
psql

基本操作

## 创建用户
create user test with password 'test';
## 创建数据库
create database testdb owner test;
## 授权
grant all privileges on database testdb to test
## 退出
\q

基本类型

图形化管理界面

https://github.com/pgadmin-org/pgadmin4

数据库同步

otter

https://github.com/alibaba/otter

https://github.com/alibaba/canal

  • canal 模拟 MySQL slave 的交互协议,伪装自己为 MySQL slave ,向 MySQL master 发送dump 协议
  • MySQL master 收到 dump 请求,开始推送 binary log 给 slave (即 canal )
  • canal 解析 binary log 对象(原始为 byte 流)

https://github.com/ucarGroup/DataLink

readyset

https://github.com/readysettech/readyset#tutorial

缓存数据库,对于pg和mysql

sql工具

帮忙生成sql工具:https://www.sqlfather.com/

快速熟悉pg库:https://www.crunchydata.com/developers/tutorials

如果你觉得我的文章对你有帮助的话,希望可以推荐和交流一下。欢迎關注和 Star 本博客或者关注我的 Github