昨晚凌晨三点,我被钉钉群里的报警短信硬生生拽醒。
心跳瞬间飙到一百二。
生产环境,Es集群,Geo索引,全挂了。
不是小问题,是大规模超时。
用户打开APP,地图加载转圈,最后直接白屏。
这种时候,慌一点用都没有。
你得冷静,得像机器一样思考。
我披上外套,连拖鞋都没换,直接连上服务器。
一看监控,CPU占用率99%,GC频繁得像个帕金森患者。
这就是典型的Es geo索引超时。
很多同行遇到这情况,第一反应是加机器。
别急,加机器救不了急,反而可能让集群更乱。
我复盘了一下最近的操作。
上周为了优化搜索速度,我把一批历史经纬度数据重新索引了一遍。
数据量不大,也就几百万条。
但在Es眼里,Geo点可不是简单的数字。
它是空间索引,是复杂的倒排结构。
每次写入,Es都要计算Shardings,还要维护GeoHash或者RTree树。
如果字段类型没设对,或者Mapping没配好,那简直是灾难。
我检查了Mapping,发现有个坑。
有个同事为了省事,把location字段设成了text类型。
这简直是给Es喂毒药。
Text类型会分词,Geo类型需要精确坐标。
这俩根本不在一个频道上。
结果就是,Es在写入时疯狂尝试分词匹配,导致线程池堆积。
请求进不来,超时自然发生。
这就是Es geo索引超时最常见的原因之一:类型错误。
除了类型,还有另一个隐形杀手:数据倾斜。
你看监控,几个主节点的负载高得吓人,其他节点却在摸鱼。
这说明数据分布不均。
Geo数据有个特性,就是热点集中。
比如北京、上海、深圳这几个点,数据量巨大。
如果Shard数量设置不合理,或者没有做好分片策略,热点数据就会压垮单个节点。
我当时的做法,很粗暴,但有效。
第一步,暂停写入。
先止血,再治病。
通过API临时关闭了索引的自动刷新间隔,从1秒改成30秒。
这一步能大幅减少IO压力。
第二步,重新调整Mapping。
把location字段改成geo_point类型。
同时,增加了shard的数量,从5个调到了15个。
别怕数据量大,Es处理海量数据是强项,怕的是结构不对。
第三步,分批重刷数据。
不能一次性全量导入,那样集群会直接崩盘。
我写了个脚本,按小时分片,每小时导入10万条。
看着进度条一点点爬升,心里才稍微踏实点。
这个过程花了大概两个小时。
当最后一个数据块导入完成,我重启了集群。
再次访问API,响应时间从之前的5秒,降到了200毫秒。
绿灯亮起,世界安静了。
事后我总结了几条血泪经验。
第一,Mapping一定要在创建索引前定好。
别想着后期改,Es改Mapping是灾难性的操作,尤其是涉及Geo类型时。
第二,Shard数量要算好。
一般建议每个Shard大小在10G到50G之间。
太小了,元数据开销大;太大了,恢复慢。
对于Geo数据,还要考虑热点分布,必要时使用自定义分片路由。
第三,硬件不是万能的。
我见过太多人,一遇到性能瓶颈就加服务器。
其实,80%的问题出在配置和代码上。
比如,批量写入时,使用bulk API,每次批量大小控制在5-15MB。
别一股脑全塞进去。
还有,开启压缩。
Es默认开启压缩,但有时候为了极致性能,可以调整压缩算法。
当然,这些都是进阶玩法。
最基础的,还是要把基本功练好。
Es geo索引超时,看似是网络问题,其实是架构和配置问题。
如果你也遇到了类似情况,别急着重启。
先抓日志,看是写入慢,还是查询慢。
写入慢,查Mapping和Bulk策略。
查询慢,查Shard分布和缓存命中率。
别被表象迷惑。
这次事件后,我在团队里立了一条规矩。
任何涉及Geo索引的变更,必须经过Code Review。
还要在测试环境模拟真实数据量进行压测。
哪怕麻烦点,也比半夜被叫醒强。
毕竟,生活已经够累了,睡眠比什么都重要。
希望这篇笔记,能帮你避开我踩过的坑。
Es geo索引超时,不可怕,可怕的是你不知道它为什么超时。
搞清楚原理,一切迎刃而解。
今晚,希望能睡个安稳觉。