1, Ribbon: load balancing (client based)
1.1 load balancing and Ribbon
What is Ribbon?
- Spring Cloud Ribbon is a set of client-side load balancing tools based on Netflix Ribbon.
- In short, Ribbon is an open source project released by Netflix. Its main function is to provide software load balancing algorithms for clients and connect Netflix's middle tier services together. The Ribbon client component provides a series of complete configuration items, such as connection timeout, Retry, etc. To put it simply, list all the machines behind the LoadBalancer (LB: load balancer for short) in the configuration file. The Ribbon will automatically help you connect these machines based on certain rules (such as simple polling, random connection, etc.). We can also easily use Ribbon to implement a custom load balancing algorithm!
What can Ribbon do?
- LB, load balancer, is an application often used in microservices or distributed clusters.
- Load balancing simply means that users' requests are evenly distributed to multiple services, so as to achieve the HA (high use) of the system.
- Common load balancing software include Nginx, Lvs, etc.
- Both Dubbo and spring cloud provide us with load balancing. The load balancing algorithm of spring cloud can be customized.
- Simple classification of load balancing:
- Centralized LB
- That is, an independent LB facility is used between the service provider and the consumer, such as nginx (reverse proxy server), which is responsible for forwarding the access request to the service provider through some policy!
- Advance program LB
- Integrate LB logic into the consumer. The consumer knows which addresses are available from the service registry, and then selects an appropriate server from these addresses.
- Ribbon belongs to in-process LB. it is just a class library integrated into the consumer process. The consumer obtains the address of the service provider through it!
- Centralized LB
1.2. Integrated Ribbon
springcloud-consumer-dept-80 adds Ribbon and Eureka dependencies to pom.xml
<!--Ribbon--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-ribbon</artifactId> <version>1.4.6.RELEASE</version> </dependency> <!--Eureka: Ribbon Need from Eureka What can I get from the service center--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka</artifactId> <version>1.4.6.RELEASE</version> </dependency>
Configure Eureka in the application.yml file
# Eureka configuration eureka: client: register-with-eureka: false # Do not register yourself with Eureka service-url: # Access one of the three registries at random defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
The main startup class is annotated with @ EnableEurekaClient to open Eureka
//After the integration of Ribbon and Eureka, the client can call directly without caring about the IP address and port number @SpringBootApplication @EnableEurekaClient //Open Eureka client public class DeptConsumer_80 { public static void main(String[] args) { SpringApplication.run(DeptConsumer_80.class, args); } }
Custom Spring configuration class: ConfigBean.java configures load balancing and implements RestTemplate
@Configuration public class ConfigBean { //@Configuration -- spring applicationContext.xml @LoadBalanced //Configure load balancing to implement RestTemplate @Bean public RestTemplate getRestTemplate() { return new RestTemplate(); } }
Modify the controller: DeptConsumerController.java
//Ribbon: the address here should be a variable accessed by the service name //private static final String REST_URL_PREFIX = "http://localhost:8001"; private static final String REST_URL_PREFIX = "http://SPRINGCLOUD-PROVIDER-DEPT";
1.3. Use Ribbon to realize load balancing
flow chart:
1. Create two new service providers: springcloud-provider-dept-8003 and springcloud-provider-dept-8002
2. Refer to springcloud-provider-dept-8001, add pom.xml dependency, mybatis and application.yml configuration under resourcece, and Java code for the other two clouds
3. Start all service tests (determine the number of services to start according to your computer configuration), and access http://eureka7001.com:7002/ View results
Test access http://localhost/consumer/dept/list At this time, the service provider 8003 is accessed randomly
Visit again http://localhost/consumer/dept/list At this time, the random service provider 8001
Each visit above http://localhost/consumer/dept/list Random access to a service provider in the cluster is called polling. The polling algorithm can be customized in spring cloud.
How to switch or customize rules?
Configure in the ConfigBean under the springcloud-provider-dept-80 module and switch to different rules
@Configuration public class ConfigBean { //@Configuration -- spring applicationContext.xml /** * IRule: * RoundRobinRule round-robin policy * RandomRule Random strategy * AvailabilityFilteringRule : It will filter out, trip, access the failed service ~, and poll the rest~ * RetryRule : The service ~ will be obtained according to the polling first. If the service acquisition fails, it will be performed within the specified time and try again */ @Bean public IRule myRule() { return new RandomRule();//Use random strategy //return new RoundRobinRule();// Use polling policy //return new AvailabilityFilteringRule();// Use polling policy //return new RetryRule();// Use polling policy } }
You can also customize rules and customize a configuration class MyRule.java under the myRule package. Note: the package should not be the same level as the package where the main startup class is located, but should be the same level as the package where the startup class is located:
MyRule.java
@Configuration public class MyRule { @Bean public IRule myRule(){ return new MyRandomRule();//The default is polling RandomRule, which is now customized as its own } }
The main startup class enables load balancing and specifies a custom MyRule configuration class
//After the integration of Ribbon and Eureka, the client can call directly without caring about the IP address and port number @SpringBootApplication @EnableEurekaClient //The custom Ribbon class can be loaded when the micro service is started (the custom rules will overwrite the original default rules) @RibbonClient(name = "SPRINGCLOUD-PROVIDER-DEPT",configuration = MyRule.class)//Turn on load balancing and specify custom rules public class DeptConsumer_80 { public static void main(String[] args) { SpringApplication.run(DeptConsumer_80.class, args); } }
Custom rules (here we refer to the default rule code in the Ribbon and change it slightly): MyRandomRule.java
public class MyRandomRule extends AbstractLoadBalancerRule { /** * If each service is accessed 5 times, the next service will be replaced (3 services in total) * <p> * total=0,Default = 0. If = 5, it points to the next service node * index=0,Default = 0, if total=5,index+1 */ private int total = 0;//Number of calls private int currentIndex = 0;//Who is currently providing services //@edu.umd.cs.findbugs.annotations.SuppressWarnings(value = "RCN_REDUNDANT_NULLCHECK_OF_NULL_VALUE") public Server choose(ILoadBalancer lb, Object key) { if (lb == null) { return null; } Server server = null; while (server == null) { if (Thread.interrupted()) { return null; } List<Server> upList = lb.getReachableServers();//Access to currently alive services List<Server> allList = lb.getAllServers();//Get all services int serverCount = allList.size(); if (serverCount == 0) { /* * No servers. End regardless of pass, because subsequent passes * only get more restrictive. */ return null; } //int index = chooseRandomInt(serverCount);// Generating interval random number //server = upList.get(index);// Randomly get one from a or living service //=====================Custom code========================= if (total < 5) { server = upList.get(currentIndex); total++; } else { total = 0; currentIndex++; if (currentIndex > upList.size()) { currentIndex = 0; } server = upList.get(currentIndex);//Obtain the specified service from the living service for operation } //====================================================== if (server == null) { /* * The only time this should happen is if the server list were * somehow trimmed. This is a transient condition. Retry after * yielding. */ Thread.yield(); continue; } if (server.isAlive()) { return (server); } // Shouldn't actually happen.. but must be transient or a bug. server = null; Thread.yield(); } return server; } protected int chooseRandomInt(int serverCount) { return ThreadLocalRandom.current().nextInt(serverCount); } @Override public Server choose(Object key) { return choose(getLoadBalancer(), key); } @Override public void initWithNiwsConfig(IClientConfig clientConfig) { // TODO Auto-generated method stub } }