天天看點

case-服務逾時排查

一、問題描述

線上的一個服務A連續出現rpc調用服務B逾時報錯。

仔細看了一下報警發現逾時的rpc服務B都是在集中在一台伺服器h上,并且都是一個接口通路失敗。初步排除網絡抖動原因和受訴主控端影響,因為異常還在出現,根據該接口平常qps情況應該是該接口所有請求都逾時了。

二、原因分析

1. 檢視系統各項監控名額:

CPU:

case-服務逾時排查

最上邊的線就是該伺服器,可以看出cpu使用率很高遠超出其他機器。又看了一下這台機器剛剛釋出過新版本代碼。我的感覺可能是哪個小夥伴挖的坑。其他名額如網絡、gc都正常。那麼就順着這條線查下去。

2. 登上伺服器,使用top檢視下cpu在忙活什麼?

發現一個java線程用了90的cpu。

3. 然後通過jstack看一下這個線程在做什麼。

case-服務逾時排查

看了一下jdk版本,嗯是1.7 ,應該就是著名的hashMap死循環了。

4. 接下來我們跟一下代碼看看到底那裡出了問題。

static {
            schemes.put(StandardScheme.class, new ThriftService.getName_result.getName_resultStandardSchemeFactory(null));
            schemes.put(TupleScheme.class, new ThriftService.getAllWmPoiRule_result.getName_result_resultTupleSchemeFactory(null));
            Map<ThriftService.getName_result._Fields, FieldMetaData> tmpMap = new EnumMap(ThriftService.getAllWmPoiRule_result._Fields.class);
            tmpMap.put(ThriftService.getName_result._Fields.SUCCESS, new FieldMetaData("success", (byte)3, new ListMetaData((byte)15, new StructMetaData((byte)12, WmPoiRule.class))));
            metaDataMap = Collections.unmodifiableMap(tmpMap);
            FieldMetaData.addStructMetaDataMap(ThriftService.getName_result.class, metaDataMap);
        }
           
public class FieldMetaData implements Serializable {
    private static Map<Class<? extends TBase>, Map<? extends TFieldIdEnum, FieldMetaData>> structMap = new HashMap();
    ...
    public FieldMetaData(String name, byte req, FieldValueMetaData vMetaData) {
        this.fieldName = name;
        this.requirementType = req;
        this.valueMetaData = vMetaData;
    }

    public static void addStructMetaDataMap(Class<? extends TBase> sClass, Map<? extends TFieldIdEnum, FieldMetaData> map) {
        structMap.put(sClass, map);
    }
    ...
}
           

熟悉thrift的同學應該知道以上的代碼是thrift自動生成的代碼。這段代碼裡在靜态塊中使用了HashMap,但是不同類的<clinit>又是多線程并發執行。同一個類的<clinit>又是同步執行的,那麼在jdk1.7的情況下并發的put造成了HashMap的死循環的,而<clinit>的同步又block住了通路這一類的所有線程,導緻了該接口的所有線程block住不能傳回最終導緻逾時。

既然查到了問題就好解決了!重新開機萬能大法!!!

三、後續TODO

這麼明顯的bug我想應該早就有人發現了吧,查了一下thrift的issues清單結果真的發現了

https://issues.apache.org/jira/browse/THRIFT-1618

emmmmm事實證明我們該更新了。。。重新開機服務搞定。