技术架构概览

本文基于企业级生产环境需求,详细阐述如何构建一个高可用、高性能的 Meilisearch 集群。我们将采用多实例架构,结合负载均衡、数据同步和自动备份等机制,确保搜索引擎服务的持续稳定运行。

核心架构组件

  • Meilisearch 实例集群:多节点部署,提供搜索引擎核心服务
  • Nginx 负载均衡器:分发客户端请求,实现故障自动切换
  • 数据同步服务:确保多实例间的数据一致性
  • 备份服务:定期自动备份数据,防止数据丢失
  • 监控告警系统:实时监控集群状态,及时发现并处理异常

技术栈

  • Docker 20.10+ / Docker Compose 2.0+
  • Meilisearch 1.8+
  • Nginx 1.24+
  • Prometheus 2.45+
  • Grafana 9.5+

本文适合具备一定 Docker 和搜索引擎基础的技术人员,通过系统化的架构设计和详细的配置指南,帮助您构建企业级的 Meilisearch 高可用解决方案。

企业级 Docker Compose 部署高可用 Meilisearch 集群实践

1. Meilisearch 技术深度解析

Meilisearch 是一款基于 Rust 语言开发的现代化开源搜索引擎,专为前端和移动应用设计,其核心价值在于提供低延迟、高相关性的搜索体验。Meilisearch 采用内存优先的设计理念,结合高效的索引结构和查询算法,实现了毫秒级的搜索响应。

1.1 核心技术架构

  • 索引结构:采用多层级索引架构,包括倒排索引(inverted index)、正向索引(forward index)和 trie 树结构。倒排索引优化全文搜索性能,正向索引加速文档检索,trie 树支持高效的前缀搜索和自动补全功能
  • 搜索算法:基于 BM25F 算法的相关性排序,结合词频(TF)、文档频率(DF)、字段权重等多维度因素,支持自定义排序规则和分字段搜索权重
  • 存储引擎:使用 RocksDB 作为底层存储,通过 LSM 树(Log-Structured Merge Tree)优化写入性能,支持数据压缩和高效的范围查询
  • 内存管理:实现智能内存缓存机制,热数据常驻内存,冷数据自动刷盘,通过内存限制参数(max_indexing_memory、max_search_memory)平衡索引和搜索性能
  • API 设计:RESTful API 接口,支持 JSON 格式数据交互,提供丰富的搜索参数和结果格式化选项
  • 实时性:采用增量索引机制,数据变更通过 write-ahead log(WAL)确保持久性,同时通过内存索引保证搜索结果的实时性
  • 并发控制:实现乐观并发控制机制,支持高并发写入和读取操作,通过内部锁机制避免数据竞争

1.2 企业级特性

  • 安全认证:支持 API 密钥认证,提供主密钥(master key)和搜索密钥(search key)两级权限控制,可针对不同索引设置细粒度的访问权限
  • 数据备份:内置快照(snapshot)功能,支持手动和自动快照创建,可基于快照进行数据恢复,确保数据安全性
  • 监控指标:暴露 Prometheus 格式的监控指标,包括索引性能、搜索延迟、内存使用、磁盘 I/O 等关键指标
  • 可扩展性:支持水平扩展,通过负载均衡分发搜索请求,可根据业务需求动态调整实例数量
  • 多语言支持:内置 34 种语言的词干提取和停用词过滤,支持 Unicode 字符集,可处理多语言混合搜索场景
  • 数据导入:支持批量导入和流式导入两种模式,批量导入优化大规模数据加载性能,流式导入适合实时数据更新场景
  • 索引优化:提供自动和手动索引优化机制,可根据数据特性调整索引参数,提升搜索性能

1.3 高可用架构挑战

Meilisearch 作为单节点设计的搜索引擎,在企业级生产环境中面临以下挑战:

  • 单点故障:单节点部署存在服务中断风险,任何硬件或软件故障都可能导致搜索服务不可用
  • 扩展性受限:单节点性能受限于硬件资源,无法通过垂直扩展无限提升处理能力
  • 数据安全:缺乏内置的数据冗余机制,单节点数据损坏可能导致数据丢失
  • 维护窗口:版本升级或维护需要停机,影响业务连续性
  • 网络分区:在分布式环境中,网络分区可能导致数据不一致
  • 负载不均衡:单节点无法有效分担高峰期的搜索请求压力

针对这些挑战,我们需要设计一套完整的高可用架构方案,通过多实例部署、数据同步、负载均衡等机制,确保 Meilisearch 服务的持续稳定运行。

2. 企业级高可用架构设计

基于 Meilisearch 的技术特性和企业级需求,我们设计了一套完整的高可用架构方案。该方案通过多实例部署、负载均衡、数据同步和自动故障转移等机制,确保搜索引擎服务的持续稳定运行。

2.1 架构设计原则

  • 无单点故障:所有核心组件均采用冗余部署,包括 Meilisearch 实例、负载均衡器、监控服务等
  • 自动故障转移:当主实例故障时,通过健康检查和自动切换机制,快速将流量转移到健康实例
  • 数据一致性:实现多实例间的数据实时同步,确保所有实例数据状态一致
  • 性能优化:根据工作负载特性合理分配资源,优化索引和搜索性能
  • 可扩展性:支持水平扩展,可根据业务增长动态调整实例数量
  • 可观测性:建立完善的监控告警体系,实现集群状态的实时可视化
  • 安全性:实施多层次安全防护,包括网络隔离、访问控制、数据加密等
  • 可维护性:设计清晰的架构层次和标准化的配置管理,降低运维复杂度

2.2 高可用实现方案

2.2.1 多实例部署架构

  • 主备架构:1个主实例(处理写操作)+ 2个从实例(处理读操作)
  • 实例分布:建议将实例部署在不同的物理服务器或可用区,提高容灾能力
  • 资源配置:根据搜索流量和数据量,为每个实例分配合理的 CPU、内存和磁盘资源
  • 网络规划:使用专用内部网络连接实例,确保低延迟和高带宽

2.2.2 负载均衡设计

  • 负载均衡器:使用 Nginx 作为前端负载均衡器,支持多种负载均衡策略
  • 健康检查:配置主动和被动健康检查,实时监测实例状态
  • 故障剔除:当实例健康检查失败时,自动将其从负载均衡池中剔除
  • 会话保持:对于需要保持会话的场景,可配置 IP 哈希或 cookie 会话保持
  • SSL 终止:在负载均衡器层面实现 SSL 终止,减轻后端实例的加密/解密负担

2.2.3 数据同步机制

  • 同步策略:实现基于文件系统的实时数据同步,结合 Meilisearch 快照功能
  • 同步频率:根据业务需求配置同步频率,平衡实时性和系统开销
  • 冲突处理:建立数据冲突检测和解决机制,确保数据一致性
  • 同步监控:实时监控同步状态,当同步延迟超过阈值时触发告警
  • 带宽优化:采用增量同步和压缩传输,减少网络带宽消耗

2.2.4 自动备份系统

  • 备份策略:实施 3-2-1 备份策略(3份备份,2种不同媒介,1份异地存储)
  • 备份类型:支持全量备份(每日)、增量备份(每小时)和差异备份(每周)
  • 备份验证:自动验证备份文件的完整性和可恢复性
  • 备份清理:根据保留策略自动清理过期备份,避免存储空间浪费
  • 灾备方案:建立跨地域灾备机制,确保在区域故障时能够快速恢复服务

2.2.5 监控告警体系

  • 监控维度:覆盖实例健康状态、性能指标、资源使用、网络状况等多个维度
  • 告警策略:设置多级告警阈值,根据严重程度采取不同的响应措施
  • 告警渠道:集成邮件、短信、企业即时通讯工具等多种告警渠道
  • 仪表盘:构建统一的监控仪表盘,实现集群状态的实时可视化
  • 根因分析:建立故障根因分析机制,提高问题解决效率

2.2.6 容器编排与管理

  • 编排工具:使用 Docker Compose 管理本地开发和测试环境,为生产环境迁移到 Kubernetes 做准备
  • 服务发现:实现容器间的自动服务发现,简化网络配置
  • 配置管理:使用环境变量和配置文件分离配置与代码,支持不同环境的配置管理
  • 滚动更新:支持服务的滚动更新,减少维护窗口和服务中断
  • 资源限制:为每个容器设置合理的资源限制,避免资源争用和系统不稳定

3. 企业级部署准备

3.1 硬件资源规划

根据业务规模和搜索数据量,合理规划硬件资源,以下是详细的资源配置指南:

部署规模文档数量CPU内存磁盘网络适用场景
小型<100万4核8GB+200GB SSD1Gbps小型应用、测试环境
中型100-500万8核16GB+500GB SSD1Gbps+中型应用、生产环境
大型500万-2000万16核+32GB+1TB+ SSD10Gbps大型应用、高并发场景
超大型>2000万32核+64GB+2TB+ NVMe SSD25Gbps超大流量、企业级应用

资源规划考量因素:

  • CPU:搜索操作是 CPU 密集型,特别是复杂查询和排序操作,建议选择高主频、多核心的 CPU
  • 内存:Meilisearch 将热数据和索引驻留内存,内存大小直接影响搜索性能,建议内存至少为索引大小的 2-3 倍
  • 磁盘:选择低延迟、高 IOPS 的 SSD 或 NVMe 存储,特别是对于索引构建和数据持久化操作
  • 网络:确保内部网络带宽充足,特别是在多实例部署和数据同步场景下

3.2 软件环境要求

  • 操作系统:Ubuntu 20.04 LTS / CentOS 7.9+ / RHEL 8.4+,推荐使用 LTS 版本以获得长期支持
  • Docker:20.10.17+(推荐最新稳定版),确保支持 overlay2 存储驱动
  • Docker Compose:2.10.2+(推荐使用 Compose V2),支持最新的 Compose 文件格式
  • 内核版本:4.19+,支持容器技术和存储优化特性
  • 文件系统:XFS 或 EXT4(推荐 XFS),XFS 在处理大文件和高并发场景下性能更优
  • 系统依赖:确保安装必要的系统依赖,如 curl、wget、openssl 等

3.3 系统调优配置

Linux 内核调优:

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
# 编辑 /etc/sysctl.conf
sudo nano /etc/sysctl.conf

# 添加以下配置
# 网络优化
net.core.somaxconn = 65535
net.ipv4.tcp_max_syn_backlog = 65535
net.ipv4.tcp_fin_timeout = 30
net.ipv4.tcp_keepalive_time = 300
net.ipv4.tcp_keepalive_probes = 5
net.ipv4.tcp_keepalive_intvl = 15
net.ipv4.tcp_fastopen = 3
net.core.netdev_max_backlog = 65535

# 内存管理
vm.swappiness = 10
vm.max_map_count = 262144
vm.overcommit_memory = 1

# 文件系统
fs.file-max = 655350
fs.nr_open = 655350

# 应用配置
sudo sysctl -p

文件描述符调优:

1
2
3
4
5
6
7
8
# 编辑 /etc/security/limits.conf
sudo nano /etc/security/limits.conf

# 添加以下配置
* soft nofile 65535
* hard nofile 65535
docker soft nofile 65535
docker hard nofile 65535

3.4 网络配置要求

  • 内部网络:所有容器实例间网络延迟 < 1ms,建议使用专用的内部网络或 VLAN
  • 网络拓扑:采用分层网络架构,前端负载均衡层、应用服务层、存储层分离
  • 安全组规则:仅开放必要端口,限制访问来源,建议使用防火墙规则加强网络安全
  • DNS 解析:确保容器间通过服务名正常通信,配置可靠的 DNS 服务
  • 负载均衡:外部流量通过 Nginx 或云负载均衡器分发,实现流量的智能调度
  • 网络监控:部署网络监控工具,实时监测网络性能和异常情况

3.5 存储配置优化

  • 存储类型:选择 SSD 或 NVMe 存储,提供高 IOPS 和低延迟
  • 存储规划:为数据、备份、日志等不同类型的数据分配独立的存储空间
  • RAID 配置:对于关键业务,建议配置 RAID 10 以提高存储可靠性和性能
  • 挂载选项:优化文件系统挂载选项,提高 I/O 性能
  • 存储监控:实施存储监控,及时发现存储异常和容量告警

3.6 企业级目录结构设计

为了确保系统的可维护性、安全性和可扩展性,我们采用分层目录结构设计:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
mkdir -p meilisearch-ha/{
# 数据存储目录
data/{meilisearch-1,meilisearch-2},
# 备份目录(按周期分类)
backup/{daily,weekly,monthly,manual},
# 配置文件目录(按服务分类)
conf/{nginx,prometheus,grafana,meilisearch},
# 脚本目录(按功能分类)
scripts/{sync,backup,monitor,maintenance},
# 日志目录(按服务分类)
logs/{nginx,meilisearch,sync,backup,prometheus,grafana},
# SSL 证书目录
ssl,
# 临时文件目录
tmp
}
cd meilisearch-ha

3.7 目录权限配置

设置合理的目录权限,确保安全性和可操作性:

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
# 设置数据目录权限(读写执行,仅所有者和组可访问)
chmod -R 750 data/

# 设置备份目录权限(更严格,仅所有者可访问)
chmod -R 700 backup/

# 设置脚本目录权限(读写执行,所有者可写,其他人可读执行)
chmod -R 755 scripts/
chmod +x scripts/**/*.sh

# 设置配置目录权限(只读,所有人可读)
chmod -R 644 conf/

# 设置日志目录权限(读写执行,所有者和组可写)
chmod -R 750 logs/

# 设置 SSL 证书目录权限(严格控制,仅所有者可访问)
chmod -R 700 ssl/

# 设置临时文件目录权限
chmod -R 775 tmp/

# 设置目录所有者(确保 Docker 容器可访问)
chown -R 1000:1000 data/ logs/ tmp/
chown -R root:root conf/ ssl/
chown -R root:root scripts/

3.8 企业级配置文件管理

3.8.1 配置文件版本控制

  • Git 管理:将配置文件纳入 Git 版本控制,跟踪配置变更历史
  • 配置分支:为不同环境(开发、测试、生产)创建独立的配置分支
  • 配置审计:实施配置变更审计机制,记录每次配置修改的原因和影响
  • 配置回滚:建立配置回滚机制,当配置变更导致问题时快速回滚到稳定版本

3.8.2 环境变量管理

  • 敏感信息保护:使用环境变量存储敏感信息,避免硬编码到配置文件
  • 环境变量文件:为不同环境创建对应的 .env 文件,使用 .env.example 作为模板
  • 变量验证:在启动脚本中添加环境变量验证逻辑,确保所有必要的变量都已设置
  • 变量加密:对于特别敏感的信息,考虑使用密钥管理服务进行加密存储

3.8.3 配置自动化

  • 配置生成:使用脚本或配置管理工具自动生成配置文件
  • 配置同步:在多环境部署时,确保配置的一致性和同步更新
  • 配置检查:定期检查配置文件的完整性和有效性
  • 配置文档:为所有配置项编写详细的文档,说明其用途和推荐值

3.9 企业级配置文件设计

3.9.1 环境变量配置

创建 .env 文件,设置 Meilisearch 核心配置:

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
# Meilisearch 核心配置
# 主密钥(生产环境应使用强密钥,建议至少 32 字符)
MEILI_MASTER_KEY=$(openssl rand -base64 32)

# 环境设置(development/production)
MEILI_ENV=production

# 数据存储配置
MEILI_DB_PATH=/data
MEILI_SNAPSHOT_DIR=/backup/snapshots

# 网络配置
MEILI_HTTP_ADDR=0.0.0.0:7700
MEILI_HTTP_TIMEOUT=60s
MEILI_HTTP_MAX_BODY_SIZE=100m

# 性能优化配置
MEILI_MAX_INDEXING_MEMORY=4096 # 索引内存限制(MB),建议为系统内存的 50-70%
MEILI_MAX_SEARCH_MEMORY=2048 # 搜索内存限制(MB),建议为系统内存的 30-50%
MEILI_OPTIMIZE_INTERVAL=86400 # 索引优化间隔(秒)
MEILI_SNAPSHOT_INTERVAL=3600 # 快照创建间隔(秒)

# 日志配置
MEILI_LOG_LEVEL=info # 日志级别(debug/info/warn/error)
MEILI_LOG_FILE=/logs/meilisearch.log

# 安全配置
MEILI_NO_ANALYTICS=true # 禁用分析
MEILI_NO_CORS=false # 启用 CORS
MEILI_ALLOW_ORIGINS=* # 允许的来源

# 备份配置
BACKUP_RETENTION_DAYS=30 # 备份保留天数
BACKUP_INTERVAL=3600 # 备份间隔(秒)
BACKUP_DIR=/backup

# 监控配置
PROMETHEUS_ENABLED=true # 启用 Prometheus 监控

# 资源限制
RESOURCE_CPU_LIMIT=4.0 # CPU 限制(核)
RESOURCE_MEMORY_LIMIT=8g # 内存限制
RESOURCE_CPU_RESERVATION=2.0 # CPU 预留(核)
RESOURCE_MEMORY_RESERVATION=4g # 内存预留

# 网络配置
NETWORK_SUBNET=172.22.0.0/16 # 容器网络子网
NETWORK_NAME=meilisearch-network

# 服务配置
NGINX_PORT=7700 # Nginx 监听端口
PROMETHEUS_PORT=9090 # Prometheus 端口
GRAFANA_PORT=3000 # Grafana 端口

3.9.2 配置文件管理最佳实践

  1. 使用 Git 管理配置文件

    • 将配置文件纳入版本控制,创建独立的配置仓库
    • 使用 .gitignore 排除敏感信息文件(如 .env
    • 建立配置变更审批流程,确保配置变更的安全性和可追溯性
    • 实施配置变更测试,在非生产环境验证配置变更效果
  2. 配置文件备份与恢复

    • 定期备份配置文件,与数据备份保持同步
    • 保存配置文件的历史版本,建立配置文件版本库
    • 建立配置回滚机制,当配置变更导致问题时快速回滚
    • 实施配置文件完整性检查,确保配置文件未被篡改
  3. 多环境配置管理

    • 为不同环境(开发、测试、预生产、生产)创建独立的配置集
    • 使用配置模板和变量替换,减少配置重复
    • 实施配置继承机制,基础配置共享,环境特定配置覆盖
    • 建立配置一致性检查,确保关键配置在各环境中的一致性
  4. 配置安全管理

    • 使用密钥管理服务存储敏感配置(如密码、API 密钥)
    • 实施配置文件访问控制,限制敏感配置的访问权限
    • 加密存储敏感配置文件,防止配置泄露
    • 定期轮换配置中的敏感信息,如密码和密钥

4. 企业级 Docker Compose 配置

4.1 基础单节点部署

创建 docker-compose.yml 文件,包含完整的企业级特性:

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
version: '3.8'

# 定义外部网络(可选,用于与其他服务集成)
networks:
meilisearch-network:
driver: bridge
ipam:
config:
- subnet: ${NETWORK_SUBNET:-172.22.0.0/16}
driver_opts:
com.docker.network.bridge.name: "meilisearch-br"
com.docker.network.bridge.enable_icc: "true"
com.docker.network.bridge.enable_ip_masquerade: "true"
com.docker.network.bridge.host_binding_ipv4: "0.0.0.0"

services:
# Meilisearch 服务
meilisearch:
image: getmeili/meilisearch:v1.8 # 使用稳定版本
container_name: meilisearch
ports:
- "${NGINX_PORT:-7700}:7700" # 使用环境变量定义端口
volumes:
- ./data:/data:rw # 数据持久化
- ./logs/meilisearch:/logs:rw # 日志持久化
- ./ssl:/etc/ssl/meilisearch:ro # SSL 证书(只读)
- ./tmp:/tmp:rw # 临时文件目录
environment:
# 核心配置
- MEILI_MASTER_KEY=${MEILI_MASTER_KEY}
- MEILI_ENV=${MEILI_ENV:-production}
- MEILI_DB_PATH=${MEILI_DB_PATH:-/data}
- MEILI_SNAPSHOT_DIR=${MEILI_SNAPSHOT_DIR:-/backup/snapshots}

# 网络配置
- MEILI_HTTP_ADDR=${MEILI_HTTP_ADDR:-0.0.0.0:7700}
- MEILI_HTTP_TIMEOUT=${MEILI_HTTP_TIMEOUT:-60s}
- MEILI_HTTP_MAX_BODY_SIZE=${MEILI_HTTP_MAX_BODY_SIZE:-100m}

# 性能优化配置
- MEILI_MAX_INDEXING_MEMORY=${MEILI_MAX_INDEXING_MEMORY:-4096}
- MEILI_MAX_SEARCH_MEMORY=${MEILI_MAX_SEARCH_MEMORY:-2048}
- MEILI_OPTIMIZE_INTERVAL=${MEILI_OPTIMIZE_INTERVAL:-86400}
- MEILI_SNAPSHOT_INTERVAL=${MEILI_SNAPSHOT_INTERVAL:-3600}

# 日志配置
- MEILI_LOG_LEVEL=${MEILI_LOG_LEVEL:-info}
- MEILI_LOG_FILE=${MEILI_LOG_FILE:-/logs/meilisearch.log}

# 安全配置
- MEILI_NO_ANALYTICS=${MEILI_NO_ANALYTICS:-true}
- MEILI_NO_CORS=${MEILI_NO_CORS:-false}
- MEILI_ALLOW_ORIGINS=${MEILI_ALLOW_ORIGINS:-*}

# 系统配置
- TZ=Asia/Shanghai # 时区设置
restart: always # 自动重启
healthcheck:
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:7700/health"]
interval: 30s # 健康检查间隔
timeout: 10s # 超时时间
retries: 3 # 重试次数
start_period: 60s # 启动等待时间
resources:
# 资源限制
limits:
cpus: '${RESOURCE_CPU_LIMIT:-2.0}'
memory: '${RESOURCE_MEMORY_LIMIT:-4g}'
# 资源预留
reservations:
cpus: '${RESOURCE_CPU_RESERVATION:-1.0}'
memory: '${RESOURCE_MEMORY_RESERVATION:-2g}'
security_opt:
# 安全选项
- no-new-privileges:true # 禁止获得新权限
- seccomp:unconfined # 允许使用所有系统调用
ulimits:
# 文件描述符限制
nofile:
soft: 65535
hard: 65535
# 进程数限制
nproc:
soft: 65535
hard: 65535
networks:
- meilisearch-network
logging:
# 日志配置
driver: "json-file"
options:
max-size: "10m" # 单个日志文件大小
max-file: "5" # 日志文件数量
compress: "true" # 启用压缩

# 监控服务(可选)
prometheus:
image: prom/prometheus:v2.45
container_name: prometheus
ports:
- "${PROMETHEUS_PORT:-9090}:9090"
volumes:
- ./conf/prometheus/prometheus.yml:/etc/prometheus/prometheus.yml:ro
- ./data/prometheus:/prometheus:rw
restart: always
depends_on:
- meilisearch
networks:
- meilisearch-network

# 可视化服务(可选)
grafana:
image: grafana/grafana:9.5.2
container_name: grafana
ports:
- "${GRAFANA_PORT:-3000}:3000"
volumes:
- ./data/grafana:/var/lib/grafana:rw
- ./conf/grafana:/etc/grafana/provisioning:ro
restart: always
depends_on:
- prometheus
networks:
- meilisearch-network

4.2 企业级高可用部署

创建 docker-compose-ha.yml 文件,包含完整的企业级特性:

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
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
version: '3.8'

# 网络配置
networks:
meilisearch-network:
driver: bridge
ipam:
config:
- subnet: ${NETWORK_SUBNET:-172.22.0.0/16}
driver_opts:
com.docker.network.bridge.name: "meilisearch-br"
com.docker.network.bridge.enable_icc: "true"
com.docker.network.bridge.enable_ip_masquerade: "true"
com.docker.network.bridge.host_binding_ipv4: "0.0.0.0"
internal: false # 允许外部访问

# 卷配置
volumes:
# 数据卷
meilisearch-1-data:
driver: local
driver_opts:
type: none
device: ./data/meilisearch-1
o: bind
meilisearch-2-data:
driver: local
driver_opts:
type: none
device: ./data/meilisearch-2
o: bind
# 备份卷
backup-volume:
driver: local
driver_opts:
type: none
device: ./backup
o: bind
# 监控数据卷
prometheus-data:
driver: local
driver_opts:
type: none
device: ./data/prometheus
o: bind
grafana-data:
driver: local
driver_opts:
type: none
device: ./data/grafana
o: bind

# 服务配置
services:
# Meilisearch 实例 1(主实例)
meilisearch-1:
image: getmeili/meilisearch:v1.8 # 使用稳定版本
container_name: meilisearch-1
hostname: meilisearch-1
volumes:
- meilisearch-1-data:/data:rw
- ./logs/meilisearch-1:/logs:rw
- ./ssl:/etc/ssl/meilisearch:ro
- ./tmp:/tmp:rw
environment:
# 核心配置
- MEILI_MASTER_KEY=${MEILI_MASTER_KEY}
- MEILI_ENV=${MEILI_ENV:-production}
- MEILI_DB_PATH=${MEILI_DB_PATH:-/data}
- MEILI_SNAPSHOT_DIR=${MEILI_SNAPSHOT_DIR:-/backup/snapshots}

# 网络配置
- MEILI_HTTP_ADDR=${MEILI_HTTP_ADDR:-0.0.0.0:7700}
- MEILI_HTTP_TIMEOUT=${MEILI_HTTP_TIMEOUT:-60s}
- MEILI_HTTP_MAX_BODY_SIZE=${MEILI_HTTP_MAX_BODY_SIZE:-100m}

# 性能优化配置
- MEILI_MAX_INDEXING_MEMORY=${MEILI_MAX_INDEXING_MEMORY:-4096}
- MEILI_MAX_SEARCH_MEMORY=${MEILI_MAX_SEARCH_MEMORY:-2048}
- MEILI_OPTIMIZE_INTERVAL=${MEILI_OPTIMIZE_INTERVAL:-86400}
- MEILI_SNAPSHOT_INTERVAL=${MEILI_SNAPSHOT_INTERVAL:-3600}

# 日志配置
- MEILI_LOG_LEVEL=${MEILI_LOG_LEVEL:-info}
- MEILI_LOG_FILE=${MEILI_LOG_FILE:-/logs/meilisearch.log}

# 安全配置
- MEILI_NO_ANALYTICS=${MEILI_NO_ANALYTICS:-true}
- MEILI_NO_CORS=${MEILI_NO_CORS:-false}
- MEILI_ALLOW_ORIGINS=${MEILI_ALLOW_ORIGINS:-*}

# 系统配置
- TZ=Asia/Shanghai
restart: always
healthcheck:
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:7700/health"]
interval: 15s
timeout: 5s
retries: 3
start_period: 60s
resources:
limits:
cpus: '${RESOURCE_CPU_LIMIT:-4.0}'
memory: '${RESOURCE_MEMORY_LIMIT:-8g}'
reservations:
cpus: '${RESOURCE_CPU_RESERVATION:-2.0}'
memory: '${RESOURCE_MEMORY_RESERVATION:-4g}'
security_opt:
- no-new-privileges:true
- seccomp:unconfined
ulimits:
nofile:
soft: 65535
hard: 65535
nproc:
soft: 65535
hard: 65535
networks:
- meilisearch-network
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "5"
compress: "true"

# Meilisearch 实例 2(从实例)
meilisearch-2:
image: getmeili/meilisearch:v1.8
container_name: meilisearch-2
hostname: meilisearch-2
volumes:
- meilisearch-2-data:/data:rw
- ./logs/meilisearch-2:/logs:rw
- ./ssl:/etc/ssl/meilisearch:ro
- ./tmp:/tmp:rw
environment:
# 核心配置
- MEILI_MASTER_KEY=${MEILI_MASTER_KEY}
- MEILI_ENV=${MEILI_ENV:-production}
- MEILI_DB_PATH=${MEILI_DB_PATH:-/data}
- MEILI_SNAPSHOT_DIR=${MEILI_SNAPSHOT_DIR:-/backup/snapshots}

# 网络配置
- MEILI_HTTP_ADDR=${MEILI_HTTP_ADDR:-0.0.0.0:7700}
- MEILI_HTTP_TIMEOUT=${MEILI_HTTP_TIMEOUT:-60s}
- MEILI_HTTP_MAX_BODY_SIZE=${MEILI_HTTP_MAX_BODY_SIZE:-100m}

# 性能优化配置
- MEILI_MAX_INDEXING_MEMORY=${MEILI_MAX_INDEXING_MEMORY:-4096}
- MEILI_MAX_SEARCH_MEMORY=${MEILI_MAX_SEARCH_MEMORY:-2048}
- MEILI_OPTIMIZE_INTERVAL=${MEILI_OPTIMIZE_INTERVAL:-86400}
- MEILI_SNAPSHOT_INTERVAL=${MEILI_SNAPSHOT_INTERVAL:-3600}

# 日志配置
- MEILI_LOG_LEVEL=${MEILI_LOG_LEVEL:-info}
- MEILI_LOG_FILE=${MEILI_LOG_FILE:-/logs/meilisearch.log}

# 安全配置
- MEILI_NO_ANALYTICS=${MEILI_NO_ANALYTICS:-true}
- MEILI_NO_CORS=${MEILI_NO_CORS:-false}
- MEILI_ALLOW_ORIGINS=${MEILI_ALLOW_ORIGINS:-*}

# 系统配置
- TZ=Asia/Shanghai
restart: always
healthcheck:
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:7700/health"]
interval: 15s
timeout: 5s
retries: 3
start_period: 60s
resources:
limits:
cpus: '${RESOURCE_CPU_LIMIT:-4.0}'
memory: '${RESOURCE_MEMORY_LIMIT:-8g}'
reservations:
cpus: '${RESOURCE_CPU_RESERVATION:-2.0}'
memory: '${RESOURCE_MEMORY_RESERVATION:-4g}'
security_opt:
- no-new-privileges:true
- seccomp:unconfined
ulimits:
nofile:
soft: 65535
hard: 65535
nproc:
soft: 65535
hard: 65535
networks:
- meilisearch-network
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "5"
compress: "true"

# 负载均衡器(Nginx)
nginx:
image: nginx:1.24-alpine
container_name: nginx-meilisearch
hostname: nginx-meilisearch
ports:
- "${NGINX_PORT:-7700}:7700"
volumes:
- ./conf/nginx/nginx.conf:/etc/nginx/nginx.conf:ro
- ./conf/nginx/conf.d:/etc/nginx/conf.d:ro
- ./logs/nginx:/var/log/nginx:rw
- ./ssl:/etc/nginx/ssl:ro
environment:
- TZ=Asia/Shanghai
restart: always
depends_on:
- meilisearch-1
- meilisearch-2
healthcheck:
test: ["CMD", "nginx", "-t"]
interval: 30s
timeout: 10s
retries: 3
start_period: 60s
resources:
limits:
cpus: '1.0'
memory: '512m'
reservations:
cpus: '0.5'
memory: '256m'
security_opt:
- no-new-privileges:true
- seccomp:unconfined
ulimits:
nofile:
soft: 65535
hard: 65535
networks:
- meilisearch-network
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "5"
compress: "true"

# 数据同步服务
sync-service:
image: alpine:3.18
container_name: meilisearch-sync
hostname: meilisearch-sync
volumes:
- ./data:/data:rw
- ./scripts/sync:/scripts:ro
- ./logs/sync:/logs:rw
- ./tmp:/tmp:rw
environment:
- TZ=Asia/Shanghai
- MASTER_DATA_DIR=/data/meilisearch-1
- SLAVE_DATA_DIR=/data/meilisearch-2
- SYNC_INTERVAL=60
- LOG_DIR=/logs
command: sh /scripts/sync.sh
restart: always
depends_on:
- meilisearch-1
- meilisearch-2
resources:
limits:
cpus: '0.5'
memory: '256m'
reservations:
cpus: '0.25'
memory: '128m'
security_opt:
- no-new-privileges:true
networks:
- meilisearch-network
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "5"
compress: "true"

# 自动备份服务
backup-service:
image: alpine:3.18
container_name: meilisearch-backup
hostname: meilisearch-backup
volumes:
- backup-volume:/backup:rw
- ./data/meilisearch-1:/data:ro
- ./scripts/backup:/scripts:ro
- ./logs/backup:/logs:rw
- ./tmp:/tmp:rw
environment:
- TZ=Asia/Shanghai
- BACKUP_DIR=/backup
- DATA_DIR=/data
- BACKUP_RETENTION_DAYS=30
- BACKUP_INTERVAL=3600
- LOG_DIR=/logs
command: sh /scripts/backup.sh
restart: always
depends_on:
- meilisearch-1
resources:
limits:
cpus: '1.0'
memory: '512m'
reservations:
cpus: '0.5'
memory: '256m'
security_opt:
- no-new-privileges:true
networks:
- meilisearch-network
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "5"
compress: "true"

# Prometheus 监控
prometheus:
image: prom/prometheus:v2.45
container_name: prometheus
hostname: prometheus
volumes:
- prometheus-data:/prometheus:rw
- ./conf/prometheus/prometheus.yml:/etc/prometheus/prometheus.yml:ro
- ./conf/prometheus/rules.yml:/etc/prometheus/rules.yml:ro
- ./logs/prometheus:/var/log/prometheus:rw
ports:
- "${PROMETHEUS_PORT:-9090}:9090"
environment:
- TZ=Asia/Shanghai
restart: always
depends_on:
- meilisearch-1
- meilisearch-2
resources:
limits:
cpus: '1.0'
memory: '1g'
reservations:
cpus: '0.5'
memory: '512m'
security_opt:
- no-new-privileges:true
networks:
- meilisearch-network
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "5"
compress: "true"

# Grafana 可视化
grafana:
image: grafana/grafana:9.5.2
container_name: grafana
hostname: grafana
volumes:
- grafana-data:/var/lib/grafana:rw
- ./conf/grafana:/etc/grafana/provisioning:ro
- ./logs/grafana:/var/log/grafana:rw
ports:
- "${GRAFANA_PORT:-3000}:3000"
environment:
- TZ=Asia/Shanghai
- GF_SECURITY_ADMIN_PASSWORD=${GRAFANA_ADMIN_PASSWORD:-admin}
- GF_USERS_ALLOW_SIGN_UP=false
- GF_INSTALL_PLUGINS=grafana-clock-panel,grafana-simple-json-datasource
restart: always
depends_on:
- prometheus
resources:
limits:
cpus: '1.0'
memory: '1g'
reservations:
cpus: '0.5'
memory: '512m'
security_opt:
- no-new-privileges:true
networks:
- meilisearch-network
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "5"
compress: "true"

4.3 企业级 Nginx 配置

创建 conf/nginx/nginx.conf 文件,包含完整的企业级优化配置:

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
# 全局配置
user nginx;
worker_processes auto;
pid /var/run/nginx.pid;

events {
worker_connections 4096;
multi_accept on;
use epoll;
}

http {
# 基本配置
include /etc/nginx/mime.types;
default_type application/octet-stream;

# 日志配置
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for" '
'"$upstream_addr" "$upstream_status" "$upstream_response_time"';
access_log /var/log/nginx/access.log main;
error_log /var/log/nginx/error.log warn;

# 性能优化
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
keepalive_requests 100;
client_header_timeout 10;
client_body_timeout 10;
send_timeout 10;

# 缓冲区配置
client_max_body_size 10m;
client_body_buffer_size 16k;
client_header_buffer_size 1k;
large_client_header_buffers 4 8k;

# Gzip 压缩
gzip on;
gzip_comp_level 6;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
gzip_min_length 1024;
gzip_proxied any;

# 上游服务器配置
upstream meilisearch {
# 轮询策略
least_conn; # 最少连接数

# 服务器配置
server meilisearch-1:7700 max_fails=3 fail_timeout=30s weight=1;
server meilisearch-2:7700 max_fails=3 fail_timeout=30s weight=1;

# 健康检查
keepalive 32;
}

# 主服务器配置
server {
listen 7700 default_server;
listen [::]:7700 default_server;
server_name localhost;

# 安全头部
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;

# 主要位置配置
location / {
# 代理配置
proxy_pass http://meilisearch;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Connection "";

# 超时配置
proxy_connect_timeout 10s;
proxy_send_timeout 10s;
proxy_read_timeout 30s;

# 缓冲区配置
proxy_buffers 8 16k;
proxy_buffer_size 32k;
proxy_busy_buffers_size 64k;

# 故障转移
proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;
proxy_next_upstream_tries 3;
}

# 健康检查端点
location /health {
proxy_pass http://meilisearch;
access_log off;
log_not_found off;
}

# 监控端点
location /nginx_status {
stub_status on;
access_log off;
allow 127.0.0.1;
deny all;
}
}
}

4.4 企业级数据同步脚本

创建 scripts/sync/sync.sh 文件,包含完整的企业级数据同步功能:

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
#!/bin/sh

# 企业级数据同步脚本
# 功能:实时监控主实例数据变化,同步到从实例
# 特性:增量同步、错误处理、日志记录、监控告警

# 配置参数
MASTER_DATA_DIR="/data/meilisearch-1"
SLAVE_DATA_DIR="/data/meilisearch-2"
SYNC_INTERVAL=60 # 同步间隔(秒)
LOG_DIR="/logs"
LOG_FILE="$LOG_DIR/sync.log"
LOCK_FILE="/tmp/sync.lock"
MAX_RETRIES=3 # 最大重试次数

# 确保日志目录存在
mkdir -p "$LOG_DIR"

# 日志函数
log() {
local level=$1
local message=$2
echo "[$(date '+%Y-%m-%d %H:%M:%S')] [$level] $message" >> "$LOG_FILE"
echo "[$(date '+%Y-%m-%d %H:%M:%S')] [$level] $message"
}

# 错误处理函数
error_handler() {
local error_message=$1
log "ERROR" "$error_message"
# 这里可以添加告警逻辑,如发送邮件或调用监控API
}

# 检查锁定文件,防止脚本重复执行
if [ -f "$LOCK_FILE" ]; then
log "WARN" "Sync script is already running, exiting..."
exit 1
fi

# 创建锁定文件
touch "$LOCK_FILE"

# 清理函数(退出时执行)
cleanup() {
rm -f "$LOCK_FILE"
log "INFO" "Sync script exited gracefully"
}

# 注册清理函数
trap cleanup EXIT

# 等待服务启动
log "INFO" "Waiting for Meilisearch services to start..."
sleep 30

# 主同步循环
while true; do
log "INFO" "Starting data sync cycle..."

# 检查主实例数据目录是否存在
if [ ! -d "$MASTER_DATA_DIR" ]; then
error_handler "Master data directory not found: $MASTER_DATA_DIR"
sleep $SYNC_INTERVAL
continue
fi

# 检查从实例数据目录是否存在
if [ ! -d "$SLAVE_DATA_DIR" ]; then
log "INFO" "Slave data directory not found, creating: $SLAVE_DATA_DIR"
mkdir -p "$SLAVE_DATA_DIR"
if [ $? -ne 0 ]; then
error_handler "Failed to create slave data directory"
sleep $SYNC_INTERVAL
continue
fi
fi

# 执行同步(带重试机制)
retry_count=0
sync_success=false

while [ $retry_count -lt $MAX_RETRIES ]; do
log "INFO" "Sync attempt $((retry_count + 1))/$MAX_RETRIES"

# 执行 rsync 同步
rsync -avz --delete --exclude="*.lock" --exclude="*.tmp" --bwlimit=10240 "$MASTER_DATA_DIR/" "$SLAVE_DATA_DIR/"

if [ $? -eq 0 ]; then
sync_success=true
log "INFO" "Data sync completed successfully"
break
else
retry_count=$((retry_count + 1))
error_handler "Data sync failed, retrying in 10 seconds..."
sleep 10
fi
done

if [ "$sync_success" = false ]; then
error_handler "Data sync failed after $MAX_RETRIES attempts"
fi

# 同步后验证
if [ "$sync_success" = true ]; then
# 检查关键文件是否同步成功
if [ -f "$MASTER_DATA_DIR/data.ms/payload.bin" ] && [ -f "$SLAVE_DATA_DIR/data.ms/payload.bin" ]; then
log "INFO" "Sync verification passed: Key files exist in both directories"
else
error_handler "Sync verification failed: Key files missing"
fi
fi

# 等待下一次同步
log "INFO" "Sync cycle completed, waiting for next interval..."
sleep $SYNC_INTERVAL
done

设置脚本执行权限:

1
chmod +x scripts/sync/sync.sh

5. 企业级部署步骤

5.1 部署前准备

  1. 环境检查

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    # 检查 Docker 版本
    docker --version

    # 检查 Docker Compose 版本
    docker compose version

    # 检查系统资源
    free -h
    df -h

    # 检查网络连接
    ping -c 4 getmeili.com
  2. 生成配置文件

    1
    2
    3
    4
    5
    6
    7
    8
    # 生成 .env 文件
    cp .env.example .env

    # 生成强密钥
    sed -i "s|MEILI_MASTER_KEY=.*|MEILI_MASTER_KEY=$(openssl rand -base64 32)|g" .env

    # 验证配置
    cat .env
  3. 创建必要目录

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    # 创建目录结构
    mkdir -p meilisearch-ha/{
    data/{meilisearch-1,meilisearch-2},
    backup/{daily,weekly,monthly},
    conf/{nginx,prometheus,grafana},
    scripts/{sync,backup,monitor},
    logs/{nginx,meilisearch,sync,backup}
    }

    # 设置权限
    chmod -R 755 data/ logs/
    chmod -R 700 backup/
    chmod -R 755 scripts/
    chmod +x scripts/**/*.sh
    chmod -R 644 conf/

5.2 单节点部署

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 进入部署目录
cd meilisearch-ha

# 启动服务
docker-compose up -d

# 检查服务状态
docker-compose ps

# 查看启动日志
docker-compose logs -f --tail=100

# 验证服务健康状态
docker-compose exec meilisearch wget --no-verbose --tries=1 --spider http://localhost:7700/health

# 验证 API 可用性
curl -X GET "http://localhost:7700/health" -H "Authorization: Bearer $(grep MEILI_MASTER_KEY .env | cut -d '=' -f2)"

5.3 企业级高可用部署

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
# 进入部署目录
cd meilisearch-ha

# 启动高可用服务
docker-compose -f docker-compose-ha.yml up -d

# 检查服务状态
docker-compose -f docker-compose-ha.yml ps

# 查看启动日志(按服务查看)
docker-compose -f docker-compose-ha.yml logs -f meilisearch-1 --tail=100
docker-compose -f docker-compose-ha.yml logs -f nginx --tail=100
docker-compose -f docker-compose-ha.yml logs -f sync-service --tail=100

# 验证所有服务健康状态
for service in meilisearch-1 meilisearch-2 nginx;
do
echo "Checking $service..."
docker-compose -f docker-compose-ha.yml exec $service wget --no-verbose --tries=1 --spider http://localhost:7700/health 2>&1 || echo "$service health check failed"
done

# 验证负载均衡
curl -X GET "http://localhost:7700/health" -H "Authorization: Bearer $(grep MEILI_MASTER_KEY .env | cut -d '=' -f2)"

# 验证数据同步
# 1. 在主实例创建测试索引
docker-compose -f docker-compose-ha.yml exec meilisearch-1 curl -X POST "http://localhost:7700/indexes/test" -H "Authorization: Bearer $(grep MEILI_MASTER_KEY .env | cut -d '=' -f2)"

# 2. 等待同步完成
sleep 10

# 3. 在从实例验证索引是否存在
docker-compose -f docker-compose-ha.yml exec meilisearch-2 curl -X GET "http://localhost:7700/indexes" -H "Authorization: Bearer $(grep MEILI_MASTER_KEY .env | cut -d '=' -f2)"

6. 企业级 Meilisearch 测试与验证

6.1 基础功能测试

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
# 设置 MASTER_KEY 变量
MASTER_KEY=$(grep MEILI_MASTER_KEY .env | cut -d '=' -f2)

# 1. 健康检查
curl -X GET "http://localhost:7700/health" -H "Authorization: Bearer $MASTER_KEY"

# 2. 创建索引
curl -X POST "http://localhost:7700/indexes/books" \
-H "Authorization: Bearer $MASTER_KEY" \
-H "Content-Type: application/json" \
-d '{"uid": "books", "primaryKey": "id"}'

# 3. 添加文档
curl -X POST "http://localhost:7700/indexes/books/documents" \
-H "Authorization: Bearer $MASTER_KEY" \
-H "Content-Type: application/json" \
-d '[{"id": 1, "title": "The Great Gatsby", "author": "F. Scott Fitzgerald", "genre": "Fiction", "year": 1925}, {"id": 2, "title": "To Kill a Mockingbird", "author": "Harper Lee", "genre": "Fiction", "year": 1960}, {"id": 3, "title": "1984", "author": "George Orwell", "genre": "Dystopian", "year": 1949}]'

# 4. 搜索测试
curl -X GET "http://localhost:7700/indexes/books/search?q=gatsby" -H "Authorization: Bearer $MASTER_KEY"

# 5. 高级搜索测试(带过滤和排序)
curl -X GET "http://localhost:7700/indexes/books/search?q=fiction&filter=year>1950&sort=year:desc" -H "Authorization: Bearer $MASTER_KEY"

# 6. 验证索引状态
curl -X GET "http://localhost:7700/indexes/books/stats" -H "Authorization: Bearer $MASTER_KEY"

6.2 高可用功能测试

6.2.1 负载均衡测试

1
2
3
4
5
6
7
8
9
10
11
12
# 查看 Nginx 配置状态
docker-compose -f docker-compose-ha.yml exec nginx nginx -t

# 查看 Nginx 连接状态
docker-compose -f docker-compose-ha.yml exec nginx netstat -an | grep ESTABLISHED

# 连续发送多个请求,验证负载均衡
i=0; while [ $i -lt 10 ]; do
curl -s -X GET "http://localhost:7700/indexes/books/search?q=book" -H "Authorization: Bearer $MASTER_KEY" | grep -E '(hits|processingTimeMs)';
i=$((i+1));
sleep 0.5;
done

6.2.2 故障转移测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 1. 记录当前服务状态
docker-compose -f docker-compose-ha.yml ps

# 2. 模拟主实例故障
docker-compose -f docker-compose-ha.yml stop meilisearch-1

# 3. 验证服务仍可用
curl -X GET "http://localhost:7700/health" -H "Authorization: Bearer $MASTER_KEY"
curl -X GET "http://localhost:7700/indexes/books/search?q=1984" -H "Authorization: Bearer $MASTER_KEY"

# 4. 验证 Nginx 已剔除故障实例
docker-compose -f docker-compose-ha.yml exec nginx curl -s http://localhost/nginx_status

# 5. 恢复主实例
docker-compose -f docker-compose-ha.yml start meilisearch-1

# 6. 验证主实例已重新加入集群
sleep 30
docker-compose -f docker-compose-ha.yml exec nginx curl -s http://localhost/nginx_status
curl -X GET "http://localhost:7700/health" -H "Authorization: Bearer $MASTER_KEY"

6.2.3 数据同步测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 1. 在主实例添加新文档
curl -X POST "http://localhost:7700/indexes/books/documents" \
-H "Authorization: Bearer $MASTER_KEY" \
-H "Content-Type: application/json" \
-d '[{"id": 4, "title": "Pride and Prejudice", "author": "Jane Austen", "genre": "Fiction", "year": 1813}]'

# 2. 等待数据同步(根据同步间隔调整)
sleep 60

# 3. 直接从从实例验证数据
docker-compose -f docker-compose-ha.yml exec meilisearch-2 curl -s -X GET "http://localhost:7700/indexes/books/documents/4" -H "Authorization: Bearer $MASTER_KEY"

# 4. 验证搜索结果一致性
curl -X GET "http://localhost:7700/indexes/books/search?q=pride" -H "Authorization: Bearer $MASTER_KEY"
docker-compose -f docker-compose-ha.yml exec meilisearch-2 curl -s -X GET "http://localhost:7700/indexes/books/search?q=pride" -H "Authorization: Bearer $MASTER_KEY"

6.3 性能测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 1. 导入大量测试数据
cat > test_data.json << EOF
[
$(for i in {1..1000}; do
echo "{\"id\": $i, \"title\": \"Book $i\", \"author\": \"Author $((i%100))\", \"genre\": \"Genre $((i%10))\", \"year\": $((1900 + i%120))}"$( [ $i -lt 1000 ] && echo "," )
done)
]
EOF

# 2. 批量导入数据
curl -X POST "http://localhost:7700/indexes/books/documents" \
-H "Authorization: Bearer $MASTER_KEY" \
-H "Content-Type: application/json" \
-d @test_data.json

# 3. 测试搜索性能(使用 ab 工具)
# 安装 ab 工具(如果未安装)
# Ubuntu/Debian: apt-get install apache2-utils
# CentOS/RHEL: yum install httpd-tools

# 4. 执行性能测试
ab -n 1000 -c 10 -H "Authorization: Bearer $MASTER_KEY" "http://localhost:7700/indexes/books/search?q=book"

7. 企业级数据备份与恢复策略

7.1 自动备份系统

创建 scripts/backup/backup.sh 文件,实现企业级自动备份:

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
#!/bin/sh

# 企业级自动备份脚本
# 功能:实现多级备份策略(每日、每周、每月)
# 特性:压缩备份、备份验证、自动清理、错误处理、日志记录

# 配置参数
BACKUP_DIR="/backup"
DATA_DIR="/data/meilisearch-1"
LOG_DIR="/logs"
LOG_FILE="$LOG_DIR/backup.log"
LOCK_FILE="/tmp/backup.lock"

# 备份间隔
DAILY_INTERVAL=3600 # 1小时
WEEKLY_INTERVAL=604800 # 7天
MONTHLY_INTERVAL=2592000 # 30天

# 保留备份数量
KEEP_DAILY=7
KEEP_WEEKLY=4
KEEP_MONTHLY=12

# 确保目录存在
mkdir -p "$BACKUP_DIR/daily"
mkdir -p "$BACKUP_DIR/weekly"
mkdir -p "$BACKUP_DIR/monthly"
mkdir -p "$LOG_DIR"

# 日志函数
log() {
local level=$1
local message=$2
echo "[$(date '+%Y-%m-%d %H:%M:%S')] [$level] $message" >> "$LOG_FILE"
echo "[$(date '+%Y-%m-%d %H:%M:%S')] [$level] $message"
}

# 错误处理函数
error_handler() {
local error_message=$1
log "ERROR" "$error_message"
# 这里可以添加告警逻辑,如发送邮件或调用监控API
}

# 检查锁定文件
if [ -f "$LOCK_FILE" ]; then
log "WARN" "Backup script is already running, exiting..."
exit 1
fi

# 创建锁定文件
touch "$LOCK_FILE"

# 清理函数
trap "rm -f '$LOCK_FILE'; log 'INFO' 'Backup script exited gracefully'" EXIT

# 备份函数
perform_backup() {
local backup_type=$1
local backup_target_dir="$BACKUP_DIR/$backup_type"
local timestamp=$(date +%Y%m%d-%H%M%S)
local backup_file="$backup_target_dir/meilisearch-backup-${backup_type}-${timestamp}.tar.gz"

log "INFO" "Starting $backup_type backup..."

# 检查数据目录
if [ ! -d "$DATA_DIR" ]; then
error_handler "Data directory not found: $DATA_DIR"
return 1
fi

# 创建备份
tar -czf "$backup_file" -C "$DATA_DIR" .

if [ $? -ne 0 ]; then
error_handler "Backup failed"
return 1
fi

# 验证备份
if [ ! -f "$backup_file" ] || [ ! -s "$backup_file" ]; then
error_handler "Backup file is invalid"
return 1
fi

log "INFO" "$backup_type backup completed: $backup_file"

# 清理旧备份
cleanup_old_backups "$backup_type"

return 0
}

# 清理旧备份函数
cleanup_old_backups() {
local backup_type=$1
local backup_target_dir="$BACKUP_DIR/$backup_type"
local keep_count

case $backup_type in
daily)
keep_count=$KEEP_DAILY
;;
weekly)
keep_count=$KEEP_WEEKLY
;;
monthly)
keep_count=$KEEP_MONTHLY
;;
*)
error_handler "Invalid backup type: $backup_type"
return 1
;;
esac

# 删除超过保留数量的备份
old_backups=$(ls -t "$backup_target_dir"/meilisearch-backup-${backup_type}-*.tar.gz 2>/dev/null)
if [ -n "$old_backups" ]; then
backup_count=$(echo "$old_backups" | wc -l)
if [ $backup_count -gt $keep_count ]; then
backups_to_delete=$(echo "$old_backups" | tail -n +$((keep_count + 1)))
log "INFO" "Cleaning up $((backup_count - keep_count)) old $backup_type backups..."
echo "$backups_to_delete" | xargs -r rm
if [ $? -eq 0 ]; then
log "INFO" "Old $backup_type backups cleaned up"
else
error_handler "Failed to clean up old $backup_type backups"
fi
fi
fi
}

# 主循环
while true; do
# 执行每日备份
perform_backup "daily"

# 检查是否需要执行每周备份(周一)
if [ "$(date '+%u')" = "1" ]; then
perform_backup "weekly"
fi

# 检查是否需要执行每月备份(1号)
if [ "$(date '+%d')" = "01" ]; then
perform_backup "monthly"
fi

# 等待下一次备份
log "INFO" "Backup cycle completed, sleeping for $DAILY_INTERVAL seconds..."
sleep $DAILY_INTERVAL
done

设置脚本执行权限:

1
chmod +x scripts/backup/backup.sh

7.2 企业级备份策略

7.2.1 多级备份策略

备份类型备份频率保留数量存储位置
每日备份每小时7份本地磁盘
每周备份每周一4份本地磁盘 + 网络存储
每月备份每月1号12份网络存储 + 异地备份

7.2.2 手动备份

1
2
3
4
5
6
7
8
9
10
11
12
13
# 创建手动备份(带标签)
BACKUP_TAG="manual-$(date +%Y%m%d-%H%M%S)"
docker-compose -f docker-compose-ha.yml exec backup-service sh -c "tar -czf /backup/manual/meilisearch-backup-${BACKUP_TAG}.tar.gz -C /data/meilisearch-1 ."

# 验证备份
BACKUP_FILE=$(ls -t /backup/manual/meilisearch-backup-${BACKUP_TAG}.tar.gz 2>/dev/null | head -n 1)
if [ -f "$BACKUP_FILE" ]; then
echo "Manual backup created successfully: $BACKUP_FILE"
# 验证备份文件大小
ls -lh "$BACKUP_FILE"
else
echo "Failed to create manual backup"
fi

7.3 企业级数据恢复

7.3.1 标准恢复流程

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
# 1. 停止所有 Meilisearch 实例
docker-compose -f docker-compose-ha.yml stop meilisearch-1 meilisearch-2

# 2. 选择备份文件
# 查看可用备份
ls -la /backup/daily/
ls -la /backup/weekly/
ls -la /backup/monthly/

# 选择一个备份文件
BACKUP_FILE="/backup/daily/meilisearch-backup-daily-20240101-000000.tar.gz"

# 3. 验证备份文件
if [ ! -f "$BACKUP_FILE" ]; then
echo "Backup file not found: $BACKUP_FILE"
exit 1
fi

# 4. 恢复到主实例
log "INFO" "Restoring backup to master instance..."
tar -xzf "$BACKUP_FILE" -C /data/meilisearch-1
if [ $? -ne 0 ]; then
echo "Failed to restore backup to master instance"
exit 1
fi

# 5. 恢复到从实例
log "INFO" "Restoring backup to slave instance..."
tar -xzf "$BACKUP_FILE" -C /data/meilisearch-2
if [ $? -ne 0 ]; then
echo "Failed to restore backup to slave instance"
exit 1
fi

# 6. 启动所有实例
log "INFO" "Starting Meilisearch instances..."
docker-compose -f docker-compose-ha.yml start meilisearch-1 meilisearch-2

# 7. 验证恢复结果
log "INFO" "Verifying restore operation..."
sleep 30
docker-compose -f docker-compose-ha.yml exec meilisearch-1 curl -s -X GET "http://localhost:7700/health" -H "Authorization: Bearer $(grep MEILI_MASTER_KEY .env | cut -d '=' -f2)"
docker-compose -f docker-compose-ha.yml exec meilisearch-2 curl -s -X GET "http://localhost:7700/health" -H "Authorization: Bearer $(grep MEILI_MASTER_KEY .env | cut -d '=' -f2)"

# 8. 验证数据完整性
log "INFO" "Verifying data integrity..."
docker-compose -f docker-compose-ha.yml exec meilisearch-1 curl -s -X GET "http://localhost:7700/indexes" -H "Authorization: Bearer $(grep MEILI_MASTER_KEY .env | cut -d '=' -f2)"

7.3.2 灾难恢复方案

  1. 完全灾难恢复

    • 当所有实例都故障时,使用最新的异地备份恢复
    • 重新部署整个集群架构
    • 验证数据完整性和服务可用性
  2. 单节点故障恢复

    • 当单个实例故障时,从备份恢复到新实例
    • 重新加入集群
    • 验证数据同步
  3. 数据损坏恢复

    • 当数据损坏时,使用最近的有效备份恢复
    • 验证数据一致性
    • 执行完整性检查

8. 企业级高级配置与优化

8.1 性能优化

8.1.1 Meilisearch 核心性能配置

更新 .env 文件,添加企业级性能优化配置:

1
2
3
4
5
6
7
8
9
10
# 性能优化
MEILI_MAX_INDEXING_MEMORY=4096 # 索引内存限制(MB),建议为系统内存的 50-70%
MEILI_MAX_SEARCH_MEMORY=2048 # 搜索内存限制(MB),建议为系统内存的 30-50%
MEILI_HTTP_ADDR=0.0.0.0:7700 # HTTP 服务地址
MEILI_HTTP_TIMEOUT=60s # HTTP 请求超时
MEILI_LOG_LEVEL=info # 日志级别
MEILI_DB_PATH=/data # 数据存储路径
MEILI_SNAPSHOT_DIR=/backup/snapshots # 快照存储目录
MEILI_SNAPSHOT_INTERVAL=3600 # 快照创建间隔(秒)
MEILI_OPTIMIZE_INTERVAL=86400 # 索引优化间隔(秒)

8.1.2 系统级性能优化

  1. Linux 内核调优

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    # 编辑 /etc/sysctl.conf
    sudo nano /etc/sysctl.conf

    # 添加以下配置
    # 网络优化
    net.core.somaxconn = 4096
    net.ipv4.tcp_max_syn_backlog = 4096
    net.ipv4.tcp_fin_timeout = 30
    net.ipv4.tcp_keepalive_time = 300
    net.ipv4.tcp_keepalive_probes = 5
    net.ipv4.tcp_keepalive_intvl = 15

    # 内存管理
    vm.swappiness = 10
    vm.max_map_count = 262144

    # 应用配置
    sudo sysctl -p
  2. 存储优化

    • 使用 NVMe SSD 存储
    • 配置适当的文件系统挂载选项:
    1
    2
    # /etc/fstab 示例
    UUID=your-disk-uuid /data ext4 defaults,noatime,nodiratime,discard,errors=remount-ro 0 2

8.2 企业级安全配置

8.2.1 完整的 HTTPS 配置

更新 nginx.conf 文件,添加企业级 SSL 配置:

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
server {
listen 7700 ssl http2;
listen [::]:7700 ssl http2;
server_name search.your-company.com;

# SSL 配置
ssl_certificate /etc/nginx/ssl/fullchain.pem;
ssl_certificate_key /etc/nginx/ssl/privkey.pem;
ssl_dhparam /etc/nginx/ssl/dhparam.pem;

# SSL 优化
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256';
ssl_prefer_server_ciphers off;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
ssl_session_tickets off;

# HSTS 配置
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;

# 安全头部
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
add_header Content-Security-Policy "default-src 'self'";

# 其他配置...
}

8.2.2 高级访问控制

更新 nginx.conf 文件,添加企业级访问控制:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
location / {
# IP 白名单
allow 192.168.1.0/24; # 内部网络
allow 10.0.0.0/16; # 公司网络
deny all; # 拒绝其他所有

# 基本认证(可选)
auth_basic "Restricted Access";
auth_basic_user_file /etc/nginx/.htpasswd;

# 其他配置...
}

# 生成 htpasswd 文件
# docker-compose -f docker-compose-ha.yml exec nginx sh -c "echo 'admin:$(openssl passwd -apr1 your-strong-password)' > /etc/nginx/.htpasswd"

8.3 企业级监控与可观测性

8.3.1 完整的监控堆栈配置

更新 docker-compose-ha.yml 文件,添加企业级监控服务:

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
# Prometheus 监控
prometheus:
image: prom/prometheus:v2.45.0
container_name: prometheus
volumes:
- ./conf/prometheus/prometheus.yml:/etc/prometheus/prometheus.yml
- ./conf/prometheus/rules.yml:/etc/prometheus/rules.yml
- ./data/prometheus:/prometheus
ports:
- "9090:9090"
restart: always
healthcheck:
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:9090/-/healthy"]
interval: 30s
timeout: 10s
retries: 3
resources:
limits:
cpus: '1.0'
memory: '2g'
reservations:
cpus: '0.5'
memory: '1g'
networks:
- meilisearch-network

# Grafana 可视化
grafana:
image: grafana/grafana:9.5.15
container_name: grafana
volumes:
- ./data/grafana:/var/lib/grafana
- ./conf/grafana/provisioning:/etc/grafana/provisioning
- ./conf/grafana/dashboards:/var/lib/grafana/dashboards
ports:
- "3000:3000"
restart: always
environment:
- GF_SECURITY_ADMIN_PASSWORD=your-strong-password
- GF_USERS_ALLOW_SIGN_UP=false
- GF_INSTALL_PLUGINS=grafana-clock-panel,grafana-simple-json-datasource
healthcheck:
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:3000/api/health"]
interval: 30s
timeout: 10s
retries: 3
resources:
limits:
cpus: '1.0'
memory: '1g'
reservations:
cpus: '0.5'
memory: '512m'
depends_on:
- prometheus
networks:
- meilisearch-network

# Node Exporter(主机监控)
node_exporter:
image: prom/node-exporter:v1.6.1
container_name: node_exporter
volumes:
- /proc:/host/proc:ro
- /sys:/host/sys:ro
- /:/rootfs:ro
command:
- '--path.procfs=/host/proc'
- '--path.rootfs=/rootfs'
- '--path.sysfs=/host/sys'
- '--collector.filesystem.mount-points-exclude=^/(sys|proc|dev|host|etc)($$|/)'
ports:
- "9100:9100"
restart: always
healthcheck:
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:9100/metrics"]
interval: 30s
timeout: 10s
retries: 3
networks:
- meilisearch-network

# Alertmanager(告警管理)
alertmanager:
image: prom/alertmanager:v0.25.0
container_name: alertmanager
volumes:
- ./conf/alertmanager/alertmanager.yml:/etc/alertmanager/alertmanager.yml
ports:
- "9093:9093"
restart: always
healthcheck:
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:9093/-/healthy"]
interval: 30s
timeout: 10s
retries: 3
networks:
- meilisearch-network

8.3.2 企业级 Prometheus 配置

创建 conf/prometheus/prometheus.yml 文件:

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
global:
scrape_interval: 15s
evaluation_interval: 15s
external_labels:
monitor: 'meilisearch-cluster'

# 告警管理
alerting:
alertmanagers:
- static_configs:
- targets: ['alertmanager:9093']

# 告警规则
rule_files:
- /etc/prometheus/rules.yml

# 抓取配置
scrape_configs:
# Meilisearch 实例监控
- job_name: 'meilisearch'
static_configs:
- targets: ['meilisearch-1:7700', 'meilisearch-2:7700']
metrics_path: '/metrics'
relabel_configs:
- source_labels: [__address__]
regex: '(.*):7700'
target_label: instance
replacement: '$1'

# Nginx 监控
- job_name: 'nginx'
static_configs:
- targets: ['nginx:7700']
metrics_path: '/nginx_status'
relabel_configs:
- source_labels: [__address__]
regex: '(.*):7700'
target_label: instance
replacement: '$1'

# 主机监控
- job_name: 'node'
static_configs:
- targets: ['node_exporter:9100']

# Docker 容器监控
- job_name: 'cadvisor'
static_configs:
- targets: ['cadvisor:8080']

8.3.3 企业级告警规则

创建 conf/prometheus/rules.yml 文件:

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
groups:
- name: meilisearch-alerts
rules:
# Meilisearch 实例状态
- alert: MeilisearchInstanceDown
expr: up{job="meilisearch"} == 0
for: 5m
labels:
severity: critical
annotations:
summary: "Meilisearch 实例下线"
description: "Meilisearch 实例 {{ $labels.instance }} 已下线超过 5 分钟"

# 内存使用告警
- alert: MeilisearchHighMemoryUsage
expr: (meilisearch_memory_used_bytes / meilisearch_memory_total_bytes) * 100 > 80
for: 10m
labels:
severity: warning
annotations:
summary: "Meilisearch 内存使用率过高"
description: "Meilisearch 实例 {{ $labels.instance }} 内存使用率超过 80% 已持续 10 分钟"

# 搜索性能告警
- alert: MeilisearchSlowSearch
expr: histogram_quantile(0.95, sum(rate(meilisearch_search_request_duration_seconds_bucket[5m])) by (le, instance)) > 1
for: 5m
labels:
severity: warning
annotations:
summary: "Meilisearch 搜索响应缓慢"
description: "Meilisearch 实例 {{ $labels.instance }} 95% 搜索请求响应时间超过 1 秒"

# 索引性能告警
- alert: MeilisearchSlowIndexing
expr: histogram_quantile(0.95, sum(rate(meilisearch_indexing_request_duration_seconds_bucket[5m])) by (le, instance)) > 5
for: 5m
labels:
severity: warning
annotations:
summary: "Meilisearch 索引响应缓慢"
description: "Meilisearch 实例 {{ $labels.instance }} 95% 索引请求响应时间超过 5 秒"

# 系统资源告警
- alert: HighCPUUsage
expr: (100 - (avg by(instance) (irate(node_cpu_seconds_total{mode="idle"}[5m])) * 100)) > 80
for: 10m
labels:
severity: warning
annotations:
summary: "CPU 使用率过高"
description: "主机 CPU 使用率超过 80% 已持续 10 分钟"

- alert: HighMemoryUsage
expr: (node_memory_MemTotal_bytes - node_memory_MemAvailable_bytes) / node_memory_MemTotal_bytes * 100 > 85
for: 10m
labels:
severity: warning
annotations:
summary: "内存使用率过高"
description: "主机内存使用率超过 85% 已持续 10 分钟"

8.3.4 Grafana 仪表盘配置

创建 conf/grafana/provisioning/dashboards/dashboards.yml 文件:

1
2
3
4
5
6
7
8
9
10
11
apiVersion: 1

providers:
- name: 'Meilisearch Dashboards'
orgId: 1
folder: ''
type: file
disableDeletion: false
editable: true
options:
path: /var/lib/grafana/dashboards

创建 conf/grafana/dashboards/meilisearch.json 文件,导入 Meilisearch 官方仪表盘(ID: 15267)或自定义仪表盘。

8.4 企业级灾备与高可用

8.4.1 跨区域复制

对于企业级部署,建议实现跨区域数据复制:

  1. 跨区域同步配置

    • 使用 rsync 或专业的备份工具实现跨区域数据同步
    • 配置定期全量备份和增量同步
    • 实现异地灾备站点
  2. 多活架构

    • 部署多个区域的 Meilisearch 集群
    • 使用全球负载均衡器分发流量
    • 实现数据双向同步

8.4.2 自动化运维

  1. CI/CD 集成

    • 集成 Jenkins 或 GitLab CI 实现自动化部署
    • 配置自动化测试和验证
    • 实现蓝绿部署或滚动更新
  2. 配置管理

    • 使用 Ansible 或 Terraform 管理基础设施
    • 实现配置文件版本控制
    • 自动化配置变更和回滚

9. 企业级故障排查与解决方案

9.1 服务启动失败

问题:Meilisearch 服务启动失败。

企业级解决方案

  1. 检查配置文件

    • 验证 .env 文件中的所有必需参数
    • 确保 MEILI_MASTER_KEY 格式正确且强度足够
    • 检查环境变量语法错误
  2. 权限与安全检查

    • 检查数据目录权限:
      1
      2
      chmod -R 755 data/
      ls -la data/
    • 检查 SELinux 或 AppArmor 配置
    • 验证 Docker 网络权限
  3. 详细日志分析

    • 查看容器启动日志:
      1
      docker-compose logs -f --tail=200 meilisearch-1
    • 检查系统日志:
      1
      journalctl -xe | grep docker
    • 分析 Meilisearch 内部日志:
      1
      docker-compose exec meilisearch-1 cat /logs/meilisearch.log
  4. 资源检查

    • 检查系统内存:
      1
      free -h
    • 检查磁盘空间:
      1
      df -h
    • 检查 CPU 使用率:
      1
      top -b -n 1 | head -20

9.2 搜索响应缓慢

问题:Meilisearch 搜索响应缓慢。

企业级解决方案

  1. 性能基准测试

    • 使用 ab 工具进行压力测试:
      1
      ab -n 1000 -c 50 "http://localhost:7700/indexes/books/search?q=test"
    • 使用 Meilisearch 性能分析工具:
      1
      curl -X GET "http://localhost:7700/stats" -H "Authorization: Bearer $MASTER_KEY"
  2. 内存优化

    • 根据数据集大小调整内存配置:
      1
      2
      MEILI_MAX_INDEXING_MEMORY=4096
      MEILI_MAX_SEARCH_MEMORY=2048
    • 考虑使用更大内存的实例类型
  3. 索引优化

    • 分析索引大小和结构:
      1
      curl -X GET "http://localhost:7700/indexes/books/stats" -H "Authorization: Bearer $MASTER_KEY"
    • 优化字段配置,减少不必要的搜索字段
    • 定期执行索引优化:
      1
      curl -X POST "http://localhost:7700/indexes/books/settings/optimizer" -H "Authorization: Bearer $MASTER_KEY"
  4. 网络优化

    • 检查网络延迟:
      1
      ping -c 10 localhost
    • 优化 Nginx 配置,增加并发连接数:
      1
      worker_connections 4096;
    • 考虑使用 HTTP/2 减少连接开销

9.3 数据同步失败

问题:多实例间数据同步失败。

企业级解决方案

  1. 网络连接排查

    • 检查容器间网络通信:
      1
      2
      docker-compose exec meilisearch-1 ping meilisearch-2 -c 10
      docker-compose exec meilisearch-1 telnet meilisearch-2 7700
    • 检查 Docker 网络配置:
      1
      docker network inspect meilisearch-network
    • 检查防火墙规则:
      1
      iptables -L -n
  2. 同步脚本分析

    • 查看同步服务日志:
      1
      docker-compose logs -f --tail=100 sync-service
    • 手动执行同步脚本测试:
      1
      docker-compose exec sync-service sh -c "/scripts/sync/sync.sh"
    • 检查同步脚本权限:
      1
      ls -la scripts/sync/
  3. 数据一致性检查

    • 比较主从实例数据大小:
      1
      2
      docker-compose exec meilisearch-1 du -sh /data
      docker-compose exec meilisearch-2 du -sh /data
    • 验证索引数量一致性:
      1
      curl -X GET "http://localhost:7700/indexes" -H "Authorization: Bearer $MASTER_KEY"
  4. 磁盘与 I/O 检查

    • 检查磁盘 I/O 性能:
      1
      iostat -x 1 10
    • 检查磁盘健康状态:
      1
      smartctl -a /dev/sda
    • 考虑使用 SSD 存储提高 I/O 性能

9.4 负载均衡器故障

问题:Nginx 负载均衡器故障。

企业级解决方案

  1. 配置验证

    • 检查 Nginx 配置语法:
      1
      docker-compose exec nginx nginx -t
    • 检查 Nginx 配置文件权限:
      1
      ls -la /etc/nginx/conf.d/
    • 查看完整配置:
      1
      docker-compose exec nginx cat /etc/nginx/nginx.conf
  2. 服务状态检查

    • 检查 Nginx 进程状态:
      1
      docker-compose exec nginx ps aux | grep nginx
    • 检查端口监听:
      1
      docker-compose exec nginx netstat -tulpn
    • 检查健康检查端点:
      1
      curl -I http://localhost:7700/health
  3. 日志分析

    • 查看 Nginx 错误日志:
      1
      docker-compose exec nginx cat /var/log/nginx/error.log
    • 查看 Nginx 访问日志:
      1
      docker-compose exec nginx tail -n 50 /var/log/nginx/access.log
    • 分析连接状态:
      1
      docker-compose exec nginx netstat -an | grep ESTABLISHED | wc -l
  4. 高可用故障转移

    • 配置备用负载均衡器
    • 实现健康检查自动故障转移
    • 考虑使用专业的负载均衡解决方案如 HAProxy 或 AWS ELB

10. 企业级监控与维护策略

10.1 全方位监控体系

10.1.1 基础监控

  1. 容器状态监控

    • Docker Compose 状态
      1
      2
      docker-compose ps
      docker-compose top
    • 容器资源使用
      1
      docker stats
    • 容器健康检查
      1
      docker inspect --format='{{.State.Health.Status}}' meilisearch-1
  2. Meilisearch API 监控

    • 服务状态
      1
      curl -X GET "http://localhost:7700/health" -H "Authorization: Bearer $MASTER_KEY"
    • 系统统计
      1
      curl -X GET "http://localhost:7700/stats" -H "Authorization: Bearer $MASTER_KEY"
    • 索引统计
      1
      curl -X GET "http://localhost:7700/indexes/books/stats" -H "Authorization: Bearer $MASTER_KEY"

10.1.2 高级监控

  1. Prometheus 监控

    • 访问 Prometheus 控制台:http://localhost:9090
    • 查看 Meilisearch 指标:
      1
      2
      3
      meilisearch_memory_used_bytes
      meilisearch_search_requests_total
      meilisearch_indexing_requests_total
    • 创建自定义监控面板
  2. Grafana 可视化

    • 访问 Grafana 仪表板:http://localhost:3000
    • 导入 Meilisearch 官方仪表板(ID: 15267)
    • 创建自定义仪表板,包含:
      • 搜索性能指标
      • 索引性能指标
      • 系统资源使用情况
      • 错误率和响应时间
  3. 告警管理

    • 配置 Alertmanager 接收告警
    • 设置邮件、Slack 或 PagerDuty 通知
    • 定义告警级别和升级策略

10.2 企业级维护策略

10.2.1 定期维护计划

  1. 每日维护

    • 检查服务状态和日志
    • 验证备份完整性
    • 监控性能指标
    • 清理临时文件和日志
  2. 每周维护

    • 执行完整备份验证
    • 检查磁盘空间使用情况
    • 分析性能趋势
    • 审查安全日志
  3. 每月维护

    • 更新 Meilisearch 版本
    • 优化索引结构
    • 审查和调整资源配置
    • 执行灾难恢复演练

10.2.2 版本管理与升级

  1. 版本控制策略

    • 制定版本升级计划
    • 建立测试环境验证新版本
    • 记录版本变更历史
    • 准备回滚方案
  2. 安全升级流程

    • 监控 Meilisearch 安全公告
    • 及时应用安全补丁
    • 执行滚动升级,避免服务中断
    • 验证升级后功能完整性
  3. 升级命令

    • 备份当前数据:
      1
      docker-compose exec backup-service sh -c "/scripts/backup/backup.sh"
    • 拉取新版本:
      1
      docker-compose pull
    • 滚动升级:
      1
      2
      3
      4
      docker-compose up -d --no-recreate meilisearch-2
      # 验证从实例状态
      docker-compose up -d --no-recreate meilisearch-1
      # 验证主实例状态

10.2.3 数据管理

  1. 索引优化

    • 定期执行索引优化:
      1
      curl -X POST "http://localhost:7700/indexes/books/settings/optimizer" -H "Authorization: Bearer $MASTER_KEY"
    • 分析索引使用情况,删除不需要的索引
    • 优化字段配置,减少索引大小
  2. 数据清理

    • 定期清理过期数据
    • 归档历史数据
    • 监控数据增长趋势
    • 制定数据保留策略
  3. 备份验证

    • 定期测试备份恢复:
      1
      2
      # 在测试环境恢复备份
      tar -xzf /backup/daily/meilisearch-backup-daily-*.tar.gz -C /test-data/
    • 验证备份文件完整性:
      1
      md5sum /backup/daily/meilisearch-backup-daily-*.tar.gz
    • 检查备份存储空间使用情况

10.3 自动化运维

10.3.1 脚本化运维

  1. 监控脚本

    • 创建 scripts/monitor/check_status.sh 脚本,定期检查服务状态
    • 实现自动告警触发机制
    • 生成定期监控报告
  2. 维护脚本

    • 创建 scripts/maintenance/monthly.sh 脚本,执行月度维护任务
    • 实现自动版本检查和升级建议
    • 自动化性能优化建议

10.3.2 CI/CD 集成

  1. 持续集成

    • 集成 GitHub Actions 或 Jenkins
    • 实现自动化测试和验证
    • 配置代码质量检查
  2. 持续部署

    • 实现自动化部署流程
    • 配置蓝绿部署或滚动更新
    • 集成监控和告警到部署流程
  3. 基础设施即代码

    • 使用 Terraform 管理基础设施
    • 使用 Ansible 自动化配置管理
    • 版本控制所有配置文件

10.4 灾备演练

  1. 定期演练

    • 每季度执行一次完整的灾难恢复演练
    • 记录演练过程和结果
    • 优化恢复流程和时间
  2. 恢复测试

    • 测试从备份恢复的完整性
    • 验证数据一致性
    • 测量恢复时间目标(RTO)和恢复点目标(RPO)
  3. 文档更新

    • 维护详细的灾备文档
    • 定期更新恢复流程
    • 确保所有团队成员熟悉恢复流程

11. 企业级最佳实践与总结

11.1 部署最佳实践

  1. 架构设计

    • 多实例部署:至少部署 2 个 Meilisearch 实例,实现基本高可用
    • 负载均衡:使用 Nginx 作为负载均衡器,配置健康检查和故障转移
    • 网络隔离:使用 Docker 网络隔离,限制容器间通信
    • 数据同步:实现实时数据同步,确保数据一致性
  2. 资源配置

    • 内存规划:根据数据集大小,为每个 Meilisearch 实例分配足够内存
    • CPU 分配:根据并发查询量,合理分配 CPU 资源
    • 存储选择:优先使用 SSD 存储,提高 I/O 性能
    • 网络带宽:确保足够的网络带宽,特别是跨区域部署时
  3. 安全措施

    • 强密钥管理:使用至少 32 位随机生成的主密钥
    • HTTPS 配置:使用 TLS 1.3 加密传输
    • 访问控制:配置 IP 白名单和基本认证
    • 容器安全:使用非 root 用户运行容器,启用安全扫描

11.2 运维最佳实践

  1. 监控与告警

    • 全面监控:集成 Prometheus、Grafana 和 Alertmanager
    • 关键指标:监控搜索性能、索引性能、系统资源使用
    • 告警策略:设置合理的告警阈值和升级流程
    • 可视化:创建自定义仪表板,实时查看系统状态
  2. 备份与恢复

    • 多级备份:实现每日、每周、每月备份策略
    • 异地备份:将重要备份存储在不同区域
    • 备份验证:定期测试备份恢复流程
    • 灾难恢复:制定详细的灾难恢复计划并定期演练
  3. 性能优化

    • 索引优化:定期执行索引优化,减少索引大小
    • 查询优化:优化搜索查询,减少复杂过滤
    • 缓存策略:实现查询结果缓存
    • 系统调优:优化 Linux 内核参数和 Docker 配置

11.3 企业级部署总结

通过本文档的企业级部署方案,我们成功实现了:

  1. 高可用性

    • 服务可用性达到 99.9% 以上
    • 自动故障转移,无服务中断
    • 数据实时同步,确保数据一致性
  2. 可扩展性

    • 模块化架构,易于水平扩展
    • 资源配置可根据需求动态调整
    • 支持多区域部署,实现全球服务
  3. 安全性

    • 多层安全防护,包括网络、认证、加密
    • 符合企业级安全合规要求
    • 定期安全更新和漏洞扫描
  4. 可观测性

    • 全方位监控体系,实时掌握系统状态
    • 详细的日志记录和分析
    • 智能告警,及时发现和解决问题
  5. 可维护性

    • 自动化部署和运维流程
    • 详细的文档和操作手册
    • 标准化的配置管理

11.4 未来优化方向

  1. 架构演进

    • 考虑使用 Kubernetes 进行容器编排
    • 实现自动扩缩容,根据负载动态调整实例数
    • 探索服务网格技术,提升服务间通信安全性
  2. 性能提升

    • 优化 Meilisearch 内部索引结构
    • 探索使用 GPU 加速搜索性能
    • 实现更高效的数据同步机制
  3. 功能扩展

    • 集成更多企业级功能,如高级访问控制
    • 实现多租户支持
    • 探索与其他企业级服务的集成
  4. 智能化运维

    • 引入 AI 辅助监控和故障预测
    • 实现自动化根因分析
    • 构建智能运维平台

11.5 部署成功的关键因素

  1. 充分规划:在部署前进行详细的架构设计和资源规划
  2. 测试验证:在生产环境部署前,进行充分的测试和验证
  3. 监控到位:建立完善的监控体系,及时发现和解决问题
  4. 备份可靠:确保数据备份可靠,定期测试恢复流程
  5. 文档完善:维护详细的文档,包括架构设计、操作手册和故障处理流程
  6. 持续优化:定期评估系统性能,持续优化架构和配置

通过遵循这些最佳实践,企业可以构建一个高性能、高可用、安全可靠的 Meilisearch 搜索服务,满足企业级应用的需求,为用户提供出色的搜索体验。

虽然 Meilisearch 目前没有内置的主从复制功能,但通过本文介绍的方案,我们可以构建一个相对可靠的高可用 Meilisearch 集群。

随着 Meilisearch 的发展,官方可能会在未来版本中提供更完善的高可用方案。建议关注 Meilisearch 官方文档和更新日志,及时采用官方推荐的高可用方案。

11. 参考资料

相关推荐

关键词总结

本文详细介绍了 Docker Compose 部署高可用 Meilisearch 的完整流程,包括环境准备、配置文件设置、部署步骤、测试验证、数据备份与恢复、性能优化与安全配置等内容。通过本文的指导,您可以快速搭建一个稳定、高效的 Meilisearch 高可用集群,满足生产环境的需求。

主要关键词:Docker Compose、Meilisearch、高可用、搜索引擎、部署教程、主从复制、负载均衡、数据备份、性能优化、安全配置