国产日韩欧美一区二区三区三州_亚洲少妇熟女av_久久久久亚洲av国产精品_波多野结衣网站一区二区_亚洲欧美色片在线91_国产亚洲精品精品国产优播av_日本一区二区三区波多野结衣 _久久国产av不卡

?

基于Netty的面向移動終端的推送服務設計

2016-01-24 07:39代超鄧中亮
軟件 2015年12期
關鍵詞:計算機應用技術

代超++鄧中亮

摘要:隨著智能手機和平板電腦等移動多媒體終端的普及和4G的加速發(fā)展,移動互聯網近年呈現了迅猛的發(fā)展態(tài)勢?;贏ndroid操作系統(tǒng)的各類APP應用如雨后春筍,影響著人們的生活習慣。面向移動端的推送服務通過分析用戶喜好給用戶推送其感興趣的內容,能大大提升用戶的活躍度和留存率,因此成為了APP應用不可或缺的重要組成部分。然而由于Android官方的消息推送機制C2DM(Cloud to Device Messaging)卻有著覆蓋率偏低的缺陷,APP開發(fā)者需要自己開發(fā)消息推送系統(tǒng)。本文通過研究開源消息推送和即時通信系統(tǒng),分析比較常用的網絡通信協(xié)議和網絡10框架,最終采用Java NIO網絡框架Netty和開源數據序列化工具Protocol Buffers實現了輕量級的面向移動端的推送服務系統(tǒng)。

關鍵詞:計算機應用技術;Netty網絡框架;推送;Protocol Buffers

中圖分類號:TP311.1

文獻標識碼:A

DOI:10.3969/j.issn.1003-6970.2015.12.001

本文著錄格式:代超,鄧中亮.基于Netty的面向移動終端的推送服務設計[J].軟件,2015,36(12):01-04

0 引言

互聯網時代,推送技術在各行各業(yè)得到應用。隨著移動瓦聯網的發(fā)展,很多APP應用都集成了推送服務,如微信、網易新聞等。消息推送主要有兩種實現方式,客戶端定時“拉取”和服務器主動“推送”。“拉取”方式是客戶端按照預設的觸發(fā)條件和時間間隔,不停地向服務器查詢更新,然后發(fā)出拉取請求以獲取最新消息;而“推送”的方式則是在客戶端和服務器之間保持一條連接通道,當服務器有新消息時豐動將消息直接發(fā)送給客戶端,減少交瓦次數,提高了推送效率。以上兩種方式各有利弊,但是為了實現移動終端的低功耗和低流量,通常采用服務器豐動“推送”技術。由于服務器豐動“推送”需要在客戶端和服務器之間保持TCP長連接,當用戶量龐大時,單臺服務器可能要保持上卣萬個TCP連接,這對于網絡服務器的開發(fā)要求很高。傳統(tǒng)的網絡服務器使用BIO(阻塞10)開發(fā),多采用一連接一線程(One thread per connection)的線程模型,即每接受一個連接請求則產牛一個子線程處理該請求,這種模型導致服務器無法承受大量客戶端的并發(fā)連接,而且頻繁的線程上下文切換導致CPU利用效率不高。Netty是一個基于NIO的客戶端/服務器框架,NIO采用反應堆(Reactor)模型,其單線程模型如圖l所示,其中一個Reactor線程聚合一個多路復用器Selector,可以同時注冊、監(jiān)聽和輪詢成千上萬個客戶端連接。Netty可以通過調整參數靈活配置成Reactor單線程、多線程和豐從多線程模型,用少量的線程即可以處理上萬條TCP連接,同時Netty中集成了豐流的編解碼框架和靈活的自定義編解碼器實現,能輕松實現私有的協(xié)議棧,很適合開發(fā)基于TCP長連接的推送服務。

1 傳輸協(xié)議的制定和編解碼實現

網絡服務器主要任務是處理與客戶端之間的數據交互,為了實現高效率可擴展的推送服務,數據傳輸協(xié)議的制定尤為重要。

1.1 數據傳輸協(xié)議的制定

當前能直接用于生產環(huán)境的協(xié)議主要有XMPP、MQTT及部分私有協(xié)議。XMPP是一種基于XML的實時通信協(xié)議,具有很強的擴展性,但是由于XML文本協(xié)議帶來的數據冗余使其不太適合于移動端使用。MQTT是一種輕量級的、基于代理的“發(fā)布/訂閱”模式的消息傳輸協(xié)議,專門為低帶寬、不穩(wěn)定網絡所設計,協(xié)議小巧可擴展性強,比較適合作為移動端的消息協(xié)議,但是其不夠成熟、實現復雜且沒有成熟的Java開源實現。協(xié)議就是原數據和消息協(xié)議數據之間的一組關系映射,可看作是一種序列化機制,本文基于開源數據序列框架Protocol Buffers實現了一個可擴展的私有消息協(xié)議。Protocol Buffers是一個靈活、高效、結構化的數據序列化框架,支持跨語言使用,在擁有.proto文件和知悉POJO對象類型的情況下可以進行POJO對象的編解碼。利用Protocol Buffers的特點設計的具體的數據傳輸協(xié)議如圖2所示,幀末尾是將POJO對象序列化后的二進制數據,由于Protobuf對POJO解碼一般來說需要知悉POJO對象的類型,所以在Protobuf Data之前采用兩個字節(jié)來表示消息對象的類型。TCP是個“流協(xié)議”,TCP協(xié)議層不保證消息的完整性,TCP協(xié)議底層存在粘包和拆包的問題,所以需要應用層協(xié)議來保證消息邊界的正確性,一般可以通過在消息頭中添加表示消息總長度的字段FrameLen來解決。

1.2 協(xié)議編解碼框架實現

由于TCP協(xié)議的粘包/拆包等特點,白行實現該協(xié)議并不簡單,幸運的是Netty提供的眾多編解碼工具可以幫助我們輕松實現該數據傳輸協(xié)議的編解碼。Netty提供了基于責任鏈模式的編解碼及業(yè)務處理框架ChanneIPipeline,同時提供對主流編解碼框架如Protocol Buffers、Marshalling的原生支持。Netty中提供的LengthFieldBasedFrameDecoder/Length-FieldPrepender編解碼器能通過在消息頭添加長度域解決TCP粘包/拆包問題。協(xié)議整體的邏輯框架圖如圖3所示,Netty為了盡可能的提升性能,采用了串行無鎖化設計Cha nneIPipeline,在10線程內部各個Handler依次被調用,避免線程競爭導致的性能下降。在接收消息時LengthFieldBasedFrameDecoder讀取消息長度域,根據長度讀取對應長度的二進制數據并遞交給NameFieldBasedProtobufDecoder進行處理。NameFieldBasedProtobufDecoder先讀取兩個字節(jié)的消息類型名(Message TypeName),通過服務端維護的消息類型名-POJO的Java類型的查找表得到具體的Java類型,通過Protobuf工具類將二進制數據轉化成POJO對象傳遞給MessageHandler進行業(yè)務處理。在發(fā)送消息時,NameFieldPrepender根據發(fā)送的消息類型名將POJO對象轉換成Protobuf二進制數據并在數據幀加上TypeName域后遞交給LengthFieldPrepender, LengthFieldPrepender計算出長度在數據幀前加上后通過網絡發(fā)送。整個推送服務的私有協(xié)議設計簡單,增加消息類型時只需重編譯.proto文件和在服務端添加對應的消息類型名-POJO的Java類型項即可,可擴展性強。

2 服務端設計與實現

推送系統(tǒng)的主要任務是將消息通過TCP長連接發(fā)送到客戶端,根據業(yè)務需求的不同,會有多種不同的推送方式,例如廣播消息(推送給全體用戶),根據標簽(Tag)推送等。同時面向移動端的推送服務還需要處理由于移動無線網絡不穩(wěn)定性帶來的TCP斷連,消息丟失等問題。下文闡述了使用Netty及數據庫存儲實現廣播消息和基于標簽推送,同時采用心跳機制、消息回執(zhí)等方法來保證消息到達率和穩(wěn)定性。

2.1 心跳機制的設計

移動終端連上移動網絡獲得的IP實際上是運營商內網IP,移動終端連接Internet需要通過運營商的GGSN(GateWay GPRS Support Note)模塊進行網絡地址轉化。運營商為了減少網絡NAT映射表的負荷,會清除一段時間內沒有通信的鏈路對應的NAT映射表,造成鏈路中斷。解決該問題的常用方法就是心跳機制,即客戶端或服務端每隔一段時間發(fā)送心跳包激活鏈路。心跳機制同時也能檢測鏈路可用性,幫助客戶端或服務端即時斷開失效鏈路,釋放寶貴的10資源。心跳機制原理主要如圖4所描述,圖中描述的是Ping-Pong型心跳,通常由通信一方定時發(fā)送Ping消息,對方收到Ping后,立即返回Pong消息。如果連續(xù)N次心跳檢測都沒有收到對方的Pong應答消息,則認為鏈路已經發(fā)生邏輯失效,可以關閉該鏈路以節(jié)約資源。Android端可以利用白帶的AlarmManager機制定時發(fā)送Ping消息,客戶端檢測到斷線時可以啟動重連機制;服務端可以利用Netty的空閑檢測機制來完成心跳檢測。Netty中集成的空閑檢測機制ReadTimeoutHandler在時間t內沒有收到任何消息時發(fā)生超時異常,可以利用其檢測t時間內有無收到Ping消息,如果連續(xù)N次發(fā)生超時,則及時關閉鏈路避免產生過多的CLOSE WAIT狀態(tài)占用服務器10資源。

2.2 離線消息推送與消息回執(zhí)

心跳檢測和斷線重連的機制能夠保證客戶端與服務器之間有穩(wěn)定的TCP長連接。Netty采用NIO實現,采用Channel表示一條連接。當客戶端需要使用推送服務時,必須先連接、注冊并登陸到服務器。Android客戶端可以使用隨機生成的用戶名和密碼進行注冊,服務器驗證合法后Android端將用戶名和密碼持久化存儲以備以后登陸使用。Android客戶端將注冊成功的用戶名和密碼發(fā)送給服務端,服務端驗證成功后將該通道Channel及用戶信息封裝成UserSession存入用戶名Username-UserSession表中。推送功能一般都是以服務的形式提供給其他用戶或者其他應用,采用Spring管理Netty可以很方便地對外提供RestFul接口的推送服務。采用Spring管理Netty并提供HTTP調用接口,整個推送服務的流程圖如圖5所示。最常用的推送服務類型為廣播類型,即推送給當前在線或者離線的全體用戶。為了使暫時離線用戶在以后也能收到該條消息,必須采用數據庫存儲離線消息。在數據庫中建立兩張表,message(id.content,type...)、user_message(id.username.message_id,state...)。message表中type表示推送消息類型,如廣播,tag等,user_message中message_id為message表的id,state表示消息狀態(tài),如未讀、已讀、過期等。當服務器通過HTTP收到服務使用者推送消息請求時,會先判斷推送消息的類型并往message表中添加該條消息,然后根據消息類型查找數據庫中相應的用戶集合,例如廣播消息類型會取出所有用戶,基于標簽推送會取出關注該標簽的用戶。遍歷用戶集合如用戶在線則根據Username取出Usersession中的Channel利用其write()方法將消息推送給用戶,如果不在線則往user_message表中添加一條消息記錄。為了確保將離線消息推送給用戶,用戶每次上線后將取出user_message及message表中的未讀消息,如果已經過期則修改state為過期,如果未過期則將消息推送給用戶。由于網絡的不確定性,服務端推送出去的消息可能不能到達用戶端,為此還需要有回執(zhí)確認的機制來保證達到率。即客戶端收到推送消息后,將發(fā)送回執(zhí)ACK消息給服務端,服務端根據ACK中的message_id信息改變user message表中對應消息的state為已讀。有了消息回執(zhí)機制,可以保證消息的到達率,大大提高用戶體驗和留存率。

3 系統(tǒng)測試

3.1 功能測試

系統(tǒng)測試分為功能測試和性能測試。功能性測試需要驗證兩個方面。首先客戶端需要能注冊登錄到服務器并接收到服務器推送的消息,其次客戶端在斷線情況下需要能夠發(fā)起重新連接。為了方便測試與觀察,采用安卓模擬器連接到服務器。模擬器收到的推送結果如圖6所示。為了測試客戶端的斷線重連機制,先斷開服務器端的網絡連接,通過LogCat可以看到客戶端檢測到了斷線并發(fā)起了重連請求,當恢復服務器端網絡連接后,客戶端成功連接上服務器,能夠接收到推送消息。

3.2 性能測試

性能測試用于測試服務端能夠承載多少在線用戶。由于無法使用Android平臺模擬大量的TCP連接,這里在PC上實現了一個客戶端程序來模擬大量的用戶連接到服務器,服務器配置如表1所示,測試網絡結構如圖7所示。

采用三臺PC機連接到服務器,每臺PC最多發(fā)起15000個連接,在服務器接受所有連接以后,分別測試基于標簽的推送(擁有某標簽的用戶占總用戶的l0%)和廣播消息。根據客戶端的消息回執(zhí)機制測試各種情況下發(fā)送到客戶端所需的時間,推送成功率以及服務器負載情況,所得結果如表2所示。

從結果可以看到,在客戶端與服務器在局域網環(huán)境下,推送成功率達到l00%,最大推送延時在12s內,單臺服務器可以完成45k在線用戶的推送服務。

4 結論

本文論述了基于Netty的面向移動端的推送服務設計與實現。目前已完成廣播消息和基于標簽的推送服務,單臺服務器能支撐45k在線用戶。下一步的工作將集中在增加富媒體消息的推送功能,進一步提高單臺服務器的并發(fā)連接數和穩(wěn)定性以及構建服務器集群以支撐百萬級用戶量。

猜你喜歡
計算機應用技術
計算機應用技術對企業(yè)信息化的影響研究
計算機應用技術對企業(yè)信息化的影響
計算機應用技術學科建設實踐與發(fā)展探討
計算機應用技術專業(yè)應用現代信息技術組織教學的工作綜述
計算機應用技術與企業(yè)信息化建設
乐业县| 巧家县| 鱼台县| 洞口县| 江都市| 皋兰县| 泰州市| 石泉县| 金寨县| 乐至县| 山东| 宜都市| 五峰| 翼城县| 上高县| 射洪县| 丽江市| 江达县| 榕江县| 宁远县| 日喀则市| 白朗县| 新丰县| 安阳县| 资源县| 醴陵市| 上饶市| 湘西| 华安县| 永济市| 龙川县| 临猗县| 临澧县| 乳源| 宣城市| 腾冲县| 乌兰察布市| 河北省| 朔州市| 天镇县| 台北县|