专职DBA-MySQL集群高可用方案-PXC 1.Percona Xtradb Cluster 介绍 Percona XtraDB Cluster 简称:PXC,是针对MySQL用户的高可用性和扩展性解决方案,基于Percona Server。 其包括了Write Set REPlication补丁,使用Galera库,这是一个针对事务性应用程序的同步多主机复制插件。 Percona XtraDB Cluster 特点: 同步复制(真正的同步),事务可以在所有节点上提交(多点写入)。 多主机复制,你可以写到任何节点。每个节点是一个完整的copy。 任何query可以在本地完成。 Percona XtraDB Cluster 完全兼容MySQL或Percona Server,包括: 数据兼容。Percona XtraDB Cluster 可在由MySQL或Percona Server创建的数据库上使用。 应用程序兼容。如果要使用Percona XtraDB Cluster,你的应用程序基本不需要作任何更改。 2.PXC和Replication的区别 Let’s take look into the well known CAP theorem for Distributed systems. Characteristics of Distributed systems: C - Consistency (all your data is consistent on all nodes), A - Availability (your system is AVAILABLE to handle requests in case of failure of one or several nodes ), P - Partitioning tolerance (in case of inter-node connection failure, each node is still available to handle requests). CAP theorem says that each Distributed system can have only two out of these three. MySQL replication has: Availability and Partitioning tolerance.(这个p 是指从库上可以不完全同步) Percona XtraDB Cluster has: Consistency and Availability. 基于以上可以看出来Replication 并不能真正保证数据一致性,但PXC 提供了强的数据一致性,但牺牲的分区特性。 3.PXC安装环境需求 ------------------------------------------ 节点 bond0 bond1 ------------------------------------------ db01 10.0.0.11 192.168.10.11 ------------------------------------------ db02 10.0.0.12 192.168.10.12 ------------------------------------------ db03 10.0.0.13 192.168.10.13 ------------------------------------------ 4.基本架构图:
5.PXC安装基本步骤: 下载PXC二进制安装包ssl101是Red Hat Enterprise Linux的: # wget https://www.percona.com/downloads/Percona-XtraDB-Cluster-LATEST/Percona-XtraDB-Cluster-5.7.25-31.35/binary/tarball/Percona-XtraDB-Cluster-5.7.25-rel28-31.35.1.Linux.x86_64.ssl101.tar.gz # wget https://www.percona.com/downloads/Percona-XtraBackup-2.4/Percona-XtraBackup-2.4.14/binary/redhat/7/x86_64/percona-xtrabackup-24-2.4.14-1.el7.x86_64.rpm [root@db01 ~]# ls -lh total 223M -rw-r--r-- 1 root root 7.6M Apr 30 13:01 percona-xtrabackup-24-2.4.14-1.el7.x86_64.rpm -rw-r--r-- 1 root root 216M Jul 27 00:34 Percona-XtraDB-Cluster-5.7.25-rel28-31.35.1.Linux.x86_64.ssl101.tar.gz 安装依赖包: [root@db01 ~]# yum -y install perl perl-devel perl-IO-Socket-SSL perl-Digest perl-Digest-MD5 perl-DBD-MySQL perl-Time-HiRes libaio libaio-devel libev socat 安装Percona-Xtrabackup [root@db01 ~]# yum -y localinstall percona-xtrabackup-24-2.4.14-1.el7.x86_64.rpm PXC-MySQL数据库安装 参考(专职DBA-品悟MySQL专业环境安装) 安装之后先不要初始化数据库 my.cnf配置文件参考(PXC大多是独占服务器,配置文件可以放在/etc/my.cnf) 周老师还是喜欢把配置文件放在老地方/data/mysql/3306/my.cnf [root@db01 ~]# cat /etc/my.cnf [mysqld] # for mysql global user = mysql basedir = /usr/local/mysql datadir = /data/mysql/3306/data tmpdir = /data/mysql/3306/tmp pid_file = /data/mysql/3306/3306.pid socket = /data/mysql/3306/mysql.sock port = 3306 server_id = 113306 #每个节点的server_id不能一样 character-set-server = utf8 # for binlog binlog_format = row #日志格式必须为ROW log_bin = /data/mysql/3306/logs/mysql-bin # for error log log_error = /data/mysql/3306/error.log # general log general_log = off general_log_file = /data/mysql/3306/general.log # for slow query log slow_query_log = on slow_query_log_file = /data/mysql/3306/slow.log long_query_time = 1.000000 # for gtid gtid_mode = on enforce_gtid_consistency = on # for replication # for innodb # percona xtradb cluster default_storage_engine = InnoDB innodb_locks_unsafe_for_binlog = 1 innodb_autoinc_lock_mode = 2 wsrep_cluster_name = pxc_mysql #cluster的名字 wsrep_cluster_address = gcomm://10.0.0.11,10.0.0.12,10.0.0.13 #cluster中的节点ip wsrep_node_address = 10.0.0.11 #cluster当前节点的ip,每个节点当前节点ip不能一样 wsrep_provider = /usr/local/mysql/lib/libgalera_smm.so wsrep_sst_method = xtrabackup-v2 wsrep_sst_auth = sst:123 [mysql] #character-set-client = utf8 #prompt ="\\u@\\h [\\d]> \" #prompt ="mysql [\\d]> \" #prompt ="Master [\\d]> \" #prompt ="Slave [\\d]> \" 第一个节点初始化 [root@db01 ~]# mysqld --defaults-file=/data/mysql/3306/my.cnf --initialize-insecure 启动 [root@db01 ~]# mysqld --defaults-file=/data/mysql/3306/my.cnf --wsrep-new-cluster & [1] 27427 说明,使用--wsrep-new-cluster启动,让他忽略参数:wsrep_cluster_address 让他知道他是集群中的第一个节点,在启动中不用去找其它节点。 [root@db01 ~]# ss -tunlp | grep mysql tcp LISTEN 0 128 *:4567 *:* users:(("mysqld",pid=27427,fd=11)) tcp LISTEN 0 80 :::3306 :::* users:(("mysqld",pid=27427,fd=33)) 设置密码 [root@db01 ~]# mysqladmin -S /data/mysql/3306/mysql.sock -p password 123 [root@db01 ~]# mysql -S /data/mysql/3306/mysql.sock -p Enter password: 创建一个可以做SST的账号: mysql> create user 'sst'@'localhost' identified by '123'; Query OK, 0 rows affected (0.01 sec) mysql> grant reload,lock tables,process,replication client on *.* to 'sst'@'localhost'; Query OK, 0 rows affected (0.01 sec) 其他节点启动,这里我直接克隆虚拟机了 克隆好的虚拟机,需要修改:ip地址、主机名、删除auto.cnf 在配置文件需要修改两处: [mysqld] server_id = xx3306 wsrep_node_address = 本机IP 关机克隆db02和db03 [root@db01 ~]# mysqladmin -S /data/mysql/3306/mysql.sock -p shutdown Enter password: 启动第一个节点 [root@db01 ~]# mysqld --defaults-file=/data/mysql/3306/my.cnf --wsrep-new-cluster & [1] 6733 [root@db01 ~]# netstat -tunlp|grep mysql tcp 0 0 0.0.0.0:4567 0.0.0.0:* LISTEN 6733/mysqld tcp6 0 0 :::3306 :::* LISTEN 6733/mysqld 其他节点可以不用初始化,直接启动 [root@db02 ~]# mysqld --defaults-file=/data/mysql/3306/my.cnf & [1] 6713 [root@db03 ~]# mysqld --defaults-file=/data/mysql/3306/my.cnf & [1] 6731 启动完毕确认 [root@db01 ~]# mysql -S /data/mysql/3306/mysql.sock -p Enter password: mysql> show global status like "%wsrep%"; +----------------------------------+----------------------------------------------+ | Variable_name | Value | +----------------------------------+----------------------------------------------+ | wsrep_local_state_uuid | c3321380-b08b-11e9-bf9f-c7528f35ede2 | | wsrep_protocol_version | 9 | | wsrep_last_applied | 3 | | wsrep_last_committed | 3 | | wsrep_replicated | 0 | | wsrep_replicated_bytes | 0 | | wsrep_repl_keys | 0 | | wsrep_repl_keys_bytes | 0 | | wsrep_repl_data_bytes | 0 | | wsrep_repl_other_bytes | 0 | | wsrep_received | 4 | | wsrep_received_bytes | 590 | | wsrep_local_commits | 0 | | wsrep_local_cert_failures | 0 | | wsrep_local_replays | 0 | | wsrep_local_send_queue | 0 | | wsrep_local_send_queue_max | 1 | | wsrep_local_send_queue_min | 0 | | wsrep_local_send_queue_avg | 0.000000 | | wsrep_local_recv_queue | 0 | | wsrep_local_recv_queue_max | 2 | | wsrep_local_recv_queue_min | 0 | | wsrep_local_recv_queue_avg | 0.250000 | | wsrep_local_cached_downto | 0 | | wsrep_flow_control_paused_ns | 0 | | wsrep_flow_control_paused | 0.000000 | | wsrep_flow_control_sent | 0 | | wsrep_flow_control_recv | 0 | | wsrep_flow_control_interval | [ 173, 173 ] | | wsrep_flow_control_interval_low | 173 | | wsrep_flow_control_interval_high | 173 | | wsrep_flow_control_status | OFF | | wsrep_cert_deps_distance | 0.000000 | | wsrep_apply_oooe | 0.000000 | | wsrep_apply_oool | 0.000000 | | wsrep_apply_window | 0.000000 | | wsrep_commit_oooe | 0.000000 | | wsrep_commit_oool | 0.000000 | | wsrep_commit_window | 0.000000 | | wsrep_local_state | 4 | | wsrep_local_state_comment | Synced | | wsrep_cert_index_size | 0 | | wsrep_cert_bucket_count | 22 | | wsrep_gcache_pool_size | 1320 | | wsrep_causal_reads | 0 | | wsrep_cert_interval | 0.000000 | | wsrep_open_transactions | 0 | | wsrep_open_connections | 0 | | wsrep_ist_receive_status | | | wsrep_ist_receive_seqno_start | 0 | | wsrep_ist_receive_seqno_current | 0 | | wsrep_ist_receive_seqno_end | 0 | | wsrep_incoming_addresses | 10.0.0.12:3306,10.0.0.13:3306,10.0.0.11:3306 | | wsrep_cluster_weight | 3 | | wsrep_desync_count | 0 | | wsrep_evs_delayed | | | wsrep_evs_evict_list | | | wsrep_evs_repl_latency | 0/0/0/0/0 | | wsrep_evs_state | OPERATIONAL | | wsrep_gcomm_uuid | e4bf0102-b092-11e9-b61c-22610d7dfea6 | | wsrep_cluster_conf_id | 3 | | wsrep_cluster_size | 3 | | wsrep_cluster_state_uuid | c3321380-b08b-11e9-bf9f-c7528f35ede2 | | wsrep_cluster_status | Primary | | wsrep_connected | ON | | wsrep_local_bf_aborts | 0 | | wsrep_local_index | 2 | | wsrep_provider_name | Galera | | wsrep_provider_vendor | Codership Oy <info@codership.com> | | wsrep_provider_version | 3.35(r) | | wsrep_ready | ON | +----------------------------------+----------------------------------------------+ 71 rows in set (0.00 sec) 确认这四个参数值: wsrep_local_state | 4 wsrep_local_state_comment | Synced wsrep_cluster_status | Primary wsrep_connected | ON 6.PXC基本管理 (1).PXC关闭 # mysqladmin -S /data/mysql/3306/mysql.sock -p shutdown # /etc/init.d/mysqld stop (2).PXC启动 第一个启动的节点(如果集群节点全部关闭,第一个节点启动需要加参数--wsrep-new-cluster) # mysqld --defaults-file=/data/mysql/3306/my.cnf --wsrep-new-cluster & # /etc/init.d/mysqld bootstrap-pxc 其他节点启动 # mysqld --defaults-file=/data/mysql/3306/my.cnf & # /etc/init.d/mysqld start 集群节点不是都关闭启动方式如下 # mysqld --defaults-file=/data/mysql/3306/my.cnf & # /etc/init.d/mysqld start (3).新加入节点db04 [root@db04 ~]# grep "address" /data/mysql/3306/my.cnf wsrep_cluster_address = gcomm://10.0.0.11,10.0.0.12,10.0.0.13,10.0.0.14 wsrep_node_address = 10.0.0.14 (4).思考 binlog_format配置成mixed,不支持,需要配置成row格式。 任何节点写入数据看能不能同步? PXC架构中三个节点的binlog内容是不是一样?(观察三个节点binlog的内容变化) PXC集群如果挂一个从库做备份,集群中哪个节点可以担任主库? (5).报错处理 加载so文件加不到: Installing MySQL system tables... /usr/local/mysql/bin/mysqld: error while loading shared libraries: libssl.so.6: cannot open shared object file: No such file or directory 可能的问题: openssl没装:yum -y install openssl openssl-devel 如果提示已经安装,可以使用 # updatedb # locate libssl.so 看看能不能找到 然后用ldd 查看还有那些依赖需安装 [root@db01 ~]# ldd /usr/local/mysql/bin/mysqld linux-vdso.so.1 => (0x00007ffc4d38e000) libpthread.so.0 => /lib64/libpthread.so.0 (0x00007fd287068000) libaio.so.1 => /lib64/libaio.so.1 (0x00007fd286e66000) libnuma.so.1 => /lib64/libnuma.so.1 (0x00007fd286c5a000) libcrypt.so.1 => /lib64/libcrypt.so.1 (0x00007fd286a23000) libssl.so.10 => /lib64/libssl.so.10 (0x00007fd2867b1000) libcrypto.so.10 => /lib64/libcrypto.so.10 (0x00007fd286350000) libdl.so.2 => /lib64/libdl.so.2 (0x00007fd28614c000) libz.so.1 => /lib64/libz.so.1 (0x00007fd285f36000) librt.so.1 => /lib64/librt.so.1 (0x00007fd285d2e000) libstdc++.so.6 => /lib64/libstdc++.so.6 (0x00007fd285a27000) libm.so.6 => /lib64/libm.so.6 (0x00007fd285725000) libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x00007fd28550f000) libc.so.6 => /lib64/libc.so.6 (0x00007fd285142000) /lib64/ld-linux-x86-64.so.2 (0x00007fd287284000) libfreebl3.so => /lib64/libfreebl3.so (0x00007fd284f3f000) libgssapi_krb5.so.2 => /lib64/libgssapi_krb5.so.2 (0x00007fd284cf2000) libkrb5.so.3 => /lib64/libkrb5.so.3 (0x00007fd284a09000) libcom_err.so.2 => /lib64/libcom_err.so.2 (0x00007fd284805000) libk5crypto.so.3 => /lib64/libk5crypto.so.3 (0x00007fd2845ea000) libkrb5support.so.0 => /lib64/libkrb5support.so.0 (0x00007fd2843db000) libkeyutils.so.1 => /lib64/libkeyutils.so.1 (0x00007fd2841d7000) libresolv.so.2 => /lib64/libresolv.so.2 (0x00007fd283fbe000) libselinux.so.1 => /lib64/libselinux.so.1 (0x00007fd283d97000) libpcre.so.1 => /lib64/libpcre.so.1 (0x00007fd283b35000) 安装中socat找不到 socat包没装上,可以把epel的源加入就可以安装。 启动报错,找不到my_print_defaults的。 可以更改/etc/my.cnf 在[mysqld]中添加 basedir=/usr/local/mysql/ 如果还不行,可以通过在/etc/init.d/mysqld中找到basedir定义为: basedir=/usr/local/mysql/ kill mysqld或是异常后PXC第一个节点起不来。 [ERROR] WSREP: It may not be safe to bootstrap the cluster from this node. It was not the last one to leave the cluster and may not contain all the updates. To force cluster bootstrap with this node, edit the grastate. dat file manually and set safe_to_bootstrap to 1. 处理办法: 编辑datadir下:grastate.dat [root@db01 ~]# cat /data/mysql/3306/data/grastate.dat # GALERA saved state version: 2.1 uuid: c3321380-b08b-11e9-bf9f-c7528f35ede2 seqno: -1 safe_to_bootstrap: 1 #把0改成1即可。 (6).参考 官方文档:http://www.percona.com/doc/percona-xtradb-cluster/5.7/ (7).测试PXC复制 [root@db01 ~]# mysql -S /data/mysql/3306/mysql.sock -p Enter password: db01 [(none)]> show databases; +--------------------+ | Database | +--------------------+ | information_schema | | mysql | | performance_schema | | sys | +--------------------+ 4 rows in set (0.01 sec) db01 [(none)]> create database app01; Query OK, 1 row affected (0.04 sec) db01 [(none)]> show databases; +--------------------+ | Database | +--------------------+ | information_schema | | app01 | | mysql | | performance_schema | | sys | +--------------------+ 5 rows in set (0.00 sec) db01 [(none)]> use app01; Database changed db01 [app01]> create table t1(id int); Query OK, 0 rows affected (0.05 sec) db01 [app01]> show tables; +-----------------+ | Tables_in_app01 | +-----------------+ | t1 | +-----------------+ 1 row in set (0.00 sec) [root@db02 ~]# mysql -S /data/mysql/3306/mysql.sock -p -e "show tables from app01;" Enter password: +-----------------+ | Tables_in_app01 | +-----------------+ | t1 | +-----------------+ [root@db03 ~]# mysql -S /data/mysql/3306/mysql.sock -p -e "show tables from app01;" Enter password: +-----------------+ | Tables_in_app01 | +-----------------+ | t1 | +-----------------+ #=============================================================================================================================================================================== 更新丢失问题: 建议PXC还是单节点写入,避免更新丢失。 PXC也是存在节点延迟的。 PXC稳定的一逼,太牛逼太稳定了。 它的替代品就是MGR,MGR现在很火。 目前PXC比MGR稳定,MGR性能比PXC高。 PXC整体架构优点: 并行同步复制(一致性强) 多点写入 高性能(乐观锁控制) PXC的复制不是基于binlog的复制,而是基于innodb引擎层来复制。 在PXC里面不能有长事务。 PXC的重要概念: PXC数据复制流程 PXC启动流程new cluster|IST|SST PXC数据冲突 PXC流控制 PXC脑裂 数据库启动 --wsrep-new-cluster 当前是集群中的第一成员,不需要和其他成员协同。 SST(State Snapshot Transfer) mysqldump rsync Xtrabackup(多的比较多的是这个,推荐XBK) IST pxc(xtrabackup) 三个节点不要全关掉 依次关掉,关一个,加入一个,再关另一个节点。 show global status like "%wsrep%"; 集群节点数 3<= cluster size <=8 状态切换 传输 SST:State Snapshot Transfer IST 脑裂 wsrep_local_state = 4 wsrep_local_state_comment = Synced 这两个表示可以对外提供服务 数据冲突 数据可能会在提交步骤失败。 原因:乐观锁控制,能不能执行,依赖于本地的数据判断,最终能不能提交需要集群中成员投票确认。 PXC流控制 pxc性能由集群中最慢的节点决定(针对写性能) 在pxc集群中,当某个节点不能跟上其他节点的写入能力时,这个节点会请求其他节点等待后面的写入,等它追上去。 参数项(wsrep_provider_options) gcs.fc_limit(wsrep_local_recv_queue) gcs.fc_master_slave(no|yes) gcs.fc_factor 动态项 wsrep_flow_control_interval = (N,M)& wsrep_local_recv_queue 脑裂 unkown command 出现的原因:集群中只有两个成员时,两个节点忽然失去联系,自己也搞不清楚当前的集群状态。 PXC一致性读 wsrep_dirty_reads 默认是off 是否允许节点在和集群失去连接时允许有select操作 wsrep_sync_wait 默认是0 PXC中运维注意事项 节点是不是工作OK show global status; wsrep_cluster_status=Primary wsrep_connected=on wsrep_ready=on wsrep_local_state=4 DDL操作 没表级锁 alter table 操作,会把整个集群全锁住,kill不掉的。 解决办法: 等待完成 快速重启 使用pt-online-schema-change操作 PXC复制延迟 引发flow control wsrep_flow_control_sent wsrep_flow_control_recv wsrep_local_recv_queue 调整 wsrep_slave_threads wsrep_max_ws_size & wsrep_max_ws_rows PXC一致性读 wsrep_dirty_reads 默认是off 是否允许节点在和集群失去连接时允许有select操作 wsrep_sync_wait 默认是0 PXC集群重启 建议滚动重启节点,不要一下全部停下来 集群节点离线时间 gcache.size(建议1-4G,要以考虑是一个小时形成的binlog量) gcache.dat mysqld --wsrep-recover 如果机器掉电了,你是启不来的,你需要 cat grastate.dat里面把safe_to_bootstrap:0,把0改成1 PXC监控要点 报警级别 节点是否正常 show global status; wsrep_cluster_status=Primary wsrep_connected=on wsrep_ready=on wsrep_local_cert_failures & wsrep_local_bf_aborts 增长 wsrep_flow_control_sent & wsrep_local_flow_control_recv wsrep_local_recv_queue > 0 存在性能问题 wsrep_local_recv_queue > 0 & wsrep_local_send_queue > 0 节点发送接收的事务量:wsrep_replicated & wsrep_received 节点发送接收的数据量:wsrep_replicated_bytes & wsrep_received_bytes 事务冲突次数:wsrep_local_failures & wsrep_local_bf_aborts 进阶技能 把一个利用主从复制,把从节点加入到pxc集群中 利用复制,把从节点加入pxc集群,减少SST传输 把pxc中一个节点转成一个复制节点 把现有复制结构迁移到pxc环境 集群之间复制 利用复制加入pxc 1.利用备份工具建一个从库 mysqldump innobackupex 2.启动mysqld不加载Galera,追上主库 3.获取slave最后一个relay log或是binary log,推荐是最后一个relay log 4.利用mysqlbinlog获取最后一个事件的Xid mysqlbinlog -j realy-log-pos relay-bin.000003 | grep Xid 5.关闭mysqld,生产grastate.dat,从主节点copy过一个改一下seqno为当前的Xid就行。 PXC限制 只支持innodb引擎 没有表级锁(lock tables,unlock tables) 最大事务操作限制 乐观锁控制,事务尽量快速提交 不支持XA事务 集群最少节点数:3 binlog_rows_query_log_events功能不支持 每个表必须有主键 不支持innodb表空间传出