跳到主要内容

微服务

微服务架构(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