美文网首页
MySQL:一个BUG和两个知识点

MySQL:一个BUG和两个知识点

作者: 重庆八怪 | 来源:发表于2023-04-26 18:24 被阅读0次

一、一个半同步BUG

这个BUG比较老了,主要是5.7.17以下的版本可能会遇到。这个BUG主要是主库ACK receiver线程需要将半同步从库的连接的fd注册到其中,然后监控连接的fd是否有数据到达,其实就是ACK 信息,如果有ACK信息到达,则需要读取信息同时解析ACK包,然后决定唤醒哪个或者哪些事务。但是这里使用的是select 函数,其原型如下,

   int select(int nfds, fd_set *restrict readfds,
                  fd_set *restrict writefds, fd_set *restrict exceptfds,
                  struct timeval *restrict timeout);

其中第一个参数nfds有如下限制(来自 linux man page)

POSIX allows an implementation to define an upper limit,
       advertised via the constant **FD_SETSIZE**, on the range of file
       descriptors that can be specified in a file descriptor set.  The
       Linux kernel imposes no fixed limit, but the glibc implementation
       makes *fd_set* a fixed-size type, with **FD_SETSIZE** defined as 1024,
       and the **FD_***() macros operating according to that limit.  To
       monitor file descriptors greater than 1023, use [poll(2)](https://man7.org/linux/man-pages/man2/poll.2.html) or [epoll(7)](https://man7.org/linux/man-pages/man7/epoll.7.html) instead.

也就是说如果当前进程打开的文件描述符大于了1023,使用select会触发这个问题,那么回到MySQL中,如果连接过多或者打开的文件数量过多会导致文件描述符较多,都可能触发半同步的这个BUG。
我们可以自己写程序测试也可以用MySQLD进行测试,我这里使用使用MySQLD进行测试,同时对ACK receiver线程进行strace查看select函数状态,如下:

  • 正常状态
select(52, [51], NULL, NULL, {tv_sec=1, tv_usec=0}) = 0 (Timeout)
  • 打开文件过多,这里很简单将innodb_open_files参数调高一点,同时建立1800左右个表,然后想select一遍就可以将提高文件描述符的上限,然后开启半同步,做一些事务。
select(1827, [], NULL, NULL, {tv_sec=1, tv_usec=0}) = 0 (Timeout)

可以看到readfds没有值,是异常的。

  • 打开连接过多,这个也比较简单用压测软件并发开高一点就可以了,这也会将进程的文件描述符上限提高,然后开启半同步,做一些事务。
select(1293, [], NULL, NULL, {tv_sec=1, tv_usec=0}) = 0 (Timeout)

可以看到readfds没有值,是异常的。

当然修复就是使用poll来进行代替select函数就可以了,

关于半同步这里放一张老图在这里供大家参考,

未命名文件 (16).png

二、关于utf8mb4_0900_ai_ci和utf8mb4_general_ci的主要区别

utf8mb4_0900_ai_ci和utf8mb4_general_ci同属于utf8mb4的collation,collation主要的作用是每个unicode字符串在进行比较和排序的时候根据规则确认字符串的大小关系。其中规则来自于Unicode Collation Algorithm (UCA [https://www.unicode.org/reports/tr10/),主要规定了每个unicode字符的大小顺序。因为每个unicode版本在不断加入新的字符,因此UCA也随之变化,而utf8mb4_0900_ai_ci和utf8mb4_general_ci就是基于了不同的unicode版本,如下,

  • utf8mb4_0900_ai_ci:基于的是unicode 9.0(2016年)
  • utf8mb4_general_ci:基于的是unicode 4.0基础上优化(2003年)

下面是来一些版本变化(具体参考:https://en.wikipedia.org/wiki/Unicode#4.0

image.png

其次需要注意utf8mb4_0900_ai_ci属于NO PAD类型的collation,而utf8mb4_general_ci则为PAD类型的collation,它们在尾部空格的比较上不一致。

三、一个小技巧

这个小技巧可以用于8.0以上,因为某些原因我们需要optimizer_switch的REFER_ORDERING_INDEX属性关闭,但是又不想影响整个实例的设置,只能在语句上生效,而查看hint又没有完全一样的,这个时候可以使用SET_VAR hint(感谢朋友金海的提醒),

SELECT /*+ SET_VAR(optimizer_switch = 'REFER_ORDERING_INDEX=off') */ 1;

在官方文档中这个hint描述为如下:

  • The SET_VAR hint sets the session value of a system variable temporarily (for the duration of a single statement)

也就是这是语句级别的不会更改整个session的参数,至少看起来运行完语句后会改回来,当然更不可能修改整个实例的。

相关文章

网友评论

      本文标题:MySQL:一个BUG和两个知识点

      本文链接:https://www.haomeiwen.com/subject/rpivjdtx.html