Takeaways from microservice antipatterns:
- Overzealous Services – don’t go straight into microservices, (following the hype perhaps?) rather than starting with the simplest thing possible. Instead, you should start by doing the simplest thing possible, identify the hotspots as they become apparent and then extract them into microservices. Start with monolith.
- Schemas Everywhere – avoid having a shared database between different services. This creates tight coupling between the services and means you can’t deploy the microservices independently if it breaks the shared schema. Any schema updates will force you to update other microservices too. Instead, every service should have its own database, and when you want data from another service you go through its API rather than reaching into its database and help yourself. Use semantic versioning.
- Spiky Load between Services – You often get spiky traffic between services, and a common solution is to amortise the load by using queues between the services. Use rabbitmq.com, redis, etc.
- Hardcoded IPs and Ports – One solution would be to use a discovery service such as consul or etcd, and there’s also Netflix’s eureka. Another solution is to use a centralised router. Both solutions require registration and deregistration, and both require high availability and scalability.
- Dogpiles – If one of your services is under load or malfunctioning, and all your other services keep retrying their failed calls, then the problem would be compounded and magnified by the additional load from these retries. The solution here is to have exponential backoff and implement the circuit breaker pattern. Many libraries such as Netflix’s Hystrix and Polly for .Net are available. You can even use the service discovery layer to help propagate the message to all your services that a circuit has been tripped (i.e. a service is struggling).
- Debugging Hell – Debugging is always a huge issue in micro-service architectures. E.g., a nested service call fails and you can’t correlate it back to a request coming from the user. One solution is to use correlation IDs. When a request comes in, you assign the request with a correlation ID and pass it on to other services in the HTTP request header. Every service would do the same and pass the correlation ID it receives in the incoming HTTP header in any out-going requests. Whenever you log a message, be sure to include this correlation ID in the log line.
- Missing Mock Servers – When you have a service that other teams depend on, each of these teams would have to mock and stub your service in order to test their own services. A good step in the right direction is for you to own a mock service and provide it to consumers. You can take it a step further, by building the mock service into the client so you don’t even have to maintain a mock service anymore. Use Anypoint Platform or Swagger.
- Flying Blind – There are more than a handful of tools available in this space. There are commercial tools (some with free tiers) such as NewRelic and StackDriver (now integrated into Google AppEngin), AWS also offers CloudWatch as part of its ecosystem. In the open source space, Netflix has been leading the way with Hystrix and something even more exciting.
- Richard Rodger – Measuring Micro-services – Codemotion Rome 2015
Microphone allows you to run self hosting services using either WebApi or NancyFx ontop of a Consul.io cluster.
You can find the code here https://github.com/rogeralsing/Microphone
Consul is a system that does service discovery, configuration management, and health checking for your services. Services can register themselves using either a REST API or via DNS, and if a service becomes unresponsive, Consul can mark this service as unavailable and not include it in any search results.
You can start consul service with below line on console:
consul agent -server -bootstrap -data-dir /tmp/consul
Check service health on Consul agent:
Check all services registered on Consul agent:
Discovery service output:
Time to play with some code.
Reference: Microservices discovery for .net
Back in the day most systems started as a monolithic system, which basically means the entire application exists in a single code base and is deployed and, importantly, scaled as a single unit.
A monolithic application puts all its functionality into a single process… and scales by replicating the monolith on multiple servers. A monolithic application is harder to scale, as one small change must be deployed across all processes.
What are microservices ?
According to wikipedia, microservices are a software architecture style in which complex applications are composed of small, independent processes communicating with each other using language-agnostic APIs. These services are small, highly decoupled and focus on doing a small task, facilitating a modular approach to system-building.
Software developer advocates James Lewis and Martin Fowler gave the best definition we could find for this increasingly popular architectural pattern:
“The microservice architectural style is an approach to developing a single application as a suite of small services, each running in its own process and communicating with lightweight mechanisms, often an HTTP resource API. These services are built around business capabilities and independently deployable by fully automated deployment machinery. There is a bare minimum of centralized management of these services, which may be written in different programming languages and use different data storage technologies.”
A microservices architecture puts each element of functionality into a separate service…and scales by distributing these services across servers, replicating as needed.
Characteristics of microservices
- Small with a single responsibility
- Each application does one thing
- Small enough to fit your head – If a class is bigger than by head then it is too big
- Small enough that you can throw them away – Rewrite over Maintain
- Status aware and Auto scaling – multiple consumers (Competing Consumers pattern example
- WatchDog process to monitor app-status (expose metrics about itself eg: queue dept) auto-scale to meet throughput requirements.
- A single capability composed of a small number of activities and exposing a uniform interface (REST)
- Each is entirely decoupled from it’s clients, scalable, testable and deployable individually.
How does a microservice outshine a monolith?
- It makes your app more scalable with smaller teams.
- Enables modularity and is more open to change in general.
- Uses a smaller codebase.
What are microservice architecture’s limitations?
- It can cause communication problems among different parts of the app and within your team.
- It requires increased effort later on to catalog, test, and fix incompatibilities.
- You should still build the monolith before building the microservices on top of it.