├── docs ├── CNAME ├── img │ ├── wx.jpg │ ├── zfb.png │ ├── sleuth-kibana.png │ ├── stream-binder.png │ ├── stream-groups.png │ ├── sleuth-parents.png │ ├── sleuth-traceid.png │ ├── sleuth-zipkin-ui.png │ ├── stream-sensors.png │ ├── sleuth-dependencies.png │ ├── sleuth-zipkin-traces.png │ ├── stream-partitioning.png │ └── stream-producers-consumers.png ├── project │ ├── SpringCloudCLI.md │ ├── SpringCloudTask.md │ ├── SpringCloudConnectors.md │ ├── SpringCloudforCloudFoundry.md │ ├── SpringCloudStreamModules.md │ ├── SpringCloudforAmazonWebServices.md │ ├── SpringCloudCloudFoundryServiceBroker.md │ ├── SpringCloudDataFlow.md │ ├── SpringCloudZookeeper.md │ ├── SpringCloudBus.md │ ├── SpringCloudSecurity.md │ ├── SpringCloudConsul.md │ ├── SpringCloudNetflix.md │ ├── SpringCloudConfig.md │ ├── SpringCloudStream.md │ ├── SpringCloudSleuth.md │ └── QuickStart.md ├── css │ └── extra.css ├── source.md ├── index.md ├── about │ ├── license.md │ ├── contributing.md │ └── release-notes.md └── user-guide │ ├── config.md │ ├── bus.md │ ├── ribbon.md │ ├── feign.md │ ├── eureka.md │ ├── zuul.md │ ├── stream.md │ └── sleuth.md ├── README.md ├── mkdocs目录.png └── mkdocs.yml /docs/CNAME: -------------------------------------------------------------------------------- 1 | docs.springcloud.cn 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # spring-cloud-docs 2 | docs.springcloud.cn文档 3 | -------------------------------------------------------------------------------- /mkdocs目录.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SpringCloud/spring-cloud-docs/HEAD/mkdocs目录.png -------------------------------------------------------------------------------- /docs/img/wx.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SpringCloud/spring-cloud-docs/HEAD/docs/img/wx.jpg -------------------------------------------------------------------------------- /docs/img/zfb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SpringCloud/spring-cloud-docs/HEAD/docs/img/zfb.png -------------------------------------------------------------------------------- /docs/img/sleuth-kibana.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SpringCloud/spring-cloud-docs/HEAD/docs/img/sleuth-kibana.png -------------------------------------------------------------------------------- /docs/img/stream-binder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SpringCloud/spring-cloud-docs/HEAD/docs/img/stream-binder.png -------------------------------------------------------------------------------- /docs/img/stream-groups.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SpringCloud/spring-cloud-docs/HEAD/docs/img/stream-groups.png -------------------------------------------------------------------------------- /docs/img/sleuth-parents.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SpringCloud/spring-cloud-docs/HEAD/docs/img/sleuth-parents.png -------------------------------------------------------------------------------- /docs/img/sleuth-traceid.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SpringCloud/spring-cloud-docs/HEAD/docs/img/sleuth-traceid.png -------------------------------------------------------------------------------- /docs/img/sleuth-zipkin-ui.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SpringCloud/spring-cloud-docs/HEAD/docs/img/sleuth-zipkin-ui.png -------------------------------------------------------------------------------- /docs/img/stream-sensors.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SpringCloud/spring-cloud-docs/HEAD/docs/img/stream-sensors.png -------------------------------------------------------------------------------- /docs/img/sleuth-dependencies.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SpringCloud/spring-cloud-docs/HEAD/docs/img/sleuth-dependencies.png -------------------------------------------------------------------------------- /docs/img/sleuth-zipkin-traces.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SpringCloud/spring-cloud-docs/HEAD/docs/img/sleuth-zipkin-traces.png -------------------------------------------------------------------------------- /docs/img/stream-partitioning.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SpringCloud/spring-cloud-docs/HEAD/docs/img/stream-partitioning.png -------------------------------------------------------------------------------- /docs/img/stream-producers-consumers.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SpringCloud/spring-cloud-docs/HEAD/docs/img/stream-producers-consumers.png -------------------------------------------------------------------------------- /docs/project/SpringCloudCLI.md: -------------------------------------------------------------------------------- 1 | # Spring Cloud CLI 2 | 3 | For full documentation visit [spring cloud cli](http://cloud.spring.io/spring-cloud-cli/). 4 | 5 | ## Quick Start 6 | 7 | -------------------------------------------------------------------------------- /docs/project/SpringCloudTask.md: -------------------------------------------------------------------------------- 1 | # Spring Cloud Task 2 | 3 | For full documentation visit [spring cloud task](http://cloud.spring.io/spring-cloud-task/). 4 | 5 | ## Quick Start 6 | 7 | -------------------------------------------------------------------------------- /docs/project/SpringCloudConnectors.md: -------------------------------------------------------------------------------- 1 | # Spring Cloud Connectors 2 | 3 | For full documentation visit [spring cloud connectors](http://cloud.spring.io/spring-cloud-connectors/). 4 | 5 | ## Quick Start 6 | 7 | -------------------------------------------------------------------------------- /docs/project/SpringCloudforCloudFoundry.md: -------------------------------------------------------------------------------- 1 | # Spring Cloud Cloud Foundry 2 | 3 | For full documentation visit [spring cloud cloud foundry](http://cloud.spring.io/spring-cloud-cloudfoundry/). 4 | 5 | ## Quick Start 6 | 7 | -------------------------------------------------------------------------------- /docs/project/SpringCloudStreamModules.md: -------------------------------------------------------------------------------- 1 | # Spring Cloud Stream Applications 2 | 3 | For full documentation visit [spring cloud stream applications](http://cloud.spring.io/spring-cloud-stream-modules/). 4 | 5 | ## Quick Start 6 | 7 | -------------------------------------------------------------------------------- /docs/project/SpringCloudforAmazonWebServices.md: -------------------------------------------------------------------------------- 1 | # Spring Cloud for Amazon Web Services 2 | 3 | For full documentation visit [spring cloud for amazon web services](http://cloud.spring.io/spring-cloud-aws/). 4 | 5 | ## Quick Start 6 | 7 | -------------------------------------------------------------------------------- /docs/project/SpringCloudCloudFoundryServiceBroker.md: -------------------------------------------------------------------------------- 1 | # Spring Cloud Cloud Foundry Service Broker 2 | 3 | For full documentation visit [spring cloud cloud foundry service broker](http://cloud.spring.io/spring-cloud-cloudfoundry-service-broker/). 4 | 5 | ## Quick Start 6 | 7 | -------------------------------------------------------------------------------- /docs/project/SpringCloudDataFlow.md: -------------------------------------------------------------------------------- 1 | # Spring Cloud Data Flow 2 | 3 | Spring Cloud Data Flow是一种原生云业务流程服务,在现代运行时组合数据的微服务。开发人员可以创建和编排数据管道常见的用例如数据采集,实时分析,数据导入/导出 4 | 5 | For full documentation visit [spring cloud data flow](http://cloud.spring.io/spring-cloud-dataflow/). 6 | 7 | ## Quick Start 8 | 9 | -------------------------------------------------------------------------------- /docs/css/extra.css: -------------------------------------------------------------------------------- 1 | div.col-md-9 h1:first-of-type { 2 | text-align: center; 3 | font-size: 60px; 4 | font-weight: 300; 5 | } 6 | 7 | div.col-md-9 p:first-of-type { 8 | text-align: center; 9 | } 10 | 11 | div.col-md-9 p.admonition-title:first-of-type { 12 | text-align: left; 13 | } 14 | 15 | div.col-md-9 h1:first-of-type .headerlink { 16 | display: none; 17 | } 18 | 19 | code.no-highlight { 20 | color: black; 21 | } 22 | -------------------------------------------------------------------------------- /docs/source.md: -------------------------------------------------------------------------------- 1 | # Spring Cloud源码分析系列 2 | ## Spring Cloud Eureka源码分析 3 | 4 | ## [Spring Cloud Eureka服务续约(Renew)源码分析](http://blog.xujin.org/sc/sc-eureka-renew/) 5 | 6 | ## [Spring Cloud Eureka服务注册源码分析](http://blog.xujin.org/sc/sc-eureka-register/) 7 | 8 | ## [Spring Cloud中@EnableEurekaClient源码分析](http://blog.xujin.org/sc/sc-enableEurekaClient-annonation/) 9 | 10 | ## [Spring Cloud Eureka服务下线(Cancel)源码分析](http://blog.xujin.org/sc/sc-eureka-cancle/) 11 | -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | # Spring Cloud中国社区 2 | 欢迎来到,Spring Cloud中国社区文档地址,欢迎贡献优质博客和翻译文档 3 | 4 | --- 5 | 6 | ## 为什么要发起Spring Cloud中国社区 7 | Spring Cloud发展到2016年,国内关注的人越来越多,但是相应学习交流的平台和材料比较分散,不利于学习交流,因此Spring Cloud中国社区应运而生。于是Spring Cloud中国社区由许进联合翟永超,周立发起Spring cloud中国社区,是国内首个Spring Cloud构建微服务架构的交流社区。我们致力于为Spring Boot或Spring Cloud技术人员提供分享和交流的平台,推动Spring Cloud在中国的普及和应用。 欢迎CTO、架构师、开发者等,在这里学习与交流使用Spring Cloud的实战经验。 目前QQ群人数:2000+,微信群:600+ 8 | 9 | Spring Cloud中国社区精英群:415028731 10 | 11 | Spring cloud中国社区QQ群:470962790(已满) 12 | 13 | Spring Cloud中国社区官网:http://springcloud.cn 14 | 15 | Spring Cloud中国社区论坛:http://bbs.springcloud.cn 16 | 17 | Spring Cloud中国社区文档:http://docs.springcloud.cn 18 | 19 | ## spring cloud目前国内使用情况 20 | 1. 中国联通子公司 21 | http://flp.baidu.com/feedland/video/?entry=box_searchbox_feed&id=144115189637730162&from=timeline&isappinstalled=0 22 | 23 | 2. 上海米么金服 24 | 3. 指点无限(北京)科技有限公司 25 | 4. 易保软件 目前在定制开发中 26 | http://www.ebaotech.com/cn/ 27 | 5. 广州简法网络 28 | 6. 深圳睿云智合科技有限公司 29 | 持续交付产品基于Spring Cloud研发 http://www.wise2c.com 30 | 7. 猪八戒网,目前调研中 31 | 8. 上海云首科技有限公司 32 | 9. 华为 33 | 整合netty进来用rpc 包括nerflix那套东西 需要注意的是sleuth traceid的传递需要自己写。tps在物理机上能突破20w 34 | 10. 东软 35 | 11. 南京云帐房网络科技有限公司 36 | 12. 四众互联(北京)网络科技有限公司 37 | 13. 深圳摩令技术科技有限公司 38 | 14. 广州万表网 39 | 15. 视觉中国 40 | 16. 上海秦苍信息科技有限公司-买单侠 41 | 17. 爱油科技(大连)有限公司 42 | [爱油科技基于SpringCloud的微服务实践](http://blog.xujin.org/sc/sc-fx1/) 43 | 数据在统计之中,会一直持续更新,敬请期待! 44 | 45 | ## 贡献文档 46 | 欢迎大家贡献,优质的博客文章和翻译文档。 47 | ## 捐赠社区发展 48 | 如果你觉得,Spring Cloud中国社区还可以,为了更好的发展,你可以捐赠社区,点击下面的打赏捐赠,捐赠的钱将用于社区发展和线下meeting up。 支付宝账号:Software_King@qq.com 49 | -------------------------------------------------------------------------------- /docs/about/license.md: -------------------------------------------------------------------------------- 1 | # License 2 | 3 | The legal stuff. 4 | 5 | --- 6 | 7 | ## Included projects 8 | 9 | Themes used under license from the ReadTheDocs projects. 10 | 11 | * ReadTheDocs theme - [View license](https://github.com/snide/sphinx_rtd_theme/blob/master/LICENSE). 12 | 13 | Many thanks to the authors and contributors of those wonderful projects. 14 | 15 | ## MkDocs License (BSD) 16 | 17 | Copyright © 2014, Tom Christie. All rights reserved. 18 | 19 | Redistribution and use in source and binary forms, with or without modification, 20 | are permitted provided that the following conditions are met: 21 | 22 | Redistributions of source code must retain the above copyright notice, this list 23 | of conditions and the following disclaimer. Redistributions in binary form must 24 | reproduce the above copyright notice, this list of conditions and the following 25 | disclaimer in the documentation and/or other materials provided with the 26 | distribution. 27 | 28 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 29 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 30 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 31 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 32 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 33 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 34 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 35 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 36 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 37 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 38 | -------------------------------------------------------------------------------- /docs/user-guide/config.md: -------------------------------------------------------------------------------- 1 | # Spring Cloud Config 2 | 3 | ## Quick Start 4 | 5 | #### Client Side Usage 6 | 7 | ## Spring Cloud Config Server 8 | 9 | #### Environment Repository 10 | 11 | #### Health Indicator 12 | 13 | #### Security 14 | 15 | #### Encryption and Decryption 16 | 17 | #### Key Management 18 | 19 | #### Creating a Key Store for Testing 20 | 21 | #### Using Multiple Keys and Key Rotation 22 | 23 | #### Serving Encrypted Properties 24 | 25 | ## Serving Alternative Formats 26 | 27 | ## Serving Plain Text 28 | 29 | ## Embedding the Config Server 30 | 31 | ## Push Notifications and Spring Cloud Bus 32 | 33 | 许多源代码库提供者(如GitHub,gitlab或bitbucket)会通过webhook通知您在代码库的变化。你可以通过供应商的用户界面配置你的webhook,一个URL和一系列你感兴趣的事件。比如Github会通过POST请求webhook,body中包含提交的一些信息,请求头“X-Github-Event”等于“push”。如果你添加了依赖`spring-cloud-config-monitor`并在你的Config Server中激活了Spring Cloud Bus,一个"/monitor" endpoint会被启用。 34 | 35 | 当webhook被触发,Config Server认为发生了改变,并将针对应用程序发送一个`RefreshRemoteApplicationEvent`。变化检测可以考虑,但默认情况下它只是在寻找application name匹配的文件的变化(例如“foo.properties”是针对“foo”应用,“application.properties”是针对所有应用)。该策略,如果你想重写的行为是`PropertyPathNotificationExtractor`,这个类接受请求头和请求体作为参数,返回一个路径改变的列表。 36 | 37 | 默认配置基于Github,Gitlab或Bitbucket。除了来自Github,Gitlab或Bitbucket的JSON通知,您可以触发一个更改通知,向/monitor发起POST请求,参数是`path={name}`,这将广播匹配“{name}”的应用(可以包含通配符) 38 | 39 | NOTE 40 | > 当`spring-cloud-bus`在Config Server的服务端和客户端被激活时,`RefreshRemoteApplicationEvent`才会被传播 41 | 42 | NOTE 43 | > 默认的配置也检测到本地的Git仓库的文件系统的变化(这种情况下不适用webhook,只要你编辑一个配置文件的更新就会被发送) 44 | 45 | ## Spring Cloud Config Client 46 | 47 | #### Config First Bootstrap 48 | 49 | #### Discovery First Bootstrap 50 | 51 | #### Config Client Fail Fast 52 | 53 | #### Config Client Retry 54 | 55 | #### Locating Remote Configuration Resources 56 | 57 | #### Security 58 | 59 | 60 | 61 | 62 | 63 | 64 | -------------------------------------------------------------------------------- /docs/project/SpringCloudZookeeper.md: -------------------------------------------------------------------------------- 1 | # Spring Cloud Zookeeper 2 | 3 | Spring Cloud Zookeeper提供了Zookeeper的整合,Spring Boot应用通过自动配置和绑定环境和其他spring模型风格。用一个简单的注释,你可以在你的应用中快速启用常见模式配置,并构建大型分布式系统。该模式包括服务发现和分布式配置。 4 | 5 | For full documentation visit [spring cloud zookeeper](http://cloud.spring.io/spring-cloud-zookeeper/). 6 | 7 | ## Features 8 | 9 | pring Cloud Zookeeper features: 10 | 11 | * 服务发现:可以在Zookeeper中注册实例,客户端可以发现使用Spring管理bean实例 12 | * 支持Ribbon,客户端负载均衡 13 | * 支持Zuul,动态路由和过滤器 14 | * 分布式配置:利用Zookeeper存取数据 15 | 16 | ## Quick Start 17 | 18 | 项目中使用`spring-cloud-zookeeper`推荐基于一个依赖管理系统 -- 下面的代码段可以被复制和粘贴到您的构建。需要帮助吗?看看我们基于[Maven](http://spring.io/guides/gs/maven/)和[Gradle](http://spring.io/guides/gs/gradle/)构建的入门指南。 19 | 20 | 21 | 22 | 23 | org.springframework.cloud 24 | spring-cloud-zookeeper-dependencies 25 | 1.0.1.RELEASE 26 | pom 27 | import 28 | 29 | 30 | 31 | 32 | org.springframework.cloud 33 | spring-cloud-zookeeper-discovery 34 | 35 | 36 | 37 | 只要classpath中包含Spring Cloud Zookeeper,Apache Curator和Zookeeper Java客户端 ,所有应用了 `@EnableDiscoveryClient`注解的Spring Boot应用将尝试连接Zookeeper服务`http://localhost:2181`(`zookeeper.connectString`默认值) 38 | 39 | @Configuration 40 | @EnableAutoConfiguration 41 | @EnableDiscoveryClient 42 | @RestController 43 | public class Application { 44 | 45 | @RequestMapping("/") 46 | public String home() { 47 | return "Hello World"; 48 | } 49 | 50 | public static void main(String[] args) { 51 | SpringApplication.run(Application.class, args); 52 | } 53 | 54 | } 55 | 56 | 本地Zookeeper服务必须运行,参见[Zookeeper](http://zookeeper.apache.org/doc/trunk/zookeeperStarted.html)文档。 57 | 58 | 59 | -------------------------------------------------------------------------------- /docs/project/SpringCloudBus.md: -------------------------------------------------------------------------------- 1 | # Spring Cloud Bus 2 | 3 | Spring Cloud Bus 通过一个轻量级消息代理连接分布式系统的节点。这可以用于广播状态更改(如配置更改)或其他管理指令。当前唯一的实现方式是通过一个AMQP代理作为消息传输,但相同的基本特征(传输上的一些依赖)是其他传输的路线图 4 | 5 | For full documentation visit [spring cloud bus](http://cloud.spring.io/spring-cloud-bus/). 6 | 7 | ## Quick Start 8 | 9 | 项目中使用`spring-cloud-bus`推荐基于一个依赖管理系统 -- 下面的代码段可以被复制和粘贴到您的构建。需要帮助吗?看看我们基于[Maven](http://spring.io/guides/gs/maven/)和[Gradle](http://spring.io/guides/gs/gradle/)构建的入门指南。 10 | 11 | 12 | 13 | 14 | org.springframework.cloud 15 | spring-cloud-bus-parent 16 | 1.1.1.BUILD-SNAPSHOT 17 | pom 18 | import 19 | 20 | 21 | 22 | 23 | 24 | org.springframework.cloud 25 | spring-cloud-starter-bus-amqp 26 | 27 | 28 | 29 | 30 | spring-snapshots 31 | Spring Snapshots 32 | https://repo.spring.io/libs-snapshot 33 | 34 | true 35 | 36 | 37 | 38 | 39 | 只要classpath中包含AMQP和RabbitMQ,Spring Boot应用将尝试连接RabbitMQ服务`http://localhost:5672`(`spring.rabbitmq.addresses`默认值) 40 | 41 | @Configuration 42 | @EnableAutoConfiguration 43 | @RestController 44 | public class Application { 45 | 46 | @RequestMapping("/") 47 | public String home() { 48 | return "Hello World"; 49 | } 50 | 51 | public static void main(String[] args) { 52 | SpringApplication.run(Application.class, args); 53 | } 54 | 55 | } 56 | 57 | ## Sample Projects 58 | 59 | [Bus Clients](https://github.com/spring-cloud-samples/customers-stores) 60 | 61 | 62 | -------------------------------------------------------------------------------- /docs/project/SpringCloudSecurity.md: -------------------------------------------------------------------------------- 1 | # Spring Cloud Security 2 | 3 | Spring Cloud Security提供了一组原语义,用最小的代价来创建安全的应用和服务。通过统一管理中心,将应用自己授权给大型协作系统、远程组件。他在Cloud Foundry平台中也非常易用。基于 Spring Boot 和 Spring Security OAuth2我们可以快速的实现统一登录、令牌传递、令牌交换。 4 | 5 | For full documentation visit [spring cloud security](http://cloud.spring.io/spring-cloud-security/). 6 | 7 | ## Features 8 | 9 | Spring Cloud Security features: 10 | 11 | * 在Zuul proxy中传递SSO tokens 12 | * 资源服务器之间的传递tokens 13 | * Feign客户端拦截器行为,如OAuth2RestTemplate(fetching tokens) 14 | * 在Zuul proxy配置下游认证 15 | 16 | ## Quick Start 17 | 18 | 项目中使用`spring-cloud-security`推荐基于一个依赖管理系统--下面的代码段可以被复制和粘贴到您的构建。需要帮助吗?看看我们基于[Maven](http://spring.io/guides/gs/maven/)和[Gradle](http://spring.io/guides/gs/gradle/)构建的入门指南。 19 | 20 | ``` 21 | 22 | 23 | org.springframework.cloud 24 | spring-cloud-security 25 | 1.1.4.BUILD-SNAPSHOT 26 | 27 | 28 | 29 | spring-snapshots 30 | Spring Snapshots 31 | https://repo.spring.io/libs-snapshot 32 | 33 | true 34 | 35 | 36 | 37 | ``` 38 | 39 | 如果你的应用启动了 Spring Cloud Zuul 反向代理(使用了@EnableZuulProxy注解),然后你就可以向下转发OAuth2访问令牌到Zuul代理的服务中.因此,在单点登录增强就像下面这样简单 40 | 41 | ``` 42 | @SpringBootApplication 43 | @EnableOAuth2Sso 44 | @EnableZuulProxy 45 | class Application { 46 | 47 | } 48 | ``` 49 | 50 | 并且他将(除了登录用户和抓取令牌)批准认证令牌下游到` /proxy/*` services,如果这些服务执行了`@EnableResourceServer`注解他们就会在标准头中得到一个有效的令牌 51 | 52 | 53 | ## Sample Projects 54 | 55 | - [SSO](https://github.com/spring-cloud-samples/sso) 56 | - [Auth Server](https://github.com/spring-cloud-samples/authserver) 57 | - [SSO Groovy](https://github.com/spring-cloud-samples/scripts/blob/master/demo/sso.groovy) 58 | - [Resource server](https://github.com/spring-cloud-samples/scripts/blob/master/demo/resource.groovy) 59 | 60 | -------------------------------------------------------------------------------- /mkdocs.yml: -------------------------------------------------------------------------------- 1 | site_name: Spring Cloud中国社区 2 | site_url: http://docs.springcloud.cn 3 | site_description: Spring Cloud中国社区文档,Spring Cloud中国社区官网,Spring Cloud中国社区,致力于为Spring Boot或Spring Cloud技术人员提供分享和交流的平台! www.springcloud.cn,springcloud.cn,spring coud中文 4 | site_author: 许进 5 | repo_url: https://github.com/springcloud 6 | copyright: Copyright © 2016-2020 许进博客,Spring Cloud中国社区 7 | 8 | theme_dir: mkdocs_bootswatch/flatly 9 | 10 | pages: 11 | - 首页: index.md 12 | 13 | - project: 14 | - Quick Start: project/QuickStart.md 15 | - Spring Cloud Config: project/SpringCloudConfig.md 16 | - Spring Cloud Netflix: project/SpringCloudNetflix.md 17 | - Spring Cloud Bus: project/SpringCloudBus.md 18 | - Spring Cloud for Cloud Foundry: project/SpringCloudforCloudFoundry.md 19 | - Spring Cloud Cloud Foundry Service Broker: project/SpringCloudforCloudFoundry.md 20 | - Spring Cloud Cloud Foundry Service Broker: project/SpringCloudCloudFoundryServiceBroker.md 21 | - Spring Cloud Consul: project/SpringCloudConsul.md 22 | - Spring Cloud Security: project/SpringCloudSecurity.md 23 | - Spring Cloud Sleuth: project/SpringCloudSleuth.md 24 | - Spring Cloud Data Flow: project/SpringCloudDataFlow.md 25 | - Spring Cloud Stream: project/SpringCloudStream.md 26 | - Spring Cloud Stream Modules: project/SpringCloudStreamModules.md 27 | - Spring Cloud Task: project/SpringCloudTask.md 28 | - Spring Cloud Zookeeper: project/SpringCloudZookeeper.md 29 | - Spring Cloud for Amazon Web Services: project/SpringCloudforAmazonWebServices.md 30 | - Spring Cloud Connectors: project/SpringCloudConnectors.md 31 | - Spring Cloud CLI: project/SpringCloudCLI.md 32 | - Spring Cloud翻译文档: 33 | - Spring Cloud Eureka: user-guide/eureka.md 34 | - 声明式REST客户端Feign: user-guide/feign.md 35 | - Spring Cloud Bus: user-guide/bus.md 36 | - Spring Cloud Config: user-guide/config.md 37 | - Spring Cloud sleuth: user-guide/sleuth.md 38 | - Spring Cloud stream: user-guide/stream.md 39 | - Spring Cloud zuul: user-guide/zuul.md 40 | - Spring Cloud ribbon: user-guide/ribbon.md 41 | - 源码分析: source.md 42 | 43 | markdown_extensions: 44 | - toc: 45 | permalink: '#' 46 | 47 | -------------------------------------------------------------------------------- /docs/project/SpringCloudConsul.md: -------------------------------------------------------------------------------- 1 | # Spring Cloud Consul 2 | 3 | Spring Cloud Consul提供了Consul的整合,Spring Boot应用通过自动配置和绑定环境和其他spring模型风格。用一个简单的注释,你可以在你的应用中快速启用常见模式配置,并构建大型分布式系统,这些组件是经过Netflix公司生产环境考验的。该模式包括服务发现,分布式配置和控制总线。 4 | 5 | For full documentation visit [spring cloud consul](http://cloud.spring.io/spring-cloud-consul/). 6 | 7 | ## Features 8 | 9 | Spring Cloud Consul features: 10 | 11 | * 服务发现:实例可以用Consul代理端注册,客户端可以发现使用Spring管理bean实例。 12 | * 支持Ribbon,利用Spring Cloud Netflix实现客户端负载均衡。 13 | * 支持Zuul,利用Spring Cloud Netflix实现动态路由和过滤。 14 | * 分布式配置:利用Consul的Key/Value存储。 15 | * 控制总线:使用Consul事件处理分布式控制事件 16 | 17 | ## Quick Start 18 | 19 | 项目中使用`spring-cloud-consul`推荐基于一个依赖管理系统 -- 下面的代码段可以被复制和粘贴到您的构建。需要帮助吗?看看我们基于[Maven](http://spring.io/guides/gs/maven/)和[Gradle](http://spring.io/guides/gs/gradle/)构建的入门指南。 20 | 21 | 22 | 23 | org.springframework.cloud 24 | spring-cloud-starter-consul-all 25 | 26 | 27 | 28 | 29 | 30 | 31 | org.springframework.cloud 32 | spring-cloud-consul-dependencies 33 | 1.0.1.RELEASE 34 | pom 35 | import 36 | 37 | 38 | 39 | 40 | 只要classpath中包含 Spring Cloud Consul和Consul API,所有应用了 `@EnableDiscoveryClient`注解的Spring Boot应用将尝试连接Consul的代理服务`http://localhost:8500`(`spring.cloud.consul.host` and `spring.cloud.consul.port`默认值) 41 | 42 | @Configuration 43 | @EnableAutoConfiguration 44 | @EnableDiscoveryClient 45 | @RestController 46 | public class Application { 47 | 48 | @RequestMapping("/") 49 | public String home() { 50 | return "Hello World"; 51 | } 52 | 53 | public static void main(String[] args) { 54 | SpringApplication.run(Application.class, args); 55 | } 56 | 57 | } 58 | 59 | 本地Consul代理的运行. 参见[Consul agent documentation](https://consul.io/docs/agent/basics.html). 60 | 61 | ## Sample Projects 62 | 63 | [Consul Sample](https://github.com/spring-cloud/spring-cloud-consul/tree/master/spring-cloud-consul-sample) 64 | 65 | -------------------------------------------------------------------------------- /docs/project/SpringCloudNetflix.md: -------------------------------------------------------------------------------- 1 | # Spring Cloud Netflix 2 | 3 | Spring Cloud Netflix提供了Netflix公司的开源软件(OSS)的整合,Spring Boot应用通过自动配置和绑定环境和其他spring模型风格。用一个简单的注释,你可以在你的应用中快速启用常见模式配置,并构建大型分布式系统,这些组件是经过Netflix公司生产环境考验的。该模式包括服务发现(Eureka)、断路器(Hystrix),智能路由(Zuul)和客户端负载均衡(Ribbon).. 4 | 5 | For full documentation visit [spring cloud netflix](http://cloud.spring.io/spring-cloud-netflix/). 6 | 7 | ## Features 8 | 9 | Spring Cloud Netflix features: 10 | 11 | * 服务发现:可以在Eureka中注册实例,客户端可以发现使用Spring管理bean实例 12 | * 服务发现:嵌入式Eureka服务可以通过声明java配置来创建 13 | * 断路器:Hystrix客户端可以通过方法上的注解来创建 14 | * 断路器:嵌入Hystrix仪表盘通过声明java配置 15 | * 声明REST客户端:伪装创建一个动态接口装饰,使用JAX-RS或Spring MVC注解 16 | * 客户端负载均衡:Ribbon 17 | * 外部配置:Spring Environment和Archaius(配置管理API)搭建起一座桥梁。(使Netflix组件的本地配置能够使用Spring Boot习俗) 18 | * 路由器和过滤器:自动注册Zuul的过滤器,和一个简单配置约定创建反向代理 19 | 20 | ## Quick Start 21 | 22 | 项目中使用`spring-cloud-netflix`推荐基于一个依赖管理系统 -- 下面的代码段可以被复制和粘贴到您的构建。需要帮助吗?看看我们基于[Maven](http://spring.io/guides/gs/maven/)和[Gradle](http://spring.io/guides/gs/gradle/)构建的入门指南。 23 | 24 | 25 | 26 | 27 | org.springframework.cloud 28 | spring-cloud-netflix 29 | 1.1.2.RELEASE 30 | pom 31 | import 32 | 33 | 34 | 35 | 36 | 37 | org.springframework.cloud 38 | spring-cloud-starter-eureka 39 | 40 | 41 | 42 | 只要classpath中包含Spring Cloud Netflix 和 Eureka Core,所有应用了 `@EnableEurekaClient`注解的Spring Boot应用将尝试连接Eureka服务`http://localhost:8761`(`eureka.client.serviceUrl.defaultZone`默认值) 43 | 44 | @Configuration 45 | @EnableAutoConfiguration 46 | @EnableEurekaClient 47 | @RestController 48 | public class Application { 49 | 50 | @RequestMapping("/") 51 | public String home() { 52 | return "Hello World"; 53 | } 54 | 55 | public static void main(String[] args) { 56 | SpringApplication.run(Application.class, args); 57 | } 58 | 59 | } 60 | 61 | 要运行你自己的服务,需要使用`spring-cloud-starter-eureka-server`依赖和`@EnableEurekaServer`注解。 62 | 63 | ## Sample Projects 64 | 65 | [Eureka Server](https://github.com/spring-cloud-samples/eureka) 66 | 67 | [Eureka Clients](https://github.com/spring-cloud-samples/customers-stores) 68 | 69 | 70 | 71 | 72 | -------------------------------------------------------------------------------- /docs/project/SpringCloudConfig.md: -------------------------------------------------------------------------------- 1 | # Spring Cloud Config 2 | 3 | Spring Cloud Config在分布式系统中为外部配置提供服务端和客户端支持。通过Config Server你可以集中管理应用程序的外部配置文件。客户端和服务端的键值对概念与`Spring Environment`和`PropertySource` 相同,所以十分适合Spring应用,另一方面可以适用于任何语言的应用程序。作为一个应用程序将通过部署管道从开发到测试到生产,你可以管理这些环境的配置,可以确定应用都需要运行时迁移。服务器的后端存储的默认实现使用Git,所以容易支持标记版本的配置环境,以及一系列管理工具访问内容。它很容易添加替代的实现,并将它们插入到Spring配置中。 4 | 5 | For full documentation visit [spring cloud config](http://cloud.spring.io/spring-cloud-config/). 6 | 7 | ## Features 8 | 9 | Spring Cloud Config Server features: 10 | 11 | * HTTP API的外部资源配置(名称-值对,或等效的YAML内容) 12 | * 对属性值(对称或非对称)进行加密和解密 13 | * 使用`@EnableConfigServer`注解嵌入Spring Boot应用 14 | 15 | Config Client features (for Spring applications): 16 | 17 | * 绑定到配置服务器,并使用远程属性源初始化Spring环境 18 | * 对属性值(对称或非对称)进行加密和解密 19 | 20 | ## Quick Start 21 | 22 | 项目中使用`spring-cloud-config`推荐基于一个依赖管理系统--下面的代码段可以被复制和粘贴到您的构建。需要帮助吗?看看我们基于[Maven](http://spring.io/guides/gs/maven/)和[Gradle](http://spring.io/guides/gs/gradle/)构建的入门指南。 23 | 24 | 25 | 26 | 27 | org.springframework.cloud 28 | spring-cloud-config 29 | 1.1.1.RELEASE 30 | pom 31 | import 32 | 33 | 34 | 35 | 36 | 37 | org.springframework.cloud 38 | spring-cloud-starter-config 39 | 40 | 41 | 42 | 只要classpath中包含Spring Boot Actuator和Spring Config Client,Spring Boot应用将尝试连接配置服务`http://localhost:8888`(`spring.cloud.config.uri`默认值) 43 | 44 | @Configuration 45 | @EnableAutoConfiguration 46 | @RestController 47 | public class Application { 48 | 49 | @Value("${config.name}") 50 | String name = "World"; 51 | 52 | @RequestMapping("/") 53 | public String home() { 54 | return "Hello " + name; 55 | } 56 | 57 | public static void main(String[] args) { 58 | SpringApplication.run(Application.class, args); 59 | } 60 | 61 | } 62 | 63 | 范例中`config.name`的值(或任何其他值)可以来自本地配置或从远程配置服务器。配置服务器将优先默认。在应用程序中看`/env`端点,看`configServer`资源文件。 64 | 65 | 要想运行你的服务,需要依赖`spring-cloud-config-server`并且使用`@EnableConfigServer`注解。如果设置`spring.config.name=configserver`,应用将在8888端口启动,数据来自样本库。你需要`spring.cloud.config.server.git.uri`为您自己的需求找到配置数据(默认情况下它是一个Git仓库,并且可以是一个本地文件路径 `file:..`) 66 | 67 | ## Sample Projects 68 | 69 | [Config Server](https://github.com/spring-cloud-samples/configserver) 70 | 71 | [Config Clients](https://github.com/spring-cloud-samples/customers-stores) 72 | 73 | 74 | 75 | -------------------------------------------------------------------------------- /docs/about/contributing.md: -------------------------------------------------------------------------------- 1 | # Contributing to MkDocs 2 | 3 | An introduction to contributing to the MkDocs project. 4 | 5 | The MkDocs project welcomes, and depends, on contributions from developers and 6 | users in the open source community. Contributions can be made in a number of 7 | ways, a few examples are: 8 | 9 | - Code patches via pull requests 10 | - Documentation improvements 11 | - Bug reports and patch reviews 12 | 13 | ## Code of Conduct 14 | 15 | Everyone interacting in the MkDocs project's codebases, issue trackers, chat 16 | rooms, and mailing lists is expected to follow the [PyPA Code of Conduct]. 17 | 18 | ## Reporting an Issue 19 | 20 | Please include as much detail as you can. Let us know your platform and MkDocs 21 | version. If the problem is visual (for example a theme or design issue) please 22 | add a screenshot and if you get an error please include the full error and 23 | traceback. 24 | 25 | ## Testing the Development Version 26 | 27 | If you want to just install and try out the latest development version of 28 | MkDocs you can do so with the following command. This can be useful if you 29 | want to provide feedback for a new feature or want to confirm if a bug you 30 | have encountered is fixed in the git master. It is **strongly** recommended 31 | that you do this within a [virtualenv]. 32 | 33 | ```bash 34 | pip install https://github.com/mkdocs/mkdocs/archive/master.tar.gz 35 | ``` 36 | 37 | ## Installing for Development 38 | 39 | First you'll need to fork and clone the repository. Once you have a local 40 | copy, run the following command. It is **strongly** recommended that you do 41 | this within a [virtualenv]. 42 | 43 | ```bash 44 | pip install --editable . 45 | ``` 46 | 47 | This will install MkDocs in development mode which binds the `mkdocs` command 48 | to the git repository. 49 | 50 | ## Running the tests 51 | 52 | To run the tests, it is recommended that you use [Tox]. This just needs 53 | to be pip installed and then the test suite can be ran for MkDocs but running 54 | the command `tox` in the root of your MkDocs repository. 55 | 56 | It will attempt to run the tests against all of the Python versions we 57 | support. So don't be concerned if you are missing some and they fail. The rest 58 | will be verified by [Travis] when you submit a pull request. 59 | 60 | ## Submitting Pull Requests 61 | 62 | Once you are happy with your changes or you are ready for some feedback, push 63 | it to your fork and send a pull request. For a change to be accepted it will 64 | most likely need to have tests and documentation if it is a new feature. 65 | 66 | [virtualenv]: https://virtualenv.pypa.io/en/latest/userguide.html 67 | [tox]: https://tox.readthedocs.io/en/latest/ 68 | [travis]: https://travis-ci.org/repositories 69 | [PyPA Code of Conduct]: https://www.pypa.io/en/latest/code-of-conduct/ 70 | -------------------------------------------------------------------------------- /docs/project/SpringCloudStream.md: -------------------------------------------------------------------------------- 1 | # Spring Cloud Stream 2 | 3 | Spring Cloud Stream是一个构建消息驱动的微服务框架。Spring Cloud Stream构建在Spring Boot之上用以创建DevOps友好的微服务,并且Spring Integration提供了和消息代理的连接。Spring Cloud Stream提供消息代理的自用配置,引入发布订阅的语义概念,引入不同的中间件厂商通用的的消费组和分区,这些自用配置提供了创建流处理应用的基础。 4 | 5 | 添加@EnableBinding注解在你的程序中,被@StreamListener修饰的方法可以立即连接到消息代理,你将收到流处理事件。 6 | 7 | For full documentation visit [spring cloud stream](http://cloud.spring.io/spring-cloud-stream/). 8 | 9 | ## Quick Start 10 | 11 | 项目中使用`spring-cloud-stream`推荐基于一个依赖管理系统 -- 下面的代码段可以被复制和粘贴到您的构建。需要帮助吗?看看我们基于[Maven](http://spring.io/guides/gs/maven/)和[Gradle](http://spring.io/guides/gs/gradle/)构建的入门指南。 12 | 13 | 14 | 15 | 16 | org.springframework.cloud 17 | spring-cloud-stream-dependencies 18 | 1.0.2.RELEASE 19 | pom 20 | import 21 | 22 | 23 | 24 | 25 | 26 | org.springframework.cloud 27 | spring-cloud-stream 28 | 29 | 30 | org.springframework.cloud 31 | spring-cloud-starter-stream-kafka 32 | 33 | 34 | 35 | 只要classpath中包含 Spring Cloud Stream和Spring Cloud Stream binder,并且被@EnableBinding修饰,应用将通过总线绑定一个外部代理(Rabbit MQ或Kafka,取决于你的选择)。示例应用: 36 | 37 | @SpringBootApplication 38 | @EnableBinding(Source.class) 39 | public class StreamdemoApplication { 40 | 41 | public static void main(String[] args) { 42 | SpringApplication.run(StreamdemoApplication.class, args); 43 | } 44 | 45 | @Bean 46 | @InboundChannelAdapter(value = Source.OUTPUT) 47 | public MessageSource timerMessageSource() { 48 | return () -> new GenericMessage<>(new SimpleDateFormat().format(new Date())); 49 | } 50 | 51 | } 52 | 53 | 确定应用运行的时候Kafka同时运行,你可以看`kafka-console-consumer.sh`kafka提供的实用工具,用来监控消息发送。 54 | 55 | ## Sample Projects 56 | 57 | [Source](https://github.com/spring-cloud/spring-cloud-stream-samples/tree/master/source) 58 | 59 | [Sink](https://github.com/spring-cloud/spring-cloud-stream-samples/tree/master/sink) 60 | 61 | [Transformer](https://github.com/spring-cloud/spring-cloud-stream-samples/tree/master/transform) 62 | 63 | [Multi-binder](https://github.com/spring-cloud/spring-cloud-stream-samples/tree/master/multibinder) 64 | 65 | [RxJava Processor](https://github.com/spring-cloud/spring-cloud-stream-samples/tree/master/rxjava-processor) 66 | 67 | ## Related Projects 68 | 69 | [Spring Cloud Stream Applications](http://cloud.spring.io/spring-cloud-stream-app-starters/) 70 | 71 | [Spring Cloud Data Flow](http://cloud.spring.io/spring-cloud-dataflow/) 72 | 73 | [Spring XD](https://projects.spring.io/spring-xd/) 74 | 75 | -------------------------------------------------------------------------------- /docs/project/SpringCloudSleuth.md: -------------------------------------------------------------------------------- 1 | # Spring Cloud Sleuth 2 | 3 | Spring Cloud Sleuth为Spring Cloud提供了分布式追踪方案,借用了Dapper,Zipkin和HTrace。对于大多数用户来说Sleuth应该是看不见的,与外部系统的相互作用是自动的。您可以简单地在日志中捕获数据,或将数据发送到远程收集服务。 4 | 5 | For full documentation visit [spring cloud Sleuth](http://cloud.spring.io/spring-cloud-sleuth/). 6 | 7 | ## Features 8 | 9 | Span是一个基本单位,例如,发送一个RPC是一个新的Span。Span是由一个64位的SpanID和一个64位的traceID组成,Span也有其他数据,如描述,键值注释,SpanID,processID(通常是IP地址)。Span有开始和停止,并且跟踪他们的时间信息。一旦你创建一个Span,你必须在未来的某一点停止它。一组Span形成一个树状结构称为一个跟踪,例如,如果运行一个分布式大数据存储,则可能由一个放请求形成一个跟踪。 10 | 11 | Spring Cloud Sleuth features: 12 | 13 | * 在Slf4J的MDC中添加traceId和spanId,所以在日志汇总处你可以提取trace或span信息。 14 | * 提供了一个抽象数据模型:traces, spans (forming a DAG), annotations, key-value annotations。轻易的基于HTrace, 和Zipkin (Dapper)兼容。 15 | * Spring应用通用的入口和出口工具(servlet filter, rest template, scheduled actions, message channels, zuul filters, feign client). 16 | * 如果激活`spring-cloud-sleuth-zipkin`,应用程序将生成并通过HTTP收集兼容Zipkin的traces。默认情况下发送到本地的Zipkin,可以通过`spring.zipkin.[host,port]`去配置正确的地址。 17 | 18 | ## Quick Start 19 | 20 | 项目中使用`spring-cloud-sleuth`推荐基于一个依赖管理系统--下面的代码段可以被复制和粘贴到您的构建。需要帮助吗?看看我们基于[Maven](http://spring.io/guides/gs/maven/)和[Gradle](http://spring.io/guides/gs/gradle/)构建的入门指南。 21 | 22 | 23 | 24 | 25 | org.springframework.cloud 26 | spring-cloud-sleuth 27 | 1.1.0.BUILD-SNAPSHOT 28 | pom 29 | import 30 | 31 | 32 | 33 | 34 | 35 | org.springframework.cloud 36 | spring-cloud-starter-sleuth 37 | 38 | 39 | 40 | spring-snapshots 41 | Spring Snapshots 42 | https://repo.spring.io/libs-snapshot 43 | 44 | true 45 | 46 | 47 | 48 | 49 | 只要classpath中包含Spring Cloud Sleuth,Spring Boot应用将产生trace数据。 50 | 51 | @SpringBootApplication 52 | @RestController 53 | public class Application { 54 | 55 | private static Logger log = LoggerFactory.getLogger(DemoController.class); 56 | 57 | @RequestMapping("/") 58 | public String home() { 59 | log.info("Handling home"); 60 | return "Hello World"; 61 | } 62 | 63 | public static void main(String[] args) { 64 | SpringApplication.run(Application.class, args); 65 | } 66 | 67 | } 68 | 69 | 运行这个程序并进入主页,你将会看到日志中的traceId和spanId,如果这个程序调用了另一个(例如RestTemplate)它将在headers中发送跟踪数据,如果接收器是一个Sleuth应用你会持续看到trace。 70 | 71 | > NOTE: instead of logging the request in the handler explicitly, you could set `logging.level.org.springframework.web.servlet.DispatcherServlet=DEBUG` 72 | 73 | > NOTE: Set `spring.application.name=bar` (for instance) to see the service name as well as the trace and span ids. 74 | 75 | ## Sample Projects 76 | 77 | [Simple HTTP app](https://github.com/spring-cloud-samples/tests/tree/master/sleuth)that calls back to itself 78 | 79 | [Using Zipkin](https://github.com/spring-cloud/spring-cloud-sleuth/tree/master/spring-cloud-sleuth-samples/spring-cloud-sleuth-sample-zipkin) to collect traces 80 | 81 | [Messaging with Spring Integration](https://github.com/spring-cloud/spring-cloud-sleuth/tree/master/spring-cloud-sleuth-samples/spring-cloud-sleuth-sample-messaging) 82 | 83 | 84 | 85 | 86 | -------------------------------------------------------------------------------- /docs/user-guide/bus.md: -------------------------------------------------------------------------------- 1 | # Spring Cloud Bus 2 | 3 | Spring Cloud Bus 通过一个轻量级消息代理连接分布式系统的节点。这可以用于广播状态更改(如配置更改)或其他管理指令。当前唯一的实现方式是通过一个AMQP代理作为消息传输,但相同的基本特征(传输上的一些依赖)是其他传输的路线图 4 | 5 | ## Quick Start 6 | 7 | 如果Spring Cloud Bus在类路径里它将通过Spring Boot autconfiguration启动。所有你需要做的就是使`spring-cloud-starter-bus-amqp`或`spring-cloud-starter-bus-kafka`添加到你的依赖管理中,Spring Cloud将完成剩下的事。确定broker (RabbitMQ or Kafka) 可用:如果在本地运行你不需要做任何事,但如果在远程运行需要配置broker信息,如Rabbit 8 | 9 | application.yml 10 | 11 | spring: 12 | rabbitmq: 13 | host: mybroker.com 14 | port: 5672 15 | username: user 16 | password: secret 17 | 18 | bus目前支持向所有的监听节点发送消息,或向所有特定服务节点(注册到Eureka中的)发送消息。更多的选择标准可能在未来增加 (ie. only service X nodes in data center Y, etc…​)。在`/bus/*`命名空间下有一些http的endpoints,目前有两个实现,第一个`/bus/env`,发送键/值对来更新每个节点Spring Environment,第二个`/bus/refresh`,重载每个应用程序的配置,就好像他们都被发现通过 `/refresh` endpoint。 19 | 20 | NOTE 21 | > Bus的starters含盖Rabbit和Kafka,因为这两个比较常见,另一方面Spring Cloud Stream十分灵活,binder将结合spring-cloud-bus进行工作。 22 | 23 | 24 | ## Addressing an Instance 25 | 26 | HTTP endpoints 接受`"destination"`参数,如:`"/bus/refresh?destination=customers:9000"`,`"destination"`参数是`ApplicationContext`的ID,如果一个Bus实例拥有一个ID,然后它将处理消息,并且所有其他实例将忽略它。Spring Boot在`ContextIdApplicationContextInitializer`设置这个ID,ID的组成默认是由`spring.application.name`, active profiles , `server.port` 27 | 28 | ## Addressing all instances of a service 29 | 30 | destination参数采用Spring PathMatcher(分隔符`:`)确认某个实例是否将处理消息,使用上面的例子"/bus/refresh?destination=customers:**" 将对象的所有实例的“customers”服务的配置和端口设置为ApplicationContext的ID 31 | 32 | ## Application Context ID must be unique 33 | 34 | bus 试图消除处理一个事件两次,一次从原来的applicationevent消除,一次从队列消除。要做到这一点,它检查发送应中的用程序上下文ID和当前应用程序上下文ID,如果多个服务实例具有相同的应用程序上下文ID,事件将不被处理。在本地机器上运行,每个服务将在一个不同的端口,这将是应用程序上下文ID的一部分。云计算提供了一个索引来区分。Cloud Foundry提供了一个索引来区分。确保应用程序上下文ID是唯一的,对每一个服务实例设置`spring.application.index`唯一。例如,在框架配置application.properties(或bootstrap.properties如果使用configserver)中设置`spring.application.index=${INSTANCE_INDEX} ` 35 | 36 | ## Customizing the Message Broker 37 | 38 | Spring Cloud Bus 通过 Spring Cloud Stream 广播消息从而获得信息的流动,你只需要在类路径中选择你绑定的实现。bus有方便的starters,AMQP (RabbitMQ) 和 Kafka (spring-cloud-starter-bus-[amqp,kafka])。一般来说,Spring Cloud Stream依靠Spring Boot autoconfiguration规则配置中间件,所以例如AMQP代理地址是可以通过`spring.rabbitmq.*`属性配置改变的。Spring Cloud Bus有少数本地配置`spring.cloud.bus.*` (例如 `spring.cloud.bus.destination`是使用的体中间件的主题的名称)。通常情况下,默认值就足够了。 39 | 40 | 41 | ## Tracing Bus Events 42 | 43 | Bus events(RemoteApplicationEvent的子类)可以通过设置` spring.cloud.bus.trace.enabled=true`追踪,如果你这样做的话,Spring Boot TraceRepository(如果存在)将显示每个事件发送和每个服务实例所有的acks。例如(/trace endpoint): 44 | 45 | { 46 | "timestamp": "2015-11-26T10:24:44.411+0000", 47 | "info": { 48 | "signal": "spring.cloud.bus.ack", 49 | "type": "RefreshRemoteApplicationEvent", 50 | "id": "c4d374b7-58ea-4928-a312-31984def293b", 51 | "origin": "stores:8081", 52 | "destination": "*:**" 53 | } 54 | }, 55 | { 56 | "timestamp": "2015-11-26T10:24:41.864+0000", 57 | "info": { 58 | "signal": "spring.cloud.bus.sent", 59 | "type": "RefreshRemoteApplicationEvent", 60 | "id": "c4d374b7-58ea-4928-a312-31984def293b", 61 | "origin": "customers:9000", 62 | "destination": "*:**" 63 | } 64 | }, 65 | { 66 | "timestamp": "2015-11-26T10:24:41.862+0000", 67 | "info": { 68 | "signal": "spring.cloud.bus.ack", 69 | "type": "RefreshRemoteApplicationEvent", 70 | "id": "c4d374b7-58ea-4928-a312-31984def293b", 71 | "origin": "customers:9000", 72 | "destination": "*:**" 73 | } 74 | } 75 | 76 | 这个trace显示了来自`customers:9000`的`RefreshRemoteApplicationEvent`,广播到所有的服务,通过`customers:9000`和`stores:8081`收到(acked) 77 | 78 | 处理自己的ACK信号你可以为AckRemoteApplicationEvent添加@EventListener,在添加SentApplicationEvent类型,或者你可以进入TraceRepository,从那里开采数据。 79 | 80 | NOTE 81 | > 所有Bus应用都可以追踪acks,在做复杂查询的数据中央服务中这么做是有用的,或将其转发到一个专门的跟踪服务。 82 | 83 | 84 | ## Broadcasting Your Own Events 85 | 86 | Bus可以支持任何RemoteApplicationEvent的事件类型,但默认传输JSON和反序列化器需要提前知道哪些类型将被使用。定义一个新类型需要在org.springframework.cloud.bus.event的子目录下,可以使用@JsonTypeName注解在你的定制类上或依赖于默认的策略,使用类的简单的名字。请注意,生产者和消费者都需要访问类定义。 87 | 88 | 89 | 90 | 91 | -------------------------------------------------------------------------------- /docs/user-guide/ribbon.md: -------------------------------------------------------------------------------- 1 | #客户端负载均衡Ribbon 2 | 3 | Ribbon是一个客户端负载均衡器,能够给HTTP和TCP客户端带来灵活的控制。 Feign已经使用了Ribbon,因此如果你正在使用@FeignClient,那么本部分的说明同样试用。 4 | 5 | Ribbon的核心概念是命名的客户端。每一个负载均衡器都是一系列工作在一起的组件的一部分,并用于按需联系远程服务。你可以给这一系列一个名字(例如使用@FeignClient注解)。Spring Cloud使用RibbonClientConfiguration为每一个命名的客户端建立一个新系列为满足ApplicationContext的需求。 这包括一个ILoadBalancer, 一个RestClient和一个ServerListFilter。 6 | 7 | ##怎么引入Ribbon 8 | 为了引入Ribbon到你的工程,可以使用org.springframework.cloud组的starter.artifact id是spring-cloud-starter-ribbon。可以参照Spring Cloud Project的细节来设置你的构建系统。 9 | 10 | 11 | ##定制化Ribbon Client 12 | 你可以使用外部的属性`.ribbon.*`来配置一些Ribbon Client,除了能够使用Sprint Boot的配置文件以外,它和使用原生的Netflix APIS没什么不同。原生选项可以在CommonClientConfigKey中被检查到。 13 | 14 | 通过使用@RibbonClient声明额外的配置(在RibbonClientConfiguration上面),Spring Cloud也让你全面的控制Client。 例如: 15 | 16 | @Configuration 17 | @RibbonClient(name = "foo", configuration = FooConfiguration.class) 18 | public class TestConfiguration { 19 | } 20 | 21 | 这个例子中,Client除了包括了已经存在于RibbonClientConfiguration的组件,也包括了自定义的FooConfiguration(一般后者会重载前者)。 22 | 23 | > 24 | 警告:FooConfiguration 不能被@ComponentScan 在main application context。这样的话,它将被所有@RibbonClients共享。如果你使用 @ComponentScan (or @SpringBootApplication) ,你需要避免它被包括其中。(例如:放它到一个独立的,无重叠的包里,或者指明不被@ComponentScan扫描)。 25 | 26 | Spring Cloud Netflix为ribbon提供了如下的Beans(BeanType beanName: ClassName): 27 | 28 | 29 | - IClientConfig ribbonClientConfig: DefaultClientConfigImpl 30 | - IRule ribbonRule: ZoneAvoidanceRule 31 | - IPing ribbonPing: NoOpPing 32 | - ServerList ribbonServerList: ConfigurationBasedServerList 33 | - ServerListFilter ribbonServerListFilter: ZonePreferenceServerListFilter 34 | - ILoadBalancer ribbonLoadBalancer: ZoneAwareLoadBalancer 35 | 36 | 建立一个如上类型的bean,放置到@RibbonClient配置(如上FooConfiguration),允许你重载其中的任意一个。例如: 37 | 38 | @Configuration 39 | public class FooConfiguration { 40 | @Bean 41 | public IPing ribbonPing(IClientConfig config) { 42 | return new PingUrl(); 43 | } 44 | } 45 | 46 | 如上将用PingUrl代替NoOpPing。 47 | 48 | ##使用properties定制化Ribbon Client 49 | 从1.2.0开始,Spring Cloud Netflix支持使用properties来定制化Ribbon clients。 50 | 这就允许你在不同的环境,在启动时改变举止。 51 | 52 | 支持的属性如下(加上.ribbon.的前缀): 53 | 54 | - NFLoadBalancerClassName: 实现ILoadBalancer 55 | - NFLoadBalancerRuleClassName: 实现IRule 56 | - NFLoadBalancerPingClassName: 实现IPing 57 | - NIWSServerListClassName: 实现ServerList 58 | - NIWSServerListFilterClassName: 实现ServerListFilter 59 | > 60 | > 在这些属性中定义的Classes优先于在@RibbonClient(configuration=MyRibbonConfig.class)定义的beans和由Spring Cloud Netflix提供的缺省值。 61 | 62 | 例如,为一个叫user的服务设置IRule,可以进行如下设置: 63 | 64 | users: 65 | ribbon: 66 | NFLoadBalancerRuleClassName: com.netflix.loadbalancer.WeightedResponseTimeRule 67 | 68 | 69 | ##一起使用Ribbon和Eureka 70 | 当Eureka被和Ribbon一起联合使用时, ribbonServerList被一个叫做DiscoveryEnabledNIWSServerList的扩展重载。这个扩展汇聚了来自于Eureka的服务列表。 71 | IPing的接口也被NIWSDiscoveryPing代替,用于委托Eureka来测定服务是否UP。 缺省的ServerListThe是一个DomainExtractingServerList,目的是使得物理上的元数据可以用于负载均衡器,而不必要使用AWA AMI的元数据。 缺省情况下,服务List将根据“zone”信息被创建。(远程客户端设置eureka.instance.metadataMap.zone)。如果这个没有设置,它可以使用d来自于服务hostname的domain name作为zone的代理(取决于approximateZoneFromHostname是否被设置)。一旦那个zone的信息可获得,他可以在ServerListFilter被使用。缺省情况下,由于使用ZonePreferenceServerListFilter,它被用于定位一个和Client相同zone的server。 默认情况下,client的zone是和远程实例一样的,通过eureka.instance.metadataMap.zone来设置。 72 | 73 | >注意:正统的"archaius"方式是通过配置属性"@zone"来设置Clinet zone。如果它是有效的,Spring Cloud使用这个优先于其他设置。(注意,这个key必须在YAML configuration被引)。 74 | 75 | >如果zone数据没有其他来源,基于Client的配置将会有一个猜测。(as opposed to the instance configuration).我们称为eureka.client.availabilityZones。它是一个从region名到zones列表的map,并且抽出第一个zone 作为实例自己的region(例如the eureka.client.region) 76 | 77 | ##Example: 没有Eureka,如何使用Ribbon 78 | Eureka是一个实用的方式,它抽象了远程服务的发现机制,可以使你不用在Clinet中硬编码URLS。但如果你不打算使用它,Ribbon和Feign仍然是相当可用的。假设你已经声明了一个@RibbonClient为一个“Stores"的服务。Eureka没有被使用。Ribbon Client会缺省到一个已配置的Server列表。你可以提供配置像: 79 | 80 | stores: 81 | ribbon: 82 | listOfServers: example.com,google.com 83 | 84 | 85 | #Example: 在Ribbon停止Eureka可用 86 | 设置`ribbon.eureka.enabled = false`,可以在Ribbon中停止对Eureka的使用 87 | 88 | ribbon: 89 | eureka: 90 | enabled: false 91 | 92 | ##直接使用Ribbon API 93 | 可以直接使用LoadBalancerClient。例如: 94 | 95 | public class MyClass { 96 | @Autowired 97 | private LoadBalancerClient loadBalancer; 98 | 99 | public void doStuff() { 100 | ServiceInstance instance = loadBalancer.choose("stores"); 101 | URI storesUri = URI.create(String.format("http://%s:%s", instance.getHost(), instance.getPort())); 102 | // ... do something with the URI 103 | } 104 | } 105 | 106 | -------------------------------------------------------------------------------- /docs/user-guide/feign.md: -------------------------------------------------------------------------------- 1 | > 译者: 王鸿飞 / brucewhf@gmail.com 2 | 3 | # 声明式REST客户端:Feign 4 | 5 | Feign是一个声明式Web Service客户端。使用Feign能让编写Web Service客户端更加简单, 它的使用方法是定义一个接口,然后在上面添加注解,同时也支持`JAX-RS`标准的注解。Feign也支持可拔插式的编码器和解码器。Spring Cloud对Feign进行了封装,使其支持了Spring MVC标准注解和`HttpMessageConverters`。Feign可以与Eureka和Ribbon组合使用以支持负载均衡。 6 | 7 | 主类示例: 8 | 9 | ```java 10 | @Configuration 11 | @ComponentScan 12 | @EnableAutoConfiguration 13 | @EnableEurekaClient 14 | @EnableFeignClients 15 | public class Application { 16 | 17 | public static void main(String[] args) { 18 | SpringApplication.run(Application.class, args); 19 | } 20 | 21 | } 22 | ``` 23 | 24 | `StoreClient.java`: 25 | 26 | ```java 27 | @FeignClient("stores") 28 | public interface StoreClient { 29 | @RequestMapping(method = RequestMethod.GET, value = "/stores") 30 | List getStores(); 31 | 32 | @RequestMapping(method = RequestMethod.POST, value = "/stores/{storeId}", consumes = "application/json") 33 | Store update(@PathVariable("storeId") Long storeId, Store store); 34 | } 35 | ``` 36 | 37 | `@FeignClient`注解中的`stores`属性可以是一个任意字符串(*译者注:如果与Eureka组合使用,则`stores`应为Eureka中的服务名*),Feign用它来创建一个Ribbon负载均衡器。你也可以通过`url`属性来指定一个地址(可以是完整的URL,也可以是一个主机名)。标注了`@FeignClient`注解的接口在`ApplicationContext`中的Bean实例名是这个接口的全限定名,同时这个Bean还有一个别名,为Bean名 + `FeignClient`。在本例中,可以使用`@Qualifier("storesFeignClient")`来注入该组件。 38 | 39 |
40 | 41 | 如果classpath中有Ribbon, 上面的例子中Ribbon Client会想办法查找`stores`服务的IP地址。如果Eureka也在classpath中,那么Ribbon会从Eureka的注册信息中查找。如果你不想用Eureka,你也可以在配置文件中直接指定一组服务器地址。 42 | 43 |
44 | 45 | ## 覆盖Feign的默认配置 46 | 47 | Spring Cloud对Feign的封装中一个核心的概念就是客户端要有一个名字。每一个客户端随时可以向远程服务发起请求,并且每个服务都可以像使用`@FeignClient`注解一样指定一个名字。Spring Cloud会将所有的`@FeignClient`组合在一起创建一个新的`ApplicationContext`, 并使用`FeignClientsConfiguration`对Clients进行配置。配置中包括编码器、解码器和一个`feign.Contract`。 48 | 49 |
50 | 51 | Spring Cloud允许你通过`configuration`属性完全控制Feign的配置信息,这些配置比`FeignClientsConfiguration`优先级要高: 52 | 53 | ```java 54 | @FeignClient(name = "stores", configuration = FooConfiguration.class) 55 | public interface StoreClient { 56 | //.. 57 | } 58 | ``` 59 | 60 | 在这个例子中,`FooConfiguration`中的配置信息会覆盖掉`FeignClientsConfiguration`中对应的配置。 61 | 62 | 63 | 64 | > 注意:`FooConfiguration`虽然是个配置类,但是它不应该被主上下文(ApplicationContext)扫描到,否则该类中的配置信息就会被应用于所有的`@FeignClient`客户端(本例中`FooConfiguration`中的配置应该只对`StoreClient`起作用)。 65 | 66 | > 注意:`serviceId`属性已经被弃用了,取而代之的是`name`属性。 67 | > 68 | > 在先前的版本中在指定了`url`属性时`name`是可选属性,现在无论什么时候`name`都是必填属性。 69 | 70 | `name`和`url`属性也支持占位符: 71 | 72 | ```java 73 | @FeignClient(name = "${feign.name}", url = "${feign.url}") 74 | public interface StoreClient { 75 | //.. 76 | } 77 | ``` 78 | 79 | Spring Cloud Netflix为Feign提供了以下默认的配置Bean:(下面最左侧是Bean的类型,中间是Bean的name, 右侧是类名) 80 | 81 | - `Decoder` feignDecoder: `ResponseEntityDecoder`(这是对`SpringDecoder`的封装) 82 | - `Encoder` feignEncoder: `SpringEncoder` 83 | - `Logger` feignLogger: `Slf4jLogger` 84 | - `Contract` feignContract: `SpringMvcContract` 85 | - `Feign.Builder` feignBuilder: `HystrixFeign.Builder` 86 | 87 | 下列Bean默认情况下Spring Cloud Netflix并没有提供,但是在应用启动时依然会从上下文中查找这些Bean来构造客户端对象: 88 | 89 | - `Logger.Level` 90 | - `Retryer` 91 | - `ErrorDecoder` 92 | - `Request.Options` 93 | - `Collection` 94 | 95 | 如果想要覆盖Spring Cloud Netflix提供的默认配置Bean, 需要在`@FeignClient`的`configuration`属性中指定一个配置类,并提供想要覆盖的Bean即可: 96 | 97 | ```java 98 | @Configuration 99 | public class FooConfiguration { 100 | @Bean 101 | public Contract feignContract() { 102 | return new feign.Contract.Default(); 103 | } 104 | 105 | @Bean 106 | public BasicAuthRequestInterceptor basicAuthRequestInterceptor() { 107 | return new BasicAuthRequestInterceptor("user", "password"); 108 | } 109 | } 110 | ``` 111 | 112 | 本例子中,我们用`feign.Contract.Default`代替了`SpringMvcContract`, 并添加了一个`RequestInterceptor`。以这种方式做的配置会在所有的`@FeignClient`中生效。 113 | 114 | 115 | 116 | ## Feign对Hystrix的支持 117 | 118 | 如果Hystrix在classpath中,Feign会默认将所有方法都封装到断路器中。Returning a`com.netflix.hystrix.HystrixCommand` is also available。这样一来你就可以使用Reactive Pattern了。(调用`.toObservalbe()`或`.observe()`方法,或者通过`.queue()`进行异步调用)。 119 | 120 | 121 | 122 | 将`feign.hystrix.enabled=false`参数设为`false`可以关闭对Hystrix的支持。 123 | 124 | 125 | 126 | 如果想只关闭指定客户端的Hystrix支持,创建一个`Feign.Builder`组件并标注为`@Scope(prototype)`: 127 | 128 | ```java 129 | @Configuration 130 | public class FooConfiguration { 131 | @Bean 132 | @Scope("prototype") 133 | public Feign.Builder feignBuilder() { 134 | return Feign.builder(); 135 | } 136 | } 137 | ``` 138 | 139 | 140 | 141 | ## Feign对Hystrix Fallback的支持 142 | 143 | Hystrix支持`fallback`的概念,即当断路器打开或发生错误时执行指定的失败逻辑。要为指定的`@FeignClient`启用Fallback支持, 需要在`fallback`属性中指定实现类: 144 | 145 | ```java 146 | @FeignClient(name = "hello", fallback = HystrixClientFallback.class) 147 | protected interface HystrixClient { 148 | @RequestMapping(method = RequestMethod.GET, value = "/hello") 149 | Hello iFailSometimes(); 150 | } 151 | 152 | static class HystrixClientFallback implements HystrixClient { 153 | @Override 154 | public Hello iFailSometimes() { 155 | return new Hello("fallback"); 156 | } 157 | } 158 | ``` 159 | 160 | > 注意:Feign对Hystrix Fallback的支持有一个限制:对于返回`com.netflix.hystrix.HystrixCommand`或`rx.Observable`对象的方法,fallback不起作用。 161 | 162 | 163 | 164 | ## Feign对继承的支持 165 | 166 | Feign可以通过Java的接口支持继承。你可以把一些公共的操作放到父接口中,然后定义子接口继承之: 167 | 168 | _UserService.java_ 169 | 170 | ``` 171 | public interface UserService { 172 | 173 | @RequestMapping(method = RequestMethod.GET, value ="/users/{id}") 174 | User getUser(@PathVariable("id") long id); 175 | } 176 | ``` 177 | 178 | _UserResource.java_ 179 | 180 | ```java 181 | @RestController 182 | public class UserResource implements UserService { 183 | 184 | } 185 | ``` 186 | 187 | _UserClient.java_ 188 | 189 | ```java 190 | package project.user; 191 | 192 | @FeignClient("users") 193 | public interface UserClient extends UserService { 194 | 195 | } 196 | ``` 197 | 198 | > 注意: 在服务的调用端和提供端共用同一个接口定义是不明智的,这会将调用端和提供端的代码紧紧耦合在一起。同时在SpringMVC中会有问题,因为请求参数映射是不能被继承的。 199 | 200 | 201 | 202 | ## Feign对压缩的支持 203 | 204 | 你可能会想要对请求/响应数据进行Gzip压缩,指定以下参数即可: 205 | 206 | ``` 207 | feign.compression.request.enabled=true 208 | feign.compression.response.enabled=true 209 | ``` 210 | 211 | 也可以添加一些更细粒度的配置: 212 | 213 | ``` 214 | feign.compression.request.enabled=true 215 | feign.compression.request.mime-types=text/xml,application/xml,application/json 216 | feign.compression.request.min-request-size=2048 217 | ``` 218 | 219 | 上面的3个参数可以让你选择对哪种请求进行压缩,并设置一个最小请求大小的阀值。 220 | 221 | 222 | 223 | ## Feign的日志 224 | 225 | 每一个`@FeignClient`都会创建一个`Logger`, `Logger`的名字就是接口的全限定名。Feign的日志配置参数仅支持`DEBUG`: 226 | 227 | _application.properties_ 228 | 229 | ``` 230 | logging.level.project.user.UserClient: DEBUG 231 | ``` 232 | 233 | `Logger.Level`对象允许你为指定客户端配置想记录哪些信息: 234 | 235 | - `NONE`, 不记录任何信息,默认值。 236 | - `BASIC`, 记录请求方法、请求URL、状态码和用时。 237 | - `HEADERS`, 在`BASIC`的基础上再记录一些常用信息。 238 | - `FULL`: 记录请求和响应报文的全部内容。 239 | 240 | 将`Level`设置为`FULL`的示例如下: 241 | 242 | ```java 243 | @Configuration 244 | public class FooConfiguration { 245 | @Bean 246 | Logger.Level feignLoggerLevel() { 247 | return Logger.Level.FULL; 248 | } 249 | } 250 | ``` 251 | 252 | -------------------------------------------------------------------------------- /docs/project/QuickStart.md: -------------------------------------------------------------------------------- 1 | # Spring Cloud 2 | 3 | Spring Cloud为开发人员提供了工具,用以快速的在分布式系统中建立一些通用方案(例如配置管理,服务发现,断路器,智能路由,微代理,控制总线,一次性令牌,全局锁,领导选举,分布式会话,集群状态)。协调分布式系统有固定样板模型,使用Spring Cloud开发人员可以快速地搭建基于实现了这些模型的服务和应用程序。他们将在任何分布式环境中工作,包括开发人员自己的笔记本电脑,裸机数据中心,和管理的平台,如云计算。 4 | 5 | For full documentation visit [spring.io](http://projects.spring.io/spring-cloud/). 6 | 7 | ## Quick Start 8 | 9 | 基于Spring Boot构建Spring Cloud,可以在类路径中自动引入提升应用程序性能的一组类库。您可以利用默认配置来快速启动,然后当您需要时,您可以配置或扩展以创建自定义解决方案。 10 | 11 | 发布版的版本号要在artifact:spring-cloud-dependencies 12 | 中明确使用,其他的版本标签会从parent中获取,你可以使用dependencyManagement去做版本依赖管理,下面是使用最新版config client和eureka的配置用例。 13 | 14 | 15 | org.springframework.boot 16 | spring-boot-starter-parent 17 | 1.3.5.RELEASE 18 | 19 | 20 | 21 | 22 | org.springframework.cloud 23 | spring-cloud-dependencies 24 | Brixton.SR1 25 | pom 26 | import 27 | 28 | 29 | 30 | 31 | 32 | org.springframework.cloud 33 | spring-cloud-starter-config 34 | 35 | 36 | org.springframework.cloud 37 | spring-cloud-starter-eureka 38 | 39 | 40 | 41 | ## Features 42 | 43 | Spring Cloud 侧重提供良好的开箱即用体验 44 | 45 | * `Distributed/versioned configuration` 46 | * `Service registration and discovery` 47 | * `Routing` 48 | * `Service-to-service calls` 49 | * `Load balancing` 50 | * `Circuit Breakers` 51 | * `Global locks` 52 | * `Leadership election and cluster state` 53 | * `Distributed messaging` 54 | 55 | Spring Cloud 提供一个发布方法,通常你获得很多特性仅是由于一个classpath的变化或注解,下面是一个discovery client的例子 56 | 57 | @SpringBootApplication 58 | @EnableDiscoveryClient 59 | public class Application { 60 | public static void main(String[] args) { 61 | SpringApplication.run(Application.class, args); 62 | } 63 | } 64 | 65 | ## Main Projects 66 | 67 | * [Spring Cloud Config](SpringCloudConfig.md) 68 | 69 | 利用git集中管理程序的配置。配置资源直接映射到Spring的Environment,另一方面如果有需要也可以被非Spring应用使用。 70 | 71 | * [Spring Cloud Netflix](SpringCloudNetflix.md) 72 | 73 | 集成了许多Netflix的开源软件(Eureka, Hystrix, Zuul, Archaius, etc) 74 | 75 | * [Spring Cloud Bus](SpringCloudBus.md) 76 | 77 | 一个事件总线,利用分布式消息将服务和服务实例连接在一起,用于在一个集群中传播状态的变化,比如配置更改事件。 78 | 79 | * [Spring Cloud for Cloud Foundry](SpringCloudforCloudFoundry.md) 80 | 81 | 利用Pivotal Cloudfoundry集成你的应用程序,提供了一个服务发现的实现也使得它很容易实现SSO和OAuth2保护资源,并创建一个Cloudfoundry服务代理。 82 | 83 | * [Spring Cloud Cloud Foundry Service Broker](SpringCloudCloudFoundryServiceBroker.md) 84 | 85 | 为建立管理云托管服务的服务代理提供了一个起点。 86 | 87 | * [Spring Cloud Cluster]() 88 | 89 | 基于Zookeeper, Redis, Hazelcast, Consul实现的领导选举和平民状态模式的抽象和实现。 90 | 91 | * [Spring Cloud Consul](SpringCloudConsul.md) 92 | 93 | 基于Hashicorp Consul实现的服务发现和配置管理。 94 | 95 | * [Spring Cloud Security](SpringCloudSecurity.md) 96 | 97 | 在Zuul代理中为OAuth2 rest客户端和认证头转发提供负载均衡 98 | 99 | * [Spring Cloud Sleuth](SpringCloudSleuth.md) 100 | 101 | Spring Cloud 应用的分布式追踪系统,和Zipkin,HTrace,ELK兼容。 102 | 103 | * [Spring Cloud Data Flow](SpringCloudDataFlow.md) 104 | 105 | 一个云本地程序和操作模型,组成数据微服务在一个结构化的平台上。 106 | 107 | * [Spring Cloud Stream](SpringCloudStream.md) 108 | 109 | 基于 Redis, Rabbit, Kafka实现的消息微服务,简单声明模型用以在Spring Cloud应用中收发消息。 110 | 111 | * [Spring Cloud Stream Modules](SpringCloudStreamModules.md) 112 | 113 | Spring Cloud Stream Modules 可用于创建消息驱动的微服务。 114 | 115 | * [Spring Cloud Task](SpringCloudTask.md) 116 | 117 | 短生命周期的微服务,为SpringBooot应用简单声明添加功能和非功能特性。 118 | 119 | * [Spring Cloud Zookeeper](SpringCloudZookeeper.md) 120 | 121 | 服务发现和配置管理基于Apache Zookeeper。 122 | 123 | * [Spring Cloud for Amazon Web Services](SpringCloudforAmazonWebServices.md) 124 | 125 | 易与托管的亚马逊网络服务的集成。它提供了一个方便的方式来与AWS提供的服务使用知名的Spring语法和API进行交互,如消息或缓存API。开发人员可以在托管服务周围建立他们的应用程序,而不必关心基础设施或维护。 126 | 127 | * [Spring Cloud Connectors](SpringCloudConnectors.md) 128 | 129 | 便于PaaS应用在各种平台上连接到后端像数据库和消息经纪服务。 130 | 131 | * [Spring Cloud Starters](https://github.com/spring-cloud/spring-cloud-starters) 132 | 133 | SpringBoot风格starter项目,用以简化Spring Cloud客户端的依赖管理。(项目已经终止并且在Angel.SR2后的版本和其他项目合并) 134 | 135 | * [Spring Cloud CLI](SpringCloudCLI.md) 136 | 137 | Spring Boot CLI 插件用Groovy快速的创建Spring Cloud组件应用。 138 | 139 | ## Release Trains 140 | 141 | Spring Cloud 是由自主项目组成的,原则上采用不同的发行节奏。管理投资组合的BOM(物料清单)见下文。发布历程有名称,而不是版本,以避免与子项目混乱。名字是伦敦地铁站的名字的字母序列排序(这样你就可以知道时间顺序),“Angel”是第一个版本,“Brixton”是第二。当子项目的发行版本中累计了大量危机的bug,或者有一个严重的bug需要让每个人可见,发布列车将推出“服务发布(service releases)”结尾的名字”.SRX”,其中“X”是一个数字。 142 | 143 | Release train contents: 144 | 145 | | Component | Angel.SR6 | Brixton.SR1 | Brixton.BUILD-SNAPSHOT | 146 | | ------------ | ------------- | ------------ | ------------ | 147 | | spring-cloud-aws | 1.0.4.RELEASE | 1.1.0.RELEASE |1.1.1.BUILD-SNAPSHOT | 148 | | spring-cloud-bus | 1.0.3.RELEASE | 1.1.0.RELEASE |1.1.1.BUILD-SNAPSHOT | 149 | | spring-cloud-cli | 1.0.6.RELEASE | 1.1.1.RELEASE |1.1.2.BUILD-SNAPSHOT | 150 | | spring-cloud-commons | 1.0.5.RELEASE | 1.1.1.RELEASE |1.1.2.BUILD-SNAPSHOT | 151 | | spring-cloud-config | 1.0.4.RELEASE | 1.1.1.RELEASE |1.1.2.BUILD-SNAPSHOT | 152 | | spring-cloud-netflix | 1.0.7.RELEASE | 1.1.2.RELEASE |1.1.3.BUILD-SNAPSHOT | 153 | | spring-cloud-security | 1.0.3.RELEASE | 1.1.0.RELEASE |1.1.1.BUILD-SNAPSHOT | 154 | | spring-cloud-starters | 1.0.6.RELEASE | | | 155 | | spring-cloud-cloudfoundry | | 1.0.0.RELEASE |1.0.1.BUILD-SNAPSHOT | 156 | | spring-cloud-cluster | | 1.0.0.RELEASE |1.0.1.BUILD-SNAPSHOT | 157 | | spring-cloud-consul | | 1.0.1.RELEASE |1.0.2.BUILD-SNAPSHOT | 158 | | spring-cloud-sleuth | | 1.0.1.RELEASE |1.0.2.BUILD-SNAPSHOT | 159 | | spring-cloud-stream | | 1.0.2.RELEASE |1.0.3.BUILD-SNAPSHOT | 160 | | spring-cloud-zookeeper | | 1.0.1.RELEASE |1.0.2.BUILD-SNAPSHOT | 161 | | spring-boot | 1.2.8.RELEASE | 1.3.5.RELEASE |1.3.5.RELEASE | 162 | | spring-cloud-stream-app-starters* | | |1.0.0.BUILD-SNAPSHOT | 163 | | spring-cloud-task* | | |1.0.0.BUILD-SNAPSHOT | 164 | 165 | (*) 这些项目在他们被发布之前还不是 Brixton 的一部分 166 | 167 | Angel基于Spring Boot 1.2.x,某些部分和1.3.x不兼容。Brixton基于Spring Boot 1.3.x尽可能的兼容1.2.x,一些基于Angel的库和基于Angel的大部分应用可以很好的运行在Brixton上,但spring-cloud-security 1.0.x 用到的OAuth2特性将需要全部修改(他们大多搬到Spring Boot1.3.0)。 168 | 169 | 使用你的依赖管理工具来控制版本。如果你正在使用Maven,记住第一个版本宣布获胜,所以申报材料清单的顺序,与第一个通常是最新的(例如,如果你想使用Spring Boot 1.3.6启动Brixton.RELEASE,把启动BOM放在第一)。同样的规则适用于Gradle,如果你使用Spring的依赖管理插件。 170 | 171 | 172 | > NOTE: starting after Brixton.M4 the release train contains a `spring-cloud-starter-dependencies` as well as the `spring-cloud-starter-parent`. Use the parent as you would the `spring-boot-starter-parent` (if you are using Maven). If you only need dependency management, the "dependencies" version is a BOM-only version of the same thing (it just contains dependency management and no plugin declarations or direct references to Spring or Spring Boot). If you are using the Spring Boot parent POM, then you can use the BOM from Spring Cloud. 173 | 174 | ## Sample Projects 175 | 176 | [Config Server](https://github.com/spring-cloud-samples/configserver) 177 | 178 | [Service Registry](https://github.com/spring-cloud-samples/eureka) 179 | 180 | [Circuit Breaker Dashboard](https://github.com/spring-cloud-samples/hystrix-dashboard) 181 | 182 | [Business Application](https://github.com/spring-cloud-samples/customers-stores)(Customers and Stores) 183 | 184 | [OAuth2 Authorization Server](https://github.com/spring-cloud-samples/authserver) 185 | 186 | [OAuth2 SSO Client](https://github.com/spring-cloud-samples/sso) 187 | 188 | [Integration Test Samples](https://github.com/spring-cloud-samples/tests) 189 | 190 | 191 | 192 | -------------------------------------------------------------------------------- /docs/user-guide/eureka.md: -------------------------------------------------------------------------------- 1 | > 译者:王鸿飞 / brucewhf@gmail.com 2 | 3 | Eureka学习文档资料: 4 | 5 | - [Netflix Eureka详细文档](https://github.com/Netflix/eureka/wiki) 6 | - [Spring Cloud中对Eureka的介绍](http://cloud.spring.io/spring-cloud-static/spring-cloud.html#_spring_cloud_netflix) 7 | 8 | 9 | 10 | Spring Cloud Netflix提供了对Netflix开源项目的集成,使得我们可以以Spring Boot编程风格使用Netflix旗下相关框架。你只需要在程序中添加注解,就能使用成熟的Netflix组件来快速实现分布式系统的常见架构模式。这些模式包括服务发现(Eureka), 断路器(Hystrix), 智能路由(Zuul)和客户端负载均衡(Ribbon)。 11 | 12 | 13 | 14 | # 服务发现:Eureka客户端 15 | 16 | 服务发现是微服务架构中的一项核心服务。如果没有该服务,我们就只能为每一个服务调用者手工配置可用服务的地址,这不仅繁琐而且非常容易出错。Eureka包括了服务端和客户端两部分。服务端可以做到高可用集群部署,每一个节点可以自动同步,有相同的服务注册信息。 17 | 18 | 19 | 20 | ## 向Eureka注册服务 21 | 22 | 当客户端向Eureka注册自己时会提供一些元信息,如主机名、端口号、获取健康信息的url和主页等。Eureka通过心跳连接判断服务是否在线,如果心跳检测失败超过指定时间,对应的服务通常就会被移出可用服务列表。 23 | 24 | > 译者注:向Eureka Server注册过的服务会每30秒向Server发送一次心跳连接, Server会根据心跳数据更新该服务的健康状态并复制到其他Server中。如果超过90秒没有收到该服务的心跳数据,则Server会将该服务移出列表。参考文档:https://github.com/Netflix/eureka/wiki/Eureka-at-a-glance 25 | 26 | 27 | 28 | Eureka Client代码示例: 29 | 30 | ```java 31 | @Configuration 32 | @ComponentScan 33 | @EnableAutoConfiguration 34 | @EnableEurekaClient 35 | @RestController 36 | public class Application { 37 | 38 | @RequestMapping("/") 39 | public String home() { 40 | return "Hello world"; 41 | } 42 | 43 | public static void main(String[] args) { 44 | new SpringApplicationBuilder(Application.class).web(true).run(args); 45 | } 46 | 47 | } 48 | ``` 49 | 50 | (其实就是个普通的Spring Boot应用)。 在这个例子中我们显式的使用了`@EnableEurekaClient`注解,如果你只添加了Eureka相关依赖(即依赖中没有`@EnableEurekaClient`的定义),可以使用`@EnableDiscoveryClient`注解达到同样的效果。除此之外你必须指定一下Eureka服务器的地址: 51 | 52 | `application.yml` 53 | 54 | ``` yaml 55 | eureka: 56 | client: 57 | serviceUrl: 58 | defaultZone: http://localhost:8761/eureka/ 59 | ``` 60 | 61 | 其中,`defaultZone`的作用是给没有指定`Zone`的客户端一个默认的Eureka地址。 62 | 63 | > 译者注:客户端可以在配置文件中指定当前服务属于哪一个`Zone`,如果没有指定,则属于默认`Zone`。 64 | 65 | 66 | 67 | 默认的应用名(Service ID)、主机名和端口号分别对应配置信息中的`${spring.application.name}`、`${spring.application.name}`和`${server.port}`参数。 68 | 69 | 使用`@EnableEurekaClient`注解后当前应用会同时变成一个Eureka服务端实例(它会注册自身)和Eureka客户端(可以查询当前服务列表),与此相关的配置都在以`eureka.instance.*`开头的参数下。只要你指定了`spring.application.name`参数,那么就可以放心的使用默认参数而不需要修改任何配置。 70 | 71 | 要查看更详细的参数,请参阅[EurekaInstanceConfigBean](https://github.com/spring-cloud/spring-cloud-netflix/blob/master/spring-cloud-netflix-eureka-client/src/main/java/org/springframework/cloud/netflix/eureka/EurekaInstanceConfigBean.java)和[EurekaClientConfigBean](http://github.com/spring-cloud/spring-cloud-netflix/tree/master/spring-cloud-netflix-eureka-client/src/main/java/org/springframework/cloud/netflix/eureka/EurekaClientConfigBean.java)。 72 | 73 | 74 | 75 | ## Eureka Server的身份验证 76 | 77 | 如果客户端的`eureka.client.serviceUrl.defaultZone`参数值(即Eureka Server的地址)中包含`HTTP Basic Authentication`信息,如`[http://user:password@localhost:8761/eureka](http://user:password@localhost:8761/eureka)`,那么客户端就会自动使用该用户名、密码信息与Eureka服务端进行验证。如果你需要更复杂的验证逻辑,你必须注册一个`DiscoveryClientOptionalArgs`组件,并将`ClientFilter`组件注入,在这里定义的逻辑会在每次客户端向服务端发起请求时执行。 78 | 79 | > 由于Eureka的限制,Eureka不支持单节点身份验证。 80 | 81 | 82 | 83 | ## 状态页和健康信息指示器 84 | 85 | Eureka应用的状态页和健康信息默认的url为`/info`和`/health`,这与`Spring Boot Actuator`中对应的Endpoint是重复的,因此你必须进行修改: 86 | 87 | ```yaml 88 | eureka: 89 | instance: 90 | statusPageUrlPath: ${management.context-path}/info 91 | healthCheckUrlPath: ${management.context-path}/health 92 | ``` 93 | 94 | 客户端通过这些URL获取数据,并根据这些数据来判断是否可以向某个服务发起请求。 95 | 96 | 97 | 98 | ## 使用HTTPS 99 | 100 | 你可以指定`EurekaInstanceConfig`类中的`eureka.instance.[nonSecurePortEnabled,securePortEnabled]=[false,true]`属性来指定是否使用HTTPS。当配置使用HTTPS时,Eureka Server会返回以`https`开头的服务地址。 101 | 102 | 即使配置了使用HTTPS,Eureka的主页依然是以普通 HTTP 方式访问的。你需要手动添加一些配置来将这些页面也通过HTTPS保护起来: 103 | 104 | ```yaml 105 | eureka: 106 | instance: 107 | statusPageUrl: https://${eureka.hostname}/info 108 | healthCheckUrl: https://${eureka.hostname}/health 109 | homePageUrl: https://${eureka.hostname}/ 110 | ``` 111 | 112 | > 注意,`eureka,hostname`是Eureka原生属性,只有新版本的Eureka才支持该属性。你也可以用Spring EL表达式代替:`${eureka.instance.hostName}` 113 | > 114 | > 如果你的应用前端部署了代理,并且SSL的终点是此代理服务器,那么你就需要在应用中解析`forwarded`请求头。如果你在配置文件中添加了`X-Forwarded-*`相关参数,Spring Boot中的嵌入式Tomcat会自动解析该请求头。一种表明你没有处理好`forwarded`请求头的迹象就是你的应用渲染出的HTML页面中链接显示的是错误的主机名和端口号。 115 | 116 | 117 | 118 | ## 健康检查 119 | 120 | 默认情况下,Eureka通过客户端发来的心跳包来判断客户端是否在线。如果你不显式指定,客户端在心跳包中不会包含当前应用的健康数据(由Spring Boot Actuator提供)。这意味着只要客户端启动时完成了服务注册,那么该客户端在主动注销之前在Eureka中的状态会永远是`UP`状态。我们可以通过配置修改这一默认行为,即在客户端发送心跳包时会带上自己的健康信息。这样做的后果是只有当该服务的状态是`UP`时才能被访问,其它的任何状态都会导致该服务不能被调用。 121 | 122 | ```yaml 123 | eureka: 124 | client: 125 | healthcheck: 126 | enabled: true 127 | ``` 128 | 129 | 如果你想对健康检查有更细粒度的控制,你可以自己实现`com.netflix.appinfo.HealthCheckHandler`接口。 130 | 131 | 132 | 133 | > 以下内容翻译自Eureka官方手册: 134 | > 135 | > Eureka客户端会每隔30s向服务端发送心跳包以告知服务端当前客户端没有挂掉。对于Client来说,服务Server超过90s没有收到该Client的心跳数据,Server就会把该Client移出服务列表。最好不要修改30s的默认心跳间隔,因为Server会使用这个时间数值来判断是否出现了大面积故障。(译者:意思是比如Eureka默认2分钟收不到心跳就认为网络出了故障,你如果把这个心跳间隔改成了3分钟,那就出问题了。) 136 | 137 | 138 | 139 | ## Eureka元数据说明 140 | 141 | 我们有必要花一些时间来了解一下Eureka的元数据,这样就可以添加一些自定义的数据以适应特定的业务场景。像主机名、IP地址、端口号、状态页url和健康检查url都是Eureka定义的标准元数据。这些元数据会被保存在Eureka Server的注册信息中,客户端会读取这些数据来向需要调用的服务直接发起连接。你可以使用以`eureka.instance.metadataMap`开头的参数来添加你自定义的元数据,所有客户端都会读取到该信息。通过这种方式你能给客户端自定义一些行为。 142 | 143 | 144 | 145 | ## 使用EurekaClient对象 146 | 147 | 当添加了`@EnableDiscoveryClient`或`@EnableEurekaClient`注解后,你就可以在应用中使用`EurekaClient`对象来获取服务列表: 148 | 149 | ```java 150 | @Autowired 151 | private EurekaClient discoveryClient; 152 | 153 | public String serviceUrl() { 154 | InstanceInfo instance = discoveryClient.getNextServerFromEureka("STORES", false); 155 | return instance.getHomePageUrl(); 156 | } 157 | ``` 158 | 159 | > 不要在`@PostConstruct`或`@Scheduled`方法中使用`EurekaClient`。在`ApplicationContext`还没有完全启动时使用该对象会发生错误。 160 | 161 | 162 | 163 | ## 使用Spring的DiscoveryClient对象 164 | 165 | 你没有必要直接使用Netflix原生的`EurekaClient`对象,在此基础上做一些封装使用起来会更方便。Spring Cloud支持`Feign`和`Spring RestTmpelate`,它们都可以使用服务的逻辑名而不是URL地址来查询服务。如果想给`Ribbon`手工指定服务列表,你可以将`.ribbon.listOfServers`属性设为逗号分隔的物理地址或主机名, 参数中的`client`是服务id,即服务名。 166 | 167 | 你可以使用Spring提供的`DiscoveryClient`对象从而代码不会与Eureka紧耦合: 168 | 169 | ```java 170 | @Autowired 171 | private DiscoveryClient discoveryClient; 172 | 173 | public String serviceUrl() { 174 | List list = discoveryClient.getInstances("STORES"); 175 | if (list != null && list.size() > 0 ) { 176 | return list.get(0).getUri(); 177 | } 178 | return null; 179 | } 180 | ``` 181 | 182 | 183 | 184 | ## 为什么注册一个服务这么慢? 185 | 186 | 服务的注册涉及到心跳连接,默认为每30秒一次。只有当Eureka服务端和客户端本地缓存中的服务元数据相同时这个服务才能被其它客户端发现,这需要3个心跳周期。你可以通过参数`eureka.instance.leaseRenewalIntervalInSeconds`调整这个时间间隔来加快这个过程。在生产环境中你最好使用默认值,因为Eureka内部的某些计算依赖于该时间间隔。 187 | 188 | 189 | 190 | # 服务发现:Eureka服务端 191 | 192 | 添加`spring-cloud-starter-eureka-server`,主类代码示例如下: 193 | 194 | ```java 195 | @SpringBootApplication 196 | @EnableEurekaServer 197 | public class Application { 198 | 199 | public static void main(String[] args) { 200 | new SpringApplicationBuilder(Application.class).web(true).run(args); 201 | } 202 | 203 | } 204 | ``` 205 | 206 | 服务启动后,Eureka有一个带UI的主页,注册信息可以通过`/eureka/*`下的URL获取到。 207 | 208 | 209 | 210 | ## 高可用, Zone 和 Region 211 | 212 | Eureka把所有注册信息都放在内存中,所有注册过的客户端都会向Eureka发送心跳包来保持连接。客户端会有一份本地注册信息的缓存,这样就不需要每次远程调用时都向Eureka查询注册信息。 213 | 214 | 215 | 216 | 默认情况下,Eureka服务端自身也是个客户端,所以需要指定一个Eureka Server的URL作为"伙伴"(peer)。如果你没有提供这个地址,Eureka Server也能正常启动工作,但是在日志中会有大量关于找不到peer的错误信息。 217 | 218 | 219 | 220 | ## Standalone模式 221 | 222 | 只要Eureka Server进程不会挂掉,这种集Server和Client于一身和心跳包的模式能让Standalone(单台)部署的Eureka Server非常容易进行灾难恢复。在 Standalone 模式中,可以通过下面的配置来关闭查找“伙伴”的行为: 223 | 224 | ```yaml 225 | server: 226 | port: 8761 227 | 228 | eureka: 229 | instance: 230 | hostname: localhost 231 | client: 232 | registerWithEureka: false 233 | fetchRegistry: false 234 | serviceUrl: 235 | defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/ 236 | ``` 237 | 238 | 注意,`serviceUrl`中的地址的主机名要与本地主机名相同。 239 | 240 | 241 | 242 | ## "伙伴"感知 243 | 244 | Eureka Server可以通过运行多个实例并相互指定为“伙伴”的方式来达到更高的高可用性。实际上这就是默认设置,你只需要指定“伙伴”的地址就可以了: 245 | 246 | ```yaml 247 | --- 248 | spring: 249 | profiles: peer1 250 | eureka: 251 | instance: 252 | hostname: peer1 253 | client: 254 | serviceUrl: 255 | defaultZone: http://peer2/eureka/ 256 | 257 | --- 258 | spring: 259 | profiles: peer2 260 | eureka: 261 | instance: 262 | hostname: peer2 263 | client: 264 | serviceUrl: 265 | defaultZone: http://peer1/eureka/ 266 | ``` 267 | 268 | 在上面这个例子中,我们通过使用不同`profile`配置的方式可以在本地运行两个Eureka Server。你可以通过修改`/etc/host`文件,使用上述配置在本地测试伙伴感特性。 269 | 270 | 271 | 272 | 你可以同时启动多个Eureka Server, 并通过伙伴配置使之围成一圈(相邻两个Server互为伙伴),这些Server中的注册信息都是同步的。If the peers are physically separated (inside a data centre or between multiple data centres) then the system can in principle survive split-brain type failures. 273 | 274 | 275 | 276 | ## 使用IP地址 277 | 278 | 有些时候你可能更倾向于直接使用IP地址定义服务而不是使用主机名。把`eureka.instance.preferIpAddress`参数设为`true`时,客户端在注册时就会使用自己的ip地址而不是主机名。 -------------------------------------------------------------------------------- /docs/user-guide/zuul.md: -------------------------------------------------------------------------------- 1 | 贡献者: Alex Wei 2 | 3 | # Zuul:路由器和过滤器 # 4 | 路由是微服务体系不可或缺的一部分, 例如 / 可以映射到Web 应用, /api/users 可以映射的用户服务 , api/shop 可以映射到商店服务。 Zuul是一个基于JVM的路由器,同时也是一个服务端负载均衡。 5 | 它由Netflix公司开源。 6 | 7 | Netflix使用Zuul做如下事情: 8 | 9 | - 认证鉴权。 10 | - 审查 11 | - 压力测试 12 | - 金丝雀测试 13 | - 动态路由 14 | - 服务迁移 15 | - 负载剪裁 16 | - 安全 17 | - 静态应答处理 18 | 19 | Zuul允许使用任何支持JVM的语言来建立规则和过滤器,内置了对Java和Groovy的支持。 20 | 21 | ## 如何引入Zuul ## 22 | 23 | 为了在自己的project中引入zuul,仅仅需要使用spring-cloud-starter-zuul就OK啦。详细的内容参照 Spring Cloud Project page 。 24 | 25 | ## 内置Zuul 反向代理 ## 26 | 当一个UI应用想要通过代理调用后端服务时,Spring Cloud通过一个内置的Zuul代理,从而减轻一些通用案例的开发。 这个特性对于前端用户交互通过代理访问后端服务是有用的,避免了为所有后端服务单独建立CORS和认证相关管理等事情。在Spring Boot的main类上面添加@EnableZuulProxy注解,它就可以转发本地的调用到适用的服务上面。 27 | 28 | 按照惯例, 一个服务ID为"users"的服务也将收到来自于/users的请求。代理使用Ribbon(一种客户端负载均衡机制)定位一个服务实例,所有迭代请求在hystrix command(服务异常断路机制)被执行,以致于一旦失败,Hystrix metrics(服务异常断路的监控机制)将能够呈现出来。 一旦断路器被打开, 代理将不再尝试与这个服务联系。 29 | 30 | 为了跳过一些自动增加的服务,可以设置zuul.ignored-services的值,使其符合想要忽略的服务列表的ID模式。如果一个服务匹配这种忽略的模式,但是被显示的配置到了Routes map里的话,它又不能被忽略。例如: 31 | 32 | application.yml 33 | zuul: 34 | ignoredServices: '*' 35 | routes: 36 | users: /myusers/** 37 | 在这个例子里,除了"users",所有的服务都会被忽略。 38 | 为了扩充或者改变代理路由, 你可以增加如下显示的配置: 39 | 40 | application.yml 41 | zuul: 42 | routes: 43 | users: /myusers/** 44 | 这意味着来自于`"/myusers"`的http请求将被转发到`"users"`服务上(例如`"/myusers/101"`被转发到`"/101"`)。 45 | 46 | 为了得到更细粒度的控制,你可以指定具体的路由到服务的标识上: 47 | 48 | zuul: 49 | routes: 50 | users: 51 | path: /myusers/** 52 | serviceId: users_service 53 | 54 | 这意味着来自于`"/myusers"`的http请求被转发到`"users_service"`这个服务上。 55 | 路由必须有一个符合Ant模式的"path",那么`"/myusers/*"` 就仅仅匹配第一级,而`"/myusers/**"` 能够层次化匹配。 56 | 57 | 后端服务的定位可以按照服务ID或者url来识别。 例如: 58 | 59 | application.yml 60 | zuul: 61 | routes: 62 | users: 63 | path: /myusers/** 64 | url: http://example.com/users_service 65 | 66 | 67 | 这些简单的url路由是不支持HystrixCommand 和Ribbon负载均衡的。为了实现这一点,需要指定service路由,并且为这个Service配置Ribbon客户端(当前需要在Ribbon失效Eureka的支持)。 例如: 68 | 69 | application.yml 70 | zuul: 71 | routes: 72 | users: 73 | path: /myusers/** 74 | serviceId: users 75 | ribbon: 76 | eureka: 77 | enabled: false 78 | users: 79 | ribbon: 80 | listOfServers: example.com,google.com 81 | 82 | 83 | 你可以使用正则匹配来建立ServiceId和路由之间的默契。使用正则表达式命名组来从服务ID中提取变量,注入他们到一个路由模式里。 84 | 85 | ApplicationConfiguration.java 86 | @Bean 87 | public PatternServiceRouteMapper serviceRouteMapper() { 88 | return new PatternServiceRouteMapper( 89 | "(?^.+)-(?v.+$)", 90 | "${version}/${name}"); 91 | } 92 | 93 | 这意味着,一个服务ID为"myusers-v1"将被映射到路由 `"/v1/myusers/**"`上。任何正则表达式都会被接受,但是所有的名称组必须同时出现在servicePattern和routePattern上。如果servicePattern不匹配Service Id,将使用默认行为。在上面的例子中, 服务ID是"myusers"的服务会被映射到路由:`"/myusers/**"`(不检测版本)。 这个特性默认是不可用的,并且仅仅适用于已经被发现(应该是已经注册)的服务。 94 | 95 | 为了给所有的映射增加前缀, 可以设置zuul.prefix,例如/api。默认情况下,在请求被转发前,这个代理前缀会被从请求中去除掉。你也可以按照独立的路由来控制这个功能的切换,例如: 96 | 97 | application.yml 98 | zuul: 99 | routes: 100 | users: 101 | path: /myusers/** 102 | stripPrefix: false 103 | 104 | 这个例子中,请求`"/myusers/101"`将被转发到`"users"`服务的`"/myusers/101"`上。 105 | 106 | Zuul.routes条目实际上是绑定到一个类型为ZuulProperties的对象上。如果查找这个对象的属性集,你会返现有一个"retryable"的标志位。将这个标志位设置为true,Ribbon的客户端将自动重试失败的请求。(如果需要,可以使用Ribbon客户端配置更改这个操作的参数)。 107 | 108 | 默认情况下,X-Forwarded-Host header会被增加到转发的请求里。 如果不想要这个功能,需要设置 `zuul.addProxyHeaders = false`。 109 | 110 | 一个带有@EnableZuulProxy的应用能够作为独立服务器。如果设置一个默认的路由("/"),例如examplezuul.route.home: / 将路由所有的请求到"home" service。 111 | 112 | 如果需要更细粒度的控制一些路由模式的忽略, 可以指定一个特殊的忽略模式。 这些模式在路由定位过程的开始被计算。这也意味着前缀应该被包含在模式里来保证匹配。忽略模式跨越所有服务和取代所有其他路由规范。 113 | 114 | application.yml 115 | zuul: 116 | ignoredPatterns: /**/admin/** 117 | routes: 118 | users: /myusers/** 119 | 120 | 121 | 这意味着所有的类似`"/myusers/101"`的请求将被转发到 `"users"`服务的` "/101"`上。但包含`"/admin/"`将不被解析。 122 | 123 | 注意: 如果你需要你的路由配置有顺序,需要使用YAML文件,properties file将流失预订的顺序。 124 | 125 | application.yml 126 | zuul: 127 | routes: 128 | users: 129 | path: /myusers/** 130 | legacy: 131 | path: /** 132 | 133 | 如果使用 properties file, legacy路径可能会跑到users路径前面,使得users路径不可达。 134 | 135 | ##Zuul Http Client## 136 | zuul默认使用的HTTP Client是Apache HTTP Client,代替了过时的Ribbon RestClient。 如果想使用 RestClient或者okhttp3.OkHttpClient,设置ribbon.restclient.enabled=true或者ribbon.okhttp.enabled=true。 137 | 138 | 139 | ##Cookies and Sensitive Headers## 140 | 同一系统在服务间共享headers是可以做到的。但是,你或许不想一些敏感的headers向下泄露到一个外部服务。你可以在路由配置里指定一个忽略的headers列表。Cookies在浏览器端有明确的语义,所以作为一个特殊的角色,总是被视为很敏感。如果客户端是浏览器,因为cookies的混杂,也会给使用下游服务的用户造成问题。 141 | 142 | 如果你对服务的设计很小心,例如如果仅仅一个下游服务设置了cookies,那么你也可能让他们一直从后端流窜到调用端。同时,如果你的代理设置了cookies,并且所有后端服务是同一系统的一部分。它可以很自然的分享他们(类似于使用Spring Session来link他们到一些共享状态)。另外,任何由下游服务设置/获取的cookies,对于调用者来说,不一定特别有用。因为,推荐你为路由"Set-Cookie"和设置cookies到header时,不要作为domain的一部分。即使路由是domain的一部分,也要尝试认真思考是否允许cookies在服务和代理间流动。 143 | 144 | 敏感性headers能够在每个route里用逗号分隔进行配置。 145 | 146 | application.yml 147 | zuul: 148 | routes: 149 | users: 150 | path: /myusers/** 151 | sensitiveHeaders: Cookie,Set-Cookie,Authorization 152 | url: https://downstream 153 | 154 | 敏感性的headers也能用 zuul.sensitiveHeaders进行全局设置。如果route上设置了sensitiveHeaders,将覆盖全局设置。 155 | 156 | 157 | ##忽略Headers## 158 | 除了route上的敏感性headers之外,在与下游服务交互期间,你可以设置zuul.ignoredHeaders来忽略headers(请求和应答)。默认,这个属性是空的。除非Spring Security不在classpath,否则他们将初始化一组由Spring Security指定的`"security"` headers。这个假设是,下游服务也可能增加headers。如果当Spring Security不在classpath,我们不想废弃那些security headers,可以设置zuul.ignoreSecurityHeaders为false。如果你不激活Spring Security的Security response headers或者希望下游服务提供这些值,这可能是有用的。 159 | 160 | ##The Routes 访问点## 161 | 如果你使用`@EnableZuulProxy`和Spring Boot Actuator,你将能得到一个/routes的访问点。GET这个访问点将返回映射的route列表。 POST这个访问点将强制刷新存在的routes。 162 | 163 | ##抑制模式和本地转发## 164 | 当迁移一个存在的应用或者API时,有一个通用的模式是“抑制”那个旧的访问点,慢慢的用不同的实现替换他们。Zuul代理就是一个有用的工具。你可以使用它重定向网络访问到新的访问点。例如如下配置: 165 | 166 | application.yml 167 | zuul: 168 | routes: 169 | first: 170 | path: /first/** 171 | url: http://first.example.com 172 | second: 173 | path: /second/** 174 | url: forward:/second 175 | third: 176 | path: /third/** 177 | url: forward:/3rd 178 | legacy: 179 | path: /** 180 | url: http://legacy.example.com 181 | 这个例子中,路径是/first/**的请求被提取到一个带有外部url的新的服务。 路径/second/**和/third/**被转发到本地服务来处理。而剩下的不符合以上模式的请求才被"legacy"处理。 182 | 183 | 184 | ##通过Zuul上传文件## 185 | 使用Zuul( @EnableZuulProxy),可以使用代理路径上传文件,但这仅仅对于尽可能小的文件。对于大的文件,有一个叫做`"/zuul/*"`的可替代的路径可以绕过Sping DispathcerServlet(为了避免多重处理)。例如,如果设置`zuul.routes.customers=/customers/**`,你可以POST一个大的文件给"/`zuul/customers/*"`。这个Servlet路径经由zuul.servletPath被暴露。极端情况下,如果代理的route利用的是Ribbon负载均衡,大的文件也需要提高超时的设置。 186 | 例如: 187 | 188 | 189 | application.yml 190 | hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds: 60000 191 | ribbon: 192 | ConnectTimeout: 3000 193 | ReadTimeout: 60000 194 | 195 | 注意,对于流式处理大的文件,需要在请求中使用分块编码(一些浏览器默认不这样做)。 例如,使用命令行: 196 | 197 | $ curl -v -H "Transfer-Encoding: chunked" \ 198 | -F "file=@mylarge.iso" localhost:9999/zuul/simple/file 199 | 200 | 201 | ##Plain Embedded Zuul## 202 | 也可以运行一个没有代理的Zuul服务器,或者选择性的开启一部分代理平台。 如果使用@EnableZuulServer(不是@EnableZuulProxy),任何增加到应用里的,扩展自ZuulFilter的beans都将自动被安装。但如果他们被标注@EnableZuulProxy,没有任何代理过滤器被自动安装。 203 | 204 | 这种情况下,zuul服务器里的routes仍然通过`"zuul.routes.*"`来指定,但是没有服务发现,也没有代理。因此,"serviceId"和“url”设置都被忽略。 例如: 205 | 206 | application.yml 207 | zuul: 208 | routes: 209 | api: /api/** 210 | 211 | 将映射所有的`"/api/**"`到Zuul过滤器链。 212 | 213 | ##失效 Zuul 过滤器## 214 | Zuul默认包含了大量的ZuulFilter Beans用于代理或者服务模式。可以参照filters包来查找有哪些可用的过滤器。如果你想失效一个,简单的设置`zuul...disable=true`就可以。依照惯例, 包中的过滤器都是Zuul的顾虑器类型。例如,为了失效`org.springframework.cloud.netflix.zuul.filters.post.SendResponseFilter`,设置 `zuul.SendResponseFilter.post.disable=true`就可以啦。 215 | 216 | ##Providing Hystrix Fallbacks For Routes## 217 | 当Zuul中一个给定route的断路器跳闸时,可以通过建立一个`ZuulFallbackProvider`的扩展Bean来提供一个fallback应答。 在这个Bean里,你需要指定Route ID,并提供一个`ClientHttpResponse`作为Fallback返回。 下面是一个非常简单的`ZuulFallbackProvider`实现。 218 | 219 | class MyFallbackProvider implements ZuulFallbackProvider { 220 | @Override 221 | public String getRoute() { 222 | return "customers"; 223 | } 224 | 225 | @Override 226 | public ClientHttpResponse fallbackResponse() { 227 | return new ClientHttpResponse() { 228 | @Override 229 | public HttpStatus getStatusCode() throws IOException { 230 | return HttpStatus.OK; 231 | } 232 | 233 | @Override 234 | public int getRawStatusCode() throws IOException { 235 | return 200; 236 | } 237 | 238 | @Override 239 | public String getStatusText() throws IOException { 240 | return "OK"; 241 | } 242 | 243 | @Override 244 | public void close() { 245 | 246 | } 247 | 248 | @Override 249 | public InputStream getBody() throws IOException { 250 | return new ByteArrayInputStream("fallback".getBytes()); 251 | } 252 | 253 | @Override 254 | public HttpHeaders getHeaders() { 255 | HttpHeaders headers = new HttpHeaders(); 256 | headers.setContentType(MediaType.APPLICATION_JSON); 257 | return headers; 258 | } 259 | }; 260 | } 261 | } 262 | 263 | 这时,route的配置看起来像: 264 | 265 | zuul: 266 | routes: 267 | customers: /customers/** -------------------------------------------------------------------------------- /docs/user-guide/stream.md: -------------------------------------------------------------------------------- 1 | # Spring Cloud Stream 2 | 3 | 这一节将更详细地介绍如何使用SpringCloudStream工作,它涵盖主题了创建和运行Stream应用。 4 | 5 | ## 简介 6 | 7 | SpringCloudStream是一个构建消息驱动的微服务框架。SpringCloudStream构建在SpringBoot之上用以创建工业级的应用程序,并且Spring Integration提供了和消息代理的连接。SpringCloudStream提供几个厂商消息中间件个性化配置,引入发布订阅、消费组和分区的语义概念。 8 | 9 | 添加@EnableBinding注解在你的程序中,被@StreamListener修饰的方法可以立即连接到消息代理接收流处理事件。下面是一个简单的接收外部消息的接收器应用程序 10 | 11 | ``` 12 | @SpringBootApplication 13 | public class StreamApplication { 14 | 15 | public static void main(String[] args) { 16 | SpringApplication.run(StreamApplication.class, args); 17 | } 18 | } 19 | 20 | @EnableBinding(Sink.class) 21 | public class TimerSource { 22 | 23 | ... 24 | 25 | @StreamListener(Sink.INPUT) 26 | public void processVote(Vote vote) { 27 | votingService.recordVote(vote); 28 | } 29 | } 30 | ``` 31 | @EnableBinding注解使用一个或者多个接口作为参数(本例子中,参数是单独的Sink接口),接口中可以定义输入或输出的channels,SpringCloudStream定义了三个接口`Source`,`Sink`,`Processor`,你也可以自定义接口。 32 | 33 | 下面是Sink接口的定义: 34 | ``` 35 | public interface Sink { 36 | String INPUT = "input"; 37 | 38 | @Input(Sink.INPUT) 39 | SubscribableChannel input(); 40 | } 41 | ``` 42 | `@Input`定义了一个接收消息的输入channel,`@Output`定义了一个发布消息的输出channel,这两个注解支持一个参数作为channel名称,如果没有设置参数则注解修饰的方法名将被设置为channel名称。 43 | 44 | SpringCloudStream会为你创建一个接口的实现,你可以通过自动装配在应用中使用它,如下例: 45 | ``` 46 | @RunWith(SpringJUnit4ClassRunner.class) 47 | @SpringApplicationConfiguration(classes = StreamApplication.class) 48 | @WebAppConfiguration 49 | @DirtiesContext 50 | public class StreamApplicationTests { 51 | 52 | @Autowired 53 | private Sink sink; 54 | 55 | @Test 56 | public void contextLoads() { 57 | assertNotNull(this.sink.input()); 58 | } 59 | } 60 | ``` 61 | 62 | ## 主要概念 63 | 64 | SpringCloudStream提供了很多抽象和基础组件来简化消息驱动型微服务应用。包含以下内容: 65 | 66 | * Spring Cloud Stream的应用模型 67 | * 绑定抽象 68 | * 持久化发布/订阅支持 69 | * 消费者组支持 70 | * 分片支持(Partitioning Support) 71 | * 可插拔API 72 | 73 | ### 应用模型 74 | 75 | SpringCloudStream由一个中立的中间件内核组成。SpringCloudStream会注入输入和输出的channels,应用程序通过这些channels与外界通信,而channels则是通过一个明确的中间件Binder与外部brokers连接。 76 | 77 | ![](/img/stream-binder.png) 78 | 79 | #### Fat JAR 80 | 81 | SpringCloudStream可以在ide中运行一个单独的实例用来测试,如果要部署在生产环境中则可以通过Maven或者Gradle提供的Spring Boot工具创建可执行JAR(胖JAR) 82 | 83 | ### 绑定抽象 84 | 85 | SpringCloudStream提供对Kafka,Rabbit MQ,Redis,和Gemfire的Binder实现。Spring Cloud Stream还包括了一个TestSupportBinder,TestSupportBinder预留一个未更改的channel以便于直接地、可靠地和channels通信。您可以使用可扩展的API来编写自己的Binder。 86 | 87 | SpringCloudStream使用SpringBoot做配置,绑定抽象使得SpringCloudStream应用可以灵活的连接到中间件。比如,开发者可以在运行时动态的选择channels连接的目标(可以是kafka topics或RabbitMQ exchanges)。这样的配置可以通过外部配置或任何SpringBoot支持的形式(包括应用参数,环境变量和application.yml或application.properties文件)。简介一节提到的sink例子中,将`spring.cloud.stream.bindings.input.destination`设置成`raw-sensor-data`程序会从命名为`raw-sensor-data`的kafka主题中读取数据,或者从一个绑定到`raw-sensor-data`的rabbitmq交换机的队列中读取数据。 88 | 89 | SpringCloudStream能自动发现并使用类路径中的binder,您可以很容易地以相同的代码使用不同类型的中间件:只需要在build的时候引入不同的binder。对于更复杂的情况,你可以引入多个binders并选择使用哪一个,甚至可以在运行时根据不同的channels选择不同的binder。 90 | 91 | ### 持久化发布/订阅支持 92 | 93 | 应用间通信遵照发布-订阅模型,数据通过共享的topics进行广播,下图显示了SpringCloudStream应用交互的典型部署. 94 | 95 | ![](/img/stream-sensors.png) 96 | 97 | 数据被发送到一个公共的目标`raw-sensor-data`,在目标中,数据分别被两个独立的微服务加工,一个微服务计算平均窗口时间,另一个将原始数据存储到HDFS。为了处理数据,两个微服务在运行时声明这个topic作为他们的输入源。 98 | 99 | 发布-订阅通信模型降低了生产者和消费者的复杂性,并允许新的应用程序被添加到拓扑结构,而不会破坏现有的流程。例如,下游的平均计算应用程序,您可以添加一个应用程序,该应用程序计算最高温度用来显示和监控。然后您可以再添加一个基于相同数据流的,解释故障检测的另一个应用程序。通过共同的topics做沟通相比点对点的队列更能减少微服务间的耦合。 100 | 101 | 发布订阅不是一个新概念,SpringCloudStream在你的应用中提供一个额外的手段供你选择。通过使用本地中间件支持,SpringCloudStream简化了不同平台上的发布订阅模型。 102 | 103 | ### 消费者组 104 | 105 | 虽然发布-订阅模型可以很容易地通过共享topics连接应用程序,但创建一个应用多实例的的扩张能力同等重要。当这样做时,应用程序的不同实例被放置在一个竞争的消费者关系中,其中只有一个实例将处理一个给定的消息。 106 | 107 | SpringCloudStream利用消费者组定义这种行为(这种分组类似于Kafka consumer groups,灵感也来源于此),每个消费者通过`spring.cloud.stream.bindings.input.group`指定一个组名称,以下图所示的消费者为例,应分别设置`spring.cloud.stream.bindings.input.group=hdfsWrite`和`spring.cloud.stream.bindings.input.group=average`。 108 | 109 | ![](/img/stream-groups.png) 110 | 111 | 所有订阅指定topics的组都会收到发布数据的一份副本,但是每一个组内只有一个成员会收到该消息。默认情况下,当一个组没有指定时,SpringCloudStream将分配给一个匿名的、独立的只有一个成员的消费组,该组与所有其他组都处于一个发布-订阅关系中。 112 | 113 | 114 | #### 持久性 115 | 116 | SpringCloudStream一致性模型中,消费者组订阅是持久的,也就是说一个绑定的实现确保组的订阅者是持久的。一旦组中至少有一个成员创建了订阅,这个组就会收到消息,即使组中所有的应用都被停止了,组仍然会收到消息。 117 | 118 | > 匿名订阅是非持久的,一些binder的实现(如:RabbitMQ),可以创建非持久化(non-durable)组订阅 119 | 120 | 在一般情况下,将应用绑定到给定目标的时候,最好指定一个消费者组,当扩展一个SpringCloudStream应用时,必须为每个输入bindings指定一个消费组,这防止了应用程序的实例接收重复的消息(除非该行为是需要的,这是不寻常的)。 121 | 122 | ### 分区支持 123 | 124 | SpringCloudStream支持在一个应用程序的多个实例之间数据分区,在分区的情况下,物理通信介质(例如,topic代理)被视为多分区结构。一个或多个生产者应用程序实例将数据发送给多个消费应用实例,并保证共同的特性的数据由相同的消费者实例处理。 125 | 126 | SpringCloudStream提供了一个通用的抽象,用于统一方式进行分区处理,因此分区可以用于自带分区的代理(如kafka)或者不带分区的代理(如rabbiemq) 127 | 128 | ![](/img/stream-partitioning.png) 129 | 130 | 分区在有状态处理中是一个很重要的概念,其重要性体现在性能和一致性上,要确保所有相关数据被一并处理,例如,在时间窗平均计算的例子中,给定传感器测量结果应该都由同一应用实例进行计算。 131 | 132 | > 如果要设置分区处理方案,需要配置数据生产端点和数据消费端点 133 | 134 | ## 编程模型 135 | 136 | 本节介绍SpringCloudStream的编程模型,SpringCloudStream提供了一些预定义的注解,用于绑定输入和输出channels,以及如何监听channels。 137 | 138 | ### 声明和绑定通道 139 | 140 | #### 通过`@EnableBinding`触发绑定 141 | 142 | 将@EnableBinding注解添加到应用的配置类,就可以把一个spring应用转换成SpringCloudStream应用,@EnableBinding注解本身就包含@Configuration注解,会触发SpringCloudStream 基本配置。 143 | ``` 144 | ... 145 | @Import(...) 146 | @Configuration 147 | @EnableIntegration 148 | public @interface EnableBinding { 149 | ... 150 | Class[] value() default {}; 151 | } 152 | ``` 153 | @EnableBinding注解可以接收一个或多个接口类作为参数,后者包含代表了可绑定构件(一般来说是消息通道)的方法 154 | 155 | >在SpringCloudStream1.0中,仅有的可绑定构件是Spring Messaging `MessageChannel`以及它的扩展`SubscribableChannel`和`PollableChannel`. 未来版本会使用相同的机制扩展对其他类型构件的支持。在本文档中,会继续引用channels。 156 | 157 | #### `@Input` 与 `@Output` 158 | 159 | 一个SpringCloudStream应用可以有任意数目的input和output通道,后者通过`@Input`和`@Output`注解在接口中定义。 160 | ``` 161 | public interface Barista { 162 | 163 | @Input 164 | SubscribableChannel orders(); 165 | 166 | @Output 167 | MessageChannel hotDrinks(); 168 | 169 | @Output 170 | MessageChannel coldDrinks(); 171 | } 172 | ``` 173 | 使用这个接口作为@EnableBinding的参数,将触发三个bound channels的创建,后者的分别被命名为`orders`,`hotDrinks`,`coldDrinks` 174 | ``` 175 | @EnableBinding(Barista.class) 176 | public class CafeConfiguration { 177 | 178 | ... 179 | } 180 | ``` 181 | 182 | **定制通道名字** 183 | 184 | 使用`@Input`和`@Output`注解,您可以为该channel指定一个自定义的channel名称,如下面的示例所示: 185 | ``` 186 | public interface Barista { 187 | ... 188 | @Input("inboundOrders") 189 | SubscribableChannel orders(); 190 | } 191 | ``` 192 | 在这个例子中,创建的绑定channel将被命名为inboundorders。 193 | 194 | **`Source`,`Sink`,`Processor`** 195 | 196 | 最常见的场景中,包含一个输入通道或者包含一个输出通道或者二者都包含,SpringCloudStream提供了三个开箱即用的预定义接口。 197 | 198 | `Source`用于有单个输出(outbound)通道的应用。 199 | ``` 200 | public interface Source { 201 | 202 | String OUTPUT = "output"; 203 | 204 | @Output(Source.OUTPUT) 205 | MessageChannel output(); 206 | 207 | } 208 | ``` 209 | `Sink`用于有单个输入(inbound)通道的应用。 210 | ``` 211 | public interface Sink { 212 | 213 | String INPUT = "input"; 214 | 215 | @Input(Sink.INPUT) 216 | SubscribableChannel input(); 217 | 218 | } 219 | ``` 220 | `Processor`用于单个应用同时包含输入和输出通道的情况。 221 | ``` 222 | public interface Processor extends Source, Sink { 223 | } 224 | ``` 225 | SpringCloudStream对这些接口不提供特殊的处理,仅提供开箱即用的特性。 226 | 227 | #### 访问绑定通道 228 | ** 注入已绑定接口 ** 229 | 230 | 对于每一个绑定的接口,SpringCloudStream将产生一个实现接口的bean,调用这个生成类的`@Input`或`@Output`方法,会返回一个相应的channel。 231 | 232 | 下面的例子中,当hello被调用时输出channel会发送一个消息,在注入的Sourc上提供唤醒output()来检索到目标通道 233 | ``` 234 | @Component 235 | public class SendingBean { 236 | 237 | private Source source; 238 | 239 | @Autowired 240 | public SendingBean(Source source) { 241 | this.source = source; 242 | } 243 | 244 | public void sayHello(String name) { 245 | source.output().send(MessageBuilder.withPayload(body).build()); 246 | } 247 | } 248 | ``` 249 | 250 | ** 直接注入到通道 ** 251 | 252 | 绑定的通道也可以直接注入 253 | ``` 254 | @Component 255 | public class SendingBean { 256 | 257 | private MessageChannel output; 258 | 259 | @Autowired 260 | public SendingBean(MessageChannel output) { 261 | this.output = output; 262 | } 263 | 264 | public void sayHello(String name) { 265 | output.send(MessageBuilder.withPayload(body).build()); 266 | } 267 | } 268 | ``` 269 | 如果channel的名字是在注解中指定的,那么请使用这个名字,而不是使用方法名。如下: 270 | ``` 271 | public interface CustomSource { 272 | ... 273 | @Output("customOutput") 274 | MessageChannel output(); 275 | } 276 | ``` 277 | 该通道将被注入,如下面的示例所示: 278 | ``` 279 | @Component 280 | public class SendingBean { 281 | 282 | @Autowired 283 | private MessageChannel output; 284 | 285 | @Autowired @Qualifier("customOutput") 286 | public SendingBean(MessageChannel output) { 287 | this.output = output; 288 | } 289 | 290 | public void sayHello(String name) { 291 | customOutput.send(MessageBuilder.withPayload(body).build()); 292 | } 293 | } 294 | ``` 295 | 296 | #### 生产和消费消息 297 | 298 | 可以使用Spring Integration的注解或者SpringCloudStream的`@StreamListener`注解来实现一个SpringCloudStream应用。`@StreamListener`注解模仿其他spring消息注解(例如`@MessageMapping`, `@JmsListener`, `@RabbitListener`等),但是它增加了内容类型管理和类型强制特性。 299 | 300 | ** 原生Spring Integration支持 ** 301 | 302 | SpringCloudStream是基于Spring Integration的,所以完全的继承了后者的基础设施以及构件本身,例如,可以将`Source`的output通道连接到一个`MessageSource` 303 | ``` 304 | @EnableBinding(Source.class) 305 | public class TimerSource { 306 | 307 | @Value("${format}") 308 | private String format; 309 | 310 | @Bean 311 | @InboundChannelAdapter(value = Source.OUTPUT, poller = @Poller(fixedDelay = "${fixedDelay}", maxMessagesPerPoll = "1")) 312 | public MessageSource timerMessageSource() { 313 | return () -> new GenericMessage<>(new SimpleDateFormat(format).format(new Date())); 314 | } 315 | } 316 | ``` 317 | 或者你可以在transformer中使用处理器的channels: 318 | ``` 319 | @EnableBinding(Processor.class) 320 | public class TransformProcessor { 321 | @Transformer(inputChannel = Processor.INPUT, outputChannel = Processor.OUTPUT) 322 | public Object transform(String message) { 323 | return message.toUpper(); 324 | } 325 | } 326 | ``` 327 | 328 | ** 使用`@StreamListener`进行自动内容类型处理 ** 329 | 330 | 作为原生Spring Integration的补充,SpringCloudStream提供了自己的`@StreamListener`注解,该注解模仿spring的其它消息注解(如`@MessageMapping`, `@JmsListener`, `@RabbitListener`等)。`@StreamListener`注解提供了一种更简单的模型来处理输入消息,尤其是处理包含内容类型管理和类型强制的用例的情况。 331 | 332 | SpringCloudStream提供了一个扩展的`MessageConverter`机制,该机制提供绑定通道实现数据处理,本例子中,数据会分发给带`@StreamListener`注解的方法。下面例子展示了处理外部`Vote`事件的应用: 333 | ``` 334 | @EnableBinding(Sink.class) 335 | public class VoteHandler { 336 | 337 | @Autowired 338 | VotingService votingService; 339 | 340 | @StreamListener(Sink.INPUT) 341 | public void handle(Vote vote) { 342 | votingService.record(vote); 343 | } 344 | } 345 | ``` 346 | `@StreamListener`和Spring Integration的`@ServiceActivator`是有区别的,区别体现在当输入消息内容头为application/json的字符串的时候,@StreamListener的MessageConverter机制会使用contentType头将string解析为Vote对象。 347 | 348 | 和其他Spring Messaging方法一样,方法参数可以被如下注解修饰,@Payload,@Headers和@Header 349 | 350 | > 对于那些有返回数据的方法,必须使用@SendTo注解来指定返回数据的输出绑定目标。 351 | 352 | ``` 353 | @EnableBinding(Processor.class) 354 | public class TransformProcessor { 355 | 356 | @Autowired 357 | VotingService votingService; 358 | 359 | @StreamListener(Processor.INPUT) 360 | @SendTo(Processor.OUTPUT) 361 | public VoteResult handle(Vote vote) { 362 | return votingService.record(vote); 363 | } 364 | } 365 | ``` 366 | > 在RabbitMQ中,内容类型头可以由外部应用设定。SpringCloudStream支持他们作为一个扩展的内部协议,用于任何类型的运输(包括运输,如Kafka,不能正常支持headers) 367 | 368 | #### 聚合 369 | 370 | SpringCloudStream可以支持多种应用聚合,直接连接他们的输入和输出channel,并避免通过代理交换消息的额外成本,截止1.0版本,聚合只支持以下类型的应用程序: 371 | 372 | * sources:带有名为output的单一输出channel的应用。典型情况下,该应用带有包含一个以下类型的绑定 373 | `org.springframework.cloud.stream.messaging.Source` 374 | 375 | * sinks:带有名为input的单一输入channel的应用。典型情况下,该应用带有包含一个以下类型的绑定 376 | `org.springframework.cloud.stream.messaging.Sink` 377 | 378 | * processors:带有名为input的单一输入channel和带有名为output的单一输出channel的应用。典型情况下,该应用带有包含一个以下类型的绑定`org.springframework.cloud.stream.messaging.Processor` 379 | 380 | 可以通过创建一个相互关联的应用的序列将他们聚合在一起,其中一个序列元素的输出通道连接到下一个其中一个元素的输出通道连接到下一个元素的输入通道元素的输入通道,序列可以由一个source或者一个processor开始,可以包含任意数目的processors,且必须由processors或者sink结束。 381 | 382 | 根据开始和结束元素的特性,序列可以有一个或者多个可绑定的channels,如下: 383 | 384 | * 如果序列由source开始,sink结束,应用之间直接通信并且不会绑定通道 385 | * 如果序列由processor开始,它的输入通道会变成聚合的input通道并进行相应的绑定 386 | * 如果序列由processor结束,它的输出通道会变成聚合的output通道并进行相应的绑定 387 | 388 | 使用AggregateApplicationBuilder功能类来实现聚合,如下例子所示。考虑一个包含source,processor和sink的工程,它们可以示包含在工程中,或者包含在工程的依赖中。 389 | ``` 390 | @SpringBootApplication 391 | @EnableBinding(Sink.class) 392 | public class SinkApplication { 393 | 394 | private static Logger logger = LoggerFactory.getLogger(SinkModuleDefinition.class); 395 | 396 | @ServiceActivator(inputChannel=Sink.INPUT) 397 | public void loggerSink(Object payload) { 398 | logger.info("Received: " + payload); 399 | } 400 | } 401 | ``` 402 | ``` 403 | @SpringBootApplication 404 | @EnableBinding(Processor.class) 405 | public class ProcessorApplication { 406 | 407 | @Transformer 408 | public String loggerSink(String payload) { 409 | return payload.toUpperCase(); 410 | } 411 | } 412 | ``` 413 | ``` 414 | @SpringBootApplication 415 | @EnableBinding(Source.class) 416 | public class SourceApplication { 417 | 418 | @Bean 419 | @InboundChannelAdapter(value = Source.OUTPUT) 420 | public String timerMessageSource() { 421 | return new SimpleDateFormat().format(new Date()); 422 | } 423 | } 424 | ``` 425 | 每一个配置可用于运行一个独立的组件,在这个例子中,它们可以这样实现聚合: 426 | ``` 427 | @SpringBootApplication 428 | public class SampleAggregateApplication { 429 | 430 | public static void main(String[] args) { 431 | new AggregateApplicationBuilder() 432 | .from(SourceApplication.class).args("--fixedDelay=5000") 433 | .via(ProcessorApplication.class) 434 | .to(SinkApplication.class).args("--debug=true").run(args); 435 | } 436 | } 437 | ``` 438 | 序列的开始组件作为from()方法的参数,序列的结束组件作为to()方法的参数,中间处理器作为via()方法的参数,同一类型的处理器可以链在一起(例如,可以使用不同配置的管道传输方式)。对于每一个组件,编译器可以为Spring Boot提供运行时参数。 439 | 440 | #### RxJava 支持 441 | 442 | RxJava 是一个响应式编程框架,SpringCloudStream通过`RxJavaProcessor`可以支持RxJava的processor,参见`spring-cloud-stream-rxjava` 443 | 444 | ``` 445 | public interface RxJavaProcessor { 446 | Observable process(Observable input); 447 | } 448 | ``` 449 | 450 | RxJavaProcessor(观察者设计模式)收到观察得到的对象Observable作为输入,相当于数据流的输入装载器。在启动时调用process方法来设置数据流。 451 | 452 | 用@EnableRxJavaProcessor修饰在你的处理方法上,就可以启用基于RxJava的处理器。@EnableRxJavaProcessor包含了@EnableBinding(Processor.class)注解并可以创建Processor,如下: 453 | ``` 454 | @EnableRxJavaProcessor 455 | public class RxJavaTransformer { 456 | 457 | private static Logger logger = LoggerFactory.getLogger(RxJavaTransformer.class); 458 | 459 | @Bean 460 | public RxJavaProcessor processor() { 461 | return inputStream -> inputStream.map(data -> { 462 | logger.info("Got data = " + data); 463 | return data; 464 | }) 465 | .buffer(5) 466 | .map(data -> String.valueOf(avg(data))); 467 | } 468 | 469 | private static Double avg(List data) { 470 | double sum = 0; 471 | double count = 0; 472 | for(String d : data) { 473 | count++; 474 | sum += Double.valueOf(d); 475 | } 476 | return sum/count; 477 | } 478 | } 479 | ``` 480 | > 实施RxJava处理器,处理流程中的异常特别重要,未捕获的异常将被视为errors,并会结束Observable,中断了处理流程。 481 | 482 | ## 绑定器 483 | 484 | SpringCloudStream提供绑定抽象用于与外部中间件中的物理目标进行连接。本章主要介绍Binder SPI背后的主要概念,主要组件以及实现细节。 485 | 486 | ### 生产者与消费者 487 | 488 | ![](/img/stream-producers-consumers.png) 489 | 490 | 任何往通道中发布消息的组件都可称作生产者。通道可以通过代理的Binder实现与外部消息代理进行绑定。调用bindProducer()方法,第一个参数是代理名称,第二个参数是本地通道目标名称(生产者向本地通道发送消息),第三个参数包含通道创建的适配器的属性信息(比如:分片key表达式)。 491 | 492 | 任何从通道中接收消息的组件都可称作消费者。与生产者一样,消费者通道可以与外部消息代理进行绑定。调用bindConsumer()方法,第一个参数是目标名称,第二个参数提供了消费者组的名称。每个组都会收到生产中发出消息的副本(即,发布-订阅语义),如果有多个消费者绑定相同的组名称,消息只会由一个消费者消费(即,队列语义) 493 | 494 | ### Binder SPI 495 | 496 | ### Binder Detection 497 | 498 | #### Classpath Detection 499 | 500 | ### Multiple Binders on the Classpath 501 | 502 | ### Connecting to Multiple Systems 503 | 504 | ### Binder configuration properties 505 | 506 | ### Implementation strategies 507 | 508 | #### Kafka Binder 509 | 510 | #### RabbitMQ Binder 511 | 512 | ## 配置管理 513 | 514 | SpringCloudStream 支持通用的配置以及bindings和binders的配置,一些binders允许binding属性用来支持中间件的特定功能。 515 | 516 | ### SpringCloudStream配置项 517 | 518 | **spring.cloud.stream.instanceCount** 519 | 520 | 应用程序的部署实例的数量。如果使用卡夫卡则会设置分区。 521 | 522 | Default: 1 523 | 524 | **spring.cloud.stream.instanceIndex** 525 | 526 | 应用程序的部署实例的数量,大小介于0 ~ (instanceCount-1),用于kafka寻找分区。在Cloud Foundry中会自动设置 527 | 528 | Default: 1 529 | 530 | **spring.cloud.stream.dynamicDestinations** 531 | 532 | A list of destinations that can be bound dynamically (for example, in a dynamic routing scenario). If set, only listed destinations can be bound. 533 | 534 | Default: empty 535 | 536 | **spring.cloud.stream.defaultBinder** 537 | 538 | The default binder to use, if multiple binders are configured 539 | 540 | Default: empty 541 | 542 | **spring.cloud.stream.overrideCloudConnectors** 543 | 544 | This property is only applicable when the cloud profile is active and Spring Cloud Connectors are provided with the application. If the property is false (the default), the binder will detect a suitable bound service (e.g. a RabbitMQ service bound in Cloud Foundry for the RabbitMQ binder) and will use it for creating connections (usually via Spring Cloud Connectors). When set to true, this property instructs binders to completely ignore the bound services and rely on Spring Boot properties (e.g. relying on the spring.rabbitmq.* properties provided in the environment for the RabbitMQ binder). The typical usage of this property is to be nested in a customized environment when connecting to multiple systems. 545 | 546 | Default: false 547 | 548 | ### Binding配置项 549 | 550 | 配置格式为`spring.cloud.stream.bindings..=`,``是配置的频道名称 (e.g., output for a Source),下面的介绍中省略`spring.cloud.stream.bindings..`前缀,只关注属性参数 551 | 552 | #### SpringCloudStream的bindings配置 553 | 554 | 下面的配置对于input bindings和output bindings都有效,且前缀是`spring.cloud.stream.bindings..` 555 | 556 | **destination** 557 | 558 | 绑定中间件的目的 (e.g., the RabbitMQ exchange or Kafka topic)。如果channel绑定的是消费者,那么可以绑定多个目的,用逗号分隔。如果不设置则channel名称会替代这个值。 559 | 560 | **group** 561 | 562 | channel的消费者组,仅对inbound bindings有效。 563 | 564 | Default: null (暗示一个匿名消费者) 565 | 566 | **contentType** 567 | 568 | The content type of the channel. 569 | 570 | Default: null (so that no type coercion is performed). 571 | 572 | **binder** 573 | 574 | The binder used by this binding. See Multiple Binders on the Classpath for details. 575 | 576 | Default: null (the default binder will be used, if one exists). 577 | 578 | #### Consumer properties 579 | 580 | 下面的配置仅对input bindings有效,且前缀是`spring.cloud.stream.bindings..consumer.` 581 | 582 | **concurrency** 583 | 584 | The concurrency of the inbound consumer. 585 | 586 | Default: 1 587 | 588 | **partitioned** 589 | 590 | Whether the consumer receives data from a partitioned producer. 591 | 592 | Default: false 593 | 594 | **headerMode** 595 | 596 | When set to raw, disables header parsing on input. Effective only for messaging middleware that does not support message headers natively and requires header embedding. Useful when inbound data is coming from outside Spring Cloud Stream applications. 597 | 598 | Default: embeddedHeaders. 599 | 600 | **maxAttempts** 601 | 602 | The number of attempts of re-processing an inbound message. 603 | 604 | Default: 3. 605 | 606 | **backOffInitialInterval** 607 | 608 | The backoff initial interval on retry. 609 | 610 | Default: 1000. 611 | 612 | **backOffMaxInterval** 613 | 614 | The maximum backoff interval. 615 | 616 | Default: 10000. 617 | 618 | **backOffMultiplier** 619 | 620 | The backoff multiplier. 621 | 622 | Default: 2.0. 623 | 624 | #### Producer Properties 625 | 626 | 下面的配置仅对output bindings有效,且前缀是`spring.cloud.stream.bindings..producer.` 627 | 628 | **partitionKeyExpression** 629 | 630 | A SpEL expression that determines how to partition outbound data. If set, or if partitionKeyExtractorClass is set, outbound data on this channel will be partitioned, and partitionCount must be set to a value greater than 1 to be effective. The two options are mutually exclusive. See Partitioning Support. 631 | 632 | Default: null. 633 | 634 | **partitionKeyExtractorClass** 635 | 636 | A PartitionKeyExtractorStrategy implementation. If set, or if partitionKeyExpression is set, outbound data on this channel will be partitioned, and partitionCount must be set to a value greater than 1 to be effective. The two options are mutually exclusive. See Partitioning Support. 637 | 638 | Default: null. 639 | 640 | **partitionSelectorClass** 641 | 642 | A PartitionSelectorStrategy implementation. Mutually exclusive with partitionSelectorExpression. If neither is set, the partition will be selected as the hashCode(key) % partitionCount, where key is computed via either partitionKeyExpression or partitionKeyExtractorClass. 643 | 644 | Default: null. 645 | 646 | **partitionSelectorExpression** 647 | 648 | A SpEL expression for customizing partition selection. Mutually exclusive with partitionSelectorClass. If neither is set, the partition will be selected as the hashCode(key) % partitionCount, where key is computed via either partitionKeyExpression or partitionKeyExtractorClass. 649 | 650 | Default: null. 651 | 652 | **partitionCount** 653 | 654 | The number of target partitions for the data, if partitioning is enabled. Must be set to a value greater than 1 if the producer is partitioned. On Kafka, interpreted as a hint; the larger of this and the partition count of the target topic is used instead. 655 | 656 | Default: 1. 657 | 658 | **requiredGroups** 659 | 660 | A comma-separated list of groups to which the producer must ensure message delivery even if they start after it has been created (e.g., by pre-creating durable queues in RabbitMQ). 661 | 662 | **headerMode** 663 | 664 | When set to raw, disables header embedding on output. Effective only for messaging middleware that does not support message headers natively and requires header embedding. Useful when producing data for non-Spring Cloud Stream applications. 665 | 666 | Default: embeddedHeaders. 667 | 668 | ## Binder-Specific Configuration 669 | 670 | ### Rabbit-Specific Settings 671 | 672 | #### RabbitMQ Binder Properties 673 | 674 | #### RabbitMQ Consumer Properties 675 | 676 | #### Rabbit Producer Properties 677 | 678 | ### Kafka-Specific Settings 679 | 680 | #### Kafka Binder Properties 681 | 682 | #### Kafka Consumer Properties 683 | 684 | #### Kafka Producer Properties 685 | 686 | ## Content Type and Transformation 687 | 688 | ### MIME types 689 | 690 | ### MIME types and Java types 691 | 692 | ### @StreamListener and Message Conversion 693 | 694 | ## 应用程序间通信 695 | 696 | ### 连接多个应用程序实例 697 | 698 | SpringCloudStream使SpringBoot应用连接消息系统变得容易,典型情况是多应用管道的创作,微服务通过这个管道彼此发送数据。 699 | 700 | 为了实现TimeSource应用的数据发送给LogSink应用,你可以通过配置相同的目的地名字来绑定他们。 701 | 702 | TimeSource的配置如下 703 | 704 | `spring.cloud.stream.bindings.output.destination=ticktock` 705 | 706 | LogSink的配置如下 707 | 708 | `spring.cloud.stream.bindings.input.destination=ticktock` 709 | 710 | ### 实例索引和实例数 711 | 712 | 当水平扩展SpringCloudStream应用时,每个实例都能收到消息,这个消息是关于本应用运行的实例数量和每个实例自己的索引值。利用`spring.cloud.stream.instanceCount`和`spring.cloud.stream.instanceIndex`就能做到上面的所述的功能。例如:如果有三个HDFS的sink application,这三个实例都设置了`spring.cloud.stream.instanceCount=3`,并且又分别设置了`spring.cloud.stream.instanceIndex`的值为0,1,2。 713 | 714 | 当SpringCloudStream应用通过SpringCloudDataFlow部署,这些参数会自动配置。如果是独立部署,那这些参数必须被正确配置。默认情况下,`spring.cloud.stream.instanceCount=1`,`spring.cloud.stream.instanceIndex=0` 715 | 716 | 水平扩展扩展的案例中,正确的配置这两个参数对于访问分区的行为十分重要,并且这两个参数需要确定的binders(e.g., the Kafka binder) ,上述是为了保证数据能被正确分配在多个消费端实例。 717 | 718 | ### 分区 719 | 720 | #### 配置Output Bindings 721 | 722 | output binding的配置是用于发送分区数据,配置`partitionKeyExpression`或`partitionKeyExtractorClass`以及`partitionCount`。例如,下面是一个有效的和典型的配置: 723 | 724 | ``` 725 | spring.cloud.stream.bindings.output.producer.partitionKeyExpression=payload.id 726 | spring.cloud.stream.bindings.output.producer.partitionCount=5 727 | ``` 728 | 729 | 基于上述的配置,数据将被用下述逻辑发送到目标分区。 730 | 731 | 分区key的值是基于partitionKeyExpression计算得出的,用于每个消息被发送至分区的输出channel,partitionKeyExpression是spirng EL表达式用以提取分区键。 732 | 733 | > 如果SpEL不能满足你的需求,你可以通过`partitionKeyExtractorClass`设置一个自定义的类去计算分区的key值,这个类需要实现`org.springframework.cloud.stream.binder.PartitionKeyExtractorStrategy`接口,通常情况下SpEL是够用的,更复杂的情况才会用到自定义的策略。 734 | 735 | 一旦消息的key被算出,分区选择器将会确定目标分区值,这个值介于0 和 partitionCount - 1之间,默认的算法,在大多数情况下适用,是基于公式的`key.hashcode() % partitioncount`。 736 | 737 | 额外的属性可以被配置为更高级的情况,如下面的章节所述。 738 | 739 | > Kafka binder使用`partitionCount`做创建topic的线索利用给定的分区数(这个数是`partitionCount`与`minPartitionCount`的最大值)。当为binder配置`minPartitionCount`,为应用配置`partitionCount`的时候你要小心,两者较大的值将会被使用。如果一个topic已经存在与小分区数的kafka中,并且`autoAddPartitions`是被禁用的(默认如此),那么binder将启动失败,如果`autoAddPartitions`是启用的则会自动添加新分区。如果topic已经存于大分区数的kafka(比`minPartitionCount` 和 `partitionCount`的值都大),这个存在的分区将会被使用。 740 | 741 | #### 配置Input Bindings 742 | 743 | 通过配置分区属性来接收分区中的数据,如下面的示例: 744 | ``` 745 | spring.cloud.stream.bindings.input.consumer.partitioned=true 746 | spring.cloud.stream.instanceIndex=3 747 | spring.cloud.stream.instanceCount=5 748 | ``` 749 | 750 | `instanceCount`表示应用实例的总数,`instanceIndex`在多个实例中必须唯一,并介于0~(instanceCount-1)之间。实例的索引可以帮助每个实例确定唯一的接收数据的分区,正确的设置这两个值十分重要,用来确保所有的数据被消耗,以及应用实例接收相互排斥的数据集。 751 | 752 | 使用多实例进行分区数据处理是一个复杂设置,SpringCloudDataFlow可以显著的简化过程,通过正确的填写输入和输出值,以及信任运行时提供的instance索引和instance数量信息 753 | 754 | ## Testing 755 | 756 | ## 健康指示器 757 | 758 | SpringCloudStream提供binders健康指示器,他以binders名字注册,可以由`management.health.binders.enabled`开控制启动或停止 759 | 760 | ## 例子 761 | 762 | [spring-cloud-stream-samples](https://github.com/spring-cloud/spring-cloud-stream-samples) 763 | 764 | ## Getting Started 765 | 766 | 767 | 768 | 769 | 770 | 771 | -------------------------------------------------------------------------------- /docs/about/release-notes.md: -------------------------------------------------------------------------------- 1 | # Release Notes 2 | 3 | --- 4 | 5 | ## Upgrading 6 | 7 | To upgrade MkDocs to the latest version, use pip: 8 | 9 | pip install -U mkdocs 10 | 11 | You can determine your currently installed version using `mkdocs --version`: 12 | 13 | $ mkdocs --version 14 | mkdocs, version 0.15.2 15 | 16 | ## Maintenance team 17 | 18 | The current and past members of the MkDocs team. 19 | 20 | * [@tomchristie](https://github.com/tomchristie/) 21 | * [@d0ugal](https://github.com/d0ugal/) 22 | * [@waylan](https://github.com/waylan/) 23 | 24 | ## Version 0.16 (2016-11-04) 25 | 26 | ### Major Additions to Version 0.16.0 27 | 28 | #### Template variables refactored. (#874) 29 | 30 | ##### Page Context 31 | 32 | Page specific variable names in the template context have been refactored as 33 | defined in [Custom Themes](../user-guide/custom-themes/#page). The 34 | old variable names will issue a warning but continue to work for version 0.16, 35 | but may be removed in a future version. 36 | 37 | Any of the following old page variables should be updated to the new ones in 38 | user created and third-party templates: 39 | 40 | | Old Variable Name | New Variable Name | 41 | | ----------------- | ------------------- | 42 | | current_page | [page] | 43 | | page_title | [page.title] | 44 | | content | [page.content] | 45 | | toc | [page.toc] | 46 | | meta | [page.meta] | 47 | | canonical_url | [page.canonical_url]| 48 | | previous_page | [page.previous_page]| 49 | | next_page | [page.next_page] | 50 | 51 | [page]: ../user-guide/custom-themes/#page 52 | [page.title]: ../user-guide/custom-themes/#pagetitle 53 | [page.content]: ../user-guide/custom-themes/#pagecontent 54 | [page.toc]: ../user-guide/custom-themes/#pagetoc 55 | [page.meta]: ../user-guide/custom-themes/#pagemeta 56 | [page.canonical_url]: ../user-guide/custom-themes/#pagecanonical_url 57 | [page.previous_page]: ../user-guide/custom-themes/#pageprevious_page 58 | [page.next_page]: ../user-guide/custom-themes/#pagenext_page 59 | 60 | ##### Global Context 61 | 62 | Additionally, a number of global variables have been altered and/or deprecated 63 | and user created and third-party templates should be updated as outlined below: 64 | 65 | Previously, the global variable `include_nav` was altered programmatically based 66 | on the number of pages in the nav. The variable will issue a warning but 67 | continue to work for version 0.16, but may be removed in a future version. Use 68 | `{% if nav|length>1 %}` instead. 69 | 70 | Previously, the global variable `include_next_prev` was altered programmatically 71 | based on the number of pages in the nav. The variable will issue a warning but 72 | continue to work for version 0.16, but may be removed in a future version. Use 73 | `{% if page.next_page or page.previous_page %}` instead. 74 | 75 | Previously the global variable `page_description` was altered programmatically 76 | based on whether the current page was the homepage. Now it simply maps to 77 | `config['site_description']`. Use `{% if page.is_homepage %}` in the template to 78 | conditionally change the description. 79 | 80 | The global variable `homepage_url` maps directly to `nav.homepage.url` and is 81 | being deprecated. The variable will issue a warning but continue to work for 82 | version 0.16, but may be removed in a future version. Use `nav.homepage.url` 83 | instead. 84 | 85 | The global variable `favicon` maps to the configuration setting `site_favicon`. 86 | Both the template variable and the configuration setting are being deprecated 87 | and will issue a warning but continue to work for version 0.16, and may be 88 | removed in a future version. Use `{{ base_url }}/img/favicon.ico` in your 89 | template instead. Users can simply save a copy of their custom favicon icon to 90 | `img/favicon.ico` in either their `docs_dir` or `theme_dir`. 91 | 92 | A number of variables map directly to similarly named variables in the `config`. 93 | Those variables are being deprecated and will issue a warning but continue to 94 | work for version 0.16, but may be removed in a future version. Use 95 | `config.var_name` instead, where `var_name` is the name of one of the 96 | [configuration] variables. 97 | 98 | [configuration]: /user-guide/configuration.md 99 | 100 | Below is a summary of all of the changes made to the global context: 101 | 102 | | Old Variable Name | New Variable Name or Expression | 103 | | ----------------- | -------------------------------------- | 104 | | current_page | page | 105 | | include_nav | nav|length>1 | 106 | | include_next_prev | (page.next_page or page.previous_page) | 107 | | site_name | config.site_name | 108 | | site_author | config.site_author | 109 | | page_description | config.site_description | 110 | | repo_url | config.repo_url | 111 | | repo_name | config.repo_name | 112 | | site_url | config.site_url | 113 | | copyright | config.copyright | 114 | | google_analytics | config.google_analytics | 115 | | homepage_url | nav.homepage.url | 116 | | favicon | {{ base_url }}/img/favicon.ico | 117 | 118 | #### Increased Template Customization. (#607) 119 | 120 | The built-in themes have been updated by having each of their many parts wrapped 121 | in template blocks which allow each individual block to be easily overridden 122 | using the `theme_dir` config setting. Without any new settings, you can use a 123 | different analytics service, replace the default search function, or alter the 124 | behavior of the navigation, among other things. See the relevant 125 | [documentation][blocks] for more details. 126 | 127 | To enable this feature, the primary entry point for page templates has been 128 | changed from `base.html` to `main.html`. This allows `base.html` to continue to 129 | exist while allowing users to override `main.html` and extend `base.html`. For 130 | version 0.16, `base.html` will continue to work if no `main.html` template 131 | exists, but it is deprecated and will raise a warning. In version 1.0, a build 132 | will fail if no `main.html` template exists. Any custom and third party 133 | templates should be updated accordingly. 134 | 135 | The easiest way for a third party theme to be updated would be to simply add a 136 | `main.html` file which only contains the following line: 137 | 138 | ```django 139 | {% extends "base.html" %} 140 | ``` 141 | 142 | That way, the theme contains the `main.html` entry point, and also supports 143 | overriding blocks in the same manner as the built-in themes. Third party themes 144 | are encouraged to wrap the various pieces of their templates in blocks in order 145 | to support such customization. 146 | 147 | [blocks]: ../user-guide/styling-your-docs/#overriding-template-blocks 148 | 149 | #### Auto-Populated `extra_css` and `extra_javascript` Deprecated. (#986) 150 | 151 | In previous versions of MkDocs, if the `extra_css` or `extra_javascript` config 152 | settings were empty, MkDocs would scan the `docs_dir` and auto-populate each 153 | setting with all of the CSS and JavaScript files found. This behavior is 154 | deprecated and a warning will be issued. In the next release, the auto-populate 155 | feature will stop working and any unlisted CSS and JavaScript files will not be 156 | included in the HTML templates. In other words, they will still be copied to the 157 | `site-dir`, but they will not have any effect on the theme if they are not 158 | explicitly listed. 159 | 160 | All CSS and javaScript files in the `docs_dir` should be explicitly listed in 161 | the `extra_css` or `extra_javascript` config settings going forward. 162 | 163 | #### Support for dirty builds. (#990) 164 | 165 | For large sites the build time required to create the pages can become problematic, 166 | thus a "dirty" build mode was created. This mode simply compares the modified time 167 | of the generated HTML and source markdown. If the markdown has changed since the 168 | HTML then the page is re-constructed. Otherwise, the page remains as is. This mode 169 | may be invoked in both the `mkdocs serve` and `mkdocs build` commands: 170 | 171 | ```text 172 | mkdocs serve --dirtyreload 173 | ``` 174 | 175 | ```text 176 | mkdocs build --dirty 177 | ``` 178 | 179 | It is important to note that this method for building the pages is for development 180 | of content only, since the navigation and other links do not get updated on other 181 | pages. 182 | 183 | #### Stricter Directory Validation 184 | 185 | Previously, a warning was issued if the `site_dir` was a child directory of the 186 | `docs_dir`. This now raises an error. Additionally, an error is now raised if 187 | the `docs_dir` is set to the directory which contains your config file rather 188 | than a child directory. You will need to rearrange you directory structure to 189 | better conform with the documented [layout]. 190 | 191 | [layout]: ../user-guide/writing-your-docs/#file-layout 192 | 193 | ### Other Changes and Additions to Version 0.16.0 194 | 195 | * Bugfix: Support `gh-deploy` command on Windows with Python 3 (#722) 196 | * Bugfix: Include .woff2 font files in Python package build (#894) 197 | * Various updates and improvements to Documentation Home Page/Tutorial (#870) 198 | * Bugfix: Support livereload for config file changes (#735) 199 | * Bugfix: Non-media template files are no longer copied with media files (#807) 200 | * Add a flag (-e/--theme-dir) to specify theme directory with the commands 201 | `mkdocs build` and `mkdocs serve` (#832) 202 | * Fixed issues with Unicode file names under Windows and Python 2. (#833) 203 | * Improved the styling of in-line code in the MkDocs theme. (#718) 204 | * Bugfix: convert variables to JSON when being passed to JavaScript (#850) 205 | * Updated the ReadTheDocs theme to match the upstream font sizes and colors 206 | more closely. (#857) 207 | * Fixes an issue with permalink markers showing when the mouse was far above 208 | them (#843) 209 | * Bugfix: Handle periods in directory name when automatically creating the 210 | pages config. (#728) 211 | * Update searching to Lunr 0.7, which comes with some performance enhancements 212 | for larger documents (#859) 213 | * Bugfix: Support SOURCE_DATE_EPOCH environment variable for "reproducible" 214 | builds (#938) 215 | * Follow links when copying media files (#869). 216 | * Change "Edit on..." links to point directly to the file in the source 217 | repository, rather than to the root of the repository (#975), configurable 218 | via the new [`edit_uri`](../user-guide/configuration.md#edit_uri) setting. 219 | * Bugfix: Don't override config value for strict mode if not specified on CLI 220 | (#738). 221 | * Add a `--force` flag to the `gh-deploy` command to force the push to the 222 | repository (#973). 223 | * Improve alignment for current selected menu item in readthedocs theme (#888). 224 | * `http://user.github.io/repo` => `https://user.github.io/repo/` (#1029). 225 | * Improve installation instructions (#1028). 226 | * Account for wide tables and consistently wrap inline code spans (#834). 227 | * Bugfix: Use absolute URLs in nav & media links from error templates (#77). 228 | 229 | ## Version 0.15.3 (2016-02-18) 230 | 231 | * Improve the error message the given theme can't be found. 232 | * Fix an issue with relative symlinks (#639) 233 | 234 | ## Version 0.15.2 (2016-02-08) 235 | 236 | * Fix an incorrect warning that states external themes [will be removed from 237 | MkDocs](#add-support-for-installable-themes). 238 | 239 | ## Version 0.15.1 (2016-01-30) 240 | 241 | * Lower the minimum supported Click version to 3.3 for package maintainers. 242 | (#763) 243 | 244 | ## Version 0.15.0 (2016-01-21) 245 | 246 | ### Major Additions to Version 0.15.0 247 | 248 | #### Add support for installable themes 249 | 250 | MkDocs now supports themes that are distributed via Python packages. With this 251 | addition, the Bootstrap and Bootswatch themes have been moved to external git 252 | repositories and python packages. See their individual documentation for more 253 | details about these specific themes. 254 | 255 | * [MkDocs Bootstrap] 256 | * [MkDocs Bootswatch] 257 | 258 | [MkDocs Bootstrap]: http://mkdocs.github.io/mkdocs-bootstrap/ 259 | [MkDocs Bootswatch]: http://mkdocs.github.io/mkdocs-bootswatch/ 260 | 261 | They will be included with MkDocs by default until a future release. After that 262 | they will be installable with pip: `pip install mkdocs-bootstrap` and `pip 263 | install mkdocs-bootswatch` 264 | 265 | See the documentation for [Styling your docs] for more information about using 266 | and customising themes and [Custom themes] for creating and distributing new 267 | themes 268 | 269 | [Styling your docs]: /user-guide/styling-your-docs.md 270 | [Custom themes]: /user-guide/custom-themes.md 271 | 272 | ### Other Changes and Additions to Version 0.15.0 273 | 274 | * Fix issues when using absolute links to Markdown files. (#628) 275 | * Deprecate support of Python 2.6, pending removal in 1.0.0. (#165) 276 | * Add official support for Python version 3.5. 277 | * Add support for [site_description] and [site_author] to the [ReadTheDocs] 278 | theme. (#631) 279 | * Update FontAwesome to 4.5.0. (#789) 280 | * Increase IE support with X-UA-Compatible. (#785) 281 | * Added support for Python's `-m` flag. (#706) 282 | * Bugfix: Ensure consistent ordering of auto-populated pages. (#638) 283 | * Bugfix: Scroll the tables of contents on the MkDocs theme if it is too long 284 | for the page. (#204) 285 | * Bugfix: Add all ancestors to the page attribute `ancestors` rather than just 286 | the initial one. (#693) 287 | * Bugfix: Include HTML in the build output again. (#691) 288 | * Bugfix: Provide filename to Read the Docs. (#721 and RTD#1480) 289 | * Bugfix: Silence Click's unicode_literals warning. (#708) 290 | 291 | [site_description]: /user-guide/configuration.md#site_description 292 | [site_author]: /user-guide/configuration.md#site_author 293 | [ReadTheDocs]: /user-guide/styling-your-docs.md#readthedocs 294 | 295 | ## Version 0.14.0 (2015-06-09) 296 | 297 | * Improve Unicode handling by ensuring that all config strings are loaded as 298 | Unicode. (#592) 299 | * Remove dependancy on the six library. (#583) 300 | * Remove dependancy on the ghp-import library. (#547) 301 | * Add `--quiet` and `--verbose` options to all subcommands. (#579) 302 | * Add short options (`-a`) to most command line options. (#579) 303 | * Add copyright footer for readthedocs theme. (#568) 304 | * If the requested port in `mkdocs serve` is already in use, don't show the 305 | user a full stack trace. (#596) 306 | * Bugfix: Fix a JavaScript encoding problem when searching with spaces. (#586) 307 | * Bugfix: gh-deploy now works if the mkdocs.yml is not in the git repo root. 308 | (#578) 309 | * Bugfix: Handle (pass-through instead of dropping) HTML entities while 310 | parsing TOC. (#612) 311 | * Bugfix: Default extra_templates to an empty list, don't automatically 312 | discover them. (#616) 313 | 314 | ## Version 0.13.3 (2015-06-02) 315 | 316 | * Bugfix: Reduce validation error to a warning if the site_dir is within 317 | the docs_dir as this shouldn't cause any problems with building but will 318 | inconvenience users building multiple times. (#580) 319 | 320 | ## Version 0.13.2 (2015-05-30) 321 | 322 | * Bugfix: Ensure all errors and warnings are logged before exiting. (#536) 323 | * Bugfix: Fix compatibility issues with ReadTheDocs. (#554) 324 | 325 | ## Version 0.13.1 (2015-05-27) 326 | 327 | * Bugfix: Fix a problem with minimal configurations which only contain a list 328 | of paths in the pages config. (#562) 329 | 330 | ## Version 0.13.0 (2015-05-26) 331 | 332 | ### Deprecations to Version 0.13.0 333 | 334 | #### Deprecate the JSON command 335 | 336 | In this release the `mkdocs json` command has been marked as deprecated and 337 | when used a deprecation warning will be shown. It will be removed in a [future 338 | release] of MkDocs, version 1.0 at the latest. The `mkdocs json` command 339 | provided a convenient way for users to output the documentation contents as 340 | JSON files but with the additions of search to MkDocs this functionality is 341 | duplicated. 342 | 343 | A new index with all the contents from a MkDocs build is created in the 344 | [site_dir], so with the default value for the `site_dir` It can be found in 345 | `site/mkdocs/search_index.json`. 346 | 347 | This new file is created on every MkDocs build (with `mkdocs build`) and 348 | no configuration is needed to enable it. 349 | 350 | [future release]: https://github.com/mkdocs/mkdocs/pull/481 351 | [site_dir]: /user-guide/configuration.md#site_dir 352 | 353 | #### Change the pages configuration 354 | 355 | Provide a [new way] to define pages, and specifically [nested pages], in the 356 | mkdocs.yml file and deprecate the existing approach, support will be removed 357 | with MkDocs 1.0. 358 | 359 | [new way]: /user-guide/writing-your-docs.md#configure-pages-and-navigation 360 | [nested pages]: /user-guide/writing-your-docs.md#multilevel-documentation 361 | 362 | #### Warn users about the removal of builtin themes 363 | 364 | All themes other than mkdocs and readthedocs will be moved into external 365 | packages in a future release of MkDocs. This will enable them to be more easily 366 | supported and updates outside MkDocs releases. 367 | 368 | ### Major Additions to Version 0.13.0 369 | 370 | #### Search 371 | 372 | Support for search has now been added to MkDocs. This is based on the 373 | JavaScript library [lunr.js]. It has been added to both the `mkdocs` and 374 | `readthedocs` themes. See the custom theme documentation on [supporting search] 375 | for adding it to your own themes. 376 | 377 | [lunr.js]: http://lunrjs.com/ 378 | [supporting search]: /user-guide/styling-your-docs.md#search-and-themes 379 | 380 | #### New Command Line Interface 381 | 382 | The command line interface for MkDocs has been re-written with the Python 383 | library [Click]. This means that MkDocs now has an easier to use interface 384 | with better help output. 385 | 386 | This change is partially backwards incompatible as while undocumented it was 387 | possible to pass any configuration option to the different commands. Now only 388 | a small subset of the configuration options can be passed to the commands. To 389 | see in full commands and available arguments use `mkdocs --help` and 390 | `mkdocs build --help` to have them displayed. 391 | 392 | [Click]: http://click.pocoo.org/4/ 393 | 394 | #### Support Extra HTML and XML files 395 | 396 | Like the [extra_javascript] and [extra_css] configuration options, a new 397 | option named [extra_templates] has been added. This will automatically be 398 | populated with any `.html` or `.xml` files in the project docs directory. 399 | 400 | Users can place static HTML and XML files and they will be copied over, or they 401 | can also use Jinja2 syntax and take advantage of the [global variables]. 402 | 403 | By default MkDocs will use this approach to create a sitemap for the 404 | documentation. 405 | 406 | [extra_javascript]: /user-guide/configuration.md#extra_javascript 407 | [extra_css]: /user-guide/configuration.md#extra_css 408 | [extra_templates]: /user-guide/configuration.md#extra_templates 409 | [global variables]: /user-guide/styling-your-docs.md#global-context 410 | 411 | ### Other Changes and Additions to Version 0.13.0 412 | 413 | * Add support for [Markdown extension configuration options]. (#435) 414 | * MkDocs now ships Python [wheels]. (#486) 415 | * Only include the build date and MkDocs version on the homepage. (#490) 416 | * Generate sitemaps for documentation builds. (#436) 417 | * Add a clearer way to define nested pages in the configuration. (#482) 418 | * Add an [extra config] option for passing arbitrary variables to the template. (#510) 419 | * Add `--no-livereload` to `mkdocs serve` for a simpler development server. (#511) 420 | * Add copyright display support to all themes (#549) 421 | * Add support for custom commit messages in a `mkdocs gh-deploy` (#516) 422 | * Bugfix: Fix linking to media within the same directory as a markdown file 423 | called index.md (#535) 424 | * Bugfix: Fix errors with unicode filenames (#542). 425 | 426 | [extra config]: /user-guide/configuration.md#extra 427 | [Markdown extension configuration options]: /user-guide/configuration.md#markdown_extensions 428 | [wheels]: http://pythonwheels.com/ 429 | 430 | ## Version 0.12.2 (2015-04-22) 431 | 432 | * Bugfix: Fix a regression where there would be an error if some child titles 433 | were missing but others were provided in the pages config. (#464) 434 | 435 | ## Version 0.12.1 (2015-04-14) 436 | 437 | * Bugfix: Fixed a CSS bug in the table of contents on some browsers where the 438 | bottom item was not clickable. 439 | 440 | ## Version 0.12.0 (2015-04-14) 441 | 442 | * Display the current MkDocs version in the CLI output. (#258) 443 | * Check for CNAME file when using gh-deploy. (#285) 444 | * Add the homepage back to the navigation on all themes. (#271) 445 | * Add a strict more for local link checking. (#279) 446 | * Add Google analytics support to all themes. (#333) 447 | * Add build date and MkDocs version to the ReadTheDocs and MkDocs theme 448 | outputs. (#382) 449 | * Standardise highlighting across all themes and add missing languages. (#387) 450 | * Add a verbose flag. (-v) to show more details about what the build. (#147) 451 | * Add the option to specify a remote branch when deploying to GitHub. This 452 | enables deploying to GitHub pages on personal and repo sites. (#354) 453 | * Add favicon support to the ReadTheDocs theme HTML. (#422) 454 | * Automatically refresh the browser when files are edited. (#163) 455 | * Bugfix: Never re-write URL's in code blocks. (#240) 456 | * Bugfix: Don't copy ditfiles when copying media from the `docs_dir`. (#254) 457 | * Bugfix: Fix the rendering of tables in the ReadTheDocs theme. (#106) 458 | * Bugfix: Add padding to the bottom of all bootstrap themes. (#255) 459 | * Bugfix: Fix issues with nested Markdown pages and the automatic pages 460 | configuration. (#276) 461 | * Bugfix: Fix a URL parsing error with GitHub enterprise. (#284) 462 | * Bugfix: Don't error if the mkdocs.yml is completely empty. (#288) 463 | * Bugfix: Fix a number of problems with relative urls and Markdown files. (#292) 464 | * Bugfix: Don't stop the build if a page can't be found, continue with other 465 | pages. (#150) 466 | * Bugfix: Remove the site_name from the page title, this needs to be added 467 | manually. (#299) 468 | * Bugfix: Fix an issue with table of contents cutting off Markdown. (#294) 469 | * Bugfix: Fix hostname for BitBucket. (#339) 470 | * Bugfix: Ensure all links end with a slash. (#344) 471 | * Bugfix: Fix repo links in the readthedocs theme. (#365) 472 | * Bugfix: Include jQuery locally to avoid problems using MkDocs offline. (#143) 473 | * Bugfix: Don't allow the docs_dir to be in the site_dir or vice versa. (#384) 474 | * Bugfix: Remove inline CSS in the ReadTheDocs theme. (#393) 475 | * Bugfix: Fix problems with the child titles due to the order the pages config 476 | was processed. (#395) 477 | * Bugfix: Don't error during live reload when the theme doesn't exist. (#373) 478 | * Bugfix: Fix problems with the Meta extension when it may not exist. (#398) 479 | * Bugfix: Wrap long inline code otherwise they will run off the screen. (#313) 480 | * Bugfix: Remove HTML parsing regular expressions and parse with HTMLParser to 481 | fix problems with titles containing code. (#367) 482 | * Bugfix: Fix an issue with the scroll to anchor causing the title to be hidden 483 | under the navigation. (#7) 484 | * Bugfix: Add nicer CSS classes to the HTML tables in bootswatch themes. (#295) 485 | * Bugfix: Fix an error when passing in a specific config file with 486 | `mkdocs serve`. (#341) 487 | * Bugfix: Don't overwrite index.md diles with the `mkdocs new` command. (#412) 488 | * Bugfix: Remove bold and italic from code in the ReadTheDocs theme. (#411) 489 | * Bugfix: Display images inline in the MkDocs theme. (#415) 490 | * Bugfix: Fix problems with no-highlight in the ReadTheDocs theme. (#319) 491 | * Bugfix: Don't delete hidden files when using `mkdocs build --clean`. (#346) 492 | * Bugfix: Don't block newer verions of Python-markdown on Python >= 2.7. (#376) 493 | * Bugfix: Fix encoding issues when opening files across platforms. (#428) 494 | 495 | ## Version 0.11.1 (2014-11-20) 496 | 497 | * Bugfix: Fix a CSS wrapping issue with code highlighting in the ReadTheDocs 498 | theme. (#233) 499 | 500 | ## Version 0.11.0 (2014-11-18) 501 | 502 | * Render 404.html files if they exist for the current theme. (#194) 503 | * Bugfix: Fix long nav bars, table rendering and code highlighting in MkDocs 504 | and ReadTheDocs themes. (#225) 505 | * Bugfix: Fix an issue with the google_analytics code. (#219) 506 | * Bugfix: Remove `__pycache__` from the package tar. (#196) 507 | * Bugfix: Fix markdown links that go to an anchor on the current page. (#197) 508 | * Bugfix: Don't add `prettyprint well` CSS classes to all HTML, only add it in 509 | the MkDocs theme. (#183) 510 | * Bugfix: Display section titles in the ReadTheDocs theme. (#175) 511 | * Bugfix: Use the polling observer in watchdog so rebuilding works on 512 | filesystems without inotify. (#184) 513 | * Bugfix: Improve error output for common configuration related errors. (#176) 514 | 515 | ## Version 0.10.0 (2014-10-29) 516 | 517 | * Added support for Python 3.3 and 3.4. (#103) 518 | * Configurable Python-Markdown extensions with the config setting 519 | `markdown_extensions`. (#74) 520 | * Added `mkdocs json` command to output your rendered 521 | documentation as json files. (#128) 522 | * Added `--clean` switch to `build`, `json` and `gh-deploy` commands to 523 | remove stale files from the output directory. (#157) 524 | * Support multiple theme directories to allow replacement of 525 | individual templates rather than copying the full theme. (#129) 526 | * Bugfix: Fix `
    ` rendering in readthedocs theme. (#171) 527 | * Bugfix: Improve the readthedocs theme on smaller displays. (#168) 528 | * Bugfix: Relaxed required python package versions to avoid clashes. (#104) 529 | * Bugfix: Fix issue rendering the table of contents with some configs. (#146) 530 | * Bugfix: Fix path for embedded images in sub pages. (#138) 531 | * Bugfix: Fix `use_directory_urls` config behaviour. (#63) 532 | * Bugfix: Support `extra_javascript` and `extra_css` in all themes. (#90) 533 | * Bugfix: Fix path-handling under Windows. (#121) 534 | * Bugfix: Fix the menu generation in the readthedocs theme. (#110) 535 | * Bugfix: Fix the mkdocs command creation under Windows. (#122) 536 | * Bugfix: Correctly handle external `extra_javascript` and `extra_css`. (#92) 537 | * Bugfix: Fixed favicon support. (#87) 538 | -------------------------------------------------------------------------------- /docs/user-guide/sleuth.md: -------------------------------------------------------------------------------- 1 | > 译者:楠倏之语 / xc8609@126.com 2 | > 3 | > 原文地址:[Spring Cloud Sleuth使用简介](http://blog.csdn.net/u010257992/article/details/52474639) 4 | > 5 | > 绝大部分出自原文,部分做了微调。 6 | 7 | # Spring Cloud Sleuth 8 | 9 | SpringCloudSleuth提供了分布式追踪的解决方案。 10 | 11 | ## 术语 12 | 13 | SpringCloudSleuth 借用了 Dapper 的术语 14 | 15 | - **Span:** 基本工作单元,例如,在一个新建的span中发送一个RPC等同于发送一个回应请求给RPC,span通过一个64位ID唯一标识,trace以另一个64位ID表示,span还有其他数据信息,比如摘要、时间戳事件、关键值注释(tags)、span的ID、以及进度ID(通常是IP地址) 16 | span在不断的启动和停止,同时记录了时间信息,当你创建了一个span,你必须在未来的某个时刻停止它。 17 | 18 | > `root span`的SpanID和TraneID相等。 19 | 20 | - **Trace:** 一系列spans组成的一个树状结构,例如,如果你正在跑一个分布式大数据工程,你可能需要创建一个trace。 21 | - **Annotation:** 用来及时记录一个事件的存在,一些核心annotations用来定义一个请求的开始和结束 22 | - cs:Client Sent - 客户端发起一个请求,这个annotion描述了这个span的开始 23 | - sr:Server Received - 服务端获得请求并准备开始处理它,如果将其sr减去cs时间戳便可得到网络延迟 24 | - ss:Server Sent - 注解表明请求处理的完成(当请求返回客户端),如果ss减去sr时间戳便可得到服务端需要的处理请求时间 25 | - cr:Client Received - 表明span的结束,客户端成功接收到服务端的回复,如果cr减去cs时间戳便可得到客户端从服务端获取回复的所有所需时间 26 | 27 | 将Span和Trace在一个系统中使用Zipkin注解的过程图形化: 28 | 29 | ![](/img/sleuth-traceid.png) 30 | 31 | 每个颜色的注解表明一个span(总计7个spans,从**A**到**G**),如果在注解中有这样的信息: 32 | 33 | ``` 34 | Trace Id = X 35 | Span Id = D 36 | Client Sent 37 | ``` 38 | 39 | 这就表明当前span将**Trace-Id**设置为**X**,将**Span-Id**设置为**D**,同时它还表明了**Client Sent**事件。 40 | 41 | spans 的parent/child关系图形化: 42 | 43 | ![](/img/sleuth-parents.png) 44 | 45 | --- 46 | 47 | ## 目的 48 | 49 | 下面章节的例子是基于上图描述的场景 50 | 51 | ### 基于Zipkin的分布式追踪 52 | 53 | 总计10个spans,如果在Zipkin中查看traces将看到如下图: 54 | 55 | ![](/img/sleuth-zipkin-traces.png) 56 | 57 | 但如果你选取一个特殊的trace你将看到7个spans: 58 | 59 | ![](/img/sleuth-zipkin-ui.png) 60 | 61 | > 当选取一个特殊trace时你会看到合并的spans,这意味着如果有两个spans使用客户端接收发送/服务端接收发送注解发送至Zipkin时,他们将表现为一个单独的span 62 | 63 | 在展示Span和Trace图形化的图片中有20个颜色标签,Zipkin又是如何接收10个spans的呢? 64 | 65 | - 2个span A标签表明span的开始和结束,接近结束时一个单独的span发送给Zipkin 66 | - 4个span B标签实际上是一个有4个注解的单独span,然而这个span是由两个分离的实例组成的,一个由 service 1发出,一个由service 2发出,因此实际上两个span实例是发送到Zipkin并在那合并 67 | - 2个span C标签表明span的开始和结束,接近结束时一个单独的span发送给Zipkin 68 | - 4个span D标签实际上是一个有4个注解的单独span,然而这个span是由两个分离的实例组成的,一个由 service 2发出,一个由service 3发出,因此实际上两个span实例是发送到Zipkin并在那合并 69 | - 2个span E标签表明span的开始和结束,接近结束时一个单独的span发送给Zipkin 70 | - 4个span F标签实际上是一个有4个注解的单独span,然而这个span是由两个分离的实例组成的,一个由 service 2发出,一个由service 4发出,因此实际上两个span实例是发送到Zipkin并在那合并 71 | - 2个span G标签表明span的开始和结束,接近结束时一个单独的span发送给Zipkin 72 | 73 | 因此1个span来自A,2个span来自B,1个span来自C,2个span来自D,1个span来自E,2个span来自F,1个来自G,总计10个spans。 74 | 75 | Zipkin中的依赖图: 76 | 77 | ![](/img/sleuth-dependencies.png) 78 | 79 | ### Log相关 80 | 81 | 当使用trace id为`2485ec27856c56f4`抓取这四个应用的log时,会获得如下输出: 82 | 83 | ``` 84 | service1.log:2016-02-26 11:15:47.561 INFO [service1,2485ec27856c56f4,2485ec27856c56f4,true] 68058 --- [nio-8081-exec-1] i.s.c.sleuth.docs.service1.Application : Hello from service1. Calling service2 85 | service2.log:2016-02-26 11:15:47.710 INFO [service2,2485ec27856c56f4,9aa10ee6fbde75fa,true] 68059 --- [nio-8082-exec-1] i.s.c.sleuth.docs.service2.Application : Hello from service2. Calling service3 and then service4 86 | service3.log:2016-02-26 11:15:47.895 INFO [service3,2485ec27856c56f4,1210be13194bfe5,true] 68060 --- [nio-8083-exec-1] i.s.c.sleuth.docs.service3.Application : Hello from service3 87 | service2.log:2016-02-26 11:15:47.924 INFO [service2,2485ec27856c56f4,9aa10ee6fbde75fa,true] 68059 --- [nio-8082-exec-1] i.s.c.sleuth.docs.service2.Application : Got response from service3 [Hello from service3] 88 | service4.log:2016-02-26 11:15:48.134 INFO [service4,2485ec27856c56f4,1b1845262ffba49d,true] 68061 --- [nio-8084-exec-1] i.s.c.sleuth.docs.service4.Application : Hello from service4 89 | service2.log:2016-02-26 11:15:48.156 INFO [service2,2485ec27856c56f4,9aa10ee6fbde75fa,true] 68059 --- [nio-8082-exec-1] i.s.c.sleuth.docs.service2.Application : Got response from service4 [Hello from service4] 90 | service1.log:2016-02-26 11:15:48.182 INFO [service1,2485ec27856c56f4,2485ec27856c56f4,true] 68058 --- [nio-8081-exec-1] i.s.c.sleuth.docs.service1.Application : Got response from service2 [Hello from service2, response from service3 [Hello from service3] and from service4 [Hello from service4]] 91 | ``` 92 | 93 | 如果你使用log集合工具例如Kibana、Splunk等,你可以看到事件的发生信息,Kibana的例子如下: 94 | 95 | ![](/img/sleuth-kibana.png) 96 | 97 | 以下是Logstash的Grok模式: 98 | 99 | ``` 100 | filter { 101 | # pattern matching logback pattern 102 | grok { 103 | match => { "message" => "%{TIMESTAMP_ISO8601:timestamp}\s+%{LOGLEVEL:severity}\s+\[%{DATA:service},%{DATA:trace},%{DATA:span},%{DATA:exportable}\]\s+%{DATA:pid}---\s+\[%{DATA:thread}\]\s+%{DATA:class}\s+:\s+%{GREEDYDATA:rest}" } 104 | } 105 | } 106 | ``` 107 | 108 | ### JSON Logback with Logstash 109 | 110 | 为了方便获取Logstash,通常保存log在JSON文件中而不是text文件中,配置方法如下: 111 | 112 | **依赖建立** 113 | 114 | - 确保Logback在classpath中(ch.qos.logback:logback-core) 115 | - 增加LogstashLogback编码 - version 4.6的例子:net.logstash.logback:logstash-logback-encoder:4.6 116 | 117 | **Logback建立** 118 | 119 | 以下是一个Logback配置的例子(文件名称 [logback-spring.xml](https://github.com/spring-cloud-samples/sleuth-documentation-apps/blob/master/service1/src/main/resources/logback-spring.xml)) : 120 | 121 | - 使用JSON格式记录应用信息到build/${spring.application.name}.json文件 122 | - 有两个添加注释源- console和标准log文件 123 | - 与之前章节使用相同的log模式 124 | 125 | ``` 126 | 127 | 128 | 129 | ​ 130 | 131 | 132 | ​ 133 | 134 | 136 | 137 | 138 | 139 | 140 | 141 | INFO 142 | 143 | 144 | ${CONSOLE_LOG_PATTERN} 145 | utf8 146 | 147 | 148 | 149 | ​ 150 | 151 | ${LOG_FILE} 152 | 153 | ${LOG_FILE}.%d{yyyy-MM-dd}.gz 154 | 7 155 | 156 | 157 | ${CONSOLE_LOG_PATTERN} 158 | utf8 159 | 160 | 161 | ​ 162 | 163 | 164 | ${LOG_FILE}.json 165 | 166 | ${LOG_FILE}.json.%d{yyyy-MM-dd}.gz 167 | 7 168 | 169 | 170 | 171 | 172 | UTC 173 | 174 | 175 | 176 | { 177 | "severity": "%level", 178 | "service": "${springAppName:-}", 179 | "trace": "%X{X-B3-TraceId:-}", 180 | "span": "%X{X-B3-SpanId:-}", 181 | "exportable": "%X{X-Span-Export:-}", 182 | "pid": "${PID:-}", 183 | "thread": "%thread", 184 | "class": "%logger{40}", 185 | "rest": "%message" 186 | } 187 | 188 | 189 | 190 | 191 | 192 | ​ 193 | 194 | 195 | 196 | 197 | 198 | 199 | ``` 200 | 201 | > 使用 `logback-spring.xml` 需要将 `spring.application.name` 在 `bootstrap` 中配置,而不是配置在 `application` 中,否则logback客户端将不能读取到配置值。 202 | 203 | --- 204 | 205 | ## 添加进工程 206 | 207 | ### 仅Sleuth(log收集) 208 | 209 | 如果仅需要Spring Cloud Sleuth而不需要Zipkin集成,只需要增加`spring-cloud-starter-sleuth`模块到你工程中,maven方式如下 210 | 211 | ``` 212 | (1) 213 | 214 | 215 | org.springframework.cloud 216 | spring-cloud-dependencies 217 | Brixton.RELEASE 218 | pom 219 | import 220 | 221 | 222 | 223 | 224 | (2) 225 | org.springframework.cloud 226 | spring-cloud-starter-sleuth 227 | 228 | ``` 229 | 230 | 1. 为了不手动添加版本号,更好的方式是通过Spring BOM添加dependencymanagement 231 | 2. 添加依赖到`spring-cloud-starter-sleuth` 232 | 233 | ### 通过HTTP使用基于Zipkin的Sleuth 234 | 235 | 如果你需要Sleuth和Zipkin,只需要添加`spring-cloud-starter-zipkin`依赖 236 | 237 | ``` 238 | (1) 239 | 240 | 241 | org.springframework.cloud 242 | spring-cloud-dependencies 243 | Brixton.RELEASE 244 | pom 245 | import 246 | 247 | 248 | 249 | 250 | (2) 251 | org.springframework.cloud 252 | spring-cloud-starter-zipkin 253 | 254 | ``` 255 | 256 | 1. 为了不手动添加版本号,更好的方式是通过Spring BOM添加dependencymanagement 257 | 2. 添加依赖到`spring-cloud-starter-zipkin` 258 | 259 | ### 通过SpringCloudStream使用Sleuth+Zipkin 260 | 261 | ``` 262 | (1) 263 | 264 | 265 | org.springframework.cloud 266 | spring-cloud-dependencies 267 | Brixton.RELEASE 268 | pom 269 | import 270 | 271 | 272 | 273 | 274 | (2) 275 | org.springframework.cloud 276 | spring-cloud-sleuth-stream 277 | 278 | (3) 279 | org.springframework.cloud 280 | spring-cloud-starter-sleuth 281 | 282 | 283 | (4) 284 | org.springframework.cloud 285 | spring-cloud-stream-binder-rabbit 286 | 287 | ``` 288 | 289 | 1. 为了不手动添加版本号,更好的方式是通过Spring BOM添加dependencymanagement 290 | 2. 添加依赖到`spring-cloud-sleuth-stream` 291 | 3. 添加依赖到`spring-cloud-starter-sleuth` 292 | 4. 添加一个binder(e.g.Rabbit binder)来告诉Spring Cloud Stream应该绑定什么 293 | 294 | ### Spring Cloud Sleuth Stream Zipkin Collector 295 | 296 | 启动一个Spring Cloud Sleuth Stream Zipkin收集器只需要添加`spring-cloud-sleuth-zipkin-stream`依赖 297 | 298 | ``` 299 | (1) 300 | 301 | 302 | org.springframework.cloud 303 | spring-cloud-dependencies 304 | Brixton.RELEASE 305 | pom 306 | import 307 | 308 | 309 | 310 | 311 | (2) 312 | org.springframework.cloud 313 | spring-cloud-sleuth-zipkin-stream 314 | 315 | (3) 316 | org.springframework.cloud 317 | spring-cloud-starter-sleuth 318 | 319 | 320 | (4) 321 | org.springframework.cloud 322 | spring-cloud-stream-binder-rabbit 323 | 324 | ``` 325 | 326 | 1. 为了不手动添加版本号,更好的方式是通过Spring BOM添加dependencymanagement 327 | 2. 添加依赖到`spring-cloud-sleuth-zipkin-stream` 328 | 3. 添加依赖到`spring-cloud-starter-sleuth` 329 | 4. 添加一个binder(e.g.Rabbit binder)来告诉Spring Cloud Stream应该绑定什么 330 | 331 | 之后只需要在你的主类中添加@EnableZipkinStreamServer注解 332 | 333 | ``` 334 | package example; 335 | 336 | import org.springframework.boot.SpringApplication; 337 | import org.springframework.boot.autoconfigure.SpringBootApplication; 338 | import org.springframework.cloud.sleuth.zipkin.stream.EnableZipkinStreamServer; 339 | 340 | @SpringBootApplication 341 | @EnableZipkinStreamServer 342 | public class ZipkinStreamServerApplication { 343 | 344 | public static void main(String[] args) throws Exception { 345 | SpringApplication.run(ZipkinStreamServerApplication.class, args); 346 | } 347 | 348 | } 349 | ``` 350 | 351 | --- 352 | 353 | ## 特性 354 | 355 | - 添加trace和spanid到Slf4J MDC,然后就可以从一个给定的trace或span中提取所有的log,例如 356 | 357 | ``` 358 | 2016-02-02 15:30:57.902 INFO [bar,6bfd228dc00d216b,6bfd228dc00d216b,false] 23030 --- [nio-8081-exec-3] ... 359 | 2016-02-02 15:30:58.372 ERROR [bar,6bfd228dc00d216b,6bfd228dc00d216b,false] 23030 --- [nio-8081-exec-3] ... 360 | 2016-02-02 15:31:01.936 INFO [bar,46ab0d418373cbc9,46ab0d418373cbc9,false] 23030 --- [nio-8081-exec-4] ... 361 | ``` 362 | 363 | 注意MDC中的`[appname,traceId,spanId,exportable]`: 364 | 365 | - 366 | - spanId - the id of a specific operation that took place 367 | - appname - the name of the application that logged the span 368 | - traceId - the id of the latency graph that contains the span 369 | - exportable - whether the log should be exported to Zipkin or not. When would you like the span not to be exportable? In the case in which you want to wrap some operation in a Span and have it written to the logs only. 370 | 371 | - 在通常的分布式追踪数据模型上提供一种抽象模型:traces、spans(生成一个DAG)、annotations、key-value annotations。基于HTrace是较为宽松的,但Zipkin(Dapper)更具兼容性 372 | - Sleuth记录时间信息来帮助延迟分析,使用Sleuth可以精确找到应用中延迟的原因,Sleuth不会log太多,因此不会导致你的应用挂掉 373 | - propagatesstructural data about your call-graph in-band, and the rest out-of-band 374 | - includesopinionated instrumentation of layers such as HTTP 375 | - includessampling policy to manage volume 376 | - canreport to a Zipkin system for query and visualization 377 | - 使用Spring应用装备出入口点(servletfilter、async endpoints、rest template、scheduled actions、messagechannels、zuul filters、feign client) 378 | - Sleuth包含默认逻辑通过http或messaging boundaries来加入一个trace,例如,http传播通过Zipkin-compatiblerequest headers工作,这个传播逻辑定义和定制是通过SpanInjector和SpanExtractor 379 | - 实现提供简单的接受或放弃span 380 | - If spring-cloud-sleuth-zipkin then the app will generate and collect Zipkin-compatible traces. By default it sends them via HTTP to a Zipkin server on localhost (port 9411). Configure the location of the service using spring.zipkin.baseUrl. 381 | - If spring-cloud-sleuth-stream then the app will generate and collect traces via Spring Cloud Stream. Your app automatically becomes a producer of tracer messages that are sent over your broker of choice (e.g. RabbitMQ, Apache Kafka, Redis). 382 | 383 | **IMPORTANT** 384 | > If using Zipkin or Stream, configure the percentage of spans exported using spring.sleuth.sampler.percentage (default 0.1, i.e. 10%). Otherwise you might think that Sleuth is not working cause it’s omitting some spans. 385 | 386 | **NOTE** 387 | 388 | > the SLF4J MDC is always set and logback users will immediately see the trace and span ids in logs per the example above. Other logging systems have to configure their own formatter to get the same result. The default is logging.pattern.level set to %clr(%5p) %clr([${spring.application.name:},%X{X-B3-TraceId:-},%X{X-B3-SpanId:-},%X{X-Span-Export:-}]){yellow} (this is a Spring Boot feature for logback users). This means that if you’re not using SLF4J this pattern WILL NOT be automatically applied. 389 | 390 | --- 391 | 392 | ## 抽样 393 | 394 | 在分布式追踪时,数据量可能会非常大,因此抽样就变得非常重要(通常不需要导出所有的spans以得到事件发生原貌),Spring Cloud Sleuth有一个`Sampler`战略,即用户可以控制抽样算法,Samplers不会停止正在生成的span id(相关的),但他们会阻止tags和events附加和输出,默认战略是当一个span处于活跃状态会继续trace,但新的span会一直处于不输出状态,如果所有应用都使用这个sampler,你会在logs中看到traces,但不会出现在任何远程仓库。测试状态资源都是充足的,并且你只使用logs的话他就是你需要的全部(e.g. 一个ELK集合),如果输出span数据到Zipkin或Spring Cloud Stream,有`AlwaysSampler`输出所有数据和`PercentageBasedSampler`采样spans确定的一部分。 395 | 396 | > 如果使用spring-cloud-sleuth-zipkin或spring-cloud-sleuth-stream,PercentageBasedSampler是默认的,你可以使用spring.sleuth.sampler.percentage配置输出 397 | 398 | 通过创建一个bean定义就可以新建一个sampler 399 | 400 | ``` 401 | @Bean 402 | public Sampler defaultSampler() { 403 | return new AlwaysSampler(); 404 | } 405 | ``` 406 | 407 | --- 408 | 409 | ## Instrumentation 410 | 411 | Spring Cloud Sleuth自动装配所有Spring应用,因此你不用做任何事来让他工作,装配是使用一系列技术添加的,例如对于一个servlet web应用我们使用一个Filter,对于SpringIntegration我们使用`ChannelInterceptors`。 412 | 413 | 用户可以使用span tags定制关键字,为了限制span数据量,一般一个HTTP请求只会被少数元数据标记,例如status code、host以及URL,用户可以通过配置`spring.sleuth.keys.http.headers`(一系列头名称)添加request headers。 414 | 415 | > tags仅在Sampler允许其被收集和输出时工作(默认情况其不工作,因此不会有在不配置的情况下收集过多数据的意外危险出现) 416 | 417 | > Currently the instrumentation in Spring Cloud Sleuth is eager - it means that we’re actively trying to pass the tracing context between threads. Also timing events are captured even when sleuth isn’t exporting data to a tracing system. This approach may change in the future towards being lazy on this matter. 418 | 419 | --- 420 | 421 | ## Span生命周期 422 | 423 | 通过Trace接口的方式可以在Span上进行如下操作: 424 | 425 | - start - 当打开一个span时,其名字被指定且开始时间戳被记录 426 | - close - span已经结束(span的结束时间已被记录)并且如果span是输出的,他将是Zipkin合适的收集项,span在当前线程也将被移除 427 | - continue - span的一个新实例将被创建,然而他将是正是正在运行的span的一个复制体 428 | - detach - span不会停止或关闭,他只会被从当前线程中移除 429 | - create with explicit parent - 建立一个新的span并设置一个明确的parent给他 430 | 431 | ### Creating and closing spans 432 | 433 | 使用Tracer接口可以手动新建spans 434 | 435 | ``` 436 | // Start a span. If there was a span present in this thread it will become 437 | // the `newSpan`'s parent. 438 | Span newSpan = this.tracer.createSpan("calculateTax"); 439 | try { 440 | // ... 441 | // You can tag a span 442 | this.tracer.addTag("taxValue", taxValue); 443 | // ... 444 | // You can log an event on a span 445 | newSpan.logEvent("taxCalculated"); 446 | } finally { 447 | // Once done remember to close the span. This will allow collecting 448 | // the span to send it to Zipkin 449 | this.tracer.close(newSpan); 450 | } 451 | ``` 452 | 453 | 在例子中我们可以看到如何新建一个span实例,假设在当前线程中已经有一个span,那么新建的线程将会是这个线程的parent。 454 | 455 | **IMPORTANT** 456 | > 新建span后要记得清除他!如果你想要将一个span发送给Zipkin,不要忘记关闭他。 457 | 458 | ### Continuing spans 459 | 460 | 有时你不想要新建一个span但你又想持续使用,这种情况的例子可能如下(当然实际依赖于使用情况): 461 | 462 | - **AOP** - 如果在实际应用前已经有一个span新建可用,那么就不需要新建一个span 463 | - **Hystrix** - 对于当前处理流程而言,执行Hystrix操作是最为合理的一部分,实际上只有技术实现细节的话,不必将他作为分离的部分反映在tracing中 464 | 465 | span的持续实例等同于正在运行的: 466 | 467 | ``` 468 | Span continuedSpan = this.tracer.continueSpan(spanToContinue); 469 | assertThat(continuedSpan).isEqualTo(spanToContinue); 470 | ``` 471 | 472 | 可以使用Tracer接口延续一个span 473 | 474 | ``` 475 | // let's assume that we're in a thread Y and we've received 476 | // the `initialSpan` from thread X 477 | Span continuedSpan = this.tracer.continueSpan(initialSpan); 478 | try { 479 | // ... 480 | // You can tag a span 481 | this.tracer.addTag("taxValue", taxValue); 482 | // ... 483 | // You can log an event on a span 484 | continuedSpan.logEvent("taxCalculated"); 485 | } finally { 486 | // Once done remember to detach the span. That way you'll 487 | // safely remove it from the current thread without closing it 488 | this.tracer.detach(continuedSpan); 489 | } 490 | ``` 491 | 492 | **IMPORTANT** 493 | > 新建一个span后记得清除他!如果有些工作在一个线程(e.g. thread X)中已经结束并且他在等待另外的线程(e.g. Y,Z)结束时,不要忘记分离span,在线程Y,Z中的spans在他们工作结束时也应被分离,结果收集完成时thread X中的span应该被关闭 494 | 495 | ### Creating spans with an explicit parent 496 | 497 | 如果你想新建一个span并且提供一个明确的parent给他,假设span的parent在一个thread中,而你想在另一个thread中新建span,Tracer接口的startSpan命令就是你需要的。 498 | 499 | ``` 500 | // let's assume that we're in a thread Y and we've received 501 | // the `initialSpan` from thread X. `initialSpan` will be the parent 502 | // of the `newSpan` 503 | Span newSpan = this.tracer.createSpan("calculateCommission", initialSpan); 504 | try { 505 | // ... 506 | // You can tag a span 507 | this.tracer.addTag("commissionValue", commissionValue); 508 | // ... 509 | // You can log an event on a span 510 | newSpan.logEvent("commissionCalculated"); 511 | } finally { 512 | // Once done remember to close the span. This will allow collecting 513 | // the span to send it to Zipkin. The tags and events set on the 514 | // newSpan will not be present on the parent 515 | this.tracer.close(newSpan); 516 | } 517 | ``` 518 | 519 | **IMPORTANT** 520 | > 记得在新建这样的span后关闭他,否则你在你的log中看到大量的相关warning,更糟糕的是你的span不会正常关闭,这样的话就无法被Zipkin收集 521 | 522 | --- 523 | 524 | ## 命名spans 525 | 526 | 为span命名是很重要的工作,span名称必须描述了一个操作名称,名称必须要简明(e.g. 不包括标识符)。 527 | 528 | Since there is a lot of instrumentation going on some of thespan names will be artificial like: 529 | 530 | - controller-method-name when received by a Controller with a methodname conrollerMethodName 531 | - async for asynchronous operations done via wrappedCallable and Runnable 532 | - @Scheduled annotated methods will return the simple nameof the class 533 | 534 | Fortunately, for the asynchronous processing you can provideexplicit naming 535 | 536 | ### @SpanName注解 537 | 538 | 可以使用@SpanName注解明确命名span 539 | 540 | ``` 541 | @SpanName("calculateTax") 542 | class TaxCountingRunnable implements Runnable { 543 | 544 | @Override public void run() { 545 | // perform logic 546 | } 547 | } 548 | ``` 549 | 550 | 在这种情况下,使用下面的方式便命名一个span为calculateTax 551 | 552 | ``` 553 | Runnable runnable = new TraceRunnable(tracer, spanNamer, new TaxCountingRunnable()); 554 | Future future = executorService.submit(runnable); 555 | // ... some additional logic ... 556 | future.get(); 557 | ``` 558 | 559 | ### toString()方法 560 | 561 | 为Runnable或Callable建立分离的classes是非常少见的,一般建立这些classes的匿名实例,你不能注解这些classes除非override,如果没有@SpanName注解,我们将会检查class是否使用传统的toString()方法实现 562 | 563 | 执行这些代码将新建一个名为calculateTax的span: 564 | 565 | ``` 566 | Runnable runnable = new TraceRunnable(tracer, spanNamer, new Runnable() { 567 | @Override public void run() { 568 | // perform logic 569 | } 570 | 571 | @Override public String toString() { 572 | return "calculateTax"; 573 | } 574 | }); 575 | Future future = executorService.submit(runnable); 576 | // ... some additional logic ... 577 | future.get(); 578 | ``` 579 | 580 | --- 581 | 582 | ## 定制化 583 | 584 | 使用`SpanInjector`和`SpanExtractor`你可以定制化span的新建和传播。 585 | 586 | 当前有两种built-in方法来在进程间传递tracing信息: 587 | 588 | - 通过SpringIntegration 589 | - 通过HTTP 590 | 591 | span id是从Zipkin-compatible(B3)头中提取的(不论Message或HTTP头),以此来开始或加入一个存在的trace,trace信息被注入到输出请求中,这样后面的步骤就可以提取他。 592 | 593 | ### Spring Integration 594 | 595 | 对于Spring Integration,存在beans负责span从Message的创建和使用tracing信息装配MessageBuilder 596 | 597 | ``` 598 | @Bean 599 | public SpanExtractor messagingSpanExtractor() { 600 | ... 601 | } 602 | 603 | @Bean 604 | public SpanInjector messagingSpanInjector() { 605 | ... 606 | } 607 | ``` 608 | 609 | 用户可以使用自己的实现来override他,或者添加`@Primary`注解到你的bean定义 610 | 611 | ### HTTP 612 | 613 | 对于HTTP,存在beans负责span从HttpServletRequest的创建和使用tracing信息装配HttpServletResponse。 614 | 615 | ``` 616 | @Bean 617 | public SpanExtractor httpServletRequestSpanExtractor() { 618 | ... 619 | } 620 | 621 | @Bean 622 | public SpanInjector httpServletResponseSpanInjector() { 623 | ... 624 | } 625 | ``` 626 | 627 | 用户可以使用自己的实现来override他,或者添加`@Primary`注解到你的bean定义 628 | 629 | ### Example 630 | 631 | 对比传统的兼容Zipkin,tracingHTTP头名有以下格式 632 | 633 | - traceid - correlationId 634 | - spanid - mySpanId 635 | 636 | 以下是一个`SpanExtractor`的例子 637 | 638 | ``` 639 | static class CustomHttpServletRequestSpanExtractor 640 | implements SpanExtractor { 641 | 642 | @Override 643 | public Span joinTrace(HttpServletRequest carrier) { 644 | long traceId = Span.hexToId(carrier.getHeader("correlationId")); 645 | long spanId = Span.hexToId(carrier.getHeader("mySpanId")); 646 | // extract all necessary headers 647 | Span.SpanBuilder builder = Span.builder().traceId(traceId).spanId(spanId); 648 | // build rest of the Span 649 | return builder.build(); 650 | } 651 | } 652 | ``` 653 | 654 | 以下`SpanInjector`将被建立 655 | 656 | ``` 657 | static class CustomHttpServletResponseSpanInjector 658 | implements SpanInjector { 659 | 660 | @Override 661 | public void inject(Span span, HttpServletResponse carrier) { 662 | carrier.addHeader("correlationId", Span.idToHex(span.getTraceId())); 663 | carrier.addHeader("mySpanId", Span.idToHex(span.getSpanId())); 664 | // inject the rest of Span values to the header 665 | } 666 | } 667 | ``` 668 | 669 | 并且你可以这样注册他们 670 | 671 | ``` 672 | @Bean 673 | @Primary 674 | SpanExtractor customHttpServletRequestSpanExtractor() { 675 | return new CustomHttpServletRequestSpanExtractor(); 676 | } 677 | 678 | @Bean 679 | @Primary 680 | SpanInjector customHttpServletResponseSpanInjector() { 681 | return new CustomHttpServletResponseSpanInjector(); 682 | } 683 | ``` 684 | 685 | ### Custom SA tag in Zipkin 686 | 687 | Sometimes you want to create a manual Span that will wrap a call to an external service which is not instrumented. What you can do is to create a span with the peer.service tag that will contain a value of the service that you want to call. Below you can see an example of a call to Redis that is wrapped in such a span. 688 | 689 | ``` 690 | org.springframework.cloud.sleuth.Span newSpan = tracer.createSpan("redis"); 691 | try { 692 | newSpan.tag("redis.op", "get"); 693 | newSpan.tag("lc", "redis"); 694 | newSpan.logEvent(org.springframework.cloud.sleuth.Span.CLIENT_SEND); 695 | // call redis service e.g 696 | // return (SomeObj) redisTemplate.opsForHash().get("MYHASH", someObjKey); 697 | } finally { 698 | newSpan.tag("peer.service", "redisService"); 699 | newSpan.tag("peer.ipv4", "1.2.3.4"); 700 | newSpan.tag("peer.port", "1234"); 701 | newSpan.logEvent(org.springframework.cloud.sleuth.Span.CLIENT_RECV); 702 | tracer.close(newSpan); 703 | } 704 | ``` 705 | 706 | > Remember not to add both peer.service tag and the SA tag! You have to add only peer.service. 707 | 708 | --- 709 | 710 | ## Spring Data as Messages 711 | 712 | 可以通过Spring Cloud Stream来积累和发送span数据,配置时需要包含spring-cloud-sleuth-streamjar为依赖且增加一个Channel Binder实现方式(e.g. spring-cloud-starter-stream-rabbit对应RabbitMQ或spring-cloud-starter-stream-kafka对应Kafka),使用payload格式Spans将自动把你的app变为一个信息生产者 713 | 714 | ### Zipkin Consumer 715 | 716 | 有一种特殊而又便利的注解方式,即为span数据建立一个信息消费者,并将他推到一个Zipkin SpanStrore中 717 | 718 | ``` 719 | @SpringBootApplication 720 | @EnableZipkinStreamServer 721 | public class Consumer { 722 | public static void main(String[] args) { 723 | SpringApplication.run(Consumer.class, args); 724 | } 725 | } 726 | ``` 727 | 728 | 这种应用将通过Spring Cloud Stream Binder监听不论何种方式传输的span数据(e.g.包括spring-cloud-starter-stream-rabbit对应RabbitMQ,和对应Redis和Kafka的类似starter存在),如果添加以下UI依赖 729 | 730 | ``` 731 | io.zipkin.java 732 | zipkin-autoconfigure-ui 733 | ``` 734 | 735 | 你将启动一个Zipkin server应用,他将通过端口9411访问UI和api。 736 | 737 | 默认SpanStore是in-memory的(适合于demos且启动迅速),你可以添加MySQL和spring-boot-starter-jdbc到你的系统环境并通过配置激活JDBC SpanStore。例如: 738 | 739 | ``` 740 | spring: 741 | rabbitmq: 742 | host: ${RABBIT_HOST:localhost} 743 | datasource: 744 | schema: classpath:/mysql.sql 745 | url: jdbc:mysql://${MYSQL_HOST:localhost}/test 746 | username: root 747 | password: root 748 | # Switch this on to create the schema on startup: 749 | initialize: true 750 | continueOnError: true 751 | sleuth: 752 | enabled: false 753 | zipkin: 754 | storage: 755 | type: mysql 756 | ``` 757 | 758 | > @EnableZipkinStreamServer也使用@EnableZipkinServer注解,因此进程也会显示标准Zipkin服务终端以通过HTTP收集span,且可以通过Zipkin Web UI查询 759 | 760 | ### Custom Consumer 761 | 762 | 使用spring-cloud-sleuth-stream且绑定SleuthSink可以很方便的实现定制消费者。例子: 763 | 764 | ``` 765 | @EnableBinding(SleuthSink.class) 766 | @SpringBootApplication(exclude = SleuthStreamAutoConfiguration.class) 767 | @MessageEndpoint 768 | public class Consumer { 769 | 770 | @ServiceActivator(inputChannel = SleuthSink.INPUT) 771 | public void sink(Spans input) throws Exception { 772 | // ... process spans 773 | } 774 | } 775 | ``` 776 | 777 | > 上述的消费者应用明确排除SleuthStreamAutoConfiguration,因此他不会给自己发消息,但这是可选的(你可能想要trace请求到消费者app) 778 | 779 | --- 780 | 781 | ## 度量 782 | 783 | 当前Spring Cloud Sleuth记录非常简单的spans metrics,使用Spring Boot的metrics support来计算接收丢弃的span数量,当有span发送给Zipkin时,接收span的数量就会增加,如果有错误发生,丢弃span数量就会增加。 784 | 785 | --- 786 | 787 | ## Integrations 788 | 789 | ### Runnable and Callable 790 | 791 | 如果你要将你的逻辑包裹在Runable或Callable中,足够将这些classes放到他们的Sleuth代表中。 792 | 793 | Example for Runnable: 794 | 795 | ``` 796 | Runnable runnable = new Runnable() { 797 | @Override 798 | public void run() { 799 | // do some work 800 | } 801 | 802 | @Override 803 | public String toString() { 804 | return "spanNameFromToStringMethod"; 805 | } 806 | }; 807 | // Manual `TraceRunnable` creation with explicit "calculateTax" Span name 808 | Runnable traceRunnable = new TraceRunnable(tracer, spanNamer, runnable, "calculateTax"); 809 | // Wrapping `Runnable` with `Tracer`. The Span name will be taken either from the 810 | // `@SpanName` annotation or from `toString` method 811 | Runnable traceRunnableFromTracer = tracer.wrap(runnable); 812 | ``` 813 | 814 | Example for Callable: 815 | 816 | ``` 817 | Callable callable = new Callable() { 818 | @Override 819 | public String call() throws Exception { 820 | return someLogic(); 821 | } 822 | 823 | @Override 824 | public String toString() { 825 | return "spanNameFromToStringMethod"; 826 | } 827 | }; 828 | // Manual `TraceCallable` creation with explicit "calculateTax" Span name 829 | Callable traceCallable = new TraceCallable<>(tracer, spanNamer, callable, "calculateTax"); 830 | // Wrapping `Callable` with `Tracer`. The Span name will be taken either from the 831 | // `@SpanName` annotation or from `toString` method 832 | Callable traceCallableFromTracer = tracer.wrap(callable); 833 | ``` 834 | 835 | 这种方式你可以保证一个新的Span在每次执行时新建和关闭。 836 | 837 | ### Hystrix 838 | 839 | **传统并发策略** 840 | 841 | 我们以将所有的`Callable`实例置入到他们的Sleuth代表-`TraceCallable`的方式来记录一个传统的`HystrixConcurrencyStrategy`,策略的打开或延续一个span取决于在Hystrix操作被调用前tracing是否在工作,为了使传统Hystrix并发策略无效可以设置`spring.sleuth.hystrix.strategy.enable`为false。 842 | 843 | **手动操作设置** 844 | 845 | 假设你有以下HystrixCommand: 846 | 847 | ``` 848 | HystrixCommand hystrixCommand = new HystrixCommand(setter) { 849 | @Override 850 | protected String run() throws Exception { 851 | return someLogic(); 852 | } 853 | }; 854 | ``` 855 | 856 | 为了传递tracing信息你必须将同样的逻辑置于`HystrixCommand`的Sleuth版本中,也就是`TraceCommand`: 857 | 858 | ``` 859 | TraceCommand traceCommand = new TraceCommand(tracer, traceKeys, setter) { 860 | @Override 861 | public String doRun() throws Exception { 862 | return someLogic(); 863 | } 864 | }; 865 | ``` 866 | 867 | ### RxJava 868 | 869 | 我们记录了一个典型的RxJavaSchedulersHook,他将所有Action0实例置入到他们的Sleuth代表-TraceAction中,hook打开或延续一个span取决于Action被安排前tracing是否已经在工作,为了使RxJavaSchedulersHook无效可设置`spring.sleuth.rxjava.schedulers.hook.enabled`为false。 870 | 871 | You can define a list of regular expressions for thread names, for which you don’t want a Span to be created. Just provide a comma separated list of regular expressions in the spring.sleuth.rxjava.schedulers.ignoredthreads property. 872 | 873 | ### HTTP integration 874 | 875 | 将`spring.sleuth.web.enabled`配置值设置为false可以使这章中的特征方法无效 876 | 877 | **HTTP Filter** 878 | 879 | 通过TraceFilter,所有抽样输入的请求都会归结到span的创建,span的名称为"http+请求发送的路径",例如,如果请求发送到/foo/bar,名称即为http:/foo/bar,你可以配置通过`spring.sleuth.web.skipPattern`,那些URIs将被过滤掉,如果你在环境中添加了ManagementServerProperties,你的contextPath值会附加到过滤配置上。 880 | 881 | **HandlerIntercepter** 882 | 883 | 由于需要span名称的精确,我们使用一个TraceHandlerInterceptor来置入一个存在的HandlerInterceptor或直接添加到存在的HandlerInterceptors列表中,TraceHandlerInterceptor添加一个特殊的请求属性给HttpServletRequest,如果TraceFilter没有看到属性,他会建立一个"fallback"span,这是一个建立在服务端的附加的span,此时trace在UI中可以正确的显示。 884 | 885 | **Async Servlet support** 886 | 887 | If your controller returns a Callable or a WebAsyncTask Spring Cloud Sleuth will continue the existing span instead of creating a new one. 888 | 889 | ### HTTP client integration 890 | 891 | **同步RestTemplate** 892 | 893 | 我们注入一个RestTemplate拦截器来保证所有的tracing信息被发送到请求端,每当一个请求被生成,一个新的span将被创建,他会在接收应答后关闭,为了限制同步RestTemplate只需要设置`spring.sleuth.web.client.enabled`为false。 894 | 895 | > 你必须注册一个RestTemplate为bean以使得拦截器可以注入,如果你使用一个新的关键字建立一个RestTemplate实例,instrumentation将无法工作 896 | 897 | **异步RestTemplate** 898 | 899 | 传统的instrumentation是通过发送接收请求来建立关闭span的,你可以通过注册你的bean来定制ClientHttpRequestFactory和AsyncClientHttpRequestFactory,记得使用tracing compatible实现方式(e.g. 不要忘记将ThreadPoolTaskScheduler置入一个TraceAsyncListenableTaskExecutor),传统请求工厂例子如下: 900 | 901 | ``` 902 | @EnableAutoConfiguration 903 | @Configuration 904 | public static class TestConfiguration { 905 | 906 | @Bean 907 | ClientHttpRequestFactory mySyncClientFactory() { 908 | return new MySyncClientHttpRequestFactory(); 909 | } 910 | 911 | @Bean 912 | AsyncClientHttpRequestFactory myAsyncClientFactory() { 913 | return new MyAsyncClientHttpRequestFactory(); 914 | } 915 | } 916 | ``` 917 | 918 | 通过设置`spring.sleuth.web.async.client.enabled`为false可以限制`AsyncRestTemplate`,使默认的`TraceAsyncClientHttpRequestFactoryWrapper`无效可以设置`spring.sleuth.web.async.client.factory.enabled`为false,如果你不想创建`AsyncRestClient`,设置`spring.sleuth.web.async.client.template.enabled`为false。 919 | 920 | ### Feign 921 | 922 | 默认Spring Cloud Sleuth通过`TraceFeignClientAutoConfiguration`提供feign的集成,你可以设置`spring.sleuth.feign.enabled`为false来使他无效,如果这样设置那么所有feign相关的装配都无法发生。 923 | 924 | 通过FeignBeanPostProcessor feign装配的部分结束,可以设置`spring.sleuth.feign.processor.enabled`为false来是他无效化,如果你这样设置,Spring Cloud Sleuth将不会装配任何你的传统feign组件,所有默认装配保持原有状态。 925 | 926 | ### 异步通信 927 | 928 | **@Async注解方法** 929 | 930 | 在Spring Cloud Sleuth中,我们装配异步关联组件以使得tracing信息可以在threads间传递,你可以通过设置`spring.sleuth.async.enabled`值为false来使其无效化。 931 | 如果你使用@Async来注解你的方法,我们将自动建立一个新的span: 932 | 933 | - span名称将是注解方法名 934 | - span将被标注为方法类名和方法名 935 | 936 | **@Scheduled注解方法** 937 | 938 | 在Spring Cloud Sleuth中,我们装配scheduled执行方法以使得tracing信息可以在threads间传递,你可以通过设置`spring.sleuth.scheduled.enabled`值为false来使其无效化。 939 | 如果你使用`@Scheduled`来注解你的方法,我们将自建立一个新的span: 940 | 941 | - span名称将是注解方法名 942 | - span将被标注为方法类名和方法名 943 | 944 | 如果在一些@Scheduled注解类中你想跳过span新建过程,可以设置`spring.sleuth.scheduled.skipPattern`为一个指定的表达式,这将匹配`@Scheduled`注解类的完整描述名称。 945 | 946 | **Executor, ExecutorServiceand ScheduledExecutorService** 947 | 948 | 我们提供了LazyTraceExecutor,TraceableExecutorService和TraceableScheduledExecutorService。每当一个新的任务被提交、调用或scheduled时,这些实现会建 949 | 立新的spans。 950 | 951 | 以下是当使用CompletableFuture时如何用TraceableExecutorService传递tracing信息: 952 | 953 | ``` 954 | CompletableFuture completableFuture = CompletableFuture.supplyAsync(() -> { 955 | // perform some logic 956 | return 1_000_000L; 957 | }, new TraceableExecutorService(executorService, 958 | // 'calculateTax' explicitly names the span - this param is optional 959 | tracer, traceKeys, spanNamer, "calculateTax")); 960 | ``` 961 | ### Messaging 962 | 963 | Spring Cloud Sleuth集成了Spring Integration。他会建立span来发布或订阅事件,设置`spring.sleuth.integration.enabled`为false可以使Spring Integration无效。 964 | 965 | Spring Cloud Sleuth到1.0.4版本前都是使用消息传递时发送无效tracing头,这些头和在HTTP(包含 - )发送的名称时一样的,为了在1.0.4版本的向后兼容目的,我们开始发送所有有效和无效的头,请更新到1.0.4,因为在Spring Cloud Sleuth 1.1中我们将会移除对分离头的支持。 966 | 967 | 从1.0.4后可以明确设置`spring.sleuth.integration.patterns`模式来提供你想要包含的tracing信道名称,默认所有的信道已被包含在内。 968 | 969 | ### Zuul 970 | 971 | 我们注册Zuul过滤器来传播tracing信息(请求头使用tracing数据填满),可以设置`spring.sleuth.zuul.enabled`为false来关闭Zuul服务。 972 | 973 | 974 | --------------------------------------------------------------------------------