arpan
Hi Everyone ![]()
I am making a multiplayer game and that uses phoenix as the backend. Its heavily dependent on Phoenix channels, there is no database all data is stored in ETS.
Now, currently, I have used a Genserver backed ETS store as shown here.
From what I read ETS is very fast and should not be a bottleneck, however, I also understand that genservers process messages sequentially.
Now all the game state is stored in a single ETS table. There is a genserver GameStore which provides a public API to perform operations on the single-game ETS table.
All game data will be in the same table with the game id as the key and a struct as the value.
When the number of users on the website increases there could be a case when say 100 games are played at once, and every game will frequently change its state which requires updating or reading from the ETS table by making calls to the GameStore genserver.
I am wondering how this setup will perform under heavy load, will this single genserver be a bottleneck?
Some other approaches that I am thinking of are…
-
Having a pool of worker genservers who can query the ETS table, so under load, some other genserver can pick up messages.
-
Spawning a genserver for every game, all managed by a DynamicSupervisor. So we have a genserver for each game that can query that game-specific data from ETS. Also, going by this approach should this genserver also create an separate ETS table only for that game, when the game is over the table is deleted

Or any other better approach that you can suggest.
But all these things will add complexity to the code and I only want to consider these if the present setup could be a bottleneck.
Can anyone help me with these approaches and also it will be very helpful if you can provide some code reference or links explaining how to manage genserver pools or dynamically spawning genservers if you are suggesting those solutions.
Thanks!
Trending in Questions
Other Trending Topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #library
- #deployment
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #elixirconf
- #channels
- #exunit
- #discussion
- #code-sync
- #podcasts
- #javascript
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixirconf-us
- #ai
- #blog-post
- #elixir-ls
- #phoenix_html
- #iex
- #graphql
- #genstage
- #websockets
- #supervisor
- #advent-of-code
- #distillery
- #processes
- #api
- #forms
- #metaprogramming
- #hex
- #security










Showing Posts 1 to 10- Show Best Posts
- Show All (oldest first)
- Show All (newest first)
mindok
First things first, can you create a load simulator so you can test performance under different loads? That way you will know what needs fixing when, and whether the fixes are good.
100 games isn’t really a heavy load (depending on frequency of updates per game), but piping all activity through a single process (particularly one that “owns” the ets table) will end in tears before too long - one bad input will crash all games for all users. OTP is all about isolating “conversations” so one failure doesn’t affect thousands or millions of connections.
Your second option (GenServer per game) makes sense. Whether or not your second option is absolutely the best I don’t know, but you should try coding it anyway - you will learn some key lessons along the way and it shouldn’t introduce much complexity overall in return for improved reliability and responsiveness.
This article will give you some pointers: The Erlangelist - To spawn, or not to spawn?
LostKobrakai
Also be sure to understand the difference between sequencing writes by going through the genserver process for writing to ets vs. having the ets table be public and directly writing to it without involving the genserver starting the table.
axelson
Here’s another good blog post I’d recommend you read to understand the performance better: The dangers of the Single Global Process
mattbaker
I was thinking the same thing as @LostKobrakai.
If it’s a named table you don’t necessarily need these interactions to happen in a “handle_call” for example.
I’m actually not sure I agree with that approach in the thoughtbot article, it’s unclear to me what the advantage is of reads and writes going through the genserver process in their example.
If this genserver is nothing but a wrapper around your ETS operations, you might try building it without a genserver first, then add one later, just as a learning tool.
arpan
Thanks for replys everyone.
@mindok
Yes that’s exactly what I am worried about, the Genserver might become a bottleneck very fast, regarding the genserver crashing I think that won’t be a problem since it’s under a supervisor which would restart it and the genserver has no state everything is in ETS so we should be fine.
@LostKobrakai
Yea, currently the genserver crates the ETS table in its
initcallback like:ets.new(@table_name, [:named_table, :set, :private]).This means only the genserver process is allowed to access the ETS table as its private. This will have to change if I have a genserver per game.
Making all ETS table access through the genserver will sequence writes as you mentioned, but I am not sure if there will be problems if the ETS table is public and accessed by multiple genservers(each game has its own genserver). Each genserver should access only its own game and not the data for some other game, so I think there shoudl be any problems.
@mattbaker
Yes that is exactly my thinking as well, the only use of genserver here is I think if we want to make the ETS table only acessible via the genserver process and also starting the genserver will create the table.(but I think just for creating the table we don’t need a genserver).
I am sharing the game genserver code that I have written for reference, there will be many more
handle_calladded as I make the gameThe below genserver is supervised by a
Pictionary.StoreSupervisorso it will restart if it crashes for some reason.paulstatezny
I thought ETS was optimized for super fast reads at the cost of slower writes.
Am I correct? If so, ETS may not be the most performant option unless you write to it infrequently. (And I assume this may not be the case for a game.)
a8t
I implemented something extremely similar to the thoughtbot article recently (for generating random slugs for urls, fetch either gets or sets and returns).
The difference is that I’m only using the Genserver to handle the ets table lifecycle, since ets tables are tied to processes.
The functions to get and set to the ets table are defined in the same module, but as regular functions that directly read/write to ets, without handle_call’ing.
I am open to criticism here as a newb (this is in fact my first Genserver! Lol), but it seems to have the best of both worlds.
krasenyp
Your approach is the most appropriate for most use cases. OP should probably do the same as you.
keathley
This isn’t quite accurate. ETS tables do have config options to optimize reads or optimize writes, and setting either option to true will tend to slow down the inverse operation (depending on table type). But neither of those configs are set to true by default.
arpan
I doubt whether this approach would work. Actually, ETS tables have some rules around accessibility. In my implementation, the ETS table I create is private this means only the process which created it(the genserver) can access it.
The functions to get and set in ETS tables should be called from the genserver process other wise you will not be able to access the table unless you have less strict access rule like public.
I don’t think having the functions defined in the same module will be of help if the process of trying to access them is not the genserver process. If you access the ETS table in genserver callbacks like
handle_callorhandle_castit will be the genserver process that will be accessing the ETS table so that should work.I have limited experience with genservers please correct me if I am wrong, but I just shared my idea of how I think it works.