標籤:
SQL Server 串連問題案例解析(1)轉載自:http://blogs.msdn.com/b/apgcdsd/archive/2015/04/27/sql.aspx?CommentPosted=true#commentmessage
Microsoft Network Monitor(Netmon)是由微軟發布的一款網路通訊協定資料分析工具,利用Netmon可以捕獲網路資料並進行查看和分析。在處理SQL Server 的串連問題時,Netmon常常會起到關鍵的作用。在本篇博文中,我將為大家分享一個通過使用 Netmon 解決的經典案例。
在這個案例中,客戶發現在用戶端的 SQL Server Management Studio 中執行某一個Query時就會發生錯誤,錯誤資訊是
“connection forcibly close by the remote server ”。 為了調查串連被關閉的原因,我們在用戶端和服務端抓取了Netmon。在正式分析這個案例前,我們先來介紹一些有關Netmon的知識和提示。 Netmon介面
1. 在Netmon介面中的Frame Summary 部分,我們首先可以看到Frame Number,不管我們在瀏覽時是否有設定filter,Frame Number的值是不會發生改變的,它相當於Frame的一個行號。 2. 在左側Network Conversation 中,我們會看到進程的name和ID,在樣本中即為Ssms.exe和3352。繼續展開後看到IPv4,那麼我們可以知道這個conversation是從哪裡來的。再次展開可以看到這個conversation的連接埠,本樣本中,連接埠為
1433到
49428 。 在這裡需要額外講解一下,當用戶端程式建立串連到SQL Server時會使用哪些連接埠呢?用戶端會向作業系統申請並使用一個動態連接埠並向SQL Server發送串連請求。如果在串連時使用的是machine name,provider預設會去串連1433連接埠,這是一個
provider的行為,改變這個行為需要修改註冊表:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\MSSQLServer\Client\<Provider>\tcp\DefaultPort
3. 當用戶端嘗試建立一個串連到SQL Server,有了source port和destination port後,在這兩個port中就會形成一組physical tcp串連。形成串連之後每發一個包,包的sequence值就會發生變化。
請注意,只有在同一個物理串連中,sequence的變化是連續的。如果用戶端和SQL Server建立了兩個不同的物理串連,這兩個串連中的sequence沒有任何關係。
4. Netmon中資料量很大,如果查看呢?比如在瀏覽一個比較大的Netmon時,我們發現了一個Reset Flag:
21 3:46:20 PM 9/5/2014 21.8000442 Ssms.exe 172.22.204.237 172.16.221.38 TCP
TCP: [Bad CheckSum]Flags=...A.R.., SrcPort=49428, DstPort=1433, PayloadLen=0,
Seq=3636257929, Ack=707503184, Win=0 {TCP:2,IPv4:1}
就可以從這個Frame的詳細資料入手。從詳細資料中可以找到它的source port是49428。(1)此時我們可以就通過添加 filterTcp.port==49428 來過濾出這個Reset的conversation。
(2)另外一種過濾方法是直接在按右鍵Frame後彈出的菜單中選擇Find Conversation, 但這種方法有可能會造成丟包,因此還是推薦使用第一種方法。
找到了port就幾乎相當於找到了出問題的串連。當然,對於不同時間點,同樣的port有可能會是兩個不同的串連,因為上一個串連關掉後,
下一個串連有可能重用這個port。按照port過濾後,從reset 開始順序往前看。
5. 在Netmon中我們還可以看到一些protocol是TDS的Frame。TDS的好處是在查看Frame Details時,可以看到更多的資訊。例如我們查看一個TDS:SQLBatch的TDS Frame Detail,可以看到SQL的statement:
對於當SQL Server使用的連接埠不是預設的1433時,如何顯示TDS frames,可以參考下面這篇博文:How to enable TDS parser to display TDS frames when SQLServer is listening on port other than default 1433
6. 除了在4中介紹的通過port進行過濾,最常用的filter還有
ipv4.address==<xxx.xx.xx.xx>
除直接在filter中寫入之外還有一種添加filter的方法,以過濾出所有flag是reset的frames為例來說明:那麼我可以在某個reset frame的details中找到這個flag,在按右鍵彈出的菜單中選擇Add Selected
Value to Display filter:
7. 一個SQL Server的包會在網路傳輸過程中會經過以下幾層:
NIC(網卡物理裝置)—》NDIS(網卡驅動)—》TCPIP (作業系統)—》afd(作業系統後台線程,每一個tcp port上都會有一個afd)—》
SQL Server—》for authentication(調用 sspi—lssas—DC)
Netmon所抓取的資料是在網卡驅動上面和TCPIP 下面的。 所以Netmon所抓到的包是不能作為網卡真正發出去的包的,需要比較發出去的包和用戶端收到的包來判斷網卡或路由等是否進行了切包。
8. 在chimney開啟時,抓到的包的資訊有可能是不全的,如果在查看時發現包的行為很奇怪,懷疑丟包,那麼一定要請客戶關閉chimney(以管理員運行CMD並且執行命令:netsh interface tcp set global chimney=disabled)後重新收集Netmon。
接下來,我們就來討論一下今天的案例。當具備了以上Netmon的知識和技巧後,在處理這個案例中所收到的Netmon資料就非常有針對性了。將用戶端的Netmon資料按照連接埠號碼filter後,可以很清楚的看到,用戶端一直面對著重傳的問題。16是12的重傳,17也是12的重傳,甚至18,19,20:
那麼我們來看一下12的詳細資料:
可以看到這個包的長度是4096。那麼16呢?查看16的詳細資料時我們發現,16的長度變成了1460:
在重傳時包的長度變小說明,由於之前大包無法傳遞,傳遞的包的大小被自動調小了。繼續查看17,18,19和20會發現這幾個包的長度都是1460。很明顯,這是一個大包發不過去導致重傳的問題。
那麼現在問題來了,為什麼第一次大包發不過去,之後以小包重傳也不成功呢?
查看server端Netmon後會發現,這是由於傳輸4096的包被切成1460+1460+1172後,server端只收到了最後一個包。接下來,由於sequence斷了,server端會認為這是一個不合法的包,因為中間的資訊缺失了。之後這個串連就在server端直接被block了(所以我們收到的錯誤資訊是“connection forcibly close by the remote server
”),因此後續re-transmit的1460的包server再也沒有接收過(後續重傳全都失敗了)。
最終問題的解決辦法是關閉網卡上的兩個選項:Jumbo Packet和Large Send Offload(LSO)。
開啟Jumbo Packet表示支援大包,關閉則表示從NIC發出的包採用標準大小1500。
如果LSO是開啟的,切包會由網卡驅動(NDIS)完成。如果LSO關閉,切包會由作業系統(TCP Stack)完成,切成多大由Jombo Packet的設定來決定。我們通常不建議由網卡來切包,因為網卡切包與網路環境有關,可能會導致包的大小不固定,建議還是由作業系統來進行切包。將這兩個選項關閉後,傳輸包的大小均為標準大小1500,就解決了這個大包被切,重傳失敗的問題。
這就是今天的分享,更多SQL Server案例學習請持續關注本部落格的更新。
server端Netmon和client端netmon Jumbo Packet:巨型包
SQL Server 串連問題案例解析(1)