索引漏洞正 silently 拖垮你的搜索性能
|
2026年6月,凌晨三点十七分,我蹲在k8s集群dashboard里刷pod重启次数,第十八秒点到那个es-data-7的pod——它又挂了,但ready状态还在绿着。我盯着metrics面板发呆,cpu曲线像被谁用指甲刮过,锯齿状抖动,间隔固定得让人起鸡皮疙瘩。没告警,没oomkill,连cgroup throttling都压在阈值线下。这事儿我原以为是node资源争抢,结果把node-exporter日志拽出来一比对,抖动时刻跟索引merge线程峰值严丝合缝。 群里突然@全员,消息是小林发的:“es集群search latency跳到两千三百毫秒,业务说搜索页loading转圈转成摩斯电码了。”他截图里curl -XGET那条命令还带着没删干净的调试参数:?pretty&explain=true&profile=true。我手滑点开explain输出,看到那个嵌套四层的bool/must/must_not/should——里头有个terms查询,terms数组里塞了三百七十二个值,其中两百零六条是空字符串,三十七条是单个星号。这玩意儿不是业务写的,是某次logstash pipeline误配置后,连续七天把原始nginx日志字段当query string塞进了_search API里跑的。没人改,没人停,它就自己活着。
文章配图,仅供参考 那个IP地址我见过三次。192.168.137.219。第一次在WAF日志里,规则ID 89341(ELK-SQLi-Like-Pattern),匹配的是/_search?q=title:,被拦了;第二次在es audit log里,status: 200,user: "elastic",source: 192.168.137.219,req_body里藏着个"_source": {"excludes": [""]},后面还跟了个\\ \\t;第三次在宿主机dmesg里,时间戳差八分钟,kernel log写着“ext4 lazytime disabled on /var/lib/elasticsearch”,底下紧接着一行:“SELinux is preventing /usr/share/elasticsearch/jdk/bin/java from getattr access”。我敢打包票,这三个时间戳是同一台物理机上的三块日志板子,但具体哪个先写、哪个是伪造的timestamp,我说不准。 我们组老张昨天拿jq写了个脚本扫所有索引settings,想看看谁家还在用默认refresh_interval: 1s。脚本跑了四小时二十三分钟,扫完发现二十七个索引用了1s,十九个用了30s,还有五个根本没设——直接继承cluster setting。但没人管这个。反而有人问:能不能让脚本也查查mapping里有没有nested类型?我说查了也没用,你猜怎么着?那五个没设refresh_interval的索引,mapping全是dynamic: false,field names全带emoji,比如"title_????"、"content_????"。运维手册上没写emoji算不算合法field name,Elastic文档里更没提。但ES收了,存了,还建了倒排索引。这个我敢打包票。 前天下午五点零六分,我收到一个陌生文件,叫.gitignore.swp。不是在git repo里,是在/opt/es-backup/tmp目录下。文件权限600,owner是elasticsearch,mtime是2026-06-12 04:17:03。打开一看全是乱码,但前四字节是b'vimg'。我没删,也没动,就把它mv到/opt/es-backup/tmp/.swp_bak_20260612_0417。今天早上看,文件还在。但它创建时间戳没变,大小从一百零二千字节涨到一百零二千零三字节。多出的三个字节是\ 安全是成本不是收入。这句话不是我发明的,是我2022年在客户现场看他们把WAF策略配成“放行所有POST _search”时,隔壁甲方CTO一边喝枸杞茶一边甩出来的。当时我以为他在骂预算。结果现在我懂了——他真觉得安全策略越细,业务越卡,收入越掉。所以他们把索引生命周期管理交给业务自建脚本,脚本里hardcode了rollover条件:“size > 5gb OR docs > 10m”,但从不check shards.total_limit_in_bytes。三个月前有个index shard跑到四百二十个,master node内存直接爆表,我们切走流量重启master的时候,运维同学在钉钉上打字:“这事儿能走报销吗?”我说不能,他说哦,然后贴了个链接,是阿里云ES控制台里“自动扩缩容建议”的截图,底下小字写着:“当前配置下,预计每日额外费用增加十八元”。 溯源做到一半断了。从es audit log查到的_source query,还原出原始用户token是uuid格式,base64解出来是{"app":"mobile-search","env":"prod","v":"2.7.4"},但我们没找到对应的client-cert,也没抓到TLS handshake包。最后线索停在ingress-nginx的access log里一条状态码499记录,req_time是0.001秒,upstream_addr是10.42.18.34:9200,request_uri是/_search。但10.42.18.34这台pod已经删了,deployment history只保留最近十五次rollout,那次不在里面。我就没继续往下追——不是不想,是k8s audit日志开关关着,etcd snapshot两周前清理过,而那个时段的prometheus metrics存储在另一个cluster里,账号权限还没打通。 我昨天把logstash配置里的output.elasticsearch.hosts从["es-master:9200"]改成["es-ingest:9200"],只加了一层ingest pipeline做query normalization。上线两小时,/_search?q= 的QPS掉了百分之四十一,latency中位数从一千一百毫秒压到六百三十毫秒。但今天早上发现es-ingest节点上多了个unknown container,镜像名是docker.elastic.co/elasticsearch/elasticsearch:8.11.3-debug,创建时间是昨晚十一点四十七分,command是"/bin/bash -c 'sleep infinity'"。它没连任何volume,网络mode是host,pid mode也是host。我看了一眼,没删。它现在还活着。我就坐在工位上,开着kubectl top node,盯着ingest节点cpu那根绿线,看它忽高忽低,像呼吸一样。 下周二我准备去跟DBA组碰一下,问问他们mysql slow log里有没有类似现象:明明没慢查询,但连接池总在半夜三点耗尽。要是真有,我就借他们一台测试库,把es的query DSL转成SQL explain,试试能不能看出merge风暴和buffer pool刷脏页之间是不是有什么鬼一样的共振频率。要没有……我就把es audit log的rotation周期调短,再把那串192.168.137.219加进黑名单——虽然我知道,加了也拦不住,人家早切走了。先这么着吧。 (编辑:站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |


安全修复对搜索引擎索引效果的影响分析
漏洞修复+索引优化:双擎驱动搜索性能跃升
