2022 Zabbix中国峰会
2022 Zabbix中国峰会

3 为数据库升级主键

概述

自Zabbix 6.0起,主键会应用于新安装 Zabbix 数据库的所有表。

在这之前安装过的Zabbix,本章节将提供手动升级所有表主键的说明。

此章节适用于如下数据库:

此页面上提供的说明专为高级用户设计。请注意,这些说明可能需要根据您的特定配置进行调整。

重要提示

  • 确保在升级前备份数据库。
  • 如果数据库使用分区,请联系数据库管理员或 Zabbix 支持团队寻求帮助。
  • 强烈建议在升级时停止 Zabbix 服务器。 但是,如果绝对必要,有一种方法可以在服务器运行时执行升级(仅适用于没有 TimescaleDB 的 MySQL、MariaDB 和 PostgreSQL)。
  • 成功升级到主键后,可以删除 CSV 文件。
  • 可选地,Zabbix 前端可以切换到维护模式
  • 升级到主键应该在将 Zabbix 服务器升级到 6.0 之后完成。
  • 在代理上,未使用的历史表可以通过执行 history_pk_prepare.sql 进行升级。

MySQL

导出和导入必须在 tmux/screen 中执行,以确保会话不会被丢弃。

另请参阅:重要说明

MySQL 8.0+ 和 mysqlsh

此方法可用于正在运行的 Zabbix server,但建议在升级时停止服务器。 MySQL Shell (mysqlsh) 必须 已安装 并且能够连接到数据库。

  • 以 root(推荐)或任何具有 FILE 权限的用户身份登录 MySQL 控制台。

  • 启用 local_infile 变量启动 MySQL。

  • 通过运行 history_pk_prepare.sql 重命名旧表并创建新表。

mysql -uzabbix -p<password> zabbix < /usr/share/zabbix-sql-scripts/mysql/history_pk_prepare.sql
  • 导出和导入数据。

通过 mysqlsh 连接。 如果使用套接字连接,可能需要指定路径。

sudo mysqlsh -uroot -S /run/mysqld/mysqld.sock --no-password -Dzabbix

运行(CSVPATH可根据需要更改):

CSVPATH="/var/lib/mysql-files";
       
       util.exportTable("history_old", CSVPATH + "/history.csv", { dialect: "csv" });
       util.importTable(CSVPATH + "/history.csv", {"dialect": "csv", "table": "history" });
       
       util.exportTable("history_uint_old", CSVPATH + "/history_uint.csv", { dialect: "csv" });
       util.importTable(CSVPATH + "/history_uint.csv", {"dialect": "csv", "table": "history_uint" });
       
       util.exportTable("history_str_old", CSVPATH + "/history_str.csv", { dialect: "csv" });
       util.importTable(CSVPATH + "/history_str.csv", {"dialect": "csv", "table": "history_str" });
       
       util.exportTable("history_log_old", CSVPATH + "/history_log.csv", { dialect: "csv" });
       util.importTable(CSVPATH + "/history_log.csv", {"dialect": "csv", "table": "history_log" });
       
       util.exportTable("history_text_old", CSVPATH + "/history_text.csv", { dialect: "csv" });
       util.importTable(CSVPATH + "/history_text.csv", {"dialect": "csv", "table": "history_text" });

没有 mysqlsh 的 MariaDB/MySQL 8.0+

这种升级方法需要更多时间,只有在无法使用 mysqlsh 进行升级时才应使用。

表升级
  • 以 root(推荐)或任何具有 FILE 权限的用户身份登录 MySQL 控制台。

  • 启用 local_infile 变量启动 MySQL。

  • 通过运行 history_pk_prepare.sql 重命名旧表并创建新表:

mysql -uzabbix -p<password> zabbix < /usr/share/zabbix-sql-scripts/mysql/history_pk_prepare.sql
停止服务器的迁移

max_execution_time 必须在迁移数据之前禁用以避免迁移期间超时。

SET @@max_execution_time=0;
       
       INSERT IGNORE INTO history SELECT * FROM history_old;
       INSERT IGNORE INTO history_uint SELECT * FROM history_uint_old;
       INSERT IGNORE INTO history_str SELECT * FROM history_str_old;
       INSERT IGNORE INTO history_log SELECT * FROM history_log_old;
       INSERT IGNORE INTO history_text SELECT * FROM history_text_old;

遵循#迁移后的说明来废弃旧的表。

运行中的服务器迁移

检查是否启用了导入/导出的路径:

mysql> SELECT @@secure_file_priv;
       +-----------------------+
       | @@secure_file_priv · |
       +-----------------------+
       | /var/lib/mysql-files/ |
       +-----------------------+

如果 secure_file_priv 值是目录路径,则将对该目录中的文件执行导出/导入。 在这种情况下,相应地编辑查询中文件的路径或将secure_file_priv 值设置为升级时间的空字符串。

如果 secure_file_priv 值为空,则可以从任何位置执行导出/导入。

如果 secure_file_priv 值为 NULL,将其设置为包含导出表数据的路径(上例中的“/var/lib/mysql-files/”)。

有关详细信息,请参阅 MySQL 文档

max_execution_time 必须在导出数据之前禁用以避免导出期间超时。

SET @@max_execution_time=0;
       
       SELECT * INTO OUTFILE '/var/lib/mysql-files/history.csv' FIELDS TERMINATED BY ',' ESCAPED BY '"' LINES TERMINATED BY '\n' FROM history_old;
       LOAD DATA INFILE '/var/lib/mysql-files/history.csv' IGNORE INTO TABLE history FIELDS TERMINATED BY ',' ESCAPED BY '"' LINES TERMINATED BY '\n';
       
       SELECT * INTO OUTFILE '/var/lib/mysql-files/history_uint.csv' FIELDS TERMINATED BY ',' ESCAPED BY '"' LINES TERMINATED BY '\n' FROM history_uint_old;
       LOAD DATA INFILE '/var/lib/mysql-files/history_uint.csv' IGNORE INTO TABLE history_uint FIELDS TERMINATED BY ',' ESCAPED BY '"' LINES TERMINATED BY '\n';
       
       SELECT * INTO OUTFILE '/var/lib/mysql-files/history_str.csv' FIELDS TERMINATED BY ',' ESCAPED BY '"' LINES TERMINATED BY '\n' FROM history_str_old;
       LOAD DATA INFILE '/var/lib/mysql-files/history_str.csv' IGNORE INTO TABLE history_str FIELDS TERMINATED BY ',' ESCAPED BY '"' LINES TERMINATED BY '\n';
       
       SELECT * INTO OUTFILE '/var/lib/mysql-files/history_log.csv' FIELDS TERMINATED BY ',' ESCAPED BY '"' LINES TERMINATED BY '\n' FROM history_log_old;
       LOAD DATA INFILE '/var/lib/mysql-files/history_log.csv' IGNORE INTO TABLE history_log FIELDS TERMINATED BY ',' ESCAPED BY '"' LINES TERMINATED BY '\n';
       
       SELECT * INTO OUTFILE '/var/lib/mysql-files/history_text.csv' FIELDS TERMINATED BY ',' ESCAPED BY '"' LINES TERMINATED BY '\n' FROM history_text_old;
       LOAD DATA INFILE '/var/lib/mysql-files/history_text.csv' IGNORE INTO TABLE history_text FIELDS TERMINATED BY ',' ESCAPED BY '"' LINES TERMINATED BY '\n';

按照 迁移后说明 删除旧表。

PostgreSQL

导出和导入必须在 tmux/screen 中执行,以确保会话不会被丢弃。 对于使用 TimescaleDB 的安装,请跳过此部分并继续阅读 PostgreSQL + TimescaleDB

另请参阅:重要说明

表升级

  • 使用 history_pk_prepare.sql 重命名表:
sudo -u zabbix psql zabbix < /usr/share/zabbix-sql-scripts/postgresql/history_pk_prepare.sql

停止服务器的迁移

  • 导出当前历史,将其导入临时表,然后将数据插入新表,同时忽略重复项:
INSERT INTO history SELECT * FROM history_old ON CONFLICT (itemid,clock,ns) DO NOTHING;
       
       INSERT INTO history_uint SELECT * FROM history_uint_old ON CONFLICT (itemid,clock,ns) DO NOTHING;
       
       INSERT INTO history_str SELECT * FROM history_str_old ON CONFLICT (itemid,clock,ns) DO NOTHING;
       
       INSERT INTO history_log SELECT * FROM history_log_old ON CONFLICT (itemid,clock,ns) DO NOTHING;
       
       INSERT INTO history_text SELECT * FROM history_text_old ON CONFLICT (itemid,clock,ns) DO NOTHING;

查看提高 INSERT 性能的技巧:PostgreSQL:批量加载大量数据, 检查点距离 和 WAL 的数量.

迁移正在运行的服务器

  • 导出当前历史,将其导入临时表,然后将数据插入新表,同时忽略重复项:
\copy history_old TO '/tmp/history.csv' DELIMITER ',' CSV
       CREATE TEMP TABLE temp_history (
           itemid                   bigint                                    NOT NULL,
           clock                    integer         DEFAULT '0'               NOT NULL,
           value                    DOUBLE PRECISION DEFAULT '0.0000'          NOT NULL,
           ns                       integer         DEFAULT '0'               NOT NULL
       );
       \copy temp_history FROM '/tmp/history.csv' DELIMITER ',' CSV
       INSERT INTO history SELECT * FROM temp_history ON CONFLICT (itemid,clock,ns) DO NOTHING;
       
       \copy history_uint_old TO '/tmp/history_uint.csv' DELIMITER ',' CSV
       CREATE TEMP TABLE temp_history_uint (
           itemid                   bigint                                    NOT NULL,
           clock                    integer         DEFAULT '0'               NOT NULL,
           value                    numeric(20)     DEFAULT '0'               NOT NULL,
           ns                       integer         DEFAULT '0'               NOT NULL
       );
       \copy temp_history_uint FROM '/tmp/history_uint.csv' DELIMITER ',' CSV
       INSERT INTO history_uint SELECT * FROM temp_history_uint ON CONFLICT (itemid,clock,ns) DO NOTHING;
       
       \copy history_str_old TO '/tmp/history_str.csv' DELIMITER ',' CSV
       CREATE TEMP TABLE temp_history_str (
           itemid                   bigint                                    NOT NULL,
           clock                    integer         DEFAULT '0'               NOT NULL,
           value                    varchar(255)    DEFAULT ''                NOT NULL,
           ns                       integer         DEFAULT '0'               NOT NULL
       );
       \copy temp_history_str FROM '/tmp/history_str.csv' DELIMITER ',' CSV
       INSERT INTO history_str (itemid,clock,value,ns) SELECT * FROM temp_history_str ON CONFLICT (itemid,clock,ns) DO NOTHING;
       
       \copy history_log_old TO '/tmp/history_log.csv' DELIMITER ',' CSV
       CREATE TEMP TABLE temp_history_log (
           itemid                   bigint                                    NOT NULL,
           clock                    integer         DEFAULT '0'               NOT NULL,
           timestamp                integer         DEFAULT '0'               NOT NULL,
           source                   varchar(64)     DEFAULT ''                NOT NULL,
           severity                 integer         DEFAULT '0'               NOT NULL,
           value                    text            DEFAULT ''                NOT NULL,
           logeventid               integer         DEFAULT '0'               NOT NULL,
           ns                       integer         DEFAULT '0'               NOT NULL
       );
       \copy temp_history_log FROM '/tmp/history_log.csv' DELIMITER ',' CSV
       INSERT INTO history_log SELECT * FROM temp_history_log ON CONFLICT (itemid,clock,ns) DO NOTHING;
       
       \copy history_text_old TO '/tmp/history_text.csv' DELIMITER ',' CSV
       CREATE TEMP TABLE temp_history_text (
           itemid                   bigint                                    NOT NULL,
           clock                    integer         DEFAULT '0'               NOT NULL,
           value                    text            DEFAULT ''                NOT NULL,
           ns                       integer         DEFAULT '0'               NOT NULL
       );
       \copy temp_history_text FROM '/tmp/history_text.csv' DELIMITER ',' CSV
       INSERT INTO history_text SELECT * FROM temp_history_text ON CONFLICT (itemid,clock,ns) DO NOTHING;

PostgreSQL + TimescaleDB

导出和导入必须在 tmux/screen 中执行,以确保会话不会被丢弃。Zabbix server 应该在升级期间关闭。

另请参阅:重要说明

  • 使用 history_pk_prepare.sql 重命名表。
sudo -u zabbix psql zabbix < /usr/share/zabbix-sql-scripts/postgresql/history_pk_prepare.sql

路径 history_pk_prepare.sql 已在 Zabbix 6.0.9 后 更改。 对于早于 6.0.9 的版本,应使用以下命令:

sudo -u zabbix psql zabbix < /usr/share/doc/zabbix-sql-scripts/postgresql/history_pk_prepare.sql
  • 运行 TimescaleDB 超表迁移脚本(兼容 TSDB v2.x 和 v1.x 版本),根据压缩设置:
    • 如果启用了压缩(默认安装),则从 /usr/share/zabbix-sql-scripts/postgresql/tsdb_history_pk_upgrade_with_compression 运行脚本:

      cat /usr/share/zabbix-sql-scripts/postgresql/tsdb_history_pk_upgrade_with_compression/history_pk.sql | sudo -u zabbix psql zabbix
             cat /usr/share/zabbix-sql-scripts/postgresql/tsdb_history_pk_upgrade_with_compression/history_pk_uint.sql | sudo -u zabbix psql zabbix
             cat /usr/share/zabbix-sql-scripts/postgresql/tsdb_history_pk_upgrade_with_compression/history_pk_log.sql | sudo -u zabbix psql zabbix
             cat /usr/share/zabbix-sql-scripts/postgresql/tsdb_history_pk_upgrade_with_compression/history_pk_str.sql | sudo -u zabbix psql zabbix
             cat /usr/share/zabbix-sql-scripts/postgresql/tsdb_history_pk_upgrade_with_compression/history_pk_text.sql | sudo -u zabbix psql zabbix
    • 如果禁用用压缩,则从 /usr/share/zabbix-sql-scripts/postgresql/tsdb_history_pk_upgrade_no_compression运行脚本:

      cat /usr/share/zabbix-sql-scripts/postgresql/tsdb_history_pk_upgrade_no_compression/history_pk.sql | sudo -u zabbix psql zabbix
             cat /usr/share/zabbix-sql-scripts/postgresql/tsdb_history_pk_upgrade_no_compression/history_pk_uint.sql | sudo -u zabbix psql zabbix
             cat /usr/share/zabbix-sql-scripts/postgresql/tsdb_history_pk_upgrade_no_compression/history_pk_log.sql | sudo -u zabbix psql zabbix
             cat /usr/share/zabbix-sql-scripts/postgresql/tsdb_history_pk_upgrade_no_compression/history_pk_str.sql | sudo -u zabbix psql zabbix
             cat /usr/share/zabbix-sql-scripts/postgresql/tsdb_history_pk_upgrade_no_compression/history_pk_text.sql | sudo -u zabbix psql zabbix

另请参阅: 提示 以提高 INSERT 性能。

Oracle

导出和导入必须在 tmux/screen 中执行,以确保会话不会被丢弃。Zabbix 服务器应该在升级期间关闭。

另请参阅:重要说明

表升级

有关性能提示,请参阅 Oracle Data Pump 文档

  • 使用 history_pk_prepare.sql 重命名表。
cd /usr/share/zabbix/zabbix-sql-scripts/database/oracle
       sqlplus zabbix/password@oracle_host/service
       sqlplus> @history_pk_prepare.sql

历史表批量迁移

  • 为 Data Pump 准备目录。

Data Pump 必须具有这些目录的读写权限。

示例:

mkdir -pv /export/history
       chown -R oracle:oracle /export
  • 创建一个目录对象,并授予此对象读写权限给用于 Zabbix 认证的用户(以下示例中为 'zabbix')。在 sysdba 角色下运行:
create directory history as '/export/history';
       grant read,write on directory history to zabbix;
  • 导出表。 将 N 替换为所需的线程数。
expdp zabbix/password@oracle_host/service \
           DIRECTORY=history \
           TABLES=history_old,history_uint_old,history_str_old,history_log_old,history_text_old \
           PARALLEL=N
  • 导入表。 将 N 替换为所需的线程数。
impdp zabbix/password@oracle_host/service \
           DIRECTORY=history \
           TABLES=history_uint_old \
        REMAP_TABLE=history_old:history,history_uint_old:history_uint,history_str_old:history_str,history_log_old:history_log,history_text_old:history_text \
           data_options=SKIP_CONSTRAINT_ERRORS table_exists_action=APPEND  PARALLEL=N CONTENT=data_only

历史表的单独迁移

  • 为每个历史表准备 Data Pump 目录。 Data Pump 必须具有这些目录的读写权限。

示例:

mkdir -pv /export/history /export/history_uint /export/history_str /export/history_log /export/history_text
       chown -R oracle:oracle /export
  • 创建一个目录对象,并授予该对象读写权限给用于 Zabbix 认证的用户(以下示例中的 'zabbix')。在 sysdba 角色下运行:
create directory history as '/export/history';
       grant read,write on directory history to zabbix;
       
       create directory history_uint as '/export/history_uint';
       grant read,write on directory history_uint to zabbix;
       
       create directory history_str as '/export/history_str';
       grant read,write on directory history_str to zabbix;
       
       create directory history_log as '/export/history_log';
       grant read,write on directory history_log to zabbix;
       
       create directory history_text as '/export/history_text';
       grant read,write on directory history_text to zabbix;
  • 导出和导入每个表。 将 N 替换为所需的线程数。
expdp zabbix/password@oracle_host:1521/xe DIRECTORY=history TABLES=history_old PARALLEL=N
       
       impdp zabbix/password@oracle_host:1521/xe DIRECTORY=history TABLES=history_old REMAP_TABLE=history_old:history data_options=SKIP_CONSTRAINT_ERRORS table_exists_action=APPEND PARALLEL=N CONTENT=data_only
       
       expdp zabbix/password@oracle_host:1521/xe DIRECTORY=history_uint TABLES=history_uint_old PARALLEL=N
       
       impdp zabbix/password@oracle_host:1521/xe DIRECTORY=history_uint TABLES=history_uint_old REMAP_TABLE=history_uint_old:history_uint data_options=SKIP_CONSTRAINT_ERRORS table_exists_action=APPEND PARALLEL=N CONTENT=data_only
       
       expdp zabbix/password@oracle_host:1521/xe DIRECTORY=history_str TABLES=history_str_old PARALLEL=N
       
       impdp zabbix/password@oracle_host:1521/xe DIRECTORY=history_str TABLES=history_str_old REMAP_TABLE=history_str_old:history_str data_options=SKIP_CONSTRAINT_ERRORS table_exists_action=APPEND PARALLEL=N CONTENT=data_only
       
       expdp zabbix/password@oracle_host:1521/xe DIRECTORY=history_log TABLES=history_log_old PARALLEL=N
       
       impdp zabbix/password@oracle_host:1521/xe DIRECTORY=history_log TABLES=history_log_old REMAP_TABLE=history_log_old:history_log data_options=SKIP_CONSTRAINT_ERRORS table_exists_action=APPEND PARALLEL=N CONTENT=data_only
       
       expdp zabbix/password@oracle_host:1521/xe DIRECTORY=history_text TABLES=history_text_old PARALLEL=N
       
       impdp zabbix/password@oracle_host:1521/xe DIRECTORY=history_text TABLES=history_text_old REMAP_TABLE=history_text_old:history_text data_options=SKIP_CONSTRAINT_ERRORS table_exists_action=APPEND PARALLEL=N CONTENT=data_only

迁移后

对于所有数据库,迁移完成后,执行以下操作:

  • 验证一切是否按预期工作。

  • 删除旧表:

DROP TABLE history_old;
       DROP TABLE history_uint_old;
       DROP TABLE history_str_old;
       DROP TABLE history_log_old;
       DROP TABLE history_text_old;