SpringCloud从零开始搭建

一、注册中心

Eureka

CAP定理: Eureka是AP (高可用性,分区容错性)

Eureka由多个instance(服务实例)组成,这些服务实例可以分为两种:Eureka ServerEureka Client。为了便于理解,我们将Eureka client再分为Service Provider和Service Consumer。

  • Eureka Server 提供服务注册和发现
  • Service Provider 服务提供方,将自身服务注册到Eureka,从而使服务消费方能够找到
  • Service Consumer 服务消费方,从Eureka获取注册服务列表,从而能够消费服务

配置Eureka服务端

搭建Eureka Server 需要引入依赖

    
    <dependency>
        <groupId>org.springframework.cloudgroupId>
        <artifactId>spring-cloud-starter-netflix-eureka-serverartifactId>
    dependency>

配置yml信息

server:
  port: 7002


eureka:
  instance:
    hostname: eureka7002.com #eureka服务端的实例名称
  client:
    register-with-eureka: false     #false表示不向注册中心注册自己。
    fetch-registry: false     #false表示自己端就是注册中心,我的职责就是维护服务实例,并不需要去检索服务
    service-url:
    #集群指向其它eureka
      defaultZone: http://localhost:7001/eureka/
    #单机就是7001自己
#      defaultZone: http://localhost:7002/eureka/
  #server:
    #关闭自我保护机制,保证不可用服务被及时踢除
    #enable-self-preservation: false
    #eviction-interval-timer-in-ms: 2000

启动类信息

@SpringBootApplication
@EnableEurekaServer
public class EurekaMain7001 {
    public static void main(String[] args) {
        SpringApplication.run(EurekaMain7001.class,args);
    }
}

搭建Eureka的服务提供方

需要引入依赖

    
    <dependency>
        <groupId>org.springframework.cloudgroupId>
        <artifactId>spring-cloud-starter-netflix-eureka-clientartifactId>
    dependency>

yml配置

server:
  port: 8001

spring:
  application:
    name: cloud-payment-service
    
eureka:
  client:
    #表示是否将自己注册进EurekaServer默认为true。
    register-with-eureka: true
    #是否从EurekaServer抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
    fetchRegistry: true
    service-url:
      #单机版
      defaultZone: http://localhost:7001/eureka
      # 集群版
#      defaultZone: http://localhost:7001/eureka,http://localhost:7002/eureka
  instance:
    instance-id: payment8001
    #访问路径可以显示IP地址
    prefer-ip-address: true
    #Eureka客户端向服务端发送心跳的时间间隔,单位为秒(默认是30秒)
    #lease-renewal-interval-in-seconds: 1
    #Eureka服务端在收到最后一次心跳后等待时间上限,单位为秒(默认是90秒),超时将剔除服务
    #lease-expiration-duration-in-seconds: 2    

启动类配置

@EnableEurekaClient
@SpringBootApplication
@EnableDiscoveryClient
public class PaymentMain8001
{
    public static void main(String[] args) {
        SpringApplication.run(PaymentMain8001.class, args);
    }
}

搭建Eureka 服务消费方

引入依赖

   
        <dependency>
            <groupId>org.springframework.cloudgroupId>
            <artifactId>spring-cloud-starter-netflix-eureka-clientartifactId>
        dependency>

yml配置

server:
  port: 80


eureka:
  client:
    #表示是否将自己注册进EurekaServer默认为true。
    register-with-eureka: true
    #是否从EurekaServer抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
    fetchRegistry: true
    service-url:
      #单机版
      defaultZone: http://localhost:7001/eureka
      # 集群版
#      defaultZone: http://localhost:7001/eureka,http://localhost:7002/eureka

启动类

package com.pyy.springcloud;

@EnableEurekaClient
@SpringBootApplication
@RibbonClient(name = "CLOUD-PAYMENT-SERVICE",configuration = SelfRule.class)
public class OrderMain80 {

    public static void main(String[] args) {
        SpringApplication.run(OrderMain80.class, args);
    }
}
配置负载均衡

SelfRule.class为自己配置的负载均衡策略,默认不配为轮询

package com.pyy.myrule;

@Configuration
public class SelfRule {

    @Bean
    public IRule iRule() {
        return new RoundRobinRule();
    }
}

该类必须与启动类包的同级包下面才会生效。

通过配置RestTemplate进行远程调用服务,集群模式通过Eureka Provider的名称进行远程调用时,需要配置负载均衡。

@Configuration
public class ApplicationContextConfig {

    @Bean
    @LoadBalanced //配置负责均衡
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}

调用方式

 public static final String PAYMENT_URL = "http://CLOUD-PAYMENT-SERVICE";
 
 @Resource
 RestTemplate restTemplate;
 
 @GetMapping("/consumer/payment/getForEntity/{id}")
 public CommonResult<Payment> getPayment2(@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,"操作失败");
        }
 }
自定义自己的负载均衡方法

编写负载均衡接口,ServiceInstance获取的服务实例。

public interface LoadBalance {

    ServiceInstance instance(List<ServiceInstance> instanceList);
}

实现类

@Component
public class Mlb implements LoadBalance {

    private AtomicInteger atomicInteger = new AtomicInteger(0);

    public final int getAndIncrement() {
        int current;
        int next;
        do {
            current = atomicInteger.get();
            next = current >= Integer.MAX_VALUE ? 0 : current + 1;
        } while (!this.atomicInteger.compareAndSet(current, next));
        System.out.println("*****第" + next + "次访问,次数" + next);
        return next;
    }

    @Override
    public ServiceInstance instance(List<ServiceInstance> instanceList) {
        int index = getAndIncrement() % instanceList.size();
        return instanceList.get(index);
    }
}

调用方式

@RestController
public class OrderController {
    @Resource
    RestTemplate restTemplate;
    @Resource
    private DiscoveryClient discoveryClient;
    @Resource
    private LoadBalance loadBalancer;
    
     @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/lb",String.class);

    }
}

注意:使用自定义的负载均衡方法时,需要把定义RestTemplate时加的@LoadBalanced注解去掉。

配置Eureka其他信息

关闭Eureka自我保护模式。默认情况下自我保护机制是打开的,线上建议都是打开的,即不需要设置。如果在测试环境需要设置为关闭,可以通过如下配置

eureka:
  server:
    enable-self-preservation: true

上报服务真实健康状态

SpringBoot的健康监测

        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-webartifactId>
        dependency>
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-actuatorartifactId>
        dependency>

自定义配置健康状态

@Service
public class HealthStatusService implements HealthIndicator {

    private Boolean status = true;

    public void setStatus(Boolean status) {
        this.status = status;
    }

    @Override
    public Health health() {
        if (status) {
            return new Health.Builder().up().build();
        }
        return new Health.Builder().down().build();
    }


    public String getStatus() {
        return this.status.toString();
    }

配置安全设置

直接引入security的依赖

        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-securityartifactId>
        dependency>

配置security的账户密码

spring:
  security:
    user:
      name: admin
      password: 123456

同时服务注册需要修改配置为

eureka:
  client:
    #表示是否将自己注册进EurekaServer默认为true。
    register-with-eureka: true
    #是否从EurekaServer抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
    fetchRegistry: true
    service-url:
      #单机版
      defaultZone: http://admin:123456@localhost:7001/eureka
      # 集群版
#      defaultZone: http://localhost:7001/eureka,http://localhost:7002/eureka

Zookeeper

CAP定理: Zookeeper是CP (一致性,分区容错性)

服务端

只需下载zookeeper的服务端压缩包,解压后运行即可。

服务提供方

引入依赖

        
        <dependency>
            <groupId>org.springframework.cloudgroupId>
            <artifactId>spring-cloud-starter-zookeeper-discoveryartifactId>
            
            <exclusions>
                <exclusion>
                    <groupId>org.apache.zookeepergroupId>
                    <artifactId>zookeeperartifactId>
                exclusion>
            exclusions>
        dependency>
        
        <dependency>
            <groupId>org.apache.zookeepergroupId>
            <artifactId>zookeeperartifactId>
            <version>3.4.8version>
            <exclusions>
                <exclusion>
                    <groupId>org.slf4jgroupId>
                    <artifactId>slf4j-log4j12artifactId>
                exclusion>
                <exclusion>
                    <groupId>org.slf4jgroupId>
                    <artifactId>slf4j-apiartifactId>
                exclusion>
            exclusions>
        dependency>

根据服务端的zookeeper版本配置版本号

yml配置

server:
  port: 8004

  #服务别名----注册zookeeper到注册中心名称
spring:
  application:
    name: cloud-provider-payment
  cloud:
    zookeeper:
      connect-string: 127.0.0.1:2181

启动类配置

@EnableDiscoveryClient
@SpringBootApplication
public class PaymentMain8004 {
    public static void main(String[] args) {
        SpringApplication.run(PaymentMain8004.class,args);
    }
}

Consul

Nacos

二、负载均衡

Ribbon

基于服务端的负载均衡

Ribbon 默认的策略是轮询

超时配置

# 请求连接的超时时间
ribbon.ConnectTimeout=2000
# 请求处理的超时时间
ribbon.ReadTimeout=5000

也可以为每个Ribbon客户端设置不同的超时时间, 通过服务名称进行指定:
ribbon-config-demo.ribbon.ConnectTimeout=2000
ribbon-config-demo.ribbon.ReadTimeout=5000

当我们禁用了 Eureka 之后,就不能使用服务名称去调用接口了,必须指定服务地址。

# 禁用 Eureka
ribbon.eureka.enabled=false

三、服务调用

Openfeign

引入依赖

 <dependency>
      <groupId>org.springframework.cloudgroupId>
      <artifactId>spring-cloud-starter-openfeignartifactId>
 dependency>

配置Api接口

@Component
@FeignClient(value = "CLOUD-PAYMENT-SERVICE") //不结合Eureka时,写具体的uri地址
public interface PaymentFeignService {

    @PostMapping(value = "/payment/create")
    CommonResult create(@RequestBody Payment payment);

    @GetMapping(value = "/payment/get/{id}")
    CommonResult<Payment> getPaymentById(@PathVariable("id") Long id);

    @GetMapping(value = "/payment/feign/timeout")
    String paymentFeignTimeout();
}

配置feign日志监控级别

@Configuration
public class FeignConfig {

    @Bean
    Logger.Level feignLoggerLevel()
    {
        return Logger.Level.FULL;
    }
}

再yml中指定该类

logging:
  level:
    # feign日志以什么级别监控哪个接口
    com.pyy.springcloud.service.PaymentFeignService: debug

调用方式

@RestController
public class OrderFeignController {

    @Resource
    PaymentFeignService paymentFeignService;


    @GetMapping("/consumer/payment/create")
    public CommonResult create(Payment payment) {
        return paymentFeignService.create(payment);
    }

    @GetMapping("/consumer/payment/get/{id}")
    public CommonResult getPayment(@PathVariable("id") Long id) {
        return paymentFeignService.getPaymentById(id);
    }

    @GetMapping(value = "/payment/feign/timeout")
    public String paymentFeignTimeout(){
        return paymentFeignService.paymentFeignTimeout();
    }

}

启动类开启Openfeign的自动注入

@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class OrderFeignMain80 {

    public static void main(String[] args) {
        SpringApplication.run(OrderFeignMain80.class,args);
    }
}

你可能感兴趣的:(Java,Springcloud)