I recently learned about the akka,but some idea I can't grasp.
my question is, if there are too many message in queue,will a new actor be created?
in many framework,for example, one http-requet message coming,and the framework found that the current "worker" are busy,so the framework will create another "worker " to process the new message in another thread.
but it seems the akka doesn't do this way,there is only one actor instance.
so I think the "busy actor" will bocking the queue, which will hit the throughout and performance , am I correct?
Each Actor stores their messages in a Mailbox.
http://doc.akka.io/docs/akka/current/scala/mailboxes.html
The default mailbox is unbounded and non-blocking. If your actor cannot process messages quickly enough, their mailbox balloons in size and consumes increasing amounts of RAM. You can configure Akka to use a bounded, blocking Mailbox which will block the sender when over capacity.
If you would like to dynamically manage a pool of actors, look into Routing strategies.
http://doc.akka.io/docs/akka/2.4.1/scala/routing.html
You can create a Router Actor that receives messages and passes them to routee actors. The Router also manages the routee pool and can dynamically generate routees as needed.
Also, if using Future and callback asynchronous execution, your actors will not block on http requests.
TL;DR:
If you send messages faster than your Actor can process them, eventually your application will start dropping messages.
Longer answer:
As I understand, every Akka Actor has a Queue associated with it, which holds all the messages it receives.
If you send messages to this Actor, faster than the Actor can process them, eventually the queue will overflow, since messages on the queue are kept in ram.
It is not possible to spawn another Actor, on the fly. Since the messages on the queue are processed in order. This ordering will be broken if more than one consumer exists.
I would suggest you take a look at Akka Streams, this is a higher level API built on top of actors, and guards you against this kind of thing by providing backpressure throughout your system. This means that if the actor you're sending messages to is slower than whoever is producing the messages, the consumer will ask the producer to slow down, and will not overflow your Actor's queue.
Related
I have question about ActorSelection/Receptionist in new Akka Typed.....
Before Akka Typed I didn't use ActorSelection because I read somewhere that it was not performant so I kept reference to the actor over HashMaps, now I am reading the documentation of the Akka Typed, I see that another mechanism Receptionist exist, so for me the question is, does it also suffers the same problems ActorSelection and I should stick to my old pattern of keeping reference to Actor over HashMap or now the receptionist is the way to go....
My specific scenario, my Actor spawns several Child Actors creates several Child Actors, if the parent Actor passivates or restored over Akka Persistence, it should again find reference to these Child Actors....
So what do you think, would I experience Performance problems if I convert to Receptionist?????
Thx for answers...
ActorSelection will resolve the actor path to an ActorRef each time you use it, this is somewhat costly, if used for a high throughput actor but has the upside that if the actor is stopped, and then later a new actor is started at the same path, the ActorSelection will deliver messages to the new actor, while if you had an ActorRef it specifically points to the actor instance that is no stopped and messages end up in dead letters.
The receptionist is quite different and is more like a registry of actors that you can subscribe to. When the set of ActorRefs registered for a key changes you get an update message with the new set, there is no extra overhead per message sent, you are dealing directly with the ActorRefs of the recipients.
Note that you can use the GroupRouter for delivery to actors registered with the receptionist and to avoid having to implement the subscription part in your actor.
I have an Akka based application that performs a large amount of work and reports progress by message passing. The "workers" report when they complete some work up to their "manager" who then feeds them more work and at the same time the "manager" sends a message (fire and forget) to an actor ref which simply keeps track of progress.
The "manager" and "workers" all share a dispatch thread pool, and the "tracker" actor sits in it's own small thread pool. I also throttle how much stuff gets posted to it using a basic modulo of the progress, so i only send a message when 20 items of work are completed each time. This seems to work ok for small numbers of jobs - say a couple of hundred. I see the tracker actor receiving the messages and updating its instance variable and responding to requests to retrieve the progress data.
However, when handling thousands of items of work, the progress count goes up for a little while and then appears to totally stop - as if no messages are being picked up by the tracker actor and they are all just filling up it's message queue. Is the "worker" dispatcher hogging all the resources perhaps? I thought that each dispatcher was supposed to be able to deliver messages to actors with some regularity. I've tried messing about with the "fairness" configuration in each dispatcher but it seems to make no difference.
I value anyone's thoughts on this.
I ended up changing some things around and putting the "manager" into a separate dispatcher and things started moving again. I ran 109,000 jobs through it no problem.
According to the Akka docs for PoisonPill:
You can also send an actor the akka.actor.PoisonPill message, which will stop the actor when the message is processed. PoisonPill is enqueued as ordinary messages and will be handled after messages that were already queued in the mailbox.
Although the usefulness/utility of such a feature may be obvious to an Akka Guru, to a newcomer, this sounds completely useless/reckless/dangerous.
So I ask: What's the point of this message and when would one ever use it, for any reason?!?
We use a pattern called disposable actors:
A new temporary actor is created for each application request.
This actor may create some other actors to do some work related to the request.
Processed result is sent back to client.
All temporary actors related to this request are killed. That's the place where PoisonPill is used.
Creating an actor implies a very low overhead (about 300 bytes of RAM), so it's quite a good practise.
I am using Akka.NET to implement an actor system in which some actors are created on demand and are deleted after a configurable idle period (I use Akka's "ReceiveTimeout" mechanism for this). Each of these actors is identified by a key, and there should not exist two actors with the same key.
These actors are currently created and deleted by a common supervisor. The supervisor can be asked to return a reference to the actor matching a given key, either by returning an existing one or creating a new one, if an actor with this key doesn't exist yet. When an actor receives the "ReceiveTimeout" message, it notifies the supervisor who in turn kills it with a "PoisonPill".
I have an issue when sending a message to one of these actors right after it has been deleted. I noticed that sending a message to a dead actor doesn't generate an exception. Worse, when sending an "Ask" message, the sender remains blocked, waiting indefinitely (or until a timeout) for a response that he will never receive.
I first thought about Akka's "Deatchwatch" mechanism to monitor an actor's lifecycle. But, if I'm not mistaken, the "Terminated" message sent by the dying actor will be received by the monitoring actor asynchronously just like any other message, so the problem may still occur in between the target actor's death and the reception of its "Terminated" message.
To solve this problem, I made it so that anyone asking the supervisor for a reference to such an actor has to send a "close session" message to the supervisor to release the actor when he doesn't need it anymore (this is done transparently by a disposable "ActorSession" object). As long as there are any open sessions on an actor, the supervisor will not delete it.
I suppose that this situation is quite common and am therefore wondering if there isn't a simpler pattern to follow to address this kind of problem. Any suggestion would be appreciated.
I have an issue when sending a message to one of these actors right after it has been deleted. I noticed that sending a message to a dead actor doesn't generate an exception.
This is by design. You will never receive an exception upon attempting to send a message - it will simply be routed to Deadletters and logged. There's a lot of reasons for this that I won't get into here, but the bottom line is that this is intended behavior.
DeathWatch is the right tool for this job, but as you point out - you might receive a Terminated message after you already sent a message to that actor.
A simpler pattern than tracking open / closed sessions is to simply use acknowledgement / reply messages from the recipient using Ask + Wait + a hard timeout. The downside of course is that if your recipient actor has a lot of long-running operations then you might block for a long period of time inside the sender.
The other option you can go with is to redesign your recipient actor to act as a state machine and have a soft-terminated or terminating state that it uses to drain connections / references with potential senders. That way the original actor can still reply and accept messages, but let callers know that it's no longer available to do work.
I solved this problem with entity actors created through Akka's Cluster Sharding mechanism:
If the state of the entities are persistent you may stop entities that are not used to reduce memory consumption. This is done by the application specific implementation of the entity actors for example by defining receive timeout (context.setReceiveTimeout). If a message is already enqueued to the entity when it stops itself the enqueued message in the mailbox will be dropped. To support graceful passivation without losing such messages the entity actor can send ShardRegion.Passivate to its parent Shard. The specified wrapped message in Passivate will be sent back to the entity, which is then supposed to stop itself. Incoming messages will be buffered by the Shard between reception of Passivate and termination of the entity. Such buffered messages are thereafter delivered to a new incarnation of the entity.
We are planning to use akka pub-sub in our project. I have the following 2 queries reg. the akka pub-sub behavior.
What if the Publisher starts sending the messages before any actor has subscribed. What will happen to those messages that were published before any subscriber came to existence. Will those be discarded silently ?
What if the subscriber actor dies?[There are no subscribers at all] Will the messages sent by the Publisher gets accumulated somewhere or will it be discarded by the pub-sub system.
Message routing is decided on the spot: no subscribers, no sending. Buffering messages arbitrarily within the toolkit will only lead to surprising memory outages. If you want to buffer you will have to do that explicitly.
If no one is subscribed, then the messages aren't caught. But if you set things up right, that won't be an issue.
For the second question, it depends what you mean by it dying. Actor death is where the actor is gone for good. Which is different from an actor failing and being restarted. If the actor is restarted using fault-handling in its supervisor, it preserves its mailbox so nothing is lost. Only if the actor completely died (not restarted), will it lose its mailbox.
So, with a good fault-handling scheme, you can preserve your messages across actor failure for most use-cases. Just keep your listeners higher-up in the actor heiarchy and push all risky things that are likely to fail such as I/O down to the bottom. Look into the error kernel pattern to see what I mean. That way, failure usually won't climb high enough for you to be losing mailboxes.
Since its just a restart, all messages it is subscribed for will still end up in its mailbox and be waiting for it.