Background
In the last post, I show you how to do service discovery in a Golang Cloud-Native microservice application based on Consul and Docker with a real demo. In that demo, the simple helloworld-server
service is registered in Consul and the helloworld-client
can discover the dynamic address of the service via Consul. But the previous demo has one limitation, as I mentioned in the last post, in the real world microservice application, each service may have multiple instances to handle the network requests.
In this post, I will expand the demo to show you how to do load balancing
when multiple instances of one service are registered in Consul.
Continue with the last post, the new demo will keep using Cloud-Native way with Docker
and Docker-compose
.
Fabio for load balancing
To do load balancing for Consul, there are several strategies are recommended from the Consul official document. In this post I choose to use Fabio.
Fabio is an open source tool that provides fast, modern, zero-conf load balancing HTTP(S) and TCP router for services managed by Consul. Users register services in Consul with a health check and fabio will automatically route traffic to them. No additional configuration required.
Fabio is an interesting project, it realizes loading balancing based on the tag
information of service registration in Consul.
Users register a service with a tag beginning with urlprefix-
, like:
1 | urlprefix-/my-service |
Then when a request is made to fabio at /my-service
, fabio will automatically route traffic to a healthy service in the cluster. I will show you how to do it in the following demo. And I will also do simple research on how Fabio realizes this load balancing strategy by reviewing the source code and share the findings in the next post.
Fabio load balancing demo
Firstly, all the code and config files shown in this post can be found in this github repo, please git checkout
the load-balancing
branch for this post’s demo.
Server side
For the helloworld-server
, there are two changes:
- First, each service instance should have an unique
ID
; - Second, add
Tags
for service registration and the tag should follow the rule ofFabio
.
Ok, let’s check the new version code.
1 | package main |
server.go
The changes are at Line 30, 32 and 40 and comments are added there to explain the purpose of the change. Simply speaking, now each service instance registers itself with a unique ID, which is consisted of the basic service name (helloworld-server in this case) and the dynamic address. Also, we add urlprefix-/helloworld
Tags for each registration. urlprefix-
is the default config of Fabio, you can set customized prefix if needed. Based on this Tags, Fabio can do automatic load balancing for the /helloworld
endpoint.
That’s all for the code change for server side. Let’s review the changes for the client.
Client side
1 | package main |
client.go
Previously, we need to run serviceDiscoveryWithConsul
to discover the service address to call. Now since we have Fabio
working as the load balancer, so we send the request to Fabio
and our request will be distributed to the service instance by Fabio
.
This part of logic is implemented inside the following method:
1 | /* Load balancing with Fabio */ |
To get the address of the Fabio service, we need to config it as an environment variable, which will be set in the yml
file of Docker-compose. Let’s review the new yml
file now.
Docker-compose config
1 | version: '2' |
docker-compose.yml
There several changes in this yml
config file:
- Add a new service
Fabio
. As mentioned above Fabio is a zero-conf load balancing, which can simply run as a docker container. This is so convenient and totally matches Cloud-Native style. The two environment variables:registry_consul_addr
andproxy_strategy
, are set to define the Consul’s address and the round-robin strategy. - Set the
FABIO_HTTP_ADDR
environment variable for the client. This is what we mentioned in the last section, which allowsclient.go
to get Fabio service address and send requests. - Upgrade two docker images to v1.0.2.
Demo
It’s time to run the demo! Suppose you have all the docker images build on your local machine, then run the following command:
1 | docker-compose up --scale helloworld-server=3 |
This command has an important tip about Docker-compose: how to run multiple instances of certain service. In our case, we need multiple instances of helloworld-server
for load balancing. Docker-compose supports this functionality with --scale
option. For the above command, 3 instances of helloworld-server will be launched.
You can see the demo’s result in the following image:
The client repeatedly and periodically sends the request and each request is distributed by Fabio to one of the three instances in round-robin style. Just what we expect!