gotidb/docs/design/engine-design.md

450 lines
9.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 存储引擎设计文档
## 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)
}
}
```