分别在两个服务下进行集群配置
服务提供者集群搭建
创建8002提供者
将8001的全部粘贴过来,不用改application: name
这时候对外暴露的服务需体现出负载均衡。所以这里
1,改8001 controller
2,8002同理
这时候5个服务启动。访问所有服务都正常。但是访问consumer,只能通过8001.。。。因为原程序restTemplete那里写死了
3, 还有必须开启restTemplete负载均衡功能
在配置类。。。加一个@loadbalance注解
其实就是服务名的改变
1,只暴露服务名,去掉主机名 2,你鼠标指到微服务名字。要显示ip。
1,
8001
随便点开一个服务
然后把后缀info改成health。。。健康检查状态
现在是UP
2,
8001 修改controller
自己写个方法自测
2,主启动类
启动就好
eureka自我保护机制默认自我保护是开启的。。。 7001
8001
启动注册中心和8001,发现8001注册上去了。但是8001如果服务停了。再刷新eureka。。发现服务就没了。
eureka基本淘汰。现在用zookeeper来代替
创建一个payment8004提供者注册进入zookeeper pom文件,eureka换成zookeeper
version 2.2.2.RELEASE
yml
启动类
controller
启动以后发现,没有报错。controller也可以正常使用
2,创建一个消费者注册进zookeeper
pom复制8004的
yml
config和controller复制之前order80的
然后controller进行修改
1,下载consul 2,配置环境变量,把文件夹根目录配置进去 3,执行consul agent -dev启动consul
编码部分 pom.xml
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-consul-discovery</artifactId> <version>2.1.0.RELEASE</version> </dependency>application.yml
server: port: 8006 spring: application: name: consul-provider-payment cloud: consul: host: localhost port: 8500 discovery: service-name: ${spring.application.name}controller
import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.util.UUID; @RestController @Slf4j public class PaymentController { @Value("${server.port}") private String serverport; @RequestMapping(value="/payment/consul") public String paymentConsul(){ return serverport+"\t"+ UUID.randomUUID().toString(); } }主启动类
package com.atguigu.springcloud; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; @SpringBootApplication @EnableDiscoveryClient public class PaymentMain8006 { public static void main(String[] args) { SpringApplication.run(PaymentMain8006.class,args); } }###consumer 1,pom.xml同上 2,application.yml改动端口号和服务名 3,启动类一样 4,增加一个config
package com.atguigu.springcloud.config; 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; @Configuration public class ApplicationContextConfig { @Bean @LoadBalanced public RestTemplate getRestTemplate(){ return new RestTemplate(); } }5,业务类
package com.atguigu.springcloud.controller; import com.atguigu.springcloud.entities.CommonResult; import com.atguigu.springcloud.entities.Payment; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.client.RestTemplate; import javax.annotation.Resource; @RestController @Slf4j public class OrderConsulController { public static final String PAYMENT_URL="http://consul-provider-payment"; @Resource private RestTemplate restTemplate; @GetMapping("/consumer/consul") public String paymentInfo(){ String result=restTemplate.getForObject(PAYMENT_URL+"/payment/consul",String.class); return result; } }###eureka zookeeper和consul三个注册中心的异同 eureka:java编写,ap(高科用,分区容错)。对外暴露http 被springcloud集成
consul:go编写,cp(强一致,分区容错)。对外暴露http/DNS 被springcloud集成
zookeeper:java编写,cp(强一致,分区容错)。对外暴露客户端 被springcloud集成
zookeeper是临时节点还是持久节点? 都有。创建以后一直都在就是持久节点 服务停止则立即被剔除就是临时节点
它是客户端的负载均衡工具
ribbon暂时不被替换。可能未来会被loadbalacer替代
#ribbon和nginx的区别? nginx是客户端请求。由nginx转发 ribbon是本地的负载均衡。本地实现rpc远程调用 ribbon属于进程内lb 。nginx属于集中式lb
eureka的pom文件没有引入ribbon为什么可以使用它? 因为新版的spring-cloud-start-netflix-eureka-client自己集成了ribbon
ribbon远程调用的实现就是负载均衡+RestTemplete
RestTemplete的ForEntity用法
编码
1,在ordermain80的controller里面加方法
//restTemplete的ForEntity @GetMapping("/consumer/payment/getForEntity/{id}") public CommonResult<Payment>entity(@PathVariable("id")Long id){ ResponseEntity<CommonResult>entity=restTemplate.getForEntity(PAYMENT_URL+"/payment/get/"+id,CommonResult.class); if(entity.getStatusCode().is2xxSuccessful()){ return entity.getBody(); }else{ return new CommonResult<>(444,"操作失败"); } }ribbon轮询算法。实现了IRule接口
一共七种 BestAvailableRule :选择一个最小的并发请求的server AvailabilityFilteringRule :过滤掉那些因为一直连接失败的被标记为circuit tripped的后端server,并过滤掉那些高并发的的后端server(active connections 超过配置的阈值) WeightedResponseTimeRule :根据相应时间分配一个weight,相应时间越长,weight越小,被选中的可能性越低 RetryRule :对选定的负载均衡策略机上重试机制 RoundRobinRule:roundRobin方式轮询选择server RandomRule:随机选择一个server ZoneAvoidanceRule:复合判断server所在区域的性能和server的可用性选择server
###替换方法
1,替换80的consumer项目 2,ribbon的轮询替换不允许跟有@ComponentScan一起
3,新建包com.atguigu.myrule 4,新建类:MyselfRule
package com.atguigu.springcloud.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,主启动类
@RibbonClient(name = "CLOUD-PAYMENT-SERVICE",configuration = MySelfRule.class)再访问localhost/consumer/payment/get/1
##负载均衡算法 rest访问次数%服务集群数=实际调用服务器位置下标。每次重启服务后,rest接口计数从1开始
RoundRobinRule底层用到CAS,比较并交换,自旋锁的方式
手写ribbon负载均衡
1,7001,7002集群启动 2,8001,8002微服务改造 3,80订单微服务改造
1,8001,8002的controller里加一个方法 //手写ribbon 负载均衡
@GetMapping(value="/payment/lb") public String getPaymentLB(){ return serverport; }2,注释掉applicationContextConfig里的@LoadBalanced注解 3,在order 80里新建包Lb,新建接口LoadBalacer
package com.atguigu.springcloud.lb; import org.springframework.cloud.client.ServiceInstance; import java.util.List; public interface LoadBalancer { ServiceInstance instance(List<ServiceInstance>serviceInstances); }4,实现类 MyLB
package com.atguigu.springcloud.lb; import org.springframework.cloud.client.ServiceInstance; 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=this.atomicInteger.get(); next=current>=2147483647?0:current+1; }while(!this.atomicInteger.compareAndSet(current,next)); System.out.println("************next:"+next); return next; } @Override public ServiceInstance instance(List<ServiceInstance> serviceInstances) { int index=getAndIncrement()% serviceInstances.size(); return serviceInstances.get(index); } }5,controller
package com.atguigu.springcloud.controller; import com.atguigu.springcloud.entities.CommonResult; import com.atguigu.springcloud.entities.Payment; import com.atguigu.springcloud.lb.LoadBalancer; import lombok.extern.slf4j.Slf4j; import org.springframework.cloud.client.ServiceInstance; import org.springframework.cloud.client.discovery.DiscoveryClient; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import org.springframework.web.client.RestTemplate; import javax.annotation.Resource; import java.net.URI; import java.util.List; @RestController @Slf4j public class OrderController { public static final String PAYMENT_URL="http://CLOUD-PAYMENT-SERVICE"; @Resource private RestTemplate restTemplate; @Resource private LoadBalancer loadBalancer; @Resource private DiscoveryClient discoveryClient; @PostMapping("/consumer/payment/add") public CommonResult<Payment>create(@RequestBody Payment payment){ return restTemplate.postForObject(PAYMENT_URL+"/payment/add",payment,CommonResult.class); } @GetMapping("/consumer/payment/get/{id}") public CommonResult<Payment>get(@PathVariable("id")Long id){ return restTemplate.getForObject(PAYMENT_URL+"/payment/get/"+id,CommonResult.class); } //restTemplete的ForEntity @GetMapping("/consumer/payment/getForEntity/{id}") public CommonResult<Payment>entity(@PathVariable("id")Long id){ ResponseEntity<CommonResult>entity=restTemplate.getForEntity(PAYMENT_URL+"/payment/get/"+id,CommonResult.class); if(entity.getStatusCode().is2xxSuccessful()){ return entity.getBody(); }else{ return new CommonResult<>(444,"操作失败"); } } //手写ribbon负载均衡 @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 serviceInstance=loadBalancer.instance(instances); URI uri=serviceInstance.getUri(); return restTemplate.getForObject(uri+"/payment/payment/lb",String.class); } }