这个礼拜轮到我做production support。今天碰到的一个问题是:X Pool的搜索节点crash!
通过分析core file和access log,我们定位到killing query。发现当输入关键字符合特定pattern的时候,search node就会crash。
根本原因是data issue。即:处理代码认为根本不可能出现某类数据,但是不幸出现了,导致代码执行异常。处理production issue时首先要考虑的问题就是如何让production环境尽快恢复运行,于是我们的任务就是找出索引文件中出问题的X数据的ID,为其重建索引。
问题转化为:找出索引文件中索引键值符合给定pattern的数据ID。
搜索引擎中每个field的属性至少有两类:store还是index,
store表示这个值要保存,但是不一定为这个值建索引;
index表示为这个值建索引,但不一定能够显示(只有保存的Field才可以显示)。
有兴趣的同学可以看一下《Lucene 2.0+Heritrix 开发自己的搜索引擎》这本书,里面对存储,索引和分词有详细的解释。
我们的难点是:我们没有办法利用搜索节点来找出拥有符合特定模式属性的ID,因为一送这样的query程序就crash了。而且我们不一定看得见某个数据是不是含有一个索引值符合给定的pattern,因为这个索引值很有可能没有store属性。虽然数据库中保存着原始数据,但是一个索引中含有的ID有几千万,我们没有办法对几千万个数据在production DB上直接做匹配操作。
解决方案1 :我们在dev环境重现了这个问题,将代码进行debug编译后,使用production的索引,在匹配pattern处设置断点,然后一边看数据结构,一边使用gdb将出问题的数据ID找出来。—> 这个方式弄了我一下午,其实效率不是很好。
解决方案2:[Much Better]
- 修改一下killing query,使用给定pattern的sub-pattern,小心避开导致crash的代码。这样搜索节点会返回匹配sub-pattern的一个ID List,由于使用sub-pattern,搜索节点返回的匹配数据的数量要比实际(使用完整pattern)多,但是却比整个索引文件中的数据量小很多。
- 使用SQL SPOOL到数据库中将ID属于步骤1 ID List中的数据全部dump到一个临时文件中。
- 使用grep, less 很容易就可以找到索引属性符合给定pattern的ID了。
find.sql:
connect username/password@sid
set pagesize 1000
set linesize 1000
define filename= ‘result.txt’
prompt *** Spooling to &filename
spool &filename
select field1,field2,… from table where id in (
id1,id2,id3…idn);
spool off
-bash-3.00$ sqlplus /NOLOG
SQL> start find.sql
SQL> quit
-bash-3.00$ less result.txt
这里补充一下寻找killing query的方法:只要core 文件没有corruption,我们就可以拿到core发生时出错线程的call stack,只有有函数参数或者栈变量保存了指向query的指针并且没有被覆盖,我们就可以使用mdb打印该内存,从而拿到killing query。
假设:
char* tp_Query = 0×80662457;
mdb> 0×80662457/S –> 打印killing query。