Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TSDB shipper + WAL #6049

Merged
merged 89 commits into from
May 5, 2022
Merged

TSDB shipper + WAL #6049

merged 89 commits into from
May 5, 2022

Conversation

owen-d
Copy link
Member

@owen-d owen-d commented Apr 28, 2022

This PR does a few things and is very large. I'm opening as a draft to get some initial feedback. It:

  • Adds a TSDB WAL for persistence on the ingesters
  • Adds a TSDB Head, which wraps a WAL and makes written index entries immediately available for querying in memory
  • Adds a TSDB Store implementation
  • Integrates TSDB with the generic indexshipper
  • Builds a TSDB Manager, which combines the (TSDB Head, TSDB WAL, indexshipper)
  • Some refactoring

This is by no means complete, but it's getting rather large and this is a relatively good place to PR so we can have multiple authors focus on different parts.

On disk, it looks like this when building/shipping the TSDB multitenant indices (first phase):

/tmp/loki/
├── data
│   ├── fake
│   │   └── ce802667485e7a77
│   │       ├── MTgwNzFjM2Y1YTY6MTgwNzFjNDQzZmY6ZGI1NzRh
│   │       ├── MTgwNzFjMzc1NjQ6MTgwNzFjM2NlN2U6YTRlYThkNzk=
│   │       ├── MTgwNzFjNDZiMjI6MTgwNzFjNGI5NmQ6NmFmNjQ1YWY=
│   │       ├── MTgwNzFjNGUwOTQ6MTgwNzFjNTJlZTY6YTE5OGJiZmM=
│   │       ├── MTgwNzFjNTU1MWI6MTgwNzFjNWEzN2M6YWZkY2ZiOWU=
│   │       └── MTgwNzFjNWNhYWI6MTgwNzFjNjE5MGM6Yjk2Mjc1Nzg=
│   ├── index
│   │   └── 19110
│   │       └── v1
│   │           └── multitenant
│   │               ├── 1651176108-.tsdb.gz
│   │               ├── 1651176138-.tsdb.gz
│   │               └── 1651176168-.tsdb.gz
│   └── loki_cluster_seed.json
├── rules
├── tsdb-shipper-active
│   └── v1
│       ├── multitenant
│       │   └── 19110
│       │       ├── 1651176108-.tsdb
│       │       ├── 1651176138-.tsdb
│       │       ├── 1651176168-.tsdb
│       │       ├── 1651176198-.tsdb
│       │       └── 1651176228-.tsdb
│       ├── per_tenant
│       ├── scratch
│       └── wal
│           └── 1651176258
│               └── 00000000
├── tsdb-shipper-cache
└── wal
    ├── 00000000
    ├── 00000001
    ├── 00000002
    └── checkpoint.000001.tmp
        └── 00000000

19 directories, 20 files

cc @sandeepsukhani @cyriltovena @slim-bean
ref #5428

t.Cfg.StorageConfig.BoltDBShipperConfig.IngesterDBRetainPeriod = shipperQuerierIndexUpdateDelay(t.Cfg.StorageConfig.IndexCacheValidity, t.Cfg.StorageConfig.BoltDBShipperConfig.ResyncInterval) + 2*time.Minute

t.Cfg.StorageConfig.TSDBShipperConfig.Mode = indexshipper.ModeWriteOnly
t.Cfg.StorageConfig.TSDBShipperConfig.IngesterName = t.Cfg.Ingester.LifecyclerConfig.ID
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The reason ingester name is not being set with target all is because t.Cfg.isModuleEnabled would only look at explicitly specified targets in -target flag. We will have to move it to a separate block with or without the check using t.Cfg.isModuleActive("ingester") check which actually checks whether the module is active or not .

@owen-d owen-d marked this pull request as ready for review May 4, 2022 19:57
@owen-d owen-d requested a review from a team as a code owner May 4, 2022 19:57
Copy link
Contributor

@sandeepsukhani sandeepsukhani left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One thing I noticed is that the new shipper code is not adding ingester names to the files, having just the timestamp. This can cause multiple ingesters uploading files at exactly the same time to override each other's files. I will take care of this issue in a follow-up PR that I will work on to make the boltdb-shipper client use the new shipper code.

@sandeepsukhani sandeepsukhani merged commit b45efd4 into grafana:main May 5, 2022
}

func (w *ChunkWriter) PutOne(ctx context.Context, from, through model.Time, chk chunk.Chunk) error {
log, ctx := spanlogger.New(ctx, "SeriesStore.PutOne")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
log, ctx := spanlogger.New(ctx, "SeriesStore.PutOne")
log, ctx := spanlogger.New(ctx, "TSDBStore.PutOne")

}

func (m *HeadManager) Append(userID string, ls labels.Labels, chks index.ChunkMetas) error {
labelsBuilder := labels.NewBuilder(ls)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

might be an overkill to use a label builder for removing a single label. It create 2 arrays of 5. Or should we reuse it via a pool ? I think just removing the labels and sorting does the job.

now := time.Now()
curPeriod := m.period.PeriodFor(now)

toRemove, err := m.shippedTSDBsBeforePeriod(curPeriod)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add a comment on this, not I fully understand how you know they are shipped.

for _, id := range wals {
// use anonymous function for ease of cleanup
if err := func(id WALIdentifier) error {
reader, closer, err := wal.NewWalReader(walPath(dir, id.ts), -1)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not a io.ReaderCloser ?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The reader is a *wal.Reader, not an io.Reader

return err
}

if len(rec.Series.Labels) > 0 {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess the expectations here is that the labels will always appear in the wal before the chunks. I think it's worth a small coment.

if !ok {
return nil, nil
}
defer unlock()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not handling RW lock inside the head code ? I get that we need RW lock to add/get new heads in the map, but seems like adding another RW per TSDB would be better because it will scale with the amount of tenant and not be bounded to the shard.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants