Cassandra单表行数缩减的正确模式及大数量级人数统计实现
针对你要处理50亿条人员数据、统计各国人数并把表行数控制在100万以内的需求,Cassandra里最靠谱的模式就是预聚合(Pre-Aggregation)——要么用原生计数器实时聚合,要么定期批量聚合,完全能实现你要的<国家, 计数>快速查询。下面给你详细拆解两种核心方案,以及极端场景下的补充技巧:
1. 原生计数器表方案(实时性优先)
这是最直接的方案,利用Cassandra原生的counter类型,直接维护一张聚合表,行数等于你的国家数量(肯定远小于100万)。
实现步骤:
- 首先创建聚合表,主键设为国家,值用计数器:
CREATE TABLE country_population ( country text PRIMARY KEY, person_count counter );
- 每当新增人员数据时,同步更新这个计数器表(如果需要保留原始人员数据,就双写:写原始人员表 + 更新计数器表):
UPDATE country_population SET person_count = person_count + 1 WHERE country = 'China';
- 查询时直接读取这张表,就能一次性拿到所有<国家, 计数>的键值对,速度极快——因为表行数极少,全表扫描或者分页查询都毫无压力。
优势&注意点:
- 实时性拉满:每新增一条数据就同步更新计数,查询结果是最新的;
- 原子性保障:Cassandra的计数器更新是原子操作,不用担心并发更新导致的计数错误;
- 若遇到人员更换国家的场景,只需先对旧国家执行
-1,再对新国家执行+1,同样是原子操作,一致性有保障。
2. 定期批量聚合方案(写入性能优先,适合海量离线数据)
如果你的人员数据是批量导入的,或者对实时性要求没那么高(比如允许延迟1小时/1天),可以用这种方案,先存原始数据,再定期聚合。
实现步骤:
- 先创建按时间分区的原始人员表,保证写入性能(Cassandra擅长处理按时间分区的海量写入):
CREATE TABLE people_raw ( partition_date date, person_id uuid, country text, PRIMARY KEY (partition_date, person_id) );
- 用Spark/Flink或者Cassandra Spark Connector,定期(比如每天凌晨)跑聚合任务:统计每个国家的人员总数,将结果写入到聚合表(可以用普通表,也可以用上面的计数器表)。
- 查询时直接读聚合表即可,同样能拿到<国家, 计数>的结果。
优势&注意点:
- 写入性能极高:原始表按时间分区,写入时不会出现热点,能轻松处理50亿级别的数据;
- 资源占用可控:聚合任务可以在业务低峰期运行,不会影响在线查询;
- 若需要回溯历史数据,原始表还能保留,方便后续重新聚合。
3. 分层缓存补充(极端海量场景)
如果你的“国家”维度真的接近100万(比如包含大量细分地区),可以再加一层缓存来优化查询速度:
- 用Redis作为一级缓存,缓存热门国家的计数;
- 查询时先查Redis,没命中再查Cassandra聚合表,同时把结果回写到Redis;
- 这样既保证了Cassandra聚合表的行数在100万以内,又能进一步提升热门查询的响应速度。
避坑提醒:
绝对不要尝试在Cassandra里对50亿条原始数据做全表扫描聚合——Cassandra的设计目标是快速读写,不是离线分析,全表扫描会直接拖垮集群,完全不现实。预聚合才是正确的思路。
内容的提问来源于stack exchange,提问作者Alex Kokorin
相关产品推荐
相关产品推荐

