效能問題案例02——sybase串連阻塞問題,02sybase

來源:互聯網
上載者:User

效能問題案例02——sybase串連阻塞問題,02sybase

現象:最近現場反饋一個問題,系統在審批的時候,經常卡死,整個系統完全用不了,瀏覽器訪問處於loading的狀態。



排查:

1.一般系統掛了首先想到記憶體問題,但是現象是loading,也就是說沒有掛,線程正在執行,懷疑是線程被阻塞了,配置上jvisualvm監控了一下,出問題後記憶體沒滿確定不是記憶體問題,查看線程dump發現大部分都在執行sql查詢,

初步發現是執行sql慢導致的。

 

2.我們用的是sybase資料庫,執行了幾個簡單sql發現幾分鐘都沒執行完,使用sp_sysmon "00:00:30"監控近30秒的情況發現cpu、記憶體、線程都沒問題,幾乎1%使用率都不到,懷疑是某個串連阻塞了表,導致其他串連全部阻塞導致的。

 

3.我們使用自己寫的預存程序查看阻塞的串連,結果如下:

PS:使用sp_lock命令就可以查看哪個串連阻塞了資料庫,但是顯示的都是tableid等,還需要重新查詢轉換成具體表名等,自己寫的預存程序只是此處轉換了一下,後面會附上。



發現其中1萬多個鎖,7000多個排它鎖,Ex_row-blk是阻塞了其他串連的鎖,發現有21個阻塞了其他串連的鎖,對應的表是T_ZXLD_SYYH,執行select * from master..sysprocesses找到對應的串連,如的User有316/287/283等,結果如下:



此時基本確定了原因,我們用的是c3p0串連池,應該是某個串連阻塞了表,其他所有串連查詢時候都被阻塞了,導致串連池被佔滿,所有請求凡是涉及資料庫查詢的都被阻塞了,頁面始終處於loading狀態。

 

 4.那麼接下來就是找到阻塞的地方,發現tran_name都是$chained_transaction,結合程式判斷,也就是說都在執行某個責任鏈裡面的事務時阻塞了,系統就2處使用了責任鏈,直接就可以判斷到時審批的責任鏈導致的,那麼接下來就是排查此處代碼是否有問題了,審批次程序如下:


(1)開啟事務

(2)根據參數查詢出要審批的主表資料,2個sql

(3)逐條調用審批組件(類似工作流程的一個組件)審批,每條資料大約5個更新sql,2個查詢sql

(4)更新主表狀態,每條資料1個更新sql

(5)插入審計日誌,每條資料1個插入sql

(6)產生提醒訊息,查詢全部主表資料,20個查詢sql,5個更新刪除sql(非常慢)

(7)更新增量記錄表,記錄該條資料修改時間和狀態等,每條資料1個更新sql

(8)提交事務


懷疑並發時相互阻塞導致的,產生提醒訊息的地方,會查詢全部業務表,如果此時有其他串連在事務中審批,就會阻塞,其他串連在產生訊息,相互阻塞,造成死結。理論上資料庫會自動處理死結的,但是不知道什麼原因,日誌報的死結數量不是特別多。


而且此處業務處理也太合理,正常使用者每次批量審批大約100條資料,所以大約有900多個增刪改sql,200多個查詢sql,像產生訊息等sql執行非常慢(因為涉及更新舊訊息),這麼多操作放到一個事務中非常慢,審批表大約3000w資料,業務主表500w資料,執行起來也不是很快。

 

解決辦法:重構了此處代碼,講上面執行慢的(5)(6)(7)步驟新起一個線程,不放到事務中執行,即使失敗也影響不大。這樣sql減少了30%,速度快了不少,更新到現場,觀察了一個星期,發現未出現不響應等情況,算是問題解決。

 

雖然問題解決,但是根本原因沒有找到,為什麼會相互阻塞,為什麼死結沒自動檢測,這個是後續需要跟蹤的。

 

最後,問題雖然解決了,但是中間溝通花了不少時間,和營運人員要現場資料耽誤了很多事,簡單整理一下,後續出問題的時候搜集這幾個資料:
1、sp__lock的結果;(使用文章最後提供的預存程序)
2、select * from master..sysprocesses;
3、如果資料庫慢,加上sp_sysmon "00:00:30"的結果;
4、中介軟體線程dump檔案;


附上sybase查看鎖的預存程序

IF OBJECT_ID ('dbo.sp__lock') IS NOT NULLDROP PROCEDURE dbo.sp__lockGOcreate procedure sp__lock(    @dbname char(30)=null,@spid int=null,    @dont_format char(1) = null)asbegin    declare @dbid smallint    if @dbname is not null        select @dbid=db_id(@dbname)    if (charindex("sa_role", show_role()) > 0)    begin        if @dont_format is null            select "Type"=substring(v.name,1,11),                "User"=substring(suser_name(p.suid)+" ("+rtrim(convert(char(6),l.spid))+")",1,20),                "Table"=substring(db_name(l.dbid)+".."+convert(char(20),object_name(l.id,l.dbid)),1,26),                "Page"=convert(char(8),l.page),                "Cmd"=substring(p.cmd,1,11)            from master..syslocks l,                 master..sysprocesses p,                 master..spt_values v            where p.spid=l.spid and                l.type = v.number and                v.type = "L" and                p.dbid=isnull(@dbid,p.dbid) and                p.spid=isnull(@spid,p.spid) and                l.dbid=isnull(@dbid,l.dbid) and                l.spid=isnull(@spid,l.spid)            order by l.dbid, l.id, v.name        else            select "Type"=v.name,                "User"=suser_name(p.suid)+" ("+rtrim(convert(char(6),l.spid))+")",                "Table"=db_name(l.dbid)+".."+object_name(l.id,l.dbid),                "Page"=l.page,                "Cmd"=p.cmd            from master..syslocks l,                  master..sysprocesses p,                 master..spt_values v            where p.spid=l.spid and                l.type = v.number and                v.type = "L" and                p.dbid=isnull(@dbid,p.dbid) and                p.spid=isnull(@spid,p.spid) and                l.dbid=isnull(@dbid,l.dbid) and                l.spid=isnull(@spid,l.spid)            order by l.dbid, l.id, v.name        return    end    select "Type"=v.name,        "Usernm"=convert(varchar(60),suser_name(p.suid)+" ("+rtrim(convert(char(6),l.spid))+")"),        "TableNm"=convert(varchar(60),db_name(l.dbid)+".."),        "Page"=l.page,        "Cmd"=p.cmd,        l.id,        l.dbid    into #locks    from master..syslocks l,         master..sysprocesses p,         master..spt_values v    where p.spid=l.spid    and        l.type = v.number    and        v.type = "L" and        l.dbid=isnull(@dbid,l.dbid) and        l.spid=isnull(@spid,l.spid) and        p.dbid=isnull(@dbid,p.dbid) and        p.spid=isnull(@spid,p.spid)    update #locks    set    TableNm=TableNm+object_name(id,dbid)    where dbid=db_id() or dbid=1 or dbid=2    update #locks    set TableNm=TableNm+convert(varchar,id)    where dbid<>db_id() and dbid>2    delete #locks    where TableNm like "tempdb..#locks%"    if @dont_format is null        select substring(Type, 1,11),            "User"=substring(Usernm, 1,14),            "Table"=convert(char(26),TableNm),            "Page"=convert(char(8),Page),            "Cmd"=substring(Cmd,1,11)        from #locks        order by dbid, id, Type    else        select Type, "User"=Usernm, "Table"=TableNm, Page, Cmd        from #locks        order by dbid, id, TypeendGO



相關文章

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.