轉:鏖戰雙十一-阿里直播平臺面臨的技術挑戰(webSocket, 敏感詞過濾等很不錯)

轉自:http://www.infoq.com/cn/articles/alibaba-broadcast-platform-technology-challenges

鏖戰雙十一-阿里直播平臺面臨的技術挑戰

做者 陳康賢 發佈於 2016年1月28日 | 2 討論html

 

前言:一直以來雙十一都是以交易爲重心,今年固然也是如此,可是這並不妨礙萬能的淘寶將雙十一打造的讓用戶更歡樂、體驗更豐富、玩法更多樣、內容更有趣,所以,今年也誕生了以直播爲特點的遊戲雙十一會場,也就是本文所要着筆重點介紹的,即阿里直播平臺在雙十一所面臨的複雜技術挑戰以及技術選型的臺前幕後。前端

大型直播的技術挑戰體如今大流量、高併發場景下,視頻流的處理、分發,播放質量保障,視頻可用性監控,超大直播間實時彈幕及聊天互動,高性能消息通道,內容控制(包括視頻內容自動鑑黃及消息文本過濾),以及系統可用性、穩定性保障等等方面。本文將針對其中的一些技術細節,抽絲剝繭,但願經過些許文字的分析和介紹,能讓你們有所啓發。java

視頻直播

對於直播平臺來講,爲了保障各類網絡環境下可以流暢的觀看視頻,須要將高清的輸入流轉換出多路不一樣清晰度的視頻流,以支持不一樣網絡條件下視頻清晰度的切換,而因爲不一樣的端所支持的協議及封裝格式並不徹底相同,好比無線端的HTML5頁面能夠很好的支持HLS協議,可是對於RTMP這類協議基本無能爲力,而PC端爲了下降延時,須要採用RTMP這一類流媒體協議。所以,爲了支持多終端(PC、Andriod、IOS、HTML5)觀看,須要對輸入流進行編碼及封裝格式的轉換。轉碼完成以後,還須要對視頻流進行分發,畢竟源站的負載能力有限,節點數有限,離大部分用戶的物理距離遠,對視頻這一類十分佔用帶寬資源的場景來講,爲了提升播放質量減小卡頓,須要儘可能減小到用戶的傳輸鏈路。所以,一般的作法就是將視頻流進行切片存儲到分佈式文件系統上,分發到CDN,或者是直接經過CDN進行流的二級轉發,由於CDN離用戶最近,這樣才能保證直播內容對於用戶的低延時,以及用戶的最短路徑訪問。客戶端對延時的要求,以及採用何種協議,決定了視頻是否須要分片,分片的目的在於,經過HTTP協議,用戶不須要下載整個視頻,只須要下載幾個分片,就能夠播放,實際上直播與錄播的技術是相通的,區別在於直播的流沒法預測終結時間,而錄播的視頻流終止時間是已知的。對延時要求沒那麼高的場景來講,客戶端能夠採用HLS協議,畢竟IOS、Andriod、HTML5等無線端應用可以很好的兼容和支持,且經常使用的靜態資源CDN能夠不作相應改造,就能支持,可是HLS協議的一大天生缺陷就是延時較高,視頻內容在切片、分發、客戶端下載的過程當中耗費了很長時間。對於時效性要求很是高的場景,就須要採用RTMP、RTSP一類的實時流媒體協議,來下降延時,而且,爲了下降源站的壓力,須要CDN邊緣節點來作流的轉發,那麼,CDN就必須得支持相應的流媒體協議,也就是一般所說的流媒體CDN。web

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

直播整個鏈路是比較長的,包含有接流、轉碼、切片、分發、客戶端下載、播放等衆多環節,鏈路上任何一個節點有問題,均可能致使視頻不能播放。所以,關鍵節點的監控就十分重要,除此以外,還須要對整個鏈路的可用性進行監控,好比,針對HLS協議來講,可經過監控相應的m3u8索引列表有沒有更新,來判斷視頻直播流是否中斷。固然,如需判斷視頻流中的幀有沒有花屏、有沒有黑屏,就更復雜了,何況,監控節點所訪問的CDN節點與用戶所訪問的CDN節點可能並不在同一地域。當前中國的網絡環境,特別是跨網段的網絡訪問,對於流媒體應用來講,存在較大的不可控因素,客戶端網絡接入環境對視頻的播放有決定性影響。所以,收集終端用戶的播放數據質量數據進行反饋,及時進行視頻清晰度切換,顯得特別重要。這些數據包括客戶端的地域分佈、播放卡頓信息、視頻分片加載時間等等,根據這些信息反饋,能夠較爲全面的評估CDN節點部署是否合理,是否須要新增CDN節點,視頻的轉碼參數對於不一樣機型的兼容性等等,及時進行調整以改善用戶體驗。正則表達式

(點擊放大圖像)redis

 

圖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[1]又被稱做爲反向ajax(Reverse AJAX ),分爲兩種實現方式,一種是長輪詢(long-polling)方式,一種是流(streaming)的形式。在長輪詢的方式下,客戶端與服務端保持HTTP鏈接,服務端會阻塞,直到服務端有信息傳遞或者是HTTP請求超時,客戶端若是收到響應,則會從新創建鏈接,另外一種方式是流的形式,服務器推送數據給客戶端,可是鏈接並不關閉,而是始終保持,直到鏈接超時,超時後客戶端從新創建鏈接,並關閉以前的鏈接。經過這兩種方式,即可借用HTTP協議,來實現服務端與客戶端的即時通信。

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

(點擊放大圖像)

圖6 WebSocket協議[3]

爲什麼說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[4]的開源,經過websocket、Adobe Flash Socket、long-polling、streaming、輪詢等多種機制的自適應切換,幫咱們解決了絕大部分瀏覽器(包括各類內核的webview)的兼容性問題,統一了客戶端以及服務端的編程方式。對於不一樣平臺的消息推送,咱們內部也衍生了一些成熟的技術平臺,封裝了包括消息推送,消息訂閱,序列化與反序列化,鏈接管理,集羣擴展等工做,限於篇幅,這裏就很少說了。

文本內容過濾

雙十一視頻直播的另外一個挑戰在於,如何對彈幕這一類的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帶來的時延,當敏感詞庫有更新時,服務端需將相應的變動信息推送給其餘應用。

分類算法

分類實際上就是按照某種標準來給對象貼標籤,而後再根據標籤進行區分,基於機率統計的貝葉斯分類算法[5]是最多見的分類算法,也是目前垃圾文本識別領域應用最普遍的算法。

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

  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[6](布隆過濾器)的方案。

圖11 Bloom Filter的基本原理[7]

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的基本原理[8]

系統穩定性

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

總結

本篇主要介紹了阿里直播平臺在雙十一所面臨的一些技術挑戰,以及應對的方案和思考過程,從音視頻直播架構,到彈幕和消息投遞,再到消息通道的技術選型、文本過濾的實現機制,大型直播不管是音視頻的可靠性保障、視頻鑑黃,仍是文本消息通過數萬在線用戶放大以後的消息下行,以及對於消息內容自己的過濾,都面臨了很大的挑戰,挑戰不可怕,兵來將擋,水來土掩,迎難而上,纔能有突破和創新。

參考文獻

  1. comet, https://software.intel.com/zh-cn/articles/comet-java-realtime-system-essay
  2. WebSocket, https://tools.ietf.org/html/rfc6455
  3. WebSocket通訊原理
  4. socket.io項目地址: http://socket.io/
  5. 貝葉斯分類, https://en.wikipedia.org/wiki/Naive_Bayes_classifier
  6. Bloom Filter, http://my.oschina.net/kiwivip/blog/133498
  7. 圖片來源, http://my.oschina.net/kiwivip/blog/133498
  8. 圖片來源,http://my.oschina.net/kiwivip/blog/133498

做者簡介

陳康賢,淘寶花名龍隆,淘寶技術部技術專家,著有《大型分佈式網站架構設計與實踐》一書,在分佈式系統架構設計、高併發系統設計、系統穩定性保障等領域積累了較爲豐富的實踐經驗,對新技術有濃厚的興趣 ,交流或簡歷請發送至longlong@taobao.com

相關文章
相關標籤/搜索