Modeling a simple MMO game entities as actors? Is it OK?

372 views
Skip to first unread message

Amir Karimi

unread,
Jun 18, 2015, 3:57:30 AM6/18/15
to akka...@googlegroups.com
Hi,

I'm working on a simple MMO game as a side project which is like Travian. I've decided to use Akka as the game back-end, so I would like to share my design with you. Your suggestions and feedbacks are very appreciated.

Each of the following entities are modeled as an actor:
- Player
- Village
- Building of a village
- etc.

Villages have some resources which are constantly decreasing or increasing based on multiple factors like buildings level, village population, etc. (Clearly, I'm not going to change the resource values periodically but I save the last resource value, its time and the coefficient of increase or decrease.)

Each player may have multiple villages. As villages can be conquered by other players, each village has an state for it's owner player (e.g. playerId or playerActorRef) and also a player has a list of his/her own villages (village actors or IDs).

Each village may contains multiple buildings. As buildings won't be moved and owned by other villages, they will be created as village actor children. So the buildings will communicate with their village through `context.parent`.

For persisting the game world state I'm going to use Akka persistence module.

This is the fundamental of my design although I have several concerns:
  • I'm not sure if players profile information should be stored into the database or into the player actors (as states).
  • According to 80/20 rule, I except 80% of the players to be much less active than the others but their corresponding actors are still resident in the memory even if they have no activity at all. What are the best practices to reduce the RAM usage for those?
  • How can I show the statics and other information in the admin panel? For example I want to be able to search among players and get their information. I know I can use actorSelection with wildcard but what about data pagination? I'm not going to load all players information.
First of all please let me know if this is a good idea to use actors for such project. I'm not sure if this approach will make things more complex or simpler.

Thanks a lot,
Amir

Guido Medina

unread,
Jun 18, 2015, 7:25:03 AM6/18/15
to akka...@googlegroups.com
You can set context time out for actors, if they don't receive a message within some time passivate them, activate them at login, that way you don't have to lazy load when the player is active but at login which will basically happen asynchronously.

Now, Akka experts should tell us if setting context timeout for many active actors is a bad idea.

HTH,

Guido.

Amir Karimi

unread,
Jun 19, 2015, 2:48:43 AM6/19/15
to akka...@googlegroups.com
I think It's not enough. There are events which will happen when the user is not logged in. For example an attack on a village (which its owner is inactive) or occupation of that village also generates a message to the owner player actor (which is not resident) as well. So I can't activate them just at login times.

Guido Medina

unread,
Jun 19, 2015, 3:10:40 AM6/19/15
to akka...@googlegroups.com
You can activate an actor if not present, as long as you send the message to its supervisor, so you have to keep say, supervisors per zone? and each supervisor will try to send/forward the message to such child and if not present create it.

This is an example in Java where I do the same thing for account, the accounts actors are not eagerly created but on demand, the following method is inside the supervisor actor class:

private void applyToAccount(Currency currency, BalanceOperation operation) {
   
final ActorContext context = context();
    context
.child(currency.code).
      getOrElse
(new AbstractFunction0<ActorRef>() {
       
@Override
       
public ActorRef apply() {
         
return context.actorOf(balancePersistorProps(currency), currency.code);
       
}
     
}).tell(operation, noSender());
 
}

HTH,

Guido.

Nikita Melkozerov

unread,
Jun 19, 2015, 3:23:35 AM6/19/15
to akka...@googlegroups.com
I'd recommend you to look at Akka Persistence. You can store entitiy as PersistentActor, and collect statistics by corresponding PersistentView.

Also, you can employ Cluster Sharding and use passivation to remove inactive entities from RAM.

Amir Karimi

unread,
Jun 19, 2015, 4:07:58 AM6/19/15
to akka...@googlegroups.com
Thanks Guido, this is good idea but as I'm not going to make this game distributed (at least in the near future) I feel this approach increases the complexity and I don't know what would I get instead of this complexity? (except for RAM usage optimization)

The reason why I decided to use Akka is to make things simpler. For example I believe Akka would help me to handle the game entity states in a very simple and concise way. But it introduces new concerns about RAM usage. It can be handled with the help of Akka persistence and supervisors although it's not as simple as I thought.
--
>>>>>>>>>> Read the docs: http://akka.io/docs/
>>>>>>>>>> Check the FAQ: http://doc.akka.io/docs/akka/current/additional/faq.html
>>>>>>>>>> Search the archives: https://groups.google.com/group/akka-user
---
You received this message because you are subscribed to a topic in the Google Groups "Akka User List" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/akka-user/IAyHHn1vJL4/unsubscribe.
To unsubscribe from this group and all its topics, send an email to akka-user+...@googlegroups.com.
To post to this group, send email to akka...@googlegroups.com.
Visit this group at http://groups.google.com/group/akka-user.
For more options, visit https://groups.google.com/d/optout.

Guido Medina

unread,
Jun 19, 2015, 6:35:18 AM6/19/15
to akka...@googlegroups.com
Say you don't have zones or any sort of grouping, you need at least one supervisor, I wouldn't recommend you to make all your players top level actors where their parent is /user, you need a fast way to locate "a player" and context().child(...) is such way IMHO, sharding with persistent actor is another way which was mentioned but it adds more complexity to your design, you don't need to de-activate actors though, maybe you just lazy load them with the method I gave you but again, you need one supervisor, you will be surprise how many millions of actors you can hold in memory, do you have millions of players?

If so then you are rich and we are talking of distributed gaming and stuff :D

Amir Karimi

unread,
Jun 19, 2015, 6:56:40 AM6/19/15
to akka...@googlegroups.com
You're absolutely right. I need at least one supervisor (or maybe two; one for players and one for villages as they are top level actors). This way I can deactivate and lazy load them as you said.

And yes I don't have millions of players :D but I hope some day I'll ;)

But seriously, as I won't have millions of users (I'm planning for 50K at max) what about keeping all actors in memory? It will make everything easier and faster.

Guido Medina

unread,
Jun 19, 2015, 7:25:47 AM6/19/15
to akka...@googlegroups.com
50K is like zero for current and modern hardware, so, I would say, load them lazily from your players' supervisor and don't expire them until you start seeing a problem, expiring them would require you only to set context time out at preStart() and then handle the timeout message which would be to just send a poison pill to your actor.

There is another detail though, for the sake of concurrent delivery under high load, you would be receiving all messages at that one supervisor, do you think that will scale well? say you have 1000 attacks, you will have to forward one at a time, so the concept of zone -think of it as a shard or hash- is not a bad idea, a way to minimize coalition.

Guido Medina

unread,
Jun 19, 2015, 7:27:39 AM6/19/15
to akka...@googlegroups.com
You could even have the concept of lazily load the zone and each zone lazily load the players.

Guido Medina

unread,
Jun 19, 2015, 7:30:09 AM6/19/15
to akka...@googlegroups.com
Nvm, that would run into the same problem, instead, eagerly load the player's zone -a supervisor for a bunch of players- and then lazily load the player per zone, that will keep your actors distributed and also will prepare your code to use these zones as shards when the game grows.

Amir Karimi

unread,
Jun 19, 2015, 7:37:43 AM6/19/15
to akka...@googlegroups.com
Yes it would be very nice. But I have no idea how to find a player zone. Suppose player A want to attack player B. First we need to find out the player B zone (to find it's supervisor). Right? Then we need an actor which knows about the players zone. That would be the bottleneck again.

Guido Medina

unread,
Jun 19, 2015, 8:01:00 AM6/19/15
to akka...@googlegroups.com
Do you have player IDs? design your application to have zones divided by a number -preferably a power of 2-, say, 64, now you have 64 evenly distributed "shards" so to send a message to player ID = 1001 then you just need to 1001 mod shards, no look up needed, it is just a convention you are using.
...

Guido Medina

unread,
Jun 19, 2015, 8:08:44 AM6/19/15
to akka...@googlegroups.com
Another option, if you don't have player ID but a sort of ID as string, say, attach player "oxygen8", get the hash of that string and apply the same formula, so you have 64 shards, so the supervisor of that player is "oxygen8".hashCode() % 64

Amir Karimi

unread,
Jun 19, 2015, 8:26:51 AM6/19/15
to akka...@googlegroups.com
Yes that would be easy and scalable!  Just out of curiosity, what if a zone get too active? In another world how can we have asymmetric zones so that we can balance zones pressure by moving active players between them.

The first thing that comes to mind is that players shouldn't have any idea about the zone their live in. Whenever we need to find out a player zone we send a message to all zones asking about the player and wait for the response from the zone in which the player actor lives. The problem is that the player may have been moved to another zone in the middle of the finding process :(

It seems like the cellular mobile network. How can they find the BTS to which my phone is connected?

Guido Medina

unread,
Jun 19, 2015, 8:43:46 AM6/19/15
to akka...@googlegroups.com
If your number of shards is high enough and your hashcode is smart enough coalitions should be very minimal, I think you should have stats of how many players you have per shard and how busy shards get, and between restarts -maintenance time-, redo your numbers and hashcode formulas, otherwise you will have to do what hash maps implementations do when there are to many coalitions which is to redistribute all the shards, up to you which one you go for, I would say, pick a high number of shards like 1024, then you will have avg of 50 players per shard.
...

Guido Medina

unread,
Jun 19, 2015, 8:49:51 AM6/19/15
to akka...@googlegroups.com
And don't worry about performance, assuming each shard has a pattern of Single Consumer - Multiple Producer, make sure the inbox type for shards and players is SingleConsumerOnlyMailbox which is a the fastest Akka mailbox atm.

Amir Karimi

unread,
Jun 19, 2015, 9:06:48 AM6/19/15
to akka...@googlegroups.com
These technologies and architectures are so appealing to me but I'm still in doubt  whether I should follow these interesting approaches or just make a traditional software (with a monolithic database-driven model). Although this is a side project, it's very important to me. I should get it done.

Anyway, thanks a lot Guido for your kind advices.
--

Guido Medina

unread,
Jun 19, 2015, 10:17:13 AM6/19/15
to akka...@googlegroups.com
Trust me you don't want to do concurrency by yourself even if you are an expert at it, asynchronous design is the way to go, with Akka that concern is easy enough and you will be able to focus only on the business logic and produce results, the last thing I'm going to Advice you is to not underestimate the documentation, specially the first 3 parts, I had to learn Akka in few weeks and that helped me the most to the point that I had no question but only the tricky ones.
...

Amir Karimi

unread,
Jun 19, 2015, 10:19:40 AM6/19/15
to akka...@googlegroups.com
I completely agree with you. Thanks again :)
--
>>>>>>>>>> Read the docs: http://akka.io/docs/
>>>>>>>>>> Check the FAQ: http://doc.akka.io/docs/akka/current/additional/faq.html
>>>>>>>>>> Search the archives: https://groups.google.com/group/akka-user
---
You received this message because you are subscribed to a topic in the Google Groups "Akka User List" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/akka-user/IAyHHn1vJL4/unsubscribe.
To unsubscribe from this group and all its topics, send an email to akka-user+...@googlegroups.com.
To post to this group, send email to akka...@googlegroups.com.
Visit this group at http://groups.google.com/group/akka-user.
For more options, visit https://groups.google.com/d/optout.

Luis Medina

unread,
Jun 19, 2015, 12:23:33 PM6/19/15
to akka...@googlegroups.com
Personally, I wouldn't organize your actors into "zones" since zones aren't really a concept that would exist in your game and like you pointed out, it can make scaling a bit tricky. The approach that I would take is to use clustering along with sharding to distribute your actors across however many machines you have at your disposal for the project. 

If you do end up using sharding, I'm not entirely sure if you would really need to have specialized supervision actors. From what I gather from previous comments, it seems that supervision would mainly be used as a way to quickly get to your child actors (ie. for player and villages) which seems unnecessary since this is something that you can already do quickly enough through ShardRegions/ShardCoordinator.

I agree with Guido's original comment in that you should probably use passivation to bring down actors that aren't used often if you want to save on resources. To do this, you will need to use Akka persistence (which you have to do anyways if you plan to use sharding since the ShardCoordinator needs it to recover from failure) in order to save the states of those actors so that they can get restored when they come back up (say if a user logs in again). Now for this, I would probably go for a distributed journal which will allow you to scale much better in the future even if your game does start out small. There are plenty of plugins that have been made by the community for various data stores so choosing one that is easy for you to work with shouldn't be too difficult.

You brought up another concern of how will downed actors for players/villages know of events that occur (ie. a village attack) while they are down. For this, you might consider using some sort of messaging queue (ie. Kafka) where these events get stored as they happen. Then when these actors do come back up, one of the first things that the actors would do after restoring their previous state from Akka persistence, would be to go into this message queue and retrieve the latest events in sequential order and apply them to their current state (kind of like what Akka persistence does during the recovery process except that this time you're sort of programming it yourself). For this you could probably organize it in such a way where every village/player has it's own partition based on its id. The reason why I would go with Kafka is because it scales much better than RabbitMQ and it persists things to disk. This approach would probably work best for your player actors although I'm sure you can make something of it for your village actors as well. I haven't thought this part through but I'll leave it up to you to figure out the details :)

Guido Medina

unread,
Jun 19, 2015, 1:38:56 PM6/19/15
to akka...@googlegroups.com
I do agree with Luis, but I wasn't pushing much that approach because AFAIK you are new to Akka and you have only one server, the concept of sharding and Akka persistence can be overwhelming at first, but if you read between the lines, the hash code approach I proposed initially is the skeleton of any sharding mechanism, which isn't more than hash maps and hash codes in steroids, it will help you study better the behavior of your players, game and actions as it evolves which will lead you to: Wait, this sharding distribution I'm using is just what Akka Sharding does.

Now I don't like to jump from zero to the extreme because to get there you have to dominate the framework you are using, the evolution to such advanced stage should come natural, if you force it and try all in a single small project from the beginning you might just give up because of the overwhelming factors and technical issues I'm sure you will face.

HTH,

Guido.

Amir Karimi

unread,
Jun 19, 2015, 3:05:19 PM6/19/15
to akka...@googlegroups.com
You are right Guido, I never used Akka in production though I have implemented several successful applications with Scala, Play and ReactiveMongo. And there is a single server with 50K user at maximum. Certainly, supporting more users and advanced scenarios would be great but as I said I fear I'm involved in technical issues more than the real work. Maybe I'm wrong!
--
>>>>>>>>>> Read the docs: http://akka.io/docs/
>>>>>>>>>> Check the FAQ: http://doc.akka.io/docs/akka/current/additional/faq.html
>>>>>>>>>> Search the archives: https://groups.google.com/group/akka-user
---
You received this message because you are subscribed to a topic in the Google Groups "Akka User List" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/akka-user/IAyHHn1vJL4/unsubscribe.
To unsubscribe from this group and all its topics, send an email to akka-user+...@googlegroups.com.
To post to this group, send email to akka...@googlegroups.com.
Visit this group at http://groups.google.com/group/akka-user.
For more options, visit https://groups.google.com/d/optout.

Luis Medina

unread,
Jun 19, 2015, 7:36:05 PM6/19/15
to akka...@googlegroups.com
I just saw this really interesting presentation from Scala Days that Martynas posted in another thread that talks about scaling with Akka. I think it will give you some ideas for how to design your app in a way that scales even if you are starting out small right now.


On Thursday, June 18, 2015 at 12:57:30 AM UTC-7, Amir Karimi wrote:

Luis Medina

unread,
Jun 19, 2015, 7:36:38 PM6/19/15
to akka...@googlegroups.com
Oops, forgot to post the link: https://www.parleys.com/tutorial/easy-scalability-akka (you'll need to register a free account to view the full video).

Amir Karimi

unread,
Jun 19, 2015, 11:53:58 PM6/19/15
to akka...@googlegroups.com

Thank you Luis.

--

Justin du coeur

unread,
Jun 22, 2015, 1:23:42 PM6/22/15
to akka...@googlegroups.com
Jumping in a bit late, but one comment:

On Fri, Jun 19, 2015 at 1:38 PM, Guido Medina <oxy...@gmail.com> wrote:
I do agree with Luis, but I wasn't pushing much that approach because AFAIK you are new to Akka and you have only one server, the concept of sharding and Akka persistence can be overwhelming at first

Honestly, I think you're overstating the complexity of sharding.  Having recently moved from my home-brew machinery for doing all this stuff to using Cluster Sharding, my code got *enormously* simpler.  Really, I was kind of startled by how easy it is to use.

Yes, there's a lot going on behind the scenes.  But for a simple application, you don't need to worry about it.  So long as you have a clean identifier for your target Actors and a way to extract the target Actor's identifier from your messages, it takes next to no time to implement a system based on Cluster Sharding, and you can just let it deal with all the annoying stuff like when to construct the Actors, finding the target Actor you're looking for, passivation and so on.

Really, for the described game I'd go for Cluster Sharding in a heartbeat.  It's the easiest way to build it, and it means that you *can* cluster it later if you decide you want to, with relatively little effort...

Amir Karimi

unread,
Jun 23, 2015, 1:33:00 AM6/23/15
to akka...@googlegroups.com
Thanks for the link. It was exactly about what I needed.
--
>>>>>>>>>> Read the docs: http://akka.io/docs/
>>>>>>>>>> Check the FAQ: http://doc.akka.io/docs/akka/current/additional/faq.html
>>>>>>>>>> Search the archives: https://groups.google.com/group/akka-user
---
You received this message because you are subscribed to a topic in the Google Groups "Akka User List" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/akka-user/IAyHHn1vJL4/unsubscribe.
To unsubscribe from this group and all its topics, send an email to akka-user+...@googlegroups.com.
To post to this group, send email to akka...@googlegroups.com.
Visit this group at http://groups.google.com/group/akka-user.
For more options, visit https://groups.google.com/d/optout.
Reply all
Reply to author
Forward
0 new messages