暂无图片
暂无图片
12
暂无图片
暂无图片
暂无图片

mysql IPv6双栈改造的一些经验和心得

原创 金同学 2024-05-29
1682

最近两年,公司在搞私有云ipv6双网改造,我主要承担了mysql ipv6适配测试,现在基本已经改造完成,mysql双栈运行也很稳定,现在把IPv6改造中的一下经验和成果分享出来,欢迎大家借鉴交流。

操作系统开启ipv6支持

mysql ipv6改造之前,必须在操作系统开启ipv6功能,下面是centos7开启ipv6的详细步骤。

第1步:
检查是否启动ipv6,步骤1如果没有出现inet6则表示未启用ipv6,按照2~4步骤检查。
ifconfig|grep -i inet6

第2步:
检查 vi /etc/sysctl.conf 是否出现以下配置,
net.ipv6.conf.all.disable_ipv6 = 1
net.ipv6.conf.default.disable_ipv6 = 1
net.ipv6.conf.lo.disable_ipv6 = 1

有则改为
net.ipv6.conf.all.disable_ipv6 = 0
net.ipv6.conf.default.disable_ipv6 = 0
net.ipv6.conf.lo.disable_ipv6 = 0

sysctl -p 执行生效

第3步:
vi /etc/sysconfig/network
NETWORKING_IPV6=no
改为
NETWORKING_IPV6=yes

重启网络network 服务

第4步:
vi /etc/default/grub
GRUB_CMDLINE_LINUX="rd.lvm.lv=rhel/swap crashkernel=auto rd.lvm.lv=rhel/root ipv6.disable=1"

删除ipv6.disable=1字段

grub2-mkconfig -o /boot/grub2/grub.cfg
#重启机器使/etc/default/grub配置生效

第5步:
根据用户给的清单配置IPv6 地址及网关地址
cp /etc/sysconfig/network-scripts/ifcfg-eth0 /opt/ifcfg-eth0.bk
vi /etc/sysconfig/network-scripts/ifcfg-eth0
IPV6INIT=yes
IPV6_FAILURE_FATAL=no
IPV6ADDR=/
IPV6_DEFAULTGW=

重启network 服务,知会用户重启network服务会导致网络短暂中断。
验证

执行下面命令,检查ipv6是否可以正常使用。

ping6 ::1

mysql数据库ipv6支持官方说明

实例支持

修改my.cnf配置文件,修改bind-address参数,配置为 :: 可以同时支持IPv4和IPv6的TCP/IP的连接。

[mysqld]
bind_address = ::

注意:bind_address是只读参数,只能重启实例生效。

驱动支持

驱动支持5.1、8.0,使用MySQL Connector 8.0驱动, 对IPv6有了更好的支持。
https://dev.mysql.com/doc/connector-j/5.1/en/connector-j-reference-url-format.html
https://dev.mysql.com/doc/connector-j/8.0/en/connector-j-reference-jdbc-url-format.html

jdbc:mysql://[2001:db8:1:0:20c:29ff:fe96:8b55]:3306/databaseName
jdbc:mysql://2001:db8:1:0:20c:29ff:fe96:8b55:3306/databaseName
jdbc:mysql://[2001:db8:1:0:20c:29ff:fe96:8b55]/databaseName

IPv6在MySQL中的测试场景和结论

大部分功能支持ipv6,如创建mysql ipv6账号,使用ipv6 tcp登录,DQL操作,主从复制同步等。但mysql cluster的相关组件均不支持ipv6。

先看测试结果

名称 测试内容 结论
mysql客户端使用IPv6访问数据库 TCP/IP连接、socket连接 支持
用户管理 创建、赋权、删除IPv6用户 支持
binlog复制 DDL、DML、DCL数据同步(传统、GTID) 支持
复制特性 异步/半同步复制、并行复制、复制线程启停等 支持
mysql shell mysqlshell接管mgr集群 不支持
mysql router IPv6连接router、router初始化 不支持

以下是测试过程和输出日志
<1>使用IPv6创建账号,远程登录测试

#先检查是否开启IPv6支持
root@localhost: 14:44:  [(none)]> select @@bind_address;
+----------------+
| @@bind_address |
+----------------+
| ::             |
+----------------+
1 row in set (0.00 sec)

#创建账号
CREATE USER 'ipv6test3'@'2406:440:a00::38' IDENTIFIED BY '123456';
GRANT ALL PRIVILEGES ON *.* TO 'ipv6test3'@'2406:440:a00::38' IDENTIFIED BY '123456';

#登录验证
mysql -h 2406:440:a00::38 -uipv6test3 -p'123456' -P 3307

#查看状态
mysql> status
Current user:           ipv6test@2406:440:a00::38
Connection:             2406:440:a00::38 via TCP/IP

<2>常见DQL操作测试

#创建ipv6用户,验证通过
create user ipv6test2@'::1' identified by '123456';
Query OK, 0 rows affected (0.01 sec)

#删除ipv6用户,验证通过
root@localhost: 15:04:  [(none)]> drop user ipv6test2@'::1';
Query OK, 0 rows affected (0.01 sec)

#赋权ipv6用户,验证通过
grant insert,update,delete,select on *.* to ipv6test2@'::1';
Query OK, 0 rows affected (0.01 sec)

<3>使用IPv6搭建主从复制,测试binlog数据同步
配置主从复制

IPv6示例
主库: 2406:440:a00::9f8
从库: 2406:440:a00::9d7

#主库:创建复制账号
CREATE USER 'ipv6repl'@'2406:440:a00::9d7' IDENTIFIED BY 'Crcrepl@2020#DBA';
grant Replication client,Replication slave on *.* to 'ipv6repl'@'2406:440:a00::9d7';

#从库:执行change master
change master to master_host='2406:440:a00::9f8',
master_port=3307,
master_user='ipv6repl',
master_password='Crcrepl@2020#DBA',
master_auto_position=1;
#从库:启动主从
start slave;
#从库:查看复制状态
show slave status\G;
root@localhost: 16:43:  [(none)]> show slave status\G;
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: 2406:440:a00::9f8
                  Master_User: ipv6repl
                  Master_Port: 3307
                Connect_Retry: 60
              Master_Log_File: mysql-bin.000002
          Read_Master_Log_Pos: 655
               Relay_Log_File: relay.000002
                Relay_Log_Pos: 414
        Relay_Master_Log_File: mysql-bin.000002
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes
              Replicate_Do_DB: 
          Replicate_Ignore_DB: 
           Replicate_Do_Table: 
       Replicate_Ignore_Table: 
      Replicate_Wild_Do_Table: 
  Replicate_Wild_Ignore_Table: 
                   Last_Errno: 0
                   Last_Error: 
                 Skip_Counter: 0
          Exec_Master_Log_Pos: 655
              Relay_Log_Space: 611
              Until_Condition: None
               Until_Log_File: 
                Until_Log_Pos: 0
           Master_SSL_Allowed: No
           Master_SSL_CA_File: 
           Master_SSL_CA_Path: 
              Master_SSL_Cert: 
            Master_SSL_Cipher: 
               Master_SSL_Key: 
        Seconds_Behind_Master: 0
Master_SSL_Verify_Server_Cert: No
                Last_IO_Errno: 0
                Last_IO_Error: 
               Last_SQL_Errno: 0
               Last_SQL_Error: 
  Replicate_Ignore_Server_Ids: 
             Master_Server_Id: 12211527
                  Master_UUID: 11993726-8105-11ed-9c1f-fa163ec0080c
             Master_Info_File: mysql.slave_master_info
                    SQL_Delay: 0
          SQL_Remaining_Delay: NULL
      Slave_SQL_Running_State: Slave has read all relay log; waiting for more updates
           Master_Retry_Count: 86400
                  Master_Bind: 
      Last_IO_Error_Timestamp: 
     Last_SQL_Error_Timestamp: 
               Master_SSL_Crl: 
           Master_SSL_Crlpath: 
           Retrieved_Gtid_Set: 
            Executed_Gtid_Set: 11993726-8105-11ed-9c1f-fa163ec0080c:1-2
                Auto_Position: 1
         Replicate_Rewrite_DB: 
                 Channel_Name: 
           Master_TLS_Version: 
1 row in set (0.00 sec)

binlog同步测试

#主库:执行测试语句
create database ipv6repldb;
use ipv6repldb;
create table ip6(id int,name varchar(20),primary key(id));
insert into ip6(name) values('maomao','peter','heihe');

#从库:验证数据是否同步过来
root@localhost: 16:46:  [ipv6repldb]> select * from ip6;
+----+--------+
| id | name   |
+----+--------+
|  1 | maomao |
|  2 | mhah   |
+----+--------+
2 rows in set (0.00 sec)

<4>mysqlrouter初始化报错
image.png
另外,ipv6通过router访问数据库也报错(下图中,6446是router端口,3307是数据库端口)
image.png
<5>mysqlshell接管mgr报错
image.png

IPv4/v6双栈访问数据库面临的困难

1、开源高可用方案中,目前还没有虚拟ipv6 vip访问的案例。
虽然mysql已经支持ipv6,但是很多mysql高可用方案中,一般通过虚拟vip实现故障漂移。那么高可用架构主库出现failover主库切换时,就需要一个虚拟ipv6漂移寻主,这个功能就需要DBA自行实现了。另外在官方的mgr cluster方案中,router不支持ipv6访问(本人亲测)。

2、ipv6改造中,无法使用ipv6单栈网络运行。
在实际的生产环境ipv6改造中发现,所有的系统几乎无法单栈网络运行,比如在TMS运输系统中,它的上下游很多系统都有数据交互。如果将TMS系统的应用全部改为ipv6单栈访问,就会导致上下游很多系统也要进行ipv6改造,这是不现实的。另外一些开源组件、第三方接口本身无法支持ipv6。

3、mysql双栈运行时,两个VIP需要具备原子性。
双栈网络改造中(即ipv4、ipv6两个独立的网络),如果mysql使用了高可用方案,就需要配置两个虚拟vip(一个ipv4,另一个ipv6),两个vip同时运行。当主库切换时,我们要保证两个vip同时在旧主下线,新主上线,保证两个vip漂移的原子性。另外,遇到网卡异常导致其中一个vip异常掉线时,需要及时发现并处理。

4、双栈网络之间彼此独立,彼此无法感知。
如果ipv4和ipv6拥有独立的网卡时,其中一个网卡故障导致通信中断时,另外一条网络链路可能是正常的,这种场景类似于脑裂,对于mysql 高可用 ipv6双栈改造带来了困难。

mysql ipv6双栈改造方案

先看一下我们的mysql高可用方案:mha(双节点)+ VIP
image.png
该方案由开源 MHA 组件(在原生的基础上做了修改)和自研 HA_Monitor 服务组成。另外在数据同步中,使用到了 GTID 复制、并行复制和半同步复制。

自研HA_Monitor服务的主要功能:

<1>守护MHA Manager 服务,实时探测manager服务可用性,确保其总是运行在slave节点上。如果发生主库切换,将在新的slave节点拉起;

<2>检查实例可用性及数据同步线程,以及从库只读状态等,发现并自愈故障,如果遇到处理不了的,则采集指标数据并上报监控平台,触发一级告警。整个过程无需DBA干预。

<3>实时检查主从状态,保证ipv4 vip总是运行在主库上,类似于mysqld_safe的功能。我在mha双栈vip开发时,部分功能在HA_Monitor中实现。

以下是ipv6设计思路:

1、双vip(ipv4、ipv6)漂移在mha原生的主库切换程序中实现。
主要涉及下面两个脚本,一个是在线切换脚本,另一个是故障切换脚本:

mha/scripts/master_ip_online_change_vip
mha/scripts/master_ip_failover_vip

当主库发生切换时,就会调用上面脚本,完成vip漂移,所以需要在这2个脚本中新增ipv6的挂载和卸载。脚本用到了两个变量,ifdev是ipv6网卡名称,vip6为ipv6虚拟ip地址。其中这两个变量通过配置文件app.conf带入,下面是部分代码展示:

vim ./mha/scripts/master_ip_online_change_vip

# 自定义VIP绑定
my $ssh_start_vip6 = "/sbin/ifconfig $ifdev inet6 add $vip6";
my $ssh_stop_vip6 = "/sbin/ifconfig $ifdev inet6 del $vip6";

# 定义VIP方法
sub start_vip() {
   `ssh $new_master_ssh_user\@$new_master_host \" $ssh_start_vip \"`;
   `ssh $new_master_ssh_user\@$new_master_host \" $ssh_start_vip6 \"`;
}
sub stop_vip() {
   return 0 unless  ($orig_master_ssh_user);
   `ssh $orig_master_ssh_user\@$orig_master_host \" $ssh_stop_vip \"`;
   `ssh $orig_master_ssh_user\@$orig_master_host \" $ssh_stop_vip6 \"`;
}

vim ./mha/scripts/master_ip_failover_vip


# 定义VIP方法
sub start_vip() {
   `ssh $ssh_user\@$new_master_host \" $ssh_start_vip \"`;
   `ssh $ssh_user\@$new_master_host \" $ssh_start_vip6 \"`;
}
sub stop_vip() {
   return 0  unless  ($ssh_user);
   `ssh $ssh_user\@$orig_master_host \" $ssh_stop_vip \"`;
   `ssh $ssh_user\@$orig_master_host \" $ssh_stop_vip6 \"`;
} 

配置文件示例,在原来的基础上,新增:–ifdev6=xxx --vip6=xxx。

#自动故障切换master脚本
master_ip_failover_script=/data/mha/scripts/master_ip_failover_vip --ifdev=eth0 --ifdev6=eth1 --vip=10.133.xxx.xxx --vip6=2406:440:600::9503/120

#手动切换master脚本
master_ip_online_change_script=/data/mha/scripts/master_ip_online_change_vip --ifdev=eth0 --ifdev6=eth1 --vip=10.133.xxx.xxx --vip6=2406:440:600::9503/120

2、在HA_Monitor.py中新增双栈 VIP 可用性检测,保证其原子性。
以ipv4 vip为主,ipv6 vip为辅,在服务中实现以下功能:

  • 双栈运行过程中,如果ipv4 vip在线,ipv6 vip异常掉线是,HA_Monitor在拥有ipv4的节点自动挂载ipv6,整个检查流程与ipv4 vip的检测流程完全独立。
  • 双栈运行过程中,如果ipv6 vip在线,ipv4 vip异常掉线时,HA_Monitor立刻在主库卸载ipv6 vip,整个检查流程与ipv4 vip的检测流程完全独立。
  • 扩展,上面检测依赖于ipv4 vip的可用性,这部分逻辑原来就有,原来的ipv4 vip是否正常运行主要通过检查主机网络、网关通信以及数据库集群状态等。

下面分享部分代码段

    def is_local_vip6(self):
        """
        这个函数用于确认IPv6是否在本地
        :param vip6:参数设置中的VIP6值
        :return: 0 vip6在本地 1 vip6不在本地
        """

        # 获取含有IPv6的网卡信息
        info = psutil.net_if_addrs()

        netcard_info = []
        for k, v in info.items():
            for item in v:
                # 获取含有ipv6的网卡信息
                if item[0] in [2, 10] and not item[1] == '127.0.0.1' and not item[1] == '::1':
                    netcard_info.append((item[1], k))

        global ipaddr
        # 获得网卡信息形如 [('192.168.99.101':'eth0')]
        ipaddr = netcard_info

        for i in ipaddr:
            # 截取配置文件中的vip参数,只保留/前面的部分,示例:'2406:440:600::206/128'截取为substring: '2406:440:600::206'
            start = self.vip6.find('/')
            substring = self.vip6[:start]

            if substring == i[0]:  # 如果vip和其中一个网卡IP相等说明在本地
                return 1  # 代表在本地

        return 0  # 代表没在本地

卸载与挂载ipv6 vip

    def start_vip6(self):
        """
        挂载vip6,先判断哪个是主库,然后进行挂载,如果是双主,判断主从是否正常,然后挂载到ip主机位较小的server上。
        """
        mount_vip6 = '/sbin/ifconfig ' + self.netcard6 + ' inet6 add ' + self.vip6 + ' > /dev/null 2>&1'

        if not subprocess.call(mount_vip6, shell=True) == 0:
            Logger('check vip6').get_logger().error("mount vip6 failed,please check os env.")

    def stop_vip6(self):
        """
        挂载vip6,先判断哪个是主库,然后进行挂载,如果是双主,判断主从是否正常,然后挂载到ip主机位较小的server上。
        """
        umount_vip6 = '/sbin/ifconfig ' + self.netcard6 + ' inet6 del ' + self.vip6 + ' > /dev/null 2>&1'

        if not subprocess.call(umount_vip6, shell=True) == 0:
            Logger('check vip6').get_logger().error("下线vip6异常,请检查主机环境!")

调用上面方法的逻辑在大循环中实现

""" 从库vip管理:
1、如果从库出现VIP,则执行方法stop_vip()
2、如果从库不存在VIP,则保持现状
"""
db_status_for_vip = db_client.exec_sql(show_slave_status)
# 再次查看复制关系(避免中途发生主库切换),如果没有发生变化,则执行下面操作,反之,进行进入下一轮检查。
if db_status_for_vip:
    if mgt_mon.is_local_vip() == 1:
        Logger('check vip').get_logger().error("current host is slave,but vip was found,must stop_vip(%s) now!" % self.vip)
        mgt_mon.stop_vip()
    elif mgt_mon.is_local_vip() == 0:
        Logger('check vip').get_logger().info("current host is slave, ipv4 vip(%s) check pass." % self.vip)

        # vip6实时监控.  ipv4 vip不存在,但是ipv6 vip在线时,必须卸载vip6。
        if mgt_mon.is_local_vip6() == 1:
            # 当主库ipv4 vip存在,ipv6 vip不存在时,立刻挂载ipv6 vip。
            Logger('check vip6').get_logger().error("fun:is_vip6_local:slave hit vip6, exec func stop vip6(%s) now! " % self.vip6)
            mgt_mon.stop_vip6()
        if mgt_mon.is_local_vip6() == 0:
            Logger('check vip6').get_logger().info("current host is slave, ipv6 vip(%s) check pass." % self.vip6)
else:
    Logger('check manager').get_logger().warning('database status is changed,exit func vip_check().')
......

代码实现方式很多,但是整体思路不变,首先要保证ipv4 vip的可用性,然后再次基础上,实时探测并保证ipv6是否挂载和卸载。

mysql mgr + vip的实现方式基本一致,这里不再赘述。
最后修改时间:2024-06-05 16:43:00
「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
3人已赞赏
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

文章被以下合辑收录

评论