ddubbert / dub.io

Agar.io clone based on Continuous Event Streams and Microservices. Implemented with Node.js, GraphQL and Apache Kafka.
MIT License
1 stars 0 forks source link

How should events be defined ? #4

Closed ddubbert closed 4 years ago

ddubbert commented 4 years ago

There are two possibilities:

  1. Send the events for each user by itself. This is a more fine granular and flexible approach but might need more processing effort. Processing services will need to hold state to be able to compare game object positions and detect collisions. Scaling with Kafka Consumer Groups is harder, because events depend on others and services would need to be synchronised.

  2. Bundle the events for each user into a bigger structure. Events are bigger and might need more transfer time but services are allowed to be stateless, because all the data they need is bundled and served by the event. In addition, Kafka Consumer Groups can be used for scaling without the need of any synchronisation between services for the same task.

The speed of those approaches is the dominant question in such a realtime environment.The game should at least be able to provide framerate of 30fps (but 60fps would be better). A Proof of Concept should be made for testing each approach before making a decision.

ddubbert commented 4 years ago

Different PoCs have been created and their time for sending and receiving 30000 events with different sizes have been measured (single and grouped events, groups consisting of 1000 events). The amount of 30000 was chosen because it represent the events needed for displaying 1000 users with 30fps. One try also has been with 60000 grouped events (grouped to messages of 1000) to test for 60fps. For all of them an average value has been calculated out of 5 tries. The events are also serialized / compressed with the help of avro-schemas. The sizes before and after compressing are also listed.

Single Events, 30.000, 38 Bytes / 8 Bytes: (Broker 1 & Partitions 3 & Replica 1)

Grouped Events, 30.000, 38018 Bytes / 8003 Bytes: (Broker 1 & Partitions 3 & Replica 1)

Grouped Events, 60.000, 38018 Bytes / 8003 Bytes: (Broker 1 & Partitions 3 & Replica 1)

Grouped Events, varying Sizes, try to keep 60 messages per second: (Broker 1 & Partitions 3 & Replica 1)

Tested by multiplying following data structure several (thousand) times:

{ id: 100, x: 100, y: 150 }
ddubbert commented 4 years ago

It seems, that the size of a message hasn't got as much impact on the performance as the amount of messages send and the time needed for each transaction. Having bigger messages results in less messages which will improve the performance factor. Whenever it is reasonable to group events, it should be done. In addition an acknowledgment factor of "none" will be used. Loosing single events in this context is worse than loosing all events of a frame because users could be favored while others would be neglected (e.g. users might move while others wont). Lastly the average values of grouped events show that message-wise a frame rate of much more than 60 fps would be possible. The bottleneck will be processing all of these events and rendering the game.

Yet the size should be considered. Even though the program wont need to send multiple thousands of nodes per event (will only be like 100 - 1000 nodes on the board), the size of each node will be higher than the data structure used for testing. A maximum size of something between 400004 Bytes (0.400004 MB) and 520004 Bytes (0.520004 MB) should be targeted to compensate for multiple Topics, parallelism and latency.