<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    posts - 42,comments - 83,trackbacks - 0
            目前Apache + Weblogic Cluster是很多企業應用的架構模式,前端Apache負責請求分發,后端利用Weblogic Cluster的session replication提供failover。絕大多數情況下,這種模式工作的很好。這篇文章我將以標題中的兩個名詞為中心,探討一下Apache plugin的分發及failover機制。首先看一下這兩個名詞:

    No backend server available:沒有可用的后端服務器。最常見最可能的原因就是:后端server全部沒有啟動或者Apache無法連接到其中的任何一個。復現方式很簡單,只啟動Apache,然后做后端weblogic server的業務請求,或者中斷Apache到后端服務器的網絡。這種原因很好檢查,也很好解決。本文中我們將探討另外一種情況,網絡沒有問題,而且至少有一個服務器存活,但客戶端仍然碰到“No backend server available”。

    HALF_OPEN_SOCKET_RETRY:Weblogic內部自定的異常,這種異常通常由于Apache使用了某個已經中斷的連接向后端服務器發送請求,這種請求肯定會失敗。連接中斷的原因也很多,比如我們關閉后端的服務器,那么Apache手里到這個服務器的連接再次被使用時,Apache將會收到HALF_OPEN_SOCKET_RETRY。

            首先,我們看一下plugin的分發機制。通常每個非初始請求都會在自己的cookie中有一個JSESSIONID,JSESSIONID由weblogic產生,用戶唯一標識和該用戶相關的Session。JSessionID常見格式為:
    SessionHash ! primaryHash ! SecondaryHash,比如:
    s4wYKyvDKG2ZDHwQclchD50PYjvCsN9nLSL9hPRMQ2ZzM3pVdbL1!1198345223!-977705075
    primary:該Session的主服務器
    secondary:該Session的備份服務器,如果沒做SessionReplication,則沒有該列。如果SessionReplication失敗,那么該列會是none或null。

            有了JSESSIONID,在load_utils.getPreferredServersFromCookie()中,plugin會解析這個JSESSIONID,如果我們打開plugin的debug,我們會看到類似如下的信息,

    Thu Sep 10 08:56:36 2009 <1899912525369961> Found cookie from cookie header: JSESSIONID=s4wYKyvDKG2ZDHwQclchD50PYjvCsN9nLSL9hPRMQ2ZzM3pVdbL1!1198345223!-977705075
    Thu Sep 10 08:56:36 2009 <1899912525369961> Parsing cookie JSESSIONID=s4wYKyvDKG2ZDHwQclchD50PYjvCsN9nLSL9hPRMQ2ZzM3pVdbL1!1198345223!-977705075
    Thu Sep 10 08:56:36 2009 <1899912525369961> getpreferredServersFromCookie: [1198345223!-977705075]
    Thu Sep 10 08:56:36 2009 <1899912525369961> primaryJVMID: [1198345223]
    secondaryJVMID: [-977705075]

          解析出了primaryJVMID、secondaryJVMID,這是plugin需要檢查這兩個id是否為空,如果兩個都為空,那么說明這個請求沒有prefer server,plugin只要按照最基本的load balance策略作請求分發即可。如果至少有一個不為空,我們繼續找該session所prefer的server,debug 信息如下:

    Thu Sep 10 08:56:36 2009 <1899912525369961>Primary or Secondary JVMID *not* found in cookie, ignore preferred servers //說明沒有從cookie中找到primay或secondary。
    Thu Sep 10 08:56:36 2009 <1899912525369961> No of JVMIDs found in cookie: 2 //說明找到了兩個jvmID

            Apache plugin運行過程中會維護一個server list,這個server list就是我們在httpd.conf中指定的server列表,如果我們使用了dynamic server list,那么這個list是隨著后端cluster的變化而動態更新的。server list中每個server有自己的JVMID。plugin從cookie中解析出primaryJVMID、secondaryJVMID后,需要primaryJVMID、secondary JVMID做校驗,防止cookie中的信息過于陳舊(如果后端服務器發生過重起,就會出現JVMID不一致的情況)。校驗過程其實很簡單,plugin會遍歷手里的server list。如果發現某個server被標志為bad,它會檢查skip-time,如果skip-time(默認10秒)已到,即從這個server被mark bad到現在已經超過10秒,那么plugin會把這個server重新mark good(這樣如果我們接下來創建到這個server的連接成功,那這個server就真的可用了,plugin通過這種機制來恢復后端server)。

     1     time_t t = lists[i].startMarkBad;
     2     if (t > 0) {
     3       time_t now = 0;
     4       time(&now);
     5       int delta = now - t;
     6       if (delta >= MAX_SKIP_TIME) {
     7         lists[i].startMarkBad = 0;
     8         lists[i].isGood = 1;
     9       }
    10     }

            接著plugin會將解析出來的primaryJVMID、secondaryJVMID后自己server list中server的JVMID做比對。如果primary匹配,就把對應的serverInfo設入請求的preferred[0],同樣如果seconday匹配,對應的serverInfo會被設入請求的preferred[1]。注意:接下來plugin將以preferred為基礎進行分發、failover。debug信息如下:

    Wed Sep 02 14:33:12 2009 <553612518731924> getPreferredFromCookie: Found Primary 172.23.4.53:8001:0
    Wed Sep 02 14:33:12 2009 <553612518731924> getPreferredFromCookie: Found Secondary 172.23.4.52:8001:0
    如果匹配的server數目和cookie中jvmid數一致,則還能看到如下輸出:
    Wed Sep 02 14:33:12 2009 <553612518731924> getPreferredFromCookie: Found 2 servers
    如果不匹配,那么輸出信息將是下面這樣:
    Wed Sep 02 14:33:12 2009 <553612518731924> getPreferredFromCookie: Found atleast 1 server

            如果匹配結果發現沒有一致的JVMID,如下:
    Thu Sep 10 08:56:36 2009 <1899912525369961> getPreferredFromCookie: Either JVMIDs not set or they are stale. Will try to get JVMIDs from WLS
    那么這時候plugin就需要強制更新自己server list中server的JVMID,這個更新通過proxy.initJVMID()實現。initJVMID中,plugin遍歷整個server list,嘗試創建到每個server的連接,如果連接創建失敗,這個server會被mark bad。連接創建成功,plugin向后端server發送internal request,如下:
    Thu Sep 10 08:56:36 2009 <1899912525369961> ======internal request /bea_wls_internal/ WLDummyInitJVMIDs======
    如果連接能夠成功創建,但發送請求的時候發生HALF_OPEN_SOCKET_RETRY(這里為什么會發送HALF_OPEN_SOCKET_RETRY,后面我們會討論到),這個server也會被mark bad(這里對HALF_OPEN_SOCKET_RETRY的處理不同于應用請求),如下:

    Thu Sep 10 08:56:36 2009 <1899912525369961> readStatus: Local port of the socket 53149, connected to Remote Host/Port 172.23.4.53/8001
    Thu Sep 10 08:56:36 2009 <1899912525369961> readStatus: Response contains no data - isRecycled: 0
    Thu Sep 10 08:56:36 2009 <1899912525369961> *******Exception type [HALF_OPEN_SOCKET_RETRY] (Unexpected EOF reading HTTP status - request retry) raised at line 854 of ../nsapi/URL.cpp
    Thu Sep 10 08:56:36 2009 <1899912525369961> initJVMID: Failed to retrieved JVMID for 172.23.4.53:8001:8001
    Thu Sep 10 08:56:36 2009 <1899912525369961> initJVMID: Marked server as BAD

    如果請求處理成功,將會看到類似于以下的信息:

    Thu Sep 10 08:56:36 2009 <1899912525369961> ServerInfo struct for JVMID '-977705075' populated
     Server Details are:
     OrigHostInfo [172.23.4.52]
     isOrigHostInfoDNS [0]
     Host [172.23.4.52]
     Port [8001]
     SecurePort [8201]
    Thu Sep 10 08:56:36 2009 <1899912525369961> Initializing lastIndex=0 for a list of length=1

    initJVMID()除了更新jvmID,同時還給我們這個請求分配了preferred server list。

            獲取到請求的preferred后,程序的控制權將回到proxy.wl_proxy(),這個方法是所有http請求的入口。回到wl_proxy后,進入while循環,循環的終止條件就是我們的retry次數(默認5次)。進入循環后,debug信息如下:
    Thu Sep 10 08:56:36 2009 <1899912525369961> attempt #0 out of a max of 5 

            plugin要成功發送一個http請求,首先需要拿到connection,如果我們設置了keep-alive,首先會從connection pool中獲取,如果沒有,則創建新的物理連接。debug信息分別如下:
    Wed Sep 02 14:35:45 2009 <553612518733456> got a pooled connection to preferred server '172.23.4.53/8001for '/test_sleep/testsleep.jsp', Local port:3651
    Wed Sep 02 14:33:12 2009 <553612518731924> created a new connection to preferred server '172.23.4.53/8001' for '/test_sleep/testsleep.jsp', Local port:3636

             拿到connection后,plugin會將request的header信息發送到server端,并從連接上讀取response。此時上面兩種連接都可能出現HALF_OPEN_SOCKET_RETRY。我們分別看看這兩種情況:

    1:如果pool connection對應的后端服務器已經被shutdown,那么我們那pool connection做操作的時候,肯定無法完成,因此很容易碰到HALF_OPEN_SOCKET_RETRY。碰到HALF_OPEN_SOCKET_RETRY,plugin會做retry,而不是直接failover。重新去getConnection,如果pool中corrupted connection足夠多,那么五次失敗后,客戶端最終會看到“No backend server available”,debug中會有如下信息:

    Tue Sep  1 10:43:41 2009 <10088125176582121> request [/socs/favicon.ico] did NOT process successfully..................

    2:pool中的connection不是很多,比如2個,那么我們做完兩次retry后,這是就要創建物理的連接,如果連接創建失敗,這個server會立刻mark bad,請求將被failover到secondary,debug信息如下:
    Wed Sep 02 14:36:06 2009 <553612518733456> *******Exception type [CONNECTION_REFUSED] (Error connecting to host 10.182.216.198:8002) raised at line 1732 of ../nsapi/URL.cpp
    如果創建連接成功,但sendRequestHeader的時候發生HALF_OPEN_SOCKET_RETRY,那么plugin同樣會繼續作retry,而不是failover。如果剩余幾次retry結果都一樣(創建連接成功,但sendRequestHeader失敗),客戶最終也會看到“No backend server available。日志通常如下:
    Tue Sep  1 10:43:41 2009 <10088125176582121> attempt #5 out of a max of 5
    Tue Sep  1 10:43:41 2009 <10088125176582121> created a new connection to preferred server '172.23.4.52/8001' for '/socs/favicon.ico', Local port:49416
    ......
    Tue Sep  1 10:43:41 2009 <10088125176582121> URL::sendHeaders(): meth='GET' file='/socs/favicon.ico' protocol='HTTP/1.1'
    ......
    Tue Sep  1 10:43:41 2009 <10088125176582121> readStatus: Local port of the socket 49416, connected to Remote Host/Port 172.23.4.52/8001
    Tue Sep  1 10:43:41 2009 <10088125176582121> readStatus: Response contains no data - isRecycled: 0
    Tue Sep  1 10:43:41 2009 <10088125176582121> *******Exception type [HALF_OPEN_SOCKET_RETRY] (Unexpected EOF reading HTTP status - request retry) raised at line 854 of ../nsapi/URL.cpp
    Tue Sep  1 10:43:41 2009 <10088125176582121> got exception in sendRequest phase: HALF_OPEN_SOCKET_RETRY: [os error=0, line 854 of ../nsapi/URL.cpp]: Unexpected EOF reading HTTP status - request retry at line 3080

            對于1,這個可以理解,如果pool中connection被關閉(keep-alive超時)完了,客戶就不會碰到這樣的問題問題了。而對于2,更多的應該說是OS的問題,OS沒有正確釋放端口。如果端口釋放成功,plugin做url.connect()的時候,應該是收到connection refuse,而不是正常創建連接(實際上是無用連接,使用時出現Socket_Half_Open)。對于2,我們可以通過以下的方法檢查:
    1:ps -ef | grep java,檢查對應的managed server時候shutdown
    2:netstat -a | grep listening port,如果server已經shutdown了,卻還能看到listening port,那么就是OS的問題了。 

          寫了這么多,覺得比較繁瑣,不知道大家能否看得明白,建議最好拿一個wl_proxy的debug log,對照著看。
           
    posted on 2009-09-14 08:54 走走停停又三年 閱讀(6642) 評論(5)  編輯  收藏 所屬分類: Weblogic

    FeedBack:
    # re: Weblogic Apache Plugin由HALF_OPEN_SOCKET_RETRY引起的“No backend server available”
    2009-09-14 21:16 | sorcerer
    一直沒搞明白,apache如何進行心跳檢測?后端的appServer主動報告?hung的情況可以被識別為not available嗎?  回復  更多評論
      
    # re: Weblogic Apache Plugin由HALF_OPEN_SOCKET_RETRY引起的“No backend server available”
    2009-09-15 08:55 | 走走停停又三年
    對于無法連接的server,apache會做mark bad。過了max skip time后,這個server會被重新加入server list(無論這個server是否存活),然后嘗試創建到該server的連接,如果失敗,那么繼續將其mark bad。至于,hanging server的問題,參考WLIOTimeoutSecs。  回復  更多評論
      
    # re: Weblogic Apache Plugin由HALF_OPEN_SOCKET_RETRY引起的“No backend server available”
    2009-09-15 22:05 | sorcerer
    搜索WLIOTimeoutSecs居然可以搜到本帖了....
    既然Apache + Weblogic Cluster可以做load balance和failover那么是不是不需要lvs了?  回復  更多評論
      
    # re: Weblogic Apache Plugin由HALF_OPEN_SOCKET_RETRY引起的“No backend server available”
    2009-09-15 22:11 | 走走停停又三年
    @sorcerer

    你可以這么認為,如果費用不吃緊可以考慮lvs。failover是由weblogic的session replication實現的,這個是硬件層面無法做到的。  回復  更多評論
      
    # re: Weblogic Apache Plugin由HALF_OPEN_SOCKET_RETRY引起的“No backend server available”
    2009-09-15 23:32 | sorcerer
    還是有點迷惑,我們用了f5,session replication沒做,怕影響性能,但是系統都是sso的,應該也不用重登錄.那么f5的主要功能似乎就是load balance了,apache既然可以做了,干嘛還要花這個錢呢.難道,只是因為廠商吹噓的硬件更穩定,性能更高?當然配置起來確實方便.  回復  更多評論
      
    主站蜘蛛池模板: 亚洲精品成人久久久| 国产成人涩涩涩视频在线观看免费 | 亚洲精品精华液一区二区| 免费人成在线观看69式小视频| 亚洲一区影音先锋色资源| 日本免费中文字幕| 亚洲AV午夜福利精品一区二区| 久久久久久免费一区二区三区| 亚洲av网址在线观看| 无码午夜成人1000部免费视频| 久久91亚洲精品中文字幕| 91av在线免费视频| 亚洲国产精品白丝在线观看| 国产麻豆视频免费观看| 亚洲精品精华液一区二区 | 亚洲视频免费观看| 亚洲啪啪免费视频| 亚洲综合偷自成人网第页色| 女人张开腿等男人桶免费视频| 国产精品亚洲专区无码唯爱网 | 国产精品免费AV片在线观看| 亚洲小视频在线观看| 色影音免费色资源| 亚洲欧美成人综合久久久| 亚洲第一区精品日韩在线播放| 中文成人久久久久影院免费观看 | 18禁黄网站禁片免费观看不卡| 国产亚洲国产bv网站在线| 国产无遮挡裸体免费视频| 中文字幕乱码系列免费| 久久亚洲精品成人AV| 亚洲免费综合色在线视频| 老司机午夜性生免费福利| 最新亚洲成av人免费看| 一区二区三区福利视频免费观看| 亚洲激情校园春色| 国产最新凸凹视频免费| 日韩电影免费在线观看| 日本亚洲欧美色视频在线播放 | 免费A级毛片无码视频| 久久亚洲国产成人影院|