用Python开发MySQL增强半同步BinlogServer(T1基础篇)

导读

作者:曾永伟 ,知数堂10期学员,多年JAVA物流行业开发管理经验和PHP/Python跨境电商开发管理经验,对数据库系统情有独钟,善于运用SQL编程简化业务逻辑,去年开始正式从业MySQL DBA, 专注于DB系统自动化运维、MySQL云上实践。

本文为python-mysql-binlogserver系列的第一篇(T1基础篇),之后会陆续发布此系列的其他文章,请大家点击在看或者收藏,自行练习。

一想到你在关注我就忍不住有点紧张

概述

前不久知数堂吴老师在公开课上把MHA拉下神坛,是因为MHA无法从根本上解决丢数据的可能性,只是尝试性的去补偿未同步的数据。使用MySQL的半同步复制可以解决数据丢失的问题,但原生 io_thread 会破坏掉Master上的Binlog File的命名,对后继的运维造成不便,所以使用原生增强半同步+blackhole引擎做binlog备份的方案几乎没有人使用,而更多的公司则使用mysqlbinlog命令来实现轻量的BinlogServer,不足的是官方mysqlbinlog并不支持半同步复制,仍然会丢数据。

据我所知,Facebook,Google和国内的美团公司都有研发自己的BinlogServer,但是目前我没有找到一个开源的支持半同步的BinlogServer项目,于是就诞生了 py-mysql-binlogserver 这个项目。

1、主要特性如下:

  • 全Python标准模块开发,无第三方库依赖,减少学习成本

  • 立Dumper进程,用于同步保存Binlog event

  • 支持半同步协议,数据零丢失

  • 独立Server进程,支持Failover时Change master to来补数据

  • 支持GTID,方便切换Master

  • 暂不支持级联复制模式

  • 仅在My SQ L官方版5.7+下测试通过

  • 仅支持Python3, 不兼容Python2

2、TODO特性

  • 使用mysql client协议来管理binlogserver

  • 实现状态信息查询,满足监控需求

具体功能请到项目首页进行查看和下载体验。

3、项目地址为:

https://github.com/alvinzane/py-mysql-binlogserver

4、目录结构:

假设你已经有了一定的Python编程基础,并且完全理解MySQL半同步复制的原理,接下来我们就一步一步走进实现BinlogServer的技术细节。

二进制基础复习

MySQL的Binlog文件是二进制的,MySQL在网络上传送的数据也是二进制的,所以我们先来复习一下二进制的一些基础知识。

1、数字的表示:

数字通常可以用十进制,二进制和十六进制来表示。在计算机中,数据的运算、存储、传输最终都会用到二进制,但由于二进制不便于人类阅读(太长了),所以我们通常用一位十六进制来表示四个bite的二进制,即2位十六制表示一个Byte(字节)。

在Python中,用非零开头的数字,表示十进制,0x,0b开头分别表示十六进制和二进制:

十六进制和二进制与十进制转换:

由于1个字节(byte)最大能表示的数字为255,所以更大的数字需要用多个字节来表示,如:

以上均为无符号的数字,即全为正数,对于有符号的正负数,则最高位的1个bit用0和1分别表示正数和负数。对于1个byte的数字,实际就只有7bit表示实际的数字,范围为[-128,127].

2、字符的表示

在计算机中所有的数据最终都要转化为数字,而且是二进制的数字。字符也不例外,也需要用到一个”映射表”来完成字符的表示。这个”映射表”叫作字符集,ASCII是最早最基础的”单字节”字符集,它可以表示键盘上所有的可打印字符,如52个大小写字母及标点符号。

Python中,使用ord()和chr()完成ASCII字符与数字之间的转换:

“单字节”最大为数字是255,能表示的字符有限,所以后来就有了”多字节”字符集,如GBK,UTF8等等,用来表示更多的字符。其中UTF8是变长的字符编码,用1-6个字节表示一个字符,可以表示全世界所有的文字与符号,也叫万国码。

Python中,多字节字符与数字间的转换:

使用hexdump查看文本文件的字符编码:

使用python来验证编码:

Python二进制相关

1、bytes对象

bytes是Python3中新增的一个处理二进制”流”的对象。可以下几种方式我们可以得到bytes对象:

  • 字符对象的encode方法

  • 二进制文件read方法

  • 网络socket的recv方法

  • 使用b打头的字符申明

  • 使用bytes对象初始化

一些简单的例子:

可以把bytes看作是一个特殊的数组,由连续的字节(byte)组成,单字节最大数不能超过255,具有数组的切片,迭代等特性,它总是尝试以ASCII编码将数据转成可显示字符,超出ASCII可显示范围则使用\x打头的二位十六进制进行显示。

bytes对象的本质是存的二进制数组,存放的是0-255的数字数组,它只有结合”字符集”才能转换正确的字符,或者要结合某种”协议”才能解读出具体的”含义”,这一点后面就会详细的讲到。

再来一个例子, 打印GBK编码表:

输出:

2、struct

计算机中几乎所有的数据都可以最终抽象成数字和字符来表示,在C语言中用struct(结构体)来描述一个复杂的对象,通过这个结构可以方便的将复杂对象转换成二进制流用于存储与网络传输。Python中提供了struct模块方便处理二进制流(bytes对象)与数字,字符对象的转换功能。

3、用struct处理数字

struct处理数字的要点有:

  • 字节数

  • 有无符号位

  • 字节序,本文中均使用低字节在前的字节序”<"

4、用struct处理字符串

字符转换为bytes:

bytes转换为字符:

需要特别说明的是,unpack返回的是元组,哪怕是只有一个元素,这样做的好处是,我们可以按照规则将多个数据的format写在一起,让代码更加简洁:

这种写法会大量应用到后继的demo代码中,请务必多加练习,并仔细阅读官方文档。

Python Socket编程

简单说Socket编程,就是面向网络传输层的接口编程,系统通过IP地址和端口号建立起两台电脑之间网络连接,并提供两个最基础的通信接口发送数据和接收数据,供开发者调用,先来看一个最简单的客户端Socket例子:

可以看出通过socket接收和发送的数据都是前面讲的bytes对象,因为bytes对象本身只是一个二进制流,所以在没有”协议”的前提下,我们是无法理解传输内容的具体含义。常见的http,https,ftp,smtp,ssh协议都是建立socket通信之上的协议。换句说,就是通socket编程可以实现与现有的任何协议进行通信。如果你熟悉了ssh协议,那么实现ssh端口扫描程序就易如反掌了。

用socket不仅可以和其它协议的服务端进行通信,而且可以实现socket服务端,监听和处理来自client的连接和数据。

通过上面两个简单的例子,相信大家对Python的socket编程已经有一个初步的认识,那就是”相当的简单”,没有想象中那么复杂。

接下再来看一个多线程版的SocketServer, 可以通过telnet来实现一个网络计算器:

使用telnet进行测试:

服务端日志:

小结

理解二进制,字符/编码,socket通信,以及如何使用Python来处理它们,是实现BinlogServer最重要的基础,由于篇幅问题,很多知识点只能点到为止,虽然很基础,但是还是需要自己的动手去实验,举一反三地多实践自己的想法,会对理解后面的文章大有帮助。

只有会认真看文档的DBA才是好DBA,只会认真看代码的Engineer,一定不是好Engineer。代码一定要运行起来,On Runtime才会有价值,才会让你变成好Engineer. ^_^

最后,祝你编码快乐〜

相关文档

https://docs.python.org/3/library/struct.html

https://docs.python.org/3/library/socketserver.html

附:基于m ysqlbinlog命令的BinlogServer简单实现

扫码加入MySQL技术Q群

(群号: 650149401)

点“在看”给我一朵小黄花