Socket通信的原理還是比較簡單的, 它大致分為以下幾個步驟。 服務(wù)器端的步驟如下。 (1)建立服務(wù)器端的Socket,開始偵聽整個網(wǎng)絡(luò)中的連接請求。 (2)當(dāng)檢測到來自客戶端的連接請求時,向客戶端發(fā)送收到連接請求的信息,并建立與客戶端之間的...
成都創(chuàng)新互聯(lián)專注為客戶提供全方位的互聯(lián)網(wǎng)綜合服務(wù),包含不限于做網(wǎng)站、網(wǎng)站設(shè)計、那曲網(wǎng)絡(luò)推廣、重慶小程序開發(fā)公司、那曲網(wǎng)絡(luò)營銷、那曲企業(yè)策劃、那曲品牌公關(guān)、搜索引擎seo、人物專訪、企業(yè)宣傳片、企業(yè)代運營等,從售前售中售后,我們都將竭誠為您服務(wù),您的肯定,是我們最大的嘉獎;成都創(chuàng)新互聯(lián)為所有大學(xué)生創(chuàng)業(yè)者提供那曲建站搭建服務(wù),24小時服務(wù)熱線:028-86922220,官方網(wǎng)址:www.cdcxhl.com
目前websocket技術(shù)已經(jīng)很成熟,選型Go語言,當(dāng)然是為了節(jié)省成本以及它強大的高并發(fā)性能。我使用的是第三方開源的websocket庫即gorilla/websocket。
由于我們線上推送的量不小,推送后端需要部署多節(jié)點保持高可用,所以需要自己做集群,具體架構(gòu)方案如圖:
Auth Service:鑒權(quán)服務(wù),根據(jù)Token驗證用戶權(quán)限。
Collect Service:消息采集服務(wù),負責(zé)收集業(yè)務(wù)系統(tǒng)消息,存入MongoDB后,發(fā)送給消息分發(fā)服務(wù)。
Dispatch Service:消息分發(fā)服務(wù),根據(jù)路由規(guī)則分發(fā)至對應(yīng)消息推送服務(wù)節(jié)點上。
Push Service:消息推送服務(wù),通過websocket將消息推送給用戶。
集群推送的關(guān)鍵點在于,web端與服務(wù)端建立長連接之后,具體跟哪個推送節(jié)點保持長連接的,如果我們能夠找到對應(yīng)的連接節(jié)點,那么我們就可以將消息推送出去。下面講解一下集群的大致流程:
1. web端用戶登錄之后,帶上token與后端推送服務(wù)(Push Service)保持長連接。
2. 推送服務(wù)收到連接請求之后,攜帶token去鑒權(quán)服務(wù)(Auth Service)驗證此token權(quán)限,并返回用戶ID。
3. 把返回的用戶ID與長連接存入本地緩存,保持用戶ID與長連接綁定關(guān)系。
4. 再將用戶ID與本推送節(jié)點IP存入redis,建立用戶(即長連接)與節(jié)點綁定關(guān)系,并設(shè)置失效時間。
5. 采集服務(wù)(Collect Service)收集業(yè)務(wù)消息,首先存入mongodb,然后將消息透傳給分發(fā)服務(wù)(Dispatch Service)。
6. 分發(fā)服務(wù)收到消息之后,根據(jù)消息體中的用戶ID,從redis中獲取對應(yīng)的推送服務(wù)節(jié)點IP,然后轉(zhuǎn)發(fā)給對應(yīng)的推送節(jié)點。
7. 推送服務(wù)節(jié)點收到消息之后,根據(jù)用戶ID,從本地緩存中取出對應(yīng)的長連接,將消息推送給客戶端。
其他注意事項:
1. 介紹
最近在研究一些消息中間件,常用的MQ如RabbitMQ,ActiveMQ,Kafka等。NSQ是一個基于Go語言的分布式實時消息平臺,它基于MIT開源協(xié)議發(fā)布,由bitly公司開源出來的一款簡單易用的消息中間件。
官方和第三方還為NSQ開發(fā)了眾多客戶端功能庫,如官方提供的基于HTTP的nsqd、Go客戶端go-nsq、Python客戶端pynsq、基于Node.js的JavaScript客戶端nsqjs、異步C客戶端libnsq、Java客戶端nsq-java以及基于各種語言的眾多第三方客戶端功能庫。
1.1 Features
1). Distributed
NSQ提供了分布式的,去中心化,且沒有單點故障的拓撲結(jié)構(gòu),穩(wěn)定的消息傳輸發(fā)布保障,能夠具有高容錯和HA(高可用)特性。
2). Scalable易于擴展
NSQ支持水平擴展,沒有中心化的brokers。內(nèi)置的發(fā)現(xiàn)服務(wù)簡化了在集群中增加節(jié)點。同時支持pub-sub和load-balanced 的消息分發(fā)。
3). Ops Friendly
NSQ非常容易配置和部署,生來就綁定了一個管理界面。二進制包沒有運行時依賴。官方有Docker image。
4.Integrated高度集成
官方的 Go 和 Python庫都有提供。而且為大多數(shù)語言提供了庫。
1.2 組件
1.3 拓撲結(jié)構(gòu)
NSQ推薦通過他們相應(yīng)的nsqd實例使用協(xié)同定位發(fā)布者,這意味著即使面對網(wǎng)絡(luò)分區(qū),消息也會被保存在本地,直到它們被一個消費者讀取。更重要的是,發(fā)布者不必去發(fā)現(xiàn)其他的nsqd節(jié)點,他們總是可以向本地實例發(fā)布消息。
NSQ
首先,一個發(fā)布者向它的本地nsqd發(fā)送消息,要做到這點,首先要先打開一個連接,然后發(fā)送一個包含topic和消息主體的發(fā)布命令,在這種情況下,我們將消息發(fā)布到事件topic上以分散到我們不同的worker中。
事件topic會復(fù)制這些消息并且在每一個連接topic的channel上進行排隊,在我們的案例中,有三個channel,它們其中之一作為檔案channel。消費者會獲取這些消息并且上傳到S3。
nsqd
每個channel的消息都會進行排隊,直到一個worker把他們消費,如果此隊列超出了內(nèi)存限制,消息將會被寫入到磁盤中。Nsqd節(jié)點首先會向nsqlookup廣播他們的位置信息,一旦它們注冊成功,worker將會從nsqlookup服務(wù)器節(jié)點上發(fā)現(xiàn)所有包含事件topic的nsqd節(jié)點。
nsqlookupd
2. Internals
2.1 消息傳遞擔(dān)保
1)客戶表示已經(jīng)準(zhǔn)備好接收消息
2)NSQ 發(fā)送一條消息,并暫時將數(shù)據(jù)存儲在本地(在 re-queue 或 timeout)
3)客戶端回復(fù) FIN(結(jié)束)或 REQ(重新排隊)分別指示成功或失敗。如果客戶端沒有回復(fù), NSQ 會在設(shè)定的時間超時,自動重新排隊消息
這確保了消息丟失唯一可能的情況是不正常結(jié)束 nsqd 進程。在這種情況下,這是在內(nèi)存中的任何信息(或任何緩沖未刷新到磁盤)都將丟失。
如何防止消息丟失是最重要的,即使是這個意外情況可以得到緩解。一種解決方案是構(gòu)成冗余 nsqd對(在不同的主機上)接收消息的相同部分的副本。因為你實現(xiàn)的消費者是冪等的,以兩倍時間處理這些消息不會對下游造成影響,并使得系統(tǒng)能夠承受任何單一節(jié)點故障而不會丟失信息。
2.2 簡化配置和管理
單個 nsqd 實例被設(shè)計成可以同時處理多個數(shù)據(jù)流。流被稱為“話題”和話題有 1 個或多個“通道”。每個通道都接收到一個話題中所有消息的拷貝。在實踐中,一個通道映射到下行服務(wù)消費一個話題。
在更底的層面,每個 nsqd 有一個與 nsqlookupd 的長期 TCP 連接,定期推動其狀態(tài)。這個數(shù)據(jù)被 nsqlookupd 用于給消費者通知 nsqd 地址。對于消費者來說,一個暴露的 HTTP /lookup 接口用于輪詢。為話題引入一個新的消費者,只需啟動一個配置了 nsqlookup 實例地址的 NSQ 客戶端。無需為添加任何新的消費者或生產(chǎn)者更改配置,大大降低了開銷和復(fù)雜性。
2.3 消除單點故障
NSQ被設(shè)計以分布的方式被使用。nsqd 客戶端(通過 TCP )連接到指定話題的所有生產(chǎn)者實例。沒有中間人,沒有消息代理,也沒有單點故障。
這種拓撲結(jié)構(gòu)消除單鏈,聚合,反饋。相反,你的消費者直接訪問所有生產(chǎn)者。從技術(shù)上講,哪個客戶端連接到哪個 NSQ 不重要,只要有足夠的消費者連接到所有生產(chǎn)者,以滿足大量的消息,保證所有東西最終將被處理。對于 nsqlookupd,高可用性是通過運行多個實例來實現(xiàn)。他們不直接相互通信和數(shù)據(jù)被認為是最終一致。消費者輪詢所有的配置的 nsqlookupd 實例和合并 response。失敗的,無法訪問的,或以其他方式故障的節(jié)點不會讓系統(tǒng)陷于停頓。
2.4 效率
對于數(shù)據(jù)的協(xié)議,通過推送數(shù)據(jù)到客戶端最大限度地提高性能和吞吐量的,而不是等待客戶端拉數(shù)據(jù)。這個概念,稱之為 RDY 狀態(tài),基本上是客戶端流量控制的一種形式。
efficiency
2.5 心跳和超時
組合應(yīng)用級別的心跳和 RDY 狀態(tài),避免頭阻塞現(xiàn)象,也可能使心跳無用(即,如果消費者是在后面的處理消息流的接收緩沖區(qū)中,操作系統(tǒng)將被填滿,堵心跳)為了保證進度,所有的網(wǎng)絡(luò) IO 時間上限勢必與配置的心跳間隔相關(guān)聯(lián)。這意味著,你可以從字面上拔掉之間的網(wǎng)絡(luò)連接 nsqd 和消費者,它會檢測并正確處理錯誤。當(dāng)檢測到一個致命錯誤,客戶端連接被強制關(guān)閉。在傳輸中的消息會超時而重新排隊等待傳遞到另一個消費者。最后,錯誤會被記錄并累計到各種內(nèi)部指標(biāo)。
2.6 分布式
因為NSQ沒有在守護程序之間共享信息,所以它從一開始就是為了分布式操作而生。個別的機器可以隨便宕機隨便啟動而不會影響到系統(tǒng)的其余部分,消息發(fā)布者可以在本地發(fā)布,即使面對網(wǎng)絡(luò)分區(qū)。
這種“分布式優(yōu)先”的設(shè)計理念意味著NSQ基本上可以永遠不斷地擴展,需要更高的吞吐量?那就添加更多的nsqd吧。唯一的共享狀態(tài)就是保存在lookup節(jié)點上,甚至它們不需要全局視圖,配置某些nsqd注冊到某些lookup節(jié)點上這是很簡單的配置,唯一關(guān)鍵的地方就是消費者可以通過lookup節(jié)點獲取所有完整的節(jié)點集。清晰的故障事件——NSQ在組件內(nèi)建立了一套明確關(guān)于可能導(dǎo)致故障的的故障權(quán)衡機制,這對消息傳遞和恢復(fù)都有意義。雖然它們可能不像Kafka系統(tǒng)那樣提供嚴格的保證級別,但NSQ簡單的操作使故障情況非常明顯。
2.7 no replication
不像其他的隊列組件,NSQ并沒有提供任何形式的復(fù)制和集群,也正是這點讓它能夠如此簡單地運行,但它確實對于一些高保證性高可靠性的消息發(fā)布沒有足夠的保證。我們可以通過降低文件同步的時間來部分避免,只需通過一個標(biāo)志配置,通過EBS支持我們的隊列。但是這樣仍然存在一個消息被發(fā)布后馬上死亡,丟失了有效的寫入的情況。
2.8 沒有嚴格的順序
雖然Kafka由一個有序的日志構(gòu)成,但NSQ不是。消息可以在任何時間以任何順序進入隊列。在我們使用的案例中,這通常沒有關(guān)系,因為所有的數(shù)據(jù)都被加上了時間戳,但它并不適合需要嚴格順序的情況。
2.9 無數(shù)據(jù)重復(fù)刪除功能
NSQ對于超時系統(tǒng),它使用了心跳檢測機制去測試消費者是否存活還是死亡。很多原因會導(dǎo)致我們的consumer無法完成心跳檢測,所以在consumer中必須有一個單獨的步驟確保冪等性。
3. 實踐安裝過程
本文將nsq集群具體的安裝過程略去,大家可以自行參考官網(wǎng),比較簡單。這部分介紹下筆者實驗的拓撲,以及nsqadmin的相關(guān)信息。
3.1 拓撲結(jié)構(gòu)
topology
實驗采用3臺NSQD服務(wù),2臺LOOKUPD服務(wù)。
采用官方推薦的拓撲,消息發(fā)布的服務(wù)和NSQD在一臺主機。一共5臺機器。
NSQ基本沒有配置文件,配置通過命令行指定參數(shù)。
主要命令如下:
LOOKUPD命令
NSQD命令
工具類,消費后存儲到本地文件。
發(fā)布一條消息
3.2 nsqadmin
對Streams的詳細信息進行查看,包括NSQD節(jié)點,具體的channel,隊列中的消息數(shù),連接數(shù)等信息。
nsqadmin
channel
列出所有的NSQD節(jié)點:
nodes
消息的統(tǒng)計:
msgs
lookup主機的列表:
hosts
4. 總結(jié)
NSQ基本核心就是簡單性,是一個簡單的隊列,這意味著它很容易進行故障推理和很容易發(fā)現(xiàn)bug。消費者可以自行處理故障事件而不會影響系統(tǒng)剩下的其余部分。
事實上,簡單性是我們決定使用NSQ的首要因素,這方便與我們的許多其他軟件一起維護,通過引入隊列使我們得到了堪稱完美的表現(xiàn),通過隊列甚至讓我們增加了幾個數(shù)量級的吞吐量。越來越多的consumer需要一套嚴格可靠性和順序性保障,這已經(jīng)超過了NSQ提供的簡單功能。
結(jié)合我們的業(yè)務(wù)系統(tǒng)來看,對于我們所需要傳輸?shù)陌l(fā)票消息,相對比較敏感,無法容忍某個nsqd宕機,或者磁盤無法使用的情況,該節(jié)點堆積的消息無法找回。這是我們沒有選擇該消息中間件的主要原因。簡單性和可靠性似乎并不能完全滿足。相比Kafka,ops肩負起更多負責(zé)的運營。另一方面,它擁有一個可復(fù)制的、有序的日志可以提供給我們更好的服務(wù)。但對于其他適合NSQ的consumer,它為我們服務(wù)的相當(dāng)好,我們期待著繼續(xù)鞏固它的堅實的基礎(chǔ)。
Go作為Google2009年推出的語言,其被設(shè)計成一門應(yīng)用于搭載 Web 服務(wù)器,存儲集群或類似用途的巨型中央服務(wù)器的系統(tǒng)編程語言。
對于高性能分布式系統(tǒng)領(lǐng)域而言,Go 語言無疑比大多數(shù)其它語言有著更高的開發(fā)效率。它提供了海量并行的支持,這對于 游戲 服務(wù)端的開發(fā)而言是再好不過了。
到現(xiàn)在Go的開發(fā)已經(jīng)是完全開放的,并且擁有一個活躍的社區(qū)。
=================================
哪些大公司在使用Go語言:
1、Google
這個不用多做介紹,作為開發(fā)Go語言的公司,當(dāng)仁不讓。Google基于Go有很多優(yōu)秀的項目,比如: ,大家也可以在Github上 查看更多Google的Go開源項目。
2、Facebook
Facebook也在用,為此他們還專門在Github上建立了一個開源組織facebookgo,大家可以通過 訪問查看facebook開源的項目,比如著名的是平滑升級的grace。
3、騰訊
騰訊作為國內(nèi)的大公司,還是敢于嘗試的,尤其是Docker容器化這一塊,他們在15年已經(jīng)做了docker萬臺規(guī)模的實踐,具體可以參考
4、百度
目前所知的百度的使用是在運維這邊,是百度運維的一個BFE項目,負責(zé)前端流量的接入。他們的負責(zé)人在2016年有分享,大家可以看下這個
5、阿里
阿里巴巴具體的項目不太清楚,不過聽說其系統(tǒng)部門、CDN等正在招Go方面的人。
6、京東
京東云消息推送系統(tǒng)、云存儲,以及京東商城等都有使用Go做開發(fā)。
7、小米
小米對Golang的支持,莫過于運維監(jiān)控系統(tǒng)的開源,也就是
此外,小米互娛、小米商城、小米視頻、小米生態(tài)鏈等團隊都在使用Golang。
8、360
360對Golang的使用也不少,一個是開源的日志搜索系統(tǒng)Poseidon,托管在Github上,
==================================
Go適合做什么?為何這么多人偏愛Go語言?
Go強大的開發(fā)團隊
1、自由高效:組合的思想、無侵入式的接口
Go語言可以說是開發(fā)效率和運行效率二者的完美融合,天生的并發(fā)編程支持。Go語言支持當(dāng)前所有的編程范式,包括過程式編程、面向?qū)ο缶幊桃约昂瘮?shù)式編程。程序員們可以各取所需、自由組合、想怎么玩就怎么玩。
2、強大的標(biāo)準(zhǔn)庫
這包括互聯(lián)網(wǎng)應(yīng)用、系統(tǒng)編程和網(wǎng)絡(luò)編程。Go里面的標(biāo)準(zhǔn)庫基本上已經(jīng)是非常穩(wěn)定了,特別是我這里提到的三個,網(wǎng)絡(luò)層、系統(tǒng)層的庫非常實用。
3、部署方便:二進制文件、Copy部署
我相信這一點是很多人選擇Go的最大理由,因為部署太方便了,所以現(xiàn)在也有很多人用Go開發(fā)運維程序。
4、簡單的并發(fā)
它包含了降低心智的并發(fā)和簡易的數(shù)據(jù)同步,我覺得這是Go最大的特色。之所以寫正確的并發(fā)、容錯和可擴展的程序如此之難,是因為我們用了錯誤的工具和錯誤的抽象,Go可以說這一塊做的相當(dāng)簡單。
5、穩(wěn)定性
Go擁有強大的編譯檢查、嚴格的編碼規(guī)范和完整的軟件生命周期工具,具有很強的穩(wěn)定性,穩(wěn)定壓倒一切。那么為什么Go相比于其他程序會更穩(wěn)定呢?這是因為Go提供了軟件生命周期(開發(fā)、測試、部署、維護等等)的各個環(huán)節(jié)的工具,如go tool、gofmt、go test。
================================
我們?yōu)槭裁催x擇GO語言
選擇GO語言,主要是基于兩方面的考慮
1. 執(zhí)行性能 縮短API的響應(yīng)時長,解決批量請求訪問超時的問題。在Uwork的業(yè)務(wù)場景下,一次API批量請求,往往會涉及對另外接口服務(wù)的多次調(diào)用,而在之前的PHP實現(xiàn)模式下,要做到并行調(diào)用是非常困難的,串行處理卻不能從根本上提高處理性能。而GO語言不一樣,通過協(xié)程可以方便的實現(xiàn)API的并行處理,達到處理效率的最大化。 依賴Golang的高性能HTTP Server,提升系統(tǒng)吞吐能力,由PHP的數(shù)百級別提升到數(shù)千里甚至過萬級別。
2. 開發(fā)效率 GO語言使用起來簡單、代碼描述效率高、編碼規(guī)范統(tǒng)一、上手快。 通過少量的代碼,即可實現(xiàn)框架的標(biāo)準(zhǔn)化,并以統(tǒng)一的規(guī)范快速構(gòu)建API業(yè)務(wù)邏輯。 能快速的構(gòu)建各種通用組件和公共類庫,進一步提升開發(fā)效率,實現(xiàn)特定場景下的功能量產(chǎn)。
Go語言近兩年的發(fā)展速度還是非常快的,一方面Go語言有強大的行業(yè)背書,另一方面Go語言在設(shè)計時充分考慮了當(dāng)前的編程環(huán)境,加強了大數(shù)據(jù)量、高并發(fā)等應(yīng)用場景的處理能力,強調(diào)編程語言自身對于處理性能的追求,相信Go語言在未來大數(shù)據(jù)和人工智能相關(guān)技術(shù)逐漸落地應(yīng)用的背景下,會有一個較為廣闊的發(fā)展空間。
此文是根據(jù)周洋在【高可用架構(gòu)群】中的分享內(nèi)容整理而成,轉(zhuǎn)發(fā)請注明出處。
周洋,360手機助手技術(shù)經(jīng)理及架構(gòu)師,負責(zé)360長連接消息系統(tǒng),360手機助手架構(gòu)的開發(fā)與維護。
不知道咱們?nèi)好裁磿r候改為“Python高可用架構(gòu)群”了,所以不得不說,很榮幸能在接下來的一個小時里在Python群里討論golang....
360消息系統(tǒng)介紹
360消息系統(tǒng)更確切的說是長連接push系統(tǒng),目前服務(wù)于360內(nèi)部多個產(chǎn)品,開發(fā)平臺數(shù)千款app,也支持部分聊天業(yè)務(wù)場景,單通道多app復(fù)用,支持上行數(shù)據(jù),提供接入方不同粒度的上行數(shù)據(jù)和用戶狀態(tài)回調(diào)服務(wù)。
目前整個系統(tǒng)按不同業(yè)務(wù)分成9個功能完整的集群,部署在多個idc上(每個集群覆蓋不同的idc),實時在線數(shù)億量級。通常情況下,pc,手機,甚至是智能硬件上的360產(chǎn)品的push消息,基本上是從我們系統(tǒng)發(fā)出的。
關(guān)于push系統(tǒng)對比與性能指標(biāo)的討論
很多同行比較關(guān)心go語言在實現(xiàn)push系統(tǒng)上的性能問題,單機性能究竟如何,能否和其他語言實現(xiàn)的類似系統(tǒng)做對比么?甚至問如果是創(chuàng)業(yè),第三方云推送平臺,推薦哪個?
其實各大廠都有類似的push系統(tǒng),市場上也有類似功能的云服務(wù)。包括我們公司早期也有erlang,nodejs實現(xiàn)的類似系統(tǒng),也一度被公司要求做類似的對比測試。我感覺在討論對比數(shù)據(jù)的時候,很難保證大家環(huán)境和需求的統(tǒng)一,我只能說下我這里的體會,數(shù)據(jù)是有的,但這個數(shù)據(jù)前面估計會有很多定語~
第一個重要指標(biāo):單機的連接數(shù)指標(biāo)
做過長連接的同行,應(yīng)該有體會,如果在穩(wěn)定連接情況下,連接數(shù)這個指標(biāo),在沒有網(wǎng)絡(luò)吞吐情況下對比,其實意義往往不大,維持連接消耗cpu資源很小,每條連接tcp協(xié)議棧會占約4k的內(nèi)存開銷,系統(tǒng)參數(shù)調(diào)整后,我們單機測試數(shù)據(jù),最高也是可以達到單實例300w長連接。但做更高的測試,我個人感覺意義不大。
因為實際網(wǎng)絡(luò)環(huán)境下,單實例300w長連接,從理論上算壓力就很大:實際弱網(wǎng)絡(luò)環(huán)境下,移動客戶端的斷線率很高,假設(shè)每秒有1000分之一的用戶斷線重連。300w長連接,每秒新建連接達到3w,這同時連入的3w用戶,要進行注冊,加載離線存儲等對內(nèi)rpc調(diào)用,另外300w長連接的用戶心跳需要維持,假設(shè)心跳300s一次,心跳包每秒需要1w tps。單播和多播數(shù)據(jù)的轉(zhuǎn)發(fā),廣播數(shù)據(jù)的轉(zhuǎn)發(fā),本身也要響應(yīng)內(nèi)部的rpc調(diào)用,300w長連接情況下,gc帶來的壓力,內(nèi)部接口的響應(yīng)延遲能否穩(wěn)定保障。這些集中在一個實例中,可用性是一個挑戰(zhàn)。所以線上單實例不會hold很高的長連接,實際情況也要根據(jù)接入客戶端網(wǎng)絡(luò)狀況來決定。
第二個重要指標(biāo):消息系統(tǒng)的內(nèi)存使用量指標(biāo)
這一點上,使用go語言情況下,由于協(xié)程的原因,會有一部分額外開銷。但是要做兩個推送系統(tǒng)的對比,也有些需要確定問題。比如系統(tǒng)從設(shè)計上是否需要全雙工(即讀寫是否需要同時進行)如果半雙工,理論上對一個用戶的連接只需要使用一個協(xié)程即可(這種情況下,對用戶的斷線檢測可能會有延時),如果是全雙工,那讀/寫各一個協(xié)程。兩種場景內(nèi)存開銷是有區(qū)別的。
另外測試數(shù)據(jù)的大小往往決定我們對連接上設(shè)置的讀寫buffer是多大,是全局復(fù)用的,還是每個連接上獨享的,還是動態(tài)申請的。另外是否全雙工也決定buffer怎么開。不同的策略,可能在不同情況的測試中表現(xiàn)不一樣。
第三個重要指標(biāo):每秒消息下發(fā)量
這一點上,也要看我們對消息到達的QoS級別(回復(fù)ack策略區(qū)別),另外看架構(gòu)策略,每種策略有其更適用的場景,是純粹推?還是推拉結(jié)合?甚至是否開啟了消息日志?日志庫的實現(xiàn)機制、以及緩沖開多大?flush策略……這些都影響整個系統(tǒng)的吞吐量。
另外為了HA,增加了內(nèi)部通信成本,為了避免一些小概率事件,提供閃斷補償策略,這些都要考慮進去。如果所有的都去掉,那就是比較基礎(chǔ)庫的性能了。
所以我只能給出大概數(shù)據(jù),24核,64G的服務(wù)器上,在QoS為message at least,純粹推,消息體256B~1kB情況下,單個實例100w實際用戶(200w+)協(xié)程,峰值可以達到2~5w的QPS...內(nèi)存可以穩(wěn)定在25G左右,gc時間在200~800ms左右(還有優(yōu)化空間)。
我們正常線上單實例用戶控制在80w以內(nèi),單機最多兩個實例。事實上,整個系統(tǒng)在推送的需求上,對高峰的輸出不是提速,往往是進行限速,以防push系統(tǒng)瞬時的高吞吐量,轉(zhuǎn)化成對接入方業(yè)務(wù)服務(wù)器的ddos攻擊所以對于性能上,我感覺大家可以放心使用,至少在我們這個量級上,經(jīng)受過考驗,go1.5到來后,確實有之前投資又增值了的感覺。
消息系統(tǒng)架構(gòu)介紹
下面是對消息系統(tǒng)的大概介紹,之前一些同學(xué)可能在gopher china上可以看到分享,這里簡單講解下架構(gòu)和各個組件功能,額外補充一些當(dāng)時遺漏的信息:
架構(gòu)圖如下,所有的service都 written by golang.
幾個大概重要組件介紹如下:
dispatcher service根據(jù)客戶端請求信息,將應(yīng)網(wǎng)絡(luò)和區(qū)域的長連接服務(wù)器的,一組IP傳送給客戶端??蛻舳烁鶕?jù)返回的IP,建立長連接,連接Room service.
room Service,長連接網(wǎng)關(guān),hold用戶連接,并將用戶注冊進register service,本身也做一些接入安全策略、白名單、IP限制等。
register service是我們?nèi)謘ession存儲組件,存儲和索引用戶的相關(guān)信息,以供獲取和查詢。
coordinator service用來轉(zhuǎn)發(fā)用戶的上行數(shù)據(jù),包括接入方訂閱的用戶狀態(tài)信息的回調(diào),另外做需要協(xié)調(diào)各個組件的異步操作,比如kick用戶操作,需要從register拿出其他用戶做異步操作.
saver service是存儲訪問層,承擔(dān)了對redis和mysql的操作,另外也提供部分業(yè)務(wù)邏輯相關(guān)的內(nèi)存緩存,比如廣播信息的加載可以在saver中進行緩存。另外一些策略,比如客戶端sdk由于被惡意或者意外修改,每次加載了消息,不回復(fù)ack,那服務(wù)端就不會刪除消息,消息就會被反復(fù)加載,形成死循環(huán),可以通過在saver中做策略和判斷。(客戶端總是不可信的)。
center service提供給接入方的內(nèi)部api服務(wù)器,比如單播或者廣播接口,狀態(tài)查詢接口等一系列api,包括運維和管理的api。
舉兩個常見例子,了解工作機制:比如發(fā)一條單播給一個用戶,center先請求Register獲取這個用戶之前注冊的連接通道標(biāo)識、room實例地址,通過room service下發(fā)給長連接 Center Service比較重的工作如全網(wǎng)廣播,需要把所有的任務(wù)分解成一系列的子任務(wù),分發(fā)給所有center,然后在所有的子任務(wù)里,分別獲取在線和離線的所有用戶,再批量推到Room Service。通常整個集群在那一瞬間壓力很大。
deployd/agent service用于部署管理各個進程,收集各組件的狀態(tài)和信息,zookeeper和keeper用于整個系統(tǒng)的配置文件管理和簡單調(diào)度
關(guān)于推送的服務(wù)端架構(gòu)
常見的推送模型有長輪訓(xùn)拉取,服務(wù)端直接推送(360消息系統(tǒng)目前主要是這種),推拉結(jié)合(推送只發(fā)通知,推送后根據(jù)通知去拉取消息).
拉取的方式不說了,現(xiàn)在并不常用了,早期很多是nginx+lua+redis,長輪訓(xùn),主要問題是開銷比較大,時效性也不好,能做的優(yōu)化策略不多。
直接推送的系統(tǒng),目前就是360消息系統(tǒng)這種,消息類型是消耗型的,并且對于同一個用戶并不允許重復(fù)消耗,如果需要多終端重復(fù)消耗,需要抽象成不同用戶。
推的好處是實時性好,開銷小,直接將消息下發(fā)給客戶端,不需要客戶端走從接入層到存儲層主動拉取.
但純推送模型,有個很大問題,由于系統(tǒng)是異步的,他的時序性無法精確保證。這對于push需求來說是夠用的,但如果復(fù)用推送系統(tǒng)做im類型通信,可能并不合適。
對于嚴格要求時序性,消息可以重復(fù)消耗的系統(tǒng),目前也都是走推拉結(jié)合的模型,就是只使用我們的推送系統(tǒng)發(fā)通知,并附帶id等給客戶端做拉取的判斷策略,客戶端根據(jù)推送的key,主動從業(yè)務(wù)服務(wù)器拉取消息。并且當(dāng)主從同步延遲的時候,跟進推送的key做延遲拉取策略。同時也可以通過消息本身的QoS,做純粹的推送策略,比如一些“正在打字的”低優(yōu)先級消息,不需要主動拉取了,通過推送直接消耗掉。
哪些因素決定推送系統(tǒng)的效果?
首先是sdk的完善程度,sdk策略和細節(jié)完善度,往往決定了弱網(wǎng)絡(luò)環(huán)境下最終推送質(zhì)量.
SDK選路策略,最基本的一些策略如下:有些開源服務(wù)可能會針對用戶hash一個該接入?yún)^(qū)域的固定ip,實際上在國內(nèi)環(huán)境下不可行,最好分配器(dispatcher)是返回散列的一組,而且端口也要參開,必要時候,客戶端告知是retry多組都連不上,返回不同idc的服務(wù)器。因為我們會經(jīng)常檢測到一些case,同一地區(qū)的不同用戶,可能對同一idc內(nèi)的不同ip連通性都不一樣,也出現(xiàn)過同一ip不同端口連通性不同,所以用戶的選路策略一定要靈活,策略要足夠完善.另外在選路過程中,客戶端要對不同網(wǎng)絡(luò)情況下的長連接ip做緩存,當(dāng)網(wǎng)絡(luò)環(huán)境切換時候(wifi、2G、3G),重新請求分配器,緩存不同網(wǎng)絡(luò)環(huán)境的長連接ip。
客戶端對于數(shù)據(jù)心跳和讀寫超時設(shè)置,完善斷線檢測重連機制
針對不同網(wǎng)絡(luò)環(huán)境,或者客戶端本身消息的活躍程度,心跳要自適應(yīng)的進行調(diào)整并與服務(wù)端協(xié)商,來保證鏈路的連通性。并且在弱網(wǎng)絡(luò)環(huán)境下,除了網(wǎng)絡(luò)切換(wifi切3G)或者讀寫出錯情況,什么時候重新建立鏈路也是一個問題??蛻舳税l(fā)出的ping包,不同網(wǎng)絡(luò)下,多久沒有得到響應(yīng),認為網(wǎng)絡(luò)出現(xiàn)問題,重新建立鏈路需要有個權(quán)衡。另外對于不同網(wǎng)絡(luò)環(huán)境下,讀取不同的消息長度,也要有不同的容忍時間,不能一刀切。好的心跳和讀寫超時設(shè)置,可以讓客戶端最快的檢測到網(wǎng)絡(luò)問題,重新建立鏈路,同時在網(wǎng)絡(luò)抖動情況下也能完成大數(shù)據(jù)傳輸。
結(jié)合服務(wù)端做策略
另外系統(tǒng)可能結(jié)合服務(wù)端做一些特殊的策略,比如我們在選路時候,我們會將同一個用戶盡量映射到同一個room service實例上。斷線時,客戶端盡量對上次連接成功的地址進行重試。主要是方便服務(wù)端做閃斷情況下策略,會暫存用戶閃斷時實例上的信息,重新連入的 時候,做單實例內(nèi)的遷移,減少延時與加載開銷.
客戶端?;畈呗?/p>
很多創(chuàng)業(yè)公司愿意重新搭建一套push系統(tǒng),確實不難實現(xiàn),其實在協(xié)議完備情況下(最簡單就是客戶端不回ack不清數(shù)據(jù)),服務(wù)端會保證消息是不丟的。但問題是為什么在消息有效期內(nèi),到達率上不去?往往因為自己app的push service存活能力不高。選用云平臺或者大廠的,往往sdk會做一些?;畈呗?,比如和其他app共生,互相喚醒,這也是云平臺的push service更有保障原因。我相信很多云平臺旗下的sdk,多個使用同樣sdk的app,為了實現(xiàn)服務(wù)存活,是可以互相喚醒和保證活躍的。另外現(xiàn)在push sdk本身是單連接,多app復(fù)用的,這為sdk實現(xiàn),增加了新的挑戰(zhàn)。
綜上,對我來說,選擇推送平臺,優(yōu)先會考慮客戶端sdk的完善程度。對于服務(wù)端,選擇條件稍微簡單,要求部署接入點(IDC)越要多,配合精細的選路策略,效果越有保證,至于想知道哪些云服務(wù)有多少點,這個群里來自各地的小伙伴們,可以合伙測測。
go語言開發(fā)問題與解決方案
下面講下,go開發(fā)過程中遇到挑戰(zhàn)和優(yōu)化策略,給大家看下當(dāng)年的一張圖,在第一版優(yōu)化方案上線前一天截圖~
可以看到,內(nèi)存最高占用69G,GC時間單實例最高時候高達3~6s.這種情況下,試想一次悲劇的請求,經(jīng)過了幾個正在執(zhí)行g(shù)c的組件,后果必然是超時... gc照成的接入方重試,又加重了系統(tǒng)的負擔(dān)。遇到這種情況當(dāng)時整個系統(tǒng)最差情況每隔2,3天就需要重啟一次~
當(dāng)時出現(xiàn)問題,現(xiàn)在總結(jié)起來,大概以下幾點
1.散落在協(xié)程里的I/O,Buffer和對象不復(fù)用。
當(dāng)時(12年)由于對go的gc效率理解有限,比較奔放,程序里大量short live的協(xié)程,對內(nèi)通信的很多io操作,由于不想阻塞主循環(huán)邏輯或者需要及時響應(yīng)的邏輯,通過單獨go協(xié)程來實現(xiàn)異步。這回會gc帶來很多負擔(dān)。
針對這個問題,應(yīng)盡量控制協(xié)程創(chuàng)建,對于長連接這種應(yīng)用,本身已經(jīng)有幾百萬并發(fā)協(xié)程情況下,很多情況沒必要在各個并發(fā)協(xié)程內(nèi)部做異步io,因為程序的并行度是有限,理論上做協(xié)程內(nèi)做阻塞操作是沒問題。
如果有些需要異步執(zhí)行,比如如果不異步執(zhí)行,影響對用戶心跳或者等待response無法響應(yīng),最好通過一個任務(wù)池,和一組常駐協(xié)程,來消耗,處理結(jié)果,通過channel再傳回調(diào)用方。使用任務(wù)池還有額外的好處,可以對請求進行打包處理,提高吞吐量,并且可以加入控量策略.
2.網(wǎng)絡(luò)環(huán)境不好引起激增
go協(xié)程相比較以往高并發(fā)程序,如果做不好流控,會引起協(xié)程數(shù)量激增。早期的時候也會發(fā)現(xiàn),時不時有部分主機內(nèi)存會遠遠大于其他服務(wù)器,但發(fā)現(xiàn)時候,所有主要profiling參數(shù)都正常了。
后來發(fā)現(xiàn),通信較多系統(tǒng)中,網(wǎng)絡(luò)抖動阻塞是不可免的(即使是內(nèi)網(wǎng)),對外不停accept接受新請求,但執(zhí)行過程中,由于對內(nèi)通信阻塞,大量協(xié)程被 創(chuàng)建,業(yè)務(wù)協(xié)程等待通信結(jié)果沒有釋放,往往瞬時會迎來協(xié)程暴漲。但這些內(nèi)存在系統(tǒng)穩(wěn)定后,virt和res都并沒能徹底釋放,下降后,維持高位。
處理這種情況,需要增加一些流控策略,流控策略可以選擇在rpc庫來做,或者上面說的任務(wù)池來做,其實我感覺放在任務(wù)池里做更合理些,畢竟rpc通信庫可以做讀寫數(shù)據(jù)的限流,但它并不清楚具體的限流策略,到底是重試還是日志還是緩存到指定隊列。任務(wù)池本身就是業(yè)務(wù)邏輯相關(guān)的,它清楚針對不同的接口需要的流控限制策略。
3.低效和開銷大的rpc框架
早期rpc通信框架比較簡單,對內(nèi)通信時候使用的也是短連接。這本來短連接開銷和性能瓶頸超出我們預(yù)期,短連接io效率是低一些,但端口資源夠,本身吞吐可以滿足需要,用是沒問題的,很多分層的系統(tǒng),也有http短連接對內(nèi)進行請求的
但早期go版本,這樣寫程序,在一定量級情況,是支撐不住的。短連接大量臨時對象和臨時buffer創(chuàng)建,在本已經(jīng)百萬協(xié)程的程序中,是無法承受的。所以后續(xù)我們對我們的rpc框架作了兩次調(diào)整。
第二版的rpc框架,使用了連接池,通過長連接對內(nèi)進行通信(復(fù)用的資源包括client和server的:編解碼Buffer、Request/response),大大改善了性能。
但這種在一次request和response還是占用連接的,如果網(wǎng)絡(luò)狀況ok情況下,這不是問題,足夠滿足需要了,但試想一個room實例要與后面的數(shù)百個的register,coordinator,saver,center,keeper實例進行通信,需要建立大量的常駐連接,每個目標(biāo)機幾十個連接,也有數(shù)千個連接被占用。
非持續(xù)抖動時候(持續(xù)逗開多少無解),或者有延遲較高的請求時候,如果針對目標(biāo)ip連接開少了,會有瞬時大量請求阻塞,連接無法得到充分利用。第三版增加了Pipeline操作,Pipeline會帶來一些額外的開銷,利用tcp的全雙特性,以盡量少的連接完成對各個服務(wù)集群的rpc調(diào)用。
4.Gc時間過長
Go的Gc仍舊在持續(xù)改善中,大量對象和buffer創(chuàng)建,仍舊會給gc帶來很大負擔(dān),尤其一個占用了25G左右的程序。之前go team的大咖郵件也告知我們,未來會讓使用協(xié)程的成本更低,理論上不需要在應(yīng)用層做更多的策略來緩解gc.
改善方式,一種是多實例的拆分,如果公司沒有端口限制,可以很快部署大量實例,減少gc時長,最直接方法。不過對于360來說,外網(wǎng)通常只能使用80和433。因此常規(guī)上只能開啟兩個實例。當(dāng)然很多人給我建議能否使用SO_REUSEPORT,不過我們內(nèi)核版本確實比較低,并沒有實踐過。
另外能否模仿nginx,fork多個進程監(jiān)控同樣端口,至少我們目前沒有這樣做,主要對于我們目前進程管理上,還是獨立的運行的,對外監(jiān)聽不同端口程序,還有配套的內(nèi)部通信和管理端口,實例管理和升級上要做調(diào)整。
解決gc的另兩個手段,是內(nèi)存池和對象池,不過最好做仔細評估和測試,內(nèi)存池、對象池使用,也需要對于代碼可讀性與整體效率進行權(quán)衡。
這種程序一定情況下會降低并行度,因為用池內(nèi)資源一定要加互斥鎖或者原子操作做CAS,通常原子操作實測要更快一些。CAS可以理解為可操作的更細行為粒度的鎖(可以做更多CAS策略,放棄運行,防止忙等)。這種方式帶來的問題是,程序的可讀性會越來越像C語言,每次要malloc,各地方用完后要free,對于對象池free之前要reset,我曾經(jīng)在應(yīng)用層嘗試做了一個分層次結(jié)構(gòu)的“無鎖隊列”
上圖左邊的數(shù)組實際上是一個列表,這個列表按大小將內(nèi)存分塊,然后使用atomic操作進行CAS。但實際要看測試數(shù)據(jù)了,池技術(shù)可以明顯減少臨時對象和內(nèi)存的申請和釋放,gc時間會減少,但加鎖帶來的并行度的降低,是否能給一段時間內(nèi)的整體吞吐量帶來提升,要做測試和權(quán)衡…
在我們消息系統(tǒng),實際上后續(xù)去除了部分這種黑科技,試想在百萬個協(xié)程里面做自旋操作申請復(fù)用的buffer和對象,開銷會很大,尤其在協(xié)程對線程多對多模型情況下,更依賴于golang本身調(diào)度策略,除非我對池增加更多的策略處理,減少忙等,感覺是在把runtime做的事情,在應(yīng)用層非常不優(yōu)雅的實現(xiàn)。普遍使用開銷理論就大于收益。
但對于rpc庫或者codec庫,任務(wù)池內(nèi)部,這些開定量協(xié)程,集中處理數(shù)據(jù)的區(qū)域,可以嘗試改造~
對于有些固定對象復(fù)用,比如固定的心跳包什么的,可以考慮使用全局一些對象,進行復(fù)用,針對應(yīng)用層數(shù)據(jù),具體設(shè)計對象池,在部分環(huán)節(jié)去復(fù)用,可能比這種無差別的設(shè)計一個通用池更能進行效果評估.
消息系統(tǒng)的運維及測試
下面介紹消息系統(tǒng)的架構(gòu)迭代和一些迭代經(jīng)驗,由于之前在其他地方有過分享,后面的會給出相關(guān)鏈接,下面實際做個簡單介紹,感興趣可以去鏈接里面看
架構(gòu)迭代~根據(jù)業(yè)務(wù)和集群的拆分,能解決部分灰度部署上線測試,減少點對點通信和廣播通信不同產(chǎn)品的相互影響,針對特定的功能做獨立的優(yōu)化.
消息系統(tǒng)架構(gòu)和集群拆分,最基本的是拆分多實例,其次是按照業(yè)務(wù)類型對資源占用情況分類,按用戶接入網(wǎng)絡(luò)和對idc布點要求分類(目前沒有條件,所有的產(chǎn)品都部署到全部idc)
系統(tǒng)的測試go語言在并發(fā)測試上有獨特優(yōu)勢。
對于壓力測試,目前主要針對指定的服務(wù)器,選定線上空閑的服務(wù)器做長連接壓測。然后結(jié)合可視化,分析壓測過程中的系統(tǒng)狀態(tài)。但壓測早期用的比較多,但實現(xiàn)的統(tǒng)計報表功能和我理想有一定差距。我覺得最近出的golang開源產(chǎn)品都符合這種場景,go寫網(wǎng)絡(luò)并發(fā)程序給大家?guī)淼谋憷?,讓大家把以往為了降低?fù)雜度,拆解或者分層協(xié)作的組件,又組合在了一起。
QA
Q1:協(xié)議棧大小,超時時間定制原則?
移動網(wǎng)絡(luò)下超時時間按產(chǎn)品需求通常2g,3G情況下是5分鐘,wifi情況下5~8分鐘。但對于個別場景,要求響應(yīng)非常迅速的場景,如果連接idle超過1分鐘,都會有ping,pong,來校驗是否斷線檢測,盡快做到重新連接。
Q2:消息是否持久化?
消息持久化,通常是先存后發(fā),存儲用的redis,但落地用的mysql。mysql只做故障恢復(fù)使用。
Q3:消息風(fēng)暴怎么解決的?
如果是發(fā)送情況下,普通產(chǎn)品是不需要限速的,對于較大產(chǎn)品是有發(fā)送隊列做控速度,按人數(shù),按秒進行控速度發(fā)放,發(fā)送成功再發(fā)送下一條。
Q4:golang的工具鏈支持怎么樣?我自己寫過一些小程序千把行之內(nèi),確實很不錯,但不知道代碼量上去之后,配套的debug工具和profiling工具如何,我看上邊有分享說golang自帶的profiling工具還不錯,那debug呢怎么樣呢,官方一直沒有出debug工具,gdb支持也不完善,不知你們用的什么?
是這樣的,我們正常就是println,我感覺基本上可以定位我所有問題,但也不排除由于并行性通過println無法復(fù)現(xiàn)的問題,目前來看只能靠經(jīng)驗了。只要常見并發(fā)嘗試,經(jīng)過分析是可以找到的。go很快會推出調(diào)試工具的~
Q5:協(xié)議棧是基于tcp嗎?
是否有協(xié)議拓展功能?協(xié)議棧是tcp,整個系統(tǒng)tcp長連接,沒有考慮擴展其功能~如果有好的經(jīng)驗,可以分享~
Q6:問個問題,這個系統(tǒng)是接收上行數(shù)據(jù)的吧,系統(tǒng)接收上行數(shù)據(jù)后是轉(zhuǎn)發(fā)給相應(yīng)系統(tǒng)做處理么,是怎么轉(zhuǎn)發(fā)呢,如果需要給客戶端返回調(diào)用結(jié)果又是怎么處理呢?
系統(tǒng)上行數(shù)據(jù)是根據(jù)協(xié)議頭進行轉(zhuǎn)發(fā),協(xié)議頭里面標(biāo)記了產(chǎn)品和轉(zhuǎn)發(fā)類型,在coordinator里面跟進產(chǎn)品和轉(zhuǎn)發(fā)類型,回調(diào)用戶,如果用戶需要阻塞等待回復(fù)才能后續(xù)操作,那通過再發(fā)送消息,路由回用戶。因為整個系統(tǒng)是全異步的。
Q7:問個pushsdk的問題。pushsdk的單連接,多app復(fù)用方式,這樣的情況下以下幾個問題是如何解決的:1)系統(tǒng)流量統(tǒng)計會把所有流量都算到啟動連接的應(yīng)用吧?而啟動應(yīng)用的連接是不固定的吧?2)同一個pushsdk在不同的應(yīng)用中的版本號可能不一樣,這樣暴露出來的接口可能有版本問題,如果用單連接模式怎么解決?
流量只能算在啟動的app上了,但一般這種安裝率很高的app承擔(dān)可能性大,常用app本身被檢測和殺死可能性較少,另外消息下發(fā)量是有嚴格控制 的。整體上用戶還是省電和省流量的。我們pushsdk盡量向上兼容,出于這個目的,push sdk本身做的工作非常有限,抽象出來一些常見的功能,純推的系統(tǒng),客戶端策略目前做的很少,也有這個原因。
Q8:生產(chǎn)系統(tǒng)的profiling是一直打開的么?
不是一直打開,每個集群都有采樣,但需要開啟哪個可以后臺控制。這個profling是通過接口調(diào)用。
Q9:面前系統(tǒng)中的消息消費者可不可以分組?類似于Kafka。
客戶端可以訂閱不同產(chǎn)品的消息,接受不同的分組。接入的時候進行bind或者unbind操作
Q10:為什么放棄erlang,而選擇go,有什么特別原因嗎?我們現(xiàn)在用的erlang?
erlang沒有問題,原因是我們上線后,其他團隊才做出來,經(jīng)過qa一個部門對比測試,在沒有顯著性能提升下,選擇繼續(xù)使用go版本的push,作為公司基礎(chǔ)服務(wù)。
Q11:流控問題有排查過網(wǎng)卡配置導(dǎo)致的idle問題嗎?
流控是業(yè)務(wù)級別的流控,我們上線前對于內(nèi)網(wǎng)的極限通信量做了測試,后續(xù)將請求在rpc庫內(nèi),控制在小于內(nèi)部通信開銷的上限以下.在到達上限前作流控。
Q12:服務(wù)的協(xié)調(diào)調(diào)度為什么選擇zk有考慮過raft實現(xiàn)嗎?golang的raft實現(xiàn)很多啊,比如Consul和ectd之類的。
3年前,還沒有后兩者或者后兩者沒聽過應(yīng)該。zk當(dāng)時公司內(nèi)部成熟方案,不過目前來看,我們不準(zhǔn)備用zk作結(jié)合系統(tǒng)的定制開發(fā),準(zhǔn)備用自己寫的keeper代替zk,完成配置文件自動轉(zhuǎn)數(shù)據(jù)結(jié)構(gòu),數(shù)據(jù)結(jié)構(gòu)自動同步指定進程,同時里面可以完成很多自定義的發(fā)現(xiàn)和控制策略,客戶端包含keeper的sdk就可以實現(xiàn)以上的所有監(jiān)控數(shù)據(jù),profling數(shù)據(jù)收集,配置文件更新,啟動關(guān)閉等回調(diào)。完全抽象成語keeper通信sdk,keeper之間考慮用raft。
Q13:負載策略是否同時在服務(wù)側(cè)與CLIENT側(cè)同時做的 (DISPATCHER 會返回一組IP)?另外,ROOM SERVER/REGISTER SERVER連接狀態(tài)的一致性|可用性如何保證? 服務(wù)側(cè)?;钣袩o特別關(guān)注的地方? 安全性方面是基于TLS再加上應(yīng)用層加密?
會在server端做,比如重啟操作前,會下發(fā)指令類型消息,讓客戶端進行主動行為。部分消息使用了加密策略,自定義的rsa+des,另外滿足我們安全公司的需要,也定制開發(fā)很多安全加密策略。一致性是通過冷備解決的,早期考慮雙寫,但實時狀態(tài)雙寫同步代價太高而且容易有臟數(shù)據(jù),比如register掛了,調(diào)用所有room,通過重新刷入指定register來解決。
Q14:這個keeper有開源打算嗎?
還在寫,如果沒耦合我們系統(tǒng)太多功能,一定會開源的,主要這意味著,我們所有的bind在sdk的庫也需要開源~
Q15:比較好奇lisence是哪個如果開源?
FreeBSD
蘋果的消息推送是通過請求域名: 實現(xiàn)的,該域名解析結(jié)果為美國,這引發(fā)了兩個問題:
1、接口請求時間長,性能低,而且容易請求超時報錯
2、高峰期推送請求錯誤率升高
總體思路:增加一個美國代理服務(wù)器,通過代理服務(wù)器請求蘋果消息推送服務(wù)
1、原來流程
2、現(xiàn)在流程
3、具體方案實施選擇
選擇一:proxy服務(wù)器,部署一個正向代理服務(wù),提供push消息的正向代理,消息通過代理服務(wù)器送達蘋果服務(wù)端
選擇二:proxy服務(wù)器,獨立實現(xiàn)、部署一個 標(biāo)準(zhǔn)的apns服務(wù),負責(zé) ios消息推送。將需要走美國節(jié)點的請求轉(zhuǎn)發(fā)到該proxy節(jié)點
具體情況、具體分析,應(yīng)思考的點:
問題一、蘋果官方提供的SDK中,不支持設(shè)置代理服務(wù)器。官方SDK不適合更改,對以后系統(tǒng)更新不利
問題二、只有蘋果的push服務(wù)需要代理,其他例如華為、小米、vivo不應(yīng)走海外代理
問題三、代理安全性
問題四、代理方案下,有重試邏輯。 如何準(zhǔn)確定義和判斷失敗, 可能會引起消息重復(fù)推送
問題五、實現(xiàn)簡單、有效,正向代理方式:只需實現(xiàn)一個實例化對象方法,其他利用原始sdk即可。獨立apns服務(wù)方式:需要實現(xiàn)一個apns服務(wù),國內(nèi)、國外均需服務(wù)部署,需要增加獨立的開發(fā)和運營成本,另外還得改造調(diào)用服務(wù),實現(xiàn)請求調(diào)度,優(yōu)點服務(wù)獨立、單一,具備一個單獨微服務(wù)條件
github.com/sideshow/apns2
方法一: 修改SDK文件
第一步:設(shè)置環(huán)境變量
第二步:修改apns2.NewClient方法
方法二: 從新定義一個NewClient方法