整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          Spring Boot 集成 socket.io 后端實現消息實時通信

          基于 socket.io 來說,采用 node 實現更加合適,本文使用兩個后端的開源框架實現,服務端使用 netty-socketio ,客戶端使用socket.io-client。使用 Scheduledexecutorservice 實現消息可配置任務調度。


          socket.io

          socket.io:是一個面向實時 web 應用的 JavaScript 庫。它使得服務器和客戶端之間實時雙向的通信成為可能。他有兩個部分:在瀏覽器中運行的客戶端庫,和一個面向Node.js的服務端庫。兩者有著幾乎一樣的API。像Node.js一樣,它也是事件驅動的.

          Socket.IO 主要使用WebSocket協議。但是如果需要的話,Socket.io可以回退到幾種其它方法,例如Adobe Flash Sockets,JSONP拉取,或是傳統的AJAX拉取,[2]并且在同時提供完全相同的接口。盡管它可以被用作WebSocket的包裝庫,它還是提供了許多其它功能,比如廣播至多個套接字,存儲與不同客戶有關的數據,和異步IO操作。


          項目搭建

          引入依賴包

          Java

          一直以來雙十一都是以交易為重心,2015年當然也是如此,但是這并不妨礙萬能的淘寶將雙十一打造的讓用戶更歡樂、體驗更豐富、玩法更多樣、內容更有趣。因此,2015年誕生了以直播為特色的游戲雙十一會場,也就是本文所要著筆重點介紹的,阿里直播平臺在雙十一所面臨的復雜技術挑戰以及技術選型的臺前幕后。

          大流量、高并發場景下,大型直播的技術挑戰一般體現在如下幾個方面:

          • 視頻流的處理、分發

          • 播放質量保障

          • 視頻可用性監控

          • 超大直播間實時彈幕及聊天互動

          • 高性能消息通道

          • 內容控制,如算法鑒黃、文本過濾

          • 系統可用性、穩定性保障

          本文將針對其中的一些技術細節,抽絲剝繭,希望通過些許文字的分析和介紹,能讓大家有所啟發。

          視頻直播

          對于直播平臺來說,為了保障各種網絡環境下能夠流暢的觀看視頻,需要將高清的輸入流轉換出多路不同清晰度的視頻流,以支持不同網絡條件下視頻清晰度的切換,而由于不同的端所支持的協議及封裝格式并不完全相同,比如無線端的HTML5頁面可以很好的支持HLS協議,但是對于RTMP這類協議基本無能為力,而PC端為了降低延時,需要采用RTMP這一類流媒體協議。

          因此,為了支持多終端(PC、Andriod、IOS、HTML5)觀看,需要對輸入流進行編碼及封裝格式的轉換。轉碼完成之后,還需要對視頻流進行分發,畢竟源站的負載能力有限,節點數有限,離大部分用戶的物理距離遠,對視頻這一類十分占用帶寬資源的場景來說,為了提高播放質量減少卡頓,需要盡量減少到用戶的傳輸鏈路。

          因此,通常的做法就是將視頻流進行切片存儲到分布式文件系統上,分發到CDN,或者是直接通過CDN進行流的二級轉發,因為CDN離用戶最近,這樣才能保證直播內容對于用戶的低延時,以及用戶的最短路徑訪問??蛻舳藢ρ訒r的要求,以及采用何種協議,決定了視頻是否需要分片,分片的目的在于,通過HTTP協議,用戶不需要下載整個視頻,只需要下載幾個分片,就可以播放,實際上直播與錄播的技術是相通的,區別在于直播的流無法預測終結時間,而錄播的視頻流終止時間是已知的。

          對延時要求沒那么高的場景來說,客戶端可以采用HLS協議,畢竟IOS、Andriod、HTML5等無線端應用能夠很好的兼容和支持,且常用的靜態資源CDN可以不做相應改造,就能支持,但是HLS協議的一大天生缺陷就是延時較高,視頻內容在切片、分發、客戶端下載的過程中耗費了很長時間。對于時效性要求非常高的場景,就需要采用RTMP、RTSP一類的實時流媒體協議,來降低延時,并且,為了降低源站的壓力,需要CDN邊緣節點來做流的轉發,那么,CDN就必須得支持相應的流媒體協議,也就是通常所說的流媒體CDN。

          由于直播流由主播上傳,如何控制違法違規內容特別是黃色內容,成了十分棘手的問題。令人欣慰的是,隨著技術的發展,算法對于黃色圖像的識別準確率已經很高,基本達到可以在生產環境應用的程度,因此我們也嘗試在視頻流分發之前,對視頻幀進行提取,并且將圖像交給算法進行識別,當超過預設的閾值時,可進行預警或者關停直播間。經過一段時間的實踐,取得了一定的效果,降低了人力成本,但不可避免的是圖像識別算法時間復雜度高,吞吐率較一般算法低。

          直播整個鏈路是比較長的,包含有接流、轉碼、切片、分發、客戶端下載、播放等眾多環節,鏈路上任何一個節點有問題,都可能導致視頻不能播放。因此,關鍵節點的監控就十分重要,除此之外,還需要對整個鏈路的可用性進行監控,比如,針對HLS協議來說,可通過監控相應的m3u8索引列表有沒有更新,來判斷視頻直播流是否中斷。

          當然,如需判斷視頻流中的幀有沒有花屏、有沒有黑屏,就更復雜了,況且,監控節點所訪問的CDN節點與用戶所訪問的CDN節點可能并不在同一地域。當前中國的網絡環境,特別是跨網段的網絡訪問,對于流媒體應用來說,存在較大的不可控因素,客戶端網絡接入環境對視頻的播放有決定性影響。

          因此,收集終端用戶的播放數據質量數據進行反饋,及時進行視頻清晰度切換, 顯得特別重要。這些數據包括客戶端的地域分布、播放卡頓信息、視頻分片加載時間等等,根據這些信息反饋,可以較為全面的評估CDN節點部署是否合理,是否需要新增CDN節點,視頻的轉碼參數對于不同機型的兼容性等等,及時進行調整以改善用戶體驗。

          圖1 視頻直播架構

          消息/彈幕

          WEB IM應用及彈幕近年來有越來越火的趨勢,是營銷與氣氛活躍的一種非常重要的手段。對于同時在線人數龐大的實時聊天互動、實時直播彈幕這一類場景來說,在保障消息實時性的前提條件下,將會面臨非常高的并發壓力。

          舉個例子來說,假設一個活躍的直播間有10w人同時在線,正在直播一場熱門的游戲賽事,假設每秒鐘每個人說一句話,將會產生10w條消息,也就是10w/s的消息上行QPS,而每條消息又需要廣播給房間里面的每一個人,也就是說消息下行將成10w倍的放大,達到驚人的10w*10w=100億/s的消息下行QPS,而這僅僅是一場直播的QPS,類似的直播可能有多場正在同時進行,對于消息通道來說,無疑將是一個巨大的挑戰。因此,在系統設計的時候,首先要考慮的問題,就是如何降低消息通道的壓力。

          圖2 消息的投遞與消費

          用戶將信息投遞到消息系統之后,系統首先對消息進行一系列的過濾,包括反垃圾、敏感關鍵詞、黑名單等等,對于信息的過濾后面會詳細介紹,此處暫且不表。為了避免系統被瞬間出現的峰值壓垮,可先將消息投遞到消息隊列,削峰填谷,在流量的高峰期積壓消息,給系統留一定裕度,降低因限流丟消息對業務產生的影響。

          而后端始終以固定的頻率處理消息,通過異步機制保障峰值時刻系統的穩定,這是一個典型的生產者—消費者模型。對于消息的消費端,則可采用多線程模型以固定的頻率從消息隊列中消費消息,遍歷對應房間所對應的在線人員列表,將消息通過不同的消息通道投遞出去。多線程增加了系統的吞吐能力,特別是對需要將消息一次性投遞給幾萬上十萬用戶這樣的場景,可以異步使用大集群并行處理,提高系統的吞吐能力。異步使后端的消息投遞可不受前端消息上行峰值流量的干擾,提高系統穩定性。

          除了采用消息隊列異步處理之外,當房間人數太多,或者消息下行壓力太大的情況下,還需要進一步降低消息下行通道的壓力,這就需要采用分桶策略。所謂的分桶策略,實際上就是限制消息的傳播范圍,假設10w人在同一個房間聊天,每人說一句可能瞬間就會排滿整個屏幕,消息在這種情況下基本沒有可讀性。

          為提高信息的可讀性,同時也降低下行壓力,可將每10000人(具體每個桶的容量可以根據實際需求來調整,這里只舉例)放一個桶,用戶發送的消息,只在一個桶或者部分桶可見,用戶按照桶的維度接收消息,這樣一方面前端用戶接收到的消息量會少很多(跟用戶所處的桶的活躍度相關),并且一條消息也不用發送給所有用戶,只發送給一個或者部分桶,以降低消息下行壓力。

          分桶的策略有很多,最簡單粗暴的方式就是根據用戶隨機。首先根據房間的活躍程度,預估房間該分多少個桶,然后將用戶通過hash函數映射到各個桶,隨機策略的好處是實現非常簡單,可以將用戶較為均衡的分配到每個桶,但是會有很多弊端。首先,準確的預估房間的活躍用戶數本身就比較困難,基本靠蒙,這將導致單個桶的用戶數量過大或者偏小,太大就會增加消息鏈路的壓力,而偏小則降低用戶積極性,后期調整分桶數也會很麻煩,需要將全部用戶進行重hash。

          另外從用戶體驗的角度來考慮,在直播過程中,在線用戶數正常情況下會經歷一個逐漸上升達到峰值然后逐漸下降的過程,由于分桶的緣故,在上升的過程中,每個桶的人是比較少的,這必然會影響到彈幕的活躍度,也可能因此導致用戶流失,而在下降的過程中,逐漸會有用戶退出直播,又會導致各個桶不均勻的情況出現:

          圖3 隨機hash分桶

          另一種方案是按需分桶,固定每個桶的大小,當現有的桶都滿了之后,再開辟新的分桶,以控制每個桶的人數,使其不至于太多也不至于太少,這樣就解決了之前可能出現的每個桶人數過少的問題,但是,有個問題將比之前的隨機分桶更為明顯,老的桶中不斷有用戶離開,人將逐漸減少,新開辟的桶將越來越多,如不進行清理的話,最后的結果仍然是分桶不均衡,并且會產生很多空桶,因此,就需要在算法和數據結構上進行調整:

          圖4 按需分桶策略

          通過一個排序list,每次將新增用戶添加到人數最少分桶,這樣可以讓新用戶加入最空閑的桶,以保持均衡,當桶滿的時候,就不再添加新的用戶,但是,當老用戶離開的速度大大高于新用戶進來的速度時,桶還是不均勻的,這時,就需要定期對分桶進行整理,以合并人數少的桶或者回收空桶,而合并的過程中,新用戶又會不斷的加入進來,并且,還需要保證消息發送時能讀到正確的用戶列表,在分布式高并發場景下,為了保證效率,有時候加鎖并不是那么容易,這就有可能出現臟寫與臟讀,桶的整理算法將會非常復雜,有點類似于JVM中的內存回收算法。

          與大數據量高并發場景下的分庫分表策略類似,實際上分桶策略也是一種取舍權衡與妥協,雖解決了原有下行通道壓力過大的問題,也引入了新問題。首先,分桶改變了原本普通用戶對于消息的可見性,一條消息只對于部分桶的用戶可見,而非所有桶的用戶,這樣不同的桶內的用戶看到的消息可能是不同的,另一個問題是,以上的分桶策略有可能導致“熱門桶”和“冷門桶”效應出現,即可能將很多“吐槽達人”分配到同一個桶,導致該桶的氛圍十分活躍,而其他不那么活躍的用戶分配到一起,以致于出現“冰火兩重天”的局面,從而影響產品體驗。

          當然,對于部分特殊的消息,如系統公告內容,或者是部分特殊角色(房間管理員、貴賓、授課的老師等等)所發送的消息,這一類消息需要廣播給所有用戶,這種情況下就需要系統對消息類型做區分,特殊的消息類型另作處理。

          對于消息投遞任務來說,需要知道消息將以什么方式被投遞給誰,這樣就需要動態地維護一個房間的人員列表,用戶上線/下線及時通知系統,以便將用戶添加到房間人員列表或者從房間人員列表中移除。用戶上線十分簡單,只需要在進入房間的時候通知系統即可,但對于下線用戶的處理則有點折騰,為什么這么說呢?用戶退出直播間的方式可能有多種,關閉瀏覽器tab、關閉窗口、關閉電源、按下home鍵將進程切換到后臺等等,有的操作可能可以獲取到事件回調,但也有很多種情況是無法獲取事件通知的,這樣就會導致人員列表只增不減,房間的人越來越多,消息投遞量也隨之增加,白白的浪費了資源。為解決這一問題,就需采用心跳。

          心跳指的是客戶端每隔一段時間向服務端匯報在線狀態,以維持服務端的在線人員列表,當同時在線人數達到一個很大的量級(如百萬級)的時候,每秒心跳的QPS也會變得非常之高,如何保障心跳的高效率、高吞吐就成了岑待解決的問題。首先是通信協議的選擇,是HTTP協議,還是WebSocket,還是TCP協議或者其他。

          HTTP協議的好處在于兼容性及跨終端,所有瀏覽器、Andriod、IOS的WebView,都能很好支持和兼容,在目前移動重于PC的大環境下,顯得尤為重要,但是HTTP協議劣勢也是顯而易見的,作為應用層協議,單次通信所要攜帶的附加信息太多,效率低。WebSocket在移動端的場景下比較合適,但是運用在PC端,需解決眾多老版本瀏覽器的兼容性問題,socket.io的出現則大大簡化了這一原本非常復雜的問題。TCP協議在傳統的客戶端應用上使用較多,但是對于WEB應用來說,存在天然障礙。使用WebSocket和TCP協議的好處顯而易見的,通信效率會比HTTP協議高很多,并且這兩種協議支持雙工通信。

          另一個問題是后端存儲的選擇,該使用怎樣的存儲結構來存儲在線人員列表這樣的數據結構,以支撐這么高的并發讀寫。經過優化并且使用SSD的關系型數據庫相較以往性能已經有了很大的提升,但是對于頻繁變化的大量在線人員列表來說,持久化存儲實際上是沒太大意義的。因此,讀寫性能更高的內存存儲,如memcache,redis,可能是一種更現實的選擇。memcache只能支持簡單的KV對象存儲,數據讀寫需要進行頻繁的序列化和反序列化,但吞吐更高,而redis的好處在于豐富的數據類型,如Lists、Hashs、Sets,省去了序列化和反序列化操作,并且支持更高效的分頁遍歷及count操作:

          圖5 基于redis Sets構建的分桶存儲結構

          消息通道

          HTTP協議請求/響應式特性決定了它擅長處理瀏覽型業務,而對于需要與服務端進行頻繁交互的即時通訊場景來說,則會顯得十分蹩腳。在直播進行的過程中,用戶可以對主播進行吐槽、評論,用戶與用戶之間也可以進行頻繁的交流,需要有像彈幕、WEB IM這樣的工具來支持,這種場景下,消息的實時性尤為重要。

          要實現這類場景,最簡單最粗暴的方式莫過于不斷地輪詢應用服務器,采用拉的方式讀取彈幕以及用戶的聊天內容,消息的實時程度取決于拉的頻率,拉的過快,可能服務器無法承受,拉的頻率過低,則消息的實時性跟不上。輪詢的方式太過于粗暴,需要頻繁的請求服務器,成本較高,并且用戶更新信息的頻率實時變化,很難選擇比較合理的輪詢時間,因為不同時間段用戶發送消息的頻率是有很大差異的,對于拉取的信息,客戶端需要進行篩選和去重。因此,對于WEB端的即時交互應用,需要采用其他解決方案,如comit服務端推送,或者通過websocket來實現類似的場景。

          comet又被稱作為反向ajax(Reverse AJAX ),分為兩種實現方式,一種是長輪詢(long-polling)方式,一種是流(streaming)的形式。在長輪詢的方式下,客戶端與服務端保持HTTP連接,服務端會阻塞,直到服務端有信息傳遞或者是HTTP請求超時,客戶端如果收到響應,則會重新建立連接,另一種方式是流的形式,服務器推送數據給客戶端,但是連接并不關閉,而是始終保持,直到連接超時,超時后客戶端重新建立連接,并關閉之前的連接。通過這兩種方式,便可借用HTTP協議,來實現服務端與客戶端的即時通訊。

          (注:comet, https://software.intel.com/zh-cn/articles/comet-java-realtime-system-essay)

          而WebSocket是IETF所提出的一種新的協議,旨在實現瀏覽器與服務器之間的全雙工(full-duplex)通信,而傳統的HTTP協議僅能夠實現單向的通信,即客戶端發起的到服務端的請求,雖然comet在一定程度上可以模擬雙向通信,但是通信的效率較低,且依賴特定的服務器實現。

          (注:WebSocket, https://tools.ietf.org/html/rfc6455)

          圖6 WebSocket協議

          (注:WebSocket通信原理, http://d.hiphotos.baidu.com/baike/c0%3Dbaike116%2C5%2C5%2C116%2C38/sign=d49cfb709e16fdfacc61cebcd5e6e731/d058ccbf6c81800a6aab8955b23533fa828b471a.jpg)

          為何說comet的通信效率會低于WebSocket呢,因為不管是comet的長輪詢機制還是流機制,都需要在請求超時后發送請求到服務端,并且,長輪詢在服務端響應消息之后,需要重新建立連接,這樣又帶來了額外的開銷。

          圖7 長輪詢與websocket消息發送對比

          我們知道HTTP協議的Request Header中附帶了很多信息,但是這中間包含的很多信息有些場景其實并不是必須的,這樣就浪費了大量的帶寬及網絡傳輸時間。而WebSocket協議使得瀏覽器與服務器只需要一次握手動作,便形成了穩定的通信通道,兩者之間就可以通過frame進行數據傳遞,而消息傳遞所發送的Header是也是很小的,這樣就會帶來效率的提升。

          圖8 websocket與comet性能對比

          通過wireshark抓包可以做一個簡單的測試對比, 假設服務端每秒推送50條消息給用戶,每條消息的長度為10byte,對應不同的用戶規模,采用websocket和comet兩種不同的通信機制,所需要傳遞的字節數如圖8所示,可見,隨著用戶規模及消息量的提升,采用websocket協議進行通信,將對通信效率帶來數量級的提升,詳細的測試過程可參見筆者博客。

          引入WebSocket協議,雖然原則上解決了瀏覽器與服務端實時通信的效率問題,相較comet這種基于HTTP協議的實現方式,能獲得更好的性能,但同時也引入了一些新的問題。擺在首位的便是瀏覽器的兼容性問題,開發WEB應用程序的一個最頭痛的問題就是多版本瀏覽器的兼容,不同瀏覽器產商對于協議的實現有各自的理解,并且,市面上還充斥著大量低版本不支持HTML5協議的瀏覽器,且這部分用戶在中國還占有較大基數,因此在產品研發的過程中不得不予以考慮。

          得益于socket.io的開源,通過websocket、Adobe Flash Socket、long-polling、streaming、輪詢等多種機制的自適應切換,幫我們解決了絕大部分瀏覽器(包括各種內核的webview)的兼容性問題,統一了客戶端以及服務端的編程方式。對于不同平臺的消息推送,我們內部也衍生了一些成熟的技術平臺,封裝了包括消息推送,消息訂閱,序列化與反序列化,連接管理,集群擴展等工作,限于篇幅,這里就不多說了。

          (注:socket.io, 項目地址: http://socket.io/)

          文本內容過濾

          雙十一視頻直播的另一個挑戰在于,如何對彈幕這一類的UGC內容進行過濾。根據以往經驗,對淘寶來說,如果內容不經過濾直接透出,毫無疑問用戶將看到滿屏的廣告,大量的廣告信息將直接導致部分功能無法使用。因此,文本內容過濾,對于我們來說可以說是一門基本功。早期垃圾、廣告內容,或者非法信息的識別,主要依賴于人工,但是當下WEB2.0 DT時代,對于海量的信息進行人工篩查顯然不太現實,社會在發展,技術也在進步,一系列新的文本篩查及過濾技術被運用到了工程領域。

          敏感詞匹配

          通過長時間的累積,大點的網站一般都會有一份敏感詞列表,如果用戶提交的內容包含敏感詞,就需要進行轉義(轉換成***),或者是拒絕發表。那如何判斷文本中是否包含敏感詞,以及如何進行敏感詞過濾呢?如果敏感詞只有很少的幾個,那最簡單的方式當然是通過關鍵詞搜索算法或者是正則表達式進行匹配,但實際情況顯然要復雜的多,需要過濾的關鍵詞可能有成千上萬個,而正則表達式的效率實際上是比較低的,尤其在高并發場景下,對系統的吞吐能力要求非常之高。因此,這種場景下就需要有更高效的算法。目前較為常見的是采用Trie樹算法或者是Trie算法的變種,如空間和時間復雜度都較為均衡的雙數組Trie樹算法來實現。Trie樹也稱為字典樹或者是單詞查找樹,它的好處在于可以利用字符串的公共前綴以減少查詢時間,最大限度的減少字符串比較次數,降低關鍵詞在內存中占用的存儲空間。

          圖9 Trie樹結構

          Trie本質上是一個有限狀態機,根據輸入的數據進行狀態轉移。假設敏感詞包含“美利堅”、“美麗”、“金幣”、“金子”、“帝王”,而輸入的文本是“我的同桌是一個美麗的姑娘”,每讀取一個字符作為輸入,根據這個字符以及它的后續字符對Trie樹進行查找,直到葉子節點,便可以找出文本中包含的違禁詞“美麗”以及這個詞在文本中對應的位置和頻次。

          當然,也可以通過構造多級的Hash Table來簡化Trie樹的實現,相同父節點的字放在同一個Hash Table中,以減少不必要的查詢,對于輸入的文本來說,只需要將字符一個個依次作為輸入對Hash Table進行查找,如包含對應的key,則繼續,直到查詢到最下層葉子節點。

          圖10 多級Hash Table簡化Trie樹的實現

          在系統變得越來越智能的同時,惡意的用戶也變得越來越狡猾,他們可能會在文本當中夾雜一些干擾字符來繞過敏感詞檢查,如“美*利*堅”,這就需要我們對輸入的文本做降噪處理,過濾掉其中的干擾字符,再進行匹配。

          除了算法的實現之外,在集群環境下,還得綜合考慮系統的吞吐以及機器內存的壓力,由于敏感詞過濾需要依賴龐大的敏感詞詞庫,并且,還需將詞庫解析成Trie樹或者多級的Hash Table置于內存當中,以便查找,這勢必將占用大量的內存空間。因此,為了提升內存資源利用率,大部分情況我們會采用RPC模式部署敏感詞過濾服務,但是,在高并發場景下,為了降低因引入敏感詞過濾而帶來的延時,提高系統的吞吐,又需要將敏感詞數據推送到本地內存,通過讀本地內存中的數據,降低因RPC帶來的時延,當敏感詞庫有更新時,服務端需將相應的變更信息推送給其他應用。

          分類算法

          分類實際上就是按照某種標準來給對象貼標簽,然后再根據標簽進行區分,基于概率統計的貝葉斯分類算法是最常見的分類算法,也是目前垃圾文本識別領域應用最廣泛的算法。

          (注:貝葉斯分類, https://en.wikipedia.org/wiki/Naive_Bayes_classifier)

          使用貝葉斯分類算法進行二分類大致可分為這幾個步驟:

          1. 收集大量的垃圾內容和非垃圾內容語料,建立訓練的垃圾語料集和正常內容的語料集。

          2. 對語料文本進行分詞,提取出獨立的字符串,并且統計字符串在文本中出現的頻次。

          3. 每個訓練語料集對應一個hash table,比如垃圾語料集放在hashtable_bad中,而非垃圾語料集放在hashtable_good中,而hashtable中存儲通過分詞提取出的字符串以及對應的詞頻。

          4. 計算hashtable所有的字符串出現的概率,即P=字符串的詞頻/字符串的總數。

          5. 綜合hashtable_good與hashtable_bad,推測當一串文本中包含某個字符串時,該文本為垃圾內容的概率,對應的數學表達式如下: P(A|ki) = Pbad(ki) / [ Pgood(ki) +Pbad(ki) ],其中事件A表示文本為垃圾內容,k1,k2 ……kn 代表提取的關鍵詞,而P(A|ki)則表示在文本中出現關鍵詞ki時,該文本為垃圾內容的概率,Pbad(ki)為ti在hashtable_bad中的值,而Pgood(ki)為ki在hashtable_good中的值。

          6. 建立新的hashtable_probability存儲字符串ki到P(A|ki)的映射。

          行文至此,貝葉斯分類的訓練學習過程就完成了,接下來就可以根據hashtable_probability來計算文本為垃圾內容的可能性了。假設用戶提交的文本內容經過分詞得到n個關鍵詞k1,k2,k3……kn,hashtable_probability中對應的值為 P1,P2……Pn ,P(A|k1,k2,k3……kn) 表示在用戶提交的文本中同時出現關鍵字k1,k2,k3……kn時,該段內容為垃圾文本的概率, P(A|k1,k2,k3……kn) =P1*P2*……Pn 。當P(A|k1,k2,k3……kn)超過預定閾值時,可以判斷該內容為垃圾內容,通過調整閥值,可以控制反垃圾系統對于內容過濾的嚴苛程度。

          當然,以上只是簡單的二分類情況,隨著語料庫的豐富,可以將垃圾語料進行細分,比如詐騙、廣告、黃色、臟話、人身攻擊等等,并且可以根據具體場景進行組合和分級使用,因為不同的使用場景對于文本中出現垃圾文本的容忍程度是不同的,要求越嚴苛的環境,勢必誤殺的概率也會增加,并且在某個場景下,一些語料可能屬于垃圾廣告內容,而在其他的場景下,可能又屬于正常的內容。

          舉例來說,如果在電商網站的評價中發現留有QQ、微信、電話等聯系方式,很有可能就屬于廣告內容,而對于社交應用來說,則屬于正常內容。另外對于一些常見詞,需要進行過濾,以減少對概率計算的干擾,詞實際上也是有權重的,比如出現某些關鍵詞,文檔為垃圾內容的概率顯著增加,可以適當提升此類詞的權重。

          貝葉斯算法的優勢是隨著語料庫的不斷豐富,可應對惡意用戶層出不窮的“新把戲”?;谟柧?,算法模型可以發現已知類型的垃圾內容,但是對于新出現的類型,算法模型也無能為力,因此就需要外界的干預。要么通過人工標注,要么采用其他方式(如文本重復度判斷),來發現新的垃圾文本類型,豐富訓練的語料庫。隨著語料庫的豐富,識別的準確性也會越來越高,道高一尺魔高一丈,最終在與惡意用戶的斗爭過程中,系統的能力也將越來越強大。

          黑名單用戶

          對于頻繁發送惡意信息的用戶,可以采用禁言一段時間或者是永久禁言的的方式進行應對, 這樣就需要維護一份用戶黑名單,當用戶提交UGC內容的時候,先判斷是否在黑名單中,如果已經加入黑名單,則拒絕發表。

          黑名單的最簡單實現方式莫過于采用hash table,借用redis的hash這一類的數據結構進行內存緩存,并且定時進行持久化或是數據備份,防止宕機導致的數據丟失,這種方式實現簡單,查詢效率也比較高,可以滿足大部分場景的使用,但是缺點也十分的明顯,采用hash table的方式隨著黑名單列表的增加,占用內存的空間越來越大,當業務需要對黑名單按一定場景進行區分和隔離的時候,這種情況尤為明顯,并且,黑名單列表越大,hash沖突也將越多,以致于查詢的效率也會降低,。當對黑名單過濾要求不那么精確的時候,可以采用Bloom Filter(布隆過濾器)的方案。

          (注:Bloom Filter, http://my.oschina.net/kiwivip/blog/133498)

          圖11 Bloom Filter的基本原理

          (注:圖片來源, http://my.oschina.net/kiwivip/blog/133498)

          Bloom Filter是一個m位的數組,初始狀態下數組所有位被置0,需要設置黑名單時,通過一系列不同的hash函數,每個hash函數將對應的輸入元素映射到數組中的一位上,通過hash函數得到數組的索引,將數組對應位置1,在查詢的時候,通過相同的hash函數,找到對應的位,如果對應的位不都為1的話,則表示用戶不在黑名單中,那么,當所有的位都為1的情況,就表示用戶一定黑名單中么?也不一定,可能是其他幾次用戶輸入剛好將本次所有位都置1了,如圖11所示,當插入x、y、z這三個元素之后,再來查詢w,會發現w不在集合之中,而如果w經過三個hash函數計算所得索引處的位全是1,那么Bloom Filter就會告訴你,w在集合之中,實際上這里是誤報,w并不在集合之中,這就是所謂誤報。從概率上來說,誤報的幾率很低,在系統可接受范圍內,如需要100%精確判斷,則Bloom Filter就不太合適。

          基本的Bloom Filter是不支持刪除操作的,Counting Bloom Filter的出現解決了這個問題,它將標準Bloom Filter位數組的每一位擴展為一個小的計數器(Counter),在插入元素時給對應的k(k為哈希函數個數)個Counter的值分別加1,刪除元素時給對應的k個Counter的值分別減1,Counting Bloom Filter通過多占用幾倍存儲空間的代價,給Bloom Filter增加了刪除操作,但是相比hash table而言,存儲效率還是提升了很多。

          圖12 Counting Bloom Filter的基本原理

          (注:圖片來源, http://my.oschina.net/kiwivip/blog/133498)

          系統穩定性

          對于每年的雙十一來說,如何在大流量高并發場景下,保障系統穩定提供服務不宕機,已經是一個經久不衰的話題,也是每年對于技術人員的一次徹底的檢閱。從大促開始之前的性能優化、依賴梳理、峰值評估,到系統壓力測試,新機器采購上線,再到流控閥值的評估、降級開關配置,再到監控數據采集、容災應急預案、全鏈路壓測、演習,再到實時、離線數據分析等等,關于這些的介紹,相信網上相關文章都已汗牛充棟,此處就不再贅述。

          總結

          本篇主要介紹了阿里直播平臺在雙十一所面臨的一些技術挑戰,以及應對的方案和思考過程,從音視頻直播架構,到彈幕和消息投遞,再到消息通道的技術選型、文本過濾的實現機制,大型直播無論是音視頻的可靠性保障、視頻鑒黃,還是文本消息經過數萬在線用戶放大之后的消息下行,以及對于消息內容本身的過濾,都面臨了很大的挑戰。

          挑戰不可怕,兵來將擋,水來土掩,迎難而上,才能有突破和創新。

          作者介紹

          陳康賢,淘寶花名龍隆,淘寶技術部技術專家,著有《大型分布式網站架構設計與實踐》一書,在分布式系統架構設計、高并發系統設計、系統穩定性保障等領域積累了較為豐富的實踐經驗,對新技術有濃厚的興趣 。

          想和作者交流或共事嗎?

          馬上加小Q微信(ID: infoqzone)

          勾搭龍隆!

          本文系InfoQ原創首發,未經授權謝絕轉載。同時,也歡迎更多企業、組織與InfoQ展開內容合作,更歡迎個人原創投稿。請加小Q微信:infoqzone,并備注「合作/投稿+名字」。

          uperSocket 是一個輕量級的可擴展的 Socket 開發框架,可用來構建一個服務器端 Socket 程序,而無需了解如何使用 Socket,如何維護Socket連接,Socket是如何工作的。該項目使用純 C# 開發,易于擴展和集成到已有的項目。只要你的已有系統是使用.NET開發的,你都能夠使用 SuperSocket來輕易的開發出你需要的Socket應用程序來集成到你的現有系統之中。

          SuperSocket具有如下特點:

          • 簡單易用,只需要幾個類就能創建出健壯的Socket服務器端程序
          • 性能優良, 穩定可靠
          • 支持各種協議, 內置的協議解析工具讓你把實現通信協議這種復雜的工作變得很簡單
          • 自動支持SSL/TLS傳輸層加密
          • 強大,靈活而且可擴展的配置讓你開發Socket服務器省時省力
          • 支持多個socket服務器實例運行, 而且支持多個服務器實例的隔離
          • SuperSocket能以控制臺或者Windows服務形式運行。一個腳本就能將SuperSocket安裝成服務
          • 靈活的日志策略能夠記錄大部分socket活動
          • 支持UDP
          • 支持IPv6
          • 支持Windows Azure
          • 支持Linux/Unix操作系統(通過Mono 2.10或以上版本)
          • 內置可直接使用的Flash/Silverlight Socket策略服務器

          SuperSocket的系統架構圖

          項目地址

          https://github.com/kerryjiang/SuperSocket

          官網

          http://www.supersocket.net/


          主站蜘蛛池模板: 精品国产不卡一区二区三区| 日本高清天码一区在线播放| 动漫精品一区二区三区3d| 久久se精品一区精品二区国产| 国精产品一区一区三区免费视频| 欧美成人aaa片一区国产精品 | 国产一区在线视频观看| 国产一区二区三区在线2021 | 国产激情视频一区二区三区| 国产在线一区二区杨幂| 韩国一区二区视频| 亚洲日韩精品无码一区二区三区| 免费观看日本污污ww网站一区| 99久久精品午夜一区二区| 国产精品高清一区二区三区| 一区二区三区日本视频| 国产福利一区二区| 无码中文人妻在线一区二区三区| 人妻激情偷乱视频一区二区三区 | 精品无码中出一区二区| 中文字幕一区日韩精品| 国产经典一区二区三区蜜芽| 久久高清一区二区三区| 日韩人妻无码一区二区三区| 一区二区三区电影在线观看| 婷婷国产成人精品一区二| 免费一区二区三区四区五区| 韩国一区二区三区视频| 亚洲精品精华液一区二区| 亚洲日韩一区精品射精| 亚洲午夜精品一区二区麻豆| 伊人久久精品无码麻豆一区| 精品无码成人片一区二区98| 精品少妇ay一区二区三区 | 久久精品无码一区二区日韩AV| 国产婷婷一区二区三区| 免费无码一区二区三区蜜桃| 嫩B人妻精品一区二区三区| 无码人妻少妇色欲AV一区二区| 亚洲成在人天堂一区二区| 日韩人妻一区二区三区免费|