我爱编程

简单spring cloud

2018-03-06  本文已影响0人  M问道

微服务有哪些优势?

1.易于开发和维护
2.可以全自动部署
3.局部修改容易部署
4.技术栈不受限

微服务有哪些挑战?

1.运维成本比较高
2.分布式固有的复杂性
3.接口调整成本高

微服务设计原则?

1.单一职责原则
2.服务自治原则
3.轻量级通信原则
4.接口明确原则

常用的微服务有哪些,spring cloud作为其中一个微服务有哪些优势?

常见的微服务有spring cloud、dubbo等。它们的区别很多,比如说调用方式,spring cloud采用REST API方式,dubbo采用RPC;spring cloud几乎涉及到分布式组件各个方面,而dubbo仅仅实现了其中的服务治理模块。spring cloud优势在于它丰富的组件以及分布式解决方案集成springboot十分的方便快捷。

下面来谈谈springcloud丰富的组件和模块,下面只给出使用说明,概念性的说明省略。

1.服务发现组件
Eureka

application.yml如下配置
security:
  basic:
    enabled: true
  user:
    name: user
    password: password123
server:
  port: 8761
eureka:
  client:
    register-with-eureka: false
    fetch-registry: false
    service-url:
      defaultZone: http://user:password123@localhost:8761/eureka

EurekaApplication.java启动类
@SpringBootApplication
@EnableEurekaServer
public class EurekaApplication {
  public static void main(String[] args) {
    SpringApplication.run(EurekaApplication.class, args);
  }
}

2.服务注册(消费者和服务者都会注册服务)

application.yml如下配置
eureka:
  client:
    healthcheck:        #健康检查 配合actuator
      enabled: true
    serviceUrl:
      defaultZone: http://user:password123@localhost:8761/eureka #权限验证
  instance:
    prefer-ip-address: true #服务可以ip调用
    instance-id: ${spring.application.name}:${spring.cloud.client.ipAddress}:${spring.application.instance_id:${server.port}}   

PS:eureka会将所有注册的服务按照application.name分组,availability zones标识集群节点数,status会显示各个实例状态(up表示可用),实例id可以用eureka.instance.instance-id来指定
3.服务消费ribbon

application.yml如何配置
eureka:
  client:
    healthcheck:
      enabled: true
    serviceUrl:
      defaultZone: http://user:password123@localhost:8761/eureka

ConsumerMovieRibbonApplicatio.java 启动类

@SpringBootApplication
@EnableEurekaClient   
@RibbonClient(name = "microservice-provider-user", configuration = TestConfiguration.class) //允许自定义ribbonclient
@ComponentScan(excludeFilters = { @ComponentScan.Filter(type = FilterType.ANNOTATION, value = ExcludeFromComponentScan.class) }) //保留默认的ribboclient  
public class ConsumerMovieRibbonApplication {

  @Bean
  @LoadBalanced
  public RestTemplate restTemplate() {
    return new RestTemplate();
  }

  public static void main(String[] args) {
    SpringApplication.run(ConsumerMovieRibbonApplication.class, args);
  }
}
@Configuration
@ExcludeFromComponentScan
public class TestConfiguration {
  //  @Autowired
  //  IClientConfig config;

  @Bean
  public IRule ribbonRule() {
    return new RandomRule();
  }
}
//注意这边使用virtual hostname(provider applicationName),ribbon会根据virtual hostname找到对应几个服务,然后根据负载均衡算法选择一个服务
this.restTemplate.getForObject("http://microservice-provider-user/simple/" + id, User.class);

PS:自定义负载均衡算法:默认是round,还有random、高可用、响应时间等

4.服务消费feign 声明式httpclient

ConsumerMovieFeignApplication.启动类
@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients
public class ConsumerMovieFeignApplication {
  public static void main(String[] args) {
    SpringApplication.run(ConsumerMovieFeignApplication.class, args);
  }
}
新建服务调用方一致的方法,方法上注解基本同springmvc一致
@FeignClient("microservice-provider-user") //对应provider serviceId
public interface UserFeignClient {
  @RequestMapping(value = "/simple/{id}", method = RequestMethod.GET)
  public User findById(@PathVariable("id") Long id); // 坑:1. @GetMapping不支持   2. @PathVariable得设置value 3.参数如果是复杂对象时,即使指定GET方法也失效
  @RequestMapping(value = "/user", method = RequestMethod.POST)
  public User postUser(@RequestBody User user);

  // 该请求不会成功,只要参数是复杂对象,即使指定了是GET方法,feign依然会以POST方法进行发送请求。可能是我没找到相应的注解或使用方法错误
  @RequestMapping(value = "/get-user", method = RequestMethod.GET)
  public User getUser(User user);
}

5.eureka实现高可用

eureka配置
spring:
  application:
    name: EUREKA-HA
---
server:
  port: 8761
spring:
  profiles: peer1
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8762/eureka/,http://localhost:8763/eureka/
---
server:
  port: 8762
spring:
  profiles: peer2
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/,http://localhost:8763/eureka/
---
server:
  port: 8763
spring:
  profiles: peer3
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/,http://localhost:8762/eureka/

PS:实现原理就是交叉注册,类似于主节点的备份,每个节点都在剩下的节点都有备份,从而实现集群

6.断路器hystrix
流程说明:

hystrix有两个隔离策略,thread和semaphore,默认是thread
thread 通过线程数量来限制并发请求数,可以提供额外的保护,但有一定的延迟,一般用于网络调用
semaphore 通过semaphore count来限制并发请求数,适用于无网络的高并发请求
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds 命令执行超时时间
hystrix.command.default.execution.isolation.semaphore.maxConcurrentRequests 最大并发请求数,默认10,该参数当使用ExecutionIsolationStrategy.SEMAPHORE策略时才有效。如果达到最大并发请求数,请求会被拒绝。
理论上选择semaphore size的原则和选择thread size一致,但选用semaphore时每次执行的单元要比较小且执行速度快(ms级别),否则的话应该用thread。

@RestController
public class MovieController {
  @Autowired
  private RestTemplate restTemplate;

  @GetMapping("/movie/{id}")
  @HystrixCommand(fallbackMethod = "findByIdFallback", commandProperties = @HystrixProperty(name = "execution.isolation.strategy", value = "SEMAPHORE"))
  public User findById(@PathVariable Long id) {
    return this.restTemplate.getForObject("http://microservice-provider-user/simple/" + id, User.class);
  }

  public User findByIdFallback(Long id) {
    User user = new User();
    user.setId(0L);
    return user;
  }
}
@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients
public class ConsumerMovieFeignApplication {
  public static void main(String[] args) {
    SpringApplication.run(ConsumerMovieFeignApplication.class, args);
  }
}

@FeignClient(name = "microservice-provider-user", fallback = HystrixClientFallback.class)
public interface UserFeignClient {
  @RequestLine("GET /simple/{id}")
  public User findById(@Param("id") Long id);
}

@Component
public class HystrixClientFallback implements UserFeignClient {

  @Override
  public User findById(Long id) {
    User user = new User();
    user.setId(0L);
    return user;
  }
}

明确问题1:进入断路器定义失败方法情况
(1):run()方法抛出非HystrixBadRequestException异常。
(2):run()方法调用超时
(3):熔断器开启拦截调用
(4):线程池/队列/信号量是否跑满

明确问题2:进入失败方法不一定短路器短路开关打开。
短路器短路开关有一定的条件,要满足再某个时间点失败次数达到一定数量。可以通过查看/hearth 来查看断路器状态。
断路器有三个状态,打开、关闭和半开。半开是指断路器打开后过一段时间它会尝试置为半开状态,即大部分请求还是短路,允许很少一部分流量请求,如果请求失败了,则断路器状态则变成打开,如果请求成功了,则断路器状态变成关闭。

7.服务网关zuul
Zuul 在云平台上提供动态路由,监控,弹性,安全等边缘服务的框架。

优点:

实现方式如下 ZuulApplication.java 入口类

@EnableZuulProxy
@SpringBootApplication
public class ZuulApplication {

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

application.yml 配置类

zuul:
  prefix: /api
  routes:
    aaa:
      path: /user/**
      serviceId: microservice-provider-user
    legacy:
      path: /**
      serviceId: microservice-provider-user_old

PS:zuul.prefix表示所有走网关转发的路由必须要有api前缀,zuul默认支持serviceId/serviceName(除非设置zuul.ignoredServices=''),同时也可以设置path匹配规则,legacy表示当所有路由规则都不匹配才生效*

zuul同样支持断路器功能
配置一个FallbackProvider即可

@Component
public class MyFallbackProvider implements ZuulFallbackProvider {
    @Override
    public String getRoute() {
        return "microservice-provider-user";
    }

    @Override
    public ClientHttpResponse fallbackResponse() {
        return new ClientHttpResponse() {
            @Override
            public HttpStatus getStatusCode() throws IOException {
                return HttpStatus.OK;
            }

            @Override
            public int getRawStatusCode() throws IOException {
                return 200;
            }

            @Override
            public String getStatusText() throws IOException {
                return "OK";
            }

            @Override
            public void close() {

            }

            @Override
            public InputStream getBody() throws IOException {
                String json = "{\"success\":false, \"msg\":\"error\"}";
                return new ByteArrayInputStream(json.getBytes());
            }

            @Override
            public HttpHeaders getHeaders() {
                HttpHeaders headers = new HttpHeaders();
                headers.setContentType(MediaType.APPLICATION_JSON);
                return headers;
            }
        };
    }
}

8.spring cloud config 分布式配置中心
spring cloud config作为配置中心优势?

配置服务端 数据repo存放在git上,ConfigServer搭建如下
ConfigServerApplication 入口类

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

application.yml配置类

spring:
  cloud:
    config:
      server:
        git:
          uri: https://gitee.com/habib/{application} #通配符,匹配git habib这个目录下所有工程
server:
  port: 8080

配置客户端 ConfigClient
bootstrap.yml

bootstrap.yml
spring:
  cloud:
    config:
      uri: http://localhost:8080 #config server访问地址 如果config server配置登录校验,这边可以这样写 http://user:password123@localhost:8080,或者username和password写在下面
      profile: dev #支持多环境 即对应application-dev.yml或者 application-dev.properties
      label: master #默认就是master
  application:
    name: simple #对应https://gitee.com/habib/{application} 这个地址的application

PS:客户端加载顺序:bootstrap.yml -> 加载服务端配置文件 -> application.yml,所以要注意读取部分的配置要放在bootstrap.yml

9.spring cloud bus
整合了java的事件处理机制和消息中间件,可以简单的认为是一个轻量级的消息总线。使用时它默认需要在一个消息中间件基础上,比如说rabbitmq、kafka。
以rabbitmq为例子
bootstrap.yml 配置类

spring:
  cloud:
    config:
      uri: http://localhost:8080
      profile: dev
      label: master
  application:
    name: simple
  rabbitmq:
    host: localhost
    port: 5672
    username: guest
    password: guest

PS:config-server 和 config-client最好都添加上如上的消息配置。执行 http://config-server/bus/refresh 即可。 这个触发事件可以通过github webhook来触发。

上一篇下一篇

猜你喜欢

热点阅读