# 存储引擎设计文档 ## 1. 概述 GoTiDB存储引擎抽象层旨在提供统一的接口,使不同的存储后端可以无缝集成到系统中。本文档描述了存储引擎的设计原则、接口定义和实现建议。 ## 2. 设计目标 - **抽象统一**: 提供一致的API,隐藏不同存储引擎的实现细节 - **可扩展性**: 支持添加新的存储引擎而无需修改核心代码 - **性能优化**: 针对时序数据的特点进行优化 - **可配置性**: 允许通过配置调整引擎行为 ## 3. 存储引擎接口 ### 3.1 核心接口 ```go // Engine 是所有存储引擎必须实现的基础接口 type Engine interface { // 基本生命周期 Open() error Close() error // 数据操作 WritePoint(ctx context.Context, point DataPoint) error WriteBatch(ctx context.Context, points []DataPoint) error // 查询操作 Query(ctx context.Context, query Query) (QueryResult, error) // 管理操作 Flush() error Compact() error // 监控 Stats() EngineStats // 能力查询 Capabilities() EngineCapabilities } ``` ### 3.2 扩展接口 特定引擎可以实现额外接口来提供特殊功能: ```go // PersistentEngine 提供持久化功能 type PersistentEngine interface { Engine Backup(path string) error Restore(path string) error } // ReplicatedEngine 提供复制功能 type ReplicatedEngine interface { Engine AddReplica(addr string) error RemoveReplica(addr string) error } ``` ## 4. 统一查询接口 所有读操作通过统一的Query接口实现,提供灵活性和一致性: ```go // Query 定义查询参数 type Query struct { // 查询类型 Type QueryType // 时间范围 StartTime int64 EndTime int64 // 序列标识 SeriesID string DeviceID string MetricCode string // 标签过滤 TagFilters []TagFilter // 聚合选项 Aggregation AggregationType AggInterval time.Duration IncludeRawData bool // 结果限制 Limit int Offset int // 其他查询选项 Options map[string]interface{} } // QueryType 定义查询类型 type QueryType int const ( // 原始数据查询 QueryTypeRaw QueryType = iota // 聚合查询 QueryTypeAggregate // 最新值查询 QueryTypeLatest // 标签查询 QueryTypeTags // 元数据查询 QueryTypeMetadata ) // TagFilter 定义标签过滤条件 type TagFilter struct { Key string Operator FilterOperator Value string } // FilterOperator 定义过滤操作符 type FilterOperator int const ( OpEqual FilterOperator = iota OpNotEqual OpRegex OpGreaterThan OpLessThan // 更多操作符... ) // AggregationType 定义聚合类型 type AggregationType int const ( AggNone AggregationType = iota AggSum AggAvg AggMin AggMax AggCount // 更多聚合类型... ) ``` ### 4.1 查询结果 ```go // QueryResult 定义查询结果 type QueryResult interface { // 结果类型 Type() QueryType } // TimeSeriesResult 定义时间序列查询结果 type TimeSeriesResult struct { SeriesID string Points []DataPoint } // AggregateResult 定义聚合查询结果 type AggregateResult struct { SeriesID string Groups []AggregateGroup } type AggregateGroup struct { StartTime int64 EndTime int64 Value float64 Count int } ``` ### 4.2 查询构建器 为了简化查询构建,提供流式API: ```go query := NewQueryBuilder(). ForMetric("cpu.usage"). WithTimeRange(startTime, endTime). WithTag("host", OpEqual, "server01"). WithAggregation(AggAvg, 5*time.Minute). Build() ``` ## 5. 配置抽象 ```go type EngineConfig interface { // 通用配置方法 WithMaxRetention(duration time.Duration) EngineConfig WithMaxPoints(points int) EngineConfig WithFlushInterval(interval time.Duration) EngineConfig // 获取特定引擎的配置 MemoryConfig() *MemoryEngineConfig FileConfig() *FileEngineConfig // 其他引擎... } // 内存引擎特定配置 type MemoryEngineConfig struct { MaxPointsPerSeries int // 可配置的保留点数,替代硬编码的30 UseCompression bool // 其他内存引擎特定参数... } ``` ## 6. 引擎注册机制 ```go // EngineRegistry 管理所有可用的存储引擎 type EngineRegistry struct { engines map[string]EngineFactory } // EngineFactory 创建存储引擎实例 type EngineFactory func(config EngineConfig) (Engine, error) // 注册新引擎 func (r *EngineRegistry) Register(name string, factory EngineFactory) { r.engines[name] = factory } // 创建引擎实例 func (r *EngineRegistry) Create(name string, config EngineConfig) (Engine, error) { if factory, ok := r.engines[name]; ok { return factory(config) } return nil, fmt.Errorf("unknown engine: %s", name) } ``` ## 7. 性能优化建议 ### 7.1 写入路径优化 实现写入缓冲区合并小批量写入: ```go type WriteBuffer struct { points map[string][]DataPoint // 按序列ID分组 mu sync.Mutex maxSize int flushCh chan struct{} engine Engine } func (wb *WriteBuffer) Add(point DataPoint) { wb.mu.Lock() seriesID := point.SeriesID() wb.points[seriesID] = append(wb.points[seriesID], point) size := len(wb.points) wb.mu.Unlock() if size >= wb.maxSize { wb.Flush() } } func (wb *WriteBuffer) Flush() { wb.mu.Lock() points := wb.points wb.points = make(map[string][]DataPoint) wb.mu.Unlock() // 批量写入引擎 wb.engine.WriteBatch(context.Background(), points) } ``` ### 7.2 并发控制优化 实现分片锁减少锁竞争: ```go type ShardedLock struct { locks []sync.RWMutex shardMask uint64 } func NewShardedLock(shards int) *ShardedLock { // 确保分片数是2的幂 shards = nextPowerOfTwo(shards) return &ShardedLock{ locks: make([]sync.RWMutex, shards), shardMask: uint64(shards - 1), } } func (sl *ShardedLock) getLockForKey(key string) *sync.RWMutex { h := fnv.New64() h.Write([]byte(key)) hashVal := h.Sum64() return &sl.locks[hashVal&sl.shardMask] } func (sl *ShardedLock) Lock(key string) { sl.getLockForKey(key).Lock() } func (sl *ShardedLock) Unlock(key string) { sl.getLockForKey(key).Unlock() } ``` ### 7.3 内存优化 实现时序数据的紧凑存储: ```go // 紧凑存储时间戳和值 type CompactTimeSeriesBlock struct { baseTime int64 deltaEncode []byte // 使用delta编码存储时间戳 values []byte // 压缩存储的值 } func NewCompactBlock(baseTime int64, capacity int) *CompactTimeSeriesBlock { return &CompactTimeSeriesBlock{ baseTime: baseTime, deltaEncode: make([]byte, 0, capacity*binary.MaxVarintLen64), values: make([]byte, 0, capacity*8), // 假设double值 } } func (b *CompactTimeSeriesBlock) AddPoint(timestamp int64, value float64) { // 存储时间增量 delta := timestamp - b.baseTime buf := make([]byte, binary.MaxVarintLen64) n := binary.PutVarint(buf, delta) b.deltaEncode = append(b.deltaEncode, buf[:n]...) // 存储值 bits := math.Float64bits(value) buf = make([]byte, 8) binary.LittleEndian.PutUint64(buf, bits) b.values = append(b.values, buf...) } ``` ### 7.4 查询优化 实现时间范围索引: ```go type TimeRangeIndex struct { // 每个时间窗口的起始位置 windows []timeWindow blockSize int64 // 时间窗口大小,如1小时 } type timeWindow struct { startTime int64 endTime int64 offset int // 数据块中的偏移 } func (idx *TimeRangeIndex) FindBlocks(start, end int64) []int { var result []int for i, window := range idx.windows { if window.endTime >= start && window.startTime <= end { result = append(result, i) } } return result } ``` ## 8. 实现路线图 1. **定义核心接口** - 实现Engine接口 - 定义Query和QueryResult结构 2. **重构现有引擎** - 调整内存引擎以实现新接口 - 使MaxPointsPerSeries可配置 3. **实现查询构建器** - 创建流式API构建查询 4. **添加性能优化** - 实现写入缓冲区 - 添加分片锁 - 优化内存使用 5. **实现引擎注册机制** - 创建EngineRegistry - 支持动态引擎选择 6. **添加监控和统计** - 实现Stats接口 - 收集性能指标 ## 9. 使用示例 ```go // 创建引擎 registry := NewEngineRegistry() registry.Register("memory", NewMemoryEngine) registry.Register("file", NewFileEngine) config := NewEngineConfig(). WithMaxRetention(24 * time.Hour). WithMaxPoints(1000) engine, err := registry.Create("memory", config) if err != nil { log.Fatal(err) } // 写入数据 point := DataPoint{ DeviceID: "device1", MetricCode: "temperature", Labels: map[string]string{"location": "room1"}, Value: 25.5, Timestamp: time.Now().UnixNano(), } err = engine.WritePoint(context.Background(), point) // 查询数据 query := NewQueryBuilder(). ForMetric("temperature"). WithTimeRange(startTime, endTime). WithTag("location", OpEqual, "room1"). Build() result, err := engine.Query(context.Background(), query) if err != nil { log.Fatal(err) } // 处理结果 if tsResult, ok := result.(*TimeSeriesResult); ok { for _, point := range tsResult.Points { fmt.Printf("Time: %v, Value: %v\n", time.Unix(0, point.Timestamp), point.Value) } } ```