2008年4月24日 星期四

Web計數問題之探討

各位夥伴,大家好:
   不久前我在檢視警政備份回來的程式碼時,發現在cluster的架構下運作時,CountFilter.java紀錄counter的部分,會引發 Database中所謂Lost update的問題,因為程式中取值與增值後寫入是分別在兩個交易中進行的。只是不知eTax的程式是否也有相同的問題,而 SessionListener的程式也可能有相同的情況。這個問題會造成Counter會比實際值要小。
   附帶說明一下, CountFilter.java可用於計數「瀏覽次數」及「訪客人次」,而「訪客人次」的計數也可以在SessionListener中進行。由於 HTTP為無狀態的應用協定,所以「訪客人次」需要利用Web container所提供的Session tracking機制才能達成,而一般Web container預設是以紀錄Session-id的Cookie來提供Session tracking機制,但Web browser不接受Cookie的話,則此方式的Session tracking將會失效,為避免此一情況發生,一般Web container還會至少提供URL-rewriting作為替代的Session tracking機制,但此方式必須要以程式對HTTP回應中所有URL進行加工處理,以便Web Container可在URL中附加Session-id,對於靜態網頁及由JavaScript所發出的請求則會失效,因為請求的URI中就不可能會附加Session-id。還有其他達成Session Tracking機制的方式,如HTTP認證機制、SSL及HTML Form的隱藏欄位等等,但Web Container一般無法提供,則需要以程式碼來達成目的。
   綜合以上所述,要精確地計數「訪客人次」是不可能的,就連「瀏覽次數」可能都會有不精確的計算結果,但eTax的計數問題並不在於不夠精確,而在於以程式計數和以分析Access log 來計數的結果相差甚遠,而又無法提出具體而可說服客戶的解釋,依據我的認知來看,以程式來計數,會比以分析Access log來計數來的可信。當然前提是以程式來計數的演算法在各種情境中是正確無誤的。我會有如此想法,有幾點原因:首先Access log並未包含請求所有的資訊,例如請求內容(content)以及部份的Header等,而被請求的網頁有時會因為這些資訊,而將原始請求轉向 (forward)或重導(redirect)至其他網頁。以Java Servlet來說,forward是發生在Web container內部,所以Web server的Access log中不會有紀錄,但是以程式來計數卻是可能會被計數的,而redirect則是利用HTTP協定的功能來達成,兩者計數並不會有落差,但原始請求網頁實際上並未產生被顯示的回應,若不想加以計數的話,以程式計數是可以辦得到,而以分析Access log來計數則應判斷回應狀態碼。還有就是Web Server接受請求,寫入Access log中,才將請求轉給Web container進行後續處理,而在Web container的後續處理的某個程序中進行以程式計數,是有可能會發生Access log有紀錄,而程式計數卻沒有執行到!另外,由於GIP有啟用Web cache機制:在回應中附加last-modified標頭。這個對Access Log的分析不知是否會造成差異。應該還有許多的情況會造成兩種計數發生差異,各位夥伙若有想到其他造成差異的原因,請回信告訴我吧!希望可以找出更多造成差異的原因,以便對客戶提出合理的解釋。
   在看了岳儒所提供的資料後,關於分析Access log有幾個疑問,可否請了解的人給予詳細的說明;首先,程式如何區分Session來計數「訪客人次」?若計數是以Cookie的Session- id來判別,那沒有Cookie(Session-id)的紀錄怎麼處理?若將沒有Cookie(Session-id)的紀錄都視為獨立的 Session,那同一Web Browser所發出的第一個請求與後續的請求,會被計數為兩個Session,但以程式計數來紀錄時則視為一個Session。依據Cookie的特性來看,應該將有Cookie(Session-id)的紀錄,視為某個無Cookie(Session-id)紀錄的後續請求,而不應加以Session 計數,否則會與程式計數有落差;而對於不接受Cookie的Web browser,若Web container有採取URL-Rewriting進行Session tracking的替代方式,且程式中也有對URL進行處理的話,那對於Session的計數兩種方式的差異將會十分明顯!我的建議是不要以分析Access log的方式來計數「訪客人次」,因為它可能非常的不精確!
   此外,我也思考了GIP中以程式在DB中紀錄Counter所可能引發的問題,首先,是對系統效能的衝擊。若每次Counter加一就寫回DB的話,在大流量的情況時,會造成DB極為沉重的寫入負擔,再加上每個網頁中要顯示計數值都要存取DB時,也會造成DB極為沉重的查詢負擔。而此作法在Cluster的情況下會更形惡化,因為Cluster中多台主機,在同時寫入和讀取時會因為交易鎖定,而需要彼此同步等待,造成負載平衡的效益大打折扣!若是程式沒有寫好還會引發Lost update的問題!雖然將交易隔離層次(isolation level)設為最低等級,可舒緩此一症狀,但DB大量的存取依然會是系統極大的負荷。關於此一問題的解決方案,我已有初步的構想,但尚未進行實際的驗證。我將會在GIP 2.0的實作中運用,至於詳細運作細節,待我整理好再寄給大家吧! 孫德華 / Walter

2008年3月22日 星期六

Portal 內容轉置的探討

  此可分為兩部份來看,首先是對原內容儲存庫中結構性內容,即有定義內容型態的部份,要定義對應的新系統Content type, 且要加上新系統所需要的考量。而對非結構性內容,亦即未定義內容型態者,則視客戶實際需求來決定,是否要在新系統中定義對應的新內容型態,而所欠缺必要的Content attribute,則要由原內容中以程式(可行的話)或以人工(極耗工)找出來補足。

  還有非結構性內容的Layout,通常與內容交雜在一起的且難以分離,新系統能否正常顯示,也必須注意。此外,Style與內容是否有以CSS分離,也必須留意才行,否則在新系統的顯示會變得很不協調!

  因此,對原結構性內容部份,需要定義新系統的內容型態,而無結構性內容部份,則還需要與客戶溝通,確認是否有某些類型內容需要轉換為結構性或混合性(兩者都兼而有之),最好是全部都不需要轉換,或是另案加以處理,否則會是極大的人力負荷!就算是全部都先不轉換,為過無障礙檢測,所有內容不分結構或非結構者,仍然會需要補足內容中許多被包含的多媒體物件或檔案的Metadata(必要的),因為原系統中這部份極可能是欠缺的,至少非結構性內容很可能沒有。

  綜合以上所述,要進行內容轉換所需進行的處理作業應該就顯而易見了:

  1. 要能區分原系統中結構性與非結構性內容。
  2. 識別出原系統所有內容已有之Metadata, 並建立與新系統Metadata的轉換對應規則。對於新系統為必要而原系統欠缺的Metadata,須提供補足的方法。
  3. 在新系統中定義所需的內容型態,Metadata及資料結構。
  4. 對結構性內容建立顯示時套版所需要的版型。
  5. 對所有內容可以程式自動轉換的部份,撰寫轉換程式並進行轉換,應在此設法補足所欠缺的必要Metadata,以減少人力負荷!
  6. 對無法以程式自動補足的部分,以人力進行補足!
  7. 測試在新系統中對所轉換內容,是否可以正常運作(CRUD及全文檢索)

  以上僅就CMS中的內容轉置來討探,但會以內容儲存庫來存取內容者,並不局限於CMS,若要考量到所有儲存庫內容的轉置時,則勢必要做更深入且廣泛的考量才行。其實對客戶而言,重要的是我們能否提出多個完備且可行的內容轉換方案,並詳列所有重要的決策點,再由使用者討論決定採取那個方案進行,再預估內容轉置時程才有意義。

2008年3月15日 星期六

交通部OA專案Porlet平台調校 - 頁面顯示效能不佳

問題及現況描述:

  現有Apache JetSpeed portlet平台頁面顯示效能不佳。雖然影響效能的因素很多,但其中Portlet的顯示方式,給使用者的感覺乃極重要因素之一。而現行做法是以synchronous server-side aggregated方式來顯示頁面,顯示所需時間為所有區塊內容產生及組合時間的總和,此乃傳統Portal平台效能無法有效提升的重要原因。
  雖然JetSpeed 2.0也有提供asynchronous server-side aggregated方式,顯示所需時間為最大區塊內容產生及組合時間的總和,應可明顯地加速頁面的顯示速度。但可能是對原JetSpeed平台修改所造成的影響,經實際地測試之後發現,並未如預期般地,各區塊內容以非同步方式產生。而且由於整個頁面的顯示時間,會受到最慢區塊內容產生的影響,所以此種方式還是無法令使用者有較好的感受。
  專案初期所使用為Apache JetSpeed 2.0,並未提供client-side aggregated (名為desktop)顯示功能,但Apache JetSpeed 2.1已具備此功能。此方式是將各區塊內容的套版,改在client-side進行作業。而server-side產生各區塊內容的方式也有兩種: PortletAggregator及PageAggregator(預設)。具推測兩者的差異,應在於server-side中各區塊內容產生,是以同步或非同步方式進行,但client-side的套版作業將會有所不同。對使用者感受而言最佳做法,應該是以非同步的方式來產生各區塊內容(Desktop+PortletAggregator)。
  雖然平台後來也轉換為Apache jetSpeed 2.1,但經實測之後發現原平台Desktop功能是可以正確運作的,而修改後的平台卻無法運作。觀察顯示的運作模式後發現,此方式在每次submit時,還是會重新顯示整個頁面,但由於各區塊內容乃以AJAX方式套入版型之中,所以對使用者的感受而言會較可接受。當然,最好的方式是各Portlet區塊的submit,全部都改以AJAX方式處理,如此將可達到最佳顯示性能,但Portlet的開發方式必須配合才可達成此一目的。

解決方案:

  1. 解決修改後的Apache JetSpeed 2.1 portlet平台,無法使用Desktop及非同步區塊內容產生功能的問題。
  2. 改寫用於主頁面所有Portlet,將顯示及submit全部改以非同步背景方式進行;但此作法乃將系統面的問題,由應用面程式來解決的不良方案。
  3. 以Filter欄截所有的請求及回應,將Portlet的顯示及submit,全部改以非同步背景方式進行,但可行性及難度未經實際驗證及評估過。

方案1的初步嘗試:

  比較原平台及修改後平台的全部原始碼,已找出原始碼差異之所在,由於本人並非原修改者,且未經實際運作差異之比較,故短時間內尚無法理解所有修改處的原由,雖然部份修改已可約略瞭解其修改之目的,但未經原修改者或實際運用差異的比較來確認,終究無法完全瞭解修改之目的。經歷此次事件的過程,本人有以下幾點想法:

  1. 對於專案開發過程所做的任何變動,不論是關於應用面或系統面的,都必須精確地紀錄其原始及變更之目的:雖然本案有用SVN(Subversion)來進行版本控制,但卻未對修改前後的JetSpeed 2.0及2.1平台原始碼進行版本控制,以及變動歷程的紀錄,也未對所修改的部份加上詳細的註解說明,如此將會造成將來接手平台維護者及此方案所面臨的窘境。
  2. 系統修改之前應先Refactoring:將要修改的部份隔離,以增加系統原始碼的可讀性。
  3. 切莫因為不瞭解原系統設計架構或求快速達到目的,而變更原系統設計架構:原JetSpeed平台的認證及授權功能,是以標準的JAAS架構來達成。此標準的設計目的即在於,希望應用程式與平台間可以透過標準的方式來進行安全性的整合。此次平台修改卻放棄以此標準做法,而走捷徑來進行認證及授權的整合。

方案1的接續做法:

  1. 先分兩部份一起進行:A.找出造成影響的被修改模組;B.瞭解每個修改的目的。
  2. 針對造成影響的被修改模組進行改造,期使原模組功能及再修改之目的皆可達成。

台北市政府入口網內容轉置的做法

現有情況:

  以RDB及File System做為內容儲存方式,以RDB為主而File System為輔。有General及Adevenced兩種版型,其中General是後來加入較為結構性之版型,但用此種版型的網站並不多,原來的Adevenced版型是以在Template中安插特殊註解符號做為代換之位置,而使用者輸入之內容則直接以HTML形式編輯,再存放為靜態之檔案,顯示所代換引入之項目,除節點靜態檔案內容外,亦包括動態生成之功能表及其他相關內容。存放內容的HTML檔,因為使用者可以任意編輯其內容,故而Layout和Style會與內容以任意方式組合,將難以程式來自動分離內容與格式,只能以人工方式進行分離作業,初期應該可以保持原狀即可,但系統必須能區分新舊內容,以免顯示會有問題!

內容及Metadata轉置處理流程:
  1. 瞭解JCR定義Schema的方式,並先定義資料結構
  2. 瞭解以標準XML組織內容及Metadata的方式
  3. 瞭解現有內容及Metadata的組成結構
  4. 撰寫將Adevenced的內容轉換為JCR滙出入XML格式的程式, 應儘力設法以自動方式補足所需之Metadata
  5. 撰寫將General內容轉換為JCR滙出入XML格式的程式, 應儘力設法以自動方式補足所需之Metadata
  6. 滙入步驟4,5產生的XML至JackRabbit中,先試行少量內容待測試無誤再進行全面性轉置,轉換後應驗證是否能正常顯示及編輯
  7. 最耗費人力的部份,則在於為好幾百個網站進行型版的客製,最好能教導各網站管理人員自行客製,部份執行有問題的網站再加以輔導,可能需要市府政令宣達方式來要求各單位配合!
  8. 另外,對原有內容先不要補足欠缺的Metadata(含研考會要求的),若有單位被要求要檢驗時,再協助該單位進行Metadata的補足,但系統必須能區分無必要Mettadata的內容,以免顯示Metadata會有問題!

ps. 對於所有轉置的內容資料,新系統應該提供能涵蓋原系統資料編輯的功能,否則所轉置的資料將不可再被編輯修改!