MySql教程

TDSQL特有的MySQL内核功能介绍

本文主要是介绍TDSQL特有的MySQL内核功能介绍,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

本文是我最初于2017年底发表在我的个人微信公众号里面,现发布在这里。所以本文所列的tdsql的mysql/mariadb内核的功能和修复的bug,并没有包括我这2018年所完成的功能和修复的bug。我近期会写一篇文章总结一下我在2018年所完成的主要的tdsql数据库内核的功能和修复的bug。

在TDSQL-MariaDB-10.1.9和TDSQL-Percona中,有一些功能是官方发布的MariaDB/Percona 没有的。开发这些功能的目的是为TDSQL实现更好的安全性,性能,可靠性,可扩展性。它们可以配合TDSQL其他功能模块的功能,或者防止用户操作失误给自己带来损失。这些功能大多是在我们处理TDSQL的真实用户遇到的问题的过程中,总结经验后设计和实现的,因而具有很强的实用性。另外我还做了一些性能优化,使得TDSQL-MariaDB和TDSQL-Percona的性能均大幅超越了原版。

我在本文分如下几个方面介绍这些功能当中面向用户使用的功能。本文可以作为TDSQL内核的简明用户手册供应用开发者和DBA 查阅使用。

  1. 主备复制相关功能
    下面两个功能是为了防止备机复制执行过慢而设计的。TDSQL内核使用row格式的binlog复制。根据目前MariaDB/MySQL的实现方式,如果一个update/delete语句更新或者删除了很多行,那么到了备机上面,更新或者删除每个行时候,需要使用索引扫描或者全表扫描来找到这个行,导致备机复制变得非常慢,这是非常严重的问题。
    在TDSQL的告警平台上面就有用户出现过主备延迟因此变得非常大的告警。为了避免这些致命问题的出现,我们做了“自动增加主键”和“禁止create table/alter table语句产生无主键的表”这两个功能,详见下文。
    禁止create table/alter table语句产生无主键的表
    当“自动增加主键”功能关闭时,如果内核发现create table语句没有创建主键和唯一索引的子句,那么就返回错误,服务器端错误码是1173,错误信息是“This table type requires a primary key”。另外,如果alter table语句删除了主键或者唯一索引,导致这个表没有了主键和唯一索引,也会返回这个错误。 这个禁止对于备机无效,以便防止因用户配置疏忽导致主备上面这个功能的开关变量配置不同导致备机无法复制。另外这个禁止对于系统数据库(xa, sys, mysql, information_schema, performance_schema,sysdb)中的表无效。该功能在reject_table_no_pk=1时候生效,改变量默认是1。
    禁止远程用户修改sql_log_bin
    TDSQL的每个set都是一主两备的,时刻都依赖mysql的replication完成主备复制同步。主备复制对TDSQL来说总是必须的。曾经发生过云上的用户误操作关闭了sql_log_bin,导致主备复制异常。为了防止用户误操作给自己挖坑,我们做了这个限制,禁止TCP/IP连上来的用户在任何时刻修改sql_log_bin变量。
  2. 事务一致性保障
    下面这两个功能用于避免用户数据一致性问题。由于历史遗留问题,很多用户和已有的应用,组件等,仍然会创建MyISAM表。由于MyISAM存储引擎不支持事务,导致系统存在很大的数据一致性风险,特别是在主备复制中,备机的数据一致性更是个大问题。
    所以TDSQL会帮助用户尽量不使用MyISAM存储引擎。当然,mysql 这个db中的很多表都是建在MyISAM上面的系统表,对此我们没办法也不做限制。目前我们做了下面两个功能。
    将建表语句中指定的存储引擎替换为默认存储引擎
    由于历史遗留问题,用户的有些软件组件无法修改,它们显式指定在MyISAM中建表。为了既能让这些组件正确工作又不使用MyISAM等非事务存储引擎,我们开发了这个功能。用户需要设置字符串变量,比如这样设置, converted_storage_engines=‘myisam,memory,heap’ 合法值是目前系统支持的存储引擎名称字符串,用逗号隔开。 如果富贵论坛建表语句使用的是这个列表里面的某个存储引擎,那么转而使用‘default_storage_engine’ 变量所指定的存储引擎 DEF-SE来建表。 如果DEF-SE需要的某些配置项在建表语句不存在,那么使用其默认值;并且忽略建表语句中不属于DEF-SE的存储引擎设置。目前只有TDSQL-Percona上面由此功能。
    禁止创建MyISAM表
    对于converted_storage_engines是空值的情况,或者没有上述功能的情况,则禁止用户创建MyISAM表。如果create table/alter table语句导致目标表创建到了MyISAM存储引擎之中,那么返回错误,服务器端错误号是10001,错误信息:“Can not create tables in myisam storage engine in user databases, controled by reject_create_table_myisam variable.” 这个禁止对于备机无效,以便防止因用户配置疏忽导致主备上面这个功能的开关变量配置不同导致备机无法复制。另外这个禁止对于系统数据库(xa, sys, mysql, information_schema, performance_schema,sysdb)中的表无效。该功能在reject_create_table_myisam=ON时候生效,改变量默认是ON。
  3. SQL语句执行规模控制
    如果某个SQL语句执行开销过大会严重增加系统负载,导致mysql服务器对其他连接上面的SQL语句的响应时间显著增大,并且严重降低系统的TPS。用户的SQL语句开销过大有些时候并不是用户真正需要执行这些语句,而可能是因为人为错误,甚至SQL注入等原因导致的。因此,TDSQL 的MySQL/MariaDB 内核会限制SQL语句执行的规模。具体来说,目前我们通过限制临时表的大小,和强制delete/update/select 增加limit子句来实现。这些限制默认都是关闭的,用户可以酌情打开启用。
    限制临时表大小
    对于创建在myisam上面的临时表,用户可以设置 全局变量 max_temp_table_size来限定临时表的大小,该动态变量默认是0,表示没有限制。当查询执行过程中任一个临时表的size大于这个限定值时候,查询直接返回失败,服务器端错误号:1114,错误字符串是:The table ‘xxx’ is full。如果max_temp_table_size 小于temp_table_size,那么在将内存表中的数据装入到myisam过程中myisam存储引擎发现超过了max_temp_table_size会返回上述错误。
    强制delete/update/select语句增加limit子句
    用户可以设置select_rows_limit/delete_rows_limit/update_rows_limit 3个动态的全局变量,来强制用户对这3类语句必须指定limit子句来限制这3类语句可以查询到,删除,更新的总行数。用户也可以在这3类语句中使用NO_LIMIT关键字,来避免这个限制。
    限制事务的binlog写入量
    限制一个事务中写入的binlog总量,当达到配置的最大值时候,当前DML语句返回错误,客户端用户应该回滚事务。这个检查在DML执行时即做,而不是在事务提交时刻。

控制binlog写入量是为了

  1. 防止强同步超时 — binlog量过大会导致该事务之后的事务强同步等待超时,io线程没有机会接收后面的事务的binlog并发回ack

  2. 各种错误导致的事务执行错误,比如用户因为操作失误无条件删表的所有行之类
    备机写入binlog量不受限制,防止主机上面放行的事务在备机上面被卡住。

  3. 系统安全机制
    禁止直接访问mysqld服务器文件系统
    为了保护TDSQL的用户免受黑客攻击,我们做了如下一些安全措施。
    为了确保mysqld服务器文件系统的安全,对于tcp/ip登录 的用户,即使他有权限,也禁止如下操作:
    1.禁止这样的用户通过以下SQL语句在mysqld运行的服务器上面创建或者打开文件:
    a. select … into dump file
    b. select … into outfile
    c. load data infile …
    在上面链接的脆弱性报告中,黑客正是通过 select into out file 来把其本地的攻击程序传输到服务器端的。
    2.禁止这样的用户读写路径变量的值。路径变量就是其值是路径字符串的变量。这是为了防止客户端得知服务器的目录结构。黑客在得知目录结构后,更容易对用户发起数据窃取和攻击。
    有了这些禁止措施,用户将无法通过TCP/IP连接的客户端在mysqld服务器上面创建或打开任意文件,用户创建的文件只有数据表文件等完全受mysqld掌控的文件。用户只能传输DDL/DML等SQL语句字符串以及得到它们的查询结果。
    防止用户误删除和修改元数据
    只允许unix socket 连上来的具有权限的用户删除 mysql, information/performance_schema, xa, sys, sysdb这几个系统DB以及其中的表,并且禁止这样的用户 alter/truncate 这些表,以及更新和删除这些表中的行。以便防止云上的用户因为误操作删除了这些重要的元数据库表。我们曾见过有用户误删除了mysql.user表,然后又试图挽回于是补创建了一个mysql.user表,结果新建的那个表的user 字段比标准的要短,于是后来创建用户失败了。有了这样的禁止以后,用户就不会给自己挖坑了。
    阻止远程用户安装插件
    MySQL提供了标准的接口允许用户实现自定义的功能,只要用户实现了这些接口就可以以动态库的形式挂载到mysqld进程中去执行用户的代码。这个机制虽然灵活方便,但是也是一个潜在的安全隐患。如果被攻击者利用的话,就可以在mysqld服务器上面以启动mysqld进程的linux用户的身份执行任意代码,是一个非常巨大的安全隐患。所以,TDSQL中,我们禁止通过TCP/IP连接上来的用户执行INSTALL PLUGIN语句安装插件。
    阻止远程用户修改和读取安全开关变量
    上述安全机制都有开关控制,但是远程用户无法修改和读取这些开关变量,TDSQL percona/mariadb会禁止这些行为,防止攻击者关掉上述安全措施。

  4. 其他防入坑机制

  5. 禁止用户设置产生 binlog_format=statement和 tx_isolation=read-committed 的组合。这个组合会导致insert语句失败。

  6. 允许用户不需要SUPER权限就可以修改session级别的 binlog_format,这样可以避免遇到上面情况,同时有时候用户不得不暂时修改binlog_format为statement,以便避免因为产生了海量的binlog导致无法执行DML语句,或者因为历史原因原有的某些数据表没有主键和唯一索引导致某些update/delete语句在备机上面执行太慢等问题。不过需要注意的是,当你set session binlog_format=statement后,TDSQL的强同步机制中非常重要的一个环节—闪回就无法正确工作了,因此必须尽快重新设置为row格式。

  7. 性能优化
    线程池性能优化
    我们对percona官方实现的线程池做了性能优化,实测明显提升了其TPS/QPS,并且缩短了平均响应时间。
    组提交性能优化
    Binlog事务组提交是一个开销较大的过程,在此过程中一个组的所有连接的工作线程中只有leader线程在工作,所有其他线程都需要等待leader线程完成工作。 这个组提交过程中我们发现了一些可以改进性能的点,通过优化改进了性能。
    在TDSQL-MariaDB中,我们实现了TDSQL-Percona的一个性能优化 — 在engine prepare期间不刷engine 事务日志,而是在执行binlog写入之前,一次性flush engine事务日志。
    强同步机制性能优化
    TDSQL的强同步机制比mysql/mariadb官方实现的半同步机制更加高效,因为工作线程不需要阻塞等待备机应答,而是将会话脱离并放入等待队列然后继续处理其他连接上过来的新的请求。这样可以充分利用线程池中的线程,避免创建过多的线程。实测的性能提升(对比官方半同步机制)非常显著。
    慢速删除
    在TDSQL-Percona上面,当用户执行drop table或者alter table … drop partition 时,innodb不再立刻删除表空间文件,而是将这些文件重命名并且在后台逐步缩小这些文件并最终删除。这样做是为了避免一次性删除巨大的表空间文件给服务器的文件系统带来突增的IO负载,导致系统的TPS/QPS和响应时间出现波动。目前只支持innodb表的慢速删除。删除一个表后可以立刻创建同名表,也可以紧接着立刻删除这个同名表,不会发生名字冲突。如果用户执行drop database,那么不再慢速删除,而是立刻删除所有表。
    同理,对于purge binary logs to命令也会做同样的慢速删除操作。

这篇关于TDSQL特有的MySQL内核功能介绍的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!