zabbix 优化
zabbix Poller 调整
1
2
3
4
5
6
7
8
9
10
11* Option: StartPollers 处理监控项
* Option: StartIPMIPollers 处理IPMI,暂时未用,设置为0
* Option: StartPollersUnreachable 获取数据遇到不可到达时,交给这些进程处理
* Option: StartHTTPPollers 监控HTTP,WEB,设置为10
* Option: StartJavaPollers 监控JAVA专用进程,设置为10
* Option: StartProxyPollers 处理代理的进程,设置为30
* Option: StartDiscoverers 处理自动发现的,设置为30
* Option: StartPingers 如果用了ICMP PING那个模板的,这个值要调大一些
注意:
StartPollers,然配置文件写是可用范围是0-1000,但这个1000是所有的进程的值,也就是说上面那些进程的总数不能超过1000,设的时候要注意一下这点关于Cache的调整
1
2
3
4
5
6
7
8* Option: CacheSize zabbix初始化时占用多少系统共享内存用于存储配置信息(HOST,ITEM,TRIGGER数据,视监控主机数量和监控项调整)
* Option: CacheUpdateFrequency zabbix更新操作系统CACHE频率,若管理页面操作不频繁,可以考虑加大参数值
* Option: HistoryCacheSize 用于设置划分多少系统共享内存用于存储采集的历史数据,此数值越大,数据库读压力越小
* Option: TrendCacheSize 用于设置划分多少系统共享内存用于存储计算出来的趋势数据,此参数值从一定程度上可影响数据库读压力
* Option: HistoryIndexCacheSize 历史数据索引缓存
* Option: ValueCacheSize 划出系统多少共享内存用于已请求的存储监控项信息,若监控项较多,建议加大此数值
注意: 关于内存的参数有这么多,都是要根据机器数量和item数量的增加而增加,这些内存的值不能大于系统内核的kernel.shmall这个值,否则申请不了内存程序启动不了内核共享内存优化
1
2
3
4
5
6
7
8
9
10
11[root@zabbix-server-mysql ~]# echo kernel.shmmax=15461882265 | tee -a /etc/sysctl.conf
[root@zabbix-server-mysql ~]# echo kernel.shmall=3774873 | tee -a /etc/sysctl.conf
[root@zabbix-server-mysql ~]# echo kernel.msgmax=65535 | tee -a /etc/sysctl.conf
[root@zabbix-server-mysql ~]# echo kernel.msgmnb=65535 | tee -a /etc/sysctl.conf
说明:
shmall是全部允许使用的共享内存大小,shmmax是单个段允许使用的大小.这两个可以设置为内存的90%
例如:16G内存,shmmax的大小为 16*1024*1024*1024*90% = 15461882265,shmall的大小为 15461882265/4k(getconf PAGESIZE可得到) = 3774873
msgmax该文件指定了从一个进程发送到另一个进程的消息的最大长度(bytes).进程间的消息传递是在内核的内存中进行的,不会交换到磁盘上,所以如果增加该值,则将增加操作系统所使用的内存数量
msgmnb该文件指定一个消息队列的最大长度(bytes)数据库配置参数优化
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[root@zabbix-server-mysql ~]# cat /mnt/app/mysql/conf/3306.M.cnf
[mysqld]
user = mysql
port = 3306
basedir = /mnt/app/mysql
datadir = /mnt/data/mysql/3306
socket = /mnt/data/mysql/3306/mysql.sock
default-storage-engine = InnoDB
character_set_server = utf8
max_connections = 5000
sql_mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES
server-id = 210
max_allowed_packet = 32m
max_heap_table_size = 128m
read_rnd_buffer_size = 8m
sort_buffer_size = 4m
join_buffer_size = 4m
query_cache_type = 1
query_cache_size = 512m
query_cache_limit = 4m
innodb_open_files = 3000
innodb_buffer_pool_size = 12G
innodb_file_per_table = 1
[mysqld_safe]
log-error=/mnt/log/mysql/3306/mysqld.log
pid-file =/mnt/app/mysql/mysqld.3306.pid
[client]
default-character-set=utf8
socket=/mnt/data/mysql/3306/mysql.sock
[mysql]
default-character-set=utf8
socket=/mnt/data/mysql/3306/mysql.sock
[root@zabbix-server-mysql ~]# /etc/init.d/mysql.3306M restart-
1
2
3
4
5机器数量多的时候,mysql里面的history表就会越来越大,虽然zabbix本身有删除功能(就是那个housekeeper的功能),但这东西太影响性能,所以网上的做法都是关闭这个东西,用mysql的表分区功能来实现清理历史数据还可以提升mysql的性能
补充: zabbix 3.2 版本数据库不需要重新执行创建索引过程;2.0,3.0版本都需要
mysql> Alter table history_text drop primary key, add index (id), drop index history_text_2, add index history_text_2 (itemid, id);
mysql> Alter table history_log drop primary key, add index (id), drop index history_log_2, add index history_log_2 (itemid, id); 创建存储过程
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[root@zabbix-server-mysql data]# vim partition_call.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 ;
[root@zabbix-server-mysql data]# mysql -S /mnt/data/mysql/3306/mysql.sock zabbix < partition_call.sql创建调用存储过程
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22[root@zabbix-server-mysql data]# vim partition_call_call.sql
DELIMITER $$
CREATE PROCEDURE `partition_maintenance_all`(SCHEMA_NAME VARCHAR(32))
BEGIN
CALL partition_maintenance(SCHEMA_NAME, 'history', 30, 24, 14);
CALL partition_maintenance(SCHEMA_NAME, 'history_log', 30, 24, 14);
CALL partition_maintenance(SCHEMA_NAME, 'history_str', 30, 24, 14);
CALL partition_maintenance(SCHEMA_NAME, 'history_text', 30, 24, 14);
CALL partition_maintenance(SCHEMA_NAME, 'history_uint', 30, 24, 14);
CALL partition_maintenance(SCHEMA_NAME, 'trends', 730, 24, 14);
CALL partition_maintenance(SCHEMA_NAME, 'trends_uint', 730, 24, 14);
END$$
DELIMITER ;
说明:
mysql> CALL partition_maintenance('<zabbix_db_name>', '<table_name>', <days_to_keep_data>, <hourly_interval>, <num_future_intervals_to_create>)
说明:
zabbix_db_name 库名
table_name 表名
days_to_keep_data 保存多少天的数据
hourly_interval 每隔多久生成一个分区
num_future_intervals_to_create 本次一共生成多少个分区执行调用存储过程
1
[root@zabbix-server-mysql data]# mysql -S /mnt/data/mysql/3306/mysql.sock zabbix -e "CALL partition_maintenance_all('zabbix');"
将”执行调用存储过程”命令,加入计划任务
1
2[root@zabbix-server-mysql data]# crontab -l
5 1 * * * /mnt/app/mysql/bin/mysql -S /mnt/data/mysql/3306/mysql.sock zabbix -e "CALL partition_maintenance_all('zabbix');"关掉Zabbix的HouseKeeper功能
1
administration -> general -> HouseKeeping -> "取消勾选框,保存"
解决表依赖关系
1
2
3mysql> SET foreign_key_checks=0;
mysql> truncate table events;
mysql> SET foreign_key_checks=1;