如何有效的跟踪线上 MySQL 实例表和权限的变更

介绍

从系统管理员或 DBA 的角度来讲, 总期望将线上的各种变更限制在一个可控的范围内, 减少一些不确定的因素. 这样做有几点好处:

1. 记录线上的库表变更;
2. 对线上的库表变更有全局的了解;
3. 如果有问题, 方便回滚操作;

从这三点来看, 有很多种方式可以实现, 比如通过 migrate
等工具强制所有的操作都以统一的方式执行, 这需要开发人员做更多的配合, 所以这类工具在非规模话的业务场景中较难实现; 另外管理员或 DBA 也可以通过知识库比如 redmine
等类似的方式记录变更, 不过不可控因素很多, 特别依赖上线的流程, 也容易出现纰漏. 这就引申出本文要介绍的如何跟踪线上库表的变更, 下文以 MySQL 数据库介绍说明.

跟踪的方式

在 Postgresql 中, 由于触发器对各种操作都有很好的支持, 我们完全可以通过触发器的形式来记录所有 DDL 语句的变更. 与此相比, MySQL 则显得较为弱小, 我们只能以其它方式实现类似的目标. 下面以中间件, log, binlog, 注册 slave, mysqldiff 五种方式进行介绍.

1. 中间件

现有的中间件 atlas
, kingshard
, mycat(https://github.com/MyCATApache/Mycat-Server) 等, 都以 proxy 的角色部署于程序和 MySQL 之间, 所有发往 MySQL 的 sql 都通过 proxy 进行转发. 如下图所示, 我们可以在 proxy 层面增加一些 DDL, DML 相关语句的记录, 达到跟踪变更的目的.

+------+        +-------+        +-------+
    | app  |  --->  | proxy |  --->  | MySQL |
    +------+        +-------+        +-------+

这种方式自由度较高, 大家都可以随意定制. 不过需要一些开发能力, 另外 sql 的过滤也会影响到查询的性能, 通过中间件来直接修改表结构等操作也是有风险较大的方式.

2. log

这种方式很简单, 打开 MySQL 的 general log 或 audit log 即可记录所有的 sql 语句. 这种方式比较适合开发环境, 线上环境如果开启会产生很多日志, 弊远远大于利, 也不利于维护;

3. binlog

管理员或 DBA 同样可以解析 MySQL 的 binlog 来过滤表或权限的变更. 这种方式本质上等同第二种方式, 线上数据库需要开启 binlog 选项, 解析 binlog 也是很耗资源的操作. 线上如果实例较多, 这种方式特别不可取.

4. 注册 slave

注册 slave 的意思即通过 MySQL 的主从协议伪造一个假的 slave, 这样 master 会把所有的更新都发送过来, 再进行一些过滤的操作. 这种方式在同步数据或增量消费的场景特别适合, 这里只用于记录表或权限的变更确实是大材小用, 线上实例较多的话也不可取. 典型的工具有 myreplication
, tungsten-replicator
以及阿里的 canal
等.

5. mysqldiff

实际上权限和表变更本身是低频率的操作事件, 上述的四种方式虽然都可以达到目标, 但本质上都是很耗费资源的操作. 考虑到这点, 我们可以通过对比的方式来实现权限及表结构变更的跟踪, 详见 sys-mysql-diff
工具. 考虑到通用性, sys-mysql-diff 工具每次都需要获取指定库的所有表的定义语句, 通过对比来生成对应的 DDL 语句. mysqldiff
则是对 sys-mysql-diff 工具的封装, 可以批量跟踪多个实例.

如何使用 mysqldiff

mysqldiff
工具是在 sys-mysql-diff 工具的基础上进行了一层封装, 所以本质上是通过 sys-mysql-diff 工具跟踪线上库的变化. 在实际的运用中, 需要注意以下几点:

1. 配置文件

mysqldiff 所需要的配置参考以下:

[backend]
dsn = user_mysqlmon:[email protected](10.0.21.17:3306)/mysqldiff?charset=utf8

[test3301]
host = 10.0.21.5
port = 3301
db   = test
user = user_mysqldiff
pass = xxxxxxxx
tag  = host_location

[test3306]
host = 10.0.21.7
port = 3306
db   = percona
user = user_mysqldiff
pass = xxxxxxxx
tag  = host_location

2. 权限

所有的变更结果都会保存到指定的 MySQL 库中的 mysql_diff
表, 即上述的 [backend]
部分, 对于该表需要 select, insert, update
相关的权限. 被跟踪的实例则是 [testXXXX]
部分, 由于需要查看表结构和用户权限所以需要 select 和 grant option 权限. 我们以 user_mysqlmon 用户为 [backend]
的用户, 以 user_mysqldiff 为 [testXXXX]
部分的用户为例, 需要赋予他们以下权限:

grant select,insert,update on mysqldiff.* to [email protected]`10.0.21.%`;
grant select on *.* to [email protected]`10.0.21.%` with grant option;

配置中的 db = information_schema 则表示跟踪所有的数据库;

3. 运行

运行 mysqldiff 命令进行跟踪:

# ./mysqldiff -conf conf.cnf -verbose
2017/03/20 16:31:27 ---------------------------
changes from 10.0.21.5:3301 
changes from 10.0.21.7:3306 
DROP TABLE `emp`;
SET GLOBAL wait_timeout = 1000;
2017/03/20 16:31:27 insert 10.0.21.17:3306/percona ok
2017/03/20 16:31:27 ---------------------------

insert ... ok
一行表示将结果插入到了 [backend]
中.

总结

以 mysqldiff 方式跟踪库表及权限的变化相对简单方便, 比起其它方式算得上轻便. 另外也不受业务场景和管理员习惯的制约, 相对很通用. 不过其也有自身的缺陷, 在短时间内经常变更的表则很难跟踪, mysqldiff 仅能记录最后一次的变更. 另外管理员需要严格限制配置文件的权限, 最好给予 0600 的权限仅限当前用户查看. 不过整体而言, 要跟踪线上库表权限的变更, mysqldiff 是一个较为合适且通用的工具.

稿源:arster's blog (源链) | 关于 | 阅读提示

本站遵循[CC BY-NC-SA 4.0]。如您有版权、意见投诉等问题,请通过eMail联系我们处理。
酷辣虫 » 后端存储 » 如何有效的跟踪线上 MySQL 实例表和权限的变更

喜欢 (0)or分享给?

专业 x 专注 x 聚合 x 分享 CC BY-NC-SA 4.0

使用声明 | 英豪名录