[技术干货] zabbix5.0 mysql表分区

[复制链接]
乐维 发表于 2020-12-23 14:50:55 | 显示全部楼层 |阅读模式 打印 上一主题 下一主题

zabbix经常出现Zabbix housekeeper processes more than 75% busy报警,报警时WEB访问就变得很慢,尤其是加载历史数据的图形。

使用网上的调优设置,修改过housekeeper的进程和间隔时间,效果都不太理想。

因此就按照网上的建议,做一下zabbix mysql的数据库表的分区吧。

使用mysql表分区来对history这种大表进行分区,但是一定要在数据量小的时候进行分区,当数据量达到好几十G设置几百G了还是采用第一种方法把数据清理了再作表分区。

我看了下我的数据,也是非常大。

[root@zabbix # find /netzbxdb/ -type f -print0 | xargs -0 du -h | sort -rh | head -n 1018G /netzbxdb/zabbix/history_uint.ibd5.1G /netzbxdb/zabbix/history.ibd2.1G /netzbxdb/zabbix/trends_uint.ibd1.1G /netzbxdb/binlog.0000511.1G /netzbxdb/binlog.0000501.1G /netzbxdb/binlog.000049
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

过程不写了,最后做法是清空zabbix历史数据,再进行分区。

步骤如下吧!

1,使用truncate命令清空zabbix 所有监控数据

-------------------------------------------------------truncate table history;optimize table history;------------------------------------------------------- truncate table history_str;optimize table history_str;-------------------------------------------------------truncate table history_uint;optimize table history_uint;-------------------------------------------------------truncate table trends;optimize table trends;-------------------------------------------------------truncate table trends_uint; optimize table trends_uint; -------------------------------------------------------truncate table events;optimize table events;-------------------------------------------------------
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

注意:这些命令会把zabbix所有的监控数据清空,只是清空监控数据,添加的主机,配置,拓扑图不会丢失。如果对监控数据比较看重的话注意备份数据库

truncate是删除了表,然后根据表结构重新建立。

2,创建sql文件

[root@zabbix ~]# vim partition.sql

DELIMITER $$CREATE PROCEDURE `partition_create`(SCHEMANAME varchar(64), TABLENAME varchar(64), PARTITIONNAME varchar(64), CLOCK int)BEGIN        /*           SCHEMANAME = The DB schema in which to make changes           TABLENAME = The table with partitions to potentially delete           PARTITIONNAME = The name of the partition to create        */        /*           Verify that the partition does not already exist        */        DECLARE RETROWS INT;        SELECT COUNT(1) INTO RETROWS        FROM information_schema.partitions        WHERE table_schema = SCHEMANAME AND table_name = TABLENAME AND partition_description >= CLOCK;        IF RETROWS = 0 THEN        /*           1. Print a message indicating that a partition was created.           2. Create the SQL to create the partition.           3. Execute the SQL from #2.        */        SELECT CONCAT( "partition_create(", SCHEMANAME, ",", TABLENAME, ",", PARTITIONNAME, ",", CLOCK, ")" ) AS msg;        SET @sql = CONCAT( 'ALTER TABLE ', SCHEMANAME, '.', TABLENAME, ' ADD PARTITION (PARTITION ', PARTITIONNAME, ' VALUES LESS THAN (', CLOCK, '));' );        PREPARE STMT FROM @sql;        EXECUTE STMT;        DEALLOCATE PREPARE STMT;        END IF;END$$DELIMITER ;DELIMITER $$CREATE PROCEDURE `partition_drop`(SCHEMANAME VARCHAR(64), TABLENAME VARCHAR(64), DELETE_BELOW_PARTITION_DATE BIGINT)BEGIN        /*           SCHEMANAME = The DB schema in which to make changes           TABLENAME = The table with partitions to potentially delete           DELETE_BELOW_PARTITION_DATE = Delete any partitions with names that are dates older than this one (yyyy-mm-dd)        */        DECLARE done INT DEFAULT FALSE;        DECLARE drop_part_name VARCHAR(16);        /*           Get a list of all the partitions that are older than the date           in DELETE_BELOW_PARTITION_DATE.  All partitions are prefixed with           a "p", so use SUBSTRING TO get rid of that character.        */        DECLARE myCursor CURSOR FOR        SELECT partition_name        FROM information_schema.partitions        WHERE table_schema = SCHEMANAME AND table_name = TABLENAME AND CAST(SUBSTRING(partition_name FROM 2) AS UNSIGNED) < DELETE_BELOW_PARTITION_DATE;        DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;        /*           Create the basics for when we need to drop the partition.  Also, create           @drop_partitions to hold a comma-delimited list of all partitions that           should be deleted.        */        SET @alter_header = CONCAT("ALTER TABLE ", SCHEMANAME, ".", TABLENAME, " DROP PARTITION ");        SET @drop_partitions = "";        /*           Start looping through all the partitions that are too old.        */        OPEN myCursor;        read_loop: LOOP        FETCH myCursor INTO drop_part_name;        IF done THEN    LEAVE read_loop;        END IF;        SET @drop_partitions = IF(@drop_partitions = "", drop_part_name, CONCAT(@drop_partitions, ",", drop_part_name));        END LOOP;        IF @drop_partitions != "" THEN        /*           1. Build the SQL to drop all the necessary partitions.           2. Run the SQL to drop the partitions.           3. Print out the table partitions that were deleted.        */        SET @full_sql = CONCAT(@alter_header, @drop_partitions, ";");        PREPARE STMT FROM @full_sql;        EXECUTE STMT;        DEALLOCATE PREPARE STMT;        SELECT CONCAT(SCHEMANAME, ".", TABLENAME) AS `table`, @drop_partitions AS `partitions_deleted`;        ELSE        /*           No partitions are being deleted, so print out "N/A" (Not applicable) to indicate           that no changes were made.        */        SELECT CONCAT(SCHEMANAME, ".", TABLENAME) AS `table`, "N/A" AS `partitions_deleted`;        END IF;END$$DELIMITER ;DELIMITER $$CREATE PROCEDURE `partition_maintenance`(SCHEMA_NAME VARCHAR(32), TABLE_NAME VARCHAR(32), KEEP_DATA_DAYS INT, HOURLY_INTERVAL INT, CREATE_NEXT_INTERVALS INT)BEGIN        DECLARE OLDER_THAN_PARTITION_DATE VARCHAR(16);        DECLARE PARTITION_NAME VARCHAR(16);        DECLARE OLD_PARTITION_NAME VARCHAR(16);        DECLARE LESS_THAN_TIMESTAMP INT;        DECLARE CUR_TIME INT;        CALL partition_verify(SCHEMA_NAME, TABLE_NAME, HOURLY_INTERVAL);        SET CUR_TIME = UNIX_TIMESTAMP(DATE_FORMAT(NOW(), '%Y-%m-%d 00:00:00'));        SET @__interval = 1;        create_loop: LOOP        IF @__interval > CREATE_NEXT_INTERVALS THEN    LEAVE create_loop;        END IF;        SET LESS_THAN_TIMESTAMP = CUR_TIME + (HOURLY_INTERVAL * @__interval * 3600);        SET PARTITION_NAME = FROM_UNIXTIME(CUR_TIME + HOURLY_INTERVAL * (@__interval - 1) * 3600, 'p%Y%m%d%H00');        IF(PARTITION_NAME != OLD_PARTITION_NAME) THEN    CALL partition_create(SCHEMA_NAME, TABLE_NAME, PARTITION_NAME, LESS_THAN_TIMESTAMP);        END IF;        SET @__interval=@__interval+1;        SET OLD_PARTITION_NAME = PARTITION_NAME;        END LOOP;        SET OLDER_THAN_PARTITION_DATE=DATE_FORMAT(DATE_SUB(NOW(), INTERVAL KEEP_DATA_DAYS DAY), '%Y%m%d0000');        CALL partition_drop(SCHEMA_NAME, TABLE_NAME, OLDER_THAN_PARTITION_DATE);END$$DELIMITER ;DELIMITER $$CREATE PROCEDURE `partition_verify`(SCHEMANAME VARCHAR(64), TABLENAME VARCHAR(64), HOURLYINTERVAL INT(11))BEGIN        DECLARE PARTITION_NAME VARCHAR(16);        DECLARE RETROWS INT(11);        DECLARE FUTURE_TIMESTAMP TIMESTAMP;        /*         * Check if any partitions exist for the given SCHEMANAME.TABLENAME.         */        SELECT COUNT(1) INTO RETROWS        FROM information_schema.partitions        WHERE table_schema = SCHEMANAME AND table_name = TABLENAME AND partition_name IS NULL;        /*         * If partitions do not exist, go ahead and partition the table         */        IF RETROWS = 1 THEN        /*         * Take the current date at 00:00:00 and add HOURLYINTERVAL to it.  This is the timestamp below which we will store values.         * We begin partitioning based on the beginning of a day.  This is because we don't want to generate a random partition         * that won't necessarily fall in line with the desired partition naming (ie: if the hour interval is 24 hours, we could         * end up creating a partition now named "p201403270600" when all other partitions will be like "p201403280000").         */        SET FUTURE_TIMESTAMP = TIMESTAMPADD(HOUR, HOURLYINTERVAL, CONCAT(CURDATE(), " ", '00:00:00'));        SET PARTITION_NAME = DATE_FORMAT(CURDATE(), 'p%Y%m%d%H00');        -- Create the partitioning query        SET @__PARTITION_SQL = CONCAT("ALTER TABLE ", SCHEMANAME, ".", TABLENAME, " PARTITION BY RANGE(`clock`)");        SET @__PARTITION_SQL = CONCAT(@__PARTITION_SQL, "(PARTITION ", PARTITION_NAME, " VALUES LESS THAN (", UNIX_TIMESTAMP(FUTURE_TIMESTAMP), "));");        -- Run the partitioning query        PREPARE STMT FROM @__PARTITION_SQL;        EXECUTE STMT;        DEALLOCATE PREPARE STMT;        END IF;END$$DELIMITER ;DELIMITER $$CREATE PROCEDURE`partition_maintenance_all`(SCHEMA_NAME VARCHAR(32))BEGIN               CALL partition_maintenance(SCHEMA_NAME, 'history', 90, 24, 14);               CALL partition_maintenance(SCHEMA_NAME, 'history_log', 90, 24, 14);               CALL partition_maintenance(SCHEMA_NAME, 'history_str', 90, 24, 14);               CALL partition_maintenance(SCHEMA_NAME, 'history_text', 90, 24, 14);               CALL partition_maintenance(SCHEMA_NAME, 'history_uint', 90, 24, 14);               CALL partition_maintenance(SCHEMA_NAME, 'trends', 730, 24, 14);               CALL partition_maintenance(SCHEMA_NAME, 'trends_uint', 730, 24, 14);END$$DELIMITER ;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175

3,导入sql文件

[root@zabbix # mysql -uzabbix -p123456 zabbix < partition.sql

4,添加计划任务

[root@zabbix # crontab  -e #zabbix partition_maintenance01 01 * * *  mysql  -uzabbix -p123456 zabbix -e"CALL partition_maintenance_all('zabbix')" &>/var/log/partition.log
  • 1
  • 2

注意: mysql的zabbix用户的密码部分按照实际环境配置

首次执行一次,确保已成功执行。
将crontab时间改为后1分钟,等待1分钟,再看log即可,比如现在是14:45,那就修改crontab如下:

[root@zabbix # crontab  -e 46 14 * * *  mysql  -uzabbix -p123456 zabbix -e"CALL partition_maintenance_all('zabbix')" &>/var/log/partition.log
  • 1

5,检查分区是否成功

可以在/var/log/partition.log查看:

[root@zabbix ~]# cat /var/log/partition.log

也可以登陆mysql,使用以下命令查看:

最后,再检查一下mysql目录下的表文件,可以看到经过分区后的表的数据库文件由原来打个ibd文件变成了按照日期划分的多个ibd文件。

[root@zabbix zabbix]# ll -h | grep history

6,关闭zabbix再带的清理功能。

依次打开,管理—-一般—-设置—管家,取消图中标识的2处勾选。


至此,zabbix5.0 mysql表分区完成,本人亲测,zabbix5.0有效。


附:修改’partition_maintenance_all

show procedure status like ‘partition_maintenance%’ \G;

drop procedure partition_maintenance_all;

重新复制修改后的partition_maintenance_all

CALL partition_maintenance_all(‘zabbix’);





上一篇:zabbix5.0 mysql表分区
下一篇:Zabbix“专家坐诊”第90期问答汇总
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关注0

粉丝0

帖子320

发布主题
最新发布

乐维社区

微信公众号

版权所有 © 2016-2021 九一乐维丨粤ICP备17007026号