Springcloud-Alibaba seven〗 〖Ribbon articles
- A. What Ribbon that?
- Two. LB load balancing (Load Balance)
- Three. Ribbon architecture
- Four. RestTemplate call
- Five. Ribbon load balancing mechanism IRule
- VI. Load Balancing Algorithm
- VII. Handwriting load balancing algorithm
- 7.1 change controller
- 7.2 out of 80 projects Note @LoadBalanced
- 7.3 80 projects to increase an interface and an implementation class
- 7.4 controller layer
- 7.5 Test
- Finally finished liver Ribbon, honest writing this really long time, because the foundation is really bad, it will go up some basic, reading may not be white prostitute oh ~
- Reproduced, please mark!
A. What Ribbon that?
Spring Cloud Ribbon is based on a set of client load balancing tool Netflix Ribbon implemented.
Ribbon is Netflix released open source project, the main function is to provide the client software load balancing algorithms and service calls . Ribbon client components, such as a series of perfect CI connection timeout, retry the like. Simply put, it is listed in the configuration file Load Balancer (referred to as LB) all machines behind, Ribbon will automatically help you to connect these machines based on certain rules (such as a simple polling, random connections, etc.). It is easy to use for load balancing algorithm Ribbon customizable.
Two. LB load balancing (Load Balance)
Simply means that the user's request equal shares allocated to the plurality of services, so as to achieve the system HA (High Availability). There are common load balancing software Nginx, LVS, F5 hardware and so on.
- Centralized B
that is separate between consumers and service providers LB facilities (can be hardware, such as F5, can be software, such as nginx), the facility is responsible for the access request is forwarded to the service through a strategy provider - LB-process
will be integrated into the LB logical consumer, consumer service registry learn from what address is available, and then select a suitable own server from these addresses. Ribbon belong to LB in the process, it's just a class library, integrated with the consumer process, consumer to get the address of the service provider through it.
Ribbon is load balancing + RestTemplate calls, and ultimately the RPC remote call.
Three. Ribbon architecture
Since eureka born with integrated ribbon, so you can not rely on it to add a ribbon
Four. RestTemplate call
4.1 getForObject () method
@GetMapping("/consumer/payment/getEntity/{id}")
public CommonResult<Payment> getForEntity(@PathVariable("id") Long id){
ResponseEntity<CommonResult> forEntity = restTemplate.getForEntity(PAYMENT_URL + "/payment/get/" + id, CommonResult.class);
if ((forEntity.getStatusCode().is2xxSuccessful())){
return forEntity.getBody();
}else {
return new CommonResult<>(444,"调用失败");
}
}
getForObject returning to get more information, including a request header, the request status code, and the like .
Test
4.2 getForObject () method
- getForObject () is actually more than getForEntity () it contains more than the HTTP turn into a POJO functions, but does not address getForObject response capabilities. We get our hands because it is shaped pojo. It omitted a lot of information in response.
transfer
@GetMapping("/consumer/payment/create")
public CommonResult<Payment> create(Payment payment){
log.info("*******消费者启动创建订单*******");
return restTemplate.postForObject(PAYMENT_URL+"/payment/create",payment,CommonResult.class);
}
@GetMapping("/consumer/payment/get/{id}")
public CommonResult<Payment> getPayment(@PathVariable("id") Long id){
return restTemplate.getForObject(PAYMENT_URL+"/payment/get/"+id,CommonResult.class);
}
Test Results
Five. Ribbon load balancing mechanism IRule
The default polling mechanism
5.1 Directory Structure
5.2 Create a rule class
The custom configuration class can not be placed under the current package @ComponentScan scanned and sub-package, or a custom configuration class will be shared by all of the Ribbon clients reach specialized custom purpose. So we create com.atguigu.myrule.MyselfRule class in java directory, where we create a random rule
package com.atguigu.myrule;
import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RandomRule;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MyselfRule {
@Bean
public IRule myRule(){
return new RandomRule(); //定义为随机
}
}
5.3 Master Boot class annotate
@RibbonClient(name = "CLOUD-PAYMENT-SERVICE",configuration = MyselfRule.class)
5.4 Test
In the case of the prior polling port 8001 and 8002 alternate, while the load balancing rule becomes random, the random port
VI. Load Balancing Algorithm
6.1 load balancing algorithm: poll
-
Interface rest of the total number of requested number of times the server cluster% = actual call server location subscript
-
Rest after each server restart from the beginning the number of interfaces
List instances = discoveryClient.getInstances(“CLOUD-PROVIDER-SERVICE”)
-
List[0] instances = 127.0.0.1:8002
-
List[1] instances = 127.0.0.1:8001
For example, we now have two machines to load balancing
The number of requests | The formula | Get subscript |
---|---|---|
1 | 1%2=1 | Correspondence 127.0.0.1:8001 |
2 | 2%2=0 | Correspondence 127.0.0.1:8002 |
3 | 3%2=1 | Correspondence 127.0.0.1:8001 |
… | … | … |
6.2 interface class
6.3 Ribbon source
IRule Interface
//IRule接口
public interface IRule{
/*
* choose one alive server from lb.allServers or
* lb.upServers according to key
*
* @return choosen Server object. NULL is returned if none
* server is available
*/
//选择哪个服务实例
public Server choose(Object key);
public void setLoadBalancer(ILoadBalancer lb);
public ILoadBalancer getLoadBalancer();
}
RoundRobinRule polling Source
public class RoundRobinRule extends AbstractLoadBalancerRule {
private AtomicInteger nextServerCyclicCounter;
private static final boolean AVAILABLE_ONLY_SERVERS = true;
private static final boolean ALL_SERVERS = false;
private static Logger log = LoggerFactory.getLogger(RoundRobinRule.class);
public RoundRobinRule() {
nextServerCyclicCounter = new AtomicInteger(0);
}
public RoundRobinRule(ILoadBalancer lb) {
this();
setLoadBalancer(lb);
}
public Server choose(ILoadBalancer lb, Object key) {
if (lb == null) {
log.warn("no load balancer");
return null;
}
Server server = null;
int count = 0;
while (server == null && count++ < 10) {
List<Server> reachableServers = lb.getReachableServers();
List<Server> allServers = lb.getAllServers();
int upCount = reachableServers.size();
int serverCount = allServers.size();
if ((upCount == 0) || (serverCount == 0)) {
log.warn("No up servers available from load balancer: " + lb);
return null;
}
int nextServerIndex = incrementAndGetModulo(serverCount);
server = allServers.get(nextServerIndex);
if (server == null) {
/* Transient. */
Thread.yield();
continue;
}
if (server.isAlive() && (server.isReadyToServe())) {
return (server);
}
// Next.
server = null;
}
if (count >= 10) {
log.warn("No available alive servers after 10 tries from load balancer: "
+ lb);
}
return server;
}
/**
* Inspired by the implementation of {@link AtomicInteger#incrementAndGet()}.
*
* @param modulo The modulo to bound the value of the counter.
* @return The next value.
*/
private int incrementAndGetModulo(int modulo) {
for (;;) {
int current = nextServerCyclicCounter.get();
int next = (current + 1) % modulo;
if (nextServerCyclicCounter.compareAndSet(current, next))
return next;
}
}
@Override
public Server choose(Object key) {
return choose(getLoadBalancer(), key);
}
@Override
public void initWithNiwsConfig(IClientConfig clientConfig) {
}
}
CAS point here with the knowledge points, not little friends can be the venue here: What is CAS
VII. Handwriting load balancing algorithm
7.1 change controller
One way to increase the project ends in 8001
@GetMapping("/payment/lb")
public String getPaymentLB(){
return serverPort;
}
In a similar increase in 8002 project end method
@GetMapping("/payment/lb")
public String getPaymentLB(){
return serverPort;
}
7.2 out of 80 projects Note @LoadBalanced
Commented, after all, we have to use to write their own
7.3 80 projects to increase an interface and an implementation class
interface
package com.aiguigu.springcloud.lb;
import org.springframework.cloud.client.ServiceInstance;
import java.util.List;
public interface LoadBalancer {
ServiceInstance instances(List<ServiceInstance> serviceInstances);
}
Implementation class
package com.aiguigu.springcloud.lb;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.stereotype.Component;
import java.lang.annotation.Annotation;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
@Component
public class MyLB implements LoadBalancer {
private AtomicInteger atomicInteger=new AtomicInteger(0);
public final int getAndIncrement(){
int current;
int next;
do{
current=atomicInteger.get();
next=current>=2147483647?0:current+1;
}while (!this.atomicInteger.compareAndSet(current,next));
System.out.println("***第几次访问,次数: "+next);
return next;
}
public ServiceInstance instances(List<ServiceInstance> serviceInstances){
int index=getAndIncrement()%serviceInstances.size();
return serviceInstances.get(index);
}
}
- Here there is a first class atomic int type, the initial value is 0, there is used a spin lock, so that he is not a time to determine the value of our previous, +1 if it is representative of the number of visits has increased again, not to continue loop until judgment is really out of the loop, there is no guarantee the increase in the number of synchronized method can achieve thread-safe under high concurrency
- The second method of instances ()% to achieve a number of clusters with the current number of visits, so this value will never exceed the number of clusters, and then to obtain this value as the index acquiring a single instance, a current instance of the cluster returns should be returned
7.4 controller layer
New method getPaymentLB ()
@Resource
private LoadBalancer loadBalancer;
@Resource
private DiscoveryClient discoveryClient;
@GetMapping(value = "/consumer/payment/lb")
public String getPaymentLB(){
List<ServiceInstance> instances = discoveryClient.getInstances("CLOUD-PAYMENT-SERVICE");
if(instances==null||instances.size()<0){
return null;
}
ServiceInstance instances1 = loadBalancer.instances(instances);
URI uri = instances1.getUri();
return restTemplate.getForObject(uri+"/payment/lb",String.class);
}
First, obtain an instance of the cluster, and then determine whether the method is empty, the cluster passed to get to the list just write in to get the current instance load balancing acquired, and then get to the instance address, last restTemplate will use the service to call before writing to our load balancing to call
7.5 Test
Call polling method would have been called, embodies our load balancing mechanism just
The server console also print out the first few visits, the service will restart number becomes 0, so to ensure that the memory does not overflow, just set the maximum value is the maximum value of int