我手里维护了一个项目,其功能是用Java模拟一个MariaDB的slave库连接到主库,对从主库传输过来的binlog事件进行监听与分析
碰到一个问题是:
如果主库做了一个很大的修改操作(比方说直接delete了一个百万条数据的表),那么会产生一个很大的binlog事件,这个binlog事件会在我们的binlog监听器中被处理,然后组装成一个很大的对象(含有这100万条数据)
问题就出在这里,这个对象太大了(占用上g的heap毫不费力),然后我们在对这个对象的分析过程中,会产生更多的对象,而这些对象都是强引用,占用的是实打实的内存。于是就OOM了
我接受这个项目的时候,前人提出的方案很简单:禁止用户执行过大的操作。
很暴力的方案,而且确实也可以解决问题。
但是我觉得应该有更好的解决方法
第一反应是修改binlog监听器模块的代码
由于binlog事件是通过网络传输,我们也许可以在接收binlog事件的时候,对监听到的超大binlog事件进行拆分,将其逐步拆分为多个等效的小binlog事件
但是这一块的代码风格很差,很难修改
于是在Google上搜了一下相关的关键词,发现有一个叫做binlog-row-event-max-size的神奇启动参数,其英文注释如下
The maximum size in bytes of a row-based binary log event. Should be a multiple of 256. Minimum 256, maximum 18446744073709547520.
似乎正好是我需要的?
但是很不幸,这个参数只在MariaDB 10.0.17之后有效
而公司的生产环境用的是MariaDB 10.0.10
对比一下两者的效果吧
MariaDB 10.0.10,delete一个百万元素的表
| Log_name | Pos | Event_type | Server_id | End_log_pos | Info | mysql-bin.000319 | 446952048 | Gtid | 90174306 | 446952086 | BEGIN GTID 17186-90174306-429975571 | | mysql-bin.000319 | 446952086 | Table_map | 90174306 | 446952126 | table_id: 14520 (cc.t1) | | mysql-bin.000319 | 446952126 | Delete_rows_v1 | 90174306 | 455952146 | table_id: 14520 flags: STMT_END_F | | mysql-bin.000319 | 455952146 | Xid | 90174306 | 455952173 | COMMIT /* xid=489278797 */