掘金 后端 ( ) • 2024-04-02 00:06

StoreStore 在 tsdb中是最上层的概念,是tsdb存储信息的一组集合,store在全局中只有一个实例,在influxdb启动时初始化完成(详情请看第一章)。

我们先来看一下 Store对应的结构体:

// Store manages shards and indexes for databases.
type Store struct {  
   mu                sync.RWMutex  
   shards            map[uint64]*Shard  
   databases         map[string]*databaseState  
   sfiles            map[string]*SeriesFile  
   SeriesFileMaxSize int64 // Determines size of series file mmap. Can be altered in tests.  
   path              string  
  
   // shared per-database indexes, only if using "inmem".  
   indexes map[string]interface{}  
  
   // Maintains a set of shards that are in the process of deletion.   // This prevents new shards from being created while old ones are being deleted.   pendingShardDeletes map[uint64]struct{}  
  
   // Epoch tracker helps serialize writes and deletes that may conflict. It  
   // is stored by shard.   epochs map[uint64]*epochTracker  
  
   EngineOptions EngineOptions  
  
   baseLogger *zap.Logger  
   Logger     *zap.Logger  
  
   closing chan struct{}  
   wg      sync.WaitGroup  
   opened  bool  
}

在这里可以看到。Store包含了 shards, databases, sfiles. indexes 这些信息,我们可以通过store对象找到, store 同样也代理了一些操作。 同样的,如果我们继续挖掘,其实Store结构体隐含了很多其他的信息:

  1. store 为什么只缓存 shard的信息,和shard相关的RP 信息为什么没有缓存?我个人的理解是这样的,由于shard只会归属于某个RP下,而shard本身记录了上级rp的信息,所以store并不需要关注rp信息,操作shard本身就已经代表了操作某个rp下的shard这一层含义。
  2. series 文件夹明明在某个database下,为什么在这里要和database平级。 在tsdb底层的存储结构中,series本身就是和databse一样是全局的概念,系统中维护的series是包含所有db的series的。这个后面了解到series模块的时候会了解到。

store 对象实现了 TSDBStore 接口如下所示:

// TSDBStore is an interface for accessing the time series data store.type TSDBStore interface {  
   CreateShard(database, policy string, shardID uint64, enabled bool) error  
   WriteToShard(shardID uint64, points []models.Point) error  
  
   RestoreShard(id uint64, r io.Reader) error  
   BackupShard(id uint64, since time.Time, w io.Writer) error  
  
   DeleteDatabase(name string) error  
   DeleteMeasurement(database, name string) error  
   DeleteRetentionPolicy(database, name string) error  
   DeleteSeries(database string, sources []influxql.Source, condition influxql.Expr) error  
   DeleteShard(id uint64) error  

   MeasurementNames(ctx context.Context, auth query.FineAuthorizer, database string, cond influxql.Expr) ([][]byte, error)  
   TagKeys(ctx context.Context, auth query.FineAuthorizer, shardIDs []uint64, cond influxql.Expr) ([]tsdb.TagKeys, error)  
   TagValues(ctx context.Context, auth query.FineAuthorizer, shardIDs []uint64, cond influxql.Expr) ([]tsdb.TagValues, error)  
  
   SeriesCardinality(ctx context.Context, database string) (int64, error)  
   MeasurementsCardinality(ctx context.Context, database string) (int64, error)  
}

store 对象虽然实现了这些方法,实现的方式是委托给下层的对象去执行具体的操作,我们拿 RestoreShard举例:

// RestoreShard restores a backup from r to a given shard.
// This will only overwrite files included in the backup.  
func (s *Store) RestoreShard(id uint64, r io.Reader) error {  
   shard := s.Shard(id)  
   if shard == nil {  
      return fmt.Errorf("shard %d doesn't exist on this server", id)  
   }  
  
   path, err := relativePath(s.path, shard.path)  
   if err != nil {  
      return err  
   }  
  
   return shard.Restore(r, path)  
}

我们可以看到Shard备份操作本身是委托给shard对象去实现的,Store对象的作用只是做一些前置校验和处理。

Store 对象有一个非常重要的 函数名叫 loadShards() 整个TSDB 模块的初始化就是从这个模块一层一层向下初始化的。具体可以看第一章 influxdb 服务端启动流程。