avatar

目录
服务拆分&应用通信

第3章 服务拆分

微服务拆分的起点

起点?

  • 既有架构的形态

终点?

  • 好的架构不是设计出来的,而是进化来的
  • 一直在演进…

适合微服务吗?

业务形态不适合的:

  • 系统包含很多很多强事物场景
  • 业务相对稳定,迭代周期长
  • 访问压力不大,可用性要求不高(中小企业内部oa系统)

康威定律和微服务

康威定律

微服务和团队结构:

![屏幕快照 2018-12-05 下午2.33.01](20181217200059093/屏幕快照 2018-12-05 下午2.33.01.png)


点餐业务服务拆分分析

如何拆分?

  • 手机端、PC端?
  • 订单、商品、支付?

看实际情况

服务拆分方法论

扩展立方模型

  • X轴 水平复制(副本扩展,负载均衡)
  • Z轴 数据分区(每个服务器负责一个数据子集,运行的代码一样)
  • Y轴 功能解耦(将不同职责的模块分成不同服务)

如何拆“功能”?

  • 单一职责、松耦合、高内聚
  • 关注点分离
    • 按职责(业务)
    • 按通用性(基础组件:消息、用户)
    • 按粒度级别

服务和数据的关系

  • 先考虑业务功能、再考虑数据
  • 无状态服务(一个数据需要多个业务共享就是有状态)

点餐业务拆分

![屏幕快照 2018-12-05 下午2.54.39](20181217200059093/屏幕快照 2018-12-05 下午2.54.39.png)

  • 业务高速发展背景下
    • 新增支付渠道(目前只支持微信、以后扩展支付宝等)
    • 短信、日志(作为基础服务单独抽离,如用户、redis缓存)
    • 积分、优惠券…

接下来实现商品、订单业务

商品服务

知识点:

Code
1
2
3
4
- API的格式定义
- 持久层:spring-boot-starter-data-jpa的使用
- VO层:数据构造
- springcloud下一个MVC的开发流程

API和SQL介绍

api

导入类目/商品表


编码实现

配置一个eureka client,工程名为product

持久层:

pom

dataobject\ProductInfo

repository\ProductInfoRepository

test

dataobject\ProductCategory

repository\ProductCategoryRepository

服务层

ProductInfo:

service\ProductInfoService

service\impl\ProductInfoServiceImpl

enums\ProductStatusEnum

test

ProductCategory:

控制层

定义api对应的VO对象 vo\ …

最外层:vo\ResultVO

utils\ResultVOUtils

订单服务

知识点:

Code
1
2
3
4
- 参数校验
- 自定义异常类
- VO层:数据构造
- springcloud下一个MVC的开发流程

api sql

业务逻辑

Code
1
2
3
4
5
6
创建订单:
1. 参数校验
2. 根据id查询商品信息(远程调用商品)
3. 查库存,做判断,计算总价
4. 扣库存(远程调用商品)
5. 订单入库

编码

新建一个order项目

持久层

Code
1
2
3
4
dataobject
respository save
测试save
enum/OrderStatus PayStatus

业务层

Code
1
2
dto
...

controller

Code
1
2
3
converter
form
...

再看“拆数据”

如何拆数据:

  • 每个微服务都有单独的数据存储(单独数据库)
  • 依据服务特点选择不同结构的数据库类型
  • 难点在确定边界
    • 针对边界设计API
    • 依据边界权衡数据冗余

第4章 应用通信

HTTP vs RPC

应用间通信方式

  • Dubbo:RPC框架

  • Spring Cloud:微服务架构下的一站式解决方案,微服务之间使用http restful方式

    • http restful:轻量易用,跨平台跨语言

SpringCloud中服务间2种restful调用方式

  • RestTemplate
  • Feign

RestTemplate

RestTemplate:Http客户端,功能上类似于HttpClient

订单服务 –> 调用 –> 商品服务

Code
1
2
商品:server
订单:client

RestTemplate的三种使用方式

java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
package com.mxx.order.controller;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.web.client.RestTemplate;
//...

@Slf4j
@RestController
@RequestMapping("/order")
public class ClientController {

@Autowired
private LoadBalancerClient loadBalancerClient;
@Autowired
private RestTemplate restTemplate;


@RequestMapping("/getProductMsg")
public String getProductMsg(){
// 1、直接使用RestTemplate,url写死
// 缺点:不知道ip/对方有多个服务地址:负载均衡
// RestTemplate restTemplate = new RestTemplate();
// String result = restTemplate.getForObject("http://localhost:8080/product/msg", String.class);

// 2、通过loadBalancerClient通过应用名获取url,解决了url硬编码
// 缺点:写一堆
// ServiceInstance product = loadBalancerClient.choose("PRODUCT");
// String url = String.format("http://%s:%s/product/msg", product.getHost(), product.getPort());
// RestTemplate restTemplate = new RestTemplate();
// String result = restTemplate.getForObject(url, String.class);

//3、利用@LoadBalanced,简化
String result = restTemplate.getForObject("http://PRODUCT/product/msg", String.class);
return result;
}
}

RestTemplateConfig

java
1
2
3
4
5
6
7
8
9
10
11
12
package com.mxx.order.config;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
//...
@Component
public class RestTemplateConfig {

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

负载均衡器:Ribbon

Eureka:客户端发现

客户端负载均衡器:Ribbon

  • RestTemplate
  • Feign
  • Zuul

@LoadBalanced会自动使用Ribbon基于某种规则(轮训、随机链接)去连接目标服务,从而使用Ribbon实现自定义负载均衡算法

Ribbon实现软负载均衡核心

  • 服务发现(发现服务列表)
  • 服务选择规则(如何从多个服务中选择有效服务)
  • 服务监听(检测失效服务,高效剔除)

Ribbon主要组件

  • ServerList
  • IRule
  • SererListFilter

流程:ServerList获取所有可用服务列表,SererListFilter过滤部分地址,在剩下地址中通过IRule选择一个实例作为结果

追踪源码自定义负载均衡策略

源码追踪

自定义负载均衡策略

yml
1
2
3
4
# 修改负载均衡的策略:由默认的轮寻改为随机
PRODUCT:
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule

Feign

使用

pom

xml
1
2
3
4
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

启动类

Code
1
@EnableFeignClients

定义好要调用的接口 client

java
1
2
3
4
5
6
7
8
9
package com.mxx.order.client;
import org.springframework.cloud.openfeign.FeignClient;

@FeignClient(name = "product") //调用服务的名称
public interface ProductClient {

@GetMapping("product/msg") //服务url
String productMsg();
}

使用

java
1
2
3
4
@RequestMapping("/getProductMsg")
public String getProductMsg(){
return productClient.productMsg();
}

Feign

  • 声明式REST客户端(伪RPC)
    • 感知不到http调用,使用的时候像本地方法一样
  • 采用了基于接口的注解
  • 内部也使用Ribbon做负载均衡

业务开发:打通下单流程

知识点:

Code
1
2
@RequestBody只能用 @PostMapping
无参、单个参数(@RequestParam)、@PathVariable可以用@GetMapping

获取商品列表、扣库存(Feign)

Code
1
2
3
4
5
product
- 通过id list 查询商品列表
- 扣库存
order
- 调用

整合接口打通下单流程(Feign)

Code
1
2
OrderServiceImpl/create
OrderController/create

项目改造成多模块

改进:

java
1
2
3
4
5
6
7
8
// 1、不要暴露全部ProductInfo,重新封装ProductInfoOutput
public List<ProductInfo> listForOrder(@RequestBody List<String> productIdList)


// 2、重复定义的类
//自己业务,重新封装自己的类,如product将CartDTO改成了DecreaseStockInput、

// 3、ProductClient应该放在product项目里(自己定义的接口自己暴露出去)

多模块:

Code
1
2
3
4
5
product-server	业务逻辑(依赖common)
product-client 对外暴露接口(依赖common)
product-common 公用对象(外部服务需要使用这里的对象)

order也一样

同步or异步

服务间的通信分为同步 和 异步

异步:消息队列

适合异步的服务:短信服务、邮件服务

订单服务改为异步方式:

![屏幕快照 2018-12-18 下午10.41.41](20181217200059093/屏幕快照 2018-12-18 下午10.41.41.png) 、

消息中间件的选择:

  • RabbitMQ
  • Kafka
  • ActiveMQ

RabbitMQ的安装

官网:http://www.rabbitmq.com/

bash
1
2
3
4
# 15762: 管理界面
$ docker run -d --hostname my-rabbit -p 5672:5672 -p 15672:15672 hub.c.163.com/library/rabbitmq:3.6.11-management
# 10.211.55.6:15762
# 登录 guest/guest

Docker和DevOps

微服务和docker代表的容器技术:天生一对

  • 从系统环境开始,自底而上打包应用
  • 轻量级、隔离
  • 可复用,版本化

Microservice、Docker、Devops紧密相连

DevOps 是一个完整的面向IT运维的工作流,以 IT 自动化以及持续集成(CI)、持续部署(CD)为基础,来优化程式开发、测试、系统运维等所有环节

Development和Operations

软件开发人员和运维人员的沟通合作

一种理念:快速高质量交付

文章作者: Machine
文章链接: https://machine4869.gitee.io/2018/12/17/20181217200059093/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 哑舍
打赏
  • 微信
    微信
  • 支付宝
    支付宝

评论