I'm playing with newly released Akka.Net 1.0 (congratulations on the release!) so it's all quite new to me, but I'm pretty sure anyone with JVM Akka experience could also chime in since there's nothing that's runtime-dependent in the question.
Let's consider several (for the sake of example, 2) separate services that are a part of a larger system/application. Those services usually do their own things, but cross-service calls are sometimes needed. Let's say that Service 2 can be standalone and has a GetStuff action. Service 1 has a DoSomething action, which has to get the result of GetStuff action first.
What is preferred way of handling that kind of situation when both services can be deployed separately and to different machines?
As I said, I don't know much about Akka, but digging through examples, docs and source I found two options:
Remoting. Separate actor systems in their own services using Remoting to get ActorSelection from remote host. It would be pretty much the same as Remoting docs example, just that two actor systems would be equal 'clients'.
Clustering. I'm trying to wrap my head around that and the most I can figure out right now would be to set up a separate cluster service that would just set up the cluster system, creating a simple listener actor so that the seed node could be properly initialized (?). Then each and every separate actor system created in their own services would join to said cluster system under different role.
Maybe there's yet another solution that I'm not aware of...?
Personally, clustering solution seems harder to grasp and set up at first glance, but maybe there are some significant advantages that I can't see right now.
To reiterate, what is the preferred way of handling such situation and what should I look out for?
Akka.Cluster depends on Akka.Remote - here's what's fundamentally different about them:
Akka.Remote - allows you to connect and communicate with actor systems running in remote processes. Can be totally separate code-bases running entirely different Akka.NET applications ("services", if you will.) All you need to communicate between the two systems is a shared set of message classes that's visible in both processes.
Akka.Cluster - an abstraction on top of Akka.Remote that eliminates the need for each of your service instances to have to know the explicit address of every other possible service instance you might need to connect to. These can be instances of the same services or instances of different services. Enables dynamic discovery of services via a really simple "seed node" strategy.
I recommend you take a look at the Akka.Cluster microservices example that I wrote - it shows how you can use the Akka.Cluster "roles" feature to dynamically make cross-service calls to nodes in a different service without having to explicitly define any of their network addresses. In particular, take a look at how I use "cluster-aware" routers to do this.
Related
I want to know how can we send a message to a particular actor in cluster without knowing the actual path..
For Example...
I have 5 nodes all have same actorsytem and formed a cluster.
Each node will have 2 actors in it all actors across cluster have unique name.
I have an actor system outside the cluster.which not part of this cluster.
I have to send message from this actor system to cluster actors.
How can i map respective message to respective actor in cluster each time.Without knowing the actual path of the actor.
Without cluster sharding how actors inside cluster will accessed by outside cluster.
There is a direct answer to your question (at the end), but I think you need to go back to the docs and rethink your design. One of the primary reasons for this is that while what you are asking is possible, it goes against all of the best practices and many of the features involved are deprecated or not recommended. The best practice is that clusters should be self-contained and clusters should expose via well defined APIs and not actor internals. To quote from the remoting docs:
When building an Akka application, you would usually not use the Remoting concepts directly, but instead use the more high-level Akka Cluster utilities or technology-agnostic protocols such as HTTP, gRPC etc.
Essentially the docs are tell you that what you are trying to do is a bad idea. If two actors need to be able to discover each other, they should be in the same cluster. If for some reason you can't have them in the same cluster, for maintainability reasons you should expose the actor in the cluster via REST/gRPC or some other well defined API rather than trying to allow direct access to the actors.
Similarly, in the section about cluster client the docs say:
Cluster Client is deprecated in favor of using Akka gRPC. It is not advised to build new applications with Cluster Client, and existing users should migrate.
But, here's an attempt to answer the question directly. To quote the first sentence of the Actor discovery docs, "There are two general ways to obtain Actor references: by creating actors and by discovery using the Receptionist."
Unrelated side note: (That is a little misleading though, because there are some other ways in untyped Actors, and you also can obviously just be given a ActorRef. It's not the the docs are wrong, I'm just taking them a little out of context.).
Anyway, that leads to the direct answer to your question: ClientClusterReceptionist. You can find details on how to use it in the Classic Cluster Client docs. It's going to require some untyped actors, but since you are using deprecated approaches that probably isn't an issue.
But, moreso, you really should rethink this because based on your last question, it seems like you really aren't understanding how either clustering or sharding work.
As #david-ogren said, what you need is cluster client. You can read the documentation here. With cluster client, you still need to know at least one of the cluster node address and either:
The name of the actor you're trying to communicate with, if you're trying to communicate with the actor instance directly, or
A predefined topic to publish to. If you went for this route, you will need to make sure that all of the participating actors inside the cluster subscribes to the topic to receive them.
You can see a working example in this GitHub repository.
I'm struggling with proper design of communication between 2 separate akka microservices/bounded contexts in akka cluster.
Lets say we have 2 microservices in cluster per node.
Both microservices are based on akka.
It's clear for me that communication within particular bounded context will be handled by sending messages from actor to actor or from actor on node1 to actor on node2 (if necessary)
Q: but is it OK to use similar communication between separate akka application? e.g. boundedContext1.actor --message--> boundedContext2.actor
or it should be done via much clearer boundaries: In bc1 raise an event - publish to broker and read the event in bc2?
//Edit currently we've implemented a service registry an we're publishing events to service registry via Akka streams.
I think there is no universal answer here.
It is like if your BCs are simple enough you can hold the BCs in one application and even in one project/library with very weak boundaries i.e. just placing them into separate namespaces and providing an API for other BCs.
But if your BCs become more complex, more independent and require its own deployment cycle then it is definitely better to construct more strong boundaries and separate microservices that communicate through message broker.
So, my answer is you should just "feel" the right way according to your particular needs. If you don't "feel" it then follow KISS principle and start with an easier way i.e. using built-in akka communication system. And if in the future your BCs will become more complex then you will have to refactor them. But this decision will be justified and it will not be an unnecessary overhead.
So, here's the thing. I really like the idea of microservices and want to set it up and test it before deciding if I want to use it in production. And then if I do want to use it I want to slowly chip away pieces of my old rails app and move logic to microservices. This I think I can do using HAProxy and set up different routing based on URLs. So this should be covered.
Then my next biggest concern is that I don't want too much overhead to ensure everything is running smoothly on the infrastructure side. I want preferrably low configuration and the ease of development, testing and deployment.
Now, I want to know what are the benefits and downsides of each styles. Akka (cluster) vs something like Kubernetes (maybe even fabric8 on top of it).
What I also worry about is fault tolerance. I don't know how do you do that with Kubernetes. Do you then have to include some message queue to ensure your messages don't get lost? And then also have multiple queue if one of the queues goes down? Or just retry until queue comes up again? Akka actors already have that right? Retrying and mail boxes? What are the strategies for fault tolerance for microservices? Do they differ for each approach?
Someone please enlighten me! ;)
I don't know much about Akka, but from reading quickly it seems that it is an app framework. Kubernetes is at a bit of a lower-level. Kubernetes runs your containers and manages them for you. We don't have a concept of queues or mailboxes.
Kubernetes will soon have L7 load balancing so you can do URL maps.
As for fault tolerance - kubernetes ensures that your stated intentions are true - run N copies of this container. That container might be an Akka app or might be mysql - dopesn't matter.
There are a bunch of guides on Docker + Akka. Kubernetes makes managing docker containers easier, but the app is still yours :)
Following is a point mentioned in a presentation slide related to SOA, and it confuses me with the concepts of service orchestration and service choreography. To enable service choreography, shouldn't a web service be able to call another web service?
SOA builds applications out of software services. Services comprise intrinsically
unassociated, loosely coupled units of functionality that have no calls to
each other embedded in them.
In theory, a service can do anything it needs to do to accomplish its job. So there doesn't seem to be a good reason to forbid using a second service to do your work. Why reinvent the wheel?
In practice, the issue is more complicated. If you start calling other services on your own web server, then you'll eventually starve it of resources. At best, "real" clients will have to wait a bit longer for their answers while your web service server plays with itself.
Another issue is recursive loops: Service A calls B calls C calls A calls B ... you get the idea. A small change in one service can introduce such a loop without anyone noticing and it can sit there for a long time until it suddenly kills your server.
That is why you should build micro services in a hierarchy inside the server (i.e. below the web service layer - this is not exposed to clients). Those micro services can use each other in a top-down manner (to avoid the loops). Unit tests then make sure they behave properly.
Lastly, such reuse is very slow. Each HTTP request takes a lot of resources to create, send, parse and process. Calling an internal method directly can be 10 - 10000 times faster.
These are the main reasons why the services exposed by a single server shouldn't reuse each other via the "public client API".
Note: There are web services which build new services by using existing ones. IFTTT - "If This Then That" is one such beast.
You could adopt every concept according to your needs. In my current project we have a separate module that is responsible for the Orchestration. This is required since in real life usage, scenarios can be very complicated. So in order to be close to the actual management of your system, you need to have such one.
Another advantage of this approach is that the Separation_of_concerns is kept. Also aligns the business request with the applications, data, and infrastructure that you have. It defines policies and service levels through automated workflows, provisioning etc.
Orchestration is critical in the delivery of Cloud services too. As they are networked to allow sharing of data-processing tasks, centralized data storage, and online access to services or resources.
I am currently working on a Play! project that has the following architecture:
Controllers -> Services (actors) -> Models (Regular case classes)
For each request that comes in, we will issue a call to the service layers like so:
Service ? DoSomething(request, context)
We have a set number of these service actors behind an akka router that are created during app initialization, and is expandable on demand.
And in the service we mostly do modest data manipulation or database calls:
receive = {
case DoSomething(x, y) => {
...
Model.doSometing(...)
sender ! result
}
}
I am having second thoughts on whether we should be using actors for our services or just use Futures only.
We do not have any internal state that needs to be modified in the service actors, whatever message comes in goes to a function and spits out the result. Isn't this the big strength of the actor model?
We are doing a lot of tasks which seem to take a lot away from the actor model
We aren't doing heavy computation and remoting doesn't make sense because most of the work is for the database and roundtriping to a remote actor to make some db call is unnecessary
We do use reactivemongo, so every db call is non blocking. We can make a lot of these calls
It seems to me that removing akka and just use Futures makes our life a lot easier, and we don't really lose anything.
There certainly is no shortage of opinion on the topic of what should and shouldn't be an actor. Like these two posts:
http://noelwelsh.com/programming/2013/03/04/why-i-dont-like-akka-actors/
http://www.chrisstucchio.com/blog/2013/actors_vs_futures.html
I don't think you're going to find an absolute answer to this question other then that it's situational and it's really up to your preferences and your problem. What I can do for you is to offer my opinion that is based on us implementing Akka for about 2 years now.
For me, I like to think of Akka really as a platform. We come for the Actor Model but we stay for all of the other goodness that the platform provides like Clustering/Remoting, FSM, Routing, Circuit Breaker, Throttling and the like. We are trying to build an SOA like architecture with our actors acting as services. We are deploying these services across a cluster, so we are taking advantage of things like Location Transparency and Routing to provide the ability for a service consumer (which itself could be another service) to find and use a service no matter where it is deployed, and in a highly available manner. Akka makes this whole process pretty simple based on the platform tools they offer.
Within our system, we have the concept of what I call Foundation Services. These are really simple services (like basic lookup/management services for a particular entity). These services generally don't call any other services, and in some cases, just perform DB lookups. These services are pooled (router) and don't usually have any state. They are pretty similar to what you are describing some of your services to be like. We then start to build more and more complex services on top of these foundation services. Most of these services are short lived (to avoid asking), sometimes FSM based, that collect data from the foundation services and then crunch and do something as a result. Even though these foundation services are themselves pretty simple, and some would say don't require an actor, I like the flexibility in that when I compose them into a higher level service, I can look them up and they can be anywhere (location transparent) in my cluster with any number of instances available (routing) for using.
So for us, it was really a design decision to baseline around an actor as a sort of micro-like service that is available within our cluster for consumption by any other service, no matter how simple that service is. I like communicating with these services, where ever they are, through a coarse grained interface in an async manner. A lot of those principles are aspects of building out a good SOA. If that's your goal, then I think Akka can be very helpful in achieving that goal. If you are not looking to do something like that, then maybe your are right in questioning your decision to use Akka for your services. Like I said earlier, it's really up to you to figure out what you are trying to do from an architecture perspective and then design your services layer to meet those goals.
I think you're on right tracks.
We do not have any internal state that needs to be modified in the service actors, whatever message comes in goes to a function and spits out the result. Isn't this the big strength of the actor model?
I found Chris Stucchio's blog (referred to by #cmbaxter above) instantly delightful. My case was so simple that architectural considerations were not a valid point. Just Spray routing and lots of database access, like you have. No state. Thus Future. So much simpler code.
Actor should be crated when you need some really long living stuff with modifying state. In other cases there are no any benefits from actors, especially from non-typed ones.
- do pattern matching every time
- control actor's lifecycle
- remember the things which should not be passed between threads
Why do all of this when you may have simple Future?
There are tasks where actors fit very well, but not everywhere
I was wondering the same and what we decide to do was to use Akka for our data access and it works very well, it's very testable (and tested), and very portable.
We created repositories, long living actors, that we bootstrapped in our App : (FYI, we are using slick for our DB Access, but also have a similar design for our MongoDB needs)
val subscriptionRepo = context.actorOf(Props(new SubscriptionRepository(appConfig.db)), "repository-subscription")
Now we are able to send a "Request" Message for data, ex:
case class SubscriptionsRequested(atDate: ZeroMillisDateTime)
that the actor will respond with
case class SubscriptionsFound(users: Seq[UserSubscription])
or Failure(exception)
In our situation (spray apps but also CLI), we wrapped those calls in a short living actor that take the context and complete on reception and closes itself. (You could handle domain specific logic in those actor, have it to extend another actor that manages its lifecycle and exception so you would only have to specify a partial function for your needs and leave the abstract actor to deal with timeouts, common exceptions etc.
We also have situations where we needed more work to be done in the initiating actor, and it very convenient to fire x messages to your repositories and have your actor storing those messages as they arrive, doing something once they are all there, firing back for completion to the sender( for instance) and close itself.
Thanks to this design, we have a very reactive repository living outside our app, completely tested with Akka TestKit and H2, completely DB agnostic, and it's dead easy, to access data from our DBs (and we never do any ASK, only Tell : Tell to repo, tell to sender, complete or x Tells to repos, pattern match on expected results until completion, tell to sender).