关于项目 java版本QQ——飞Q (含服务器和客户端)
下面概要講述一下我在設計完成服務器模塊和設計客戶端后臺中遇到的問題及解決方案。
服務器:
1、服務器使用什么機制,是線程還是進程?
2、數據庫如何設計能使服務器訪問的效率提高?
3、如何處理大量用戶同時訪問服務器?
4、服務器與客戶端之間選擇何種心跳模型?
客戶端:
1、客戶端聊天到底使用什么模式,是C/S模型還是P2P?
2、客戶端之間通信有何種模型?
3、。。。。?
4、。?
這里僅僅列舉了很小一部分問題,但這些問題的解決與否在此項目中至關重要,直接決定做出來的課程設計是否高效,是否能經得起各種測試的考驗,尤其是壓力測試(對于服務器)。
那么下面我簡單講述一下我的解決方案:
1、服務器使用什么機制,是線程還是進程?
服務器中最重要的差不多就是線程活進程的使用,在并發處理大量用戶的請求時,線程或進程發揮著不可替代的作用,在此項目中我選擇了使用線程來完成服務器的設計,線程較進程有如下優點:
1)、它是一種非常"節儉"的多任務操作方式。操作系統啟動一個新的進程必須分配給它獨立的地址空間,建立眾多的數據表來維護它的代碼段、堆棧段和數據段,這是一種"昂貴"的多任務工作方式。而運行于一個進程中的多個線程,它們彼此之間使用相同的地址空間,共享大部分數據,啟動一個線程所花費的空間遠遠小于啟動一個進程所花費的空間,而且,線程間彼此切換所需的時間也遠遠小于進程間切換所需要的時間。當然,在具體的系統上,這個數據可能會有較大的區別;
2)、線程間方便的通信機制,由于同一進程下的線程之間共享數據空間(此處非常重要),所以一個線程的數據可以直接為其它線程所用,這不僅快捷,而且方便;
3)、使多CPU系統更加有效。操作系統會保證當線程數不大于CPU數目時,不同的線程運行于不同的CPU上;
4)、改善程序結構。一個既長又復雜的進程可以考慮分為多個線程,成為幾個獨立或半獨立的運行部分,這樣的程序會利于理解和修改。
鑒于以上四條線程的優點,我最終還是選擇了用線程機制來完成服務器的設計。
2、數據庫如何設計能使服務器訪問的效率提高?
數據庫的設計對于要訪問數據庫的用戶請求非常重要,好的數據庫設計方案往往能使服務器的效率幾十倍甚至上百倍(實際數據測得),反之,差的數據庫模式可能是服務器在應答大量用戶請求時崩潰,或是客戶端超時率增大很多,用戶體驗直接降到低谷,更談何別人使用你的軟件。所以對于數據庫的設計,我把它放到了相當高的地位,其實說實話,后來的優化,數據庫的改善是最提高服務器效率的最有效的方法。
早期的數據設計思路如下:
當用戶申請帳號時,服務器選出能被申請的下一個帳號作為申請的帳號,將此帳號作為唯一標識給用戶創建一個數據庫,即每個人的數據(除了基本信息外)都用一個數據庫來存儲。
如下圖
? ?
 
這種模式看似挺清晰,但這極大的降低了效率,這種設計方法在服務器在接收到用戶請求需要訪問數據庫時,不通的用戶就要進入不通的數據庫,如果此時還需要該用戶的一些基本信息,那么在數據庫切換時耗時很長,在實際測試中用戶申請失敗的概率很大,用戶的感受就不言而喻了,同樣服務器的價值幾乎全部喪失,此種設計方法很失敗。
經過很長時間的思考,我想到了另外一種模型,即把用戶群的基本信息放入到main數據庫各表中,用戶群其他的全部信息表放在users數據庫中。
如下圖:
在實際壓力測試中,尤其是申請好友操作中此更改,顯著提高了效率,比如原來同時申請100個帳號,最多只有28個申請成功,其他的均超時,而此番修改后,申請100個帳號,只需不到兩秒,用戶體驗就顯著提高了。
3、如何處理大量用戶同時訪問服務器?
這是最令人頭疼的事情,作為服務器壓力測試不過關,其他的都免談。服務器是干什么的,當然就是為處理用戶的請求的,請求的人數少的時候你怎么做都行,但大量用戶同時發送請求時,可不是你想怎么做就怎么做了,對于這個問題,我提出了一些解決方案。
1、先保證服務器不崩潰,即保證內存、cpu等正常工作
保證此項不出問題,就得控制好多線程的開辟、啟動、終止的 關系,此服務器用的機制是線程機制,即當服務器接收到用戶的 請求時,服務器會開辟一個子線程,用來處理此請求,處理完請 求就終止線程。但問題出來了,當很多用戶訪問時,比如1000個,10000個甚至更多的時候,服務器會在很短的時間內開辟如此多的線程,請試想一下,服務器能不崩潰嗎?肯定會崩潰,除非你是巨型機,呵呵。。。所以現在要解決這個問題,當我想到這個問題時,我很糾結啊,該怎么辦呢?后來問了問魏老師,他提出的是在線程數量達到一定數量時,讓請求排隊,的確,雖然這樣可能導致排隊的請求超時,但畢竟服務器正常運行是重中之重,所以我根據魏老師的思路稍微修改了一下,從而達到了不讓服務器崩潰的效果。
2、如何使用戶快速得到一些經常訪問的信息
這個看似不大重要的設計點卻對服務器優化起著很重要的作用,比如說用戶的密碼、用戶的ip?和?一些?port?,這些數據經常被用到,如果每次都去硬盤中的數據庫中去讀取的話,這樣浪費在IO上的時間就會增加很多。所以,我提出的解決方案是將常用但占用內存較少的數據預讀到數據庫中,保證在IO上浪費的時間盡可能的少。
 
4、服務器與客戶端之間選擇何種心跳模型?
心跳對很多人來說是一個挺陌生的概念,但實際上心跳在很多地方得到應用,如并行運算工作組還有此次的即時聊天領域,它在這些領域發揮著不可替代的作用,通過心跳可以自動檢測完成很多功能,比如此次項目的監測用戶的狀態改變與“假死”和“真死”等等,同時此模塊也是系統運行中運作最頻繁的一部分,因此處理好此模塊將很的降低服務器的壓力。
當今的心跳檢測模型大約有以下幾種:
1、推模型
 
2、拉模型
 
3、推拉混合式
此模式就是上述兩種模式的有機組合,即正常情況下用推模型,客戶端每隔一段時間便向服務器發送心跳包,告訴服務器客戶端當前的狀態;假如客戶端由于斷電、任務管理器強制關閉導致意外關閉時,客戶端不能再想服務器發送心跳包,但遺憾的是客戶端也無法發送自己下線的心跳報,此時服務器檢測到客戶端三次沒有發過來心跳,于是服務器主動想客戶端發送詢問,來最終判斷客戶端是否在線,此模型充分發揮了推模型的省資源高效率、拉模型準確性高的優勢,所以我最終選擇了此模型。
早期的心跳模型設計和后期的心跳改進不大,改動了接收存儲心跳的位置,即從硬盤轉到了內存,但也大大降低了服務器的壓力,畢竟心跳是服務器中最繁忙的部分,稍微一優化便可以產生很大的性能提升。
客戶端:
1、客戶端聊天到底使用什么模式,是C/S模型還是P2P?
這個問題在我剛開始做的時候和很多人一樣認為,既然是C/S結構,聊天肯定經過服務器的中轉發往另一個客戶端。當少量的用戶在線聊天是此模型的效率不是很差而且在網絡不好時會發揮其優勢,作為一個為公眾做的軟件,服務的群體畢竟不是一個兩個,而是成千上萬,我們都知道即時聊天工具最繁忙的無外乎就是聊天模塊,問題來了,這么多人都通過服務器中轉,服務器能承受的了嗎?呵呵,我還是那句話,服務器得非常非常。。。強大。。。此時我想如何能降低服務器的壓力呢,那答案就是客戶端之間通過P2P的方式進行通信
 
2、客戶端之間通信有何種模型?
這問題就真正涉及到聊天的具體環節了,怎么樣才能做到軟件工程要求模塊的內聚性強、耦合度低呢?這里就要是功能模塊獨立化,這個思想正好用在了聊天的實現上,同時也是受TCP/IP?分層協議的啟發得出的模型。
 
這種模型保證了功能模塊的獨立化,非常清晰,各層之間功能獨立,各自完成各自的工作。自我感覺這種聊天內部模型比較出色。
關于源碼:http://blog.csdn.net/wangchangshuai0010/article/details/7343103
 
 
 
 
總結
以上是生活随笔為你收集整理的关于项目 java版本QQ——飞Q (含服务器和客户端)的全部內容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: 怎么一步步自建CentOS7 Minim
- 下一篇: should not include d
