多节点与分片
流量上来以后,加进程、加 ClickHouse 分片都不用换架构,也不用多装组件。这一页说明怎么加、项目怎么分配,以及把项目换到别的分片的手工步骤。
加进程
每台 evstats 进程使用同一个 EVS_CLICKHOUSE 和同一个 EVS_REDIS(同名启动参数写了就覆盖)。Redis 不写进 ClickHouse,新进程靠自己的环境变量连上。
负载均衡(不需要会话粘滞)
┌────────────┼────────────┐
evstats-1 evstats-2 evstats-3 每台一样的 EVS_CLICKHOUSE 与 EVS_REDIS
└────────────┼────────────┘
Redis(所有进程共用一个)
│
ClickHouse s0(EVS_CLICKHOUSE) s1 s2 …(在设置页追加)- 负载均衡随便打:
/sa、页面、/api/v1转到任意一台都可以,不需要粘滞会话。登录会话、限流、验证码都在共用的 Redis 里,换一台进程立即生效。 - 节点名是主机名:「系统 → 采集状态」靠它区分节点,每台的主机名要不同。
data/各自独立:每台进程工作目录下的data/(IP 库)是本地盘,不要共用;每台自己下载、自己载入内存。- Redis 不要按节点拆:所有进程必须连同一个 Redis。
源码仓库的 deploy/compose/multi-node/ 是一份三个进程、一个 Nginx、两个分片的示例,可以先在一台机器上看清拓扑,再拆到多台。
上报在多台之间怎么走
- 任意一台收到
/sa,校验通过后写入 Redis 的采集队列(Redis Stream),写入成功才给 SDK 返回成功。 - 所有进程在同一个消费组里取消息,按项目所在的分片凑批,插入 ClickHouse,插入成功才确认(ACK)。
- 某台进程在确认之前崩溃,它没确认的消息空闲 60 秒后会被别的进程接着写。
- 同一个项目总是写进同一个分片。
所以多台一起接上报不会乱,也不会因为一台挂掉丢掉已经返回成功的事件。代价是重试时可能出现少量重复行,本期查询不按 event_id 去重。
加分片
更多 ClickHouse 在「系统 → 分片」里追加,不在命令行里加。


- 点「追加分片」,填新 ClickHouse 的地址,格式和
EVS_CLICKHOUSE相同,例如http://evstats:口令@ch-s1:8123/evstats。 - 点「测试连接」,通过后保存。evstats 会在新分片上建好事件表,再通知所有进程连上它。
- 分片按顺序编号
s1、s2……只能加在末尾。
| 规则 | 说明 |
|---|---|
s0 | 就是 EVS_CLICKHOUSE(或 -clickhouse),系统数据(账号、项目、配置)也在这里。只读,不能删 |
| 新项目落在哪 | 在启用的分片里选当前项目数最少的一个;并列时选编号小的 |
| 已有项目 | 不会自动搬走。追加分片只影响之后新建的项目 |
| 删除分片 | 只允许删没有项目的分片;仍被项目引用时保存被拒绝(40901) |
| 分片后面做副本 | 应用看到的一个分片就是一个 HTTP 地址。地址后面如果你自己做了 ClickHouse 副本,应用不感知 |
一个项目的全部事件、聚合、漏斗、留存、会话、自定义 SQL 都只访问它所在的分片。所以一个人的事件不会跨分片,UV、漏斗、留存在分片内就能算完。
分片连不上时,只有落在它上面的项目查询失败,别的项目照常;采集照常写进队列,积压会上升,见 运维与排障。
把一个项目换到别的分片
有风险,需要维护窗口
本期没有界面按钮,只能由管理员手工做。步骤里任何一步对不上,就停下来,不要改分片编号。
停采集:在项目设置里关掉该项目的「采集开关」,确认采集状态页的积压里不再有它的事件(或者停掉全部进程,并确认它们已经优雅退出)。
准备目标分片:目标分片如果还没有被 evstats 调和过,先按上一节追加它,事件表会自动建好。
复制明细:在目标分片上从源分片复制这个项目的事件:
sqlINSERT INTO evstats.evs_event SELECT * FROM remote('源分片地址:9000', evstats.evs_event, 'evstats', '口令') WHERE project_id = '项目 ID';重算聚合:在目标分片上按 升级 里的回填语句,只针对这个项目重算日聚合和维度聚合。
核对条数:比较源分片和目标分片上这个项目的事件条数,必须一致。对不上就不要进行下一步。
改分片编号:在
s0(系统数据所在的库)里把这个项目的shard_id改成新值:按evs_project表的规则再插入一行完整记录(它是 ReplacingMergeTree,改一行就是插一行新的)。打开采集:确认新事件出现在新分片上之后,再删除源分片上这个项目的数据。