共计 1662 个字符,预计需要花费 5 分钟才能阅读完成。
引言
随着 ChatGPT 等大型语言模型的广泛应用,聊天记录的归档和检索成为开发者面临的重要挑战。非结构化数据处理、历史消息检索延迟以及分布式存储一致性是三大核心痛点。本文将详细介绍一套基于 Elasticsearch 和 MongoDB 的混合存储方案,帮助开发者实现高效归档与秒级检索。

技术方案对比
存储性能基准测试
在选择存储方案时,我们对比了 MongoDB、Elasticsearch 和 MySQL 的性能表现。以下是测试结果(测试环境:AWS c5.2xlarge,8 vCPU,16GB 内存):
- MongoDB:写入速度 12,000 docs/s,查询延迟 15ms
- Elasticsearch:写入速度 8,000 docs/s,查询延迟 8ms
- MySQL:写入速度 5,000 docs/s,查询延迟 25ms
Elasticsearch 在查询性能上表现最优,而 MongoDB 在写入速度上更胜一筹。因此,我们采用混合存储方案,将热数据存放在 Elasticsearch,冷数据归档到 MongoDB。
消息分片策略
为了提高查询效率,我们设计了按时间和用户 ID 双维度的分片策略:
- 按时间分片:每月一个分片,便于按时间范围快速定位
- 按用户 ID 哈希分片:确保同一用户的消息分布均匀
数据模型设计
Elasticsearch 索引 Mapping
{
"mappings": {
"properties": {"user_id": {"type": "keyword"},
"timestamp": {"type": "date"},
"conversation": {
"type": "nested",
"properties": {"role": {"type": "keyword"},
"content": {
"type": "text",
"analyzer": "ik_max_word"
}
}
}
}
}
}
nested 结构优化了多轮对话的存储和查询效率,使得对话上下文可以作为一个整体进行处理。
消息压缩算法
为了减少存储空间,我们实现了基于 zlib 的消息压缩算法:
import zlib
from typing import Union
import json
class MessageCompressor:
@staticmethod
def compress(message: Union[str, dict]) -> bytes:
"""压缩消息"""
if isinstance(message, dict):
message = json.dumps(message)
return zlib.compress(message.encode('utf-8'))
@staticmethod
def decompress(compressed: bytes) -> str:
"""解压消息"""
return zlib.decompress(compressed).decode('utf-8')
测试结果显示,压缩比平均达到 60%-70%,显著降低了存储成本。
性能优化
单节点与集群模式对比
在相同的测试环境下(100 万条消息):
- 单节点:QPS 1,200,平均延迟 25ms
- 三节点集群:QPS 3,500,平均延迟 8ms
冷热数据分离
我们设计了冷热数据分离存储方案:
- 热数据(最近 3 个月):Elasticsearch
- 温数据(3-12 个月):Elasticsearch + 压缩存储
- 冷数据(1 年以上):MongoDB 归档
避坑指南
中文分词器选型
- IK 分词器:支持自定义词典,适合专业术语较多的场景
- jieba 分词器:分词速度快,但内存占用较高
批量写入调优
- 最佳 bulk 大小:5,000-10,000 条 / 批次
- 并发线程数:建议 CPU 核心数的 1.5 倍
索引别名切换
使用索引别名实现无缝切换:
- 创建新索引
- 重建数据
- 原子操作切换别名
开放性问题
- 如何实现跨会话的语义搜索?
- 敏感信息自动脱敏方案如何设计?
总结
本文介绍了一套完整的 ChatGPT 聊天归档技术方案,从存储选型到性能优化,涵盖了实际应用中的关键问题。通过混合存储、分片策略和压缩算法,我们实现了千万级聊天记录的高效管理。希望这些实践经验能为开发者提供有价值的参考。
正文完
发表至: 技术分享
近一天内
