香雨站

 找回密码
 立即注册
搜索
热搜: 活动 交友 discuz
查看: 87|回复: 0

go-zero 成长之路—微服务电商实战系列(二、划分篇)

[复制链接]

2

主题

2

帖子

6

积分

新手上路

Rank: 1

积分
6
发表于 2022-9-21 18:05:33 | 显示全部楼层 |阅读模式
1. 概述

微服务架构是一种架构风格,它将一个大的系统构建为多个微服务的集合,这些微服务是围绕业务功能构建的,服务关注单一的业务功能,这些服务具有以下特点:

  • 高度可维护和可测试
  • 松散的耦合
  • 可独立部署
  • 围绕业务功能进行构建
  • 由不同的小团队进行维护
微服务架构能够快速、频繁、可靠地交付大型、复杂的应用程序,通过业务拆分实现服务组件化,使用组件进行组合从而快速开发系统。


2. 服务划分

在实际项目开发中,我们通常采用两种微服务划分策略:

  • 第一种:通过业务职能进行边界进行划分
  • 第二种:通过DDD界限上下文进行边界划分
我们这里采用大家比较容易理解的业务职能的方式进行微服务划分,再次贴上我们电商项目的思维导图:


从以上思维导图可以看出,我们根据业务职能做如下微服务的划分:

  • 商品服务(product) - 商品的添加、信息查询、库存管理等功能
  • 购物车服务(cart) - 购物车的增删改查、收藏等功能
  • 订单服务(order) - 生成订单,订单管理等功能
  • 支付服务(pay) - 通过调用第三方支付实现支付等功能
  • 账号服务(user) - 用户信息、实名认证、账号设置、地址管理等功能
  • 首页服务(home) - 首页商品推荐、排行榜、限时开抢、banner等功能
每个服务都可以再分为 api 服务和 rpc 服务。
api 服务对外,可提供给 app 调用。
rpc 服务是对内的,可提供给内部 api 服务或者其他 rpc 服务调用。
整个项目服务依赖流程图大致如下:


3. BFF层

一般对于客户端我们会采用HTTP接口的方式提供服务,以上划分的这些微服务都需要直接提供HTTP接口对外提供服务,当然这样架构整体看起来也会比较简单。


但是这只是一个相对简单并且没有高并发的系统来。
对于一个复杂的高并发系统来讲,我们需要处理各种异常场景,比如:

  • 某些页面需要依赖多个微服务提供数据,为了避免串行请求导致耗时过长。一般会采用并行请求多个微服务,这个时候其中某一个服务请求异常或宕机,那我们可能需要做一些特殊的处理,比如数据降级等
  • 某些页面需要组合多个微服务的数据满足业务需求时,如果每个微服务都提供HTTP对外接口,那这些复杂数据组合和异常处理都要在客户端完成,大家都知道客户端是不宜做复杂业务逻辑的,它的重点在与做交互体验,所以我们的架构组要做到前轻后重(即客户端逻辑尽量少而把比较重的业务处理逻辑下沉到服务端,而服务端又根据业务职能拆分成了不同的微服务,这些微服务只关注单一的业务)
那么这些面向业务场景的复杂逻辑的处理应该放到哪里呢?
我们的解决方案就是加一层,即BFF层,通过BFF对外提供HTTP接口,客户端只与BFF进行交互。


BFF层的引入解决了我们上面遇到的问题,但增加一层就会增加架构的复杂度,所以如果你的服务是一个单体应用的话,那么BFF是不必要的,引入它不会增加任何价值。
对于我们当前项目来说,应用程序依赖于微服务,同时需要面向业务功能提供HTTP接口和要保证接口的高可用,所以BFF对于当前项目来说是一个合适的选择。
BFF在这里不做太多说明。具体可以自行百度搜索。
4. 服务实现


  • 用户服务 user
api服务端口:9001rpc服务端口:8080
login用户登录接口login用户登录接口
register用户注册接口register用户注册接口
userinfo用户信息接口userinfo用户信息接口
............


  • 首页服务 home
api服务端口:9002rpc服务端口:8081
banner首页Banner接口banner首页Banner接口
recommend人气推荐接口recommend人气推荐接口
ranking-list排行榜接口ranking-list排行榜接口
............


  • 产品服务 product
api服务端口:9004rpc服务端口:8083
detail商品详情接口detail商品详情接口
lists商品列表接口lists商品列表接口
stock商品库存接口stock商品库存接口
cate-lists分类列表接口cate-lists分类列表接口
search搜索接口search搜索接口
............


  • 订单服务 order
api服务端口:9003rpc服务端口:8082
create-order创建订单接口create-order创建订单接口
order-detail订单详情接口order-detail订单详情接口
order-list订单列表接口order-list订单列表接口
order-cancel订单取消接口order-cancel订单取消接口
............


  • 支付服务 pay
api服务端口:9004rpc服务端口:8083
pay-order订单支付接口pay-order订单支付接口
pay-callback支付回调接口pay-callback支付回调接口
............


  • 购物车服务 cart
api服务端口:9004rpc服务端口:8083
cart-add添加购物车接口cart-add添加购物车接口
cart-edit编辑购物车接口cart-edit编辑购物车接口
cart-del删除购物车接口cart-del删除购物车接口
cart-edit-num购物车数量变更接口cart-edit-num购物车数量变更接口
............
5. 目录结构

5.1 创建目录结构

microShop
├── cart             // 购物车服务
│   ├── api         
│   └── rpc         
├── home             // 首页服务
│   ├── api
│   └── rpc
├── order            // 订单服务
│   ├── api
│   └── rpc
├── pay              // 支付服务
│   ├── api
│   └── rpc
├── product          // 产品服务
│   ├── api
│   └── rpc
└── user             // 用户服务
    ├── api
    └── rpc
...
...以上就是咱们这次要实现服务的大体目录结构。
5.2 初始化目录

规划好服务目录结构后,咱么要进行开发离不来一个重要的环节:初始化。go-zero 如何初始化呢?
还记得上一章节 4小节说的吗? 如果不记得请看:go-zero 成长之路—微服务电商实战系列(一、需求篇) 第4小节:需要使用到的命令和工具。
上一章节咱们提到过:goctl,这个工具就是go-zero用来快捷开发的一个服务生成工具。
具体的使用命令呢,可以去 go-zero 官方文档中查看。在这里咱们不过多介绍。
接下来咱们就来直接使用,以 user服务为例:

  • 构建 API 服务,有两种构建方式:
// 方式1:一键初始化api服务
goctl api new user

// 方式2:通过 编写的 user.api 文件进行生成, api.api 文件语法,参考 go-zero 官方文档
goctl api go -api user.api -dir . -style go-zero  构建后的目录结构如下:
├── api.api
├── etc
│   └── user-api.yaml
├── internal
│   ├── config
│   │   └── config.go
│   ├── handler
│   │   ├── handlers.go
│   │   └── routes.go
│   ├── logic
│   │   ├── login-logic.go
│   │   └── register-logic.go
│   ├── svc
│   │   └── service-context.go
│   └── types
│       └── types.go
├── model
│   ├── user_model.go
│   ├── user_model_gen.go
│   ├── user_receive_address_model.go
│   ├── user_receive_address_model_gen.go
│   └── vars.go
├── sql
│   └── user.sql
└── user.go构建后怎么进行启动呢?通过go run 具体参考 go-zero 官方文档
go run user.go -f etc/user-api.yaml

  • 构建 RPC 服务:
// 首先先创建 proto 文件
touch account.proto

// 书写proto文件配置, 具体参考 `go-zero` 官方文档

// 根据proto 文件生成RPC服务
goctl rpc protoc account.proto --go_out=./types --go-grpc_out=./types --zrpc_out=. -style go-zero 构建后的目录结构如下:
├── account.go
├── account.proto
├── etc
│   └── account.yaml
├── internal
│   ├── config
│   │   └── config.go
│   ├── logic
│   │   ├── login-logic.go
│   │   └── register-logic.go
│   ├── server
│   │   └── user-server.go
│   └── svc
│       └── service-context.go
├── model
│   ├── user_model.go
│   ├── user_model_gen.go
│   ├── user_receive_address_model.go
│   ├── user_receive_address_model_gen.go
│   └── vars.go
├── types
│   └── account
│       ├── account.pb.go
│       └── account_grpc.pb.go
└── user
    └── user.go启动方式 同上
go run account.go -f etc/account.yaml

  • 构建 model 模型,有两种构建方式,具体参考 go-zero 官方文档
// 首先 先导出 sql 文件
// 其次通过sql文件的方式进行生成,也就是 ddl 方式
goctl model mysql ddl -src="*.sql" -dir="." -c -style go-zero

// 通过资源句柄链接方式进行生成
goctl model mysql datasource -url="user:password@tcp(127.0.0.1:3306)/database" -table="*"  -dir="./model"到这里user服务的代码初始化已经完成,其他服务和user服务类似,这里就不再多说了。
6. 结束语

本篇我们讲解了微服务的定义,微服务是围绕业务功能构建的,服务关注单一的业务,服务间采用轻量级的通讯机制,每个微服务都可以独立的部署和测试。
我们根据商城功能进行了微服务的拆分,主要拆分了购物车、订单、支付、商品、首页推荐、用户等服务,然后我们又说明了为什么需要引入BFF服务,BFF本质上是一个用于做数据组装的服务,对外提供面向业务功能的或者说面向客户端UI的HTTP接口。
接着我们定义了我们这个工程的目录结构,主要分为api、rpc等服务,不同服务的职责不同,api对外提供HTTP接口,rpc对内提供RPC接口。
最后我们通过goctl对项目做了初始化,使用goctl可一键生成项目框架代码,大大提供了生产力。
希望本篇文章对你有所帮助,谢谢。
7. 关注公众号

GoLang成长之路
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|香雨站

GMT+8, 2025-3-15 17:00 , Processed in 0.219467 second(s), 34 queries .

Powered by Discuz! X3.4

© 2001-2013 Comsenz Inc.. 技术支持 by 巅峰设计

快速回复 返回顶部 返回列表