SpringCloud微服务架构第三篇

原文链接:https://www.javazhiyin.com/5130.html

微服务开发专栏:https://www.javazhiyin.com/category/springcloud

Ribbon是什么?

Ribbon是基于Netflix Ribbon实现的一套客户端 负载均衡的工具。

简单的说,Ribbon是Netflix发布的开源项目,主要功能是提供客户端的软件负载均衡算法,将Netflix的中间层服务连接在一起。Ribbon客户端组件提供一系列完善的配置项如连接超时,重试等。

简单的说,就是在配置文件中列出Load Balancer(简称LB)后面所有的机器,Ribbon会自动的帮助你基于某种规则(如简单轮询,随机连接等)去连接这些机器。我们也很容易使用Ribbon实现自定义的负载均衡算法。

Ribbon能干什么?

LB,即负载均衡(Load Balance),在微服务或分布式集群中经常用的一种应用。 
负载均衡简单的说就是将用户的请求平摊的分配到多个服务上,从而达到系统的HA。

常见的负载均衡有软件Nginx,LVS,硬件 F5等。

相应的在中间件,例如:dubbo和SpringCloud中均给我们提供了负载均衡,SpringCloud的负载均衡算法可以自定义。

集中式LB:

即在服务的消费方和提供方之间使用独立的LB设施(可以是硬件,如F5, 也可以是软件,如nginx), 由该设施负责把访问请求通过某种策略转发至服务的提供方。

进程内LB:

将LB逻辑集成到消费方,消费方从服务注册中心获知有哪些地址可用,然后自己再从这些地址中选择出一个合适的服务器。

Ribbon就属于进程内LB,它只是一个类库,集成于消费方进程,消费方通过它来获取到服务提供方的地址。

Ribbon的相关资料

https://github.com/Netflix/ribbon/wiki/Getting-Started

Ribbon初步的配置

1.修改microservicecloud-consumer-dept-80工程

1).修改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>

  

2.修改application.yml 追加eureka的服务注册地址

2).修改application.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/

  

3.对ConfigBean类进行新注解@LoadBalanced 获得Rest时加入Ribbon的配置。

3).修改ConfigBean类,增加以下内容:

@Bean

@LoadBalanced //要求客户端通过Rest去访问微服务的时候自带负载均衡

public RestTemplate getRestTemplate(){

return new RestTemplate();

}

4.主启动类DeptConsumer80_App添加@EnableEurekaClient注解。

4).修改主启动类DeptConsumer80_App,增加以下内容:

@SpringBootApplication

@EnableEurekaClient  

public class DeptConsumer80_App {

public static void main(String[] args) {

SpringApplication.run(DeptConsumer80_App.class, args);

}

}

  

5.修改DeptController_Consumer客户端访问类。

5).修改DeptController_Consumer,增加以下内容:

/private static final String REST_URL_PREFIX = "http://localhost:8001";

//从Eureka上面有一个叫MICROSERVICECLOUD-DEPT微服务名字,按名字访问的微服务

private static final String REST_URL_PREFIX = "http://MICROSERVICECLOUD-DEPT";

  

6.测试:

1).先启动3个eureka集群,也就是microservicecloud-eureka-7001,microservicecloud-eureka-7002和microservicecloud-eureka-7003。

2).再启动microservicecloud-provider-dept-8001并注册进eureka。

3).再启动microservicecloud-consumer-dept-80。

输入到浏览器: http://localhost/consumer/dept/get/1 进行测试

输入到浏览器: http://localhost/consumer/dept/list 进行测试

输入到浏览器: http://localhost/consumer/dept/add?dname=大数据部 进行测试

查看我们的mysql数据库看是否添加了大数据部:

添加成功效果图:

总结:Ribbon和Eureka整合后Consumer可以直接调用服务而不用再关心地址和端口号。

Ribbon负载均衡

Ribbon负载均衡架构图:

Ribbon在工作时分成两步

  • 第一步先选择 EurekaServer ,它优先选择在同一个区域内负载较少的server.
  • 第二步再根据用户指定的策略,在从server取到的服务注册列表中选择一个地址。 
    其中Ribbon提供了多种策略:比如轮询、随机和根据响应时间加权。

1.在总父工程下创建microservicecloud-provider-dept-8002的maven Module

1).然后再参考microservicecloud-provider-dept-8001的pom文件,将pom文件里的配置复制一份到microservicecloud-provider-dept-8002 pom文件中

2.在总父工程下再创建microservicecloud-provider-dept-8003的maven Module

1).然后再参考microservicecloud-provider-dept-8001的pom文件,将pom文件里的配置复制一份到microservicecloud-provider-dept-8003 pom文件中

3.将microservicecloud-provider-dept-8001的java源码复制两份分别给microservicecloud-provider-dept-8002和microservicecloud-provider-dept-8003,并且分别修改主启动类名字

修改成功后的效果图:

4.然后再将microservicecloud-provider-dept-8001工程下的resources资源文件夹里面的两个配置文件都复制到microservicecloud-provider-dept-8002和microservicecloud-provider-dept-8003

效果图如下:

然后我们修改microservicecloud-provider-dept-8002和microservicecloud-provider-dept-8003的application.yml文件里面的端口,都分别改为8002和8003端口。

5.新建两个数据库给microservicecloud-provider-dept-8002和microservicecloud-provider-dept-8003这两个工程连接和使用

备注:创建cloudDB02数据库,执行以下sql语句

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;

  

再创建一个名为cloudDB03的数据库,执行以下sql语句。

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;

  

然后再改microservicecloud-provider-dept-8002和microservicecloud-provider-dept-8003这两个工程的application.yml文件下的数据库源的url指定的数据库名字

  • microservicecloud-provider-dept-8002工程连 cloudDB02,
  • microservicecloud-provider-dept-8003工程连 cloudDB03。

好了,我们做了那么多配置和修改,现在要进入测试我们的负载均衡了!!!!

测试的步骤:

1.启动3个eureka集群配置(microservicecloud-eureka-7001系列)

2.启动3个Dept微服务并各自测试通过(microservicecloud-provider-dept-8001系列)

启动3个Dept微服务成功后先进行一次测试

1).先在浏览器输入第一个网址:http://localhost:8001/dept/list 进行测试

2).再从浏览器中输入第二个网址:http://localhost:8002/dept/list 进行测试

3).再从浏览器中输入第三个网址:http://localhost:8003/dept/list 进行测试

如果三个网址都成功出现JSON字符串,并且db_source的数据都不同,那么说明成功了!!!

3.启动microservicecloud-consumer-dept-80

启动成功以后,在浏览器输入:http://localhost/consumer/dept/list

就可以体现负载均衡的效果了。

启动成功后的负载均衡效果图: 这是第一次访问的结果,

我们在http://localhost/consumer/dept/list 这个页面上刷新一次该页面就会看到clouddb03会变成clouddb02再刷新一次就会变成clouddb01。依次这样,这种模式采用的是轮询算法,这里就不演示了。

备注:注意观察看到返回的数据库名字,各不相同,负载均衡实现

然后再打开http://eureka7001.com:7001/ 你就可以看到在一个微服务下面挂着三个实例

总结:Ribbon其实就是一个软负载均衡的客户端组件,他可以和其他所需请求的客户端结合使用,和eureka结合只是其中的一个实例。

Ribbon核心组件之IRule

根据特定算法中从服务列表中选取一个要访问的服务。

SpringCloud结合Ribbon,它默认出厂自带了7种算法。

第一种是:RoundRobinRule 轮询

第二种是:RandomRule 随机

第三种是:AvailabilityFilteringRule 会先过滤掉由于多次访问故障而处于断路器跳闸状态的服务,

还有并发的连接数量超过阈值的服务,然后对剩余的服务列表按照轮询策略进行访问。

第四种是:WeightedResponseTimeRule 根据平均响应时间计算所有服务的权重,响应时间越快服务权重越大被选中的概率越高。刚启动时如果统计信息不足,则使用RoundRobinRule策略,等统计信息足够, 
会切换到WeightedResponseTimeRule。

第五种是:RetryRule 先按照RoundRobinRule的策略获取服务,如果获取服务失败则在指定时间内会进行重试,获取可用的服务。

第六种是:BestAvailableRule 会先过滤掉由于多次访问故障而处于断路器跳闸状态的服务,然后选择一个并发量最小的服务。

第七种是:ZoneAvoidanceRule 默认规则,复合判断server所在区域的性能和server的可用性选择服务器。

那么目前,我们实现了第一种算法RoundRobinRule 轮询的方式。

那我们就来做第二种随机算法的实现吧。

在microservicecloud-consumer-dept-80工程ConfigBean类下做一个随机算法的方法

@Bean

public IRule myRule(){

//用重新选择的随机算法替代默认的轮询算法。

return new RandomRule();

}

  

我们来测试一下:

1.启动3个eureka集群配置(microservicecloud-eureka-7001系列)。

2.启动3个Dept微服务并各自测试通过(microservicecloud-provider-dept-8001系列)。

3.启动microservicecloud-consumer-dept-80工程进行随机算法的测试。

请在浏览器输入:http://localhost/consumer/dept/list

随机的效果我不截图了,因为用了随机算法,随机的效果的体现你们就能体会的到。

那么其他的一些算法,我就不一一进行展示了。

Ribbon自定义算法

如果上面的7种算法,都不够出来业务逻辑,那么可以来自定义算法。

1.修改microservicecloud-consumer-dept-80的主启动类

1).在主启动类上添加一个注解@RibbonClient()

/*在启动该微服务的时候就能去加载我们的自定义Ribbon配置类,从而使配置生效。

并且官方文档明确给出了警告:

这个自定义配置类不能放在@ComponentScan所扫描的当前包下以及子包下,

否则我们自定义的这个配置类就会被所有的Ribbon客户端所共享,也就是说

我们达不到特殊化定制的目的了。*/

//那么解决方案是重新在java包下再建一个包名,并把MySelfRule类放入该包内。

@RibbonClient(name="MICROSERVICECLOUD-DEPT",configuration=MySelfRule.class)

请看下面的效果图:

编写MySelfRule自定义配置类的:

@Configuration

public class MySelfRule{

@Bean

public IRule myRule()

 {

return new RandomRule();//Ribbon默认是轮询,我自定义为随机

}

}

  

然后进行测试:

1.启动3个eureka集群配置(microservicecloud-eureka-7001系列)。

2.启动3个Dept微服务并各自测试通过(microservicecloud-provider-dept-8001系列)。

3.启动microservicecloud-consumer-dept-80工程进行随机算法的测试。

请在浏览器输入:http://localhost/consumer/dept/get/1

测试的效果我不截图了,因为用的是自定义随机算法,随机的效果的实现你们就能体会的到。

自定义规则深度解析

需求:依旧轮询策略,但是加上新需求,每个服务器要求被调用5次。也即以前是每台机器一次,现在是每台机器5次。

需求代码实现: 在MySelfRule类中的myRule方法里面添加以下内容:

@Configuration

public class MySelfRule {

@Bean

public IRule myRule()

   {

//return new RandomRule();//Ribbon默认是轮询,自定义为随机

return new RandomRule();

}

  

然后在myrule包下创建一个RandomRule_hhf的类,并且添加以下内容:

解析源码:https://github.com/Netflix/ribbon/blob/master/ribbon-loadbalancer/src/main/java/com/netflix/loadbalancer/RandomRule.java

import com.netflix.client.config.IClientConfig;

import com.netflix.loadbalancer.AbstractLoadBalancerRule;

import com.netflix.loadbalancer.ILoadBalancer;

import com.netflix.loadbalancer.Server;

import java.util.List;

import java.util.concurrent.ThreadLocalRandom;

//需求是5次,但是微服务只有8001,8002,8003三台机器

public class RandomRule_hhf extends AbstractLoadBalancerRule {

//总共被调用的次数,目前要求每台被调用5次

private int total = 0;

//当前提供服务的机器号

private int currentIndex = 0;

public Server choose(ILoadBalancer lb, Object key) {

//ILoadBalancer哪一种负载均衡算法如果等于null的话就返回null,那么自然而然,它肯定会加载一种算法,所以它不会变成null。

if (lb == null) {

return null;

}

//现在还不知道是哪个算法来响应server

Server server = null;

//如果说server等于null,那么就看线程是否中断了,如果被中断的话就返回null

while (server == null) {

if (Thread.interrupted()) {

return null;

}

//upList的意思就是现在活着的可以对外提供的机器,然后.get()方法通过

//int index = rand.nextInt(serverCount); 那么就是随机到几就返回第几的值

List<Server> upList = lb.getReachableServers();

List<Server> allList = lb.getAllServers();

//如果serverCount目前有三台,那么就不等于0,那么就是flase。

int serverCount = allList.size();

if (serverCount == 0) {

/*

* No servers. End regardless of pass, because subsequent passes

* only get more restrictive.

*/

return null;

}

//这个的意思就是说如果serverCount有三台,那么index就得到了从下标0和1和2数组

// int index = rand.nextInt(serverCount);

// server = upList.get(index);

//当第一次total < 5的时候

//当第二次total < 5的时候

//当第五次total < 5的时候(那么第五次就不小于5),那么if(total < 5)这段里面的代码就不执行了

if(total < 5){

//那么第一次的server是0号机

//那么第二次的server也是0号机

server = upList.get(currentIndex);

//第一次的总的计数次数是加一个1

//第二次的总的计数次数是再加一个1

total++;

//当第五次total < 5的时候就走else

}else {

//那么total等于0

total = 0;

//而currentIndex就加一个1

currentIndex++;

//那么1大于等于upList.size(),目前假设有三台机器,那么1就不大于等于upList.size()

//那么现在就是给0号机给1号机进行服务了,以此类推。。

//但是如果currentIndex等于下标3的时候并且>= upList.size(),但我们按照数组下标来算的话只               //有0和1和2的下标,那么当currentIndex等于下标3的时候这样就是超过第三台了,那么                        //currentIndex就重新等于0。以此类推。。

if(currentIndex >= upList.size())

{

currentIndex = 0;

}

}

//如果这个server等于null,那么线程中断一会,下一轮继续

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;

}

//如果活着好好的,那么就返回server回去

if (server.isAlive()) {

return (server);

}

// Shouldn‘t actually happen.. but must be transient or a bug.

server = null;

Thread.yield();

}

//返回对应该响应服务是8001,还是8002还是8003

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) {

}

}

那么我们的自定义算法定义好了以后,我们再回到MySelfRule类中添加RandomRule_hhf类进行自定义算法的测试了

在MySelfRule类中添加RandomRule_hhf类:

@Configuration

public class MySelfRule {

@Bean

public IRule myRule()

{

//return new RandomRule();//Ribbon默认是轮询,自定义为随机

//return new RandomRule();

return new RandomRule_hhf();  //自定义每台机器5次

}

}

进入测试:

1.启动3个eureka集群配置(microservicecloud-eureka-7001系列)。

2.启动3个Dept微服务并各自测试通过(microservicecloud-provider-dept-8001系列)。

3.启动microservicecloud-consumer-dept-80工程进行自定义负载均衡算法的测试。

请在浏览器输入:http://localhost/consumer/dept/get/1

测试的效果我不截图了,只要在页面刷新5次即可看出效果!!

原文地址:https://www.cnblogs.com/javazhiyin/p/9406627.html

时间: 2024-10-07 12:37:49

SpringCloud微服务架构第三篇的相关文章

Java生鲜电商平台-SpringCloud微服务架构中网络请求性能优化与源码解析

Java生鲜电商平台-SpringCloud微服务架构中网络请求性能优化与源码解析 说明:Java生鲜电商平台中,由于服务进行了拆分,很多的业务服务导致了请求的网络延迟与性能消耗,对应的这些问题,我们应该如何进行网络请求的优化与处理呢? 到底有没有一些好的建议与方案呢? 下面这个文章将揭晓上面的问题,让你对SpringCloud微服务网络请求性能有一个全新的认识. 目录简介 01.网络请求异常分类 02.开发中注意问题 03.原始的处理方式 04.如何减少代码耦合性 05.异常统一处理步骤 06

基于SpringCloud 微服务架构下 广告系统设计与实现完整教程

var link="www.marenzy.top"//完整视频资源获取地址,复制链接在浏览器打开 var vx="aishangit666"//如链接失效可添加微信 基于Spring Cloud微服务架构 广告系统设计与实现 广告系统是互联网公司中的必备知识体系,但是关于怎样设计.实现广告系统的资料.课程却非常稀少 .本课程将从零开始逐步实现广告系统中最为核心的两个模块:广告投放系统与广告检索系统,并测试它们的可用性,让你在实战中学习广告系统的设计思想,实现方法,

(三)springcloud - 微服务架构代码结构

我们根据微服务化设计思想,结合spring cloud本身的服务发现.治理.配置化管理.分布式等项目优秀解决方案,我们使用Maven技术将框架进行模块化.服务化.原子化封装,也为后期的热插拔.持续集成做一些准备工作. particle云架构使用maven来构建的,使用maven不仅仅是jar包的管控,重要的是要抓住maven的一个核心作用,那就是将整个项目按照模块化的方式进行划分,业务与业务之间解耦,然后将模块化的业务再进行服务化或者组件化,这样可以进行任意的项目或者平台的业务移植.最后还要考虑

构建SpringBoot,SpringCloud微服务架构分布式电商项目实战

Spring Cloud 微服务总体架构图 上面图中技术名词理解: 1.Sleuth-链路跟踪 为服务之间调用提供链路追踪.通过Sleuth可以很清楚的了解到一个服务请求经过了哪些服务,每个服务处理花费了多长.从而让我们可以很方便的理清各微服务间的调用关系. 2.断路器(Hystrix) 在微服务架构中,根据业务来拆分成一个个的服务,服务与服务之间可以相互调用(RPC),在Spring Cloud可以用RestTemplate+Ribbon和Feign来调用.为了保证其高可用,单个服务通常会集群

基于SpringCloud 微服务架构下 广告系统设计与实现

第1章 课程简介本章对这门课程进行说明,包括:广告系统的介绍.课程使用的技术介绍.课程的学习规划等. 第2章 广告系统概览与准备工作本章会介绍广告系统的思想.广告系统的技术实现架构.学习本课程之前的准备工作和广告系统的代码目录结构. 第3章 广告系统骨架开发广告系统使用SpringCloud微服务框架开发,并使用Maven做多模块管理.这一章完成项目骨架的开发,包括搭建注册中心和服务网关,同时也会对Maven的重要特性做介绍. 第4章 微服务通用模块开发本章实现广告系统微服务通用的功能,例如:统

SpringCloud微服务架构搭建--Mybatis-Plus(三)

学而时习之,不亦说乎 前言 具体业务实现离不开与数据库交互,本章重点记录一下SpringBoot集成druid数据源,集成mybatis-plus,为了开发方便,基于mybatis-plus的代码生成器,实现对业务最基本的增删改查操作. 准备工作 在mysql数据库中创建mingx_user库,并创建sys_user表,用于后续查询验证.表生成代码如下: DROP TABLE IF EXISTS `sys_user`;CREATE TABLE `sys_user` (  `id` varchar

Spring Cloud构建微服务架构(三)断路器

在分布式架构中,断路器模式的作用也是类似的,当某个服务单元发生故障(类似用电器发生短路)之后,通过断路器的故障监控(类似熔断保险丝),向调用方返回一个错误响应,而不是长时间的等待.这样就不会使得线程因调用故障服务被长时间占用不释放,避免了故障在分布式系统中的蔓延. Netflix Hystrix 在Spring Cloud中使用了Hystrix 来实现断路器的功能.Hystrix是Netflix开源的微服务框架套件之一,该框架目标在于通过控制那些访问远程系统.服务和第三方库的节点,从而对延迟和故

pring Cloud构建微服务架构

SpringCloud-Learning 本项目内容为Spring Cloud教程的程序样例. 作者博客:http://blog.didispace.com Spring Cloud系列博文:http://blog.didispace.com/categories/Spring-Cloud/ Spring Cloud中文社区:http://bbs.springcloud.com.cn/ GitHub:https://github.com/dyc87112/SpringCloud-Learning

Devops微服务架构下具有代码级穿透能力的精准测试

微服务是Devops场景下热门的开发框架,在大型项目中被广泛采用.它把一个大型的单个应用程序和服务拆分为数十个的支持微服务,独立部署.互相隔离,通过扩展组件来处理功能瓶颈问题,比传统的应用程序更能有效利用计算资源.微服务之间无需关心对方的模型,它通过事先约定好的接口进行数据流转,使业务可以高效响应市场变化.但微服务一个明显的表象就是随着服务的增多,传统的测试模式受到很大制约,无法有效进行下去,威胁到整体系统质量.所有J2EE代码层白盒采集工具都无法区分覆盖和具体功能的对应关系,只能以后台模式"笼