[云框架]基于 Spring Cloud 的微服务架构 v1.0
微服务 https://martinfowler.com/articles/microservices.html 与传统架构模式相比, 具有语言无关性独立进程通讯高度解耦任务边界固定按需扩展等特点, 非常适合互联网公司快速交付响应变化不断试错的需求, 也因此受到了像 TwitterNetflixAmazoneBay 这样的科技巨头的青睐
目前主流微服务框架包括 Spring CloudDubboAPI Gateway 等, 其中 Spring Cloud http://projects.spring.io/spring-cloud/ 利用 Spring Boot 的开发便利性, 为 JVM 云应用开发中的配置管理服务发现断路器智能路由微代理控制总线全局锁决策竞选分布式会话和集群状态管理等操作提供了一种简单的实现方式
相比 Dubbo 等 RPC 框架, Spring Cloud 是一个比较新的微服务架构基础框架选择, 2016 年才推出的 1.0 release 版本, 不过 Spring Cloud 的方案完整度非常高, 各个子项目几乎覆盖了微服务架构的方方面面从目前的关注度和活跃度来看, Spring Cloud 很可能会成为微服务架构的标准
本篇 云框架 https://github.com/cloudframeworks-springcloud/user-guide-springcloud/blob/master/ABOUT.md 总结过去数十个微服务架构项目的成功经验, 并结合典型案例 PiggyMetrics https://github.com/cloudframeworks-springcloud/PiggyMetrics (一款个人财务管理应用), 为开发者提供基于 Spring Cloud 的微服务架构落地最佳实践
初学者可通过实例代码文档快速学习 Spring Cloud 及微服务, 并在社群中交流讨论;
已有一定了解的开发者, 不必从零开始开发, 仅需在云框架基础上替换部分业务代码, 即可将最佳实践应用于生产环境并立即产生价值
内容概览
快速部署
镜像部署
框架说明
业务
业务背景
业务架构
业务模块
组件
组件架构
- Spring Cloud Config
- Netflix Eureka
- Netflix Zuul
- Netflix Ribbon
- Netflix Hystrix
- Netflix Feign
如何变成自己的项目
生产环境
常见问题
更新计划
参与贡献
加入社群
快速部署
镜像部署
Docker 环境准备
centos
1. 清除 docker 旧版本
- rpm -qa |grep docker
- yum -y remove docker*
2. 安装新的 docker
- yum install -y docker-engine
- 3.systemctl start docker
4.docker info 查看 docker 状态
ubuntu
1. 更新 apt 包
sudo apt-get update
2. 安装 Docker
- sudo apt-get install docker-engine
- 3.sudo service docker start
4.docker info 查看 docker 状态
mac
请参考 https://docs.docker.com/docker-for-mac/ https://docs.docker.com/docker-for-mac/
克隆完整代码
git clone https://github.com/cloudframeworks-springcloud/PiggyMetrics https://github.com/cloudframeworks-springcloud/PiggyMetrics
设置环境变量
- export CONFIG_SERVICE_PASSWORD=root
- export NOTIFICATION_SERVICE_PASSWORD=root
- export STATISTICS_SERVICE_PASSWORD=root
- export ACCOUNT_SERVICE_PASSWORD=root
- export MONGODB_PASSWORD=root ## 必填, 其他变量可不设置
基于 docker-compose https://docs.docker.com/compose/install/ 运行如下命令( docker-compose.yml https://github.com/cloudframeworks-springcloud/PiggyMetrics/blob/master/docker-compose.yml )
docker-compose -f docker-compose.yml up -d
通过脚本运行:
- docker run -d -p15672:15672 --name=rabbitmq rabbitmq:3-management
- docker run -d -e CONFIG_SERVICE_PASSWORD=${CONFIG_SERVICE_PASSWORD} -p 8888:8888 --name=config goodraincloudframeworks/piggymetrics-config
- docker run -d -e CONFIG_SERVICE_PASSWORD=${CONFIG_SERVICE_PASSWORD} --link config:config --name=registry -p 8761:8761 goodraincloudframeworks/piggymetrics-registry
- docker run -d -e MONGODB_PASSWORD=${MONGODB_PASSWORD} --name auth-mongodb goodraincloudframeworks/piggymetrics-mongodb
- docker run -d -e CONFIG_SERVICE_PASSWORD=${CONFIG_SERVICE_PASSWORD} -e NOTIFICATION_SERVICE_PASSWORD=${NOTIFICATION_SERVICE_PASSWORD} -e STATISTICS_SERVICE_PASSWORD=${STATISTICS_SERVICE_PASSWORD} -e ACCOUNT_SERVICE_PASSWORD=${ACCOUNT_SERVICE_PASSWORD} -e MONGODB_PASSWORD=${MONGODB_PASSWORD} --link config:config --link auth-mongodb:auth-mongodb --link registry:registry --name=auth-service goodraincloudframeworks/piggymetrics-auth-service
- docker run -d -e MONGODB_PASSWORD=${MONGODB_PASSWORD} --name account-mongodb goodraincloudframeworks/piggymetrics-mongodb
- docker run -d -e CONFIG_SERVICE_PASSWORD=${CONFIG_SERVICE_PASSWORD} -e ACCOUNT_SERVICE_PASSWORD=${ACCOUNT_SERVICE_PASSWORD} -e MONGODB_PASSWORD=${MONGODB_PASSWORD} --link config:config --link account-mongodb:account-mongodb --link registry:registry --link auth-service:auth-service --link rabbitmq:rabbitmq --name=account-service goodraincloudframeworks/piggymetrics-account-service
- docker run -d -e MONGODB_PASSWORD=${MONGODB_PASSWORD} --name statistics-mongodb goodraincloudframeworks/piggymetrics-mongodb
- docker run -d -e CONFIG_SERVICE_PASSWORD=${CONFIG_SERVICE_PASSWORD} -e STATISTICS_SERVICE_PASSWORD=${STATISTICS_SERVICE_PASSWORD} -e MONGODB_PASSWORD=${MONGODB_PASSWORD} --link config:config --link statistics-mongodb:statistics-mongodb --link registry:registry --link auth-service:auth-service --link rabbitmq:rabbitmq --name=statistics-service goodraincloudframeworks/piggymetrics-statistics-service
- docker run -d -e MONGODB_PASSWORD=${MONGODB_PASSWORD} --name notification-mongodb goodraincloudframeworks/piggymetrics-mongodb
- docker run -d -e CONFIG_SERVICE_PASSWORD=${CONFIG_SERVICE_PASSWORD} -e NOTIFICATION_SERVICE_PASSWORD=${NOTIFICATION_SERVICE_PASSWORD} -e MONGODB_PASSWORD=${MONGODB_PASSWORD} --link config:config --link statistics-mongodb:statistics-mongodb --link registry:registry --link auth-service:auth-service --link rabbitmq:rabbitmq --name=notification-service goodraincloudframeworks/piggymetrics-notification-service
- docker run -ti -e CONFIG_SERVICE_PASSWORD=${CONFIG_SERVICE_PASSWORD} --link config:config --link registry:registry --link rabbitmq:rabbitmq --name=monitoring -p 9000:8080 -p 8989:8989 goodraincloudframeworks/piggymetrics-monitoring
- docker run -d -e CONFIG_SERVICE_PASSWORD=${CONFIG_SERVICE_PASSWORD} --link config:config --link registry:registry --link auth-service:auth-service --name=gateway -p 80:4000 goodraincloudframeworks/piggymetrics-gateway
- Endpoints
- http://DOCKER-HOST:80 http://docker-host/ - Gateway
- http://DOCKER-HOST:8761 http://docker-host:8761/ - Eureka Dashboard
- http://DOCKER-HOST:9000/hystrix http://docker-host:9000/hystrix - Hystrix Dashboard
- http://DOCKER-HOST:8989 http://docker-host:8989/ - Turbine stream (source for the Hystrix Dashboard)
- http://DOCKER-HOST:15672 http://docker-host:15672/ - RabbitMq management (默认账号 guest / 默认密码 guest)
框架说明
业务
Piggymetrics 通过 Spring Cloud 实现微服务架构, 应用被分解为 账户服务 ( ACCOUNT SERVICE https://github.com/cloudframeworks-springcloud/PiggyMetrics/tree/master/account-service ) 统计服务 ( STATISTICS SERVICE https://github.com/cloudframeworks-springcloud/PiggyMetrics/tree/master/statistics-service ) 通知服务 ( NOTIFICATION SERVICE https://github.com/cloudframeworks-springcloud/PiggyMetrics/tree/master/notification-service )等三个核心微服务每个微服务都是围绕业务能力组织的可独立部署的应用程序, 拥有独立的数据库并使用同步的 REST API http://www.restapitutorial.com/ 实现微服务与微服务之间的通信
PiggyMetrics 业务架构如下图所示:
账户服务 模块包含一般用户输入逻辑和验证: 收入 / 费用项目, 储蓄和帐户设置
方法 | 路径 | 描述 | 用户验证 | UI 可用 |
---|---|---|---|---|
GET | /accounts/{account} | 获取特定账户数据 | ||
GET | /accounts/current | 获取当前账户数据 | × | × |
GET | /accounts/demo | 获取 demo 账户数据 (预填充收入 / 支出项目等) | × | |
PUT | /accounts/current | 保存当前账户数据 | × | × |
POST | /accounts/ | 注册新账户 | × |
统计服务模块执行主要统计参数的计算, 并捕获每个帐户的时间序列
方法 | 路径 | 描述 | 用户验证 | UI 可用 |
---|---|---|---|---|
GET | /statistics/{account} | 获取特定账户统计 | ||
GET | /statistics/current | 获取当前账户统计 | × | × |
GET | /statistics/demo | 获取 demo 账户统计 | × | |
PUT | /statistics/{account} | 创建或更新时间系列数据点指定的帐户 |
通知服务模块存储用户联系信息和通知设置(如提醒和备份频率), 计划工作人员从其他服务收集所需的信息, 并向订阅的客户发送电子邮件
方法 | 路径 | 描述 | 用户验证 | UI 可用 |
---|---|---|---|---|
GET | /notifications/settings/current | 获取当前账户通知设置 | × | × |
PUT | /notifications/settings/current | 保存当前账户通知设置 | × | × |
组件
Piggymetrics 基础服务设施中用到了 Spring Cloud ConfigNetflix EurekaNetflix HystrixNetflix ZuulNetflix RibbonNetflix Feign 等组件, 而这也正是 Spring Cloud 分布式开发中最核心的组件
组件架构如下图所示:
账户服务通过远程客户端 (Feign) 调用统计服务及通知服务, 通过 Ribbon 实现负载均衡, 并在调用过程中增加了断路器 (Hystrix) 的功能;
由于服务发现后才能调用, 因此账户服务统计服务通知服务通过注册中心 (Eureka) 实现互相发现;
API Gateway(Zuul)提供对外统一的服务网关, 首先从注册中心 (Eureka) 处获取相应服务, 再根据服务调用各个服务的真实业务逻辑;
服务调用过程通过聚合器 (Turbine) 统一所有断路信息;
整个业务过程中所有服务的配置文件通过 Spring Cloud Config 来管理, 即起什么端口配置什么参数等;
认证机制通过 Auth service 实现, 提供基本认证服务
需要注意的是 Spring Cloud ConfigEurekaRibbonHystrixFeign 以及 Turbine 均为标准组件, 与业务之间没有强关系, 不涉及到业务代码, 仅需简单配置即可工作
Spring Cloud Config
通用说明
在分布式系统中, Spring Cloud Config 通过 config-server(服务端)和 config-client(客户端)提供可扩展的配置服务, 并利用配置服务中心集中管理所有服务的各种环境配置文件 Spring Cloud Config 基于使用中心配置仓库的思想(版本控制), 支持 Git(默认)SVNFile 等三种储存方式
创建 Config Server
创建一个 mvn 工程, 起名为 config-server, 核心依赖:
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-test</artifactId>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>org.springframework.cloud</groupId>
- <artifactId>spring-cloud-config-server</artifactId>
- </dependency>
在程序的入口 Application 类加上 @EnableConfigServer 注解开启配置服务器
- @EnableConfigServer
- @SpringBootApplication
- public class Application {
- public static void main(String[] args) {
- new SpringApplicationBuilder(Application.class).web(true).run(args);
- }
- }
配置文件
- server:
- port: 8888
- spring:
- application:
- name: config-server
- cloud:
- config:
- server:
- git:
- uri: ## 配置文件所存放的 git 地址
- searchPaths: config ## 寻找路径
获取 git 上的资源信息遵循如下规则:
- /{application}/{profile}[/{label}]
- /{application}-{profile}.yml
- /{label}/{application}-{profile}.yml
- /{application}-{profile}.properties
- /{label}/{application}-{profile}.properties
创建 Config client
创建一个 mvn 工程, 起名为 config-client, 核心依赖:
- <dependency>
- <groupId>org.springframework.cloud</groupId>
- <artifactId>spring-cloud-config-client</artifactId>
- </dependency>
在程序的入口 Application 类加上 @EnableConfigServer 注解开启配置服务器
- @SpringBootApplication
- public class Application {
- public static void main(String[] args) {
- new SpringApplicationBuilder(Application.class).web(true).run(args);
- }
- }
创建一个 restful 接口访问配置文件中属性
- @EnableAutoConfiguration
- @RefreshScope
- @RestController
- public class DemoController {
- @Value("${from}")
- String from;
- @RequestMapping("/from")
- public String from() {
- return this.from;
- }
- }
配置文件
- server:
- port: 9000
- spring:
- application:
- name: config-client
- profiles:
- active: dev
- cloud:
- config:
- uri: http://${CONFIG_HOST}:${CONFIG_PORT}
- label: master
访问地址
http://DOCKER_HOST:DOCKER_PORT/from
业务配置
在 PiggyMetrics 项目中, config_server https://github.com/cloudframeworks-springcloud/PiggyMetrics/tree/master/config 从本地类路径加载配置文件:
我们可以在 config service https://github.com/cloudframeworks-springcloud/PiggyMetrics/tree/master/config/src/main/resources/shared 中查看 shard 目录资源, 其中 application.yml 被所有客户端应用共享, 比如当 Notification-service 请求配置时, 使用
shared/notification-service.yml
和
shared/application.yml
配置服务响应
使用 Spring Cloud config 需要在 pom.xml https://github.com/cloudframeworks-springcloud/PiggyMetrics/blob/master/config/pom.xml 中添加 spring-cloud-starter-config(它将从配置中心自动获取配置), 并在各服务资源目录 bootstrap.yml 中, 例如 moinitoring 的 bootstrap.yml https://github.com/cloudframeworks-springcloud/PiggyMetrics/blob/master/monitoring/src/main/resources/bootstrap.yml 中添加如下代码:
- spring:
- application:
name: 服务名
- cloud:
- config:
- uri: http://config:8888
- fail-fast: true
配置文件修改后可通过 http://DOCKER-HOST:DOCKER-PORT/xxx/refresh https://github.com/cloudframeworks-springcloud/http://DOCKER-HOST:DOCKER-PORT/xxx/refresh 刷新配置(xxx 表示服务根路径), 无需重启服务
Netflix Eureka
通用说明
微服务架构比传统 SOA 架构中的服务粒度更小服务数量更多, 为了有效管理各个服务, 服务注册的概念应运而生它的特点是 1)简单易用, 对用户透明; 2)高可用, 满足 CAP 理论; 3)多语言支持
在基于 Spring Cloud 的微服务架构中, 通常采用 Netflix Eureka 作为注册中心, 它的易用性体现在:
通过与 Spring Boot(Cloud)结合达到只用注解和 Maven 依赖即可部署和启动服务的效果
Netflix Eureka 自带 Client 包, 使得使用 Eureka 作为注册中心的客户端 (即服务) 不需要关心自己与 Eureka 的通讯机制, 只需要引入 Client 依赖即可, 当然前提是使用 Java
Netflix Eureka 通过伙伴机制实现高可用, 每一台 Eureka 都需要在配置中指定另一个 Eureka 的地址作为伙伴, Eureka 启动时会向自己的伙伴节点获取当前已经存在的注册列表, 这样在向 Eureka 集群中增加新机器时就不需要担心注册列表不完整的问题, 在 CAP 理论中满足 AP 原则
除此之外, Netflix Eureka 支持 Region 和 Zone 的概念, 其中一个 Region 可以包含多个 ZoneEureka 在启动时需要指定一个 Zone 名, 即指定当前 Eureka 属于哪个 Zone, 如果不指定则属于 defaultZone 值得注意的是, Eureka Client 也需要指定 Zone
Netflix Eureka 使用 Java 编写, 但它会将所有注册信息和心跳连接地址都暴露为 HTTP REST 接口, 客户端实际是通过 HTTP 请求与 Server 进行通讯的, 因此 Client 完全可以使用其它语言进行编写, 只需要即时调用注册服务注销服务获取服务列表和心跳请求的 HTTP REST 接口即可
创建 Eureka Server
创建一个 mvn 工程, 起名为 eureka-server, 核心依赖:
- <dependency>
- <groupId>org.springframework.cloud</groupId>
- <artifactId>spring-cloud-starter-eureka-server</artifactId>
- </dependency>
在程序的入口 Application 类加上 @EnableEurekaServer 注解开启配置服务器
- @SpringBootApplication
- @EnableEurekaServer
- public class EurekaApplication {
- public static void main(String[] args) {
- SpringApplication.run(EurekaApplication.class, args);
- }
- }
配置文件
- server:
- port: 8761
- spring:
- application:
- name: eureka-server
- eureka:
- instance:
- prefer-ip-address: true
- client:
- registerWithEureka: false
- fetchRegistry: false
- serviceUrl:
- defaultZone: http://127.0.0.1:8761/eureka/
- server:
- waitTimeInMsWhenSyncEmpty: 0
- server
- eviction-interval-timer-in-ms: 4000
- enableSelfPreservation: false
- renewalPercentThreshold: 0.9
创建 Eureka service
创建一个 mvn 工程, 起名为 eureka-service, 核心依赖:
- <dependency>
- <groupId>org.springframework.cloud</groupId>
- <artifactId>spring-cloud-starter-eureka</artifactId>
- </dependency>
在程序的入口 Application 类加上 @EnableDiscoveryClient 注解开启配置服务器
- @SpringBootApplication
- @EnableDiscoveryClient
- public class DemoServiceApplication {
- public static void main(String[] args) {
- SpringApplication.run(DemoServiceApplication.class, args);
- }
- }
创建 2 个 restful 接口
普通的 demo 程序, 提供 / demo/show 和 /demo/index 接口
- @RequestMapping("/demo")
- @RestController
- public class DemoController {
- @RequestMapping("/show")
- public String show() {
- return "demo show";
- }
- @RequestMapping("/index")
- public String index() {
- return "demo index";
- }
- }
user 程序, 提供 / user/online 和 / user/offline 接口, 其中 EurekaDiscoveryClientConfiguration 管理改服务在注册中心的声明周期(下线和上线)
- @RequestMapping("/user")
- @RestController
- public class UserController {
- @Autowired
- private EurekaDiscoveryClientConfiguration lifecycle;
- @RequestMapping("/online")
- public String online() {
- this.lifecycle.start();
- return "user online method";
- }
- @RequestMapping("/offline")
- public String offline() {
- this.lifecycle.stop();
- return "user offline method";
- }
- }
配置文件
- spring.application.name=eureka-service
- server.port=5000
- eureka.region=default
- eureka.preferSameZone=false
- eureka.shouldUseDns=false
- eureka.client.serviceUrl.defaultZone=http://${EUREKA_HOST}:${EUREKA_PORT}/eureka/
- eureka.instance.preferIpAddress=true
- eureka.instance.leaseRenewalIntervalInSeconds=10
- eureka.instance.leaseExpirationDurationInSeconds=20
EUREKA_HOST: 注册中心 ip
EUREKA_PORT: 注册中心端口
访问地址
- http://DOCKER_HOST:DOCKER_PORT/demo/index
- http://DOCKER_HOST:DOCKER_PORT/demo/show
- http://DOCKER_HOST:DOCKER_PORT/user/online
- http://DOCKER_HOST:DOCKER_PORT/user/offline
访问注册中心可以看到 eureka-service 已注册
http://EUREKA_HOST:EUREKA_PORT/eureka/
业务配置
PiggyMetrics 通过 Eureka server 实现 registy https://github.com/cloudframeworks-springcloud/PiggyMetrics/tree/master/registry , 代码逻辑比较简单和标准, 不用做任何修改, 需要注意的是在 bootstrap.yml https://github.com/cloudframeworks-springcloud/PiggyMetrics/blob/master/registry/src/main/resources/bootstrap.yml 加入配置中心服务地址信息
- spring:
- cloud:
- config:
- uri: http://config:8888
- fail-fast: true
- password: ${CONFIG_SERVICE_PASSWORD}
- username: user
- Netflix Zuul
通用说明
Netflix Zuul 提供动态路由监控弹性安全等的边缘服务
在通过服务网关统一向外的提供 REST API 的微服务架构中, Netflix Zuul 为微服务机构提供了前门保护的作用, 同时将权限控制这些较重的非业务逻辑内容迁移到服务路由层面, 使得服务集群主体能够具备更高的可复用性和可测试性
创建 zuul service
创建一个 mvn 工程, 起名为 zuul, 核心依赖:
- <dependency>
- <groupId>org.springframework.cloud</groupId>
- <artifactId>spring-cloud-starter-zuul</artifactId>
- </dependency>
在程序的入口 Application 类加上 @EnableZuulProxy 注解开启配置服务器
- @SpringBootApplication
- @EnableDiscoveryClient
- @EnableZuulProxy
- public class GatewayApplication {
- public static void main(String[] args) {
- SpringApplication.run(GatewayApplication.class, args);
- }
- }
配置文件
- server:
- port: 5000
- spring:
- application:
- name: zuul
- eureka:
- client:
- service-url:
- defaultZone: http://${EUREKA_HOST}:${EUREKA_PORT}/eureka/
- hystrix:
- command:
- default:
- execution:
- isolation:
- thread:
- timeoutInMilliseconds: 20000
- ribbon:
- ReadTimeout: 20000
- ConnectTimeout: 20000
- zuul:
- ignoredServices: '*'
- host:
- connect-timeout-millis: 20000
- socket-timeout-millis: 20000
- routes:
- routes:
- demo:
- path: /demo/**
- serviceId: eureka-service
- stripPrefix: false
- sensitiveHeaders: Cookie,Set-Cookie,Authorization
- user:
- path: /user/**
- serviceId: eureka-service
- stripPrefix: false
- sensitiveHeaders: Cookie,Set-Cookie,Authorization
- outer:
- path: /baidu/**
- url: http://www.baidu.com
EUREKA_HOST: 注册中心 ip
EUREKA_PORT: 注册中心端口
访问地址
http://DOCKER_HOST:DOCKER_PORT/feign
业务配置
PiggyMetrics 借助 Netflix Zuul 实现 gateway https://github.com/cloudframeworks-springcloud/PiggyMetrics/tree/master/gateway , 代理授权服务账户服务统计服务和通知服务, 这里的代码比较简单, 基本上是标准的, 不需要修改
我们在实际业务的开发中, 在 GatewayApplication.java https://github.com/cloudframeworks-springcloud/PiggyMetrics/blob/master/gateway/src/main/java/com/piggymetrics/gateway/GatewayApplication.java 用具体业务替换相应的服务即可
- @EnableZuulProxy ## 增加 zuul proxy 代理功能
- public class GatewayApplication {
- public static void main(String[] args) {
- SpringApplication.run(GatewayApplication.class, args);
- }
- }
在 resources 目录下增加 static https://github.com/cloudframeworks-springcloud/PiggyMetrics/tree/master/gateway/src/main/resources/static 录存放你的静态资源(如 htmlcssimages 等)
在 zuul 的配置文件 gateway.yml https://github.com/cloudframeworks-springcloud/PiggyMetrics/blob/master/config/src/main/resources/shared/gateway.yml 中增加代理服务的配置
- zuul:
- ignoredServices: '*'
- host:
- connect-timeout-millis: 20000 ## 超时时间
- ocket-timeout-millis: 20000
- routes:
- auth-service: ## 认证服务
- path: /uaa/** ## 匹配路径
- url: http://auth-service:5000 ## 服务路径(http 方式)
- stripPrefix: false ## 是否包括前缀
- sensitiveHeaders:
- account-service:
- path: /accounts/**
- serviceId: account-service ## 通过服务 ID 动态查找
- stripPrefix: false
- sensitiveHeaders:
- statistics-service:
- path: /statistics/**
- serviceId: statistics-service
- stripPrefix: false
- sensitiveHeaders:
- notification-service:
- path: /notifications/**
- serviceId: notification-service
- stripPrefix: false
- sensitiveHeaders:
- Netflix Ribbon
通用说明
Ribbon 是一个客户端负载均衡器, 有多种负载均衡策略可选 (包括自定义的负载均衡算法), 并可配合服务发现及断路器使用在配置文件中列出 Load Balancer 后面所有的机器, Ribbon 会自动的帮助你基于某种规则(如简单轮询随机连接等) 去连接这些机器
Ribbon 的主要特点包括: 1)负载均衡, 2)容错, 3)在异步和反应模型中支持多协议 (HTTTCPUDP),4) 缓存和批处理
创建 Ribbon service
创建一个 mvn 工程, 起名为 ribbon, 核心依赖如下:
- <dependency>
- <groupId>org.springframework.cloud</groupId>
- <artifactId>spring-cloud-starter-ribbon</artifactId>
- </dependency>
程序的入口 Application 类
- @SpringBootApplication
- @EnableDiscoveryClient
- public class RibbonApplication {
- @Bean
- @LoadBalanced
- RestTemplate restTemplate() {
- return new RestTemplate();
- }
- public static void main(String[] args) {
- SpringApplication.run(RibbonApplication.class, args);
- }
- }
@LoadBalanced: 声明一个 loadBalanced 模版
创建一个远程调用服务
- @RestController
- public class DemoController {
- @Autowired
- RestTemplate restTemplate;
- @RequestMapping(value = "/ribbon", method = RequestMethod.GET)
- public String add() {
- return restTemplate.getForEntity("http://EUREKA-SERVICE/demo/show", String.class).getBody();
- }
- }
EUREKA-SERVICE: 在 eureka 模块中注册的服务
远程调用 / demo/show 这个 rest 接口, 也可以改成 / demo/index 等
配置文件
- spring.application.name=ribbon
- server.port=5000
- eureka.client.serviceUrl.defaultZone=http://${EUREKA_HOST}:${EUREKA_PORT}/eureka/
- eureka.instance.preferIpAddress=true
EUREKA_HOST: 注册中心 ip
EUREKA_PORT: 注册中心端口
访问地址
http://DOCKER_HOST:DOCKER_PORT/ribbon
业务配置
PiggyMetrics 并没有显式的去定义 Netflix Ribbon 的使用, 但是在 ZuulFeign 等组件中隐式的使用到了 Ribbon, 我们在实际的业务开发中, 也不需要刻意定义 Ribbon
Netflix Hystrix
通用说明
Netflix Hystrix 是一个延迟和容错库, 旨在隔离远程系统, 服务和第三方库的访问点, 停止级联故障, 并在不可避免的故障的复杂分布式系统中启用弹性
创建 Hystrix service
创建一个 mvn 工程, 起名为 hystrix-service, 核心依赖如下:
- <dependency>
- <groupId>org.springframework.cloud</groupId>
- <artifactId>spring-cloud-netflix-hystrix-stream</artifactId>
- </dependency>
在程序的入口 Application
- @SpringBootApplication
- @EnableDiscoveryClient
- @EnableFeignClients
- public class HystrixDemoApplication {
- public static void main(String[] args) {
- SpringApplication.run(HystrixDemoApplication.class, args);
- }
- }
创建一个远程调用服务
- @Service
- public class RemoteShowService {
- @Autowired
- private RestTemplate restTemplate;
- @HystrixCommand(fallbackMethod = "reliable", groupKey = "Demo", commandKey = "Show", commandProperties = { @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "1000") })
- public String remoteShow() {
- return restTemplate.getForObject("http://EUREKA-SERVICE/demo/show", String.class);
- }
- public String reliable() {
- return "fallback Method";
- }
- }
@HystrixCommand: 自定义拦截机制
EUREKA-SERVICE: 在 eureka 模块中注册的服务
创建另一个远程调用服务
- @RestController
- @RequestMapping("/first")
- public class HystrixHelloController {
- @Autowired
- private RemoteInvokerService remoteInvokerService;
- @RequestMapping("hystrix")
- @HystrixCommand(fallbackMethod = "failme", groupKey = "Demo", commandKey = "first", commandProperties = { @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "10000") })
- public String remoteHello() {
- return remoteInvokerService.remoteInvoker();
- }
- protected String failme() {
- return "failed invoked Method";
- }
- }
@HystrixCommand: 自定义拦截机制
EUREKA-SERVICE: 在 eureka 模块中注册的服务
配置文件
- spring.application.name=hystrix-service
- server.port=5000
- eureka.client.serviceUrl.defaultZone=http://${EUREKA_HOST}:${EUREKA_PORT}/eureka/
- eureka.instance.preferIpAddress=true
EUREKA_HOST: 注册中心 ip
EUREKA_PORT: 注册中心端口
访问地址
- http://DOCKER_HOST:DOCKER_PORT/first
- http://DOCKER_HOST:DOCKER_PORT/second
创建 Hystrix monitoring
创建一个 mvn 工程, 起名为 hystrix-monitoring, 核心依赖:
- <dependency>
- <groupId>org.springframework.cloud</groupId>
- <artifactId>spring-cloud-starter-turbine-stream</artifactId>
- </dependency>
- <dependency>
- <groupId>org.springframework.cloud</groupId>
- <artifactId>spring-cloud-starter-stream-rabbit</artifactId>
- </dependency>
- <dependency>
- <groupId>org.springframework.cloud</groupId>
- <artifactId>spring-cloud-starter-hystrix-dashboard</artifactId>
- </dependency>
基于 rabbitmq 去收集聚合
在程序的入口 Application, 加入 @EnableTurbineStream 和 @EnableHystrixDashboard
- @@SpringBootApplication
- @EnableTurbineStream
- @EnableHystrixDashboard
- public class MonitoringApplication {
- public static void main(String[] args) {
- SpringApplication.run(MonitoringApplication.class, args);
- }
- }
配置文件
- eureka:
- instance:
- prefer-ip-address: true
- client:
- serviceUrl:
- defaultZone: http://EUREKA_HOST:EUREKA_PORT/eureka/
- spring:
- application:
- name: hystrix-monitor
- rabbitmq:
- host: rabbitmq
EUREKA_HOST: 注册中心 ip
EUREKA_PORT: 注册中心端口
访问地址
http://DOCKER_HOST:8080/hystrix 页面中加入 http://DOCKER_HOST:8989/
业务配置
项目中统一定义了熔断策略(不涉及代码侵入):
- hystrix:
- command:
- default:
- execution:
- isolation:
- thread:
- timeoutInMilliseconds: 10000 ## 10000ms 超时限制
由于 Hystrix 的监控只针对单个节点, 因此 PiggyMetrics 通过 Netflix Turbine 来监控集群下 Hystrix 的 metrics 情况
实现客户端将 Hystrix 命令推送到 Turbine, 只需要在客户端添加如下代码即可, 例如 /notification-service/pom.xml https://github.com/cloudframeworks-springcloud/PiggyMetrics/blob/master/notification-service/pom.xml#L79
- <dependency>
- <groupId>org.springframework.cloud</groupId>
- <artifactId>spring-cloud-netflix-hystrix-stream</artifactId>
- </dependency>
- Netflix Feign
通用说明
Feign 是一个声明式模板化的 HTTP 客户端, 它使得写 web 服务变得更简单使用 Feign, 只需要创建一个接口并注解它具有可插拔的注解特性, 包括 Feign 注解和 JAX-RS 注解 Feign 同时支持可插拔的编码器和解码器当我们使用 feign 的时候, spring cloud 整和了 Ribbon 和 Eureka 去提供负载均衡
简而言之: 1)feign 采用的是接口加注解; 2)feign 整合了 Ribbon
创建 feign service
创建一个 mvn 工程, 起名为 feign, 其 pom.xml 见实例代码, 核心依赖如下:
- <dependency>
- <groupId>org.springframework.cloud</groupId>
- <artifactId>spring-cloud-starter-ribbon</artifactId>
- </dependency>
- <dependency>
- <groupId>org.springframework.cloud</groupId>
- <artifactId>spring-cloud-starter-feign</artifactId>
- </dependency>
在程序的入口 Application 类加上 @EnableFeignClients 注解开启配置服务器
- @SpringBootApplication
- @EnableDiscoveryClient
- @EnableFeignClients
- public class FeignDemoApplication {
- public static void main(String[] args) {
- SpringApplication.run(FeignDemoApplication.class, args);
- }
- }
创建一个远程掉用服务
- @FeignClient("eureka-service")
- public interface RemoteInvokerService {
- @RequestMapping(value = "/demo/show", method = RequestMethod.GET)
- public String remoteInvoker();
- }
eureka-service: 是我们在 eureka 模块中注册的服务
远程掉用 / demo/show 这个 rest 接口, 也可以改成 / demo/index 等
配置文件
- spring.application.name=feign
- server.port=5000
- eureka.client.serviceUrl.defaultZone=http://${EUREKA_HOST}:${EUREKA_PORT}/eureka/
- eureka.instance.preferIpAddress=true
EUREKA_HOST: 注册中心 ip
EUREKA_PORT: 注册中心端口
访问地址
http://DOCKER_HOST:DOCKER_PORT/feign
业务关系
PiggyMetrics 多次用到了 Feign, 使用为在客户端中添加如下代码, 例如 StatisticsServiceClient.java https://github.com/cloudframeworks-springcloud/PiggyMetrics/blob/master/account-service/src/main/java/com/piggymetrics/account/client/StatisticsServiceClient.java
- @FeignClient(name = "auth-service") ## 声明一个认证服务的一个客户端, 通过注册中心去查找 auth-service
- public interface AuthServiceClient {
- @RequestMapping(method = RequestMethod.POST, value = "/uaa/users", consumes = MediaType.APPLICATION_JSON_UTF8_VALUE)
- void createUser(User user);
- }
Feign 同时可以引用注册中心以外的服务没, 例如在统计服务模块, Feign 引入了一个汇率客户端 ExchangeRatesClient.java https://github.com/cloudframeworks-springcloud/PiggyMetrics/blob/master/statistics-service/src/main/java/com/piggymetrics/statistics/client/ExchangeRatesClient.java
- @FeignClient(url = "${rates.url}", name = "rates-client") ## 声明一个汇率客户端, 根据具体的 url(这个可以是外部的服务)
- public interface ExchangeRatesClient {
- @RequestMapping(method = RequestMethod.GET, value = "/latest")
- ExchangeRatesContainer getRates(@RequestParam("base") Currency base);
- }
如何变成自己的项目
步骤:
git clone 项目到本地, 并基于该项目创建自己的 mvn 项目
configregistrygatewaymonitoring, 这 4 个组件不需要修改代码
auth-serviceaccount-servicenotification-servicestatistics-service 替换成自己的服务
在 config 中修改统一的配置文件, 比如新增服务的服务名端口等
通过 mvn 构建后生成镜像
运行所有的镜像, 可参考快速部署
生产环境
TODO CI/CD
TODO 扩容
TODO 服务容错
TODO 业务监控 / 性能分析
TODO K8s 部署
常见问题
任何相关问题均可通过 GitHub ISSUE https://github.com/cloudframeworks-springcloud/user-guide/issues 提交或讨论, 问题总结请查看[ QA https://github.com/cloudframeworks-springcloud/user-guide-springcloud/blob/master/QA.md ]
更新计划
Roadmap
文档 增加在线演示
组件 增加组件内容, 如 Spring Cloud SleuthSpring Cloud Consul 等
生产环境 增加生产环境下各项扩展操作, 如性能测试及各类部署特性技术实现等
快速部署 增加好雨云帮部署
常见问题 补充问题总结 QA https://github.com/cloudframeworks-springcloud/user-guide-springcloud/blob/master/QA.md
点击查看 历史更新 https://github.com/cloudframeworks-springcloud/user-guide-springcloud/blob/master/CHANGELOG.md
参与贡献
如何成为云框架贡献者 https://github.com/cloudframeworks-springcloud/user-guide-springcloud/blob/master/CONTRIBUTING.md
来源: http://www.tuicool.com/articles/m2YJzqR