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