ribbon負載均衡,feign負載均衡,nginx負載均衡。springcloud對dubbo。eureka對dubbo。
從阿裡巴巴等級的p3到p10。
舉例說明,我去麥當勞買吃的,有三個視窗,三個視窗是服務端,我是用戶端,我如果不傻的話肯定去人少的那個視窗,這就是用戶端的負載均衡。
程序内就類似于麥當勞點餐,我看哪裡人少就去哪裡排隊。去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通路服務的時候自帶用戶端的負載均衡,需要開啟,
做到這裡看不懂?完成真正的通過微服務名字從eureka上找到并通路。修改啟動類,
修改用戶端的通路類,成為真正的微服務,
分别啟動7001,7002,7003和8001,80工程,使用微服真正的路徑通路
負載規則預設是輪訓。建立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中資料名,服務名絕對不能動。
啟動三個eureka700x,然後啟動三個微服務800x,測試,其實consumer才是暴露給廣大消費者
自測通過。然後啟動80。記得修改
通路consumer位址連續通路三次,
以上測試證明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。自定義算法。
在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);
}
}
@SpringBootApplication注解就有
不能放到和啟動類同級或子包中。建立包和類,
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全家桶源碼位址: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沒什麼意義,有意義的是改源碼,讀源碼,寫邏輯算法。