InfluxDB源碼編譯、安裝、配置及主從同步實現

直接使用官方包進行安裝很簡單,查看官方說明即可。安裝之後使用才發現,開源的只支持單機版的,但是公司用不能這麼low吧,怎麼也要“高可用”一點,於是自己參考MySQL主從複製原理、半同步操作步驟及原理餓了麼 Influxdb 實踐之路,做了InfluxDB主從系統。


客戶端系統

客戶端系統拓撲圖 

blob.png

這個系統主要是用來從kafka獲取數據源,經過處理之後存到InfluxDB中去,這裏參考了「餓了麼」那篇文章,但是我看過他們的源碼,基本上搞不懂,就根據文章的描述搞了一個簡陋版的東西吧,這裏涉及到kafka和influxdb-java,項目源代碼可以看這裏。該項目啓動運行參考其中的README。


InfluxDB主從同步系統

InfluxDB同步系統 

blob.png

主從同步架構,是簡陋版的MySQL主從同步。腳本讀取InfluxDB的增刪改操作日誌,使用腳本將記錄寫入從機中。經過測試,運行狀況良好,只要主從機不掛,同步系統可以健康運行。

同步腳本使用Python編寫,項目源代碼在這裏。該項目啓動運行參考其中的README。

爲什麼使用Python腳本來編寫主從同步代碼?

  • 主要是考慮到降低與數據庫的代碼耦合程度,InfluxDB源碼如果出現大規模的升級改動,同步腳本只需略作修改就可以了。

  • 畢竟Python是世界上**的語言。?


InfluxDB源碼修改

  • 下載源碼

    在github上下載InfluxDB源碼(這裏使用的是我的fork地址,已經修改好的源碼)。

  • 修改源碼

    由於腳本需要讀取InfluxDB的增刪改操作日誌,需要對源碼中這一部分操作的日誌進行修改,方便腳本解析日誌。官方版的日誌不記錄寫入操作的數據值,所以需要我們自己修改源碼中對應的記錄寫日誌的地方。

    修改文件influxdb/services/httpd/handler.go

    // 記錄日誌的具體方法
    func buildLogLine(l *responseLogger, r *http.Request, start time.Time, body string) string {
    
        redactPassword(r)
    
        username := parseUsername(r)
    
        host, _, err := net.SplitHostPort(r.RemoteAddr)
        if err != nil {
            host = r.RemoteAddr
        }
    
        if xff := r.Header["X-Forwarded-For"]; xff != nil {
            addrs := append(xff, host)
            host = strings.Join(addrs, ",")
        }
    
        uri := r.URL.RequestURI()
    
        referer := r.Referer()
    
        userAgent := r.UserAgent()
    
        // 新增請求中的請求路徑
        path := r.URL.Path
    
        // 新增請求中的form值
        r.ParseForm()
        form := r.Form
    
        // 新增請求中的body的值
        newbody := strings.Replace(body, "\n", ";", -1)
    
        // 將日誌記錄變爲json格式
        return fmt.Sprintf(`{"timeindex":%d,"host":"%s","username":"%s","method":"%s","path":"%s","uri":"%s","form":"%s","body":"%s","proto":"%s","status":"%s","size":"%s","referer":"%s","agent":"%s","reqId":"%s"}`,
            start.Nanosecond(),
            host,
            detect(username, "-"),
            r.Method,
            path,
            uri,
            form,
            newbody,
            r.Proto,
            detect(strconv.Itoa(l.Status()), "-"),
            strconv.Itoa(l.Size()),
            detect(referer, "-"),
            detect(userAgent, "-"),
            r.Header.Get("Request-Id"))
    }

    修改文件influxdb/services/httpd/handler.go其中兩處調用上面修改過的函數buildLogLine的地方

    func (h *Handler) logging(inner http.Handler, name string) http.Handler {
        return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
            start := time.Now()
            l := &responseLogger{w: w}
            inner.ServeHTTP(l, r)
            // 增加請求中的body
            h.CLFLogger.Println(buildLogLine(l, r, start, h.body))
    
            // Log server errors.
            if l.Status()/100 == 5 {
                errStr := l.Header().Get("X-InfluxDB-Error")
                if errStr != "" {
                    h.Logger.Error(fmt.Sprintf("[%d] - %q", l.Status(), errStr))
                }
            }
        })
    }
    func (h *Handler) recovery(inner http.Handler, name string) http.Handler {
        return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
            start := time.Now()
            l := &responseLogger{w: w}
    
            defer func() {
                if err := recover(); err != nil {
                    // 增加請求中的body
                    logLine := buildLogLine(l, r, start, h.body)
                    logLine = fmt.Sprintf("%s [panic:%s] %s", logLine, err, debug.Stack())
                    h.CLFLogger.Println(logLine)
                    http.Error(w, http.StatusText(http.StatusInternalServerError), 500)
                    atomic.AddInt64(&h.stats.RecoveredPanics, 1) // Capture the panic in _internal stats.
    
                    if willCrash {
                        h.CLFLogger.Println("\n\n=====\nAll goroutines now follow:")
                        buf := debug.Stack()
                        h.CLFLogger.Printf("%s\n", buf)
                        os.Exit(1) // If we panic then the Go server will recover.
                    }
                }
            }()
    
            inner.ServeHTTP(l, r)
        })
    }

    到此InfluxDB源碼修改完成。

    爲什麼要在func buildLogLine(l *responseLogger, r *http.Request, start time.Time, body string) string方法上增加一個字段body,而body明明是從h *Handler中獲取的,而函數buildLogLine中明明是有r *http.Request的?

    因爲經過測試,在func buildLogLine中從r *http.Request裏面實際上取不到body的值,我沒有深入研究過這段代碼,確實不懂爲什麼會這樣。所以才從上層將body的值直接傳入這個方法中。


編譯源碼和運行

使用源碼構建時序數據庫主從同步系統

系統要求

Linux 64位系統即可。

依賴環境

本系統使用InfluxDB v1.5.2,所以需要Go 1.9.2或者以上的版本。

InfluxDB使用Dep管理依賴包,需要安裝dep

主從同步腳本使用Python 2.7開發。

需要從Github上拉取源碼,環境中需要安裝git

安裝InfluxDB

新建目錄$YOUR_PATH/gocodez/src$YOUR_PATH/gocodez/src$YOUR_PATH爲自定義目錄:

mkdir -p $YOUR_PATH/gocodez/srcmkdir -p $YOUR_PATH/gocodez/bin12

將源碼下載解壓到目錄$YOUR_PATH/gocodez/src中:

cd $YOUR_PATH/gocodez/src/
git clone https://github.com/callELPSYCONGROO/influxdb.git12

將目錄$YOUR_PATH/設置爲GOPATH

export GOPATH=$YOUR_PATH/1

進入目錄中:

cd $YOUR_PATH/gocodez/src/influxdb1

如果正確安裝了dep,這使用這個命令安裝依賴:

dep ensure1

安裝依賴時,如果遇到無法連接到依賴所需的服務器,需要查看所缺依賴,手動將這些依賴源碼下載到$YOUR_PATH/src/對應路徑下。所需依賴在Github上均有源碼可以下載。

如果安裝或使用dep不成功,可以跳過此步,在下一步時根據錯誤提示,手動安裝所需依賴。

安裝依賴可以使用依賴包,將依賴包的/src解壓到$YOUR_PATH/gocodez目錄下即可。

構建安裝二進制執行碼:

go clean ./...go install ./...12

安裝完成後,二進制執行碼放在$YOUR_PATH/gocodez/bin/中,啓動時序數據庫:

$YOUR_PATH/gocodez/bin/influxd1

安裝主從同步腳本

新建目錄$YOUR_SCRIPT$YOUR_SCRIPT爲自定義腳本目錄:

mkdir $YOUR_SCRIPT1

從Github中拉取腳本:

cd $YOUR_SCRIPTgit clone https://github.com/callELPSYCONGROO/master_slave12

參考其中的README.md完成腳本配置和運行。


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