一、一个半同步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函数就可以了,
关于半同步这里放一张老图在这里供大家参考,
![](https://img.haomeiwen.com/i7398834/70b2357b629d9952.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)
![](https://img.haomeiwen.com/i7398834/d41bff0fc8e9727e.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的参数,至少看起来运行完语句后会改回来,当然更不可能修改整个实例的。
网友评论