Influxdb 資料寫入流程
資料寫入流程分析
本篇不涉及儲存層的寫入,只分析寫入請求的處理流程
Influxdb名詞介紹
如果想搞清楚Influxdb資料寫入流程,Influxdb本身的用法和其一些主要的專用詞還是要明白是什麼意思,比如measurement, field key,field value, tag key, tag value, tag set, line protocol, point, series, query, retention policy等;
相關的專用名詞解釋可參考:
分析入口
我們還是以http寫請求為入口來分析,在
httpd/handler.go
中建立Handler時有如下程式碼:
Route{ "write", // Data-ingest route. "POST", "/write", true, writeLogEnabled, h.serveWrite, }
因此對寫入請求的處理就在函式 func (h *Handler) serveWrite(w http.ResponseWriter, r *http.Request, user meta.User)
中。
Handler.serveWrite
流程梳理:
2.1 獲取寫入的db並判斷db是否存在
database := r.URL.Query().Get("db") if database == "" { h.httpError(w, "database is required", http.StatusBadRequest) return } if di := h.MetaClient.Database(database); di == nil { h.httpError(w, fmt.Sprintf("database not found: %q", database), http.StatusNotFound) return }
2.2 許可權驗證
if h.Config.AuthEnabled { if user == nil { h.httpError(w, fmt.Sprintf("user is required to write to database %q", database), http.StatusForbidden) return } if err := h.WriteAuthorizer.AuthorizeWrite(user.ID(), database); err != nil { h.httpError(w, fmt.Sprintf("%q user is not authorized to write to database %q", user.ID(), database), http.StatusForbidden) return } }
2.3 獲取http請求的body部分,如需gzip解壓縮則解壓,並且作body size的校驗,因為有body size大小限制
body := r.Body if h.Config.MaxBodySize > 0 { body = truncateReader(body, int64(h.Config.MaxBodySize)) } ... _, err := buf.ReadFrom(body)
2.4 從http body中解析出 points
points, parseError := models.ParsePointsWithPrecision(buf.Bytes(), time.Now().UTC(), r.URL.Query().Get("precision"))
2.5 將解析出的points寫入db
h.PointsWriter.WritePoints(database, r.URL.Query().Get("rp"), consistency, user, points);
Points的解析
將http body解析成Points是寫入前的最主要的一步, 相關內容定義在
models/points.go
中;我們先來看一下一條寫入語句是什麼樣子的:
insert test_mea_1,tag1=v1,tag2=v2 cpu=1,memory=10
其中test_mea_1
是measurement, tag key是tag1和tag2, 對應的tag value是v1和v2, field key是cpu和memory, field value是1和10;先來看下
point
的定義,它實現了Point interface
type point struct { time time.Time //這個 key包括了measurement和tag set, 且tag set是排序好的 key []byte // text encoding of field data fields []byte // text encoding of timestamp ts []byte // cached version of parsed fields from data cachedFields map[string]interface{} // cached version of parsed name from key cachedName string // cached version of parsed tags cachedTags Tags //用來遍歷所有的field it fieldIterator }
解析出Points
func ParsePointsWithPrecision(buf []byte, defaultTime time.Time, precision string) ([]Point, error) { points := make([]Point, 0, bytes.Count(buf, []byte{'n'})+1) var ( pos int block []byte failed []string ) for pos < len(buf) { pos, block = scanLine(buf, pos) pos++ ... pt, err := parsePoint(block[start:], defaultTime, precision) if err != nil { failed = append(failed, fmt.Sprintf("unable to parse '%s': %v", string(block[start:]), err)) } else { points = append(points, pt) } } return points, nil }
這裡的解析並沒有用正則之類的方案,純的字串逐次掃描,這裡不詳細展開說了.
PointsWriter分析
定義在
coordinator/points_writer.go
中主要負責將資料寫入到本地的儲存,我們重點分析下
WritePointsPrivileged
func (w *PointsWriter) WritePointsPrivileged(database, retentionPolicy string, consistencyLevel models.ConsistencyLevel, points []models.Point) error { .... //將point按time對應到相應的Shar上, 這個對應關係儲存在shardMappings裡, 這個MapShareds我們後面會分析 shardMappings, err := w.MapShards(&WritePointsRequest{Database: database, RetentionPolicy: retentionPolicy, Points: points}) if err != nil { return err } // Write each shard in it's own goroutine and return as soon as one fails. ch := make(chan error, len(shardMappings.Points)) for shardID, points := range shardMappings.Points { // 每個 Shard啟動一個goroutine作寫入操作, 真正的寫入操作w.writeToShard go func(shard *meta.ShardInfo, database, retentionPolicy string, points []models.Point) { err := w.writeToShard(shard, database, retentionPolicy, points) if err == tsdb.ErrShardDeletion { err = tsdb.PartialWriteError{Reason: fmt.Sprintf("shard %d is pending deletion", shard.ID), Dropped: len(points)} } ch <- err }(shardMappings.Shards[shardID], database, retentionPolicy, points) } ... // 寫入超時會return ErrTimeout timeout := time.NewTimer(w.WriteTimeout) defer timeout.Stop() for range shardMappings.Points { select { case <-w.closing: return ErrWriteFailed case <-timeout.C: atomic.AddInt64(&w.stats.WriteTimeout, 1) // return timeout error to caller return ErrTimeout case err := <-ch: if err != nil { return err } } } return err }
Point到Shard的映謝
3.1 先根據point的time找到對應的ShardGroup, 沒有就建立新的ShardGroup;
3.2 按Point的key(measurement + tag set取hash)來散
sgi.Shards[hash%uint64(len(sgi.Shards))]
作者:掃帚的影子
連結:
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/1868/viewspace-2817409/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 通過Python將監控資料由influxdb寫入到MySQLPythonUXMySql
- 資料讀寫流程
- HBase資料的讀寫流程
- InfluxDB入門UX
- ASP.NET Core2讀寫InfluxDB時序資料庫ASP.NETUX資料庫
- 時序資料庫influxdb資料庫UX
- JuiceFS 資料讀寫流程詳解UI
- influxdb使用入門UX
- spark寫入hive資料SparkHive
- MongoDB寫入資料策略MongoDB
- InfluxDB vs TDengine,用資料“說”效能UX
- 如何將 EXCEL 資料寫入資料庫Excel資料庫
- Elasticsearch 資料寫入原理分析Elasticsearch
- InfluxDB—資料保留策略(Retention Policies)介紹UX
- 寫入效能:TDengine 最高達到 InfluxDB 的 10.3 倍,TimeScaleDB 的 6.74 倍UX
- 為什麼是InfluxDB | 寫在《InfluxDB原理和實戰》出版之際UX
- Mysql增量寫入Hdfs(一) --將Mysql資料寫入Kafka TopicMySqlKafka
- java資料list寫入檔案Java
- 資料管理流程,基礎入門簡介
- influxdb與傳統資料庫的比較UX資料庫
- 時序資料庫之InfluxDB的基本操作資料庫UX
- Spring Boot中使用時序資料庫InfluxDBSpring Boot資料庫UX
- 時序資料庫InfluxDB的基本語法資料庫UX
- Go 實現 nginx log 讀取 分析 寫入InfluxDB 並用Grafana 顯示GoNginxUXGrafana
- 使用scrapy框架把資料非同步寫入資料庫框架非同步資料庫
- 資料庫併發寫入問題-丟失更新與寫入偏差資料庫
- HBase BulkLoad批量寫入資料實戰
- C#之txt的資料寫入C#
- MySQL資料寫入過程介紹MySql
- TDengine 釋出效能測試報告,寫入效能達到 InfluxDB 的 10.6 倍測試報告UX
- 一次使用InfluxDB資料庫的總結UX資料庫
- [docker][influxdb][grafana][jmeter] 配置 jmeter 資料至 grafana 展示DockerUXGrafanaJMeter
- 深入淺出:瞭解時序資料庫 InfluxDB資料庫UX
- 大資料實踐解析(下):Spark的讀寫流程分析大資料Spark
- Elasticsearch Lucene 資料寫入原理 | ES 核心篇Elasticsearch
- Elasticsearch Lucene是怎樣資料寫入的Elasticsearch
- C# 將資料寫入到Excel表格C#Excel
- MySQL的寫入資料儲存過程MySql儲存過程