服务提供者集群搭建
创建8002提供者
将8001的全部粘贴过来,不用改application:
name
这时候对外暴露的服务需体现出负载均衡。所以这里
2,8002同理
这时候5个服务启动。访问所有服务都正常。但是访问consumer,只能通过8001.。。。因为原程序restTemplete那里写死了
在配置类。。。加一个@loadbalance注解
其实就是服务名的改变
1,只暴露服务名,去掉主机名
2,你鼠标指到微服务名字。要显示ip。
1,
8001
随便点开一个服务
然后把后缀info改成health。。。健康检查状态
现在是UP
2,
8001
修改controller
自己写个方法自测
2,主启动类
启动就好
eureka自我保护机制
8001
启动注册中心和8001,发现8001注册上去了。但是8001如果服务停了。再刷新eureka。。发现服务就没了。
eureka基本淘汰。现在用zookeeper来代替
创建一个payment8004提供者注册进入zookeeper
pom文件,eureka换成zookeeper
version 2.2.2.RELEASE
yml
启动类
启动以后发现,没有报错。controller也可以正常使用
2,创建一个消费者注册进zookeeper
pom复制8004的
config和controller复制之前order80的
然后controller进行修改
1,下载consul
2,配置环境变量,把文件夹根目录配置进去
3,执行consul agent -dev启动consul
编码部分
pom.xml
org.springframework.cloud
spring-cloud-starter-consul-discovery
2.1.0.RELEASE
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 CommonResultentity(@PathVariable("id")Long id){
ResponseEntityentity=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(ListserviceInstances);
}
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 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 CommonResultcreate(@RequestBody Payment payment){
return restTemplate.postForObject(PAYMENT_URL+"/payment/add",payment,CommonResult.class);
}
@GetMapping("/consumer/payment/get/{id}")
public CommonResultget(@PathVariable("id")Long id){
return restTemplate.getForObject(PAYMENT_URL+"/payment/get/"+id,CommonResult.class);
}
//restTemplete的ForEntity
@GetMapping("/consumer/payment/getForEntity/{id}")
public CommonResultentity(@PathVariable("id")Long id){
ResponseEntityentity=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(){
Listinstances=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);
}
}