使用事件溯源提高了Elasticsearch的效能 - luis-sena
Elasticseach 並不真正支援更新。在 Elasticsearch 中,更新總是意味著刪除+建立,持續不斷的文件更新可能會使 Elasticsearch 叢集癱瘓。幸運的是,有辦法避免這種情況。
最終的解決方案包括使用事件溯源設計模式將所有需要儲存的更改轉換為事件。此案例的應用程式狀態將儲存在 Elasticsearch 中。
解決方案的第二部分是我們如何儲存該狀態。
我們需要將對每個文件的所有更改組合到一個操作中。這意味著在某些情況下有一個值列表,而在其他情況下只保留最後一次更改(如使用者名稱更改)。為了確保狀態一致,我們需要保證針對同一文件的事件的順序,否則我們可能會面臨狀態與我們的真實來源不匹配的風險。
該解決方案基於流的概念。我使用的是 Kafka,但 Redis Streams 或 AWS Kinesis 都可以正常工作。
這個想法是將所有新更改(如新關注者、使用者名稱更改等)儲存在分割槽主題中。確保您的分割槽鍵與文件 id 一致以保證順序,但也要避免每個使用者 id 一個分割槽,否則您將殺死 Kafka 叢集。
順序對於覆蓋最後一個欄位值(如使用者名稱更改)的事件很重要。我們要確保我們堅持使用最後一個版本而不是中間版本。
為了處理這些訊息,我們需要一個流處理解決方案。對於此示例,我將使用Faust,但它是如此簡單的模式,我建議您使用更適合您的模式。
import base64 import os import random import faust # Models describe how messages are serialized: # {"user_id": "3fae...", username": "my_new_username"} class UserEvent(faust.Record): user_id: str username: str follower_id: str following_id: str app = faust.App('es_event_processor', broker='kafka://broker') topic = app.topic( 'user_events', key_type=str, value_type=UserEvent ) def add_value(user_docs, user_id, key, value, op): if user_id not in user_docs: user_docs[user_id] = {} if op == 'set': user_docs[user_id][key] = value elif op == 'append': if not user_docs[user_id][key]: user_docs[user_id][key] = [] user_docs[user_id][key].append(value) @app.agent(topic) async def user_event_consumer(user_events): """ Very simple way to aggregate user events and storing them into ES Other options like aggregating into another kafka topic or using RocksDB table is also valid :param user_events: :return: """ print("starting agent") # get 1000 messages with 30s timeout async for lst in user_events.take(1000, within=30.0): user_docs = {} for user_event in lst: if user_event.username: add_value(user_docs, user_event.user_id, 'username', user_event.username, 'set') if user_event.follower_id: add_value(user_docs, user_event.user_id, 'follower_id', user_event.follower_id, 'set') if user_event.following_id: add_value(user_docs, user_event.user_id, 'following_id', user_event.following_id, 'set') # ES Load logic goes here # user_docs already has the aggregated data ready to bulk load into the index # or even multiple indexes print(len(user_docs.keys())) @app.timer(interval=0.5) async def example_sender(app): """ Used to simulate user interactions with the system like username change, add follower, etc :param app: :return: """ print("preparing msg") user_id_lst = ['er56kmn', 'oiuh76n', 'df47kj'] user_id = random.choice(user_id_lst) extra_kwargs = {} if random.randint(0,10) >= 5: extra_kwargs['username'] = f'c{base64.urlsafe_b64encode(os.urandom(6)).decode()}' user_event = UserEvent( user_id=user_id, follower_id=f'c{base64.urlsafe_b64encode(os.urandom(6)).decode()}', following_id=f'c{base64.urlsafe_b64encode(os.urandom(6)).decode()}', **extra_kwargs ) await topic.send( key=user_id, value=user_event, ) print("sent msg") if __name__ == '__main__': app.main() |
相關文章
- 使用Kafka實現事件溯源Kafka事件
- 事件協作和事件溯源事件
- 事件流與事件溯源事件
- PHP 事件溯源PHP事件
- Rust中的事件溯源 - ariseyhunRust事件
- 剖玄析微聚合 - 事件溯源事件
- Chronicle事件溯源的最佳實踐事件
- 使用EventStoreDB實現事件溯源的Java開源專案事件Java
- 使用Datomic實現沒有麻煩的事件溯源事件
- 如何讓客戶方便地使用事件溯源?事件溯源有什麼好處?- daryush_d事件
- 事件溯源全指南 - Arkwrite事件
- 事件溯源不是什麼?事件
- 事件消費者之 Projector - 事件溯源事件Project
- 事件消費者之 Reactor - 事件溯源事件React
- 說服您的CTO使用事件溯源 -Event Store Blog事件
- 使用EventStoreDB實現事件溯源的Python開源專案事件Python
- Python的事件溯源開源庫Python事件
- .NET的事件溯源構建庫:Eventuous事件
- 事件消費者之 Saga - 事件溯源事件
- Linux中的getrandom()方法效能提高了8450% - PhoronixLinuxrandom
- 使用AsyncAPI規範簡潔實現CQRS事件溯源案例API事件
- 事件溯源與流水賬的結賬模式事件模式
- Occcurrent:JVM事件溯源工具庫包JVM事件
- .NET分散式Orleans - 6 - 事件溯源分散式事件
- 事件溯源:是來自事件的狀態與作為狀態的事件? - verraes事件
- 在微服務中使用事件溯源的六大原因 - Herath微服務事件
- 新的谷歌電視更新提高了效能和儲存谷歌
- MySQL的事件溯源Event Sourcing表結構MySql事件
- 從 CRUD 遷移到事件溯源的祕訣 - eventstore事件
- 拯救祭天的程式設計師——事件溯源模式程式設計師事件模式
- .NET Core中的事件溯源開源專案事件
- 審計系統的一劑良方——事件溯源事件
- Java反應式事件溯源:領域Java事件
- 從增刪改查到事件溯源 - PHP事件PHP
- 從入門到放棄 - 事件溯源事件
- HomeAway分享雲端事件溯源經驗事件
- Spring Boot和EventStoreDB事件溯源案例Spring Boot事件
- 什麼是事件溯源Event Sourcing?事件