数据库与前端:新闻词频统计场景的负载均衡方案咨询
核心思路是用分层预聚合+窄表存储把99%的计算压力前置到离线定时任务,前端仅接收最终计算完成的结果,完全不承担词频计算逻辑,同时把传输数据量控制在KB级别。
1. 词频统计表结构设计
不要用固定字段存单词的宽表,直接用KV结构的窄表设计,从根本上解决文章长度差异、用词差异带来的字段浪费/数据不全问题。
最小粒度的基础聚合表用小时维度,表结构参考:
CREATE TABLE source_word_hourly_stats ( id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, news_source VARCHAR(64) NOT NULL COMMENT '新闻来源唯一标识', stat_hour DATETIME NOT NULL COMMENT '统计周期起始时间,精确到小时', word VARCHAR(128) NOT NULL COMMENT '预处理后的标准词条', word_count INT UNSIGNED NOT NULL DEFAULT 0 COMMENT '对应周期内该词条的总出现次数', UNIQUE KEY uk_source_hour_word (news_source, stat_hour, word), KEY idx_source_time_range (news_source, stat_hour) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
这个结构没有任何字段冗余:不管单篇文章有多少词、不同来源用词重合度多低,每一条记录只存「某来源+某小时+某词条」的计数值,既不用为长文章预留多余字段,也不会因为只存TopN丢失全量词频数据。
注意跑聚合任务前先做文本预处理:提前过滤无意义停用词、对单词做词干提取(比如把running/ran统一归为run),能砍掉至少60%的无效存储。
2. 多粒度聚合解决时间分辨率问题
不要只做天级单一粒度的聚合,搭三层查询路由,同时满足细粒度查询灵活性和长周期查询性能:
- 短时间窗(查询范围<6小时):直接扫描对应时间范围内的原始文章正文做实时词频统计。这个时间范围内的文章总量最多不超过单日爬取量的1/4,计算压力极低,支持精确到分钟级的任意细粒度查询需求。
- 中时间窗(6小时≤查询范围<30天):直接查询小时粒度聚合表,按词条分组对
word_count做求和,再排序取目标高频词即可,不需要扫原始文本。因为基础聚合粒度是1小时,完全支持非整天的时间范围查询(比如查过去7天里每天早8点到晚10点的词频)。 - 长时间窗(查询范围≥30天):复用和小时表完全一致的表结构建天级聚合表,每天凌晨把前一天24小时的小时表数据按词条求和写入天表,查长周期数据时直接扫天表,查询速度比扫小时表快20倍以上。
3. 前后端交互的负载控制逻辑
所有词频计算逻辑全部放在后端,前端请求只需要传3个参数:news_source(目标来源)、start_time/end_time(查询时间范围)、top_n(需要返回的高频词数量,默认设20,强制上限100防止恶意拉取全量数据)。
后端接到请求后自动路由到对应的数据层做计算,最终只返回前端需要的TopN词条和对应计数,单条响应数据量基本在10KB以内,不会出现传输过量的问题。
额外给查询结果加10分钟的本地缓存,相同来源、相同时间范围(按小时对齐)的请求直接返回缓存结果,能挡住80%的重复查询压力。
按这个方案落地,哪怕后续爬取量翻10倍,数据库查询响应时间也能稳定在100ms以内,前端不需要做任何词频相关的计算。
内容的提问来源于stack exchange,提问作者Ric

