zabbix optimization

zabbix 优化

  1. 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,设的时候要注意一下这点
  2. 关于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这个值,否则申请不了内存程序启动不了
  3. 内核共享内存优化

    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)
  4. 数据库配置参数优化

    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
  5. zabbix mysql 表分区优化

    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);
  6. 创建存储过程

    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
  7. 创建调用存储过程

    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 本次一共生成多少个分区
  8. 执行调用存储过程

    1
    [root@zabbix-server-mysql data]# mysql -S /mnt/data/mysql/3306/mysql.sock zabbix -e "CALL partition_maintenance_all('zabbix');"
  9. 将”执行调用存储过程”命令,加入计划任务

    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');"
  10. 关掉Zabbix的HouseKeeper功能

    1
    administration -> general -> HouseKeeping -> "取消勾选框,保存"
  11. 解决表依赖关系

    1
    2
    3
    mysql> SET foreign_key_checks=0;
    mysql> truncate table events;
    mysql> SET foreign_key_checks=1;