• [技术干货] springcloud详解
    Spring Cloud 是什么?在学习本课程之前,读者有必要先了解一下 Spring Cloud。Spring Cloud 是一系列框架的有序集合,它利用 Spring Boot 的开发便利性简化了分布式系统的开发,比如服务发现、服务网关、服务路由、链路追踪等。Spring Cloud 并不重复造轮子,而是将市面上开发得比较好的模块集成进去,进行封装,从而减少了各模块的开发成本。换句话说:Spring Cloud 提供了构建分布式系统所需的“全家桶”。Spring Cloud 现状目前,国内使用 Spring Cloud 技术的公司并不多见,不是因为 Spring Cloud 不好,主要原因有以下几点:Spring Cloud 中文文档较少,出现问题网上没有太多的解决方案。国内创业型公司技术老大大多是阿里系员工,而阿里系多采用 Dubbo 来构建微服务架构。大型公司基本都有自己的分布式解决方案,而中小型公司的架构很多用不上微服务,所以没有采用 Spring Cloud 的必要性。但是,微服务架构是一个趋势,而 Spring Cloud 是微服务解决方案的佼佼者,这也是作者写本系列课程的意义所在。Spring Cloud 优缺点其主要优点有:集大成者,Spring Cloud 包含了微服务架构的方方面面。约定优于配置,基于注解,没有配置文件。轻量级组件,Spring Cloud 整合的组件大多比较轻量级,且都是各自领域的佼佼者。开发简便,Spring Cloud 对各个组件进行了大量的封装,从而简化了开发。开发灵活,Spring Cloud 的组件都是解耦的,开发人员可以灵活按需选择组件。接下来,我们看下它的缺点:项目结构复杂,每一个组件或者每一个服务都需要创建一个项目。部署门槛高,项目部署需要配合 Docker 等容器技术进行集群部署,而要想深入了解 Docker,学习成本高。Spring Cloud 的优势是显而易见的。因此对于想研究微服务架构的同学来说,学习 Spring Cloud 是一个不错的选择。Spring Cloud 和 Dubbo 对比Dubbo 只是实现了服务治理,而 Spring Cloud 实现了微服务架构的方方面面,服务治理只是其中的一个方面。下面通过一张图对其进行比较:可以看出,Spring Cloud 比较全面,而 Dubbo 由于只实现了服务治理,需要集成其他模块,需要单独引入,增加了学习成本和集成成本。Spring Cloud 学习Spring Cloud 基于 Spring Boot,因此在研究 Spring Cloud 之前,本课程会首先介绍 Spring Boot 的用法,方便后续 Spring Cloud 的学习。本课程不会讲解 Spring MVC 的用法,因此学习本课程需要读者对 Spring 及 Spring MVC 有过研究。本课程共分为四个部分:第一部分初识 Spring Boot,掌握 Spring Boot 基础知识,为后续入门 Spring Cloud 打好基础 。第二部分 Spring Cloud 入门篇,主要介绍 Spring Cloud 常用模块,包括服务发现、服务注册、配置中心、链路追踪、异常处理等。第三部分 Spring Cloud 进阶篇,介绍大型分布式系统中事务处理、线程安全等问题,并以一个实例项目手把手教大家搭建完整的微服务系统。第四部分 Spring Cloud 高级篇,解析 Spring Cloud 源码,并讲解如何部署基于 Spring Cloud 的大型分布式系统。本课程的所有示例代码均可在:https://github.com/lynnlovemin/SpringCloudLesson 下载。
  • [技术干货] springcloud
    Spring Cloud是一系列框架的有序集合。它利用Spring Boot的开发便利性巧妙地简化了分布式系统基础设施的开发,如服务发现注册、配置中心、消息总线、负载均衡、断路器、数据监控等,都可以用Spring Boot的开发风格做到一键启动和部署。Spring Cloud并没有重复制造轮子,它只是将各家公司开发的比较成熟、经得起实际考验的服务框架组合起来,通过Spring Boot风格进行再封装屏蔽掉了复杂的配置和实现原理,最终给开发者留出了一套简单易懂、易部署和易维护的分布式系统开发工具包。外文名Spring Cloud性    质一系列框架的有序集合目录1 Spring Cloud组成2 Spring Cloud前景Spring Cloud组成编辑 播报Spring Cloud的子项目,大致可分成两类,一类是对现有成熟框架”Spring Boot化”的封装和抽象,也是数量最多的项目;第二类是开发了一部分分布式系统的基础设施的实现,如Spring Cloud Stream扮演的就是kafka, ActiveMQ这样的角色。对于我们想快速实践微服务的开发者来说,第一类子项目就已经足够使用,如:Spring Cloud Netflix  是对Netflix开发的一套分布式服务框架的封装,包括服务的发现和注册,负载均衡、断路器、REST客户端、请求路由等。Spring Cloud Config  将配置信息中央化保存, 配置Spring Cloud Bus可以实现动态修改配置文件Spring Cloud Stream  分布式消息队列,是对Kafka, MQ的封装Spring Cloud Security  对Spring Security的封装,并能配合Netflix使用Spring Cloud Zookeeper  对Zookeeper的封装,使之能配置其它Spring Cloud的子项目使用Spring Cloud Eureka 是 Spring Cloud Netflix 微服务套件中的一部分,它基于Netflix Eureka 做了二次封装,主要负责完成微服务架构中的服务治理功能。Spring Cloud前景编辑 播报Spring Cloud对于中小型互联网公司来说是一种福音,因为这类公司往往没有实力或者没有足够的资金投入去开发自己的分布式系统基础设施,使用Spring Cloud一站式解决方案能在从容应对业务发展的同时大大减少开发成本。同时,随着近几年微服务架构和Docker容器概念的火爆,也会让Spring Cloud在未来越来越“云”化的软件开发风格中立有一席之地,尤其是在五花八门的分布式解决方案中提供了标准化的、全站式的技术方案,意义可能会堪比当年Servlet规范的诞生,有效推进服务端软件系统技术水平的进步。
  • [整体安全] 【漏洞预警】Spring Cloud Function SPEL表达式注入漏洞
    漏洞描述:作为一种函数计算框架,Spring Cloud Function 是基于Spring Boot而产生的。Spring Cloud Function能抽象出所有传输细节和基础架构,允许开发人员保留所有熟悉的工具和流程,并专注于业务逻辑,提高业务效率。Spring Cloud Function 要实现高级别要求的目标:1.通过函数促进业务逻辑的实现。2.将业务逻辑的开发生命周期与特定运行时分离,以便相同的代码可以作为任务运行。3.支持Serverless 提供商之间的统一编程模型,以及独立运行的能力。4.在Serverless提供商上启用Spring Boot 功能。近期,Spring Cloud官方修复了一个Spring Cloud Function中的SPEL表达式注入漏洞。由于Spring Cloud Function中RoutingFunction类的apply方法将请求头中的“spring.cloud. function.routing-expression”参数作为Spel表达式进行处理,造成了Spel表达式注入漏洞。使得未经授权的远程攻击者可利用该漏洞执行任意代码。漏洞危害:攻击者利用此漏洞,可实现远程代码执行。通过发送恶意制作的请求,从而导致在主机上执行任意恶意代码。使得攻击者在用户运行应用程序时执行恶意程序,并控制这个受影响的系统。攻击者一旦访问该系统后,它会试图提升其权限,甚至控制企业的服务器。影响范围:3.0.0.RELEASE <= Spring Cloud Function<= 3.2.2注:发布时间为2019年11月22日至2022年2月17日漏洞等级:    高危修复方案:目前官方已针对此漏洞发布修复补丁,请受影响的用户尽快更新进行防护,官方链接:https://github.com/spring-cloud/spring-cloud-function/commit/0e89ee27b2e76138c16bcba6f4bca906c4f3744f注:目前官方暂未发布新版本,请持续关注更新链接:https://github.com/spring-cloud/spring-cloud-function/tags
  • [技术交流] SpringCloud项目接入华为云微服务引擎CSE
    ### 一、SpringCloud项目架构介绍 #### 1.项目地址: [https://gitee.com/caichunfu/dtse-practice-microservice](https://gitee.com/caichunfu/dtse-practice-microservice) #### 2.项目技术栈如下: 1. 注册中心:Eureka 2. 网关:zuul 3. 声明式调用:feign 4. 存储:OBS、RDS for MySql ![](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20222/18/1645173154462340346.png) #### 3.项目结构: 1. dtse-commons:项目的公共工具类 2. dtse-eureka-server:eureka注册中心集群 3. dtse-feign-client:feign调用客户端 4. dtse-obs-storage:服务端,完成对obs的操作,包括上传和删除obs对象 5. dtse-system:消费端,实现用户登录、查询用户头像、更新用户头像(调用服务端请求) 6. dtse-zuul-getway:项目网关 ### 二、SpringCloud Huawei改造方案 #### 1.替换技术栈对比 | SpringCloud | SpringCloud-Huawei | | ------------------ | ------------------------------------------------------------ | | Eureka注册中心 | [华为云CSE微服务引擎](https://support.huaweicloud.com/devg-cse/cse_devg_0010.html) | | zuul网关 | SpringCloud Huawei Getway | | SpringCloud config | [CSE Config](https://support.huaweicloud.com/devg-cse/cse_devg_0022.html) | #### 2.SpringCloud Huawei技术文档 [https://github.com/huaweicloud/spring-cloud-huawei](https://github.com/huaweicloud/spring-cloud-huawei) #### 3.SpringCloud Huawei基础Demo [https://github.com/huaweicloud/spring-cloud-huawei-samples/tree/master/basic](https://github.com/huaweicloud/spring-cloud-huawei-samples/tree/master/basic) #### 4.SpringCloud Huawei版本对照 ![](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20222/18/1645174723327212698.png) #### 5.改造前设置 1. 下载本地CSE,下载地址:[https://support.huaweicloud.com/devg-cse/cse_devg_0036.html](https://support.huaweicloud.com/devg-cse/cse_devg_0036.html) 2. 将maven镜像改为华为镜像仓库: ``` <mirror> <id>huaweicloud</id> <mirrorOf>*</mirrorOf> <url>https://repo.huaweicloud.com/repository/maven/</url> </mirror> ``` 3. 项目版本选定 - SpringBoot:2.3.7.RELEASE - SpringCloud:Hoxton.SR9 - SpringCloud Huawei:1.8.0-Hoxton #### 6.改造方案 1. 移除微服务项目里所有的eureka依赖,删掉application.yml里的eureka的配置 ``` <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> </dependency> ``` 2. 导入SpringCloud Huawei依赖 - 父工程里导入 ```xml <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> ``` - 子工程里导入 ```xml <dependency> <groupId>com.huaweicloud</groupId> <artifactId>spring-cloud-starter-huawei-service-engine</artifactId> </dependency> ``` 3. 添加bootstrap.yaml配置文件 ```yaml spring: application: name: #微服务名 cloud: servicecomb: discovery: enabled: true address: http://127.0.0.1:30100 appName: basic-application serviceName: ${spring.application.name} version: 0.0.1 healthCheckInterval: 30 config: serverAddr: http://127.0.0.1:30110 serverType: kie ``` 4. 解决启动中的报错 4.1. 需要编写IClientConfig配置类: ![](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20222/18/1645176166364496834.png) ![](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20222/18/1645176147975776732.png) 4.2. 配置类添加 ![](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20222/18/1645176207306600820.png) ![](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20222/18/1645176216784964848.png) 4.3. 微服务里无数据库配置: ![](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20222/18/1645176276185922690.png) 需要在启动类上加`@SpringBootApplication(exclude={DataSourceAutoConfiguration.class})` 4.4. feign调用报错 ![](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20222/18/1645176345773477730.png) SpringCloud Huawei当前版本对负载均衡支持不够友好,openfeign自带负载均衡,建议使用RestTemplate *以下解决方法来自本站的帖子[SpringCloud项目接入华为云微服务引擎CSE(一)](https://bbs.huaweicloud.com/forum/thread-178657-1-1.html)* 4.5. 修改openfeign调用为RestTemplate - 在dtse-system--usercontroller--UpdateIconImage路径对应的方法里注释掉openfeign调用代码 - 添加RestTemplate方式调用的代码 ```java //请求url String url = "http://xxxx:xxxx/xx/x"; ​ //构造请求头 HttpHeaders httpHeaders = new HttpHeaders(); HttpHeaders headers = httpHeaders; headers.setContentType(MediaType.MULTIPART_FORM_DATA); ​ //FileSystemResource将文件变成流以发送 File file = MultipartFileToFile.multipartFileToFile(multipartFile); FileSystemResource fileSystemResource = new FileSystemResource(file); ​ //构造请求体,使用LinkedMultiValueMap MultiValueMap<String, Object> resultMap = new LinkedMultiValueMap<>(); resultMap.add("file", fileSystemResource); resultMap.add("obsParamsJson", obsParamsJson); ​ //HttpEntity封装整个请求报文 HttpEntity<MultiValueMap<String, Object>> httpEntity = new HttpEntity<>(resultMap, headers); ​ //postForObject发送请求体 String objURL = restTemplate.postForObject(url, httpEntity, String.class); ``` **MultipartFile转File:** ```java import org.springframework.web.multipart.MultipartFile; import java.io.File; import java.io.FileOutputStream; import java.io.InputStream; import java.io.OutputStream; ​ public class MultipartFileToFile { /** * MultipartFile 转 File * * @param file * @throws Exception */ public static File multipartFileToFile(MultipartFile file) throws Exception { File toFile = null; if (file.equals("") || file.getSize() <= 0) { file = null; } else { InputStream ins = null; ins = file.getInputStream(); toFile = new File(file.getOriginalFilename()); inputStreamToFile(ins, toFile); ins.close(); } return toFile; } //获取流文件 private static void inputStreamToFile(InputStream ins, File file) { try { OutputStream os = new FileOutputStream(file); int bytesRead = 0; byte[] buffer = new byte[8192]; while ((bytesRead = ins.read(buffer, 0, 8192)) != -1) { os.write(buffer, 0, bytesRead); } os.close(); ins.close(); } catch (Exception e) { e.printStackTrace(); } } /** * 删除本地临时文件 * @param file */ public static void delteTempFile(File file) { if (file != null) { File del = new File(file.toURI()); del.delete(); } } } ``` 4.6 网关改造 - 删除原项目zuul的依赖,添加springcloudgateway的依赖和springcloudhuawei提供的网关依赖 ```xml <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-gateway</artifactId> </dependency> <dependency> <groupId>com.huaweicloud</groupId> <artifactId>spring-cloud-starter-huawei-service-engine-gateway</artifactId> </dependency> ``` - 添加网关配置文件(注意uri不要用lb地址,当前版本涉及负载均衡的均有问题,暂时用固定地址) ```yaml spring: main: allow-bean-definition-overriding: true cloud: gateway: # 路由(routes:路由,它由唯一标识(ID)、目标服务地址(uri)、一组断言(predicates)和一组过滤器组成(filters)。filters 不是必需参数。) routes: #路由标识(id:标识,具有唯一性) - id: dtse-system-route # 目标服务地址(uri:地址,请求转发后的地址) #uri: lb://dtse-system #不要用lb地址 uri: http://localhost:9090 filters: args: # 路由条件(predicates:断言,匹配 HTTP 请求内容) predicates: - Path=/** urifiler: login-uri: /login ``` - 定义全局过滤器实现鉴权 ```java @Component @Slf4j public class RouteConfiguration implements GlobalFilter, Ordered { ​ @Autowired JwtUtil jwtUtil; @Autowired URIFilter uriFilter; ​ @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { ​ ServerHttpRequest request = exchange.getRequest(); RequestPath path = request.getPath(); ​ // 2、登陆请求放行 if(path.value().contains(uriFilter.getLoginuri().get(0))){ System.out.println("登陆请求路经:request.getPath() = " + path.value()); log.info("登录"); return chain.filter(exchange); } //3、非登陆请求用户权限校验 String authorization = request.getHeaders().getFirst("Authorization"); if (!StringUtils.isEmpty((authorization))) { System.out.println("非登陆请求路径:request.getPath() = " + path.value()); //2、获取请求头中Token信息 String token = authorization.replace("Bearer", ""); ​ //3、Token校验 Claims claims = jwtUtil.parseToken(token) ; ​ //4、获取用户id,并将用户id传送到后端 if (claims == null) { try { throw new Exception(String.valueOf(ResultCode.UNAUTHENTICATED)); } catch (Exception e) { e.printStackTrace(); } return null; } String id = claims.getId(); ​ //5、添加用户请求头 request.mutate().header("userId",id).build(); return chain.filter(exchange); } ​ return chain.filter(exchange); } ​ @Override public int getOrder() { return 0; } } ``` - urifiler配置类 ```java @ConfigurationProperties(prefix = "urifiler", ignoreUnknownFields = false) @Data @Component public class URIFilter { private List<String> loginuri; } ``` 4.7 配置中心 在浏览器输入http://127.0.0.1:30103/,进入cse可视化界面,选择配置列表,创建配置项 ![](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20222/21/1645427195901258209.png)
  • [技术交流] SpringCloud项目接入华为云微服务引擎CSE(二)
    目录1.    业务架构说明2.    开发环境3.    本地CSE开发环境搭建    3.1.    下载本地CSE    3.2.    解压,双击cse.exe    3.3.    登录CSE控制台4.    接入前准备    4.1.    下载实验工程源码,使用IDEA打开    4.2.    IDE 配置    4.3.    Maven配置5.    服务端CSE接入    5.1.    主pom修改    5.2.    dtse-feign-client接入    5.3.    dtse-obs-storage接入    5.4.    dtse_system接入    5.5.    dtse-zuuL-gateway网关接入6.    前端服务接入7.    其他接入中问题记录    1. 业务架构说明    项目Gitee地址     后端   https://gitee.com/caichunfu/dtse-practice-microservice     前端   https://gitee.com/HuaweiCloudDeveloper/dtse-practice-frontEnd/tree/devCSE改造前:    • 微服务包含4个微服务模块:zuul-gateway模块、Eureka注册中心、dtse-system模块、obs-storage模块;其中dtse-system模块、obs-storage模块是业务模块。    • 用户发送请求,微服务网关(zuul-gateway) 过滤器根据请求URI,路由和负载均衡请求到不同服务;同时利用JWT进行token校验请求的合法性。    • Eureka注册中心管理zuul-gateway、dtse-system、obs-storage微服务状态;    • dtse-system与obs-storage之间通过feign进行内部接口调用改造技术路径    • 引入使用spring-cloud-huawei    • 使用华为云CSE服务替换Eureka注册中心的功能    • 使用Spring Cloud Gateway替换zuul网关基线版本选择    查看 spring-cloud-huawei官网地址:    https://github.com/huaweicloud/spring-cloud-huawei     通过实践master分支与openFeign存在兼容问题,所以本次实践以Hoxton为基线版本,Hoxten与openFeign不存在兼容性问题    由于Spring Cloud Huawei与zuul调试中发现有兼容问题,所以将网关替换成Spring Cloud Gateway2. 开发环境JDKOpenjdk 1.8.0_312Maven3.6.3IDEA2021.2.2CSELocal-CSE-2.1.3-windows-amd64.zipspring-boot2.3.5.RELEASEspring-cloudHoxton.SR9spring-cloud-huawei1.8.0-Hoxton3. 本地CSE开发环境搭建3.1. 下载本地CSE    https://cse-bucket.obs.cn-north-1.myhuaweicloud.com/LocalCSE/Local-CSE-2.1.3-windows-amd64.zip 3.2. 解压,双击cse.exe3.3. 登录CSE控制台    http://127.0.0.1:30103 4. 接入前准备4.1. 下载实验工程源码,使用IDEA打开    源码地址 https://gitee.com/caichunfu/dtse-practice-microservice 4.2. IDE 配置4.3. Maven配置    使用华为云Maven5. 服务端CSE接入改造5.1. 主pom改造5.1.1. 主pom引入依赖5.1.2. 使用CSE做为注册中心,删除相关模块和依赖    a、删除eureka-server    b、引入华为spring cloud` <properties> <java.version>1.8</java.version> <spring-boot.version>2.3.5.RELEASE</spring-boot.version> <spring-cloud.version>Hoxton.SR9</spring-cloud.version> <spring-cloud-huawei.version>1.8.0-Hoxton</spring-cloud-huawei.version> </properties>`<!-- configure user spring cloud / spring boot versions --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>${spring-boot.version}</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> <!-- configure spring cloud huawei version --> <dependency> <groupId>com.huaweicloud</groupId> <artifactId>spring-cloud-huawei-bom</artifactId> <version>${spring-cloud-huawei.version}</version> <type>pom</type> <scope>import</scope> </dependency>5.2. dtse-feign-client接入5.2.1. 引入openfeign版本<dependency> <groupId>io.github.openfeign.form</groupId> <artifactId>feign-form-spring</artifactId> <version>3.8.0</version> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-openfeign-core</artifactId> <version>3.0.3</version> </dependency>5.3. dtse-obs-storage接入5.3.1. Pom文件处理5.3.1.1. 删除zuul依赖    删除spring-cloud-starter-netflix-zuul,增加spring-cloud-starter-netflix-ribbon <!--wmh add--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-ribbon</artifactId> <version>2.2.0.RELEASE</version> <scope>compile</scope> <exclusions> <exclusion> <artifactId>ribbon-transport</artifactId> <groupId>com.netflix.ribbon</groupId> </exclusion> <exclusion> <artifactId>rxnetty</artifactId> <groupId>io.reactivex</groupId> </exclusion> </exclusions> <optional>true</optional> </dependency> <!-- wmh delete <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-zuul</artifactId> </dependency> -->5.3.2. 引入CSE配置5.3.3. 处理com.netflix.client.config.IClientConfig‘ that could not be found问题    出现这种问题是因为启动类找不到(扫描)其他类的路径,处理方法有多种,我这边使用的是方法二    方法一:把启动类放在其他类文件包的同一级,而不要放在上一级    方法二:在启动类的标签中加入启动扫描的路径如下:    方法三: new个IClientConfig类,不过需要初始化,不然会出现空指针5.3.3.1. 方法二指定扫描路径:    SpringBootApplication指定扫描路径@SpringBootApplication(scanBasePackages = {"com.huaweicloud.controller","com.huaweicloud.service","com.huaweicloud.commons","com.huaweicloud.persistent"}) @EnableFeignClients @EnableDiscoveryClient public class OBSStorageMain { public static void main(String[] args) { SpringApplication.run(OBSStorageMain.class, args); } }5.3.3.2. 方法三增加config类:    IClientConfig 类,重点来了,就是这个类,如果不自己定义(openFeign 是可以自定义这个类的,然后自己初始化),那么就千万不要自己去创建一个 bean 出来,然后自己加上注解定义成配置类如下:@Configuration public class IClientConfig { @Bean public DefaultClientConfigImpl iClientConfig(){ return new DefaultClientConfigImpl(); } }    这玩意千万不要在程序里自己创建出来,可能很多初学者不是很懂,一开始有配置了这个,结果又只是单纯的 return 了一个没有任何属性的 DefaultClientConfigImpl 对象,然后 openFeign 就会使用你创建的这个对象,结果去初始化的时候,就会在源码里面报空指针异常,把这玩意去掉,基本就可以了,如果要自己定义,那记得把里面该有的属性都要初始化值。5.4. Dtse_system接入5.4.1. Pom文件处理    删除eureka client,引入华为service engine <!-- <dependency>--> <!-- <groupId>org.springframework.cloud</groupId>--> <!-- <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>--> <!-- </dependency>--> <dependency> <groupId>com.huaweicloud</groupId> <artifactId>spring-cloud-starter-huawei-service-engine</artifactId> </dependency>删除netflix-hystrix <!-- <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix</artifactId> </dependency>-->5.4.2. 引入CSE配置5.4.3. 处理com.netflix.client.config.IClientConfig‘ that could not be found问题package com.huaweicloud; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.openfeign.EnableFeignClients; @SpringBootApplication(scanBasePackages = {"com.huaweicloud.controller","com.huaweicloud.commons","com.huaweicloud.service","com.huaweicloud.persistent"}) @EnableFeignClients //开启feign客户端调用支持 public class SystemMain { public static void main(String[] args) { SpringApplication.run(SystemMain.class, args); } }5.5. Dtse-zuuL-gateway网关接入    使用spring cloud huawei与zuul有兼容性问题,所以切换到Spring Cloud Gateway5.5.1. Pom文件处理    spring-boot-starter-web排除spring-webmvc包,删除spring-cloud-starter-netflix-zuul包 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <exclusions> <exclusion> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> </exclusion> </exclusions> </dependency>    删除eureka-client包 <!-- <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency>-->    引入spring-cloud-starter-gateway和huawei-service-engine-gateway <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-gateway</artifactId> </dependency> <dependency> <groupId>com.huaweicloud</groupId> <artifactId>spring-cloud-starter-huawei-service-engine-gateway</artifactId> </dependency>5.5.2. 引入CSE配置    修改网关配置5.5.3. 修改网关全局过滤器package com.huaweicloud.filter; import com.huaweicloud.commons.outhUtils.JwtUtil; import com.huaweicloud.commons.response.ResultCode; import com.huaweicloud.config.URIFilter; import io.jsonwebtoken.Claims; import org.apache.servicecomb.foundation.common.utils.JsonUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cloud.gateway.filter.GatewayFilterChain; import org.springframework.cloud.gateway.filter.GlobalFilter; import org.springframework.core.Ordered; import org.springframework.core.annotation.Order; import org.springframework.http.server.RequestPath; import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.stereotype.Component; import org.springframework.util.StringUtils; import org.springframework.web.server.ServerWebExchange; import reactor.core.publisher.Mono; import java.lang.annotation.Annotation; @Component public class RouteConfiguration implements GlobalFilter, Ordered { @Autowired JwtUtil jwtUtil; @Autowired URIFilter uriFilter; private String writeJson(Object o) { try { return JsonUtils.writeValueAsString(o); } catch (Exception ee) { ee.printStackTrace(); } return null; } @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { System.out.println("access filter......"); ServerHttpRequest request = exchange.getRequest(); RequestPath path = request.getPath(); System.out.println("收到请求路经:request.getPath() = " + path.value()); // 2、登陆请求放行 if(path.value().contains(uriFilter.getLoginuri().get(0))){ System.out.println("登陆请求路经:request.getPath() = " + path.value()); return chain.filter(exchange); } //3、非登陆请求用户权限校验 String authorization = request.getHeaders().getFirst("Authorization"); if (!StringUtils.isEmpty((authorization))) { System.out.println("非登陆请求路径:request.getPath() = " + path.value()); //2、获取请求头中Token信息 String token = authorization.replace("Bearer", ""); //3、Token校验 Claims claims = jwtUtil.parseToken(token) ; //4、获取用户id,并将用户id传送到后端 if (claims == null) { try { throw new Exception(String.valueOf(ResultCode.UNAUTHENTICATED)); } catch (Exception e) { e.printStackTrace(); } return null; } String id = claims.getId(); //5、添加用户请求头 request.mutate().header("userId",id).build(); return chain.filter(exchange); } return chain.filter(exchange); } @Override public int getOrder() { return 0; } }5.5.4. 处理com.netflix.client.config.IClientConfig‘ that could not be found问题package com.huaweicloud; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; @SpringBootApplication(exclude = {DataSourceAutoConfiguration.class},scanBasePackages = {"com.huaweicloud.config","com.huaweicloud.filter","com.huaweicloud.commons"}) @EnableDiscoveryClient public class SpringCloudGatewayMain { public static void main(String[] args) throws Exception { SpringApplication.run(SpringCloudGatewayMain.class, args); } }6. 前端服务接入    修改vue.config.js,配置服务网关服务的端口    修改login.Vue,通过网关经过systemmain统一接入,所以修改登录url    修改图片上传接口,和获取用户信息接口7. 其他接入中问题记录7.1. 方便openFeign调试,openFeign调试,增加Feign日志类config 增加类FeignConfigurationpackage com.huaweicloud.config; import feign.Logger; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class FeignConfiguration { /** * 日志级别 * * @return */ @Bean Logger.Level feignLoggerLevel() { return Logger.Level.FULL; } }7.2. Idea 编译报错:Ambiguous method call. Both...    IDEA Settings... > Plugins > 搜索已安装的插件Hrisey Plugins > 禁用该插件 7.3. gateway报错org. springframework.cloud.gateway.config.GatewayAutoConfiguration required a bean of type 'org.springframework.http.codec.ServerCodec Configurer' that could not be found      spring-cloud-starter-gateway依赖与mvc是不兼容的,如果要引用spring-boot-starter-web需要把mvc排除 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <exclusions> <exclusion> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> </exclusion> </exclusions> </dependency>7.4. OpenFeign调用报错com.netflix.client.ClientException: Load balancer does not have available server for client: DTSE-OBS-STORAGE    yml 文件里面的服务名,要和 @FeignClient(value = "xxx") 里面的 xxx 一样,切记别弄错,大小写也要一致
  • [技术交流] SpringCloud项目接入华为云微服务引擎CSE(一)
    1.项目Gitee地址https://gitee.com/caichunfu/dtse-practice-microservice2.运行环境JDK1.8Maven3.6.3本地CSE引擎下载地址:https://support.huaweicloud.com/devg-cse/cse_devg_0036.html3.注意事项踩过的一些坑:3.1依赖导入报错需要把Maven的中央仓库地址改为华为中央仓库地址,修改setting.xml文件      <mirror>          <id>huaweicloud</id>          <mirrorOf>*,!HuaweiCloudSDK</mirrorOf>          <url>https://repo.huaweicloud.com/repository/maven/</url>     </mirror>3.2版本问题官网地址:https://github.com/huaweicloud/spring-cloud-huawei1)使用Hoxton分支,项目启动时ribbon的启动类会报错,建议使用master分支com.huaweicloud.servicecomb.discovery.ribbon.ServiceCombRibbonClientConfiguration required a bean of type 'com.netflix.client.config.IClientConfig' that could not be found.2)master分支1.8.0-2020.0.x与网关存在兼容性问题,建议使用1.6.1-2020.0.x版本3)master分支需要使用 springcloud 2020.x 的版本,这个版本移除了Netflix相关的组件,所以需要对组件进行替换3.3本次测试使用的版本   <properties>       <spring-boot.version>2.5.3</spring-boot.version>       <spring-cloud.version>2020.0.4</spring-cloud.version>       <spring-cloud-huawei.version>1.6.1-2020.0.x</spring-cloud-huawei.version>       <servicecomb.version>2.5.0</servicecomb.version>       <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>   </properties>4.引入依赖4.1父工程引入 <dependencyManagement>      <!-- configure spring cloud huawei version -->      <dependency>        <groupId>com.huaweicloud</groupId>        <artifactId>spring-cloud-huawei-bom</artifactId>        <version>${spring-cloud-huawei.version}</version>        <type>pom</type>        <scope>import</scope>      </dependency>    </dependencies>  </dependencyManagement>4.2子工程引入,并删除eureka相关依赖<dependency>  <groupId>com.huaweicloud</groupId>  <artifactId>spring-cloud-starter-huawei-service-engine</artifactId></dependency>5.创建bootstrap.yml文件spring: application:   name: #微服务名 cloud:   servicecomb:     discovery:       enabled: true       address: http://127.0.0.1:30100       appName: #应用名       serviceName: ${spring.application.name}       version: 0.0.1       healthCheckInterval: 30     config:       serverAddr: http://127.0.0.1:30110       serverType: kie6.启动类添加注解@EnableDiscoveryClient启动本地微服引擎,访问http://127.0.0.1:30103/进入微服务引擎管理界面,查看服务是否注册成功7.启动前遇到的问题7.1报错信息:could not be registered. A bean with that name has already been defined in URL ​Action:​Consider renaming one of the beans or enabling overriding by setting spring.main.allow-bean-definition-overriding=true​无法注册。URL中已经定义了一个具有该名称的bean​考虑重命名一个bean,或者通过设置Spring实现重写。主要的允许bean定义覆盖=true解决方案:yml配置文件添加配置spring: main:   allow-bean-definition-overriding: true7.2报错信息:Action:​Correct the classpath of your application so that it contains a single, compatible version of io.micrometer.core.instrument.distribution.DistributionStatisticConfig$Builder解决方案:pom.xml里面的依赖包有重复,需要将重复的依赖包删除7.3报错信息:此问题只会在使用Honxton版本时出现,建议使用master分支1.6.1-2020.0.x版本Parameter 0 of method ribbonServerList in com.huaweicloud.servicecomb.discovery.ribbon.ServiceCombRibbonClientConfiguration required a bean of type 'com.netflix.client.config.IClientConfig' that could not be found.​Action:​Consider defining a bean of type 'com.netflix.client.config.IClientConfig' in your configuration.解决方案:IClientConfig 类,这个类定义时,不能直接 return 一个没有任何属性的 DefaultClientConfigImpl 对象, openFeign 会在源码里面使用这个对象,报空指针异常,如果要自己定义,需要初始化里面该有的属性@Configurationpublic class IClientConfig {   @Bean   public DefaultClientConfigImpl iClientConfig(){           //网上很多的错误写法       //return new DefaultClientConfigImp();               //加上getClientConfigWithDefaultValues初始化参数       return DefaultClientConfigImpl.getClientConfigWithDefaultValues();   }}8.Feign远程调用使用SpringCloudHuawei做远程调用时会报错,可能兼容性存在问题为了验证问题还原了SpringCloud项目,openfeign调用不会报错报错信息:org.apache.servicecomb.service.center.client.exception.OperationException: get service instances list fails, statusCode = 400; message = Bad Request; content = {"errorCode":"400012","errorMessage":"Micro-service does not exist","detail":"Consumer[30b75156753bc55385a7ae74d0611c77fc5f7522][development/dtse-practice-microservice/dtse-system/0.0.1] find provider[development/dtse-practice-microservice/default/0+] failed, provider does not exist"}​Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.lang.RuntimeException: com.netflix.client.ClientException: Load balancer does not have available server for client: default解决---暂未解决:已对接后端技术专家,暂未解决,解决后会更新进度9.改为RestTemplate方式调用前端参数为MultipartFile和JSON,请求类型为POST    @PostMapping(value = "/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)    public String upLoadOneFile(@RequestPart("file") MultipartFile file, @RequestParam("obsParamsJson") String obsParamsJson) throws IOException {                OBSStorageParams obsParams = JSON.parseObject(obsParamsJson, OBSStorageParams.class);​        String objURL = obsService.uploadOneFile(file.getInputStream(), obsParams);        return objURL;   }RestTemplate调用代码        //请求url        String url = "http://xxxx:xxxx/xx/x";​        //构造请求头        HttpHeaders httpHeaders = new HttpHeaders();        HttpHeaders headers = httpHeaders;        headers.setContentType(MediaType.MULTIPART_FORM_DATA);​        //FileSystemResource将文件变成流以发送        File file = MultipartFileToFile.multipartFileToFile(multipartFile);        FileSystemResource fileSystemResource = new FileSystemResource(file);​        //构造请求体,使用LinkedMultiValueMap        MultiValueMap<String, Object> resultMap = new LinkedMultiValueMap<>();        resultMap.add("file", fileSystemResource);        resultMap.add("obsParamsJson", obsParamsJson);​        //HttpEntity封装整个请求报文        HttpEntity<MultiValueMap<String, Object>> httpEntity = new HttpEntity<>(resultMap, headers);​        //postForObject发送请求体        String objURL = restTemplate.postForObject(url, httpEntity, String.class);MultipartFile转File import org.springframework.web.multipart.MultipartFile; import java.io.File;import java.io.FileOutputStream;import java.io.InputStream;import java.io.OutputStream;​public class MultipartFileToFile {    /**     * MultipartFile 转 File     *     * @param file     * @throws Exception     */    public static File multipartFileToFile(MultipartFile file) throws Exception {        File toFile = null;        if (file.equals("") || file.getSize() <= 0) {            file = null;       } else {            InputStream ins = null;            ins = file.getInputStream();            toFile = new File(file.getOriginalFilename());            inputStreamToFile(ins, toFile);            ins.close();       }        return toFile;   }    //获取流文件    private static void inputStreamToFile(InputStream ins, File file) {        try {            OutputStream os = new FileOutputStream(file);            int bytesRead = 0;            byte[] buffer = new byte[8192];            while ((bytesRead = ins.read(buffer, 0, 8192)) != -1) {                os.write(buffer, 0, bytesRead);           }            os.close();            ins.close();       } catch (Exception e) {            e.printStackTrace();       }   }    /**     * 删除本地临时文件     * @param file     */    public static void delteTempFile(File file) {    if (file != null) {        File del = new File(file.toURI());        del.delete();   }}}10.网关改造官网的说明:Spring Cloud Huawei Hoxton分支只提供Spring Cloud Gateway基于Ribbon的负载均衡,及其配套的基于流量治理和灰度发布功能。 Spring Cloud Huawei master(2020.0.x版本)分支只提供Spring Cloud Gateway基于Spring Cloud LoadBalance的负载均衡, 及其配套的基于流量治理和灰度发布功能。建议Spring Cloud Gateway升级到2020.0.x版本。由于原项目使用的网关为Zuul,需要改为Spring Cloud Gateway10.1删除原项目zuul的依赖,添加springcloudgateway的依赖和springcloudhuawei提供的网关依赖<dependency>   <groupId>org.springframework.cloud</groupId>   <artifactId>spring-cloud-starter-gateway</artifactId></dependency><dependency>   <groupId>com.huaweicloud</groupId>   <artifactId>spring-cloud-starter-huawei-service-engine-gateway</artifactId></dependency>10.2添加网关配置文件spring: main:   allow-bean-definition-overriding: true cloud:   gateway:    # 路由(routes:路由,它由唯一标识(ID)、目标服务地址(uri)、一组断言(predicates)和一组过滤器组成(filters)。filters 不是必需参数。)     routes:     #路由标识(id:标识,具有唯一性)       - id: dtse-system-route        # 目标服务地址(uri:地址,请求转发后的地址)         uri: lb://dtse-system         filters:             args: # 路由条件(predicates:断言,匹配 HTTP 请求内容)         predicates:           - Path=/**urifiler: login-uri: /login10.3定义全局过滤器实现鉴权package com.huaweicloud.filter;​import com.huaweicloud.commons.outhUtils.JwtUtil;import com.huaweicloud.commons.response.ResultCode;import com.huaweicloud.config.URIFilter;import io.jsonwebtoken.Claims;import lombok.extern.slf4j.Slf4j;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.cloud.gateway.filter.GatewayFilterChain;import org.springframework.cloud.gateway.filter.GlobalFilter;import org.springframework.core.Ordered;import org.springframework.http.server.RequestPath;import org.springframework.http.server.reactive.ServerHttpRequest;import org.springframework.stereotype.Component;import org.springframework.util.StringUtils;import org.springframework.web.server.ServerWebExchange;import reactor.core.publisher.Mono;​@Component@Slf4jpublic class RouteConfiguration implements GlobalFilter, Ordered {​    @Autowired    JwtUtil jwtUtil;    @Autowired    URIFilter uriFilter;​    @Override    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {​        ServerHttpRequest request = exchange.getRequest();        RequestPath path = request.getPath();​        // 2、登陆请求放行        if(path.value().contains(uriFilter.getLoginuri().get(0))){            System.out.println("登陆请求路经:request.getPath() = " + path.value());            log.info("登录");            return chain.filter(exchange);       }        //3、非登陆请求用户权限校验        String authorization = request.getHeaders().getFirst("Authorization");        if (!StringUtils.isEmpty((authorization))) {            System.out.println("非登陆请求路径:request.getPath() = " + path.value());            //2、获取请求头中Token信息            String token = authorization.replace("Bearer", "");​            //3、Token校验            Claims claims = jwtUtil.parseToken(token) ;​            //4、获取用户id,并将用户id传送到后端            if (claims == null) {                try {                    throw new Exception(String.valueOf(ResultCode.UNAUTHENTICATED));               } catch (Exception e) {                    e.printStackTrace();               }                return  null;           }            String id = claims.getId();​            //5、添加用户请求头            request.mutate().header("userId",id).build();            return chain.filter(exchange);       }​        return chain.filter(exchange);   }​    @Override    public int getOrder() {        return 0;   }}10.4urifiler配置类@ConfigurationProperties(prefix = "urifiler", ignoreUnknownFields = false)@Data@Componentpublic class URIFilter {   private List<String> loginuri;}11.配置中心的使用访问http://127.0.0.1:30103/进入微服务本地引擎管理界面选择配置列表,创建配置项
  • [交流吐槽] token代替session使用
    1.面临问题:session存在于服务端,分布式中多个微服务,每个微服务都是独立的服务器,session信息不同步,该怎么办?2.解决思路 token替代session使用流程:1.用户登录成功 生成token存入redis(key:token,value:用户信息);把token返回给前端2.将token加入header,使用过滤器,在每个接口执行前验证token是否有效,无效返回登录页3.微服务中如果想获取登录的用户信息,可以获取redis的key=tokentoken + redis优点:1.分布式session,解决同步问题2.单点登录 和(确保系统同一账号登录)3.token统一管理,响应快
  • [Java] spring cloud 的核心组件
    ①. 服务发现——Netflix Eureka一个RESTful服务,用来定位运行在AWS地区(Region)中的中间层服务。由两个组件组成:Eureka服务器和Eureka客户端。Eureka服务器用作服务注册服务器。Eureka客户端是一个java客户端,用来简化与服务器的交互、作为轮询负载均衡器,并提供服务的故障切换支持。Netflix在其生产环境中使用的是另外的客户端,它提供基于流量、资源利用率以及出错状态的加权负载均衡。②. 客服端负载均衡——Netflix RibbonRibbon,主要提供客户侧的软件负载均衡算法。Ribbon客户端组件提供一系列完善的配置选项,比如连接超时、重试、重试算法等。Ribbon内置可插拔、可定制的负载均衡组件。③. 断路器——Netflix Hystrix断路器可以防止一个应用程序多次试图执行一个操作,即很可能失败,允许它继续而不等待故障恢复或者浪费 CPU 周期,而它确定该故障是持久的。断路器模式也使应用程序能够检测故障是否已经解决。如果问题似乎已经得到纠正,应用程序可以尝试调用操作。④. 服务网关——Netflix Zuul类似nginx,反向代理的功能,不过netflix自己增加了一些配合其他组件的特性。⑤. 分布式配置——Spring Cloud Config这个还是静态的,得配合Spring Cloud Bus实现动态的配置更新。来自:https://blog.csdn.net/fangchao2011/article/details/89186765
  • [技术干货] 【转载】spring cloud 2.0 概述
    云社区 博客 博客详情spring cloud 2.0 概述 【摘要】 传统单体架构就是单点应用,也就是在早期开发学习的ssm或ssh整合项目采用分层架构模式、数据库访问层、业务逻辑层、控制层,从前端到后端所有代码都是一个人写的微服务架构演变过程传统单体架构 =》 分布式架构 =》 soa面向服务架构 =》 微服务架构传统单体架构传统单体架构就是单点应用,也就是在早期开发学习的ssm或ssh整合项目采用分层架构模式、数据库访问层、业务逻辑层、控制层,从前端到后端所有代码都是一个人写的cn.itycu.controler ---springmvc 视图层 jsp/ftl cn.itycu.service ---业务逻辑层 cn.itycu.dao ---数据库访问层 将所有的代码都放入到同一个项目中,部署在同一个tomcat中该架构模式存在的优缺点优点:开发简单、运维简单缺点:该架构模式没有对业务逻辑进行拆分,这样子耦合度非常高,只适合小团队或者个人形式开发,不适合团队模式协同工作开发,维护性很难,如果系统中某个模块出现问题,会导致整个系统无法使用。应用场景:政府项目、管理系统、crm、oa,适合于小团队或个人进行开发分布式架构分布式架构模式基于传统的架构模式演变过来,将我们传统的单点系统实现根据业务拆分。会拆分为会员系统、订单系统、支付系统、秒杀系统等。从而降低整个项目的耦合度,这种架构模式开始慢慢适合于互联网公司开发。会员系统 memner.itycu.cn 支付系统 pay.itycu.cn 项目命名为系统意味:包含视图层和服务层soa面向服务架构sso单点登录系统,抽离出通用服务soa面向服务架构基于分布式架构模式演变过来,俗称服务化,也就是面向于服务与接口开发(服务开发),将共同存在的业务逻辑抽取成一个公共服务,提供给其他接口实现调用,服务与服务之间采用rpc远程调用技术。服务:只是有接口、没有视图层cn.itycu.service cn.itycu.dao能够解决我们的代码冗余性问题soa架构模式特点传统政府、银行项目还是保留的在使用webservicewebservice架构模式wsdl组件表示接口信息、方法、调用地址、参数soa架构模式传输协议采用soap协议(HTTP/https+xml)实现传输,在高并发情况下实现通讯协议存在大量的冗余性传输,而且非常占用带宽。所以后来微服务架构中使用json替代了xml。soa架构模式实现方案webservice或者esb企业服务总线,底层采用soap传输协议。soa架构模式存在缺点前后端分离就是对我们控制层和业务逻辑实现区分,前端控制可以采用vue调用我们后端接口(http+json)采用soap协议实现通讯,xml传输非常重,效率比较低。服务化管理和治理设施不够完善依赖于中心服务发现机制不适合前后端分离架构模式微服务架构微服务架构模式基于soa架构模式演变过来的,比soa架构迷失对服务拆分力度会更加精细,采用前后端分离模式让专业的人做专业的事(专注),目的可以实现高效率开发。微服务架构中,每个服务之间都是互不影响,每个服务必须要独立部署、运维、互不影响,微服务架构模式非常轻巧,轻量级、适合于互联网公司开发模式。服务与服务之间通讯的协议采用restful形式,数据交换格式采用http+json格式实现传输整个过程中,采用二进制,所以http协议可以实现跨语言的平台,并且和其他语言实现通讯,所以为什么开放都是采用http+json格式传输SOA架构与微服务架构有哪些区别微服务架构模式比soa架构模式,更加适合于互联网公司敏捷、高效、快速迭代版本开发,因为力度非常精细。微服务架构模式比soa架构模式拆分力度更加精细,提倡让专业的人做专业的事,目的是实现高效的开发,每个服务与服务之间互不影响,每个服务都是单独独立数据库、redis连接、MQ等。并且都是实现独立部署,整个微服务架构更加轻量级。在soa架构中,有可能纯在多个服务共享同一个数据库,但是微服务架构必须强调每个都是独立数据库部署,互不影响。微服务架构基于soa架构模式演变过来,继承了soa架构的优点,在微服务架构中去除soa架构中soap协议和esp企业服务总线。改为http+json形式传输我们的数据。esb企业服务总线解决多系统间跨语言无法实现通讯的问题,对我们的数据实现转换,可以提供可靠的消息传输。一般情况我们采用http+json传输数据,不需要esb对数据进行转换。通讯协议服务拆分力度迭代微服务架构中可能会存在哪些问题分布式事务解决方案(rabbitmq、rocketmq事务消息、lcn(淘汰)、setata)最终一级概念分布式任务调度平台(xxl-job、elastic-job)分布式服务注册与发现(eureka、consul、zookeeper、nacos)分布式日志采集系统elk+kafka分布式服务最综与调用链系统zipkin分布式服务配置中心(spring cloud config/携程阿波罗/nacos/disconfig)微服务架构中有个非常重要的概念:独立部署、可配置、动态化。为什么要使用到spring cloudspring cloud 并不是一个rpc远程调用框架,而是一个微服务全家桶的解决方案的框架。理念就是***服务解决我们在微服务架构中遇到的问题。服务治理:eureka分布式配置:config客户端调用工具:rest/feign客户 rpc远程调用说明:阿里巴巴、腾讯、百度注意:大家如果去一些比较大型的互联网公司中,整个公司内部实现rpc通讯的框架、服务帮助治理都是内部自己研发。rpc远程调用框架:HTTPclent、dubbo、feign、grpc、基于netty手写rpcspring cloud一代和二代的区别spring cloud第一代实际上采用Netflix开源的组件整合微服务解决方案。spring cloud第二代实际上就是自己研发和国内的优秀的服务解决微服务框架进行组合。nacos实现服务注册于发现微服务服务治理核心概念Nacos产生背景rpc远程调用框架:HTTP client、grpc、dubbo、rest、openfeign等。传统rpc远程调用中存在哪些问题?超时、安全、服务与服务之间的url地址管理在我们的微服务架构通讯中,服务间依赖非常大,如果使用传统方式管理我们的服务,非常麻烦,所以采用url治理技术,可以实现我们整个实现动态服务注册与发现、本地负载均衡、容错等nacos分布式注册与发现功能 | 分布式配置中心产生于rpc远程调用中,服务的url的治理传统服务注册中心的实现方式把每个服务器的地址信息和端口号人工存放到数据库表中IdserviceIP端口号1itycu.cn192.168.1.180802itycu.cn192.168.1.18000维护成本高没有实现动态自动化基于数据库形式实现服务url治理的缺点分布式注册中心实现原理注册中心的作用管理整个微服务url地址可以实现动态感知注册中心:duboo依赖zookeeper、eureka、consul、nacos、redis、数据库nacos与eureka的区别eureka与zookeeper的区别注册中心的原理keyIP端口号服务名称192.168.1.18080生产者启动时,根据这种存储方式注册到微服务注册中心根据以上存储方式的服务名称获取到IP地址和端口号获取到地址后在本地实现rpc远程调用生产者:提供我们接口被其他服务调用消费者:调用接口实现服务服务注册:提供服务接口地址信息存放Naxos基本介绍实现注册中心和分布式配置中心默认账号密码:nacos使用命令模式实现对nacos的注册使用discovertyClient从注册中心获取接口地址使用rest Template实现rpc远程调用纯手写本地负载均衡轮询算法实现线下服务动态感知
  • [技术干货] 【转载】spring cloud 2.0 概述
    微服务架构演变过程传统单体架构 =》 分布式架构 =》 soa面向服务架构 =》 微服务架构传统单体架构传统单体架构就是单点应用,也就是在早期开发学习的ssm或ssh整合项目采用分层架构模式、数据库访问层、业务逻辑层、控制层,从前端到后端所有代码都是一个人写的cn.itycu.controler ---springmvc 视图层 jsp/ftl cn.itycu.service ---业务逻辑层 cn.itycu.dao ---数据库访问层 将所有的代码都放入到同一个项目中,部署在同一个tomcat中该架构模式存在的优缺点优点:开发简单、运维简单缺点:该架构模式没有对业务逻辑进行拆分,这样子耦合度非常高,只适合小团队或者个人形式开发,不适合团队模式协同工作开发,维护性很难,如果系统中某个模块出现问题,会导致整个系统无法使用。应用场景:政府项目、管理系统、crm、oa,适合于小团队或个人进行开发分布式架构分布式架构模式基于传统的架构模式演变过来,将我们传统的单点系统实现根据业务拆分。会拆分为会员系统、订单系统、支付系统、秒杀系统等。从而降低整个项目的耦合度,这种架构模式开始慢慢适合于互联网公司开发。会员系统 memner.itycu.cn 支付系统 pay.itycu.cn 项目命名为系统意味:包含视图层和服务层soa面向服务架构sso单点登录系统,抽离出通用服务soa面向服务架构基于分布式架构模式演变过来,俗称服务化,也就是面向于服务与接口开发(服务开发),将共同存在的业务逻辑抽取成一个公共服务,提供给其他接口实现调用,服务与服务之间采用rpc远程调用技术。服务:只是有接口、没有视图层cn.itycu.service cn.itycu.dao能够解决我们的代码冗余性问题soa架构模式特点传统政府、银行项目还是保留的在使用webservicewebservice架构模式wsdl组件表示接口信息、方法、调用地址、参数soa架构模式传输协议采用soap协议(HTTP/https+xml)实现传输,在高并发情况下实现通讯协议存在大量的冗余性传输,而且非常占用带宽。所以后来微服务架构中使用json替代了xml。soa架构模式实现方案webservice或者esb企业服务总线,底层采用soap传输协议。soa架构模式存在缺点前后端分离就是对我们控制层和业务逻辑实现区分,前端控制可以采用vue调用我们后端接口(http+json)采用soap协议实现通讯,xml传输非常重,效率比较低。服务化管理和治理设施不够完善依赖于中心服务发现机制不适合前后端分离架构模式微服务架构微服务架构模式基于soa架构模式演变过来的,比soa架构迷失对服务拆分力度会更加精细,采用前后端分离模式让专业的人做专业的事(专注),目的可以实现高效率开发。微服务架构中,每个服务之间都是互不影响,每个服务必须要独立部署、运维、互不影响,微服务架构模式非常轻巧,轻量级、适合于互联网公司开发模式。服务与服务之间通讯的协议采用restful形式,数据交换格式采用http+json格式实现传输整个过程中,采用二进制,所以http协议可以实现跨语言的平台,并且和其他语言实现通讯,所以为什么开放都是采用http+json格式传输SOA架构与微服务架构有哪些区别微服务架构模式比soa架构模式,更加适合于互联网公司敏捷、高效、快速迭代版本开发,因为力度非常精细。微服务架构模式比soa架构模式拆分力度更加精细,提倡让专业的人做专业的事,目的是实现高效的开发,每个服务与服务之间互不影响,每个服务都是单独独立数据库、redis连接、MQ等。并且都是实现独立部署,整个微服务架构更加轻量级。在soa架构中,有可能纯在多个服务共享同一个数据库,但是微服务架构必须强调每个都是独立数据库部署,互不影响。微服务架构基于soa架构模式演变过来,继承了soa架构的优点,在微服务架构中去除soa架构中soap协议和esp企业服务总线。改为http+json形式传输我们的数据。esb企业服务总线解决多系统间跨语言无法实现通讯的问题,对我们的数据实现转换,可以提供可靠的消息传输。一般情况我们采用http+json传输数据,不需要esb对数据进行转换。通讯协议服务拆分力度迭代微服务架构中可能会存在哪些问题分布式事务解决方案(rabbitmq、rocketmq事务消息、lcn(淘汰)、setata)最终一级概念分布式任务调度平台(xxl-job、elastic-job)分布式服务注册与发现(eureka、consul、zookeeper、nacos)分布式日志采集系统elk+kafka分布式服务最综与调用链系统zipkin分布式服务配置中心(spring cloud config/携程阿波罗/nacos/disconfig)微服务架构中有个非常重要的概念:独立部署、可配置、动态化。为什么要使用到spring cloudspring cloud 并不是一个rpc远程调用框架,而是一个微服务全家桶的解决方案的框架。理念就是***服务解决我们在微服务架构中遇到的问题。服务治理:eureka分布式配置:config客户端调用工具:rest/feign客户 rpc远程调用说明:阿里巴巴、腾讯、百度注意:大家如果去一些比较大型的互联网公司中,整个公司内部实现rpc通讯的框架、服务帮助治理都是内部自己研发。rpc远程调用框架:HTTPclent、dubbo、feign、grpc、基于netty手写rpcspring cloud一代和二代的区别spring cloud第一代实际上采用Netflix开源的组件整合微服务解决方案。spring cloud第二代实际上就是自己研发和国内的优秀的服务解决微服务框架进行组合。nacos实现服务注册于发现微服务服务治理核心概念Nacos产生背景rpc远程调用框架:HTTP client、grpc、dubbo、rest、openfeign等。传统rpc远程调用中存在哪些问题?超时、安全、服务与服务之间的url地址管理在我们的微服务架构通讯中,服务间依赖非常大,如果使用传统方式管理我们的服务,非常麻烦,所以采用url治理技术,可以实现我们整个实现动态服务注册与发现、本地负载均衡、容错等nacos分布式注册与发现功能 | 分布式配置中心产生于rpc远程调用中,服务的url的治理传统服务注册中心的实现方式把每个服务器的地址信息和端口号人工存放到数据库表中IdserviceIP端口号1itycu.cn192.168.1.180802itycu.cn192.168.1.18000维护成本高没有实现动态自动化基于数据库形式实现服务url治理的缺点分布式注册中心实现原理注册中心的作用管理整个微服务url地址可以实现动态感知注册中心:duboo依赖zookeeper、eureka、consul、nacos、redis、数据库nacos与eureka的区别eureka与zookeeper的区别注册中心的原理keyIP端口号服务名称192.168.1.18080生产者启动时,根据这种存储方式注册到微服务注册中心根据以上存储方式的服务名称获取到IP地址和端口号获取到地址后在本地实现rpc远程调用生产者:提供我们接口被其他服务调用消费者:调用接口实现服务服务注册:提供服务接口地址信息存放Naxos基本介绍实现注册中心和分布式配置中心默认账号密码:nacos使用命令模式实现对nacos的注册使用discovertyClient从注册中心获取接口地址使用rest Template实现rpc远程调用纯手写本地负载均衡轮询算法实现线下服务动态感知
  • [热门活动] 直播大放送:《对接SpringCloud?一课接入华为云ServiceStage应用平台!》参与直播赢好礼!
     直播简介:如何实现spring cloud应用无缝接入ServiceStage应用平台?看直播听华为云微服务专家现场手把手教你应用部署上云 直播时间:7.9 19:30-20:30直播参与流程:1.   加小助手好友报名进入直播群2.   与下方体验任务(获码豆换好礼)3.   等待7.9 19:30-20:30直播开始直播链接:https://bbs.huaweicloud.com/signup/b86fe50c0f7e48b4a8aba2de41f04f8e 奖励&规则任务一:分享任务规则&奖励:点击领取任务(加超链接)活动时间:2020年7月01日-2020年7月09日分享海报,可获得500码豆激励!第一步: 分享以下文案+海报至朋友圈或100人以上技术群(微信、QQ、钉钉不限)。分享可获得500码豆!码豆可用于兑换DevCloud会员中心精美实物礼品。(1)文案:我正在参与华为云直播《对接SpringCloud?一课接入华为云ServiceStage应用平台!》,看华为云专家教你如何实现SpringCloud原生应用快速接入搞性能网关,对接ServiceStage服务平台,看直播还能赢好礼,快来参加吧!(2)海报:添加小助手微信(little-one-1806)或扫下方二维码,回复“分享海报”获取海报和文案。第二步: 分享完成后,截图并点击链接https://www.wjx.top/jq/83359544.aspx上传分享截图;符合要求的截图即可算作分享成功,获得500码豆!码豆奖励会在直播活动结束后15个工作日内发放注意:为保证码豆成功发放,请先登录一次会员中心 任务二:体验任务规则&奖励:活动时间:2020年7月01日-2020年7月09日完成体验产品任务,可获得1000码豆激励!第一步: 体验产品,跟着教程指引点点点就可获得1000码豆!产品体验指导https://bbs.huaweicloud.com/forum/thread-63353-1-1.html码豆可用于兑换DevCloud会员中心精美实物礼品。第二步:体验完成后,截图并在教程帖盖楼回复上传分享截图;符合要求的截图即可算作分享成功,获得1000码豆!码豆奖励会在直播活动结束后15个工作日内发放注意:为保证码豆成功发放,请先登录一次会员中心请务必按照以下格式要求进行回帖打卡,否则无法计算奖励:华为云账号名:XXX(即右上角的字母数字组合ID)微信昵称:XXX 打卡样例图:添加小助手微信:little-one-1806 或 扫下方二维码添加小助手回复”微服务“报名 进群了解更多微服务信息,直播开始前,小助手会在群里pick大家看直播哦~任务三:直播抽奖观看直播并参与评论互动,就有机会获得《微服务架构与实践(第2版)》书籍1本,直播结束后5个工作日内寄出奖品
  • [热门活动] 直播大放送:《对接SpringCloud?一课接入华为云ServiceStage应用平台!》体验任务教程帖
     【7.9直播活动码豆发放公示】感谢各位小伙伴参与本期活动!本期直播活动已于7月9日24:00结束,满足码豆发放条件的名单已公布,详见附件表格为保证码豆成功发放,请名单中的小伙伴于7月23日先登录一次会员中心,以便码豆发放码豆将于7月24日发放到账,请及时参与。未及时登录会员中心或未到账的用户请于7月30日登录一次会员中心,我们会通知相关人员于7月31日补发码豆,请及时参与,错过不再补发。直播简介:如何实现spring cloud应用无缝接入ServiceStage应用平台?看直播听华为云微服务专家现场手把手教你应用部署上云 直播时间:7.9 19:30-20:30直播参与流程:1.   加小助手好友报名进入直播群2.   与下方体验任务(获码豆换好礼)3.   等待7.9 19:30-20:30直播开始直播观看链接:https://bbs.huaweicloud.com/signup/b86fe50c0f7e48b4a8aba2de41f04f8e返回活动帖入口:https://bbs.huaweicloud.com/forum/thread-63361-1-1.html体验任务教程动动手指赢码豆,点点点教程开始啦~ 单击体验链接并登录后,进入如下界面: 单击“开始教程”开始体验 跟随指引单击下一步 在应用运维这一步截图并单击完成,结束体验。截图注意一起截取用户名。  完成后,截图并在本帖盖楼回复上传体验截图;前100名符合要求的截图即可算作体验成功,获得1000码豆!码豆奖励会在直播活动结束后15个工作日内发放,请注意查收哦~请务必按照以下格式要求进行回帖打卡,否则无法计算奖励:华为云账号名:XXX(即右上角的字母数字组合ID)微信昵称:XXX 打卡样例图: 
  • [问题求助] spring cloud 项目用 CSE 框架改造,配置中心这些配置如何迁移?
    spring cloud 项目 迁移到 CSE 框架。配置中心的那些yaml 文件,如果迁移到 CSE 配置中心呢? CSE 全局配置项,跟spring cloud 配置中心的 数据如何迁移 让 项目通用的配置抽取出来!
  • [问题求助] CSE可以和spring cloud stream 兼容吗
    加上EnableBinding注解后,启动报端口占用错误猜测是先启动了vertx rest的端口后面再启动spring的tomcat的时候报错了下面是pom和父pom4.0.0com.huawei.aciotparent1.0-SNAPSHOTdevice-common0.0.1-SNAPSHOTdevice-commonDemo project for Spring Boot1.8org.projectlomboklomboktrueorg.apache.servicecombhandler-tracing-zipkinorg.springframework.cloudspring-cloud-stream-test-supporttestorg.springframework.cloudspring-cloud-streamorg.springframework.cloudspring-cloud-stream-binder-kafkaorg.springframework.kafkaspring-kafkacom.huawei.eciotcore-util0.0.1-SNAPSHOT父pomorg.springframework.bootspring-boot-starter-parent2.1.6.RELEASEpomimportorg.springframeworkspring-core5.1.8.RELEASEpomimportcom.huawei.paas.csecse-dependency-spring-boot26.5.62pomimportcom.huawei.paas.csecse-solution-service-engineorg.slf4jslf4j-log4j12org.apache.servicecombspring-boot2-starter-servletorg.springframework.bootspring-boot-starter-testtestyaml:   :     : device-common :   : 8090   :     : /device-north : ac-iot :   : device   : 0.0.1             :     : true   : development :   :     :       : false   :     : 192.188.240.32:${server.port}   :     : /device   :     :       : http://192.88.16.46:30100      :   :     :       :         : loadbalance,tracing-consumer       :         : tracing-provider   :     :       : http://localhost:9411大佬们帮忙看一下是哪里配错了吗
  • [技术干货] 方志朋-SpringCloud系列:Spring Cloud Consul 之Greenwich版本全攻略-2
    微服务架构是一个分布式架构,微服务系统按业务划分服务单元,一个微服务系统往往有很多个服务单元。由于服务单元数量众多,业务的复杂性较高,如果出现了错误和异常,很难去定位。主要体现在一个请求可能需要调用很多个服务,而内部服务的调用复杂性决定了问题难以定位。所以在微服务架构中,必须实现分布式链路追踪,去跟进一个请求到底有哪些服务参与,参与的顺序又是怎样的,从而达到每个请求的步骤清晰可见,出了问题能够快速定位的目的。                  在微服务系统中,一个来自用户的请求先到达前端A(如前端界面),然后通过远程调用,到达系统的中间件B、C(如负载均衡、网关等),最后到达后端服务D、E,后端经过一系列的业务逻辑计算,最后将数据返回给用户。对于这样一个请求,经历了这么多个服务,怎么样将它的请求过程用数据记录下来呢?这就需要用到服务链路追踪。Spring Cloud SleuthSpring Cloud Sleuth 为服务之间调用提供链路追踪。通过Sleuth 可以很清楚的了解到一个服务请求经过了哪些服务,每个服务处理花费了多长。从而让我们可以很方便的理清各微服务间的调用关系。此外Sleuth 可以帮助我们:§ 耗时分析: 通过Sleuth 可以很方便的了解到每个采样请求的耗时,从而分析出哪些服务调用比较耗时;§ 可视化错误: 对于程序未捕捉的异常,可以通过集成Zipkin 服务界面上看到;§ 链路优化: 对于调用比较频繁的服务,可以针对这些服务实施一些优化措施。Google开源了Dapper链路追踪组件,并在2010年发表了论文《Dapper, a Large-Scale Distributed Systems Tracing Infrastructure》,这篇论文是业内实现链路追踪的标杆和理论基础,具有很高的参考价值。Spring Cloud Sleuth采用了Google的开源项目Dapper的专业术语。§ Span:基本工作单元,发送一个远程调度任务就会产生一个Span,Span是用一个64位ID唯一标识的,Trace是用另一个64位ID唯一标识的。Span还包含了其他的信息,例如摘要、时间戳事件、Span的ID以及进程ID。§ Trace:由一系列Span组成的,呈树状结构。请求一个微服务系统的API接口,这个API接口需要调用多个微服务单元,调用每个微服务单元都会产生一个新的Span,所有由这个请求产生的Span组成了这个Trace。§ Annotation:用于记录一个事件,一些核心注解用于定义一个请求的开始和结束,这些注解如下。o   cs-Client Sent:客户端发送一个请求,这个注解描述了Span的开始。o   sr-Server Received:服务端获得请求并准备开始处理它,如果将其sr减去cs时间戳,便可得到网络传输的时间。o   ss-Server Sent:服务端发送响应,该注解表明请求处理的完成(当请求返回客户端),用ss的时间戳减去sr时间戳,便可以得到服务器请求的时间。o   cr-Client Received:客户端接收响应,此时Span结束,如果cr的时间戳减去cs时间戳,便可以得到整个请求所消耗的时间。Spring Cloud Sleuth 也为我们提供了一套完整的链路解决方案,Spring Cloud Sleuth 可以结合Zipkin,将信息发送到Zipkin,利用Zipkin 的存储来存储链路信息,利用Zipkin UI 来展示数据。ZipkinZipkin是一种分布式链路追踪系统。它有助于收集解决微服务架构中的延迟问题所需的时序数据。它管理这些数据的收集和查找。Zipkin的设计基于Google Dapper论文。跟踪器存在于应用程序中,记录请求调用的时间和元数据。跟踪器使用库,它们的使用对用户是无感知的。例如,Web服务器会在收到请求时和发送响应时会记录相应的时间和一些元数据。一次完整链路请求所收集的数据被称为Span。我们可以使用它来收集各个服务器上请求链路的跟踪数据,并通过它提供的REST API 接口来辅助我们查询跟踪数据以实现对分布式系统的监控程序,从而及时地发现系统中出现的延迟升高问题并找出系统性能瓶颈的根源。除了面向开发的API 接口之外,它也提供了方便的UI 组件来帮助我们直观的搜索跟踪信息和分析请求链路明细,比如:可以查询某段时间内各用户请求的处理时间等。Zipkin 提供了可插拔数据存储方式:In-Memory、MySql、Cassandra 以及Elasticsearch。接下来的测试为方便直接采用In-Memory 方式进行存储,生产推荐Elasticsearch.上图展示了Zipkin 的基础架构,它主要由4 个核心组件构成:§ Collector:收集器组件,它主要用于处理从外部系统发送过来的跟踪信息,将这些信息转换为Zipkin 内部处理的Span 格式,以支持后续的存储、分析、展示等功能。§ Storage:存储组件,它主要对处理收集器接收到的跟踪信息,默认会将这些信息存储在内存中,我们也可以修改此存储策略,通过使用其他存储组件将跟踪信息存储到数据库中。§ RESTful API:API 组件,它主要用来提供外部访问接口。比如给客户端展示跟踪信息,或是外接系统访问以实现监控等。§ Web UI:UI 组件,基于API 组件实现的上层应用。通过UI 组件用户可以方便而有直观地查询和分析跟踪信息。案例实战在本案例一共有三个应用,分别为注册中心,eureka-server、eureka-client、eureka-client-feign,三个应用的基本信息如下:应用名端口作用eureka-server8761注册中心eureka-client8763服务提供者eureka-client-feign8765服务消费者其中eureka-server 应用为注册中心,其他两个应用向它注册。eureka-client为服务提供者,提供了一个RESTAPI,eureka-client-feign为服务消费者,通过Feign Client向服务提供者消费服务。在之前的文章已经讲述了如何如何搭建服务注册中心,在这里就省略这一部分内容。服务提供者提供一个REST接口,服务消费者通过FeignClient消费服务。服务提供者eureka-client服务提供者,对外提供一个RESTAPI,并向服务注册中心注册,这部分内容,不再讲述,见源码。需要在工程的pom文件加上sleuth的起步依赖和zipkin的起步依赖,代码如下:1.  <dependency>2.      <groupId>org.springframework.cloud</groupId>3.      <artifactId>spring-cloud-starter-sleuth</artifactId>4.  </dependency>5.  <dependency>6.      <groupId>org.springframework.cloud</groupId>7.      <artifactId>spring-cloud-starter-zipkin</artifactId>8.  </dependency>在工程的配置文件application.yml需要做以下的配置:1.  spring:2.    sleuth:3.      web:4.        client:5.          enabled:true6.      sampler:7.        probability:1.0 # 将采样比例设置为1.0,也就是全部都需要。默认是0.18.    zipkin:9.      base-url:http://localhost:9411/ # 指定了Zipkin 服务器的地址其中spring.sleuth.web.client.enable为true设置的是web开启sleuth功能;spring.sleuth.sampler.probability可以设置为小数,最大值为1.0,当设置为1.0时就是链路数据100%收集到zipkin-server,当设置为0.1时,即10%概率收集链路数据;spring.zipkin.base-url设置zipkin-server的地址。对外提供一个Api,代码如下:1.  @RestController2.  publicclassHiController{3.    4.      @Value("${server.port}")5.      Stringport;6.      @GetMapping("/hi")7.      publicStringhome(@RequestParamStringname){8.          return"hi "+name+",i am from port:"+port;9.      }10.   11.  }服务消费者服务消费者通过FeignClient消费服务提供者提供的服务。同服务提供者一样,需要在工程的pom文件加上sleuth的起步依赖和zipkin的起步依赖,另外也需要在配置文件application.yml做相关的配置,具体同服务提供者。服务消费者通过feignClient进行服务消费,feignclient代码如下:1.  @FeignClient(value ="eureka-client",configuration =FeignConfig.class)2.  publicinterfaceEurekaClientFeign{3.    4.      @GetMapping(value ="/hi")5.      StringsayHiFromClientEureka(@RequestParam(value ="name")Stringname);6.  }servcie层代码如下:1.  @Service2.  publicclassHiService{3.    4.      @Autowired5.      EurekaClientFeigneurekaClientFeign;6.    7.    8.      publicStringsayHi(Stringname){9.          return eurekaClientFeign.sayHiFromClientEureka(name);10.      }11.  }controller代码如下:1.  @RestController2.  publicclassHiController{3.      @Autowired4.      HiServicehiService;5.    6.      @GetMapping("/hi")7.      publicStringsayHi(@RequestParam(defaultValue ="forezp",required =false)Stringname){8.          returnhiService.sayHi(name);9.      }上面的代码对外暴露一个API,通过FeignClient的方式调用eureka-client的服务。zipkin-server在Spring Cloud D版本,zipkin-server通过引入依赖的方式构建工程,自从E版本之后,这一方式改变了,采用官方的jar形式启动,所以需要通过下载官方的jar来启动,也通过以下命令一键启动:1.  curl -sSL https://zipkin.io/quickstart.sh | bash -s2.  java -jar zipkin.jar上面的第一行命令会从zipkin官网下载官方的jar包。如果是window系统,建议使用gitbash执行上面的命令。如果用Docker 的话,使用以下命令:1.  docker run -d -p 9411:9411openzipkin/zipkin通过java -jar zipkin.jar的方式启动之后,在浏览器**问lcoalhost:9411,显示的界面如下:链路数据验证依次启动eureka-server,eureka-client,eureka-client-feign的三个应用,等所有应用启动完成后,在浏览器**问http://localhost:8765/hi(如果报错,是服务与发现需要一定的时间,耐心等待几十秒),访问成功后,再次在浏览器**问zipkin-server的页面,显示如下:从上图可以看出每次请求所消耗的时间,以及一些span的信息。从上图可以看出具体的服务依赖关系,eureka-feign-client依赖了eureka-client。使用rabbitmq进行链路数据收集在上面的案例中使用的http请求的方式将链路数据发送给zipkin-server,其实还可以使用rabbitmq的方式进行服务的消费。使用rabbitmq需要安装rabbitmq程序,下载地址http://www.rabbitmq.com/。下载完成后,需要eureka-client和eureka-client-feign的起步依赖加上rabbitmq的依赖,依赖如下:1.  <dependency>2.      <groupId>org.springframework.cloud</groupId>3.      <artifactId>spring-cloud-stream-binder-rabbit</artifactId>4.  </dependency>在配置文件上需要配置rabbitmq的配置,配置信息如下:1.  spring:2.    rabbitmq:3.      host:localhost4.      username:guest5.      password:guest6.      port:5672另外需要把spring.zipkin.base-url去掉。在上面2个工程中,rabbitmq通过发送链路数据,那么zipkin-server是怎么样知道rabbitmq的地址呢,怎么监听收到的链路数据呢?这需要在程序启动的时候,通过环境变量的形式到环境中,然后zikin-server从环境变量中读取。可配置的属性如下:属性环境变量描述zipkin.collector.rabbitmq.addressesRABBIT_ADDRESSES用逗号分隔的RabbitMQ 地址列表,例如localhost:5672,localhost:5673zipkin.collector.rabbitmq.passwordRABBIT_PASSWORD连接到RabbitMQ 时使用的密码,默认为guestzipkin.collector.rabbitmq.usernameRABBIT_USER连接到RabbitMQ 时使用的用户名,默认为guestzipkin.collector.rabbitmq.virtual-hostRABBITVIRTUALHOST使用的RabbitMQ virtual host,默认为/zipkin.collector.rabbitmq.use-sslRABBITUSESSL设置为true则用SSL 的方式与RabbitMQ 建立链接zipkin.collector.rabbitmq.concurrencyRABBIT_CONCURRENCY并发消费者数量,默认为1zipkin.collector.rabbitmq.connection-timeoutRABBITCONNECTIONTIMEOUT建立连接时的超时时间,默认为60000毫秒,即1 分钟zipkin.collector.rabbitmq.queueRABBIT_QUEUE从中获取span 信息的队列,默认为zipkin比如,通过以下命令启动:1.  RABBIT_ADDRESSES=localhost java-jar zipkin.jar上面的命令等同于一下的命令:1.  java -jar zipkin.jar --zipkin.collector.rabbitmq.addressed=localhost用上面的2条命令中的任何一种方式重新启动zipkin-server程序,并重新启动eureka-client、eureka-server、eureka-client-feign,动完成后在浏览器**问http://localhost:8765/hi,再访问http://localhost:9411/zipkin/,就可以看到通过Http方式发送链路数据一样的接口。自定义Tag在页面上可以查看每个请求的traceId,每个trace又包含若干的span,每个span又包含了很多的tag,自定义tag可以通过Tracer这个类来自定义。1.  @Autowired2.  Tracertracer;3.    4.   @GetMapping("/hi")5.      publicStringhome(@RequestParamStringname){6.          tracer.currentSpan().tag("name","forezp");7.          return"hi "+name+",i am from port:"+port;8.      }将链路数据存储在Mysql数据库中上面的例子是将链路数据存在内存中,只要zipkin-server重启之后,之前的链路数据全部查找不到了,zipkin是支持将链路数据存储在mysql、cassandra、elasticsearch中的。现在讲解如何将链路数据存储在Mysql数据库中。首先需要初始化zikin存储在Mysql的数据的scheme,可以在这里查看https://github.com/openzipkin/zipkin/blob/master/zipkin-storage/mysql-v1/src/main/resources/mysql.sql,具体如下:1.  CREATE TABLE IF NOT EXISTS zipkin_spans (2.    `trace_id_high`BIGINT NOT NULL DEFAULT 0COMMENT 'If non zero, this means the trace uses 128 bit traceIds instead of 64 bit',3.    `trace_id`BIGINT NOT NULL,4.    `id`BIGINT NOT NULL,5.    `name`VARCHAR(255)NOT NULL,6.    `parent_id`BIGINT,7.    `debug`BIT(1),8.    `start_ts`BIGINT COMMENT 'Span.timestamp(): epoch micros used for endTs query and to implement TTL',9.    `duration`BIGINT COMMENT 'Span.duration(): micros used for minDuration and maxDuration query'10.  )ENGINE=InnoDBROW_FORMAT=COMPRESSED CHARACTER SET=utf8 COLLATE utf8_general_ci;11.   12.  ALTER TABLE zipkin_spans ADD UNIQUE KEY(`trace_id_high`,`trace_id`,`id`)COMMENT 'ignore insert on duplicate';13.  ALTER TABLE zipkin_spans ADD INDEX(`trace_id_high`,`trace_id`,`id`)COMMENT 'for joining with zipkin_annotations';14.  ALTER TABLE zipkin_spans ADD INDEX(`trace_id_high`,`trace_id`)COMMENT 'for getTracesByIds';15.  ALTER TABLE zipkin_spans ADD INDEX(`name`)COMMENT 'for getTraces and getSpanNames';16.  ALTER TABLE zipkin_spans ADD INDEX(`start_ts`)COMMENT 'for getTraces ordering and range';17.   18.  CREATE TABLE IF NOT EXISTS zipkin_annotations (19.    `trace_id_high`BIGINT NOT NULL DEFAULT 0COMMENT 'If non zero, this means the trace uses 128 bit traceIds instead of 64 bit',20.    `trace_id`BIGINT NOT NULL COMMENT 'coincides with zipkin_spans.trace_id',21.    `span_id`BIGINT NOT NULL COMMENT 'coincides with zipkin_spans.id',22.    `a_key`VARCHAR(255)NOT NULL COMMENT 'BinaryAnnotation.key or Annotation.value if type == -1',23.    `a_value`BLOB COMMENT 'BinaryAnnotation.value(), which must be smaller than 64KB',24.    `a_type`INT NOT NULL COMMENT 'BinaryAnnotation.type() or -1 if Annotation',25.    `a_timestamp`BIGINT COMMENT 'Used to implement TTL; Annotation.timestamp or zipkin_spans.timestamp',26.    `endpoint_ipv4`INT COMMENT 'Null when Binary/Annotation.endpoint is null',27.    `endpoint_ipv6`BINARY(16)COMMENT 'Null when Binary/Annotation.endpoint is null, or no IPv6 address',28.    `endpoint_port`SMALLINT COMMENT 'Null when Binary/Annotation.endpoint is null',29.    `endpoint_service_name`VARCHAR(255)COMMENT 'Null when Binary/Annotation.endpoint is null'30.  )ENGINE=InnoDBROW_FORMAT=COMPRESSED CHARACTER SET=utf8 COLLATE utf8_general_ci;31.   32.  ALTER TABLE zipkin_annotations ADD UNIQUE KEY(`trace_id_high`,`trace_id`,`span_id`,`a_key`,`a_timestamp`)COMMENT 'Ignore insert on duplicate';33.  ALTER TABLE zipkin_annotations ADD INDEX(`trace_id_high`,`trace_id`,`span_id`)COMMENT 'for joining with zipkin_spans';34.  ALTER TABLE zipkin_annotations ADD INDEX(`trace_id_high`,`trace_id`)COMMENT 'for getTraces/ByIds';35.  ALTER TABLE zipkin_annotations ADD INDEX(`endpoint_service_name`)COMMENT 'for getTraces and getServiceNames';36.  ALTER TABLE zipkin_annotations ADD INDEX(`a_type`)COMMENT 'for getTraces and autocomplete values';37.  ALTER TABLE zipkin_annotations ADD INDEX(`a_key`)COMMENT 'for getTraces and autocomplete values';38.  ALTER TABLE zipkin_annotations ADD INDEX(`trace_id`,`span_id`,`a_key`)COMMENT 'for dependencies job';39.   40.  CREATE TABLE IF NOT EXISTS zipkin_dependencies (41.    `day`DATE NOT NULL,42.    `parent`VARCHAR(255)NOT NULL,43.    `child`VARCHAR(255)NOT NULL,44.    `call_count`BIGINT,45.    `error_count`BIGINT46.  )ENGINE=InnoDBROW_FORMAT=COMPRESSED CHARACTER SET=utf8 COLLATE utf8_general_ci;47.   48.  ALTER TABLE zipkin_dependencies ADD UNIQUE KEY(`day`,`parent`,`child`);在数据库中初始化上面的脚本之后,需要做的就是zipkin-server如何连接数据库。zipkin如何连数据库同连接rabbitmq一样。zipkin连接数据库的属性所对应的环境变量如下:属性环境变量描述zipkin.torage.typeSTORAGE_TYPE默认的为mem,即为内存,其他可支持的为cassandra、cassandra3、elasticsearch、mysqlzipkin.torage.mysql.hostMYSQL_HOST数据库的host,默认localhostzipkin.torage.mysql.portMYSQLTCPPORT数据库的端口,默认3306zipkin.torage.mysql.usernameMYSQL_USER连接数据库的用户名,默认为空zipkin.torage.mysql.passwordMYSQL_PASS连接数据库的密码,默认为空zipkin.torage.mysql.dbMYSQL_DBzipkin使用的数据库名,默认是zipkinzipkin.torage.mysql.max-activeMYSQLMAXCONNECTIONS最大连接数,默认是101.  STORAGE_TYPE=mysql MYSQL_HOST=localhost MYSQL_TCP_PORT=3306MYSQL_USER=root MYSQL_PASS=123456MYSQL_DB=zipkin java -jar zipkin.jar等同于以下的命令1.  java -jar zipkin.jar --zipkin.torage.type=mysql --zipkin.torage.mysql.host=localhost --zipkin.torage.mysql.port=3306--zipkin.torage.mysql.username=root --zipkin.torage.mysql.password=123456使用上面的命令启动zipkin.jar工程,然后再浏览数**问http://localhost:8765/hi,再访问http://localhost:9411/zipkin/,可以看到链路数据。这时去数据库查看数据,也是可以看到存储在数据库的链路数据,如下:这时重启应用zipkin.jar,再次在浏览器**问http://localhost:9411/zipkin/,仍然可以得到之前的结果,证明链路数据存储在数据库中,而不是内存中。将链路数据存在在Elasticsearch中zipkin-server支持将链路数据存储在ElasticSearch中。读者需要自行安装ElasticSearch和Kibana,下载地址为https://www. elastic.co/products/elasticsearch。安装完成后启动,其中ElasticSearch的默认端口号为9200,Kibana的默认端口号为5601。同理,zipkin连接elasticsearch也是从环境变量中读取的,elasticsearch相关的环境变量和对应的属性如下:属性环境变量描述zipkin.torage.elasticsearch.hostsES_HOSTSES_HOSTS,默认为空zipkin.torage.elasticsearch.pipelineES_PIPELINEES_PIPELINE,默认为空zipkin.torage.elasticsearch.max-requestsESMAXREQUESTSESMAXREQUESTS,默认为64zipkin.torage.elasticsearch.timeoutES_TIMEOUTES_TIMEOUT,默认为10szipkin.torage.elasticsearch.indexES_INDEXES_INDEX,默认是zipkinzipkin.torage.elasticsearch.date-separatorESDATESEPARATORESDATESEPARATOR,默认为“-”zipkin.torage.elasticsearch.index-shardsESINDEXSHARDSESINDEXSHARDS,默认是5zipkin.torage.elasticsearch.index-replicasESINDEXREPLICASESINDEXREPLICAS,默认是1zipkin.torage.elasticsearch.usernameES_USERNAMEES的用户名,默认为空zipkin.torage.elasticsearch.passwordES_PASSWORDES的密码,默认是为空采用以下命令启动zipkin-server:1.  STORAGE_TYPE=elasticsearch ES_HOSTS=http://localhost:9200 ES_INDEX=zipkin java -jar zipkin.jar1.  java -jar zipkin.jar --STORAGE_TYPE=elasticsearch --ES_HOSTS=http://localhost:9200 --ES_INDEX=zipkin 1.  java -jar zipkin.jar --STORAGE_TYPE=elasticsearch --ES_HOSTS=http://localhost:9200 --ES_INDEX=zipkin 1.  java -jar zipkin.jar --zipkin.torage.type=elasticsearch --zipkin.torage.elasticsearch.hosts=http://localhost:9200 --zipkin.torage.elasticsearch.index=zipkin 启动完成后,然后在浏览数**问http://localhost:8765/hi,再访问http://localhost:9411/zipkin/,可以看到链路数据。这时链路数据存储在ElasticSearch。在zipkin上展示链路数据链路数据存储在ElasticSearch中,ElasticSearch可以和Kibana结合,将链路数据展示在Kibana上。安装完成Kibana后启动,Kibana默认会向本地端口为9200的ElasticSearch读取数据。Kibana默认的端口为5601,访问Kibana的主页http://localhost:5601,其界面如下图所示。在上图的界面中,单击“Management”按钮,然后单击“Add New”,添加一个index。我们将在上节ElasticSearch中写入链路数据的index配置为“zipkin”,那么在界面填写为“zipkin-*”,单击“Create”按钮,界面如下图所示:创建完成index后,单击“Discover”,就可以在界面上展示链路数据了,展示界面如下图所示。参考资料https://zipkin.io/https://github.com/spring-cloud/spring-cloud-sleuthhttps://cloud.spring.io/spring-cloud-static/spring-cloud-sleuth/2.1.0.RELEASE/single/spring-cloud-sleuth.htmlhttps://github.com/openzipkin/zipkin/blob/master/zipkin-server/src/main/resources/zipkin-server-shared.ymlhttps://github.com/openzipkin/zipkin/blob/master/zipkin-storage/mysql-v1/src/main/resources/mysql.sqlhttps://windmt.com/2018/04/24/spring-cloud-12-sleuth-zipkin/https://segmentfault.com/a/119000001569767http://www.cnblogs.com/JreeyQi/p/9336692.html原创作者:方志朋方志朋简介:SpringCloud中国社区联合创始人,博客访问量突破一千万,爱好开源,热爱分享,活跃于各大社区,保持着非常强的学习驱动力,终身学习践行者,终身学习受益者。目前就职于国内某家知名互联网保险公司,担任DEVOPS工程师,对微服务领域和持续集成领域研究较深,精通微服务框架SpringCloud