-
Notifications
You must be signed in to change notification settings - Fork 330
Add Polaris Events to Persistence #1844
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
Add Polaris Events to Persistence #1844
Conversation
|
Thanks @adnanhemani for tackling the effort. It looks that this change introduces another serialization implementation, although we already have Jackson in place. Can you explain why that's needed? It's a bit unclear why these "buffers" are needed. Would you mind elaborating on this? I have some concerns around how the approach could be implemented in the NoSQL world, via #1189. There we already have a way to iterate over recent changes (aka: events). Do you have some idea around how both could live together? Would be nice to consider NoSQL in this new approach, because we already agreed that NoSQL will become part of Polaris. I think it's better to have a way that satisfies both persistence worlds. |
|
Thanks for the high-level comments, @snazy!
My anecdotal experience is that Jackson is a much slower serialization library than Kryo and given that we want to make these commands quick so that the user does not notice a difference, I went ahead with a quicker implementation. I do understand that this brings additional overhead/maintainance - so I'm okay to shift the code to use Jackson instead if that's a hard requirement. WDYT?
This was earlier discussed on the ML thread. TL;DR on this is: if we aim to support some read activities in the near future, flushing to persistence constantly per call will become quite heavy on the persistence. To ensure we are not hammering the persistence (which in the current case is the same as the metastore) and causing an accidentally DDoS, these buffers will help.
I took a brief look at the linked PR for NoSQL - but to be fair, it is a massive PR, so please correct and/or augment my knowledge as required. Per my understanding, the changes are stored to commit to the persistence. I'm in agreement that this is very similar to events in terms of what they are representing, but not in terms of the way they are being used. Events (which I am only modifying in this PR) are to be used as administrator-facing representation of customer-triggered actions, whereas Changes (being introduced in the NoSQL PR) are a way for committing actions to the persistence. Given that Events should not be solely for changes to the persistence, I don't really see how Changes can be used to power and/or replace Events. The way I imagine things would be that Events can (and should) be stored in the NoSQL persistence as well - and any calls to the future Events API should understand which type of persistence layer was used for Events storage and delegate the call to that persistence type. That is why I have introduced an append-only Base line to state: I 100% agree that the Events functionality should exist in NoSQL as well as JDBC-Relational - and I'm happy to help contribute towards this once NoSQL finalizes and merges. But I'm not sure that Changes is helpful in this journey - unless we'd like to evolve that object into something that can represent all events as well. |
|
I don't think we're in a rush with this change, because the mandatory support/spec in Iceberg is not there yet. I think it's safer to wait for the Iceberg change before adding something to Polaris. WDYT? |
adutra
left a comment
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.
@adnanhemani I must say I'm not at all satisfied with the current state of FileBufferPolarisPersistenceEventListener.
In fact, I am not at all convinced that we need file-based buffers here.
Have you thought about the event bus in Quarkus / Vertx? This mechanism allows to asynchronously process events in a dedicated thread pool, without hurting the original request latencies.
polaris-core/src/main/java/org/apache/polaris/core/config/PolarisConfigurationStore.java
Outdated
Show resolved
Hide resolved
polaris-core/src/main/java/org/apache/polaris/core/entity/PolarisEvent.java
Outdated
Show resolved
Hide resolved
...bc/src/main/java/org/apache/polaris/persistence/relational/jdbc/JdbcBasePersistenceImpl.java
Outdated
Show resolved
Hide resolved
...tional-jdbc/src/main/java/org/apache/polaris/persistence/relational/jdbc/QueryGenerator.java
Outdated
Show resolved
Hide resolved
service/common/src/main/java/org/apache/polaris/service/events/AfterTableCommitedEvent.java
Outdated
Show resolved
Hide resolved
...a/org/apache/polaris/service/events/listeners/FileBufferPolarisPersistenceEventListener.java
Outdated
Show resolved
Hide resolved
...a/org/apache/polaris/service/events/listeners/FileBufferPolarisPersistenceEventListener.java
Outdated
Show resolved
Hide resolved
...a/org/apache/polaris/service/events/listeners/FileBufferPolarisPersistenceEventListener.java
Outdated
Show resolved
Hide resolved
...a/org/apache/polaris/service/events/listeners/FileBufferPolarisPersistenceEventListener.java
Outdated
Show resolved
Hide resolved
...a/org/apache/polaris/service/events/listeners/FileBufferPolarisPersistenceEventListener.java
Outdated
Show resolved
Hide resolved
adnanhemani
left a comment
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.
@adnanhemani I must say I'm not at all satisfied with the current state of FileBufferPolarisPersistenceEventListener.
I would be glad to hear further feedback on this if there is anything further than the comments you've left on the review so far!
Have you thought about the event bus in Quarkus / Vertx? This mechanism allows to asynchronously process events in a dedicated thread pool, without hurting the original request latencies.
I did think about Vertx and similar solutions but the largest issue we have is there is no durability guarantees we can provide when using those. If Polaris crashes at any point after which the event is placed on the event bus but not processed, the event is lost and there is no way to recover. Please correct me if I'm wrong here.
...bc/src/main/java/org/apache/polaris/persistence/relational/jdbc/JdbcBasePersistenceImpl.java
Outdated
Show resolved
Hide resolved
polaris-core/src/main/java/org/apache/polaris/core/config/PolarisConfigurationStore.java
Outdated
Show resolved
Hide resolved
polaris-core/src/main/java/org/apache/polaris/core/entity/PolarisEvent.java
Outdated
Show resolved
Hide resolved
...tional-jdbc/src/main/java/org/apache/polaris/persistence/relational/jdbc/QueryGenerator.java
Outdated
Show resolved
Hide resolved
service/common/src/main/java/org/apache/polaris/service/events/AfterTableCommitedEvent.java
Outdated
Show resolved
Hide resolved
...a/org/apache/polaris/service/events/listeners/FileBufferPolarisPersistenceEventListener.java
Outdated
Show resolved
Hide resolved
...a/org/apache/polaris/service/events/listeners/FileBufferPolarisPersistenceEventListener.java
Outdated
Show resolved
Hide resolved
...a/org/apache/polaris/service/events/listeners/FileBufferPolarisPersistenceEventListener.java
Outdated
Show resolved
Hide resolved
...a/org/apache/polaris/service/events/listeners/FileBufferPolarisPersistenceEventListener.java
Outdated
Show resolved
Hide resolved
...a/org/apache/polaris/service/events/listeners/FileBufferPolarisPersistenceEventListener.java
Outdated
Show resolved
Hide resolved
|
From yesterday's discussion: Query patterns & event payload, considering the Iceberg proposal, are still not set in stone - I have mentioned concerns about the IRC proposal as it stands. Considering especially the event payload size issues in that proposal, I think it is way too early to push this one. |
+1 to the above. Also I would like to stress that the need for a commitlog-like structure on disk stems from the design choice to isolate events persistence from catalog persistence. If all writes (catalog and events) were done within the same transaction, we would be leveraging the transactional backend to do the heavy lifting of maintaining those two consistent with each other. And we would get "exactly once" semantics for free. For this reason, I think we need to take a step back and rethink the persistence model. |
...e/service/src/main/java/org/apache/polaris/service/events/BeforeRequestRateLimitedEvent.java
Outdated
Show resolved
Hide resolved
runtime/service/src/main/java/org/apache/polaris/service/events/BeforeTableCommitedEvent.java
Outdated
Show resolved
Hide resolved
runtime/service/src/main/java/org/apache/polaris/service/events/AfterTableCreatedEvent.java
Outdated
Show resolved
Hide resolved
runtime/service/src/main/java/org/apache/polaris/service/events/AfterCatalogCreatedEvent.java
Outdated
Show resolved
Hide resolved
polaris-core/src/main/java/org/apache/polaris/core/entity/PolarisEvent.java
Show resolved
Hide resolved
...g/apache/polaris/service/events/listeners/InMemoryBufferPolarisPersistenceEventListener.java
Outdated
Show resolved
Hide resolved
...ache/polaris/service/events/listeners/InMemoryBufferPolarisPersistenceEventListenerTest.java
Show resolved
Hide resolved
...g/apache/polaris/service/events/listeners/InMemoryBufferPolarisPersistenceEventListener.java
Outdated
Show resolved
Hide resolved
...ache/polaris/service/events/listeners/InMemoryBufferPolarisPersistenceEventListenerTest.java
Outdated
Show resolved
Hide resolved
...g/apache/polaris/service/events/listeners/InMemoryBufferPolarisPersistenceEventListener.java
Outdated
Show resolved
Hide resolved
adutra
left a comment
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.
This is almost ready to go 👍
...va/org/apache/polaris/service/events/listeners/ConcurrentLinkedQueueWithApproximateSize.java
Outdated
Show resolved
Hide resolved
...va/org/apache/polaris/service/events/listeners/InMemoryBufferEventListenerConfiguration.java
Show resolved
Hide resolved
...g/apache/polaris/service/events/listeners/InMemoryBufferPolarisPersistenceEventListener.java
Outdated
Show resolved
Hide resolved
|
|
||
| abstract String getRequestId(); | ||
|
|
||
| abstract void addToBuffer(org.apache.polaris.core.entity.PolarisEvent event); |
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.
it should be that they are not processed in any OSS implementation
Why? Is there a compelling reason for excluding such events upfront?
Imho OSS implementations should stay very "general-purpose" and apply the same processing logic to all events.
...ache/polaris/service/events/listeners/InMemoryBufferPolarisPersistenceEventListenerTest.java
Outdated
Show resolved
Hide resolved
jbonofre
left a comment
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.
It looks good to me, thanks !
It's a great start and we can always update later.
As @snazy is on vacation, in order to unblock this PR, I dismiss this review.
| if (containerRequestContext != null && containerRequestContext.hasProperty(REQUEST_ID_KEY)) { | ||
| return (String) containerRequestContext.getProperty(REQUEST_ID_KEY); | ||
| } | ||
| return UUID.randomUUID().toString(); |
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.
Minor: having a fake request id may cause issue when users are trying to debug with it, as it doesn't exist anywhere else. I think the containerRequestContext mighty always have one. At least, it's more of the containerRequestContext's responsibility to generate one if it's missing. For event, we could just use what containerRequestContext has.
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.
Changed.
| buffer.computeIfAbsent(realmId, k -> new ConcurrentLinkedQueueWithApproximateSize<>()); | ||
| realmQueue.add(polarisEvent); | ||
| if (realmQueue.size() >= maxBufferSize) { | ||
| futures.add(executor.submit(() -> checkAndFlushBufferIfNecessary(realmId, true))); |
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.
It would be a nice improvement if we don't add a duplicated future into the set.
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.
Added new logic for this.
flyrain
left a comment
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.
Thanks a lot for working on it @adnanhemani !
As per my proposal on the Dev ML, this is the implementation of persisting Polaris Events to a persistence. The overall goal for this PR is to store Events in the Polaris persistence layer - which will later be used to power the Iceberg Events API.
High-level overview of the changes:
and file-based bufferimplementation for flushing events to the persistenceHere are the following upcoming items that will be updated in this PR soon:
Upcoming items that will be tackled in subsequent PRs (and were excluded to ensure that this PR contains only the end-to-end MVP):