Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Microservices: Recommended way to refactor an app by splitting services? #332

Open
lius opened this issue May 19, 2016 · 27 comments
Open

Microservices: Recommended way to refactor an app by splitting services? #332

lius opened this issue May 19, 2016 · 27 comments

Comments

@lius
Copy link

lius commented May 19, 2016

I'm trying to find a practical/recommend way to extract services, separating them into their own instances, following microservices-style. In this matter, there is an interesting statement on the landing page of feathers:

Service Oriented: Feathers Gives you the structure to build service oriented apps from day one. When you eventually need to split up your app into microservices it's an easy transition and Feathers your apps can scale painlessly.

But, I still could not find information about how to deal with this use case in feathers.

In practical terms, I'm focusing initially on two basic topics:

  • Communication: I think should be a way to extract a service and allow the original application to continue communicating without the need of a big rewrite effort, for example, by replacing the invocations to service by HTTP requests, for example.
  • Authentication: clarifications about how feathers handle authentication towards inter-service communication after the service has been splitted.

Thanks in advance!

@daffl
Copy link
Member

daffl commented May 20, 2016

You are right, there isn't too much documentation out there yet and we created #157 a little while ago to keep track of that. Here are some of my thoughts on the two topics you mentioned:

Let's assume we initially have a server with two services, maybe something like

app.use('/users', memory())
  .use('/todos', memory());

The users service is getting more traffic than the one server can handle so we want to move it to another system by creating another app for it:

// server1
app.use('/users', memory());
// server2
app.use('/todos', memory());

For the /todos service to now communicate with the remote service we can use Feathers as the client to connect to it (Websockets are fast and bidirectional so why not use them for server-to-server communication?):

// server2
const client = require('feathers/client')
const socketClient = require('feathers-socketio/client');
const io = require('socket.io-client');

const socket = io('http://other-server.com');
const otherApp = client().configure(socketClient(socket));

app.use('/todos', memory())
 .use('/users', otherApp.service('users'));

This would basically transparently pass the user service to the remote service through a websocket connection. Anything using the original /users endpoint won't have to change anything.

As for authentication, there is many different options. In the above scenario the easiest way would be for server1 to just whitelist the other servers IP address since server2 is still the only point of communication for the clients. Eventually server2 could just become a gateway that handles user authentication and then just passes service calls through to other servers (which don't have to worry about authentication other than checking the origin IP address).

@lius
Copy link
Author

lius commented May 20, 2016

Thanks for the response! Do you plan to cover this topic on official docs (maybe a sub-section of Guides)? Let me know if I can contribute in this regard.

@daffl
Copy link
Member

daffl commented May 21, 2016

Definitely. And we could definitely use some help. Maybe lets gather first what we'd like to see in a guide and then make some demo applications?

@ekryski
Copy link
Contributor

ekryski commented May 22, 2016

💯 @daffl is bang on. This is something that I am planning on tackling officially over the next month or so as I have committed to giving a presentation on it.

@lius
Copy link
Author

lius commented May 24, 2016

@daffl The approach you mentioned using feathers-client on a backend microservice allows bidirectional communication via streaming data, since socket.io is used. Feathers already has semantic/API for this scenario? I'm thinking on a situation where a microservice publish a event for other interested microservices, not a browser client.

@daffl
Copy link
Member

daffl commented May 24, 2016

Yes but why couldn't the other interested services also use websockets? We are thinking of adding other providers (e.g. for different messaging services) but for now websockets seem to be fast enough and it isn't written anywhere that they can only be used in the browser.

@justingreenberg
Copy link
Contributor

@daffl @ekryski as feathers applications become distributed, we would also need to address issues such as at-least-once delivery (acks), idempotency, transactions, backpressure (queues), etc. have you considered something like "feathers-service-worker?".. ie. external processes that consume events from durable amqp (ie rabbitmq) queue or redis (using ie kue)?

@lius
Copy link
Author

lius commented May 24, 2016

@daffl I think I did not understand well before your answer. As long as the interested services uses web sockets to subscribe to the producer service, using regular events API to publish new events on producer it's enough to implement this in feathers, right?

I agree with @justingreenberg, another issue to be addressed is replaying requests when the responsible microservices goes offline (crash, updates, etc). Technically, this would be address by using message queues too.

@imns
Copy link

imns commented Jul 20, 2016

Any progress on this? I'd really love to see some documentation / a working example. Especially in regards to how authentication is handled.

@ekryski
Copy link
Contributor

ekryski commented Jul 20, 2016

@imns we are working on this. I started working on example and splitting an app up and we realized there are some limitations with how auth is set up. So we're currently refactoring auth to better support this. Should be about a week for that to land.

@imns
Copy link

imns commented Jul 20, 2016

Oh man, I could use this so bad right now :D

Just out of curiosity are you reworking auth to work with multiple front-ends as well? I think a lot of larger apps now-a-days use a microservice on the backend, but also break their front-end apps up.

@marshallswain
Copy link
Member

If you have a few extra bucks, I think this book could be considered recommended reading: https://www.amazon.com/Building-Microservices-Sam-Newman/dp/1491950358/ref=sr_1_1?ie=UTF8&qid=1469071253&sr=8-1&keywords=Microservices

@juanpujol
Copy link

Guys, any updates on this? Thank you.

@marshallswain
Copy link
Member

@juanpujol the latest information will always be in this ticket. Thanks for checking, though.

@ekryski ekryski modified the milestone: Auk Oct 17, 2016
@idibidiart
Copy link

(marcfawzi here)

I've not read the entire thread but I assume that we'll be able to use a database per service (in the Micreoservices architecture having this separation is crucial to maintaining the abstraction. Else, if all services share the same database what prevents folks from defining relations across service models (a violation of the microservices abstraction) instead of composing services using the uniform service API?

@daffl
Copy link
Member

daffl commented Jan 27, 2017

Nothing really prevents that, I'd say it's on you not to do that. It will only really be a problem if you define your models and relationships at the ORM level. I don't think that getting relationships at the service level by calling out to another services violates the microservice abstraction.

@idibidiart
Copy link

Yeah exactly what I meant. I tend to think that segregation of services where each service has its own db is a sure way to force composition via the service interface rather than at the ORM level.

But Feathers is more general than a Microservices framework, so all good here. Thanks David! This keeps looking better and better the more I dig into it! Great work all around!

@zpetterd
Copy link

Just thought I would mention this here are it solves some of the problems that come up with using Feathers in a micro services environment. It is only the first implementation but if you have anything to contribute feel free to here zpetterd/feathers-rabbitmq#1

@idibidiart
Copy link

@zapur1 that looks promising... I've posted a comment to get the discussion started

@ekryski
Copy link
Contributor

ekryski commented Feb 10, 2017

You can use also use https://github.com/feathersjs/feathers-sync with rabbitMQ, Redis, or MongoDB as the message brokers in between services to keep them all in sync.

@zpetterd
Copy link

@ekryski feathers-sync solves a bit of a different problem, what if you only want a event to be received once within the realm of a named service(not a Feathers service but a microservices style service)? If you had multiple instances of a single service receiving events from a single API app each one will receive the event likely duplicating the actions that are taken when that event is received across multiple instances of the exact same code.

@zpetterd
Copy link

@ekryski I just had a look at the repo again and zapur1/feathers-rabbitmq solves the exact problem you mention in "Caveats"

@InnerPeace080
Copy link

if i connect a service 1 to service 2 by socketClient , so if my service 2 have multi instance , how can i implement load balance :(

@dottodot
Copy link

If I create a separate serverside app that connects via socketClient what's the best way to authenticate so that any of the services are available regardless of any restrictions that have been set up.

@claustres
Copy link
Contributor

I add my 2 cents on this with https://github.com/kalisio/feathers-distributed, it aims at deploying N feathers apps holding different services talking together, so that you can develop each one independently. It is different from https://github.com/feathersjs/feathers-sync which aims at deploying N feathers apps holding the same services as far as I understand. All of this raises a set of questions like:

  • authentication management
  • API gateway and load balancing
  • remote hooks invokation
  • ...

@aecorredor
Copy link

aecorredor commented Jun 26, 2018

@daffl on the example that you gave involving server 1 and server 2, how would you secure the /users service in server 2? If we had that service defined in server 2 we could use hooks in the specific service hook file, but since we're doing app.use('/users', otherApp.service('users'));, how would we make sure that calls to that service from server 2 would only be done if the user authenticated first?

EDIT:
Nvm, I think I have an idea: we could do something like const usersService = app.service('users') and then usersService.hooks(hooks) where hooks has the auth hooks required to secure the endpoint right?

@daffl
Copy link
Member

daffl commented Jun 26, 2018

I wrote more about how distributed authentication could be done in https://stackoverflow.com/questions/41076627/evaluating-featherjs-authentication-needs/41095638#41095638:

There are several ways of splitting up services each with their own advantages and drawbacks. One generally important thing for Feathers is that there are no sessions, just JSON web tokens. JWTs are stateless and can be read by any server that shares the same secret so there does not have to be a central session store. The two main options I can think of are:

  1. Have a main application that handles authorization and managing all connected clients but instead of having services that talk to the database they connect to separate simple individual API servers in the internal network. This is the easier setup and the advantage is that the internal API servers can be super simple and don't need authentication at all (since the main application is allowed to do everything and will make queries according to the authenticated users restrictions). The disadvantage is that the main application is still the bottleneck (but with a decreased load since it basically acts as a proxy to internal APIs).

my50m

  1. Every client connects to every API server they need using a JWT. The JWT is created by a separate authentication (or user) API. This is the more scalable solution since the only bottleneck is retrieving the most up-to-date user information from a common users service (which might not even always be necessary). The disadvantage is that it is more complex to manage on the client side and authentication (at least for JWT) will have to be configured on every server. Due to the statelessness of JWT however, there does not need to be any shared sessions.

lw1bg

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests