芬达,《芬达的数据库学习笔记》大众号作者,开源爱好者,拿手 MySQL、ansible。

布景

openEuler 是什么

openEuler22.03 LTS 是 openEuler 社区于 2022 年 3 月发布的开源操作体系(从体系版别的命名不难发现吧)。openEuler 社区的运营由华为为主导,社区以全球开源奉献者的协作,构建了这个高效、安稳和安全的操作体系。依据 Linux 内核的 openEuler 操作体系,支撑 Kunpeng 以及其他处理器,旨在充分发挥核算芯片的潜力。它适用于数据库、大数据、云核算和人工智能等场景。经过社区协作,openEuler 构建了一个立异平台,创立了一个支撑多处理器架构的统一敞开操作体系,并推动了软件和硬件运用生态体系的昌盛。

openEuler22.03 LTS 带来了一系列关键功用,包括依据 Linux Kernel 5.10 的深度优化、新式媒体文件体系、分层内存扩展、用户模式协议栈、云原生调度增强、QEMU 热补丁、KubeOS、增强的轻量级安全容器、增强的 iSulad、双平面布置、边缘核算支撑、嵌入式镜像,以及 secPaver 等。

openEuler22.03 LTS 能够被视为国产操作体系立异项目的首选体系版别之一。

GreatSQL 是什么

GreatSQL,作为 MySQL 分支 Percona 的延伸,立志成为我国广泛受欢迎的开源数据库。其上一版别依据 Percona Server 8.0.25 构建,而这次的新版别则运用 Percona Server 8.0.32 作为基础,引入了许多重要特性。新发布的 GreatSQL 8.0.32-24 版别增加了并行 load data、逻辑和 CLONE 备份加密、MGR 读写节点可动态绑定 VIP、SQL 兼容扩展、审计日志增强等严重特性。

GreatSQL 8.0.32-24 能够被视为国产开源数据库信创项目,并且处理 MySQL5.7 EOL 问题的重要代替计划之一。

关于 MySQL5.7 EOL 问题,能够翻阅我之前写的文章《阴谋论: MySQL 将死,国产数据库的春天?》

dbops 是什么

dbops 是一款提供出产等级 MySQL 布置的 playbook 工具,由芬达个人开发。

地址: gitee.com/fanderchan/…

GreatSQL 官方并未提供专门针对 openEuler 的编译装置包,而我发现布置 GreatSQL、GreatSQL MGR、GreatSQL HA 等都有许多细节需求注意。本文首要叙述我怎么思考并开发 dbops 的新功用,以在 openEuler22 上成功布置 GreatSQL,并运行其”MGR 读写节点可动态绑定 VIP”功用(以下简称”GreatSQL HA 功用”)。

dbops 怎么支撑 GreatSQL

dbops 本来就支撑 MySQL 和 Percona,所以对 GreatSQL 的支撑并不需求大规模的改动。以下大部分是一些针对布置 GreatSQL 与 MySQL 或 Percona 的不同之处的调整。

1. 只对 Linux – Generic 包的支撑

由于 dbops 的目标是支撑大量的国产操作体系,与 MySQL 一样,GreatSQL 提供了针对各种操作体系的预编译二进制包,但有一个是通用的,那就是 Linux – Generic 包。在 dbops 为 MySQL 提供支撑以及在实践出产中,都在运用这个包。

一起,为了支撑更多的 Linux 体系,我挑选了依据 glibc2.17 的包,而非 glibc2.28 的包。前者意味着包是在 glibc 公共库版别为 2.17 的体系下编译出来的,因而,它不会包括大于 2.17 的库函数,兼容性会更强。

我挑选支撑的是 minimal 包,这个版别剔除了与调试相关的二进制文件和调试符号,体积非常小,仅为常规包的三分之一,我认为非 minimal 包并无优势。

现在,dbops 仅支撑 GreatSQL-8.0.32-24-Linux-glibc2.17-x86_64.tar.xz 的布置。

2. dbops 的 mysql_ansible 的装备文件 common_config.yml 的调整

dbops 能够很方便的装备履行 playbook 的变量,变量设置非常会集,一般只需求修正两个文件,一个是大局参数装备文件 common_config.yml,另外一个是当前需求履行的 playbook yaml 文件。

  • 新增了 db_type 参数,用于判别待布置的数据库类型,可选值为 MySQL、Percona、GreatSQL。依据 db_type 的不同,布置流程将有所区别。
  • 将 mysql_base_dir 参数和 mysql_data_dir_base 参数设定为依据 db_type 主动生成,这样能够得到不同的目录途径。我希望避免将 MySQL 和 GreatSQL 放置在同一目录下,以便于区别。
  • 关于 mysql_package 参数,即装置包的称号,假如是 MySQL,会依据 {{ mysql_version }} 主动生成;假如是 GreatSQL,将读取 greatsql_package 的设置。
  • 新增了 fcs_use_greatsql_ha 开关参数,其默许值为 1,即假如布置的是 GreatSQL 并且选用 MGR 架构(履行的 playbook==mgr.yml),那么默许会布置”MGR 读写节点可动态绑定 VIP”的功用插件。
## DB TYPE,suport mysql,percona,greatsql
+ db_type: greatsql
#Directory of MySQL installation package
mysql_packages_dir: ../downloads/ 
+ greatsql_package: GreatSQL-8.0.32-24-Linux-glibc2.17-x86_64-minimal.tar.xz
+ percona_package: Percona-Server-8.0.29-21-Linux.x86_64.glibc2.17.tar.gz
## do not modify
- mysql_package: "{{ 'mysql-' + mysql_version + '-linux-' + ('glibc2.12' if mysql_version.startswith('5.') else 'glibc2.17') + '-x86_64' + ('.tar.gz' if mysql_version.startswith('5.') else '-minimal.tar.xz') }}"
+ mysql_package: "{% if db_type == 'mysql' %}{{ 'mysql-' + mysql_version + '-linux-' + ('glibc2.12' if mysql_version.startswith('5.') else 'glibc2.17') + '-x86_64' + ('.tar.gz' if mysql_version.startswith('5.') else '-minimal.tar.xz') }}{% elif db_type == 'percona' %}{{ percona_package }}{% elif db_type == 'greatsql' %}{{ greatsql_package }}{% endif %}"
## linux mysql run user name
mysql_user: mysql
mysql_group: mysql
mysql_user_password: Dbops@9999
## mysql install directory
- mysql_base_dir: /database/mysql/base/{{ mysql_version }}
+ mysql_base_dir: /database/{{ db_type }}/base/{{ mysql_version }}
## mysql_data_dir_base define mysql datadir base, real datadir= mysql_data_dir_base + /port
- mysql_data_dir_base: /database/mysql
+ mysql_data_dir_base: /database/{{ db_type }}
+ fcs_use_greatsql_ha: 1

3. 新增 GreatSQL 专属 my.cnf 模板,并对 GreatSQL HA 的新参数支撑

在 mgr.yml 这个 playbook 里新增三个与 GreatSQL HA 相关的参数设置

+ greatsql_vip: 192.168.199.174
+ greatsql_net_work_interface: "ens33"
+ greatsql_netmast: "255.255.255.255"

新增了 mysql_ansible/roles/mysql_server/templates/8.0/greatsql-my.cnf.j2 模板,此模板是从 percona-my.cnf.j2 模板克隆而来。为了支撑 GreatSQL HA 的相关参数设置,我运用 jinja2 语法设置了判别逻辑,只要满意以下三个条件,才会增加这些参数:

  • 数据库类型为 ‘greatsql’ (在 common_config.yml 中设置)
  • 设置了 fcs_use_greatsql_ha: 1 开关,要求布置 GreatSQL HA 功用(在 common_config.yml 中设置)
  • 在装置 MGR 时(运行 ansible-playbook mgr.yml 时)
+ {% if db_type == 'greatsql' and fcs_use_greatsql_ha == 1 and make_mgr_role_included is defined and make_mgr_role_included %}
+ #GreatSQL MGR vip
+ plugin-load-add=greatdb_ha.so
+ loose-greatdb_ha_enable_mgr_vip=1
+ loose-greatdb_ha_mgr_vip_ip={{ greatsql_vip }}
+ loose-greatdb_ha_mgr_vip_mask={{ greatsql_netmast }}
+ loose-greatdb_ha_mgr_vip_nic={{ greatsql_net_work_interface }}
+ 
+ #single-primary mode
+ loose-group_replication_single_primary_mode=1
+ loose-group_replication_enforce_update_everywhere_checks=0
+ {% endif %}

前面设置的三个参数值,greatsql_vip、greatsql_netmast、greatsql_net_work_interface 会对应传入到 my.cnf 里。

4. 支撑主动下载 GreatSQL 装置包

+ - name: Download GreatSQL binary tarball if not found locally and auto download is enabled(local)
+   ansible.builtin.get_url:
+     url: "https://product.greatdb.com/{{ mysql_package[0:18] }}/{{ mysql_package }}"
+     dest: "{{ mysql_packages_dir }}/{{ mysql_package }}"
+     mode: '0644'
+     timeout: 30
+     headers:
+       User-Agent: "Wget/1.21.1"
+   when: not mysql_server__package_file.stat.exists and fcs_auto_download_mysql == 1 and db_type == 'greatsql'
+   delegate_to: 127.0.0.1

在正常情况下,您应该手动上传 GreatSQL 的包到 downloads/ 文件夹中。假如在 downloads/ 文件夹中没有找到对应的包,且在 common_config.yml 文件中设置了 fcs_auto_download_mysql == 1(答应从互联网下载装置包),并且 db_type == ‘greatsql’,那么将会主动从互联网下载装置包。

dbops 自身就支撑下载 MySQL 装置包的功用。但由于 GreatSQL 的装置包下载途径不同,因而我额外增加了一个下载链接,以完成相同的下载功用。

5. 修正 GreatSQL 发动服务

为了让 GreatSQL HA 支撑 mysqld 履行通常需求较高权限才干操作的挂载和卸载 VIP 操作,咱们需求进行一些特殊设置。官方原先提供了两个计划,但我提出了新的处理计划。

在服务设置中,咱们参加以下代码:

[Service]
+ {% if db_type == 'greatsql' and fcs_use_greatsql_ha == 1 and make_mgr_role_included is defined and make_mgr_role_included %}
+ AmbientCapabilities=CAP_NET_ADMIN CAP_NET_RAW
+ {% endif %}

只要当满意条件(需求布置 GreatSQL HA)时,体系会主动在发动服务中装备 “CAP_NET_ADMIN CAP_NET_RAW” 的权限。

![图片](data:image/svg+xml,%3C%3Fxml version=’1.0′ encoding=’UTF-8’%3F%3E%3Csvg width=’1px’ height=’1px’ viewBox=’0 0 1 1′ version=’1.1′ xmlns=’www.w3.org/2000/svg’ xmlns:xlink=’www.w3.org/1999/xlink’… stroke=’none’ stroke-width=’1′ fill=’none’ fill-rule=’evenodd’ fill-opacity=’0’%3E%3Cg transform=’translate(-249.000000, -126.000000)’ fill=’%23FFFFFF’%3E%3Crect x=’249′ y=’126′ width=’1′ height=’1’%3E%3C/rect%3E%3C/g%3E%3C/g%3E%3C/svg%3E)

我设计的这种办法也得到了官方的采纳,成为首选引荐办法。

6. fix 布置 GreatSQL 有可能报错的问题

GreatSQL 在布置后可能在运用 mysqld 初始化时,或许初始化后运用 mysql 登录时,陈述 libcrypto.so 或 libssl.so 找不到。

[root@192-168-199-171 ~]# /usr/local/mysql/bin/mysqld --defaults-file=/database/mysql/etc/3306/my.cnf --initialize-insecure
/usr/local/mysql/bin/mysqld: error while loading shared libraries: libcrypto.so: cannot open shared object file: No such file or directory
[root@192-168-199-171 lib]# mysql -uroot -p -S /database/mysql/data/3307/mysql.sock
mysql: error while loading shared libraries: libssl.so: cannot open shared object file: No such file or directory

针对此问题,咱们有两种处理计划。第一种办法是运用 yum install openssl-devel 装置,之后体系库就会包括这两个 so 库:

/usr/lib64/libcrypto.so
/usr/lib64/libssl.so

但是,咱们也有第二种处理办法。GreatSQL 的 Generic 包其完成已编译了这两个库,仅仅它们被命名为 libcrypto.so.10 和 libssl.so.10,而非 libcrypto.so 和 libssl.so。咱们只需在 /usr/local/mysql/lib/private/ 文件夹内为这两个库创立软链接即可。

并且,我认为选用第二种办法,运用官方包内的 libcrypto.so 和 libssl.so,是最佳的处理计划。

改动代码如下:

mysql_ansible/roles/mysql_server/tasks/fix_greatsql_install.yml

+ - name: Create symbolic links for libssl.so and libcrypto.so
+   file:
+     src: "/usr/local/mysql/lib/private/{{ link.src }}"
+     dest: "/usr/local/mysql/lib/private/{{ link.dest }}"
+     state: link
+     owner: "{{ mysql_user }}"
+     group: "{{ mysql_group }}"
+   loop:
+     - { src: 'libssl.so.10', dest: 'libssl.so' }
+     - { src: 'libcrypto.so.10', dest: 'libcrypto.so' }
+   loop_control:
+     loop_var: link

mysql_ansible/roles/mysql_server/tasks/main.yml

  - name: Install mysql to /usr/local/mysql
    ansible.builtin.import_tasks: install_mysql.yml
+ - name: Fix libcrypto.so and libssl.so not find by create link if db_type is greatsql
+   ansible.builtin.import_tasks: fix_greatsql_install.yml
+   when: db_type == 'greatsql'
  - name: Init mysql datadir
    ansible.builtin.import_tasks: initialize_mysql_datadir.yml

7. 查看网卡是否共同

在设定了 VIP 漂移的三台机器中,与 MHA 架构相同,咱们可能会遇到一种状况:在一开始设置网卡绑定时,主机管理员可能会没注意,产生以下情况:

192.168.199.171  网卡名 bond1
192.168.199.172  网卡名 bond1
192.168.199.173  网卡名 bond0

你可能现已发现了,第三台机器的网卡名与前两台不共同。因而,假如产生高可用漂移,MHA 或 MGR 在挑选主机时,假如挑选了第三台作为主机,那么依据 greatsql_net_work_interface: "bond1" 的设置,漂移操作可能会失利。虽然我还没有进行过测验,但这个问题在 MHA 架构中肯定会产生,并且在 GreatSQL HA 架构中也有很大可能产生!

因而,在运行 ansible-playbook 布置 mgr.yml 时,我已在第一步的 pre_check_and_set(查看和设置体系参数)中,参加了查看网卡名是否共同的步骤。假如网卡名不共同,playbook 将报错并停止运行,给出提示。代码如下:

- name: Add network interface alias to a temporary file
  ansible.builtin.lineinfile:
    path: "/tmp/net_aliases.txt"
    line: "{{ ansible_default_ipv4.alias }}"
    create: true
    mode: '0644'
- name: Fetch copy
  ansible.builtin.fetch:
    src: /tmp/net_aliases.txt
    dest: /tmp/ssh
- name: Append file /tmp/net_aliases.txt (delegate to 127.0.0.1)
  ansible.builtin.shell: set -o pipefail && find /tmp/ssh/ -name "*.txt" -type f -exec sh -c 'cat {}' \; | sort | uniq | wc -l
  register: pre_check_and_set__shell_output
  changed_when: false
  run_once: true
  delegate_to: 127.0.0.1
- name: Check if shell output is 1
  ansible.builtin.assert:
    that: pre_check_and_set__shell_output.stdout | int == 1
    fail_msg: "Network card names are different!"
  run_once: true
  delegate_to: 127.0.0.1
- name: Delete /tmp/net_aliases.txt
  ansible.builtin.file:
    path: /tmp/net_aliases.txt
    state: absent
- name: Delete /tmp/ssh/ (delegate to 127.0.0.1)
  ansible.builtin.file:
    path: /tmp/ssh/
    state: absent
  run_once: true
  delegate_to: 127.0.0.1

8. 支撑运用 jemalloc 内存分配器

GreatSQL 和 Percona 官方都引荐运用 jemalloc 代替默许的 malloc,我至今没有发现 MySQL 官方的相似主张。但是,在实践中,我曾经经过替换 malloc 为 jemalloc 内存管理器来处理内存走漏问题,虽然根本原因仍不清楚。因而,我之前现已在我的 dbops 工具中参加了在布置时挑选运用 jemalloc 内存分配器的功用,它是在 systemd 服务中完成的。

以下是涉及的代码:

mysql_ansible/playbooks/common_config.yml

# 装备文件中提供一个开关,决议是否运用 jemalloc 内存分配器,其默许值为 0,即不修正内存分配器
fcs_mysql_use_jemalloc: 1

mysql_ansible/roles/mysql_server/tasks/install_mysql_dependents.yml

- name: Install libaio and numactl
  ansible.builtin.yum:
    name: "{{ package.name }}"
    state: present
  loop:
    - { name: 'libaio' }
    - { name: 'numactl' }
  loop_control:
    loop_var: package
  tags:
    - dependents
- name: Install jemalloc
  when: fcs_mysql_use_jemalloc == 1
  tags:
    - dependents
  block:
    - name: Install jemalloc using yum
      ansible.builtin.yum:
        name: jemalloc
        state: present
      register: mysql_server__jemalloc_install_result
      ignore_errors: true
    - name: Set jemalloc rpm file name based on OS
      ansible.builtin.set_fact:
        mysql_server__jemalloc_rpm_file: "{{ 'jemalloc-3.6.0-1.el8.x86_64.rpm' if os_type in ['openEuler22', 'openEuler20', 'CentOS8', 'BigCloud8', 'Anolis OS8'] else 'jemalloc-3.6.0-1.el7.x86_64.rpm' }}"
    - name: Copy jemalloc rpm to target server
      ansible.builtin.copy:
        src: "../files/{{ mysql_server__jemalloc_rpm_file }}"
        dest: "/tmp/{{ mysql_server__jemalloc_rpm_file }}"
        mode: '0755'
      when: mysql_server__jemalloc_install_result.failed
    - name: Install jemalloc from local file
      ansible.builtin.yum:
        name: "/tmp/{{ mysql_server__jemalloc_rpm_file }}"
        state: present
        disable_gpg_check: true
      register: mysql_server__jemalloc_local_install_result
      when: mysql_server__jemalloc_install_result.failed
      ignore_errors: true
    - name: Check if jemalloc installation failed
      ansible.builtin.fail:
        msg: "Failed to install jemalloc"
      when: mysql_server__jemalloc_install_result.failed and mysql_server__jemalloc_local_install_result.failed

这段代码首要是用于装置 mysql_server 的依赖包,假如你在装备中设置了 fcs_mysql_use_jemalloc: 1,那么将会装置 jemalloc。默许情况下,它会测验运用 yum 来装置。假如 yum 装置失利,那么它会测验运用 dbops 自带的 jemalloc 包。

原因是,预备的 jemalloc 包只要两个版别:一个是针对 EL7,一个是针对 EL8。并没有专门为国产操作体系预备的专用包。在国产操作体系上,你应该优先运用 yum 来装置适合该体系的包。假如运用 yum 装置失利,你能够考虑运用 EL7 或许 EL8 的 jemalloc 包来进行兼容性装置。

mysql_ansible/roles/mysql_server/templates/mysql.service.j2

[Service]
...
{% if fcs_mysql_use_jemalloc == 1 %}
{% if os_type in ['openEuler22','openEuler20'] %}
Environment="LD_PRELOAD=/usr/lib64/libjemalloc.so.2"
{% else %}
Environment="LD_PRELOAD=/usr/lib64/libjemalloc.so.1"
{% endif %}
{% endif %}

依据 yum 或许 rpm 包方式装置 libjemalloc 后,不同操作体系的 libjemalloc.so 途径可能会不同,我在服务装备里会做判别和正确加载。

结语与反应征集

假如你对 dbops 感兴趣,欢迎你运用,并提出名贵的主张或问题。假如在运用过程中遇到任何问题,或有任何改进的主张,欢迎在 dbops 的 gitee 项目页面上提交 issue。你的反应将协助我不断改进,使其更好地服务于所有开源数据库用户。

我会认真处理每一个提交的 issue,力求在第一时间给出解答或处理计划。一起,咱们也欢迎你为 dbops 的开发做出奉献,无论是提交代码,还是参与评论,我都非常欢迎。感谢你的支撑!

Enjoy GreatSQL :)

关于 GreatSQL

GreatSQL是由万里数据库维护的MySQL分支,专注于提高MGR可靠性及性能,支撑InnoDB并行查询特性,是适用于金融级运用的MySQL分支版别。

相关链接: GreatSQL社区 Gitee GitHub Bilibili

GreatSQL社区:

openEuler22+GreatSQL+dbops玩转MGR

社区有奖主张反应: greatsql.cn/thread-54-1…

社区博客有奖征稿详情: greatsql.cn/thread-100-…

社区2022年度勋章获奖名单: greatsql.cn/thread-184-…

(对文章有疑问或许有独到见解都能够去社区官网提出或共享哦~)

技术交流群:

微信&QQ群:

QQ群:533341697

微信群:增加GreatSQL社区助手(微信号:wanlidbc )好友,待社区助手拉您进群。