跳到主要内容

微服务

微服务架构(Microservices Architecture)是一种将单个应用程序分解为多个独立部署的小服务的架构模式, 每个服务专注于特定的业务功能, 具有高内聚和松耦合的特点. 它允许各个服务独立开发, 部署和扩展, 支持灵活的技术选型, 提高系统的弹性和扩展性. 然而微服务架构也带来了系统复杂性增加, 运维成本高, 通信开销大和数据一致性保障难等挑战

Graphoenix 全面支持微服务架构, 提供服务注册, 网关, 熔断, 负载均衡, 事务补偿等全套的微服务解决方案. 系统通过不同的包名(Package Name)来区分模块, 每个模块可以独立提供服务, 通过 gRPC 等通讯协议构成微服务矩阵, 也可以与其他模块合并为单体架构提供服务

服务拆分

微服务的拆分是将一个单体应用分解为多个独立部署的小服务, 每个服务专注于特定业务功能. 通过领域驱动设计(DDD), 业务功能划分, 独立数据库, 独立部署和服务通信, 实现更好的隔离和独立性

例: 我们将快速开始中的订单系统拆分为订单(demo.gp.order), 用户(demo.gp.user), 评论(demo.gp.review)三个子系统

模块和服务

项目按照功能分为模块(package)和服务(app), 服务作为模块的载体, 按照不同的组合方式构建单体架构或微服务矩阵:

  1. app(package1 + package2 + package3) = monolithic
  2. app1(package1) + app2(package2) + app3(package3) = microservices
项目结构
|-- order-microservices
|-- build.gradle
|-- gradle.properties
|-- settings.gradle
|-- order-app 订单系统
| |-- build.gradle
| |-- src
| |-- main
| |-- java
| | |-- demo.gp.order
| | |-- App.java
| |-- resources
| |-- application.conf
|-- order-package 订单模块
| |-- build.gradle
| |-- src
| |-- main
| |-- java
| | |-- demo.gp.order
| | |-- package-info.java
| |-- resources
| |-- graphql
| |-- order.gql 定义订单相关类型
|-- review-app 评论系统
| |-- build.gradle
| |-- src
| |-- main
| |-- java
| | |-- demo.gp.review
| | |-- App.java
| |-- resources
| |-- application.conf
|-- review-package 评论模块
| |-- build.gradle
| |-- src
| |-- main
| |-- java
| | |-- demo.gp.review
| | |-- package-info.java
| |-- resources
| |-- graphql
| |-- review.gql 定义评论相关类型
|-- user-app 用户系统
| |-- build.gradle
| |-- src
| |-- main
| |-- java
| | |-- demo.gp.user
| | |-- App.java
| |-- resources
| |-- application.conf
|-- user-package 用户模块
|-- build.gradle
|-- src
|-- main
|-- java
| |-- demo.gp.user
| |-- package-info.java
|-- resources
|-- graphql
|-- user.gql 定义用户相关类型
  1. 用户模块中定义用户(User)和用户类型(UserType)
  2. 评论模块中定义评论(Review), 评论的评论人字段(user)引用用户模块的用户(User)
  3. 订单模块中定义订单(Order)和产品(Product), 订单的购买用户字段(user)引用用户模块的用户(User), 产品的评论列表字段(reviews)引用评论模块的评论(Review)

安装

protobuf 插件

模块之间默认使用 gRPC 进行通讯, 需要引用插件生成 protobuf 文件

user-package
build.gradle
buildscript {
repositories {
jcenter()
}
}

plugins {
id 'java'
id 'com.google.protobuf' version '0.9.1'
id "org.graphoenix" version "0.1.1"
}

classes {
dependsOn generateGraphQLSource
dependsOn generateProtobufV3
}

生成 DTO 和 protobuf

./gradlew :user-package:build
review-package
build.gradle
buildscript {
repositories {
jcenter()
}
}

plugins {
id 'java'
id 'com.google.protobuf' version '0.9.1'
id "org.graphoenix" version "0.1.1"
}

classes {
dependsOn generateGraphQLSource
dependsOn generateProtobufV3
}

生成 DTO 和 protobuf

./gradlew :review-package:build
order-package
build.gradle
buildscript {
repositories {
jcenter()
}
}

plugins {
id 'java'
id 'com.google.protobuf' version '0.9.1'
id "org.graphoenix" version "0.1.1"
}

classes.dependsOn {
generateGraphQLSource
generateProtobufV3
}

生成 DTO 和 protobuf

./gradlew :order-package:build

模块(package)依赖

安装和配置 gRPC, 引用其他模块

user-package
build.gradle
// gRPC 配置
protobuf {
protoc {
artifact = 'com.google.protobuf:protoc:3.21.7'
}
plugins {
grpc {
artifact = 'io.grpc:protoc-gen-grpc-java:1.52.1'
}
reactor {
artifact = 'com.salesforce.servicelibs:reactor-grpc:1.2.3'
}
}
generateProtoTasks {
all()*.plugins {
grpc {}
reactor {}
}
}
}

// gRPC 目录配置
sourceSets {
main {
java {
srcDirs 'build/generated/source/proto/main/java'
srcDirs 'build/generated/source/proto/main/grpc'
srcDirs 'build/generated/source/proto/main/reactor'
}
}
}

dependencies {
// gRPC 依赖
runtimeOnly 'io.grpc:grpc-netty-shaded:1.52.1'
implementation 'io.grpc:grpc-protobuf:1.52.1'
implementation 'io.grpc:grpc-stub:1.52.1'
implementation 'com.salesforce.servicelibs:reactor-grpc-stub:1.2.3'
compileOnly 'org.apache.tomcat:annotations-api:6.0.53' // necessary for Java 9+

// ...
}
review-package
build.gradle
// gRPC 配置
protobuf {
protoc {
artifact = 'com.google.protobuf:protoc:3.21.7'
}
plugins {
grpc {
artifact = 'io.grpc:protoc-gen-grpc-java:1.52.1'
}
reactor {
artifact = 'com.salesforce.servicelibs:reactor-grpc:1.2.3'
}
}
generateProtoTasks {
all()*.plugins {
grpc {}
reactor {}
}
}
}

// gRPC 目录配置
sourceSets {
main {
java {
srcDirs 'build/generated/source/proto/main/java'
srcDirs 'build/generated/source/proto/main/grpc'
srcDirs 'build/generated/source/proto/main/reactor'
}
}
}

dependencies {
// 引用 User 模块
implementation project(':user-package')

// gRPC 依赖
runtimeOnly 'io.grpc:grpc-netty-shaded:1.52.1'
implementation 'io.grpc:grpc-protobuf:1.52.1'
implementation 'io.grpc:grpc-stub:1.52.1'
implementation 'com.salesforce.servicelibs:reactor-grpc-stub:1.2.3'
compileOnly 'org.apache.tomcat:annotations-api:6.0.53' // necessary for Java 9+

// 引用 User 模块
annotationProcessor project(':user-package')

// 引用 User 模块
protobuf project(':user-package')

// ...
}
order-package
build.gradle
// gRPC 配置
protobuf {
protoc {
artifact = 'com.google.protobuf:protoc:3.21.7'
}
plugins {
grpc {
artifact = 'io.grpc:protoc-gen-grpc-java:1.52.1'
}
reactor {
artifact = 'com.salesforce.servicelibs:reactor-grpc:1.2.3'
}
}
generateProtoTasks {
all()*.plugins {
grpc {}
reactor {}
}
}
}

// gRPC 目录配置
sourceSets {
main {
java {
srcDirs 'build/generated/source/proto/main/java'
srcDirs 'build/generated/source/proto/main/grpc'
srcDirs 'build/generated/source/proto/main/reactor'
}
}
}

dependencies {
// 引用 User 模块
implementation project(':user-package')
// 引用 Review 模块
implementation project(':review-package')

// gRPC 依赖
runtimeOnly 'io.grpc:grpc-netty-shaded:1.52.1'
implementation 'io.grpc:grpc-protobuf:1.52.1'
implementation 'io.grpc:grpc-stub:1.52.1'
implementation 'com.salesforce.servicelibs:reactor-grpc-stub:1.2.3'
compileOnly 'org.apache.tomcat:annotations-api:6.0.53' // necessary for Java 9+

// 引用 User 模块
annotationProcessor project(':user-package')
// 引用 Review 模块
annotationProcessor project(':review-package')

// 引用 User 模块
protobuf project(':user-package')
// 引用 Review 模块
protobuf project(':review-package')

// ..
}

服务(app)依赖

引用模块, 安装服务依赖

user-app
build.gradle
dependencies {
// User 模块
implementation project(':user-package')

// Http 服务
implementation 'org.graphoenix:graphoenix-http-server:0.1.4'
// gRPC 服务
implementation 'org.graphoenix:graphoenix-grpc-server:0.1.4'

// User 模块
annotationProcessor project(':user-package')

// gRPC 服务
annotationProcessor 'org.graphoenix:graphoenix-grpc-server:0.1.4'

// ...
}
review-app
build.gradle
dependencies {
// User 模块
implementation project(':user-package')
// Review 模块
implementation project(':review-package')

// Http 服务
implementation 'org.graphoenix:graphoenix-http-server:0.1.4'
// gRPC 服务
implementation 'org.graphoenix:graphoenix-grpc-server:0.1.4'
// gRPC 客户端, 调用其他模块
implementation 'org.graphoenix:graphoenix-grpc-client:0.1.3'

// User 模块
annotationProcessor project(':user-package')
// Review 模块
annotationProcessor project(':review-package')

// gRPC 服务
annotationProcessor 'org.graphoenix:graphoenix-grpc-server:0.1.4'
// gRPC 客户端, 调用其他模块
annotationProcessor 'org.graphoenix:graphoenix-grpc-client:0.1.3'

// ...
}
order-app
build.gradle
dependencies {
// User 模块
implementation project(':user-package')
// Review 模块
implementation project(':review-package')
// Order 模块
implementation project(':order-package')

// Http 服务
implementation 'org.graphoenix:graphoenix-http-server:0.1.4'
// gRPC 服务
implementation 'org.graphoenix:graphoenix-grpc-server:0.1.4'
// gRPC 客户端, 调用其他模块
implementation 'org.graphoenix:graphoenix-grpc-client:0.1.3'

// User 模块
annotationProcessor project(':user-package')
// Review 模块
annotationProcessor project(':review-package')
// Order 模块
annotationProcessor project(':order-package')

// gRPC 服务
annotationProcessor 'org.graphoenix:graphoenix-grpc-server:0.1.4'
// gRPC 客户端, 调用其他模块
annotationProcessor 'org.graphoenix:graphoenix-grpc-client:0.1.3'

// ...
}

配置

配置数据库和服务

user-app/src/main/resources/application.conf
r2dbc {
driver = "mariadb"
database = "user"
user = "root"
password = "root"
}
http {
port = 8082 //Http 端口
}
grpc {
port = 50053 //gRPC 端口
}
review-app/src/main/resources/application.conf
r2dbc {
driver = "mariadb"
database = "review"
user = "root"
password = "root"
}
http {
port = 8081 //Http 端口
}
grpc {
port = 50052 //gRPC 端口
}
order-app/src/main/resources/application.conf
r2dbc {
driver = "mariadb"
database = "order"
user = "root"
password = "root"
}
http {
port = 8080 //Http 端口
}
grpc {
port = 50051 //gRPC 端口
}

配置模块地址

使用 package.members 配置每个模块的地址, 每个模块都可以提供多个服务作为冗余

review-app/src/main/resources/application.conf
package {
members: {"demo.gp.user": [{host: "127.0.0.1", port: 50053, protocol: "GRPC"}]}
}
order-app/src/main/resources/application.conf
package {
members: {"demo.gp.review": [{host: "127.0.0.1", port: 50052, protocol: "GRPC"}], "demo.gp.user": [{host: "127.0.0.1", port: 50053, protocol: "GRPC"}]}
}

Gossip

随着项目规模的发展, 微服务节点逐步增长, 需要引入一种自动注册机制来替代手动配置. Graphoenix 使用 Gossip 协议进行服务发现. Gossip 协议是一种用于分布式系统中信息传播和数据一致性的协议, 具有去中心化, 容错性强, 渐进一致性和易扩展等特性, 是确保节点间信息同步和一致性的关键技术

安装 Gossip 依赖

dependencies {
implementation 'org.graphoenix:graphoenix-gossip:0.1.3'

annotationProcessor 'org.graphoenix:graphoenix-gossip:0.1.3'

// ...
}

配置 Gossip 端口

user-app/src/main/resources/application.conf
gossip {
port = 3000
}
review-app/src/main/resources/application.conf
gossip {
port = 3001
}
order-app/src/main/resources/application.conf
gossip {
port = 3002
}

配置种子节点

使用 package.members.seeds 配置种子节点, 所有节点都会从种子节点开始交换信息

例: 使用用户模块(demo.gp.user)节点作为种子节点

review-app/src/main/resources/application.conf
package {
// members: {"demo.gp.user": [{host: "127.0.0.1", port: 50053, protocol: "GRPC"}]}
members: {seeds: [{host: "127.0.0.1", port: 3000}]}
}
order-app/src/main/resources/application.conf
package {
// members: {"demo.gp.review": [{host: "127.0.0.1", port: 50052, protocol: "GRPC"}], "demo.gp.user": [{host: "127.0.0.1", port: 50053, protocol: "GRPC"}]}
members: {seeds: [{host: "127.0.0.1", port: 3000}]}
}

事务补偿

在微服务架构下, Graphoenix 通过事务补偿(TCC)保持数据一致性.

使用 mutation.compensatingTransaction 配置开启事务补偿

mutation {
compensatingTransaction = true
}

微服务启动

  1. Run/Debug user-app/src/main/java/demo/gp/user/App.java
  2. Run/Debug review-app/src/main/java/demo/gp/review/App.java
  3. Run/Debug order-app/src/main/java/demo/gp/order/App.java

start


服务合并

在业务收缩阶段或是流量低谷时段, 多个模块可以合并为单一服务来降低通信和硬件等成本

配置本地模块

使用 package.localPackageNames 配置本地模块, 本地模块将和到主模块合并到同一服务中

例: 订单模块(demo.gp.order)引入评论模块(demo.gp.review)和用户模块(demo.gp.user)

order-app/src/main/resources/application.conf
package {
// members: {"demo.gp.review": [{host: "127.0.0.1", port: 50052, protocol: "GRPC"}], "demo.gp.user": [{host: "127.0.0.1", port: 50053, protocol: "GRPC"}]}
// members: {seeds: [{host: "127.0.0.1", port: 3080}]}
localPackageNames = ["demo.gp.review", "demo.gp.user"]
}

单体服务启动

Run/Debug order-app/src/main/java/demo/gp/order/App.java

start


查询和变更

架构的切换不会影响查询和变更的使用, Graphoenix 通过底层技术屏蔽不同架构的差异, 让接口层的表现保持一致

测试数据
mutation {
userList(
list: [
{ id: "1", name: "Alice", email: "alice@example.com", userType: VIP }
{ id: "2", name: "Bob", email: "bob@example.com", userType: REGULAR }
{ id: "3", name: "Charlie", email: "charlie@example.com", userType: VIP }
{ id: "4", name: "Diana", email: "diana@example.com", userType: REGULAR }
{ id: "5", name: "Edward", email: "edward@example.com", userType: VIP }
{ id: "6", name: "Fiona", email: "fiona@example.com", userType: REGULAR }
{ id: "7", name: "George", email: "george@example.com", userType: VIP }
{
id: "8"
name: "Hannah"
email: "hannah@example.com"
userType: REGULAR
}
{ id: "9", name: "Ian", email: "ian@example.com", userType: VIP }
{ id: "10", name: "Jane", email: "jane@example.com", userType: REGULAR }
{ id: "11", name: "Kyle", email: "kyle@example.com", userType: VIP }
{ id: "12", name: "Laura", email: "laura@example.com", userType: REGULAR }
{ id: "13", name: "Mike", email: "mike@example.com", userType: VIP }
{ id: "14", name: "Nina", email: "nina@example.com", userType: REGULAR }
{ id: "15", name: "Oliver", email: "oliver@example.com", userType: VIP }
{ id: "16", name: "Paula", email: "paula@example.com", userType: REGULAR }
{ id: "17", name: "Quentin", email: "quentin@example.com", userType: VIP }
{
id: "18"
name: "Rachel"
email: "rachel@example.com"
userType: REGULAR
}
{ id: "19", name: "Steve", email: "steve@example.com", userType: VIP }
{ id: "20", name: "Tina", email: "tina@example.com", userType: REGULAR }
]
) {
id
}
reviewList(
list: [
{
id: "1"
content: "Great laptop, very fast and reliable."
rating: 5
user: { where: { id: { val: "10" } } }
}
{
id: "2"
content: "Decent laptop but a bit expensive."
rating: 4
user: { where: { id: { val: "8" } } }
}
{
id: "3"
content: "The phone is amazing, camera quality is top-notch."
rating: 5
user: { where: { id: { val: "6" } } }
}
{
id: "4"
content: "Tablet is good for the price."
rating: 4
user: { where: { id: { val: "4" } } }
}
]
) {
id
}
productList(
list: [
{
id: "1"
name: "Laptop"
price: 999.99
reviews: [
{ where: { id: { val: "1" } } }
{ where: { id: { val: "2" } } }
]
}
{
id: "2"
name: "Phone"
price: 499.99
reviews: [{ where: { id: { val: "3" } } }]
}
{
id: "3"
name: "Tablet"
price: 299.99
reviews: [{ where: { id: { val: "4" } } }]
}
{ id: "4", name: "Monitor", price: 199.99 }
{ id: "5", name: "Keyboard", price: 49.99 }
]
) {
id
}
orderList(
list: [
{
user: { where: { id: { val: "1" } } }
items: [
{ product: { where: { id: { val: "1" } } }, quantity: 1 }
{ product: { where: { id: { val: "3" } } }, quantity: 2 }
]
}
{
user: { where: { id: { val: "2" } } }
items: [{ product: { where: { id: { val: "2" } } }, quantity: 1 }]
}
{
user: { where: { id: { val: "3" } } }
items: [
{ product: { where: { id: { val: "4" } } }, quantity: 2 }
{ product: { where: { id: { val: "5" } } }, quantity: 3 }
]
}
{
user: { where: { id: { val: "4" } } }
items: [
{ product: { where: { id: { val: "1" } } }, quantity: 1 }
{ product: { where: { id: { val: "2" } } }, quantity: 1 }
{ product: { where: { id: { val: "3" } } }, quantity: 1 }
]
}
]
) {
id
}
}
  1. 例: 查询用户 Alice 的订单
{
orderList(user: { name: { val: "Alice" } }) {
items {
product {
name
}
quantity
}
}
}
{
"data": {
"orderList": [
{
"items": [
{
"product": {
"name": "Laptop"
},
"quantity": 1
},
{
"product": {
"name": "Tablet"
},
"quantity": 2
}
]
}
]
}
}
  1. 例: 查询评价 4 分以上的产品
{
productList(reviews: { rating: { opr: GT, val: 4 } }) {
name
price
reviews {
content
rating
user {
name
}
}
}
}
{
"data": {
"productList": [
{
"name": "Laptop",
"price": 999.99,
"reviews": [
{
"content": "Great laptop, very fast and reliable.",
"rating": 5,
"user": {
"name": "Jane"
}
},
{
"content": "Decent laptop but a bit expensive.",
"rating": 4,
"user": {
"name": "Hannah"
}
}
]
},
{
"name": "Phone",
"price": 499.99,
"reviews": [
{
"content": "The phone is amazing, camera quality is top-notch.",
"rating": 5,
"user": {
"name": "Fiona"
}
}
]
}
]
}
}
  1. 例: 同时新增产品, 评论和用户
mutation {
product(
name: "Mouse"
price: 25.99
reviews: [
{
content: "Been using this mouse for quite some time with no concerns. "
rating: 4
user: { name: "Victor", userType: VIP }
}
]
) {
name
price
reviews {
content
rating
user {
name
userType
}
}
}
}
{
"data": {
"product": {
"name": "Mouse",
"price": 25.99,
"reviews": [
{
"content": "Been using this mouse for quite some time with no concerns. ",
"rating": 4,
"user": {
"name": "Victor",
"userType": "VIP"
}
}
]
}
}
}

本节示例

https://github.com/doukai/order-microservices