共计 3928 个字符,预计需要花费 10 分钟才能阅读完成。
数据写入
数据写入时,首先 points 按 shard 划分,归属于一个 shard 的 points 一起写入:
//tsdb/store.go
// WriteToShard writes a list of points to a shard identified by its ID.
func (s *Store) WriteToShard(shardID uint64, points []models.Point) error {sh := s.shards[shardID]
return sh.WritePoints(points)
}
//tsdb/shard.go
// WritePoints will write the raw data points and any new metadata to the index in the shard.
func (s *Shard) WritePoints(points []models.Point) error {
.....
// Write to the engine.
err := engine.WritePoints(points);
.....
}
由 tsm1.Engine 负责写入 points:
- 首先,结构数据,由 points 结构 values=map[string][]Values,key=seriesKey+ 分隔符 +fieldName, value=[]Value={timestamp,fieldValue}汇合;
- 而后,将 values 写入 cache;
- 最初,将 values 写入 WAL;
//tsdb/engine/tsm1/engine.go
// WritePoints writes metadata and point data into the engine.
// It returns an error if new points are added to an existing key.
func (e *Engine) WritePoints(points []models.Point) error {values := make(map[string][]Value, len(points))
for _, p := range points {keyBuf = append(keyBuf[:0], p.Key()...)
keyBuf = append(keyBuf, keyFieldSeparator...)
// 一个 Point 中可能含多个 field
iter := p.FieldIterator()
t := p.Time().UnixNano()
for iter.Next() {keyBuf = append(keyBuf[:baseLen], iter.FieldKey()...)
var v Value
switch iter.Type() {
case models.Float:
fv, err := iter.FloatValue()
if err != nil {return err}
v = NewFloatValue(t, fv)
......
}
values[string(keyBuf)] = append(values[string(keyBuf)], v)
}
}
// 先写到 cache
// first try to write to the cache
if err := e.Cache.WriteMulti(values); err != nil {return err}
// 再写到 WAL
if e.WALEnabled {if _, err := e.WAL.WriteMulti(values); err != nil {return err}
}
return seriesErr
}
数据删除
与 LSM-Tree 相似,influxdb 应用标记删除的办法,待执行 compactor 的时候,再真正的将其删除。
在 data 目录,有.tombstone 文件,记录了哪个时间段的数据须要删除:
- 查问时,将查问后果和.tombstone 内容比对,将要删除的记录去掉;
- compactor 时,查问.tombstone 内容,将数据删除;
数据查问与索引构造
LSM-Tree 有良好的写入性能,然而查问性能有余;TSM-Tree 基于 LSM-Tree,通过采纳索引、布隆过滤器的办法进行查问优化,这里重点关注索引。
influxdb 中有两种类型的索引:元数据索引和 TSM File 索引
元数据索引
元数据指 measurement 和 series 信息,每个 database 都有一个 Index 构造,存储该 database 中的元数据索引信息:
//tsdb/store.go
type Store struct {
path string
// shared per-database indexes, only if using "inmem".
indexes map[string]interface{} //key=databaseName, value 理论是 *Index
....
}
元数据索引的内部结构:
type Index struct {
// 数据库下 name-->*measurement
measurements map[string]*measurement // measurement name to object and index
// 数据库下 seriesKey-->*series
series map[string]*series // map series key to the Series object
// 数据库名称
database string
}
type measurement struct {
Database string
Name string `json:"name,omitempty"`
fieldNames map[string]struct{}
// in-memory index fields
//seriesId-->*series
seriesByID map[uint64]*series // lookup table for series by their id
//tagKey-->tagValue-->[]seriesId
// 查问时,可依据 tagKey 找到 seriesId,而后再找到相干的 series
seriesByTagKeyValue map[string]*tagKeyValue // map from tag key to value to sorted set of series ids
sortedSeriesIDs seriesIDs // sorted list of series IDs in this measurement
}
type tagKeyValue struct {
mu sync.RWMutex
entries map[string]*tagKeyValueEntry
}
type tagKeyValueEntry struct {m map[uint64]struct{} // series id set}
对于元数据查问语句:
show tag values from "cpu_usage" with key="host"
该语句的查问过程:
- 依据 ”cpu_usage” 找到 measurement 对象;
- 在 measurement 对象内,依据 tagKey=”host”,找到其对应的 tagValue+[]seriesId;
对于一般查问语句:
select value from "cpu_usage" where host='server01' and time > now() - 1h
该语句的查问过程:
- 依据工夫:time > now() – 1h,失去数据 shard;
- 在 shard 内,依据 ”cpu_usage” 找到 measurement 对象;
- 在 measurement 对象内,依据 tagKey=”server01″,找到其对应的 tagValue+[]seriesId;
- 遍历 []seriesId,取得[]series 对象,再应用TSM File 索引 查找 TSM File,读取 TSM File block 失去后果;
TSM File 索引
单个 TSM File 中蕴含 block 数据和 index 数据:
Blocks 中寄存压缩后的 timestamp/value。
Index 中寄存 Block 中的索引,Index 会存储到内存做间接索引,以便实现疾速检索。
间接索引的数据结构:
//tsdb/engine/tsm1/reader.go
type indirectIndex struct {b []byte //Index 的内容
offsets []byte
minKey, maxKey []byte // 最小 / 最大 key
minTime, maxTime int64 // 最小 / 最大工夫
}
TSM File 的查找过程:
- 依据 seriesKey,在 []offset 和Index 中各 offset 的 key进行二分查找,失去 offset;
- 依据 offset 读取[]byte 内容,失去 indexEntries;
- 在 indexEntries 中,失去 TSM File 的偏移量,而后读取文件内容失去后果;
//tsdb/engine/tsm1/reader.go
type indexEntries struct {
Type byte
entries []IndexEntry}
// IndexEntry is the index information for a given block in a TSM file.
type IndexEntry struct {
// The min and max time of all points stored in the block.
MinTime, MaxTime int64
// The absolute position in the file where this block is located.
Offset int64 //TSM 文件的偏移量
// The size in bytes of the block in the file.
Size uint32
}
参考
1.http://blog.fatedier.com/2016…
正文完