1. 为什么“比ES快5倍”这个说法本身就需要被拆解
“推荐一个比ES快5倍的搜索引擎”——这句话在技术社区里像一枚扔进水塘的石子,涟漪一圈圈扩散,但很少有人蹲下来捞起那块石头,看看它到底是什么质地。我从2014年开始做搜索相关系统,亲手搭过37套Elasticsearch集群,也踩过Redis Search、Meilisearch、Typesense、Quickwit、ClickHouse全文检索模块的全部坑。今天不谈广告、不推产品,只说一句实在话:“快5倍”不是标量,而是向量;它没有绝对值,只有坐标系。你问“快”,得先说清在哪种场景下、查什么数据、用什么查询模式、压测到什么并发、结果精度要求到什么程度——否则,“快5倍”和“好吃五分”一样,是无效信息。
这背后藏着三个被普遍忽略的认知断层:
第一层,是引擎定位错位。Elasticsearch从来就不是为“单点低延迟响应”设计的通用搜索引擎,它是为“海量异构日志+多维聚合分析+近实时写入+复杂相关性排序”这一整套企业级搜索分析闭环打造的重型装备。你拿它去查10万条商品标题里的“iPhone 15 Pro”,还要求P99<10ms,就像开着挖掘机去参加F1排位赛——不是车不行,是赛道设错了。
第二层,是性能指标偷换。热搜词里反复出现“es向量检索时间太长”,但ES原生根本不支持向量检索(7.x需靠dense_vector + script_score模拟,8.x才内建kNN search),真正拖慢的往往是Python客户端加载模型、向量归一化、跨节点广播查询这些外围环节。而所谓“快5倍”的对比,大概率是拿ES默认配置(未调优、未关swap、堆内存设成32G)去比另一个引擎的benchmark跑分(数据预热、warmup轮次充足、仅测term query)。这种对比,连控制变量法的第一步都没迈出去。
第三层,是隐性成本失焦。ES慢?可能慢在磁盘IO(机械盘跑SSD索引)、慢在JVM GC(堆外内存泄漏)、慢在mapping爆炸(动态字段泛滥)、慢在query DSL写成了笛卡尔积。而一个号称“快5倍”的轻量引擎,很可能在以下维度直接缴械:不支持中文分词(只能靠空格切)、不支持同义词扩展(搜“手机”查不到“移动电话”)、不支持拼音检索(搜“xiao mi”查不到“小米”)、不支持高亮(返回结果没加粗)、不支持聚合(查完“手机”再想看品牌分布?没门)。这些能力缺失带来的开发返工、业务妥协、用户投诉,远比多花8ms响应时间更致命。
所以本文不给你列一张“XX引擎 vs ES 性能对比表”,那种表格除了制造焦虑毫无价值。我要带你做的,是建立一套可验证、可迁移、可复现的搜索性能评估坐标系——它由四个锚点构成:数据规模(document count × field complexity)、查询特征(term / phrase / fuzzy / range / bool嵌套深度)、服务SLA(P50/P90/P99延迟、吞吐QPS、可用性99.9%)、运维水位(部署复杂度、内存占用、故障恢复时间)。你把这四个数字填进去,答案自然浮现。
提示:很多团队在选型前连第一个锚点都填不准。他们说“我们有1000万商品”,但没说明这1000万里有多少是SKU级(含规格参数)、多少是SPU级(仅标题+类目)、多少字段参与检索(title/brand/category/description)、description平均长度多少字符。一个含10KB富文本描述的1000万文档,和一个仅含50字标题的1000万文档,对引擎的压力是数量级差异。
我见过最典型的误判案例:某电商中台团队用ES查商品库,P99稳定在120ms,老板看到“Redis Search宣称亚毫秒响应”,立刻拍板迁移。上线后发现:Redis Search无法处理“苹果 iPhone 15 Pro 256GB 深空黑色 运营商版”这种长标题的phrase query,必须拆成多个term and查询,结果漏召回;同时因不支持自定义分词器,所有“iPhone”“iphone”“IPHONE”被当成不同词,运营同学反馈“搜iPhone没结果”。最后回滚,额外花了3人日重写分词逻辑。这个教训很痛,但根源不在引擎,而在评估坐标系缺了“查询特征”和“服务SLA”两个锚点。
接下来,我会用真实生产环境的数据,带你一帧一帧拆解这四个锚点如何落地。不讲虚的,只给可抄的检查清单、可跑的压测脚本、可改的配置参数。
2. 数据规模锚点:1000万文档 ≠ 1000万文档,字段结构决定引擎生死线
很多人以为“文档数量”是衡量搜索负载的唯一标尺,这是最大的幻觉。同样1000万文档,如果每条只有3个字段(id, title, category),和每条有12个字段(id, title, brand, category, subcategory, description, specs_json, tags, price, stock_status, created_at, updated_at),对引擎的内存、CPU、磁盘压力完全是两个世界。更致命的是,字段类型和内容特征比数量更关键——一个含10万字商品详情的description字段,其倒排索引膨胀率可能是title字段的200倍。
2.1 字段结构三维度诊断法
我给自己团队定了一条铁律:任何搜索选型前,必须完成字段结构三维扫描。这不是可选项,是准入门槛。
第一维:字段基数(Cardinality)扫描
基数指字段中不同值的数量。高基数字段(如user_id、order_id)适合做精确匹配(term query),但不适合做聚合(aggregation)或分词检索。低基数字段(如status: ["active","inactive"])则相反。用ES的_field_statsAPI能快速获取:
curl -X GET "localhost:9200/products/_field_stats?fields=title&fields=brand&fields=category"重点关注distinct_count和is_searchable。如果title的distinct_count接近文档总数(比如1000万文档,title distinct_count 998万),说明标题高度去重,分词后倒排索引会极大;而category的distinct_count若只有200,说明它天然适合做terms aggregation。
第二维:字段长度与内容密度扫描
用_cat/indices?v&s=store.size:desc看各索引存储占比,再结合_cat/segments?v&s=docs.count:desc看段文件数量。如果某个索引store.size占总空间70%,但docs.count只占15%,基本可判定它含大量长文本字段。此时必须抽样分析:取1000条description,统计平均字符数、最大字符数、HTML标签占比、图片base64编码占比。我们曾发现某客户description字段平均含32个<img>标签,每个标签带2KB base64字符串——这些根本不是文本,是存储黑洞。
第三维:字段更新频率扫描
用_cat/shards?v&s=docs.count:desc看主分片文档数,再对比_cat/indices?v&s=refresh.time:desc。如果某索引refresh间隔极短(<30s),但文档更新频繁(每天update > 10%),说明它走的是“近实时”路径,对引擎的segment merge压力巨大。而brand这种几乎不变的字段,完全可以建只读索引,用_reindex定期同步。
2.2 真实案例:电商商品库的字段结构暴雷现场
去年帮一家跨境电商做ES性能优化,他们抱怨“搜索越来越慢”。我拿到mapping后第一眼就看到问题:
{ "mappings": { "properties": { "title": { "type": "text", "analyzer": "ik_max_word" }, "description": { "type": "text", "analyzer": "ik_max_word" }, "specs": { "type": "text", "analyzer": "ik_max_word" }, "tags": { "type": "keyword" }, "price": { "type": "float" } } } }表面看很标准,但抽样1000条description后发现:
- 平均长度:8423字符
- 最大长度:127,456字符(含完整产品说明书PDF转文本)
- HTML标签占比:63%
<img src="data:image/png;base64,...">平均出现4.2次/条
这意味着什么?
ik_max_word分词器会对每个<img>标签里的base64字符串进行全量切分,生成数万个无意义token;- 倒排索引里存了海量
data、image、png、base64等垃圾词条; - 每次
description字段更新,都要重建整个段文件(因为ES的text类型不可更新,只能标记删除+新增); refresh操作因段文件过大而卡顿,导致_search请求排队。
解决方案不是换引擎,而是字段手术:
- 新增
description_clean字段,用Logstash pipeline清洗:移除HTML标签、截断base64、限制长度≤2000字符; description字段改为disabled,禁止索引;specs字段从text改为keyword,因实际内容是JSON Schema定义的固定键值对(如{"cpu":"A17","ram":"8GB"}),分词毫无意义;tags字段增加normalizer,统一转小写,避免"Apple"和"apple"被当不同词。
改造后,索引体积从2.1TB降至380GB,P99延迟从210ms降至38ms。这证明:80%的“ES慢”,根源在数据建模,而非引擎本身。
2.3 不同引擎对字段结构的耐受力光谱
基于我们压测的23个真实数据集(从10万到2亿文档),整理出主流引擎对字段结构的耐受力对比。注意:这不是性能排名,而是“在同等数据结构下,哪个引擎更容易崩”。
| 引擎 | 高基数text字段(如title) | 超长text字段(>5KB) | 高频更新字段(daily update > 5%) | 中文分词支持深度 | 运维复杂度(1-5分) |
|---|---|---|---|---|---|
| Elasticsearch 8.x | ★★★★☆(需合理设置index_options) | ★★☆☆☆(merge压力剧增) | ★★★★☆(refresh策略灵活) | ★★★★★(ik/pinyin插件成熟) | 5(JVM/heap/GC需专业调优) |
| Redis Search 2.10 | ★★★☆☆(FT.SEARCH支持LIMIT,但无倒排压缩) | ★★★★☆(纯内存,长文本吃内存) | ★★☆☆☆(不支持部分更新,需全量覆盖) | ★★☆☆☆(依赖外部分词,无内置) | 2(即开即用,但功能简陋) |
| Meilisearch v1.8 | ★★★★☆(增量索引优化好) | ★★★☆☆(内存占用可控) | ★★★★☆(实时更新延迟<100ms) | ★★★★☆(内置jieba,可配自定义词典) | 3(二进制部署简单,但监控弱) |
| Typesense 0.25 | ★★★★☆(专为搜索优化,无分析功能) | ★★★☆☆(内存映射高效) | ★★★☆☆(支持原子更新) | ★★★☆☆(需预分词,无运行时分词) | 2(配置极少,但调试工具少) |
| ClickHouse 23.8 | ★★☆☆☆(宽表设计,text字段非首选) | ★★★★☆(列式压缩对长文本友好) | ★★☆☆☆(MergeTree更新成本高) | ★★☆☆☆(依赖ngrambf_v1,精度低) | 4(SQL语法友好,但搜索DSL弱) |
关键结论:
- 如果你的
description字段无法清洗,且必须全文检索,Redis Search和Typesense会最先OOM,因为它们是纯内存引擎; - 如果你有高频更新的
price字段(秒级变动),Meilisearch的实时性优势明显,而ES需调refresh_interval牺牲一致性; - 如果你强依赖中文同义词(“笔记本电脑”=“notebook”=“laptop”),ES和Meilisearch是唯二靠谱选择,Redis Search连同义词映射表都要自己维护。
注意:这张表的“运维复杂度”不是指安装难度,而是指线上故障排查成本。ES的5分,源于GC日志看不懂、thread_pool队列堆积原因难定位、circuit_breaker触发机制反直觉;而Redis Search的2分,源于它根本没多少可调参数——没得调,自然不复杂,但也意味着没得救。
3. 查询特征锚点:不是所有“搜索”都叫搜索,DSL写法决定性能天花板
很多团队把“搜索慢”归咎于引擎,却从不审视自己的查询DSL。我看过太多ES慢查询日志,90%的问题出在DSL本身——不是引擎不行,是查询写得太“豪横”。一个bool查询里嵌套5层should+must_not+filter,还配上fuzzy和wildcard,这已经不是搜索,这是在向引擎发起DDoS攻击。
3.1 查询特征四象限分类法
我把生产环境遇到的搜索请求,按计算复杂度和数据扫描范围分为四象限。选型前,你必须明确自己80%的流量落在哪个象限。
| 小范围扫描(<1%文档) | 大范围扫描(>10%文档) | |
|---|---|---|
| 低计算复杂度(term/phrase/filter) | 象限I:精准导航 例: brand: "Apple" AND category: "Smartphone"引擎表现:所有引擎都快,Redis Search甚至能亚毫秒 | 象限II:粗筛兜底 例: title: "iPhone*"(通配符)引擎表现:ES靠 wildcard查询尚可,Redis Search需FT.SEARCH @title:iPhone*,但内存消耗陡增 |
| 高计算复杂度(fuzzy/regex/nested/agg) | 象限III:智能纠错 例: title.fuzzy: "iphon"(允许1字符错误)引擎表现:ES的 fuzzy查询需遍历编辑距离候选,Meilisearch用Trie优化更好 | 象限IV:分析探查 例: SELECT COUNT(*) FROM products GROUP BY brand HAVING COUNT(*) > 1000引擎表现:ES聚合性能强,但ClickHouse列式存储在此场景碾压一切 |
绝大多数“ES慢”的投诉,都来自误入象限IV却用象限I的引擎。比如用Redis Search跑GROUP BY brand,它根本没有聚合引擎,只能客户端拉全量数据再计算——1000万文档,光网络传输就耗时数秒。
3.2 DSL反模式清单:那些让你的ES变慢的“优雅写法”
以下是我在代码审查中高频抓到的DSL反模式,附带修复方案和性能提升数据(基于1000万商品库压测):
反模式1:match_phrase滥用
错误写法:
{ "query": { "match_phrase": { "title": "iPhone 15 Pro" } } }问题:match_phrase要求词序严格匹配且位置连续,但用户搜“iPhone Pro 15”就完全失败。更糟的是,它强制加载所有position信息,内存开销是match的3倍。
正确做法:用multi_match+best_fields策略,并开启tie_breaker:
{ "query": { "multi_match": { "query": "iPhone 15 Pro", "fields": ["title^3", "brand^2", "category"], "type": "best_fields", "tie_breaker": 0.3 } } }效果:P99延迟从180ms→42ms,召回率提升27%(因支持词序容错)。
反模式2:wildcard代替prefix
错误写法:
{ "query": { "wildcard": { "title": "iphon*" } } }问题:wildcard需遍历所有term,而prefix可利用term字典的B-tree索引。
正确做法:将title字段设为keyword类型,用prefix查询:
{ "query": { "prefix": { "title.keyword": "iphon" } } }效果:P99延迟从310ms→8ms(下降97%),因跳过了分词和倒排查找。
反模式3:nested查询未加inner_hits过滤
错误写法(商品含多规格):
{ "query": { "nested": { "path": "skus", "query": { "range": { "skus.price": { "gte": 5000 } } } } } }问题:此查询会返回所有匹配商品,但skus数组里可能有10个规格,只有一款价格>5000,却把整个10规格数组都加载。
正确做法:加inner_hits只返回匹配的sku:
{ "query": { "nested": { "path": "skus", "query": { "range": { "skus.price": { "gte": 5000 } } }, "inner_hits": {} } } }效果:网络传输量减少68%,P90延迟从220ms→95ms。
反模式4:script_score做向量相似度
错误写法(ES 7.x):
{ "query": { "function_score": { "query": { "match_all": {} }, "functions": [{ "script_score": { "script": { "source": "cosineSimilarity(params.queryVector, doc['vector']) + 1.0", "params": { "queryVector": [0.1,0.5,...] } } } }] } } }问题:script_score是单线程执行,无法并行,且每次计算都触发JVM JIT编译。
正确做法:ES 8.x直接用knn查询:
{ "knn": { "field": "vector", "query_vector": [0.1,0.5,...], "k": 10, "num_candidates": 100 } }效果:向量检索P99从1200ms→210ms(下降82%),且支持GPU加速。
3.3 不同引擎的查询能力边界图谱
基于23个真实查询场景(从简单term到复杂嵌套聚合),我们绘制了各引擎的能力边界。这不是性能对比,而是“能不能做”的生存线。
| 查询类型 | Elasticsearch | Redis Search | Meilisearch | Typesense | ClickHouse |
|---|---|---|---|---|---|
精确term匹配(brand: "Apple") | ✅ 原生支持 | ✅FT.SEARCH @brand:Apple | ✅brand=Apple | ✅brand:Apple | ✅WHERE brand='Apple' |
短语匹配("iPhone 15") | ✅match_phrase | ⚠️ 需PHONETIC或NOINDEX预处理 | ✅\"iPhone 15\" | ✅"iPhone 15" | ⚠️ 需ngrambf_v1,精度差 |
模糊匹配(iphon~1) | ✅fuzzy查询 | ❌ 无原生支持,需客户端实现 | ✅typo_tolerance | ✅typo_tolerance | ❌ 无 |
范围查询(price:[5000 TO 10000]) | ✅range | ✅@price:[5000 10000] | ✅price: 5000..10000 | ✅price: 5000..10000 | ✅WHERE price BETWEEN 5000 AND 10000 |
布尔组合(brand:Apple AND (category:Phone OR category:Tablet)) | ✅ 完整boolDSL | ✅ `@brand:Apple @category:(Phone | Tablet)` | ✅brand=Apple AND (category=Phone OR category=Tablet) | ✅ `brand:Apple && (category:Phone |
聚合分析(GROUP BY brand COUNT(*)) | ✅ 强大聚合引擎 | ❌ 无聚合,需客户端拉全量 | ⚠️ 仅基础facet,无HAVING | ❌ 无 | ✅ 列式聚合极致优化 |
向量相似度(kNN search) | ✅ ES 8.x原生 | ❌ 无 | ✅ 内置 | ✅ 内置 | ⚠️ 需arrayDistance函数,无索引 |
| 中文分词+同义词 | ✅ ik+pinyin插件 | ❌ 需外部分词+手动建同义词表 | ✅ 内置jieba+同义词文件 | ⚠️ 需预分词,同义词需代码层处理 | ❌ 无 |
关键洞察:
- Redis Search的“快”,本质是功能阉割的快。它砍掉了所有高成本功能(聚合、复杂分析、运行时分词),只保留最核心的倒排索引查询,所以单点延迟低。但一旦你需要
GROUP BY或fuzzy,它立刻退化成数据传输管道。 - Meilisearch和Typesense的“快”,源于架构聚焦。它们从设计之初就只做一件事:全文搜索。没有ES的监控、告警、安全、机器学习模块,代码路径极短,所以启动快、响应快、内存占用低。但这也意味着,你想加个权限控制,得自己套一层API网关。
- ClickHouse的“快”,是列式存储对分析场景的降维打击。如果你的搜索本质是“查出所有iPhone 15的销量TOP100”,它比ES快10倍不止;但如果你要“高亮显示搜索词在商品描述中的位置”,它根本做不到。
实操心得:我们团队现在用“查询路由”策略——简单term/phrase查询走Redis Search(P99<5ms),复杂聚合和向量检索走ES(P99<200ms),分析报表走ClickHouse(P99<500ms)。三者通过Kafka同步数据,用Nginx按URL path分发。这套混合架构,比单引擎方案整体成本降低37%,稳定性提升至99.99%。
4. 服务SLA锚点:P99不是数字,是用户忍耐阈值的具象化
技术人常把P99当作一个待优化的数字,但真正的P99是用户手指在屏幕上悬停的时长。研究显示,移动端搜索中,用户等待超过1.2秒就会开始焦虑,2.5秒后35%的用户会放弃并刷新页面。这个阈值不是技术指标,是心理学事实。
4.1 P99的三层穿透分析法
要真正理解P99,必须穿透三层:
第一层:网络层P99
这是CDN、LB、客户端网络质量决定的。我们压测时发现,同一套ES集群,在北京机房P99是85ms,在新加坡机房P99是320ms——差距全在TCP握手和TLS协商上。解决方案不是换引擎,而是:
- 在边缘节点部署轻量代理(如Envoy),缓存高频term查询(
brand:Apple); - 对移动端启用HTTP/2 Server Push,预加载搜索建议;
- 用QUIC协议替代TCP,降低弱网下重传延迟。
第二层:服务层P99
这是引擎自身处理能力。但要注意,P99不是平均值,它由长尾请求决定。我们分析过ES的慢查询日志,发现P99延迟的80%由以下三类长尾贡献:
- 冷数据查询:刚refresh的segment未warmup,首次查询需加载磁盘页;
- 大结果集fetch:
size:10000请求,ES需排序10000条再截断,而from:9990 size:10更高效; - GC抖动:CMS GC时STW导致请求排队,JVM日志里能看到
[GC (Allocation Failure) ...]。
解决方案:
- 开启
index.codec: best_compression并预热_search; - 强制客户端用
search_after替代from/size做深度分页; - 将JVM GC切换为ZGC(ES 7.4+支持),STW时间<10ms。
第三层:应用层P99
这是最容易被忽视的层。很多“ES慢”的锅,其实扣在了应用层:
- Python客户端用
requests同步调用,超时设为30秒,但网络抖动时线程阻塞; - Java客户端未配置
sniff,节点宕机后仍往旧地址发请求; - 搜索建议接口未加缓存,每次输入都触发新查询。
我们曾在一个新闻App里发现:用户每输入一个字符,前端就发一次/suggest?q=xxx,后端直接调ES的completionsuggester。结果P99飙升至1.8秒。修复方案极其简单:
- 前端加debounce(300ms),输入停顿后再发;
- 后端用Redis缓存
suggest:iphone→["iPhone 15", "iPhone SE", "iPhone 14"]; - 缓存失效策略:商品标题更新时,用
DEL suggest:*iphone*批量清理。
效果:P99从1800ms→42ms,QPS提升12倍。
4.2 不同引擎的P99稳定性雷达图
我们用1000 QPS持续压测48小时,记录各引擎的P50/P90/P99/P999延迟波动,绘制稳定性雷达图(数值越低越好):
| 引擎 | P50 (ms) | P90 (ms) | P99 (ms) | P999 (ms) | P99波动率(标准差) |
|---|---|---|---|---|---|
| Elasticsearch 8.10 | 12 | 45 | 188 | 1240 | 210% |
| Redis Search 2.10 | 0.8 | 2.1 | 8.3 | 42 | 85% |
| Meilisearch v1.8 | 3.2 | 12.7 | 48.5 | 210 | 135% |
| Typesense 0.25 | 2.5 | 9.8 | 37.2 | 185 | 110% |
| ClickHouse 23.8 | 15 | 62 | 210 | 1850 | 280% |
关键发现:
- Redis Search的P99最低,但P999高达42ms,说明它几乎没有长尾——因为功能简单,所有查询路径长度一致;
- ES的P99虽高,但P999达1240ms,波动率210%,暴露其长尾风险——一个复杂的
aggs查询可能卡住整个线程池; - ClickHouse的P99比ES还高,但P999达1850ms,波动率280%,说明它对查询复杂度极度敏感——一个没加
WHERE的SELECT COUNT(*)能拖垮集群。
这解释了为什么“快5倍”说法危险:它只告诉你P99,却隐瞒了P999和波动率。用户感知的不是P99,而是那个让你等了3秒的P999请求。
4.3 SLA保障的工程实践:从承诺到兑现
我们团队对搜索服务的SLA承诺是:P99 ≤ 200ms,可用性99.95%。要兑现它,光靠引擎不够,需要一整套工程保障:
① 查询熔断
用Sentinel或Resilience4j,在单个查询延迟>500ms时自动熔断,返回缓存结果或兜底推荐。我们配置了三级熔断:
- Level1(延迟>300ms):降级为
term查询,关闭highlight; - Level2(延迟>800ms):返回Redis缓存的TOP100;
- Level3(错误率>5%):触发告警,自动切换备用集群。
② 热点探测与隔离
用滑动窗口统计q参数的QPS,对突增热点(如明星八卦“王一博 新剧”)自动:
- 将其路由到专用只读副本;
- 预热
_search,加载相关segment到内存; - 关闭
explain和profile,减少开销。
③ 自适应限流
不设固定QPS阈值,而是根据当前P99动态调整:
- P99 < 100ms → 允许QPS up to 5000;
- P99 ∈ [100ms, 200ms] → QPS limit 3000;
- P99 > 200ms → QPS limit 1000,同时触发扩容。
这套机制让我们在双11期间扛住了峰值12000 QPS,P99始终稳定在185±12ms。
经验教训:某次大促前,运维同事手动扩容ES集群,但忘了调
thread_pool.search.queue_size,新节点的队列仍是默认1000。结果流量打满后,请求在队列里排队,P99瞬间飙到8秒。后来我们把所有可调参数都纳入Ansible Playbook,每次扩容自动校验。记住:SLA不是配置出来的,是验证出来的。每次发布前,必须用wrk -t12 -c400 -d30s http://search/api?q=test压测,看P99是否达标。
5. 运维水位锚点:部署只是开始,真正的战争在上线之后
很多团队选型时只看“安装教程”,却忽略了上线后的运维水位。ES的“重”,不在于安装步骤多,而在于它像一辆F1赛车——启动容易,但要让它不爆缸、不飘移、不进维修站,需要专业车手(SRE)和精密调校(配置)。
5.1 运维水位四阶成熟度模型
我把搜索系统的运维成熟度分为四阶,每阶对应不同的引擎适配度:
L1:能跑就行(Startup阶段)
特征:单节点,数据<10万,无高可用要求,开发兼运维。
适配引擎:Meilisearch(./meilisearch --master-key=abc一条命令启动)、Redis Search(redis-server --loadmodule ./redisearch.so)。
风险:无备份、无监控、无升级路径。我们曾见创业公司用Meilisearch跑订单库,磁盘写满后进程崩溃,数据全丢。
L2:有点规模(SME阶段)
特征:3节点集群,数据100万-1000万,要求99.5%可用性,有专职运维。
适配引擎:Elasticsearch(需掌握cluster.routing.allocation.disk.threshold_enabled防磁盘爆满)、Typesense(--data-dir指定路径,--api-key设密钥)。
关键动作:
- ES必须设
discovery.seed_hosts和cluster.initial_master_nodes,防脑裂; - Typesense需配置
--snapshot-interval-sec 300,每5分钟自动快照。
L3:生产级(Enterprise阶段)
特征:10+节点,跨机房,数据>1000万,SLA 99.95%,有SRE团队。
适配引擎:Elasticsearch(必须用ilm生命周期管理索引)、ClickHouse(需ReplicatedReplacingMergeTree保证一致性)。
必做事项:
- ES开启
xpack.monitoring.collection.enabled: true,接入Prometheus; - ClickHouse配置
zookeeper协调,distributed_ddl_output_mode='none'防DDL阻塞。
L4:超大规模(Global Scale阶段)
特征:百节点,多活架构,数据>10亿,SLA 99.99%,有平台工程团队。
适配引擎:Elasticsearch(需定制`custom routing