Tag Archives: plugin

禁用 MYISAM 引擎的 MySQL 插件

在无法控制最终用户使用 MySQL 时,就可能出现混合使用 InnoDB 和 MYISAM 的情况。这时就需要考虑为两种引擎各自配置缓存等资源,即使最后实际只会用 InnoDB 的时候也是如此,这就造成了无法充分利用资源,也增加了资源限制的难度。同时由于 MYISAM 引擎的稳定性问题,为了减少运维工作,通常也不希望用户去使用 MYISAM 引擎。这时候就想禁用掉它。但是 MYISAM 引擎被 MySQL 系统表使用,还可能用于内部临时表,所以不可能直接禁用,因此 mysqld 也没有 –skip-myisam 这样的参数。所以只能想别的办法。比如,只禁止创建新的 MYISAM 表,对于原有的表则没有影响。于是就做了这么一个插件

https://github.com/xiezhenye/mysql-plugin-disable-myisam

其实这个插件很简单,只是替换了 MYISAM 引擎的 create 入口,改为返回一个包装过的,替换了 create 方法的 ha_myisam 对象。在试图创建表的时候直接错误返回。

按装插件后,就无法再创建任何新的 MYISAM 表了

mysql> CREATE TABLE `test4` (
  `id` int(11) AUTO_INCREMENT,
  `value` varchar(30),
  PRIMARY KEY (`id`)
) ENGINE=MyISAM;
ERROR 1030 (HY000): Got error 1 from storage engine

显示 metadata lock 信息的 mysql 插件

有一回碰上在 mysql 5.5 中,一些表没法执行 DDL ,会一直被阻塞住。show processlist 会看到

mysql> show full processlist;
+----+------+-----------------+------+---------+------+---------------------------------+-----------------------+
| Id | User | Host            | db   | Command | Time | State                           | Info                  |
+----+------+-----------------+------+---------+------+---------------------------------+-----------------------+
...
|  6 | root | localhost:56841 | test | Query   |    0 | init                            | show full processlist |
|  7 | root | localhost:56843 | test | Query   |   13 | Waiting for table metadata lock | rename table u to uu  |
...
+----+------+-----------------+------+---------+------+---------------------------------+-----------------------+

可以看出,是被一个 metadata lock 阻塞住了。但是从 process list 里是没法看出是哪个线程持有了这个锁。用别的方式,也只能得到通过 lock table 方式获取的锁或 innodb 事务的信息。对于一些比较隐蔽的方式,比如

mysql> begin;
mysql> select * from test.u;

这样也同样会获取 metadata lock 。在 autocommit 为 0 的时候,没有显式 begin 也是如此。这类情况没法从任何途径获取究竟是谁上了锁。

于是我就试着做了一个 mysql 的 information schema 插件。 https://github.com/xiezhenye/mysql-plugin-mdl-info 安装后,只要 select * from information_schema.MDL_INFO 就可以获取到所有 metadata lock ,也就是 mdl 的信息。

mysql> select * from information_schema.MDL_INFO;
+-----------+-------------+---------------------+-----------+----------+------+
| THREAD_ID | DURATION    | TYPE                | NAMESPACE | DATABASE | NAME |
+-----------+-------------+---------------------+-----------+----------+------+
|         7 | STATEMENT   | INTENTION_EXCLUSIVE | GLOBAL    |          |      |
|         7 | TRANSACTION | SHARED_WRITE        | TABLE     | test     | t    |
+-----------+-------------+---------------------+-----------+----------+------+
2 rows in set (0.00 sec)

在写这个插件的时候,发现 mysql 把 mdl lock 的信息封装的相当严密,即使是写插件也没法用常规途径获取。只好用了一些很恶心的技巧。如果各位有碰到类似的问题,也可以先在测试环境试试。