Fix NOT_ENOUGH_SPACE error from CH during monthly clean sites job - #6551
Fix NOT_ENOUGH_SPACE error from CH during monthly clean sites job#6551apata wants to merge 1 commit into
Conversation
| [database, table] | ||
| ) | ||
|
|
||
| Enum.map(rows, fn [partition_id] -> partition_id end) |
There was a problem hiding this comment.
| Enum.map(rows, fn [partition_id] -> partition_id end) | |
| List.flatten(rows) |
| @partition_delete_timeout :timer.minutes(15) | ||
|
|
||
| def perform(_job) do | ||
| deleted_sites = get_deleted_sites_with_clickhouse_data() |
There was a problem hiding this comment.
Not sure if you like to do that, but we could store the deleted IDs upon deletion and pick them up from there instead of dancing around with mapset and somewhat greedy queries. We could run this exact cleanup for the last time manually and keep reading exactly what we need from a trusted source.
There was a problem hiding this comment.
Good idea. These queries are scanning a lot of rows. We will need to discuss how to implement the removal of a site_id from that table: it must not happen before all mutations cleaning the data for the site for all tables for all partitions have run, but it's not obvious to me where we can get that signal.
| ] | ||
|
|
||
| @settings if Mix.env() in [:test, :ce_test, :e2e_test], do: [mutations_sync: 2], else: [] | ||
| @settings [mutations_sync: 2] |
There was a problem hiding this comment.
Pretty sure this should be async on prod
There was a problem hiding this comment.
It is a bit of a step away from tradition and you're right to point this out. If mutations_sync: 2, we wait for all nodes in the cluster to finish the mutation, which is a bit flimsy if one of the nodes is in trouble at the time.
If mutations_sync: 0, we dump the mutations into a list on CH cluster Keeper, hang up and the job completes with :ok. CH then churns through these as and when able (https://clickhouse.com/docs/reference/statements/alter/index#mutations). The mutations may succeed or they may fail. How do we know that we actually cleaned up that which we intended? There's also the matter of mutation concurrency. With this method, we lose control over it (beyond settings levers), which can lead to mutations using up all the available disk space.
I'm ok with mutations_sync: 0, but in this case we should run another job soon after to check up on these mutations.
If mutations are absolutely necessary, monitor them carefully using the system.mutations table and use KILL MUTATION if a process is stuck or misbehaving. Misusing mutations can lead to degraded performance, excessive storage churn, and potential service instability—so apply them with caution and sparingly.
(from https://clickhouse.com/docs/concepts/best-practices/avoid-mutations)
There was a problem hiding this comment.
I think running a single oban job potentially for hours/days is unacceptable design-wise. If you think you can recover from a synchronous timeout or other failure by retrying the job, please make it so each partition prune is a job on its own and oban takes care of scheduling.
There was a problem hiding this comment.
The mutations may succeed or they may fail. How do we know that we actually cleaned up that which we intended?
Why do you need to know right away? What is the consequence of one partition not getting pruned because site id 2387 was deleted? On a scale of no one is affected to catastrophic, what is the severity?
Monitoring ClickHouse for its inability to execute mutations consistently is another matter, completely out of scope, so we're talking a one-off event where a partition isn't fully rewritten. What is the big deal?
There was a problem hiding this comment.
Monitoring ClickHouse for its inability to execute mutations consistently is another matter, completely out of
scope, so we're talking a one-off event where a partition isn't fully rewritten. What is the big deal?
With the currently deployed method that's using mutations_sync: 0, if the mutation cleaning up events_v2 table for a batch of sites succeeded, but cleaning up other tables failed, when will the data for those sites be cleaned up from the other tables?
Data deletion is a critical part of security and privacy guarantees to users and I look at it with utmost severity, so I don't think monitoring mutations we rely on to ensure this is out of scope. CH docs explicitly advise monitoring mutations. Still, it can be done over our monitoring platform and with alerts, not in app code as I suggested.
I think running a single oban job potentially for hours/days is unacceptable design-wise.
Agreed, converting to draft and will discuss alternatives, separate job per partition per table or similar.
There was a problem hiding this comment.
Data deletion is a critical part of security and privacy guarantees to users and I look at it with utmost severity
Care to elaborate how the data we store at rest is not private and how this is important for security? The site ID doesn't exist anymore, there's a bunch of anonymous visits with meaningless identifiers worst case, on a rare event (we have no record of) of a partial mutation failing.
so I don't think monitoring mutations we rely on to ensure this is out of scope
Out of scope of ensuring ingestion is uninterrupted due to deletions happening
There was a problem hiding this comment.
The data about website visits is valuable, as evidenced by analytics platforms that offer their service for free in exchange for some access to the data.
This value and meaning persists even if the site_id that it is for doesn't exist any more. In events_v2 we have hostname, page, meta, ...
Failure to clean up this properly means that in the event of a data leak, data of website visitors of sites that have stopped using Plausible would be exposed as well.
| @settings if Mix.env() in [:test, :ce_test, :e2e_test], do: [mutations_sync: 2], else: [] | ||
| @settings [mutations_sync: 2] | ||
|
|
||
| @partition_delete_timeout :timer.minutes(15) |
There was a problem hiding this comment.
So are we ok to crash if this takes more than 15 mins? What's the reasoning here?
There was a problem hiding this comment.
Important question, we must take fails / timeouts into account when working on another solution.
| [table, partition_id, deleted_sites_ids], | ||
| settings: @settings, | ||
| timeout: @partition_delete_timeout, | ||
| checkout_retries: 0 |
There was a problem hiding this comment.
Why checkout_retries: 0? Are we effectively rescheduling this partition for next month if the pool is busy?
There was a problem hiding this comment.
Valid question! Need to discuss when working on another solution
There was a problem hiding this comment.
Right, but why did you write it even? 😅
There was a problem hiding this comment.
I appreciate your input and wanted to clarify that it will not be ignored, just that I didn't want to go in depth for a solution that is inadequate for other reasons.
Since timeouts and failures are such an integral part of any new solution, I'd prefer to discuss it with the proposal of the new system at hand.
These comments are a public record of how things are done at Plausible, so I thought it's appropriate to take an extra minute to ack.
Changes
Tests
Changelog
Documentation
Dark mode