化繁為簡,寫乙個簡單好用的server

2022-01-23 11:27:41 字數 1566 閱讀 3945

目前很著名的輪子有libevent,boost等高併發的網路庫,可以說著名的網路庫我都用過,用過才知道當要實現一些定製化的功能時並不方便,不但要了解底層原始碼,而且還要進行適當的改造,總有種黑盒開發的感覺,所以在15年我就開始自己封裝一些epoll,select模型,當時基於多路復用用reactor模式封裝了betternet,雖然穩定性不如成熟的網路庫,但是可以根據需求靈活修改網路層和應用層,這是難能可貴的。市面上也有一些成型的即時通訊server,使用過kbengine,origine等整合度較高的server,當要實現一些心跳,邏輯檢測,連線管理等需求時,還是要修改底層的原始碼,感覺很糟糕。18年接觸golang,net包裡封裝的網路模型和協程管理,很完善的排程策略讓我眼前一亮,所以考慮能不能基於golang的官方net包做一些框架上的設計,搭建乙個高可用的網路服務。19年基於net包實現了wentby這個伺服器,併發和穩定性都不錯,最近又翻看了原來的**,覺得很多地方可以精簡一下,而且不想為了相容別人的開發習慣降低伺服器的效率,也不想增加複雜度,所以乾脆做乙個精簡的server給自己用,只要他穩定高效就可以了,執行緒安全這種問題交由開發者考慮。讀了redis網路服務那塊也就500行,簡約而不簡單。

我的想法時盡可能減少執行緒切換的開銷,盡可能精簡的處理訊息,同時也盡可能減少資源的開銷,我的想法是這樣的

當有新的連線建立時,i/o網路協程開闢新的協程,這個協程管理新的連線,負責讀取客戶端傳送的資料。理論上每個連線建立後都有乙個單獨的協程為其服務,所以對於不同的連線,他們讀取資料是併發進行的,無需加鎖。同時在各自的協程裡完成粘包處理,反序列化為乙個邏輯請求包,將該邏輯請求投遞的邏輯協程中。邏輯協程可以配置多個,也可以配置乙個,建議配置乙個,因為多協程處理共享區存在加鎖問題,我在邏輯協程底層做了判斷,如果邏輯協程數大於1則加鎖,否則無鎖。我覺得大部分的請求都是i/o密集型的,所以邏輯隊列為1個足夠,而且能保證應用層是線性處理的。當邏輯協程處理好邏輯請求後,將資料報投遞到傳送協程。這裡傳送協程數量也是可配置的,為了盡可能提公升傳送效率,我這裡根據連線的id分配給指定協程傳送,比如連線id為1的socket他的傳送請求只交給傳送攜程1,這裡用到了取餘分配的原則。

1 網路方面用到了go的原生net包。

2 協程分配和管理是自己實現的,協同和退出等通知都是通過channel實現的

3 配置和日誌庫用的beego的,主要是方便,懶得寫檔案管理。

4 由於go的網路層不會提供檔案描述符,這裡用到了uuid庫生成string型別uid管理tcp

5 websocket用的原生net/websocket包,也沒有單獨開闢協程讀寫和處理,我覺得越簡單越好

5 websocket每個請求其實是放在獨立的協程中管理的,所以各協程處理邏輯時要加鎖,這個我處理好了,應用層只需要安心寫邏輯就可以。

效率測試了一下,單節點8000以上的長連線,每個連線不間斷收發請求未出現卡頓現象,延遲也都在10ms之內,而且未出現連線異常中斷和丟包現象。

目前用於公司內部呼叫系統的併發服務,基於webrtc實現信令控制,訊息**。

目前**已經開源

隨著經驗的豐富,肯定會不滿足現狀的,以後會不斷優化和擴充。

PHP parseurl 乙個好用的函式

parse url 解析 url,返回其組成部分。array parse url string url 本函式解析乙個 url 並返回乙個關聯陣列,包含在 url 中出現的各種組成部分。本函式不是用來驗證給定 url 的合法性的,只是將其分解為下面列出的部分。不完整的 url 也被接受,parse ...

乙個好用的Tag函式

文章標題提到的tag函式是基於jquery寫的,所以,在使用之前務必要引入jquery檔案。該函式主要用於動態建立標籤,並獲取建立的標籤對應的dom物件等。注意 該函式並沒有封裝成jquery外掛程式的形式,若想改造成jquery外掛程式形式,需要的自己動手啦。1.tag函式需要用到其他一些工具函式...

乙個好用的Dialog外掛程式

網頁中常常須要彈出dialog,儘管非常多js開源框架都提供這個功能,可是效果都不是非常好,比方easy ui。改動樣式這些又不是我擅長的,身邊又沒有美工兄弟,苦逼啊!easy ui的basicdialog 並且假設使用這個,僅僅能在div中加入 內容,source code例如以下 click b...