NSQ 學習隨記(1)

NSQ是用golang編寫的高性能分佈式消息隊列(可以理解爲輕量化的kafka),就個人理解來說,消息隊列可以看成一個大的buffer ,用於信息生產速率和信息消費速率、分佈式消息同步,同時也便於一些容災策略的實現。

本系列文章着重點在於深入源碼理解,不會寫一些大的概念以及整體架構,方便理解具體功能的具體實現方式。

項目地址 nsq

整體的代碼結構如下

  • apps裏主要是nsq系列進程的啓動器,可以理解爲具體業務邏輯。主要包含nsqd,nsqlookup以及一些通訊和存儲相關daemon
  • bench裏主要是一些性能測試代碼,沒啥說的。
  • contrib裏是一些配置文件,有興趣可以看看到底需要配置啥。
  • internal是主要的方法庫和底層邏輯,本系列會重點關注這一部分
  • nsqadmin是web管理界面的代碼,可以稍微看看,主要是瞭解打樁數據的獲取方式以及這些數據說明的問題
  • nsqd和nsqlookup就是這兩部分需要的方法庫。

 

作爲系列的第一篇文章,先大概闡述下internal包的部分內容

  • 首先是實現了float_array和string_array(我只能說實現的方法很樸實……本來以爲會有一些優化考慮)
  • 提供了認證機制,對producer的publish和customer的subscribe操作進行校驗,主要是校驗合法性(是不是可以推送,是不是可以訂閱等),同時包括認證過期檢測、tls等。(實現也很樸實……)
  • 提供了集羣信息的獲取接口(admin和其他的一些會用到,自己也可以使用這些方法來進行上層封裝),這一部分主要涉及http相關的知識,部分控制信息通過Header傳送。
  • 文件鎖部分,log文件(數據文件)需要進行緩存,在這裏提供了一個dirlock,調用系統的flock接口。看上去目前沒有提供windos版本
  • http_api部分,這部分主要就是封裝了下http通信接口,同時在傳輸時進行壓縮(gzip和deflate方法),我個人覺得比較好的點就是Hijack方法的使用,自己管理連接,不用通過go原生的client,同時可以偷換應用層協議,只使用http的建連方式,這樣實際效果好很多。
  • 自己實現了一個優先隊列,沒啥特殊的。
  • 定義了logger接口,並且提供了對loglevel的一系列操作
  • 提供了端到端(e2e)延遲收集接口。
  • 提供了一些字符串處理方法(比如一些字段的fmt、查詢,合併等操作)
  • 提供了一個rand方法,可以防止原生rand造成的碰撞(math/rand是僞隨機,可能會出現隨機結果相同的情況,如果兩個協程同時訪問一個單元就會block住)
  • 封了下WaitGroup,方便使用,包了個函數句柄。
    type WaitGroupWrapper struct {
    	sync.WaitGroup
    }
    
    func (w *WaitGroupWrapper) Wrap(cb func()) {
    	w.Add(1)
    	go func() {
    		cb()
    		w.Done()
    	}()
    }

     

  • 關於傳輸的相關協議:首先是提供了base10方法(ascii碼轉uint64,0~9的映射)
  • 內部提供了一個TCPserver
type TCPHandler interface {
	Handle(net.Conn)
}

func TCPServer(listener net.Listener, handler TCPHandler, logf lg.AppLogFunc) error {
	logf(lg.INFO, "TCP: listening on %s", listener.Addr())

	var wg sync.WaitGroup

	for {
		clientConn, err := listener.Accept()
		if err != nil {
			if nerr, ok := err.(net.Error); ok && nerr.Temporary() {
				logf(lg.WARN, "temporary Accept() failure - %s", err)
				runtime.Gosched()//讓當前goroutine釋放cpu資源
				continue
			}
			// theres no direct way to detect this error because it is not exposed
			if !strings.Contains(err.Error(), "use of closed network connection") {
				return fmt.Errorf("listener.Accept() error - %s", err)
			}
			break
		}

		wg.Add(1)
		go func() {
			handler.Handle(clientConn)//處理鏈接
			wg.Done()
		}()
	}

	// wait to return until all handler goroutines complete
	wg.Wait()

	logf(lg.INFO, "TCP: closing %s", listener.Addr())

	return nil
}
  • 提供了傳輸協議接口,目前有V1和V2兩版,nsqd使用V2,nsqdlookup使用V1(這個地方不是很清楚爲什麼這麼做,後面補充)
  • 剩下就是一些valid方法,檢查一些命名規範問題。

 

總體來說整體還是比較簡單的,結構也比較清晰。

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章