-
Notifications
You must be signed in to change notification settings - Fork 73
Fix queries and storage block operations synchronisation #699
Conversation
b1567dc
to
c42dfe5
Compare
In addition, testing revealed one more bug I can easily reproduce on
|
Fixed a data race spotted by race detector: Stack traces
|
4a2bed1
to
576b20b
Compare
I'm going to leave my stress test running over the night, to make sure the fix does not introduce new bugs: 50 clients with "real" profiles, 5 parallel queries (last hour, the response data is not verified), phlare is compiled with the race detector enabled and is running with these options:
It's worth running a test like this periodically, I believe |
s.lock.RLock() | ||
defer s.lock.RUnlock() | ||
|
||
buffer := parquet.NewBuffer( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not possible to re-use it anymore ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm afraid I failed to find where we reuse dedup slice or its parts: we use zero values at head initialization:
Line 158 in d303348
func NewHead(phlarectx context.Context, cfg Config, limiter TenantLimiter) (*Head, error) { |
and the Init
function does not seem to try to reuse allocated objects by any means:
phlare/pkg/phlaredb/deduplicating_slice.go
Lines 61 to 77 in d303348
func (s *deduplicatingSlice[M, K, H, P]) Init(path string, cfg *ParquetConfig, metrics *headMetrics) error { | |
s.cfg = cfg | |
s.metrics = metrics | |
file, err := os.OpenFile(filepath.Join(path, s.persister.Name()+block.ParquetSuffix), os.O_RDWR|os.O_CREATE|os.O_EXCL, 0o644) | |
if err != nil { | |
return err | |
} | |
s.file = file | |
// TODO: Reuse parquet.Writer beyond life time of the head. | |
s.writer = parquet.NewGenericWriter[P](file, s.persister.Schema(), | |
parquet.ColumnPageBuffers(parquet.NewFileBufferPool(os.TempDir(), "phlaredb-parquet-buffers*")), | |
parquet.CreatedBy("github.com/grafana/phlare/", build.Version, build.Revision), | |
) | |
s.lookup = make(map[K]int64) | |
return nil | |
} |
The buffer itself is not used anywhere but at Flush
.
I should say that if we want to flush the head without blocking writes to the db, we have to sacrifice some memory. Although a pool could help there, judging by the GC rate, it's very likely the objects will be removed from it before the next flush. My conclusion is, provided that I don't find this allocation particularly harmful (it is almost unnoticeable in the heap profile), performance improvement would be small to unnoticeable. Therefore I'm not very concerned about this
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice work, I'd love to see how this impact our tail latency.
LGTM 👏
Also fixed one more bug in block querier – turns out the recent change has not fixed the race: |
…are#699) * Fix ingest/flush race * Allow concurrent reads in cutRowGroup * profileStore synchronization * alloc dedup slice buffer * Fix block eviction synchronisation
Resolves #687