天天看點

springcloud全家桶之ribbon

ribbon負載均衡,feign負載均衡,nginx負載均衡。springcloud對dubbo。eureka對dubbo。

springcloud全家桶之ribbon

從阿裡巴巴等級的p3到p10。

springcloud全家桶之ribbon
springcloud全家桶之ribbon

舉例說明,我去麥當勞買吃的,有三個視窗,三個視窗是服務端,我是用戶端,我如果不傻的話肯定去人少的那個視窗,這就是用戶端的負載均衡。

springcloud全家桶之ribbon
springcloud全家桶之ribbon
springcloud全家桶之ribbon
springcloud全家桶之ribbon

程序内就類似于麥當勞點餐,我看哪裡人少就去哪裡排隊。去github code是代碼,主要的是看wiki,仔細去扣就會有收獲。學習準則:理論+實戰。正确的思維方式+落地方法論。皮肉骨魂四種境界,魂是學習達不到的,就如架構師魂是不停地加班不停地熬夜自己修成的。消費者的負載均衡,在80工程上pom

<!-- Ribbon相關 -->
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-eureka</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-ribbon</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-config</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
           

需要整合eureka用戶端。80的yml

eureka:
  client:
    register-with-eureka: false
    service-url: 
      defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/  
           

目的是80中controller的restTemplate通路服務的時候自帶用戶端的負載均衡,需要開啟,

springcloud全家桶之ribbon

做到這裡看不懂?完成真正的通過微服務名字從eureka上找到并通路。修改啟動類,

springcloud全家桶之ribbon

修改用戶端的通路類,成為真正的微服務,

springcloud全家桶之ribbon

分别啟動7001,7002,7003和8001,80工程,使用微服真正的路徑通路

springcloud全家桶之ribbon
springcloud全家桶之ribbon

負載規則預設是輪訓。建立8002,8003工程,參考8001

<dependencies>
		<!-- 引入自己定義的api通用包,可以使用Dept部門Entity -->
		<dependency>
			<groupId>com.atguigu.springcloud</groupId>
			<artifactId>microservicecloud-api</artifactId>
			<version>${project.version}</version>
		</dependency>
		<!-- actuator監控資訊完善 -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-actuator</artifactId>
		</dependency>
		<!-- 将微服務provider側注冊進eureka -->
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-eureka</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-config</artifactId>
		</dependency>
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
		</dependency>
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
		</dependency>
		<dependency>
			<groupId>com.alibaba</groupId>
			<artifactId>druid</artifactId>
		</dependency>
		<dependency>
			<groupId>ch.qos.logback</groupId>
			<artifactId>logback-core</artifactId>
		</dependency>
		<dependency>
			<groupId>org.mybatis.spring.boot</groupId>
			<artifactId>mybatis-spring-boot-starter</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-jetty</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
		</dependency>
		<!-- 修改後立即生效,熱部署 -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>springloaded</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-devtools</artifactId>
		</dependency>
	</dependencies>
           

同時将8001所有的東西src/main/java都放到8002和8003記得改啟動類名字。src/main/resources全部都放到8001,8002修改yml端口。每個微服務對應一個獨立的資料庫800x就展現了。建立sql表2和3

DROP DATABASE IF EXISTS cloudDB02;
CREATE DATABASE cloudDB02 CHARACTER SET UTF8;
USE cloudDB02;
CREATE TABLE dept
(
  deptno BIGINT NOT NULL PRIMARY KEY AUTO_INCREMENT,
  dname  VARCHAR(60),
  db_source  VARCHAR(60)
);

INSERT INTO dept(dname,db_source) VALUES('開發部',DATABASE());
INSERT INTO dept(dname,db_source) VALUES('人事部',DATABASE());
INSERT INTO dept(dname,db_source) VALUES('财務部',DATABASE());
INSERT INTO dept(dname,db_source) VALUES('市場部',DATABASE());
INSERT INTO dept(dname,db_source) VALUES('運維部',DATABASE());

SELECT * FROM dept;
           
DROP DATABASE IF EXISTS cloudDB03;
CREATE DATABASE cloudDB03 CHARACTER SET UTF8;
USE cloudDB03;
CREATE TABLE dept
(
  deptno BIGINT NOT NULL PRIMARY KEY AUTO_INCREMENT,
  dname  VARCHAR(60),
  db_source  VARCHAR(60)
);

INSERT INTO dept(dname,db_source) VALUES('開發部',DATABASE());
INSERT INTO dept(dname,db_source) VALUES('人事部',DATABASE());
INSERT INTO dept(dname,db_source) VALUES('财務部',DATABASE());
INSERT INTO dept(dname,db_source) VALUES('市場部',DATABASE());
INSERT INTO dept(dname,db_source) VALUES('運維部',DATABASE());

SELECT * FROM dept;
           

修改yml中資料名,服務名絕對不能動。

springcloud全家桶之ribbon

啟動三個eureka700x,然後啟動三個微服務800x,測試,其實consumer才是暴露給廣大消費者

springcloud全家桶之ribbon
springcloud全家桶之ribbon
springcloud全家桶之ribbon

自測通過。然後啟動80。記得修改

springcloud全家桶之ribbon

通路consumer位址連續通路三次,

springcloud全家桶之ribbon
springcloud全家桶之ribbon
springcloud全家桶之ribbon
springcloud全家桶之ribbon

以上測試證明ribbon負載均衡算法預設是輪訓政策。

springcloud全家桶之ribbon
springcloud全家桶之ribbon

是一個其他的負載均衡方式,關閉80其他六個開啟,如果沒有顯示的聲明就用預設的輪詢方法,80配置類中加

package com.atguigu.springcloud.cfgbeans;

import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RetryRule;
import com.netflix.loadbalancer.RoundRobinRule;

@Configuration
public class ConfigBean //boot -->spring   applicationContext.xml --- @Configuration配置   ConfigBean = applicationContext.xml
{ 
	@Bean
	@LoadBalanced
	public RestTemplate getRestTemplate()
	{
		return new RestTemplate();
	}
	@Bean
	public IRule myRule()
	{
//		return new RoundRobinRule();
		return new RandomRule();
	}
}
           

然後啟動80重新整理幾次看是否是随機算法,如果不是随機還是輪詢則重新開機所有工程再測試,ok我成功了。繼續換,

@Bean
	public IRule myRule()
	{
//		return new RoundRobinRule();
//		return new RandomRule();
		return new RetryRule();
	}
           

retryrule也是 輪詢,不一樣的是關閉一個微服務後8002關閉,重新整理頁面也是輪詢不過到了02時會error page,但是稍等一段時間後他會自動跳過02直接輪詢01和03。自定義算法。

springcloud全家桶之ribbon

在80啟動類添加,

package com.atguigu.springcloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.ribbon.RibbonClient;

@SpringBootApplication
@EnableEurekaClient
//在啟動該微服務的時候就能去加載我們的自定義Ribbon配置類,進而使配置生效
//@RibbonClient(name="MICROSERVICECLOUD-DEPT",configuration=MySelfRule.class)
@RibbonClient(name="MICROSERVICECLOUD-DEPT",configuration=MySelfRule.class)
public class DeptConsumer80_App
{
	public static void main(String[] args)
	{
		SpringApplication.run(DeptConsumer80_App.class, args);
	}
}
           
springcloud全家桶之ribbon

@SpringBootApplication注解就有

springcloud全家桶之ribbon

不能放到和啟動類同級或子包中。建立包和類,

package com.atguigu.myrule;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RandomRule;

@Configuration
public class MySelfRule
{
	@Bean
	public IRule myRule()
	{
		return new RandomRule();// Ribbon預設是輪詢,我自定義為随機
	}
}
           

自定義類,模仿RoundRobinRule類,

package com.atguigu.myrule;

import java.util.List;

import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.AbstractLoadBalancerRule;
import com.netflix.loadbalancer.ILoadBalancer;
import com.netflix.loadbalancer.Server;

public class RandomRule_ZY extends AbstractLoadBalancerRule
{

	// total = 0 // 當total==5以後,我們指針才能往下走,
	// index = 0 // 目前對外提供服務的伺服器位址,
	// total需要重新置為零,但是已經達到過一個5次,我們的index = 1
	// 分析:我們5次,但是微服務隻有8001 8002 8003 三台,OK?
	// 
	
	
	private int total = 0; 			// 總共被調用的次數,目前要求每台被調用5次
	private int currentIndex = 0;	// 目前提供服務的機器号

	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();
			List<Server> allList = lb.getAllServers();

			int serverCount = allList.size();
			if (serverCount == 0) {
				/*
				 * No servers. End regardless of pass, because subsequent passes only get more
				 * restrictive.
				 */
				return null;
			}

//			int index = rand.nextInt(serverCount);// java.util.Random().nextInt(3);
//			server = upList.get(index);

			
//			private int total = 0; 			// 總共被調用的次數,目前要求每台被調用5次
//			private int currentIndex = 0;	// 目前提供服務的機器号
            if(total < 5)
            {
	            server = upList.get(currentIndex);
	            total++;
            }else {
	            total = 0;
	            currentIndex++;
	            if(currentIndex >= upList.size())
	            {
	              currentIndex = 0;
	            }
            }			
			
			
			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;

	}

	@Override
	public Server choose(Object key)
	{
		return choose(getLoadBalancer(), key);
	}

	@Override
	public void initWithNiwsConfig(IClientConfig clientConfig)
	{
		// TODO Auto-generated method stub

	}

}
           
springcloud全家桶之ribbon
springcloud全家桶之ribbon

在這裡給小夥伴一個驚喜,那就是到本節結束springcloud全家桶源碼位址:https://github.com/batare11/springCloud2018

修改自定義類,使用我們自定義的算法,

package com.atguigu.myrule;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RandomRule;
import com.netflix.loadbalancer.RoundRobinRule;

@Configuration
public class MySelfRule
{
	@Bean
	public IRule myRule()
	{
//		return new RandomRule();// Ribbon預設是輪詢,我自定義為随機
//		return new RoundRobinRule();
		return new RandomRule_ZY();// 我自定義為每台機器5次
	}
}
           

啟動所有工程,通路80測試,測試成功!

到此為止,ribbon完畢,irule完畢。debug沒什麼意義,有意義的是改源碼,讀源碼,寫邏輯算法。

繼續閱讀