?
做一個好的社區(qū)論壇一直是我的理想,BBS-CS從1.0到現(xiàn)在的5.0用了2年時間,5.0在技術上、性能上都已經(jīng)基本穩(wěn)定,屆此想對BBS-CS的開發(fā)思想、技術做一個說明。
在2000年的時候,我的個人網(wǎng)站“愛情工作室”就是使用我自己的寫的論壇,當時是用PHP,功能上比較簡單,主要是為了網(wǎng)站使用,后來我想把社區(qū)論壇單獨拿出來,并且愛情工作室網(wǎng)站也只剩下了社區(qū)這一部分,所以就開始用PHP按照網(wǎng)易社區(qū)結構寫了BBS-CS PHP 1.0的版本,后來這個版本一直沒有更新,但JSP版BBS-CS 1.0到3.0的數(shù)據(jù)結構都是從PHP版本發(fā)展來的,2000年底我開始用JAVA,2001年就寫了BBS-CS1.0,后來出了2.0,1.0、2.0的安裝都不是很方便,并且SQL都是在JSP中,結構不好,2002年我寫了BBS-CS3.0,此時數(shù)據(jù)庫操作已經(jīng)用JavaBean來封裝,但是3.0的性能非常不好,2003年初我寫了4.0,4.0的結構已經(jīng)發(fā)生了完全的變化,主要是適應多種數(shù)據(jù)庫和數(shù)據(jù)庫訪問均衡處理,性能大大增強,并且BBS-CS定名為“天乙社區(qū)”,今年下半年我寫了5.0,5.0采用了Struts的框架,國際化內核,同時支持集群運行,全文檢索等等。
有人可能會拿BBS-CS和Jive來比較,覺得BBS-CS是小兒科,但我想BBS-CS的設計模式雖然沒有Jive那么復雜,但是在國際化、實用性、性能等方面并不差。
一、數(shù)據(jù)庫設計
BBS-CS從4.0開始,數(shù)據(jù)庫結構發(fā)生了根本的變化,主要是對數(shù)據(jù)表作了負載均衡的處理,即一個功能不是使用一張表,而是使用多張同樣結構的表,比如存放帖子的表有20張,這樣做的目的是為了將數(shù)據(jù)庫的查詢壓力分散到不同表中,其實道理很簡單,如果一張表中存放100萬條記錄,和100張表,每個表存放1萬條記錄,查詢效率是完全不一樣的。具體程序中,比如一個版區(qū)的帖子往那個表中插,是由算法來實現(xiàn)的,算法會保證某個版區(qū)的帖子只會往某一個表中插入。
二、分頁處理
BBS-CS4.0和5.0都是支持多數(shù)據(jù)庫的,現(xiàn)在支持的數(shù)據(jù)庫有Mysql、Oracle和SQL Server,在分頁處理上確實要花一些功夫,以前我看過很多關于分頁的技術資料,處理分頁的方法主要是有幾個:1、用JDBC的本身特性,將數(shù)據(jù)全部取出,然后根據(jù)頁碼,每頁記錄數(shù),對查詢出的數(shù)據(jù)集的數(shù)據(jù)滾動,這個方法比較簡單、通用,但是性能極差,如果一個百萬級的數(shù)據(jù)表,將耗費巨大的系統(tǒng)資源,甚至宕機;2、和第一種比較類似,但不是查出所有數(shù)據(jù),只查出數(shù)據(jù)的主鍵,對主鍵滾動,然后根據(jù)主鍵再次查找相對應的數(shù)據(jù),產生集合,這種方法也是EJB中實體Bean查詢數(shù)據(jù)的方法,但依然存在性能問題,因為數(shù)據(jù)過多的時候主鍵數(shù)據(jù)集也很大,而來用主鍵插找數(shù)據(jù)的是后又進行了多次數(shù)據(jù)庫的執(zhí)行操作,性能降低。在多種分頁方法比較之后,BBS-CS還是決定采用數(shù)據(jù)自身特有的SQL語句來進行分頁,比如Mysql使用limit,Oracle使用rownum,SQL Server使用Top,分頁類是一個抽象類,每種數(shù)據(jù)庫的分頁實現(xiàn)方法都去繼承這個抽象類,然后用一個工廠方法根據(jù)系統(tǒng)配置文件來產生分頁類的實例,采用這樣的分頁方法,能都達到最佳的分頁查詢效率。
三、系統(tǒng)配置文件
BBS-CS5.0的系統(tǒng)配置文件用了一個XML文件,在4.0的時候,系統(tǒng)的配置文件是采用properties文件來解決,后來我覺得properties的文件還是有很大的局限性,比如,不方便進行有數(shù)據(jù)庫結構的數(shù)據(jù)進行配置,后來覺得XML文件是一個絕佳的方案,難怪現(xiàn)在很多產品的配置文件都是XML的:),對于XML文件的解析,BBS-CS采用了jdom,jdom就是java+dom(詳細資料http://www.jdom.org),一個很方便的處理XML的軟件包,在BBS-CS種對jdom的運用也不復雜,主要是用來解析bbscs.xml這個配置文件。系統(tǒng)解析bbscs.xml文件后,將這些系統(tǒng)信息保存在靜態(tài)變量中,以供系統(tǒng)其他程序隨時調用。
四、國際化與資源文件
JAVA本身就是國際化的內部采用了Unicode的編碼格式,而Struts的框架,更方便了國際化的應用,Struts會根據(jù)瀏覽器的Locale,自動調取相應的properties資源文件,在BBS-CS就是定義的app.peoperties文件,BBS-CS只定義了中文的資源包,即app_zh_CN.properties文件,當然只要將這個文件翻譯成日文、韓文等等其他國家文字,即可實現(xiàn)BBS-CS多語言瀏覽。當然只有瀏覽多語言是不行,數(shù)據(jù)的保存也必須是通用的格式,BBS-CS采用了UTF-8的編碼格式的保存數(shù)據(jù),以解決多語言的問題,關于Unicode、UTF-8編碼格式的資料、原理大家可以在網(wǎng)上查找資料,我在這里不多做講解了。
五、編碼問題
在(四)中講了國際化問題,但是如果不作處理,對中文顯示處理都會有問題,要對app_zh_CN.propertie進行native2ascii的轉換,這個命令是在jdk/bin下的,之后我們要做一個Servlet的過濾器,對所有的request對象進行編碼的轉換,com.laoer.bbscs.servlet.EncodingFilter就是BBS-CS的過濾器,它對request的編碼格式進行了處理,定義為了UTF-8的編碼格式。以前網(wǎng)上在看到過的一些文章上說,采用Servlet過濾器會有性能的下降,在我使用的感覺上來說,問題倒不是很大。
六、集群與Session處理
BBS-CS5.0設計的時候考慮到了集群的應用,因為隨著系統(tǒng)訪問量和數(shù)據(jù)的不斷增長,單臺服務器是很難支撐的,所以要求系統(tǒng)能夠用多臺服務器來運行,跨服務器的Session就是一個很大的問題,大家都知道Session是生存與一個應用中的,跨應用,Session必然不能共享,現(xiàn)在JSP容器,包括Weblogic、Resin、Tomcat都可以進行集群應用,但是配制起來可能比較復雜,所以BBS-CS實現(xiàn)了自己的集群運用方案。實現(xiàn)的原理比較簡單,主要是涉及了網(wǎng)絡編程,在JAVA中,對象只要implements了java.io.Serializable這個接口,即可實現(xiàn)串行化,便可以在網(wǎng)絡中傳輸,BBS-CS就是把需要在網(wǎng)絡中傳輸?shù)腟ession對象進行串行化,在多個服務器之間進行通訊,以達到服務器之間的Session同步,同時對于幾臺服務器的訪問是負載均衡的。
Session實現(xiàn),BBS-CS在單服務器配制下是采用了應用的Session,而在機群方式下,是建立了自己的Session列表,Session是一個靜態(tài)的HashTable,每個用戶在登陸的時候會產生一個隨機的sid,這個sid就是HashTable的key,而value則是一個HasMap,保存需要的對象。系統(tǒng)在運行期間會根據(jù)配置文件的Session超時時間定時對超時的Session進行清理。
七、靜態(tài)變量與線程運用
為了減少對數(shù)據(jù)庫的訪問,系統(tǒng)很多地方使用了靜態(tài)變量來儲存數(shù)據(jù),比如,版區(qū)列表和信息是系統(tǒng)需要頻繁訪問的,如果每次都從數(shù)據(jù)庫中讀取,消耗是很大的,BBS-CS采用的方法是,一次性將數(shù)據(jù)庫讀出,放在一個靜態(tài)的列表里(HashTable),以后再訪問則從靜態(tài)列表中取,而不是從數(shù)據(jù)庫中取,如果版區(qū)信息發(fā)生變化,只要刷新這個靜態(tài)變量就行了。
通常在B/S結構下,系統(tǒng)的定時操作是比較困難的,因為B/S結構的軟件是瀏覽器事件驅動的模型,而不是服務器事件驅動,在Unix/Linux下,通常是寫一個腳本,然后用Crontab來跑,在win下可能就要用VB/VC/Delphi來寫一個定時程序了。BBS-CS必須要做到跨品臺和通用性,而線程和Sevlet提供很好的方法,一個web應用,可以在啟動的時候按順序的執(zhí)行Servlet程序(在web.xml文件中定義),在Servlet中就可以啟動一個線程,這個線程定時執(zhí)行、休眠,便可以達到定時運行程序的目的,在BBS-CS中,清除超時Session、游客等等都是采用了線程定時執(zhí)行的方式。