本文讲述如何使用现有开源社区资源完成MySQL数据库分区。如果你想深入了解关于Zabbix MySQL数据库分区的更多知识,欢迎阅读下文。

本文内容适用于所有主要的MySQL版本,包括MySQL 8、MariaDB以及其他MySQL分支版本。因此不管你使用何种版本,本文都可以帮到你。

目录

  • 概述
  • 如何实现
    • 数据库分区
    • 设置Perl脚本
    • 使用存储过程
    • 禁用Zabbix housekeeper
  • 总结

如需本文的视频版本,可以访问 Zabbix YouTube English:https://youtube/KbwloPasMYI

概述

一旦你的Zabbix服务达到一定规模,Zabbix自身的housekeeper功能就无法有效地清理过期数据。这是因为Zabbix的housekeeper功能需要从数据库中查找每一行过期的数据记录并删除它,过期时间的判断规则遵从Zabbix前端页面的设置。housekeeper需要逐个搜索每一条历史数据记录和趋势数据记录,这在MySQL数据库规模很大的情况无疑会导致性能差、速度慢。当此种情况发生时,housekeeper的性能表现有可能如下图所示(持续100%繁忙)。

你会发现Zabbix housekeeper进程持续地100%繁忙,并且数据库的数据量不断地增长。对于PostgreSQL数据库,Zabbix提供了内置的解决方案——即TimescaleDB,但是对于MySQL数据库Zabbix并没有提供类似的解决方案。不过幸好有一种非常有效的解决方案可以通过MySQL数据库分区实现,本文下面就对此进行讲解。

MySQL分区是以时间为单位将数据拆分为一系列的块(chunk)。这样一来,一旦某个块中的数据过期(超出设定的保留时长),就可以非常方便地直接将整个块删掉。相较于逐个查找数据记录,这种删除块的操作要快速得多。

现在我们开始动手试一下吧!

如果你想获取与本文有关或者类似的更多Zabbix实践,欢迎阅读我们的Zabbix书籍:

https://www.packtpub.com/product/zabbix-6-it-infrastructure-monitoring-cookbook-second-edition/9781803246918

https://www.amazon.com/Zabbix-Infrastructure-Monitoring-Cookbook-maintaining/dp/180324691X/

如果你想获取与本文类似的更多资源,请访问我们的GitHub:

https://github.com/OpensourceICTSolutions/

 

如何实现

要实现上述方案,我们需要登录Zabbix数据库并进行分区。在此之前,请确保已经停止Zabbix服务进程,或者将数据库复制到另一台服务器上进行分区。如果你不清楚如何复制数据库,可以查阅以下关于MySQL dump和MySQL导入的文档:

https://mariadb.com/kb/en/mysqldump/

https://mariadb.com/kb/en/mariadb-import/

不管使用哪种方法,请一定备份你的数据库。虽然不常见,但是在数据库上执行大规模修改时发生数据损坏并不是不可能。

为了避免在分区过程中出现MySQL存储空间不足的情况,请确保有充足的剩余空间。如果分区过程中出现空间已满的情况,可能会导致数据损坏。使用以下命令查看剩余空间:

df -h

数据库分区

一旦停止了Zabbix服务进程或者已经将数据库复制到了另一台服务器上,我们就可以开始分区了。在开始分区之前我们要注意,创建分区可能是非常耗时的一个过程,在大型数据库上甚至需要几天时间。所以,一定要使用tmux来运行分区命令。安装tmux:

dnf install tmux

或者在Debian系统中

apt-get install tmux

现在,我们可以运行tmux命令来打开一个tmux会话:

tmux

该命令会打开一个终端,即使在ssh会话超时的情况下,这个终端也不会关闭。现在我们开始分区。

我们将对以下表进行分区:

表名 作用 数据类型
history 存储原始的历史数据 数字(浮点数)
history_uint 存储原始的历史数据 数字(无符号)
history_str 存储原始的短字符串数据 字符型
history_text 存储原始的长字符串数据 文本
history_log 存储原始的日志字符串数据 日志
history_bin 在此表中存储二进制数据 二进制
trends 存储每小时统计数据(趋势) 数字(浮点数)
trends_uint 保持每小时统计数据(趋势) 数字(无符号)

使用以下命令登录MySQL以开始进行分区:

mysql -u root -p

因为分区是基于时间的,所以我们需要知道每个表中时间戳最小的数据记录。我们需要为每个表执行一个SQL语句,首先是:

SELECT FROM_UNIXTIME(MIN(clock)) FROM history_uint;

为每个表执行以上语句,执行时将history_uint修改为对应的表名。执行语句后记下每个表的返回结果,在后面定义分区时需要用到。返回结果是一个时间戳,该时间戳是我们需要创建的最早的分区。在此示例中,我将使用2020-12-19,正好是作者撰写本文时间(2021-02-19)再往前两个月。

现在我们需要准备分区语句了。我们的历史(history)表按天进行分区,趋势(trends)表按月进行分区。

我们从history_uint表开始:

ALTER TABLE history_uint PARTITION BY RANGE ( clock)
(PARTITION p2020_12_19 VALUES LESS THAN (UNIX_TIMESTAMP("2020-12-20 00:00:00")) ENGINE = InnoDB,
PARTITION p2020_12_20 VALUES LESS THAN (UNIX_TIMESTAMP("2020-12-21 00:00:00")) ENGINE = InnoDB,
PARTITION p2020_12_21 VALUES LESS THAN (UNIX_TIMESTAMP("2020-12-22 00:00:00")) ENGINE = InnoDB,
PARTITION p2020_12_22 VALUES LESS THAN (UNIX_TIMESTAMP("2020-12-23 00:00:00")) ENGINE = InnoDB,
…
PARTITION p2021_02_18 VALUES LESS THAN (UNIX_TIMESTAMP("2021-02-19 00:00:00")) ENGINE = InnoDB,
PARTITION p2021_02_19 VALUES LESS THAN (UNIX_TIMESTAMP("2021-02-20 00:00:00")) ENGINE = InnoDB,
PARTITION p2021_02_20 VALUES LESS THAN (UNIX_TIMESTAMP("2021-02-21 00:00:00")) ENGINE = InnoDB,
PARTITION p2021_02_21 VALUES LESS THAN (UNIX_TIMESTAMP("2021-02-22 00:00:00")) ENGINE = InnoDB,
PARTITION p2021_02_22 VALUES LESS THAN (UNIX_TIMESTAMP("2021-02-23 00:00:00")) ENGINE = InnoDB);

请确保每天添加一个分区——上面的语句中省略了部分日期(省略号位置)。

你会看到我们使用了最早时间戳,也就是2020-12-19,来定义第一个分区。而最后一个分区的时间是2021-02-22,比当前时间(2021-02-19)往后3天。这就是我们定义分区范围的方式。请确保使用你自己的时间戳定义分区,也就是在第一步执行的SQL语句中获取的时间戳。请注意,有可能每个表的时间戳是不同的。

你需要为每个历史数据表准备相同的语句,然后再为趋势表准备语句。提示:在执行任何操作之前先写下本文中使用的所有命令,这将使操作过程更方便一些。

对于趋势表,我们仍然使用第一步获取的时间戳,即2020-12-19。所以,我们需要处理的是2020年12月及以后的所有数据。trends_uint表的分区语句如下所示:

ALTER TABLE trends_uint PARTITION BY RANGE ( clock)
(PARTITION p2020_10 VALUES LESS THAN (UNIX_TIMESTAMP("2020-11-01 00:00:00")) ENGINE = InnoDB,
PARTITION p2020_11 VALUES LESS THAN (UNIX_TIMESTAMP("2020-12-01 00:00:00")) ENGINE = InnoDB,
PARTITION p2020_12 VALUES LESS THAN (UNIX_TIMESTAMP("2021-01-01 00:00:00")) ENGINE = InnoDB,
PARTITION p2021_01 VALUES LESS THAN (UNIX_TIMESTAMP("2021-02-01 00:00:00")) ENGINE = InnoDB,
PARTITION p2021_02 VALUES LESS THAN (UNIX_TIMESTAMP("2021-03-01 00:00:00")) ENGINE = InnoDB,
PARTITION p2021_03 VALUES LESS THAN (UNIX_TIMESTAMP("2021-04-01 00:00:00")) ENGINE = InnoDB);

可见,这里我们按月而不是按天进行分区,这种分区方式更适合于趋势表。别忘了对所有趋势表,也就是trends表和trends_uint表,进行同样的操作,使用的时间戳同样是第一步时你获取的时间戳。

至此,我们已经为每个表准备好了MySQL语句,可以将其复制到MySQL终端去执行了(每次只执行一个表)。别忘了使用前面提到的tmux命令,还要有一些耐心,对于较大的数据库,每个表可能需要几天时间。这就是为什么我总是建议在一开始上线Zabbix的时候就进行分区,而不是等到数据量很大时。

设置Perl脚本

仅仅设置分区是不够的,我们还需要维护分区设置。MySQL不会自动为我们创建新分区,我们需要自己将这一过程自动化。最好的方法是使用已公开的Perl脚本。我们不确定其作者是谁,但是你可以在我们的GitHub库中找到它:

https://github.com/OpensourceICTSolutions/zabbix-mysql-partitioning-perl

从我们的GitHub下载该脚本,并将其保存到Zabbix数据库服务器的以下文件夹中:

/usr/lib/zabbix/

然后给脚本赋予执行权限:

chmod 750 /usr/lib/zabbix/mysql_zbx_part.pl

接下来,我们需要使用以下命令对其进行编辑(当然你也可以使用nano,而非vim):

vim /usr/lib/zabbix/mysql_zbx_part.pl

有几行语句需要修改。首先是MySQL登录信息:

my $dsn = 'DBI:mysql:'.$db_schema.':mysql_socket=/var/lib/mysql/mysql.sock';
my $db_user_name = 'zabbix';
my $db_password = 'password';

按照你的服务器情况对其进行修改。例如,用户名和密码可能要与Zabbix服务器配置文件中的设置保持一致。

其次,我们需要编辑数据的保存时长,可以在以下的行中修改:

my $tables = { 'history' => { 'period' => 'day', 'keep_history' => '60'},
'history_log' => { 'period' => 'day', 'keep_history' => '60'},
'history_str' => { 'period' => 'day', 'keep_history' => '60'},
'history_text' => { 'period' => 'day', 'keep_history' => '60'},
'history_uint' => { 'period' => 'day', 'keep_history' => '60'},
'history_bin' => { 'period' => 'day', 'keep_history' => '60'}, 
'trends' => { 'period' => 'month', 'keep_history' => '12'},
'trends_uint' => { 'period' => 'month', 'keep_history' => '12'},

第三,将时区修改为Zabbix数据库服务器系统所设置的时区。因为我们在荷兰,所以将时区设置为Europe/Amsterdam:

my $curr_tz = 'Europe/Amsterdam';

如果你使用的是比较旧的或者比较新的MySQL版本,脚本中的某些行可能需要注释掉或者取消注释。如果你使用的是MySQL 5.5及其以前的版本,或者MySQL 8.x及其以后的版本,你需要将下面的行注释掉,这些行在# MySQL 5.6 + MariaDB下面。

# my $sth = $dbh->prepare(qq{SELECT plugin_status FROM information_schema.plugins WHERE plugin_name = 'partition'});
#
# $sth->execute();
#
# my $row = $sth->fetchrow_array();
#
# $sth->finish();
# return 1 if $row eq 'ACTIVE';
#

如果你使用的是MySQL 5.5,你需要将下面的行取消注释,这些行在# MySQL 5.5下面。

# my $sth = $dbh->prepare(qq{SELECT variable_value FROM information_schema.global_variables WHERE variable_name = 'have_partitioning'});
#return 1 if $row eq 'YES';
#

如果你要在MySQL 8以及更高版本中使用该脚本,请从# MySQL 8.x (NOT MariaDB!)开始取消注释以下内容。

# MySQL 8.x (NOT MariaDB!)
# my $sth = $dbh->prepare(qq{select version();});
# $sth->execute();
# my $row = $sth->fetchrow_array();

# $sth->finish();
# return 1 if $row >= 8;
#

请注意,只有当你使用MySQL 5.5以及更低版本或者MySQL 8.x以及更高版本时才需要进行上面的所有这些修改。如果你使用的是MySQL 5.6或者MariaDB,就不需要进行任何修改。

对于Zabbix 5.4以及更低的版本,还需要取消注释下面的一行(对Zabbix 6.0以及更高版本不需要进行此操作):

# $dbh->do("DELETE FROM auditlog_details WHERE NOT EXISTS (SELECT NULL FROM auditlog WHERE auditlog.auditid = auditlog_details.auditid)");

对于 Zabbix 6.4 及更早版本,还请确保注释掉以下行。但不要对 Zabbix 7.0 及更高版本执行此操作:

'history_bin' => { 'period' => 'day', 'keep_history' => '60'},

 

该脚本默认将历史表数据保留时间设定为60天,将趋势表数据保留时间设定为12个月。你可以将其修改为自己喜欢的时间长度。不过请注意,保留历史数据和趋势数据的时间越长,数据库就会越大。

现在,我们添加一个定时任务:

crontab -e

然后在定时任务中添加下面的行

55 22 * * * /usr/lib/zabbix/mysql_zbx_part.pl >/dev/null 2>&1

我们还需要使用下面的命令安装一些Perl依赖项:

dnf install perl-DateTime perl-Sys-Syslog

如果是基于Debian的系统,则执行:

apt-get install libdatetime-perl liblogger-syslog-perl

好了!现在你已经完成了整个MySQL分区配置。我们可以手动执行一下Perl脚本:

perl /usr/lib/zabbix/mysql_zbx_part.pl

然后可以通过下面的命令查看其是否有效:

journalctl -t mysql_zbx_part

如果操作无误,该命令应该返回创建和删除的分区列表。

使用存储过程

请注意,如果你已经在使用上述的Perl脚本,那么你可以跳过这一部分。

自动创建和删除数据库分区的另一种方法是使用MySQL存储过程。不过作者不推荐使用此方法,这一方法应该只用于那些不允许使用外部脚本的企业。这是一种难以排查故障的方法,一旦出现故障会很头疼。

尽管如此,在Opensource ICT Solutions公司我们相信灵活性的价值并且提供多样性的解决方案。显然我们可以选择这样做。所以现在开始吧。

首先,我们需要使用以下命令登录MySQL:

mysql -u root -p

然后,我们需要创建一个表来管理分区,创建语句如下:

CREATE TABLE manage_partitions (
tablename VARCHAR(64) NOT NULL COMMENT ‘Table name’,
period VARCHAR(64) NOT NULL COMMENT ‘Period - daily or monthly’,
keep_history INT(3) UNSIGNED NOT NULL DEFAULT ‘1’ COMMENT ‘For how many days or months to keep the partitions’,
last_updated DATETIME DEFAULT NULL COMMENT ‘When a partition was added last time’,comments VARCHAR(128) DEFAULT ‘1’ COMMENT ‘Comments’,
PRIMARY KEY (tablename)
) ENGINE=INNODB;

然后,我们可以向表中插入所需的数据保留时间信息:

INSERT INTO manage_partitions (tablename, period, keep_history, last_updated, comments) VALUES (‘history’, ‘day’, 60, now(), ‘’);
INSERT INTO manage_partitions (tablename, period, keep_history, last_updated, comments) VALUES (‘history_uint’, ‘day’, 60, now(), ‘’);
INSERT INTO manage_partitions (tablename, period, keep_history, last_updated, comments) VALUES (‘history_str’, ‘day’, 60, now(), ‘’);
INSERT INTO manage_partitions (tablename, period, keep_history, last_updated, comments) VALUES (‘history_text’, ‘day’, 60, now(), ‘’);
INSERT INTO manage_partitions (tablename, period, keep_history, last_updated, comments) VALUES (‘history_log’, ‘day’, 60, now(), ‘’);
INSERT INTO manage_partitions (tablename, period, keep_history, last_updated, comments) VALUES (‘trends’, ‘month’, 12, now(), ‘’);
INSERT INTO manage_partitions (tablename, period, keep_history, last_updated, comments) VALUES (‘trends_uint’, ‘month’, 12, now(), ‘’);

我们默认将历史表数据保留时间设定为60天,将趋势表数据保留时间设定为12个月。如有需要,请根据自己的情况修改。

现在我们需要添加一些MySQL存储过程来管理我们的分区。首先,我们添加一个按天创建分区的存储过程:

DELIMITER $$
USE zabbix$$
DROP PROCEDURE IF EXISTS create_partition_by_day$$

CREATE PROCEDURE create_partition_by_day(IN_SCHEMANAME VARCHAR(64), IN_TABLENAME VARCHAR(64))BEGINDECLARE ROWS_CNT INT UNSIGNED;DECLARE BEGINTIME TIMESTAMP;DECLARE ENDTIME INT UNSIGNED;DECLARE PARTITIONNAME VARCHAR(16);SET BEGINTIME = DATE(NOW()) + INTERVAL 1 DAY;SET PARTITIONNAME = DATE_FORMAT( BEGINTIME, ‘p%Y_%m_%d’ );

SET ENDTIME = UNIX_TIMESTAMP(BEGINTIME + INTERVAL 1 DAY);

SELECT COUNT(*) INTO ROWS_CNT
FROM information_schema.partitions
WHERE table_schema = IN_SCHEMANAME AND table_name = IN_TABLENAME AND partition_name = PARTITIONNAME;

IF ROWS_CNT = 0 THEN
SET @SQL = CONCAT( 'ALTER TABLE `', IN_SCHEMANAME, '`.`', IN_TABLENAME, '`',
' ADD PARTITION (PARTITION ', PARTITIONNAME, ' VALUES LESS THAN (', ENDTIME, '));' );
PREPARE STMT FROM @SQL;
EXECUTE STMT;
DEALLOCATE PREPARE STMT;
ELSE
SELECT CONCAT("partition `", PARTITIONNAME, "` for table `",IN_SCHEMANAME, ".", IN_TABLENAME, "` already exists") AS result;
END IF;

END$$
DELIMITER ;

然后再添加一个按月创建分区的存储过程,语句如下:

DELIMITER $$

USE zabbix$$

DROP PROCEDURE IF EXISTS create_partition_by_month$$

CREATE PROCEDURE create_partition_by_month(IN_SCHEMANAME VARCHAR(64), IN_TABLENAME VARCHAR(64))BEGINDECLARE ROWS_CNT INT UNSIGNED;DECLARE BEGINTIME TIMESTAMP;DECLARE ENDTIME INT UNSIGNED;DECLARE PARTITIONNAME VARCHAR(16);SET BEGINTIME = DATE(NOW() - INTERVAL DAY(NOW()) DAY + INTERVAL 1 DAY + INTERVAL 1 MONTH);SET PARTITIONNAME = DATE_FORMAT( BEGINTIME, ‘p%Y_%m’ );

SET ENDTIME = UNIX_TIMESTAMP(BEGINTIME + INTERVAL 1 MONTH);
SELECT COUNT(*) INTO ROWS_CNT
FROM information_schema.partitions
WHERE table_schema = IN_SCHEMANAME AND table_name = IN_TABLENAME AND partition_name = PARTITIONNAME;

IF ROWS_CNT = 0 THEN
SET @SQL = CONCAT( 'ALTER TABLE `', IN_SCHEMANAME, '`.`', IN_TABLENAME, '`',
' ADD PARTITION (PARTITION ', PARTITIONNAME, ' VALUES LESS THAN (', ENDTIME, '));' );
PREPARE STMT FROM @SQL;

EXECUTE STMT;
DEALLOCATE PREPARE STMT;
ELSE

SELECT CONCAT("partition `", PARTITIONNAME, "` for table `",IN_SCHEMANAME, ".", IN_TABLENAME, "` already exists") AS result;
END IF;

END$$

DELIMITER ;

现在,通过调用上面的两个存储过程,我们可以添加一个为所有表(历史表和趋势表)创建分区的存储过程,具体语句如下:

DELIMITER $$
USE zabbix$$
DROP PROCEDURE IF EXISTS create_next_partitions$$

CREATE PROCEDURE create_next_partitions(IN_SCHEMANAME VARCHAR(64))BEGINDECLARE TABLENAME_TMP VARCHAR(64);DECLARE PERIOD_TMP VARCHAR(12);DECLARE DONE INT DEFAULT 0;

DECLARE get_prt_tables CURSOR FOR
SELECT `tablename`, `period`
FROM manage_partitions;

DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;

OPEN get_prt_tables;

loop_create_part: LOOP
IF DONE THEN
LEAVE loop_create_part;
END IF;

FETCH get_prt_tables INTO TABLENAME_TMP, PERIOD_TMP;

CASE WHEN PERIOD_TMP = 'day' THEN
CALL `create_partition_by_day`(IN_SCHEMANAME, TABLENAME_TMP);
WHEN PERIOD_TMP = 'month' THEN
CALL `create_partition_by_month`(IN_SCHEMANAME, TABLENAME_TMP);
ELSE
BEGIN
ITERATE loop_create_part;
END;
END CASE;

UPDATE manage_partitions set last_updated = NOW() WHERE tablename = TABLENAME_TMP;

END LOOP loop_create_part;
CLOSE get_prt_tables;

END$$

DELIMITER ;

除了分区的创建,我们还需要添加用于删除分区的存储过程。先添加一个删除指定分区的存储过程,如下:

DELIMITER $$

USE zabbix$$

DROP PROCEDURE IF EXISTS drop_old_partition$$
CREATE PROCEDURE drop_old_partition(IN_SCHEMANAME VARCHAR(64), IN_TABLENAME VARCHAR(64), IN_PARTITIONNAME VARCHAR(64))BEGINDECLARE ROWS_CNT INT UNSIGNED;
SELECT COUNT(*) INTO ROWS_CNT
FROM information_schema.partitions
WHERE table_schema = IN_SCHEMANAME AND table_name = IN_TABLENAME AND partition_name = IN_PARTITIONNAME;

IF ROWS_CNT = 1 THEN
SET @SQL = CONCAT( 'ALTER TABLE `', IN_SCHEMANAME, '`.`', IN_TABLENAME, '`',
' DROP PARTITION ', IN_PARTITIONNAME, ';' );
PREPARE STMT FROM @SQL;
EXECUTE STMT;
DEALLOCATE PREPARE STMT;
ELSE
SELECT CONCAT("partition `", IN_PARTITIONNAME, "` for table `", IN_SCHEMANAME, ".", IN_TABLENAME, "` not exists") AS result;
END IF;

END$$




DELIMITER ;

然后基于前一个存储过程,我们添加一个用于为所有表删除分区的存储过程:

DELIMITER $$




USE zabbix$$
DROP PROCEDURE IF EXISTS drop_partitions$$
CREATE PROCEDURE drop_partitions(IN_SCHEMANAME VARCHAR(64))
BEGIN
DECLARE TABLENAME_TMP VARCHAR(64);
DECLARE PARTITIONNAME_TMP VARCHAR(64);
DECLARE VALUES_LESS_TMP INT;
DECLARE PERIOD_TMP VARCHAR(12);
DECLARE KEEP_HISTORY_TMP INT;
DECLARE KEEP_HISTORY_BEFORE INT;
DECLARE DONE INT DEFAULT 0;
DECLARE get_partitions CURSOR FOR
SELECT p.table_name, p.partition_name, LTRIM(RTRIM(p.partition_description)), mp.period, mp.keep_history
FROM information_schema.partitions p
JOIN manage_partitions mp ON mp.tablename = p.table_name
WHERE p.table_schema = IN_SCHEMANAME
ORDER BY p.table_name, p.subpartition_ordinal_position;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;

OPEN get_partitions;

loop_check_prt: LOOP
IF DONE THEN
LEAVE loop_check_prt;
END IF;

FETCH get_partitions INTO TABLENAME_TMP, PARTITIONNAME_TMP, VALUES_LESS_TMP, PERIOD_TMP, KEEP_HISTORY_TMP;
CASE WHEN PERIOD_TMP = 'day' THEN
SET KEEP_HISTORY_BEFORE = UNIX_TIMESTAMP(DATE(NOW() - INTERVAL KEEP_HISTORY_TMP DAY));
WHEN PERIOD_TMP = 'month' THEN
SET KEEP_HISTORY_BEFORE = UNIX_TIMESTAMP(DATE(NOW() - INTERVAL KEEP_HISTORY_TMP MONTH - INTERVAL DAY(NOW())-1 DAY));
ELSE
BEGIN

ITERATE loop_check_prt;
END;
END CASE;

IF KEEP_HISTORY_BEFORE >= VALUES_LESS_TMP THEN
CALL drop_old_partition(IN_SCHEMANAME, TABLENAME_TMP, PARTITIONNAME_TMP);
END IF;
END LOOP loop_check_prt;
CLOSE get_partitions;

END$$

DELIMITER ;

最后,我们需要添加一个EVENT调度器来自动执行删除和创建分区的所有操作:

DELIMITER $$

USE zabbix$$

CREATE EVENT IF NOT EXISTS e_part_manage
ON SCHEDULE EVERY 1 DAYSTARTS ‘2021-02-19 04:00:00’
ON COMPLETION PRESERVE
ENABLE
COMMENT ‘Creating and dropping partitions’
DO BEGIN
CALL zabbix.drop_partitions(‘zabbix’);
CALL zabbix.create_next_partitions(‘zabbix’);
END$$

DELIMITER ;

这就是存储过程方法,简单易懂。

禁用Zabbix housekeeper

在进行了分区并部署了Perl脚本或者存储过程之后,我们需要禁用历史表和趋势表的housekeeper功能。在Zabbix Web前端打开Administartion | Housekeeping页面,确保将历史表和趋势表下的Enable internal housekeeping选项关闭,如下图所示:

Perl脚本或者存储过程将接管删除数据的工作,并且,在各监控项中设置的历史数据和趋势数据保留时间将不再起作用。

结论

MySQL分区看上去是一项大胆的行动,但是绝对可以做。在Zabbix社区成员发布的早期贴子中已经有帮助用户设置分区的内容。随着时间推移,这些帖子已经消失不见,所以我们认为自己有责任建立一个公开的手册,以随时可以帮助大家完成这项非常重要的任务。

完成所有设置以后,请务必在前几天留意观察你的分区情况,因为有可能你忽略了一些东西导致没有创建成功。

希望您喜欢阅读本文,如果您在Zabbix设置管理方面有任何问题或者需要任何帮助,请随时联系我和Opensource ICT Soluctions团队。

Nathan Liefting

https://oicts.com

A close up of a logo Description automatically generated

 

翻译:鲍光亚,《深入理解Zabbix监控系统》作者,更多图书信息请访问以下链接

纸书:https://item.jd.com/13204768.html

Kindle版: https://www.amazon.cn/dp/B092VT9949/ref=cm_sw_em_r_mt_dp_NNVTE0EZ31AXNNH67NZA

 

 

 

 

常见问题:

  1. 你可能遇到这样的错误:Table has no partition for value <unixtime>
    • 如果<unixtime>是一个未来时间,请使用下面的语句检查最新分区与表中的最大时间戳是否匹配:
SELECT FROM_UNIXTIME(MAX(clock)) FROM history_uint;
    • 如果<unixtime>是一个过去的时间,请使用下面的语句检查最老分区与表中的最小时间戳是否匹配:
SELECT FROM_UNIXTIME(MIN(clock)) FROM history_uint;
订阅评论
提醒
0 Comments
最旧
最新 最多投票
内联反馈
查看所有评论
0
希望看到您的想法,请您发表评论x