Administrator
Published on 2026-01-08 / 7 Visits
0
0

【Zabbix从0到1实战指南】第 9 讲|Zabbix 7.0.22 + MySQL 同机部署的极限调优实战指南【Docker-compose和.env的调优配置】

说明:Zabbix 官方 Docker 镜像支持用 ZBX_* 环境变量直接映射到 zabbix_server.conf 的同名参数(例如 ZBX_LOGSLOWQUERIES 对应 LogSlowQueries),以及 DB_SERVER_HOST/MYSQL_* 等数据库连接变量。
参数含义/原理可查 Zabbix 官方 server 配置文档。


https://www.zabbix.com/documentation/current/en/manual/appendix/config/zabbix_server?utm_source=chatgpt.com

一、服务端优化点

A. 抗高并发采集:进程数(poller / preprocess / trapper / dbsyncer)

  • StartPollers / StartPollersUnreachable / StartPingers / StartHTTPPollers:决定并发采集能力(队列堆积、busy% 高就要加)

  • StartPreprocessors:预处理并发(依赖 item preprocessing、LLD、复杂表达式时很关键)

  • StartDBSyncers:写库并发(历史写入慢、DB 压力大时关键)

这些都能用镜像环境变量直接配:ZBX_STARTPOLLERSZBX_STARTPREPROCESSORSZBX_STARTDBSYNCERS 等。


B. 抗“缓存不足/频繁读库”:Cache / HistoryCache / TrendCache / ValueCache

核心逻辑:Zabbix server 是强缓存架构,缓存小会导致:

  • 配置缓存频繁抖动、触发器/计算慢

  • 历史写入/读取卡顿

  • 前端“忙”、队列堆积

对应可配项(Docker env 支持):
ZBX_CACHESIZE / ZBX_HISTORYCACHESIZE / ZBX_HISTORYINDEXCACHESIZE / ZBX_TRENDCACHESIZE / ZBX_VALUECACHESIZE


C. Housekeeping(保洁)不要“把库拖死”

  • HousekeepingFrequency / MaxHousekeeperDelete:如果历史量大,housekeeping 会制造巨大 delete 压力(MySQL 最怕)

  • 常见实践:降低每轮删除量避免频繁全表大清理(并结合分区/保留策略)

Docker env 支持:ZBX_HOUSEKEEPINGFREQUENCYZBX_MAXHOUSEKEEPERDELETE


D. MySQL 侧:InnoDB buffer / redo / flush 策略(决定“写得动不动”)

Zabbix 大头是 history/trends 写入,MySQL 优化重点:

  • innodb_buffer_pool_size(最重要)

  • innodb_flush_log_at_trx_commit(性能 vs 严格持久化)

  • sync_binlog(如果开 binlog)

  • innodb_log_file_sizemax_connectionstable_open_cache


二、 生产环境的【.env】配置

适合:几百台主机、几万~十几万 items 量级(后续你看队列/忙碌度再调)


三、 docker-compose.yml【把优化项落盘 + 引用 .env】

/data/zbx7/… 落盘、网桥 zbx7-net、MySQL conf 只读挂载。

services:
  # =========================
  # MySQL 8.0
  # =========================
  mysql:
    image: mysql:8.0.44
    container_name: zbx7-mysql-${ZBX_INSTANCE}
    hostname: zbx7-mysql-${ZBX_INSTANCE}
    restart: unless-stopped
    command:
      - --default-authentication-plugin=mysql_native_password
      - --character-set-server=utf8mb4
      - --collation-server=utf8mb4_bin
      - --log-bin-trust-function-creators=1
      # ---- perf tuning ----
      - --innodb-buffer-pool-size=${MYSQL_INNODB_BUFFER_POOL_SIZE}
      - --max-connections=${MYSQL_MAX_CONNECTIONS}
      - --innodb-log-file-size=${MYSQL_INNODB_LOG_FILE_SIZE}
      - --innodb-flush-log-at-trx-commit=${MYSQL_INNODB_FLUSH_LOG_AT_TRX_COMMIT}
      - --sync-binlog=${MYSQL_SYNC_BINLOG}
    environment:
      MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
      MYSQL_DATABASE: ${ZBX_DB_NAME}
      MYSQL_USER: ${ZBX_DB_USER}
      MYSQL_PASSWORD: ${ZBX_DB_PASS}
      TZ: ${TZ}
    volumes:
      - /data/zbx7/mysql/data:/var/lib/mysql
      - /data/zbx7/mysql/conf:/etc/mysql/conf.d:ro
      - /data/zbx7/mysql/backup:/backup
    networks:
      zbx7-net:
        ipv4_address: ${IP_MYSQL}
    healthcheck:
      test: ["CMD-SHELL", "mysqladmin ping -h 127.0.0.1 -uroot -p$${MYSQL_ROOT_PASSWORD} --silent"]
      interval: 10s
      timeout: 5s
      retries: 30
    # 按要求:不映射 13306

  # =========================
  # Zabbix Server
  # =========================
  zabbix-server:
    image: zabbix/zabbix-server-mysql:7.0.22-ol
    container_name: zbx7-server-${ZBX_INSTANCE}
    hostname: zbx7-server-${ZBX_INSTANCE}
    restart: unless-stopped
    depends_on:
      mysql:
        condition: service_healthy
    environment:
      TZ: ${TZ}
      DB_SERVER_HOST: mysql
      DB_SERVER_PORT: 3306
      MYSQL_DATABASE: ${ZBX_DB_NAME}
      MYSQL_USER: ${ZBX_DB_USER}
      MYSQL_PASSWORD: ${ZBX_DB_PASS}

      # ---- Server tuning ----
      ZBX_DEBUGLEVEL: ${ZBX_DEBUGLEVEL}
      ZBX_TIMEOUT: ${ZBX_TIMEOUT}
      ZBX_LOGSLOWQUERIES: ${ZBX_LOGSLOWQUERIES}

      ZBX_STARTPOLLERS: ${ZBX_STARTPOLLERS}
      ZBX_STARTPOLLERSUNREACHABLE: ${ZBX_STARTPOLLERSUNREACHABLE}
      ZBX_STARTTRAPPERS: ${ZBX_STARTTRAPPERS}
      ZBX_STARTPINGERS: ${ZBX_STARTPINGERS}
      ZBX_STARTDISCOVERERS: ${ZBX_STARTDISCOVERERS}
      ZBX_STARTHTTPPOLLERS: ${ZBX_STARTHTTPPOLLERS}
      ZBX_STARTPREPROCESSORS: ${ZBX_STARTPREPROCESSORS}
      ZBX_STARTLLDPROCESSORS: ${ZBX_STARTLLDPROCESSORS}
      ZBX_STARTDBSYNCERS: ${ZBX_STARTDBSYNCERS}

      ZBX_CACHESIZE: ${ZBX_CACHESIZE}
      ZBX_HISTORYCACHESIZE: ${ZBX_HISTORYCACHESIZE}
      ZBX_HISTORYINDEXCACHESIZE: ${ZBX_HISTORYINDEXCACHESIZE}
      ZBX_TRENDCACHESIZE: ${ZBX_TRENDCACHESIZE}
      ZBX_TRENDFUNCTIONCACHESIZE: ${ZBX_TRENDFUNCTIONCACHESIZE}
      ZBX_VALUECACHESIZE: ${ZBX_VALUECACHESIZE}
      ZBX_CACHEUPDATEFREQUENCY: ${ZBX_CACHEUPDATEFREQUENCY}

      ZBX_HOUSEKEEPINGFREQUENCY: ${ZBX_HOUSEKEEPINGFREQUENCY}
      ZBX_MAXHOUSEKEEPERDELETE: ${ZBX_MAXHOUSEKEEPERDELETE}
    volumes:
      - /data/zbx7/zabbix/alertscripts:/usr/lib/zabbix/alertscripts:ro
      - /data/zbx7/zabbix/externalscripts:/usr/lib/zabbix/externalscripts:ro
      - /data/zbx7/zabbix/modules:/var/lib/zabbix/modules:ro
      - /data/zbx7/zabbix/snmptraps:/var/lib/zabbix/snmptraps:rw
      - /data/zbx7/logs/zabbix-server:/var/log/zabbix:rw
    ports:
      - "${ZBX_SERVER_PORT}:10051"
    networks:
      zbx7-net:
        ipv4_address: ${IP_SERVER}

  # =========================
  # Zabbix Web (Nginx)
  # =========================
  zabbix-web:
    image: zabbix/zabbix-web-nginx-mysql:7.0.22-ol
    container_name: zbx7-web-${ZBX_INSTANCE}
    hostname: zbx7-web-${ZBX_INSTANCE}
    privileged: true
    restart: unless-stopped
    depends_on:
      mysql:
        condition: service_healthy
      zabbix-server:
        condition: service_started
    environment:
      TZ: ${TZ}
      PHP_TZ: ${PHP_TZ}
      ZBX_SERVER_HOST: zabbix-server
      ZBX_SERVER_NAME: ${ZBX_SERVER_NAME}
      DB_SERVER_HOST: mysql
      MYSQL_DATABASE: ${ZBX_DB_NAME}
      MYSQL_USER: ${ZBX_DB_USER}
      MYSQL_PASSWORD: ${ZBX_DB_PASS}
      ZBX_WEB_ALLOW_1: ${ZBX_WEB_ALLOW_1}
      ZBX_WEB_ALLOW_2: ${ZBX_WEB_ALLOW_2}
      ZBX_WEB_ALLOW_3: ${ZBX_WEB_ALLOW_3}
    ports:
      - "${ZBX_WEB_HTTP_PORT}:8080"
      # HTTPS 可选
      # - "${ZBX_WEB_HTTPS_PORT}:8443"
    volumes:
      - ${ZBX_NGX_CONF_DIR}:/etc/nginx/conf.d:rw
      - ${ZBX_TLS_CERT_DIR}:/etc/nginx/certs:rw
      - ${ZBX_NGX_LOG_DIR}:/var/log/nginx:rw
    networks:
      zbx7-net:
        ipv4_address: ${IP_WEB}

  # =========================
  # Zabbix Web Service(仅 amd64)
  # 报表 / Dashboard 截图 / PDF
  # =========================
  zabbix-web-service:
    image: zabbix/zabbix-web-service:7.0.22-ol
    container_name: zbx7-web-service-${ZBX_INSTANCE}
    hostname: zbx7-web-service-${ZBX_INSTANCE}
    restart: unless-stopped
    environment:
      ZBX_ALLOWEDIP: 0.0.0.0/0
      TZ: ${TZ}
    volumes:
      - /data/zbx7/logs/web-service:/var/log/zabbix:rw
    networks:
      - zbx7-net
    # 内部端口 10053,不需要对外暴露

  # =========================
  # Zabbix Java Gateway
  # =========================
  zabbix-java-gateway:
    image: zabbix/zabbix-java-gateway:7.0.22-ol
    container_name: zbx7-web-gw-${ZBX_INSTANCE}
    hostname: zbx7-web-gw-${ZBX_INSTANCE}
    restart: unless-stopped
    environment:
      TZ: ${TZ}
    networks:
      zbx7-net:
        ipv4_address: ${IP_JAVA_GW}

  # =========================
  # Zabbix Agent2
  # =========================
  zabbix-agent2:
    image: zabbix/zabbix-agent2:7.0.22-ol
    container_name: zbx7-agent2-${ZBX_INSTANCE}
    hostname: zbx7-agent2-${ZBX_INSTANCE}
    restart: unless-stopped
    environment:
      ZBX_SERVER_HOST: zabbix-server
      ZBX_HOSTNAME: ${AGENT_HOSTNAME}
      TZ: ${TZ}
    networks:
      zbx7-net:
        ipv4_address: ${IP_AGENT2}

  # =========================
  # Grafana
  # =========================
  grafana:
    image: grafana/grafana:12.3.1
    container_name: zbk7-grafana-${ZBX_INSTANCE}
    hostname: zbk7-grafana-${ZBX_INSTANCE}
    restart: unless-stopped
    environment:
      TZ: ${TZ}
      GF_SECURITY_ADMIN_USER: ${GRAFANA_ADMIN_USER}
      GF_SECURITY_ADMIN_PASSWORD: ${GRAFANA_ADMIN_PASSWORD}
      # 可选:允许匿名访问(不建议生产开启)
      # GF_AUTH_ANONYMOUS_ENABLED: "true"
    ports:
      - "${GRAFANA_PORT}:3000"
    volumes:
      - /data/zbx7/grafana/data:/var/lib/grafana:rw
      - /data/zbx7/logs/grafana:/var/log/grafana:rw
      # 可选:自动导入数据源/仪表盘(你后面要再加)
      - /data/zbx7/grafana/provisioning:/etc/grafana/provisioning:ro
    networks:
      zbx7-net:
        ipv4_address: ${IP_GRAFANA}


networks:
  zbx7-net:
    name: zbx7-net
    driver: bridge
    ipam:
      config:
        - subnet: ${ZBX_NET_SUBNET}
          gateway: ${ZBX_NET_GW}

四、 你上线后怎么判断“这些值该不该继续加/减”

建议在 Zabbix 里给 server 本机套用模板(Zabbix server 自监控),盯三类指标:

  1. Queue(采集队列)是否堆积

  2. 各类进程 busy%(poller/preprocessor/dbsyncer 等是否长期高于 70%)

  3. 缓存命中/使用率(cache 是否经常满)

对应策略很直接:

  • poller busy 高 + queue 堆积 → 加 ZBX_STARTPOLLERS

  • preprocessing busy 高 → 加 ZBX_STARTPREPROCESSORS

  • dbsyncer busy 高 / DB 写入慢 → 加 ZBX_STARTDBSYNCERS 或先优化 MySQL

  • cache 满/抖 → 增大 ZBX_*CACHESIZE


(7天 history 场景最常见的“下一步优化”)

  • 你如果发现 queue 不堆、busy% 很低:可以继续把 StartPollers/Preprocessors 小幅下调,减少上下文切换。

  • 如果发现 dbsyncer busy 高:优先看磁盘写延迟、MySQL redo/flush;7天一般不需要上分区。

如果你把 items 的类型占比(agent passive/active、SNMP、HTTP、trap)告诉我,我还能把 poller/http poller/trapper/preprocessor 的比例配得更“贴脸”。


(30天 history = 尽快做 MySQL 分区

如果你坚持 30 天 history,最稳的长期解法是对 history/trends 表做分区,让“删除过期数据”变成 DROP PARTITION,从 “删百万行” 变成 “删一个分区”,DB 压力会小很多。Zabbix 官方博客也专门给了 MySQL 8 的分区方案思路。

你可以先按方案A跑起来,然后在业务低谷窗口做分区迁移(通常要短暂停写或做切换)。

https://blog.zabbix.com/partitioning-a-zabbix-mysql-database-with-perl-or-stored-procedures/13531/


你上线后,用这 3 个指标判断“还要不要再调”

  1. housekeeper busy(如果长期高,说明 delete 压力太大 → 要么再降 MaxHousekeeperDelete,要么上分区)

  2. dbsyncer busy / history write(高则 DB 写入顶住了)

  3. queue(如果队列有堆积,再加 poller/预处理)



Comment