Spring Cloud (1)

SpringCloud

微服务定义

  1. 是一种架构风格
  2. 一系列微小的服务共同组成
  3. 每个服务跑在自己的进程里
  4. 每个服务为独立的业务开发
  5. 独立部署
  6. 分布式的管理

架构形态

单体架构

特点:
  1. 打包成一个war包,没有外部依赖
  2. 共用一个db
  3. 容易测试
  4. 容易部署
  5. 开发效率低
  6. 代码维护困难
  7. 部署不够灵活

    • 构建时间特别长
  8. 稳定性不高
  9. 扩展性不够,不能满足高并发需求

基于ajax的前后端分离

分布式架构

定义:支持应用程序和服务的开发,可以利用物理架构和多个自制的处理元素(多节点),不共享主内存,但通过网络发送消息

简单的微服务

基础框架组件

服务注册发现

服务网关

  • 连接内外大门
  • 屏蔽后台细节,让用户无感知
  • 路由功能,外部请求反向路由到内部某个服务
  • 网关功能,控制流量,监控和日志

    • 用户认证
    • 授权
    • 服务网关

前端服务(边缘服务)

聚合

把两个接口聚合在一起返回出去

裁剪

通过不同需求返回不同数据,pc和手机端淘宝返回详情数据不一致

后端通用服务(中间层服务)

阿里系

Dubbo

Zookeeper

Spring MVC or SpringBoot

Spring Cloud

定义

  • 是一个开发工具集
  • 利用spring boot的开发遍历
  • 基于对netflix 开源组件的进一步封装
  • 简化了分布式开发

来源

基于Netflix Eureka做了二次封装

文档

http://projects.spring.io/spr...

版本查看

Eureka Server(注册中心)

-Dserver.port=

pom文件

  
            org.springframework.cloud
            spring-cloud-starter-netflix-eureka-server
        

配置方式

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8080/eureka/
    # 不把自己注册到注册中心
    register-with-eureka: false
# 设置应用名
spring:
  application:
    name: eureka

打包

mvn clean package install

Eureka Client(服务注册)

pom文件


            org.springframework.cloud
            spring-cloud-starter-netflix-eureka-client
        

yml配置方式

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/
    # 不把自己注册到注册中心
    register-with-eureka: false
    #关闭心跳监测
  server:
    enable-self-preservation: false
# 设置应用名
spring:
  application:
    name: eureka
server:
  port: 8761

开启注解

@EnableDiscoveryClient@EnableEurekaClient区别

如果注册中心是eureka那么推荐使用EnableEurekaClient`

如果是其他注册中心那么推荐使用Enable

Eureka的高可用

两个eureka都能看到client的信息

如果一个client挂掉了那么两个eureka都没有信息

解决:

多台

分布式中为什么需要服务发现

a和b沟通完全通过注册中心

服务端发现
  • Nginx
  • Zookeeper
  • Kubernetes
客户端发现
  • Eureka

微服务的特点

  1. 异构
  2. 不同类型的数据库
  3. Spring Cloud通过rest方式实现服务注册
  4. Node.js的eureka-js-client

服务拆分方法

  1. 分清楚起点和终点
  2. 了解现有架构是否支持微服务架构
  3. 架构是不断引进的

不适合微服务的系统

  1. 系统中包含很多强事物场景的
  2. 业务相对稳定,迭代周期长
  3. 访问压力不大,可用性要求不高

康威定律

任何组织在设计一套系统时,所交互的设计方案在结构上都与该组织的沟通结构保持一直

微服务特点

  • 一系列微小的服务共同组成
  • 单独部署,跑在自己的进程里
  • 每个服务为独立的业务开发
  • 分布式的管理

扩展立方模型

  • X轴 水平复制
  • Y轴功能解耦

    • 单一职责,每个服务负责单一功能
    • 相关功能聚集在一个服务内
    • 关注点分离

      • 职责分离
      • 通用性分离

        • 基础组件划分
        • 消息服务
        • 用户服务
        • 公共组件拆分
      • 粒度分离

        • 不是越小越好
  • Z轴 数据分区

点餐业务拆分

拆分服务

服务拆分方法论

  • 每个微服务都有单独的数据存储
  • 依据服务特点选择不同结构的数据库类型

    • 搜索->elasticsearch
    • 订单类-》mysql
  • 难点在难以确定边界

    • 针对边界设置api
    • 依据边界权衡数据冗余

应用通信

调用的三种方式

  1. 直接使用RestTemplate

    • String s = restTemplate.getForObject("http://localhost:8083/hello", String.class);
  2. 使用LoadbalanceClient

    • ServiceInstance serviceInstance = loadBalancerClient.choose("PRODUCT");
      String url = String.format("http://%s:%s", serviceInstance.getHost(), serviceInstance.getPort() + "/hello");
      String result = restTemplate.getForObject(url, String.class);
  3. 使用注解

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

客户端负载均衡器(Ribbon)

  • RestTemplate
  • Feign
  • Zuul
发现方式
  • 服务发现
  • 服务选择规则
  • 服务监听
主要组件
  • ServerList
  • IRule
  • ServerListFilter
源码解析
  1. 用来获取所有列表
  2. 轮循策略默认是roundRobinRule

    修改默认轮询策略
    1. http://cloud.spring.io/spring...

      users:
        ribbon:
          NFLoadBalancerRuleClassName: com.netflix.loadbalancer.WeightedResponseTimeRule
    2. 轮循策略

Feign使用(内部也使用了rabbion做负载均衡)

  1. Pom文件

    1. 
          org.springframework.cloud
          spring-cloud-starter-feign
         
  2. 启动主类增加注解@FeignClient
  3. 编写接口

    1. @FeignClient("product")
      public interface FeignConfig {
          @GetMapping("hello")
          String hello();
      }
  4. 注入和调用

    1.  @Autowired
          private FeignConfig feignConfig;
          
          @RequestMapping("/feign")
          public String feign() {
              String result = feignConfig.hello();
              return result;
          }

多模块拆分服务

问题

  1. 商品和订单dto重复定义
  2. 同一个对象多次重复定义
  3. 订单服务里面不应该知道商品服务的uri

模块拆分

  • product-server

    • 业务逻辑
  • product-client

    • 对外暴露的接口
  • Product-common

    • 公用的对象
  • 依赖关系

打包命令

  • mvn -Dmaven.test.skip=true -U clean install

同步还是异步

    1. 消费者通过消息中间件进行解耦
    2. 用户调用短信服务,积分服务,其他服务,服务耦合过大,用户登录成功需要多个服务同步响应后才告诉成功
    1. 商品服务库存变化发布消息,订单服务订阅消息,比如商品信息

      1. 订单不需要查询商品服务而是查询自己服务中的信息
      2. 保证数据最终一致性,只需要订阅对应服务就能保证
  1. 常见消息队列

    • RabbitMQ
    • Kafka
    • ActiveMQ

RabbitMQ安装

5672->默认RabbitMQServer端口

15672->RabbitMQ管理页面端口,页面只需要配置这个

docker run -d --hostname my-rabbit -p 5672:5672 -p 15672:15672 rabbitmq:3.7.3-management

默认密码:guest

Docker和DevOps

  1. docker能够解决不同环境下应用程序都能运行
  2. 轻量
  3. 进程隔离和管理
  4. 可复用,版本化(tag机制)
  5. 微服务架构师核心,devops和docker是手段

统一配置中心(Spring Cloud Config)

原因

  1. 配置方式不方便维护
  2. 配置内容与权限(针对线上)
  3. 每更新一个配置都要重启项目

ConfigServer使用

configServer从远端git拉下配置放到本地git如果远端不可用使用本地的

  • pom
  1.  
         org.springframework.cloud
         spring-cloud-config-server
     
     
         org.springframework.cloud
         spring-cloud-starter-netflix-eureka-client
     
  • 开启注解

    @EnableDiscoveryClient
    @EnableConfigServer
  • 没有配置对应的gituri
  • 在git上新建项目

  • 在配置中填写对应git uri,username,password
  • 访问对应配置文件

    1. .properties展示为properties ,.yml为yml
    2. /{label}/{name}-{profiles}

      1. label->分支(不写默认master)
      2. name->文件名
      3. profiles->环境
  • 设置配置文件基础目录

    • spring.cloud.config.server.git.basedir

ConfigClient使用

导入依赖

    org.springframework.cloud
    spring-cloud-config-client
更改配置
spring:
  application:
    name: order
  cloud:
    config:
      discovery:
        enabled: true
        service-id: config
      profile: dev
修改application.yml

修改为bootstrap.yml这样会优先启动

注意

配置中心会读取拼接order.yml+order-xx.yml的内容

Spring Cloud Bus

通过git hook访问配置文件变更,同步信息到消息队列,(/bus/refresh)

Config-server 通过消息队列同步到其他服务

使用

更新版本
 
        org.springframework.boot
        spring-boot-starter-parent
        2.0.0.BUILD-SNAPSHOT
         
    

    
        UTF-8
        UTF-8
        1.8
        Finchley.BUILD-SNAPSHOT
    
导入jar包
 
            org.springframework.cloud
            spring-cloud-starter-bus-amqp
            2.0.0.RELEASE
        
yml开放端口用来刷新对应变更
management:
  endpoints:
    web:
      exposure:
        include: bus-refresh
访问端口刷新配置

curl -v -X POST "http://localhost:8991/actuator/bus-refresh"

需要变更的类上面加上注解@RefreshScope
@RestController
@RequestMapping("/env")
@RefreshScope
public class EnvController {
    @Value("${env}")
    public String env;

    @GetMapping("/profile")
    public String getenv() {
        return env;
    }
}
通过 git HOOK自动访问地址

有bug

异步和消息

定义

  1. 异步:客户端请求不会阻塞进程,服务端的响应可以是非及时的

    1. 通知
    2. 请求异步响应
    3. 客户端不会阻塞
    4. 通过消息实现一对多

      1. 客户端发送请求消息等待服务端响应

MQ

应用场景

  1. 异步处理

    1. 用户注册后需要发短信和加积分
  2. 流量削锋

    1. 秒杀场景,丢弃请求,控制活动人数
  3. 日志处理(kafka)

    1. 通过日志采集定时写入队列
  4. 应用解耦

    1. 用户下单后需要调用商品服务,使用mq用户下单后把消息写入商品服务,商品使用拉或者推的方式,订单服务写入订单后就可以不关注后续流程了

使用

导入依赖
 
            org.springframework.boot
            spring-boot-starter-amqp
        

yml配置

spring:
  application:
    name: order
  cloud:
    config:
      discovery:
        enabled: true
        service-id: config
      profile: test
  rabbitmq:
    host: localhost
    port: 5672
    username: guest
    guest: guest
发送方式
 @Autowired
    private AmqpTemplate amqpTemplate;

    @Test
    public void send() {
        amqpTemplate.convertAndSend("myQueue", "now time:" + System.currentTimeMillis());
    }
接收方式
第一种(需要手动创建队列)

@Slf4j
@Component
public class MqReceiver {
    @RabbitListener(queues = "myQueue")
    public void process(String message) {
        log.info("MqReceiver:{}", message);
    }
}
第二种 自动创建队列
 /**
     * 自动创建队列
     *
     * @param message
     */
    @RabbitListener(queuesToDeclare = @Queue("myQueue2"))
    public void autoCreateQueue(String message) {
        log.info("autoCreateQueue:{}", message);
    }

第三种 Exchange和Queue绑定

   @RabbitListener(bindings = {@QueueBinding(
            value = @Queue("myQueueExchange"),
            exchange = @Exchange("myExchange")
    )})
    public void exchange(String message) {
        log.info("myExchange:{}", message);
    }

消息分组使用第三种方式

@RabbitListener(bindings = @QueueBinding(
        exchange = @Exchange("myOrder"),
        key = "computer",
        value = @Queue("computerOrder")
))
public void computerOrder(String message) {
    log.info("computerOrder:{}", message);
}

@RabbitListener(bindings = @QueueBinding(
        exchange = @Exchange("myOrder"),
        key = "fruit",
        value = @Queue("fruitOrder")
))
public void fruitOrder(String message) {
    log.info("fruitOrder:{}", message);
}
   @Test
    public void sendToProduct() {
        amqpTemplate.convertAndSend("myOrder", "computer", "now time:" + System.currentTimeMillis());
    }

Spring Cloud Stream

为微服务应用构建消息能力的应用,对于消息中间件的封装,代码对于中间件的无感知,但是只支持rabbitMQ 和Kafka

使用
导入pom

            org.springframework.cloud
            spring-cloud-starter-stream-rabbit
        
定义接口
public interface StreamClient {
    @Input("myMessage")
    SubscribableChannel input();

    @Output("myMessage")
    MessageChannel output();
}
接受
@Component
@EnableBinding(StreamClient.class)
@Slf4j
public class StreamReceiver {
    @StreamListener("myMessage")
    public void process(Object message) {
        log.info("StreamReceiver:{}",message);
    }
}
发送
@RestController
public class SendMessageController {
    @Autowired
    private StreamClient streamClient;

    @GetMapping("/sendMessage")
    public void process() {
        String message = "now " + new Date();
        streamClient.output().send(MessageBuilder.withPayload(message).build());
    }
}

参考:https://coding.imooc.com/learn/list/187.html

你可能感兴趣的:(springcloud)