程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 數據庫知識 >> SyBase數據庫 >> SyBase教程 >> 性能問題案例02——sybase連接阻塞問題

性能問題案例02——sybase連接阻塞問題

編輯:SyBase教程

性能問題案例02——sybase連接阻塞問題


現象:最近現場反饋一個問題,系統在審批的時候,經常卡死,整個系統完全用不了,浏覽器訪問處於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等,結果如下:<喎?http://www.Bkjia.com/kf/ware/vc/" target="_blank" class="keylink">vcD4KPHA+PGltZyBzcmM9"http://www.2cto.com/uploadfile/Collfiles/20150610/2015061010111750.png" alt="\">

此時基本確定了原因,我們用的是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 NULL
	DROP PROCEDURE dbo.sp__lock
GO

create procedure sp__lock(
    @dbname char(30)=null,@spid int=null,
    @dont_format char(1) = null
)
as
begin

    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, Type

end
GO


  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved