91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

【開源】gnet: 一個輕量級且高性能、基于事件驅動的 Go 網絡庫

發布時間:2020-07-12 09:47:39 來源:網絡 閱讀:1442 作者:sq5d9c9998b6d1f 欄目:編程語言

【開源】gnet: 一個輕量級且高性能、基于事件驅動的 Go 網絡庫

gnet 是一個基于事件驅動的高性能和輕量級網絡框架。它直接使用 epoll 和 kqueue 系統調用而非標準 Golang 網絡包:net 來構建網絡應用,它的工作原理類似兩個開源的網絡庫:netty 和 libuv。

這個項目存在的價值是提供一個在網絡包處理方面能和 Redis、Haproxy 這兩個項目具有相近性能的 Go 語言網絡服務器框架。

gnet 的亮點在于它是一個高性能、輕量級、非阻塞的純 Go 實現的傳輸層(TCP/UDP/Unix-Socket)網絡框架,開發者可以使用 gnet 來實現自己的應用層網絡協議,從而構建出自己的應用層網絡應用:比如在 gnet 上實現 HTTP 協議就可以創建出一個 HTTP 服務器 或者 Web 開發框架,實現 Redis 協議就可以創建出自己的 Redis 服務器等等。

gnet 衍生自另一個項目:evio,但性能遠勝之。

功能

  • 高性能 的基于多線程/Go程模型的 event-loop 事件驅動
  • 內置 Round-Robin 輪詢負載均衡算法
  • 內置 goroutine 池,由開源庫 ants 提供支持
  • 內置 bytes 內存池,由開源庫 pool 提供支持
  • 簡潔的 APIs
  • 基于 Ring-Buffer 的高效內存利用
  • 支持多種網絡協議:TCP、UDP、Unix Sockets
  • 支持兩種事件驅動機制:Linux 里的 epoll 以及 FreeBSD 里的 kqueue
  • 支持異步寫操作
  • 靈活的事件定時器
  • SO_REUSEPORT 端口重用

核心設計

多線程/Go程模型

主從多 Reactors 模型

gnet 重新設計開發了一個新內置的多線程/Go程模型:『主從多 Reactors』,這也是 netty 默認的線程模型,下面是這個模型的原理圖:

【開源】gnet: 一個輕量級且高性能、基于事件驅動的 Go 網絡庫

它的運行流程如下面的時序圖:
【開源】gnet: 一個輕量級且高性能、基于事件驅動的 Go 網絡庫

主從多 Reactors + 線程/Go程池

你可能會問一個問題:如果我的業務邏輯是阻塞的,那么在 EventHandler.React 注冊方法里的邏輯也會阻塞,從而導致阻塞 event-loop 線程,這時候怎么辦?

正如你所知,基于 gnet 編寫你的網絡服務器有一條最重要的原則:永遠不能讓你業務邏輯(一般寫在 EventHandler.React 里)阻塞 event-loop 線程,否則的話將會極大地降低服務器的吞吐量,這也是 netty 的一條最重要的原則。

我的回答是,基于gnet 的另一種多線程/Go程模型:『帶線程/Go程池的主從多 Reactors』可以解決阻塞問題,這個新網絡模型通過引入一個 worker pool 來解決業務邏輯阻塞的問題:它會在啟動的時候初始化一個 worker pool,然后在把 EventHandler.React里面的阻塞代碼放到 worker pool 里執行,從而避免阻塞 event-loop 線程,

模型的架構圖如下所示:

【開源】gnet: 一個輕量級且高性能、基于事件驅動的 Go 網絡庫

它的運行流程如下面的時序圖:
【開源】gnet: 一個輕量級且高性能、基于事件驅動的 Go 網絡庫

gnet 通過利用 ants goroutine 池(一個基于 Go 開發的高性能的 goroutine 池 ,實現了對大規模 goroutines 的調度管理、goroutines 復用)來實現『主從多 Reactors + 線程/Go程池』網絡模型。關于 ants 的全部功能和使用,可以在 ants 文檔 里找到。

gnet 內部集成了 ants 以及提供了 pool.NewWorkerPool 方法來初始化一個 ants goroutine 池,然后你可以把 EventHandler.React 中阻塞的業務邏輯提交到 goroutine 池里執行,最后在 goroutine 池里的代碼調用 gnet.Conn.AsyncWrite 方法把處理完阻塞邏輯之后得到的輸出數據異步寫回客戶端,這樣就可以避免阻塞 event-loop 線程。

有關在 gnet 里使用 ants goroutine 池的細節可以到這里進一步了解。

自動擴容的 Ring-Buffer

gnet 利用 Ring-Buffer 來緩沖網絡數據以及管理內存。

【開源】gnet: 一個輕量級且高性能、基于事件驅動的 Go 網絡庫

開始使用

安裝

$ go get -u github.com/panjf2000/gnet

使用示例

詳細的文檔在這里: gnet 接口文檔,不過下面我們先來了解下使用 gnet 的簡略方法。

gnet 來構建網絡服務器是非常簡單的,只需要實現 gnet.EventHandler接口然后把你關心的事件函數注冊到里面,最后把它連同監聽地址一起傳遞給 gnet.Serve 函數就完成了。在服務器開始工作之后,每一條到來的網絡連接會在各個事件之間傳遞,如果你想在某個事件中關閉某條連接或者關掉整個服務器的話,直接把 gnet.Action 設置成 Cosed 或者 Shutdown就行了。

Echo 服務器是一種最簡單網絡服務器,把它作為 gnet 的入門例子在再合適不過了,下面是一個最簡單的 echo server,它監聽了 9000 端口:

不帶阻塞邏輯的 echo 服務器

package main

import (
    "log"

    "github.com/panjf2000/gnet"
)

type echoServer struct {
    *gnet.EventServer
}

func (es *echoServer) React(c gnet.Conn) (out []byte, action gnet.Action) {
    out = c.Read()
    c.ResetBuffer()
    return
}

func main() {
    echo := new(echoServer)
    log.Fatal(gnet.Serve(echo, "tcp://:9000", gnet.WithMulticore(true)))
}

正如你所見,上面的例子里 gnet 實例只注冊了一個 EventHandler.React 事件。一般來說,主要的業務邏輯代碼會寫在這個事件方法里,這個方法會在服務器接收到客戶端寫過來的數據之時被調用,然后處理輸入數據(這里只是把數據 echo 回去)并且在處理完之后把需要輸出的數據賦值給 out 變量然后返回,之后你就不用管了,gnet 會幫你把數據寫回客戶端的。

帶阻塞邏輯的 echo 服務器

package main

import (
    "log"
    "time"

    "github.com/panjf2000/gnet"
    "github.com/panjf2000/gnet/pool"
)

type echoServer struct {
    *gnet.EventServer
    pool *pool.WorkerPool
}

func (es *echoServer) React(c gnet.Conn) (out []byte, action gnet.Action) {
    data := append([]byte{}, c.Read()...)
    c.ResetBuffer()

    // Use ants pool to unblock the event-loop.
    _ = es.pool.Submit(func() {
        time.Sleep(1 * time.Second)
        c.AsyncWrite(data)
    })

    return
}

func main() {
    p := pool.NewWorkerPool()
    defer p.Release()

    echo := &echoServer{pool: p}
    log.Fatal(gnet.Serve(echo, "tcp://:9000", gnet.WithMulticore(true)))
}

正如我在『主從多 Reactors + 線程/Go程池』那一節所說的那樣,如果你的業務邏輯里包含阻塞代碼,那么你應該把這些阻塞代碼變成非阻塞的,比如通過把這部分代碼通過 goroutine 去運行,但是要注意一點,如果你的服務器處理的流量足夠的大,那么這種做法將會導致創建大量的 goroutines 極大地消耗系統資源,所以我一般建議你用 goroutine pool 來做 goroutines 的復用和管理,以及節省系統資源。

更多的例子可以在這里查看: gnet 示例。

I/O 事件

gnet 目前支持的 I/O 事件如下:

  • EventHandler.OnInitComplete 當 server 初始化完成之后調用。
  • EventHandler.OnOpened 當連接被打開的時候調用。
  • EventHandler.OnClosed 當連接被關閉的時候調用。
  • EventHandler.React 當 server 端接收到從 client 端發送來的數據的時候調用。(你的核心業務代碼一般是寫在這個方法里)
  • EventHandler.Tick 服務器啟動的時候會調用一次,之后就以給定的時間間隔定時調用一次,是一個定時器方法。
  • EventHandler.PreWrite 預先寫數據方法,在 server 端寫數據回 client 端之前調用。

定時器

EventHandler.Tick 會每隔一段時間觸發一次,間隔時間你可以自己控制,設定返回的 delay 變量就行。

定時器的第一次觸發是在 gnet.Serving 事件之后,如果你要設置定時器,別忘了設置 option 選項:WithTicker(true)

events.Tick = func() (delay time.Duration, action Action){
    log.Printf("tick")
    delay = time.Second
    return
}

UDP 支持

gnet 支持 UDP 協議,在 gnet.Serve 里綁定 UDP 地址即可,gnet 的 UDP 支持有如下的特性:

  • 數據進入服務器之后立刻寫回客戶端,不做緩存。
  • EventHandler.OnOpenedEventHandler.OnClosed 這兩個事件在 UDP 下不可用,唯一可用的事件是 React

使用多核

gnet.WithMulticore(true) 參數指定了 gnet 是否會使用多核來進行服務,如果是 true 的話就會使用多核,否則就是單核運行,利用的核心數一般是機器的 CPU 數量。

負載均衡

gnet 目前內置的負載均衡算法是輪詢調度 Round-Robin,暫時不支持自定制。

SO_REUSEPORT 端口復用

服務器支持 SO_REUSEPORT 端口復用特性,允許多個 sockets 監聽同一個端口,然后內核會幫你做好負載均衡,每次只喚醒一個 socket 來處理 accept 請求,避免驚群效應。

開啟這個功能也很簡單,使用 functional options 設置一下即可:

gnet.Serve(events, "tcp://:9000", gnet.WithMulticore(true), gnet.WithReusePort(true)))

性能測試

同類型的網絡庫性能對比

Linux (epoll)

系統參數

# Machine information
        OS : Ubuntu 18.04/x86_64
       CPU : 8 Virtual CPUs
    Memory : 16.0 GiB

# Go version and configurations
Go Version : go1.12.9 linux/amd64
GOMAXPROCS=8
Echo Server

【開源】gnet: 一個輕量級且高性能、基于事件驅動的 Go 網絡庫

HTTP Server

【開源】gnet: 一個輕量級且高性能、基于事件驅動的 Go 網絡庫

FreeBSD (kqueue)

系統參數

# Machine information
        OS : macOS Mojave 10.14.6/x86_64
       CPU : 4 CPUs
    Memory : 8.0 GiB

# Go version and configurations
Go Version : go version go1.12.9 darwin/amd64
GOMAXPROCS=4
Echo Server

【開源】gnet: 一個輕量級且高性能、基于事件驅動的 Go 網絡庫

HTTP Server

【開源】gnet: 一個輕量級且高性能、基于事件驅動的 Go 網絡庫

證書

gnet 的源碼允許用戶在遵循 MIT 開源證書 規則的前提下使用。

致謝

  • evio
  • netty
  • ants
  • pool

相關文章

  • A Million WebSockets and Go
  • Going Infinite, handling 1M websockets connections in Go
  • gnet: 一個輕量級且高性能的 Golang 網絡庫
向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

松潘县| 岳阳县| 芜湖县| 乳源| 磐安县| 遵化市| 安平县| 沿河| 清新县| 阿荣旗| 古交市| 百色市| 依安县| 饶平县| 靖远县| 扶绥县| 武功县| 松阳县| 孝感市| 富平县| 娱乐| 宣武区| 土默特右旗| 江城| 普洱| 金川县| 垫江县| 达州市| 平度市| 三穗县| 恩平市| 甘洛县| 陆川县| 财经| 红原县| 星子县| 集贤县| 元阳县| 蒙城县| 亚东县| 图们市|