当前位置: 首页 > news >正文

做网站服务费税率wordpress关联adsense

做网站服务费税率,wordpress关联adsense,运营笔记wordpress,简述一下网站的设计流程SpringCloudAlibaba常用组件 微服务概念 1.1 单体、分布式、集群 单体 ⼀个系统业务量很⼩的时候所有的代码都放在⼀个项⽬中就好了#xff0c;然后这个项⽬部署在⼀台服务器上就 好了。整个项⽬所有的服务都由这台服务器提供。这就是单机结构。 单体应⽤开发简单,部署测试…SpringCloudAlibaba常用组件 微服务概念 1.1 单体、分布式、集群 单体 ⼀个系统业务量很⼩的时候所有的代码都放在⼀个项⽬中就好了然后这个项⽬部署在⼀台服务器上就 好了。整个项⽬所有的服务都由这台服务器提供。这就是单机结构。 单体应⽤开发简单,部署测试简单.但是存在⼀些问题,⽐如:单点问题,单机处理能⼒有限,当你的业务增⻓到 ⼀定程度的时候单机的硬件资源将⽆法满⾜你的业务需求。 分布式 由于整个系统运⾏需要使⽤到Tomcat和MySQL单台服务器处理的能⼒有限,2G的内存需要分配给 Tomcat和MySQL使⽤随着业务越来越复杂请求越来越多. 内存越来越不够⽤了所以这时候我们 就需要进⾏分布式的部署。 我们进⾏⼀个评论的请求这个请求是需要依赖分布在两台不同的服务器的组件[Tomat和MySQL],才能 完成的. 所以叫做分布式的系统. 集群 在上⾯的图解中其实是存在问题的⽐如Tomcat存在单点故障问题⼀旦Tomcat所在的服务器宕机不 可⽤了我们就⽆法提供服务了,所以针对单点故障问题我们会使⽤集群来解决.那什么是集群模式呢? 单机处理到达瓶颈的时候你就把单机复制⼏份这样就构成了⼀个“集群”。集群中每台服务器就叫做 这个集群的⼀个“节点”所有节点构成了⼀个集群。每个节点都提供相同的服务那么这样系统的处理 能⼒就相当于提升了好⼏倍有⼏个节点就相当于提升了这么多倍。 但问题是⽤户的请求究竟由哪个节点来处理呢最好能够让此时此刻负载较⼩的节点来处理这样使得 每个节点的压⼒都⽐较平均。要实现这个功能就需要在所有节点之前增加⼀个“调度者”的⻆⾊⽤户 的所有请求都先交给它然后它根据当前所有节点的负载情况决定将这个请求交给哪个节点处理。这 个“调度者”有个⽜逼了名字——负载均衡服务器。 我们在上⾯的图中仅展示了Tomcat的集群如果MySQL压⼒⽐较⼤的情况下我们也是可以对MySQL 进⾏集群的. 1.2 系统架构演变 随着互联⽹的发展⽹站应⽤的规模也不断的扩⼤进⽽导致系统架构也在不断的变化。 从互联⽹早起到现在系统架构⼤体经历了下⾯⼏个过程: 单体应⽤架构—垂直应⽤架构—分布 式架构—SOA架构—微服务架构。 接下来我们就来了解⼀下每种系统架构是什么样⼦的 以及各有什么优缺点。 1.2.1 单体应⽤架构 互联⽹早期⼀般的⽹站应⽤流量较⼩只需⼀个应⽤将所有功能代码都部署在⼀起就可以这 样可以减少开发、部署和维护的成本。 ⽐如说⼀个电商系统⾥⾯会包含很多⽤户管理商品管理订单管理物流管理等等很多模块 我们会把它们做成⼀个web项⽬然后部署到⼀台tomcat服务器上。 优点 项⽬架构简单⼩型项⽬的话 开发成本低 项⽬部署在⼀个节点上 维护⽅便 缺点 全部功能集成在⼀个⼯程中对于⼤型项⽬来讲不易开发和维护 项⽬模块之间紧密耦合单点容错率低 ⽆法针对不同模块进⾏针对性优化和⽔平扩展 1.2.2 垂直应⽤架构 随着访问量的逐渐增⼤单⼀应⽤只能依靠增加节点来应对但是这时候会发现并不是所有的模块 都会有⽐较⼤的访问量. 还是以上⾯的电商为例⼦ ⽤户访问量的增加可能影响的只是⽤户和订单模块 但是对消息模块 的影响就⽐较⼩. 那么此时我们希望只多增加⼏个订单模块 ⽽不增加消息模块. 此时单体应⽤就做不 到了 垂直应⽤就应运⽽⽣了. 所谓的垂直应⽤架构就是将原来的⼀个应⽤拆成互不相⼲的⼏个应⽤以提升效率。⽐如我们可 以将上⾯电商的单体应⽤拆分成: 电商系统(⽤户管理 商品管理 订单管理) 后台系统(⽤户管理 订单管理 客户管理) CMS系统(⼴告管理 营销管理) 这样拆分完毕之后⼀旦⽤户访问量变⼤只需要增加电商系统的节点就可以了⽽⽆需增加后台 和CMS的节点。 优点 系统拆分实现了流量分担解决了并发问题⽽且可以针对不同模块进⾏优化和⽔平扩展 ⼀个系统的问题不会影响到其他系统提⾼容错率 缺点 系统之间相互独⽴ ⽆法进⾏相互调⽤ 系统之间相互独⽴ 会有重复的开发任务 1.2.3 分布式架构 当垂直应⽤越来越多重复的业务代码就会越来越多。这时候我们就思考可不可以将重复的代码 抽取出来做成统⼀的业务层作为独⽴的服务然后由前端控制层调⽤不同的业务层服务呢 这就产⽣了新的分布式系统架构。它将把⼯程拆分成表现层和服务层两个部分服务层中包含业务 逻辑。表现层只需要处理和⻚⾯的交互业务逻辑都是调⽤服务层的服务来实现。 优点 抽取公共的功能为服务层提⾼代码复⽤性 缺点 系统间耦合度变⾼调⽤关系错综复杂难以维护 1.2.4 SOA架构 在分布式架构下当服务越来越多容量的评估⼩服务资源的浪费等问题逐渐显现此时需增加⼀个调度中⼼对集群进⾏实时管理。此时⽤于资源调度和治理中⼼(SOA Service OrientedArchitecture⾯向服务的架构)是关键。 优点: 使⽤注册中⼼解决了服务间调⽤关系的⾃动调节 缺点: 服务间会有依赖关系⼀旦某个环节出错会影响较⼤( 服务雪崩 ) 服务关系复杂运维、测试部署困难 1.2.5 微服务架构 微服务架构在某种程度上是⾯向服务的架构SOA继续发展的下⼀步它更加强调服务的彻底拆分。 优点 服务原⼦化拆分独⽴打包、部署和升级保证每个微服务清晰的任务划分利于扩展 微服务之间采⽤RESTful等轻量级Http协议相互调⽤ 缺点 分布式系统开发的技术成本⾼容错、分布式事务等 1.3 微服务架构介绍 微服务架构 简单的说就是将单体应⽤进⼀步拆分拆分成更⼩的服务每个服务都是⼀个可以独⽴运⾏的项⽬。 微服务架构的常⻅问题 ⼀旦采⽤微服务系统架构就势必会遇到这样⼏个问题 这么多⼩服务如何管理他们 这么多⼩服务他们之间如何通讯 这么多⼩服务客户端怎么访问他们 这么多⼩服务⼀旦出现问题了应该如何⾃处理 这么多⼩服务⼀旦出现问题了应该如何排错? 对于上⾯的问题是任何⼀个微服务设计者都不能绕过去的因此⼤部分的微服务产品都针对每⼀个问题提供了相应的组件来解决它们。 1.4 SpringCloud介绍 Spring Cloud是⼀系列框架的集合。它利⽤Spring Boot的开发便利性巧妙地简化了分布式系统基础设施的开发如服务发现注册、配置中⼼、消息总线、负载均衡、断路器、数据监控等都可以⽤SpringBoot的开发⻛格做到⼀键启动和部署。 Spring Cloud并没有重复制造轮⼦它只是将⽬前各家公司开发的⽐较成熟、经得起实际考验的服务框架组合起来通过Spring Boot⻛格进⾏再封装屏蔽掉了复杂的配置和实现原理最终给开发者留出了⼀套简单易懂、易部署和易维护的分布式系统开发⼯具包。 1.4.1 SpringBoot和SpringCloud有啥关系? SpringBoot专注于快速⽅便的开发单个个体微服务。 SpringCloud是关注全局的微服务协调整理治理框架它将SpringBoot开发的⼀个个单体微服务整合并管理起来为各个微服务之间提供配置管理、服务发现、断路器、路由、事件总线、分布式事务、等等集成服务。 总结: SpringBoot专注于快速、⽅便的开发单个微服务个体SpringCloud关注全局的服务治理组件的集合。 1.4.2 SpringCloud版本名称? 因为Spring Cloud不同其他独⽴项⽬它是拥有很多⼦项⽬的⼤项⽬。所以它是的版本是 版本名版本号 如Greenwich.SR6。 版本名是伦敦的地铁名 版本号SRService Releases是固定的 ,⼤概意思是稳定版本。后⾯会有⼀个递增的数字。所以 Greenwich.SR6就是Greenwich的第6个Release版本。 1.4.3 为什么选择SpringCloud Alibaba 我们这⾥为什么选择SpringCloud Alibaba呢主要因为SpringCloud Netflix的组件服务注册与发现的Eureka、服务限流降级的 Hystrix、⽹关 Zuul都已经停⽌更新了当然继续使⽤是没问题的只是出现问题官⽅不维护需要⾃⾏解决. 微服务环境搭建 商品微服务 查询商品列表 订单微服务 创建订单 2.1 技术选型 持久层: SpingData Jpa 数据库: MySQL5.7 其他: SpringCloud Alibaba 技术栈 2.2 模块设计 — shop-parent ⽗⼯程 — shop-product-api 商品微服务api 【存放商品实体】 — shop-product-server 商品微服务 【端⼝:808x】 — shop-order-api 订单微服务api 【存放订单实体】 — shop-order-server 订单微服务 【端⼝:809x】 2.3 微服务调用 在微服务架构中最常⻅的场景就是微服务之间的相互调⽤。我们以电商系统中常⻅的⽤户下单为例来演示微服务的调⽤客户向订单微服务发起⼀个下单的请求在进⾏保存订单之前需要调⽤商品微服务查询商品的信息。 我们⼀般把服务的主动调⽤⽅称为服务消费者把服务的被调⽤⽅称为服务提供者。 在这种场景下订单微服务就是⼀个服务消费者 商品微服务就是⼀个服务提供者。 2.4 版本说明 https://github.com/alibaba/spring-cloud-alibaba/wiki/版本说明 2.5 创建⽗⼯程 创建⼀个maven⼯程然后在pom.xml⽂件中添加下⾯内容 ?xml version1.0 encodingUTF-8? project xmlnshttp://maven.apache.org/POM/4.0.0xmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsdmodelVersion4.0.0/modelVersiongroupIdcom.xiaoge/groupIdartifactIdshop-parent/artifactIdversion1.0-SNAPSHOT/versionpackagingpom/packaging!--⽗⼯程--parentgroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-parent/artifactIdversion2.3.2.RELEASE/version/parent!--依赖版本的锁定--propertiesjava.version1.8/java.versionproject.build.sourceEncodingUTF-8/project.build.sourceEncodingproject.reporting.outputEncodingUTF-8/project.reporting.outputEncodingspring-cloud.versionHoxton.SR8/spring-cloud.versionspring-cloud-alibaba.version2.2.3.RELEASE/spring-cloud-alibaba.version/propertiesdependencyManagementdependenciesdependencygroupIdorg.springframework.cloud/groupIdartifactIdspring-cloud-dependencies/artifactIdversion${spring-cloud.version}/versiontypepom/typescopeimport/scope/dependencydependencygroupIdcom.alibaba.cloud/groupIdartifactIdspring-cloud-alibaba-dependencies/artifactIdversion${spring-cloud-alibaba.version}/versiontypepom/typescopeimport/scope/dependency/dependencies/dependencyManagement/project2.6 创建商品微服务 1.创建shop-product-api项⽬然后在pom.xml⽂件中添加下⾯内容 ?xml version1.0 encodingUTF-8? project xmlnshttp://maven.apache.org/POM/4.0.0xmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsdmodelVersion4.0.0/modelVersionparentgroupIdcom.xiaoge/groupIdartifactIdshop-parent/artifactIdversion1.0-SNAPSHOT/version/parentartifactIdshop-product-api/artifactId!--依赖--dependenciesdependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-data-jpa/artifactId/dependencydependencygroupIdorg.projectlombok/groupIdartifactIdlombok/artifactId/dependency/dependencies /project2 创建实体类 package com.xiaoge.entity;import lombok.Data;import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id;//商品 Entity(name t_shop_product) Data public class Product {IdGeneratedValue(strategy GenerationType.IDENTITY)private Long pid;//主键private String pname;//商品名称private Double pprice;//商品价格private Integer stock;//库存 }3.创建shop-product-server项⽬然后在pom.xml⽂件中添加下⾯内容 ?xml version1.0 encodingUTF-8? project xmlnshttp://maven.apache.org/POM/4.0.0xmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsdmodelVersion4.0.0/modelVersionparentgroupIdcom.xiaoge/groupIdartifactIdshop-parent/artifactIdversion1.0-SNAPSHOT/version/parentartifactIdshop-product-service/artifactIddependenciesdependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-web/artifactId/dependencydependencygroupIdmysql/groupIdartifactIdmysql-connector-java/artifactId/dependencydependencygroupIdcom.alibaba/groupIdartifactIdfastjson/artifactIdversion1.2.56/version/dependencydependencygroupIdcom.xiaoge/groupIdartifactIdshop-product-api/artifactIdversion1.0-SNAPSHOT/version/dependency/dependencies/project4.编写启动类ProductServer.java package com.xiaoge;import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;SpringBootApplication public class ProductServer {public static void main(String[] args) {SpringApplication.run(ProductServer.class, args);} }5.编写配置⽂件application.yml server:port: 8081 spring:application:name: product-servicedatasource:driver-class-name: com.mysql.jdbc.Driverurl: jdbc:mysql:///shop-product?serverTimezoneUTCuseUnicodetruecharacterEncodingutf-8useSSLtrueusername: rootpassword: rootjpa:properties:hibernate:hbm2ddl:auto: updatedialect: org.hibernate.dialect.MySQL5InnoDBDialect6.在数据库中创建shop-product的数据库 7.创建ProductDao package com.xiaoge.dao;import com.xiaoge.entity.Product; import org.springframework.data.jpa.repository.JpaRepository;public interface ProductDao extends JpaRepositoryProduct, Long { }8.创建ProductService接⼝和实现类 package com.xiaoge.service.impl;import com.xiaoge.dao.ProductDao; import com.xiaoge.entity.Product; import com.xiaoge.service.ProductService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service;Service public class ProductServiceImpl implements ProductService {Autowiredprivate ProductDao productDao;Overridepublic Product findByPid(Long pid) {return productDao.findById(pid).get();} }9.创建Controller package com.xiaoge.controller;import com.alibaba.fastjson.JSON; import com.xiaoge.entity.Product; import com.xiaoge.service.ProductService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController;RestController Slf4j public class ProductController {Autowiredprivate ProductService productService;//商品信息查询RequestMapping(/product/{pid})public Product findByPid(PathVariable(pid) Long pid) {log.info(接下来要进⾏{}号商品信息的查询, pid);Product product productService.findByPid(pid);log.info(商品信息查询成功,内容为{}, JSON.toJSONString(product));return product;} }10.启动⼯程等到数据库表创建完毕之后加⼊测试数据 INSERT INTO t_shop_product VALUE(NULL,⼩⽶,1000,5000); INSERT INTO t_shop_product VALUE(NULL,华为,2000,5000); INSERT INTO t_shop_product VALUE(NULL,苹果,3000,5000); INSERT INTO t_shop_product VALUE(NULL,OPPO,4000,5000);11.通过浏览器访问服务 2.7 创建订单微服务 1.创建shop-order-api项⽬然后在pom.xml⽂件中添加下⾯内容 ?xml version1.0 encodingUTF-8? project xmlnshttp://maven.apache.org/POM/4.0.0xmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsdmodelVersion4.0.0/modelVersionparentgroupIdcom.xiaoge/groupIdartifactIdshop-parent/artifactIdversion1.0-SNAPSHOT/version/parentartifactIdshop-order-api/artifactId!--依赖--dependenciesdependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-data-jpa/artifactId/dependencydependencygroupIdorg.projectlombok/groupIdartifactIdlombok/artifactId/dependency/dependencies /project2 创建实体类 package com.xiaoge.entity;import lombok.Data;import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id;//订单 Entity(name t_shop_order) Data public class Order {IdGeneratedValue(strategy GenerationType.IDENTITY)private Long oid;//订单id//⽤户private Long uid;//⽤户idprivate String username;//⽤户名//商品private Long pid;//商品idprivate String pname;//商品名称private Double pprice;//商品单价//数量private Integer number;//购买数量 }3.创建shop-order-server项⽬然后在pom.xml⽂件中添加下⾯内容 ?xml version1.0 encodingUTF-8? project xmlnshttp://maven.apache.org/POM/4.0.0xmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsdmodelVersion4.0.0/modelVersionparentgroupIdcom.xiaoge/groupIdartifactIdshop-parent/artifactIdversion1.0-SNAPSHOT/version/parentartifactIdshop-order-service/artifactIddependenciesdependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-web/artifactId/dependencydependencygroupIdmysql/groupIdartifactIdmysql-connector-java/artifactId/dependencydependencygroupIdcom.alibaba/groupIdartifactIdfastjson/artifactIdversion1.2.56/version/dependencydependencygroupIdcom.xiaoge/groupIdartifactIdshop-order-api/artifactIdversion1.0-SNAPSHOT/version/dependency/dependencies/project4.编写启动类OrderServer.java package com.xiaoge;import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;SpringBootApplication public class OrderServer {public static void main(String[] args) {SpringApplication.run(OrderServer.class, args);} }5.编写配置⽂件application.yml server:port: 8091 # tomcat: # threads: # max: 10 spring:application:name: order-servicedatasource:driver-class-name: com.mysql.jdbc.Driverurl: jdbc:mysql:///shop-order?serverTimezoneUTCuseUnicodetruecharacterEncodingutf-8useSSLtrueusername: rootpassword: rootjpa:properties:hibernate:hbm2ddl:auto: updatedialect: org.hibernate.dialect.MySQL5InnoDBDialect6.在数据库中创建shop-order的数据库 7.创建OrderDao package com.xiaoge.dao;import com.xiaoge.entity.Order; import org.springframework.data.jpa.repository.JpaRepository;public interface OrderDao extends JpaRepositoryOrder, Long { }8.创建OrderService接⼝和实现类 package com.xiaoge.service.impl;import com.alibaba.fastjson.JSON; import com.xiaoge.dao.OrderDao; import com.xiaoge.entity.Order; import com.xiaoge.entity.Product; import com.xiaoge.service.OrderService; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service;import java.util.List;Service Slf4j public class OrderServiceImpl implements OrderService {Autowiredprivate OrderDao orderDao;Overridepublic Order createOrder(Long productId,Long userId) {log.info(接收到{}号商品的下单请求,接下来调⽤商品微服务查询此商品信息,productId);//远程调⽤商品微服务,查询商品信息Product product null;log.info(查询到{}号商品的信息,内容是:{}, productId,JSON.toJSONString(product));//创建订单并保存Order order new Order();order.setUid(userId);order.setUsername(叩丁狼教育);order.setPid(productId);order.setPname(product.getPname());order.setPprice(product.getPprice());order.setNumber(1);orderDao.save(order);log.info(创建订单成功,订单信息为{}, JSON.toJSONString(order));return order;} }9.创建Controller package com.xiaoge.controller;import com.xiaoge.entity.Order; import com.xiaoge.service.OrderService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController;RestController Slf4j public class OrderController {Autowiredprivate OrderService orderService;RequestMapping(/save)public Order order(Long pid, Long uid) {return orderService.createOrder(pid, uid);} }2.8 服务间如何进⾏远程调⽤ 商品微服务已经提供了数据接⼝了订单微服务应该如何去调⽤呢? 其实就是如何通过Java代码去调⽤⼀个http的接⼝地址我们可以使⽤RestTemplate来进⾏调⽤. 1.在启动类上添加RestTemplate的bean配置 package com.xiaoge;import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.Bean; import org.springframework.web.client.RestTemplate;SpringBootApplication public class OrderServer {public static void main(String[] args) {SpringApplication.run(OrderServer.class, args);}Beanpublic RestTemplate restTemplate() {return new RestTemplate();} }2.在OrderServiceImpl中注⼊RestTemplate并实现远程调⽤ package com.xiaoge.service.impl;import com.alibaba.fastjson.JSON; import com.xiaoge.dao.OrderDao; import com.xiaoge.entity.Order; import com.xiaoge.entity.Product; import com.xiaoge.feign.ProductFeignClientApi; import com.xiaoge.service.OrderService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cloud.client.ServiceInstance; import org.springframework.cloud.client.discovery.DiscoveryClient; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.client.RestTemplate;import java.util.List;Service Slf4j public class OrderServiceImpl implements OrderService {Autowiredprivate OrderDao orderDao;Autowiredprivate RestTemplate restTemplate;Overridepublic Order createOrder(Long productId, Long userId) {log.info(接收到{}号商品的下单请求,接下来调⽤商品微服务查询此商品信息,productId);Product product restTemplate.getForObject(http://localhost:8081/product/ productId, Product.class);log.info(查询到{}号商品的信息,内容是:{}, productId, JSON.toJSONString(product));//创建订单并保存Order order new Order();order.setUid(userId);order.setUsername(music啸);order.setPid(productId);order.setPname(product.getPname());order.setPprice(product.getPprice());order.setNumber(1);orderDao.save(order);log.info(创建订单成功,订单信息为{}, JSON.toJSONString(order));return order;} }虽然我们已经可以实现微服务之间的调⽤。但是我们把服务提供者的⽹络地址ip端⼝等硬编码到了代码中这种做法存在许多问题 ⼀旦服务提供者地址变化就需要⼿⼯修改代码 ⼀旦是多个服务提供者⽆法实现负载均衡功能 ⼀旦服务变得越来越多⼈⼯维护调⽤关系困难 那么应该怎么解决呢 这时候就需要通过注册中⼼动态的实现服务治理。 服务治理 Nacos Discovery 3.1 什么是服务治理 服务治理是微服务架构中最核⼼最基本的模块。⽤于实现各个微服务的⾃动化注册与发现。 服务注册 在服务治理框架中都会构建⼀个注册中⼼每个服务单元向注册中⼼登记⾃⼰提供服务的详细信息。并在注册中⼼形成⼀张服务的清单服务注册中⼼需要以⼼跳的⽅式去监测清单中的服务是否可⽤如果不可⽤需要在服务清单中剔除不可⽤的服务。 服务发现 服务调⽤⽅向服务注册中⼼咨询服务并获取所有服务的实例清单实现对具体服务实例的访问。 通过上⾯的调⽤图会发现除了微服务还有⼀个组件是服务注册中⼼它是微服务架构⾮常重要的⼀个组件在微服务架构⾥主要起到了协调者的⼀个作⽤。注册中⼼⼀般包含如下⼏个功能 服务发现 服务注册保存服务提供者和服务调⽤者的信息 服务订阅服务调⽤者订阅服务提供者的信息注册中⼼向订阅者推送提供者的信息 服务健康检测 检测服务提供者的健康情况如果发现异常执⾏服务剔除 3.2 常⻅注册中⼼ Zookeeper Zookeeper是⼀个分布式服务框架是Apache Hadoop 的⼀个⼦项⽬它主要是⽤来解决分布式应⽤中经常遇到的⼀些数据管理问题如统⼀命名服务、状态同步服务、集群管理、分布式应⽤配置项的管理等。 Eureka Eureka是Springcloud Netflflix中的重要组件主要作⽤就是做服务注册和发现。但是现在已经闭源 Consul Consul是基于GO语⾔开发的开源⼯具主要⾯向分布式服务化的系统提供服务注册、服务发现和配置管理的功能。Consul的功能都很实⽤其中包括服务注册/发现、健康检查、Key/Value存储、多数据中⼼和分布式⼀致性保证等特性。Consul本身只是⼀个⼆进制的可执⾏⽂件所以安装和部署都⾮常简单只需要从官⽹下载后在执⾏对应的启动脚本即可。 Nacos Nacos是⼀个更易于构建云原⽣应⽤的动态服务发现、配置管理和服务管理平台。它是 SpringCloud Alibaba 组件之⼀负责服务注册发现和服务配置。 3.3 Nacos 简介 Nacos 致⼒于帮助您发现、配置和管理微服务。Nacos 提供了⼀组简单易⽤的特性集帮助您快速实现动态服务发现、服务配置、服务元数据及流量管理。 从上⾯的介绍就可以看出Nacos的作⽤就是⼀个注册中⼼⽤来管理注册上来的各个微服务。 核⼼功能点: 服务注册: Nacos Client会通过发送REST请求想Nacos Server注册⾃⼰的服务提供⾃身的元数据⽐如IP地址端⼝等信息。Nacos Server接收到注册请求后就会把这些元数据存储到⼀个双层的内存Map中。 服务⼼跳: 在服务注册后Nacos Client会维护⼀个定时⼼跳来维持统治Nacos Server,说明服务⼀致处于可⽤状态防⽌被剔除默认5s发送⼀次⼼跳 服务同步: Nacos Server集群之间会相互同步服务实例⽤来保证服务信息的⼀致性。 服务发现 服务消费者(Nacos Client)在调⽤服务提供的服务时会发送⼀个REST请求给NacosServer,获取上⾯注册的服务清单并且缓存在Nacos Client本地,同时会在Nacos Client本地开启⼀个定时任务拉取服务最新的注册表信息更新到本地缓存。 服务健康检查: Nacos Server 会开启⼀个定时任务来检查注册服务实例的健康情况对于超过15s没有收到客户端⼼跳的实例会将他的healthy属性设置为false(客户端服务发现时不会发现)如果某个实例超过30s没有收到⼼跳直接剔除该实例(被剔除的实例如果恢复发送⼼跳则会重新注册) 3.4 Nacos实战入门 接下来我们就在现有的环境中加⼊nacos并将我们的两个微服务注册上去。 3.4.1 搭建Nacos环境 安装Nacos 下载地址: https://github.com/alibaba/nacos/releases 下载zip格式的安装包然后进⾏解压缩操作,上课使⽤的Nacos Server版本是1.3.2启动Nacos #切换⽬录 cd nacos/bin #命令启动 startup.cmd -m standalone访问Nacos 打开浏览器输⼊http://localhost:8848/nacos即可访问服务 默认密码是nacos/nacos 3.4.2 将商品服务注册到Nacos 接下来开始修改 shop-product-server 模块的代码 将其注册到nacos服务上 在pom.xml中添加Nacos的依赖 !--nacos客户端-- dependencygroupIdcom.alibaba.cloud/groupIdartifactIdspring-cloud-starter-alibaba-nacos-discovery/artifactId /dependency在主类上添加**EnableDiscoveryClient**注解 SpringBootApplication EnableDiscoveryClient public class ProductServer {public static void main(String[] args) {SpringApplication.run(ProductServer.class,args);} }在application.yml中添加Nacos服务的地址 spring:cloud:nacos:discovery:server-addr: localhost:8848启动服务 观察Nacos的控制⾯板中是否有注册上来的商品微服务 3.4.3 将订单服务注册到Nacos 接下来开始修改 shop-order-server 模块的代码 将其注册到nacos服务上 在pom.xml中添加Nacos的依赖 !--nacos客户端-- dependencygroupIdcom.alibaba.cloud/groupIdartifactIdspring-cloud-starter-alibaba-nacos-discovery/artifactId /dependency在主类上添加**EnableDiscoveryClient**注解 package com.xiaoge;import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient;EnableDiscoveryClient SpringBootApplication public class OrderServer {public static void main(String[] args) {SpringApplication.run(OrderServer.class, args);} }在application.yml中添加Nacos服务的地址 spring:cloud:nacos:discovery:server-addr: localhost:8848启动服务 观察Nacos的控制⾯板中是否有注册上来的订单微服务 修改OrderServiceImpl 实现微服务调⽤ package com.xiaoge.service.impl;import com.alibaba.fastjson.JSON; import com.xiaoge.dao.OrderDao; import com.xiaoge.entity.Order; import com.xiaoge.entity.Product; import com.xiaoge.feign.ProductFeignClientApi; import com.xiaoge.service.OrderService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cloud.client.ServiceInstance; import org.springframework.cloud.client.discovery.DiscoveryClient; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.client.RestTemplate;import java.util.List;Service Slf4j public class OrderServiceImpl implements OrderService {Autowiredprivate OrderDao orderDao;Autowiredprivate RestTemplate restTemplate;Autowiredprivate DiscoveryClient discoveryClient;TransactionalOverridepublic Order createOrder(Long productId, Long userId) {log.info(接收到{}号商品的下单请求,接下来调⽤商品微服务查询此商品信息, productId);//从nacos中获取服务地址ServiceInstance instance discoveryClient.getInstances(product-service).get(0);String url instance.getHost():instance.getPort();//远程调⽤商品微服务,查询商品信息Product product restTemplate.getForObject(http://url/product/productId,Product.class);log.info(查询到{}号商品的信息,内容是:{}, productId, JSON.toJSONString(product));//创建订单并保存Order order new Order();order.setUid(userId);order.setUsername(music啸);order.setPid(productId);order.setPname(product.getPname());order.setPprice(product.getPprice());order.setNumber(1);orderDao.save(order);log.info(创建订单成功,订单信息为{}, JSON.toJSONString(order));return order;} }远程调⽤负载均衡 Ribbon 4.1 什么是负载均衡 通俗的讲 负载均衡就是将负载⼯作任务访问请求进⾏分摊到多个操作单元服务器,组件上进⾏执⾏。 根据负载均衡发⽣位置的不同,⼀般分为服务端负载均衡和客户端负载均衡。 服务端负载均衡指的是发⽣在服务提供者⼀⽅,⽐如常⻅的Nginx负载均衡 ⽽客户端负载均衡指的是发⽣在服务请求的⼀⽅也就是在发送请求之前已经选好了由哪个实例处理请求 我们在微服务调⽤关系中⼀般会选择客户端负载均衡也就是在服务调⽤的⼀⽅来决定服务由哪个提供者执⾏。 4.2 ⾃定义负载均衡 通过idea再启动⼀个 shop-product 微服务设置其端⼝为8082 通过nacos查看微服务的启动情况 修改 OrderServiceImpl 的代码实现负载均衡 package com.xiaoge.service.impl;import com.alibaba.fastjson.JSON; import com.xiaoge.dao.OrderDao; import com.xiaoge.entity.Order; import com.xiaoge.entity.Product; import com.xiaoge.feign.ProductFeignClientApi; import com.xiaoge.service.OrderService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cloud.client.ServiceInstance; import org.springframework.cloud.client.discovery.DiscoveryClient; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.client.RestTemplate;import java.util.List;Service Slf4j public class OrderServiceImpl implements OrderService {Autowiredprivate OrderDao orderDao;Autowiredprivate RestTemplate restTemplate;Autowiredprivate DiscoveryClient discoveryClient;TransactionalOverridepublic Order createOrder(Long productId, Long userId) {log.info(接收到{}号商品的下单请求,接下来调⽤商品微服务查询此商品信息, productId);//从nacos中获取服务地址//⾃定义规则实现随机挑选服务ListServiceInstance instances discoveryClient.getInstances(product-service);int index new Random().nextInt(instances.size());ServiceInstance instance instances.get(index);String url instance.getHost():instance.getPort();//远程调⽤商品微服务,查询商品信息Product product restTemplate.getForObject(http://url/product/productId,Product.class);log.info(查询到{}号商品的信息,内容是:{}, productId, JSON.toJSONString(product));//创建订单并保存Order order new Order();order.setUid(userId);order.setUsername(music啸);order.setPid(productId);order.setPname(product.getPname());order.setPprice(product.getPprice());order.setNumber(1);orderDao.save(order);log.info(创建订单成功,订单信息为{}, JSON.toJSONString(order));return order;} }启动两个服务提供者和⼀个服务消费者多访问⼏次消费者测试效果 4.3 基于Ribbon实现负载均衡 Ribbon是Spring Cloud的⼀个组件 它可以让我们使⽤⼀个注解就能轻松的搞定负载均衡 在RestTemplate 的⽣成⽅法上添加LoadBalanced注解 Bean LoadBalanced // todo 这个注解使用了Ribbon中的负载均衡, 它会去读取本地缓存中的服务信息去调用(注意:前提是该服务要能拉取到nacos服务列表) public RestTemplate restTemplate() {return new RestTemplate(); }修改OrderServiceImpl服务调⽤的⽅法 package com.xiaoge.service.impl;import com.alibaba.fastjson.JSON; import com.xiaoge.dao.OrderDao; import com.xiaoge.entity.Order; import com.xiaoge.entity.Product; import com.xiaoge.feign.ProductFeignClientApi; import com.xiaoge.service.OrderService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cloud.client.ServiceInstance; import org.springframework.cloud.client.discovery.DiscoveryClient; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.client.RestTemplate;import java.util.List;Service Slf4j public class OrderServiceImpl implements OrderService {Autowiredprivate OrderDao orderDao;Autowiredprivate RestTemplate restTemplate;Autowiredprivate DiscoveryClient discoveryClient;TransactionalOverridepublic Order createOrder(Long productId, Long userId) {log.info(接收到{}号商品的下单请求,接下来调⽤商品微服务查询此商品信息, productId);//远程调⽤商品微服务,查询商品信息Product product restTemplate.getForObject(http://product-service/product/productId,Product.class);log.info(查询到{}号商品的信息,内容是:{}, productId, JSON.toJSONString(product));//创建订单并保存Order order new Order();order.setUid(userId);order.setUsername(music啸);order.setPid(productId);order.setPname(product.getPname());order.setPprice(product.getPprice());order.setNumber(1);orderDao.save(order);log.info(创建订单成功,订单信息为{}, JSON.toJSONString(order));return order;} }为了更直观看到请求是进⾏负载均衡了我们修改⼀下ProductController代码 package com.xiaoge.controller;import com.alibaba.fastjson.JSON; import com.xiaoge.entity.Product; import com.xiaoge.service.ProductService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController;RestController Slf4j public class ProductController {Autowiredprivate ProductService productService;Value(${server.port})private String port;//商品信息查询RequestMapping(/product/{pid})public Product findByPid(PathVariable(pid) Long pid) {log.info(接下来要进⾏{}号商品信息的查询, pid);Product product productService.findByPid(pid);product.setPname(product.getPname() data, from port);log.info(商品信息查询成功,内容为{}, JSON.toJSONString(product));return product;} }调⽤订单保存的⽅法查看⽇志. 默认情况下,采取的是ZoneAvoidanceRule的策略,复合判断server所在区域的性能和server的可⽤性选择server Ribbon⽀持的负载均衡策略 Ribbon内置了多种负载均衡策略,内部负载均衡的顶级接⼝为 com.netflix.loadbalancer.IRule , 具体的负载策略如下图所示: 策略名策略描述实现说明BestAvailableRule选择⼀个最⼩的并发请求的server逐个考察Server如果Server被tripped了则忽略在选择其中ActiveRequestsCount最⼩的serverAvailabilityFilteringRule先过滤掉故障实例再选择并发较⼩的实例使⽤⼀个AvailabilityPredicate来包含过滤server的逻辑其实就就是检查status⾥记录的各个server的运⾏状态WeightedResponseTimeRule根据相应时间分配⼀个weight相应时间越⻓weight越⼩被选中的可能性越低。⼀个后台线程定期的从status⾥⾯读取评价响应时间为每个server计算⼀个weight。Weight的计算也⽐较简单responsetime 减去每个server⾃⼰平均的responsetime是server的权RetryRule对选定的负载均衡策略机上重试机制。在⼀个配置时间段内当选择server不成功则⼀直尝试使⽤subRule的⽅式选择⼀个可⽤的serverRoundRobinRule轮询⽅式轮询选择server轮询index选择index对应位置的serverRandomRule随机选择⼀个server在index上随机选择index对应位置的serverZoneAvoidanceRule(默认)复合判断server所在区域的性能和server的可⽤性选择server使⽤ZoneAvoidancePredicate和AvailabilityPredicate来判断是否选择某个server前⼀个判断判定⼀个zone的运⾏性能是否可⽤剔除不可⽤的zone的所有serverAvailabilityPredicate⽤于过滤掉连接数过多的Server。我们可以通过修改配置来调整Ribbon的负载均衡策略在order-server项⽬的application.yml中增加如下配置: product-service: # 调⽤的提供者的名称ribbon:NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule # 使用随机算法远程调用Feign 5.1 什么是Feign Feign是Spring Cloud提供的⼀个声明式的伪Http客户端 它使得调⽤远程服务就像调⽤本地服务⼀样简单 只需要创建⼀个接⼝并添加⼀个注解即可。 Nacos很好的兼容了Feign Feign默认集成了 Ribbon 所以在Nacos下使⽤Fegin默认就实现了负载均衡的效果。 Feign处理流程 5.2 订单微服务集成Feign 在shop-order-server项⽬的pom⽂件加⼊Fegin的依赖 !--fegin组件-- dependencygroupIdorg.springframework.cloud/groupIdartifactIdspring-cloud-starter-openfeign/artifactId /dependency在启动类OrderServer.java上添加Fegin的扫描注解,注意扫描路径(默认扫描当前包及其⼦包) SpringBootApplication EnableDiscoveryClient EnableFeignClients public class OrderServer {public static void main(String[] args) {SpringApplication.run(OrderServer.class,args);} }在shop-order-server项⽬中新增接⼝ProductFeignApi package com.xiaoge.feign;import com.xiaoge.entity.Product; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping;//name的名称⼀定要和订单服务的服务名保持⼀致 FeignClient(value product-service) public interface ProductFeignClientApi {RequestMapping(/product/{pid})Product findByPid(PathVariable(pid) Long pid);} 修改OrderServiceImpl.java的远程调⽤⽅法 package com.xiaoge.service.impl;import com.alibaba.fastjson.JSON; import com.xiaoge.dao.OrderDao; import com.xiaoge.entity.Order; import com.xiaoge.entity.Product; import com.xiaoge.feign.ProductFeignClientApi; import com.xiaoge.service.OrderService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional;import java.util.List;Service Slf4j public class OrderServiceImpl implements OrderService {Autowiredprivate OrderDao orderDao;Autowiredprivate ProductFeignClientApi productFeignClientApi;TransactionalOverridepublic Order createOrder(Long productId, Long userId) {log.info(接收到{}号商品的下单请求,接下来调⽤商品微服务查询此商品信息, productId);// todo feign 远程调⽤商品微服务,查询商品信息Product product productFeignClientApi.findByPid(productId);log.info(查询到{}号商品的信息,内容是:{}, productId, JSON.toJSONString(product));//创建订单并保存Order order new Order();order.setUid(userId);order.setUsername(music啸);order.setPid(productId);order.setPname(product.getPname());order.setPprice(product.getPprice());order.setNumber(1);orderDao.save(order);log.info(创建订单成功,订单信息为{}, JSON.toJSONString(order));return order;} }重启订单服务并验证. 服务熔断降级 Sentinel 6.1 高并发带来的问题 在微服务架构中我们将业务拆分成⼀个个的服务服务与服务之间可以相互调⽤但是由于⽹络原因或者⾃身的原因服务并不能保证服务的100%可⽤如果单个服务出现问题调⽤这个服务就会出现⽹络延迟此时若有⼤量的⽹络涌⼊会形成任务堆积最终导致服务瘫痪。 接下来模拟⼀个高并发的场景 在订单服务中新建SentinelController.java RestController public class SentinelController {RequestMapping(/sentinel1)public String sentinel1() {//模拟⼀次⽹络延时try {TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}return sentinel1;}RequestMapping(/sentinel2)public String sentinel2() {return 测试⾼并发下的问题;} }修改配置⽂件中tomcat的并发数 server:port: 8091tomcat:threads:max: 10 #tomcat的最⼤并发值修改为10接下来使⽤压测⼯具,对请求进⾏压⼒测试 下载地址https://jmeter.apache.org/ 第⼀步修改配置并启动软件 进⼊bin⽬录,修改jmeter.properties⽂件中的语⾔⽀持为languagezh_CN然后点击jmeter.bat启动软件。 第⼆步添加线程组 第三步配置线程并发数 第四步添加Http请求 第五步配置取样并启动测试 第六步访问 http://localhost:8091/sentinel2 观察结果 结论:此时会发现, 由于sentinel1⽅法囤积了⼤量请求, 导致sentinel2⽅法的访问出现了问题这就是服务雪崩的雏形。 6.2 服务器雪崩效应 在分布式系统中,由于⽹络原因或⾃身的原因,服务⼀般⽆法保证 100% 可⽤。如果⼀个服务出现了问题调⽤这个服务就会出现线程阻塞的情况此时若有⼤量的请求涌⼊就会出现多条线程阻塞等待进⽽导致服务瘫痪。 由于服务与服务之间的依赖性故障会传播会对整个微服务系统造成灾难性的严重后果这就是服务故障的 “雪崩效应” 。 情景1: 微服务之间相互调⽤,关系复杂,正常情况如下图所示: 情景2某个时刻服务A挂了服务B和服务C依然在调⽤服务A 情景3:由于服务A挂了,导致服务C和服务B⽆法得到服务A的响应,这时候服务C和服务B由于⼤量线程积压,最终导致服务C和服务B挂掉. 情景4: 相同道理,由于服务之间有关联所以会导致整个调⽤链上的所有服务都挂掉. 服务器的雪崩效应其实就是由于某个微⼩的服务挂了,导致整⼀⼤⽚的服务都不可⽤.类似⽣活中的雪崩效应,由于落下的最后⼀⽚雪花引发了雪崩的情况. 雪崩发⽣的原因多种多样有不合理的容量设计或者是⾼并发下某⼀个⽅法响应变慢亦或是某台机器的资源耗尽。我们⽆法完全杜绝雪崩源头的发⽣只有做好⾜够的容错保证在⼀个服务发⽣问题不会影响到其它服务的正常运⾏。 6.3 常见容方案 要防⽌雪崩的扩散我们就要做好服务的容错容错说⽩了就是保护⾃⼰不被猪队友拖垮的⼀些措施, 下⾯介绍常⻅的服务容错思路和组件。 常⻅的容错思路 常⻅的容错思路有隔离、超时、限流、熔断、降级这⼏种下⾯分别介绍⼀下。 隔离机制: ⽐如服务A内总共有100个线程, 现在服务A可能会调⽤服务B,服务C,服务D.我们在服务A进⾏远程调⽤的时候,给不同的服务分配固定的线程,不会把所有线程都分配给某个微服务. ⽐如调⽤服务B分配30个线程,调⽤服务C分配30个线程调⽤服务D分配40个线程. 这样进⾏资源的隔离保证即使下游某个服务挂了也不⾄于把服务A的线程消耗完。⽐如服务B挂了这时候最多只会占⽤服务A的30个线程,服务A还有70个线程可以调⽤服务C和服务D. 超时机制: 在上游服务调⽤下游服务的时候设置⼀个最⼤响应时间如果超过这个时间下游未作出反应就断开请求释放掉线程。 限流机制: 限流就是限制系统的输⼊和输出流量已达到保护系统的⽬的。为了保证系统的稳固运⾏,⼀旦达到的需要限制的阈值,就需要限制流量并采取少量措施以完成限制流量的⽬的。 熔断机制: 在互联⽹系统中当下游服务因访问压⼒过⼤⽽响应变慢或失败上游服务为了保护系统整体的可⽤性可以暂时切断对下游服务的调⽤。这种牺牲局部保全整体的措施就叫做熔断。 服务熔断⼀般有三种状态 熔断关闭状态Closed 服务没有故障时熔断器所处的状态对调⽤⽅的调⽤不做任何限制 熔断开启状态Open 后续对该服务接⼝的调⽤不再经过⽹络直接执⾏本地的fallback⽅法 半熔断状态Half-Open 尝试恢复服务调⽤允许有限的流量调⽤该服务并监控调⽤成功率。如果成功率达到预期则说明服务已恢复进⼊熔断关闭状态如果成功率仍旧很低则重新进⼊熔断关闭状态。 降级机制: 降级其实就是为服务提供⼀个兜底⽅案⼀旦服务⽆法正常调⽤就使⽤兜底⽅案。 6.4 常见的容错组件 Hystrix Hystrix是由Netflflix开源的⼀个延迟和容错库⽤于隔离访问远程系统、服务或者第三⽅库防⽌级联失败从⽽提升系统的可⽤性与容错性。 Resilience4J Resilicence4J⼀款⾮常轻量、简单并且⽂档⾮常清晰、丰富的熔断⼯具这也是Hystrix官⽅推荐的替代产品。不仅如此Resilicence4j还原⽣⽀持Spring Boot 1.x/2.x⽽且监控也⽀持和prometheus等多款主流产品进⾏整合。 Sentinel Sentinel 是阿⾥巴巴开源的⼀款断路器实现本身在阿⾥内部已经被⼤规模采⽤⾮常稳定。 6.5 Sentinel ⼊⻔ 6.5.1 什么是 Sentinel Sentinel (分布式系统的流量防卫兵) 是阿⾥开源的⼀套⽤于服务容错的综合性解决⽅案。它以流量为切⼊点, 从流量控制、熔断降级、系统负载保护等多个维度来保护服务的稳定性 Sentinel 具有以下特征: 丰富的应⽤场景Sentinel 承接了阿⾥巴巴近 10 年的双⼗⼀⼤促流量的核⼼场景, 例如秒杀即突发流量控制在系统容量可以承受的范围、消息削峰填⾕、集群流量控制、实时熔断下游不可⽤应⽤等。 完备的实时监控Sentinel 提供了实时的监控功能。通过控制台可以看到接⼊应⽤的单台机器秒级数据, 甚⾄ 500 台以下规模的集群的汇总运⾏情况。 ⼴泛的开源⽣态Sentinel 提供开箱即⽤的与其它开源框架/库的整合模块, 例如与 SpringCloud、Dubbo、gRPC 的整合。只需要引⼊相应的依赖并进⾏简单的配置即可快速地接⼊Sentinel。 Sentinel 分为两个部分: 核⼼库Java 客户端不依赖任何框架/库,能够运⾏于所有 Java 运⾏时环境同时对 Dubbo / Spring Cloud 等框架也有较好的⽀持。 控制台Dashboard基于 Spring Boot 开发打包后可以直接运⾏不需要额外的 Tomcat 等应⽤容器。 6.5.2 订单微服务集成 Sentinel 为微服务集成Sentinel⾮常简单, 只需要加⼊Sentinel的依赖即可在shop-order-server项⽬的pom⽂件中添加如下依赖 !--sentinel组件-- dependencygroupIdcom.alibaba.cloud/groupIdartifactIdspring-cloud-starter-alibaba-sentinel/artifactId /dependency6.5.3 安装 Sentinel 控制台 Sentinel 提供⼀个轻量级的控制台, 它提供机器发现、单机资源实时监控以及规则管理等功能。 下载jar包 https://github.com/alibaba/Sentinel/releases 启动控制台 # 直接使⽤jar命令启动项⽬(控制台本身是⼀个SpringBoot项⽬) java -Dserver.port8080 -Dcsp.sentinel.dashboard.serverlocalhost:8080 -Dproject.namesentinel-dashboard -jar sentinel-dashboard-1.8.0.jar修改shop-order-server项⽬中的配置⽂件application.yml,新增如下配置: spring:cloud: sentinel:transport:port: 9999 #跟控制台交流的端⼝,随意指定⼀个未使⽤的端⼝即可dashboard: localhost:8080 # 指定控制台服务的地址通过浏览器访问localhost:8080 进⼊控制台 ( 默认⽤户名密码是 sentinel/sentinel )注意: 默认是没显示order-service的需要访问⼏次接⼝然后再刷新sentinel管控台才可以看到. 6.5.4 实现⼀个接口的限流 第⼀步: 簇点链路—流控 第⼆步: 在单机阈值填写⼀个数值表示每秒上限的请求数 第三步:通过控制台快速频繁访问, 观察效果 6.5.5 Sentinel 容错的维度 流量控制流量控制在⽹络传输中是⼀个常⽤的概念它⽤于调整⽹络包的数据。任意时间到来的请求往往是随机不可控的⽽系统的处理能⼒是有限的。我们需要根据系统的处理能⼒对流量进⾏控制。 熔断降级当检测到调⽤链路中某个资源出现不稳定的表现例如请求响应时间⻓或异常⽐例升⾼的时候则对这个资源的调⽤进⾏限制让请求快速失败避免影响到其它的资源⽽导致级联故障。 系统负载保护Sentinel 同时提供系统维度的⾃适应保护能⼒。当系统负载较⾼的时候如果还持续让请求进⼊可能会导致系统崩溃⽆法响应。在集群环境下会把本应这台机器承载的流量转发到其它的机器上去。如果这个时候其它的机器也处在⼀个边缘状态的时候Sentinel 提供了对应的保护机制让系统的⼊⼝流量和系统的负载达到⼀个平衡保证系统在能⼒范围之内处理最多的请求。 6.5.6 Sentinel 规则种类 Sentinel主要提供了这五种的流量控制接下来我们每种演示⼀下 6.6 Sentinel 规则 - 流控 6.6.1 流控规则 流量控制其原理是监控应⽤流量的QPS(每秒查询率) 或并发线程数等指标当达到指定的阈值时对流量进⾏控制以避免被瞬时的流量⾼峰冲垮从⽽保障应⽤的⾼可⽤性。 资源名唯⼀名称默认是请求路径可⾃定义 针对来源指定对哪个微服务进⾏限流默认指default意思是不区分来源全部限制 阈值类型 / 单机阈值 QPS每秒请求数量: 当调⽤该接⼝的QPS达到阈值的时候进⾏限流 线程数当调⽤该接⼝的线程数达到阈值的时候进⾏限流 是否集群暂不需要集群 6.6.1.1 QPS 流控 前⾯6.4.4案例就是演示的QPS流控 6.6.1.2 线程数流控 删除掉之前的QPS流控新增线程数流控 在Jmeter中新增线程 访问 http://localhost:8091/sentinel2 会发现已经被限流 6.6.2 流控模式 点击上⾯设置流控规则的编辑按钮然后在编辑⻚⾯点击高级选项会看到有流控模式⼀栏。 sentinel共有三种流控模式分别是 直接默认接⼝达到限流条件时开启限流 关联当关联的资源达到限流条件时开启限流 [适合做应⽤让步] 链路当从某个接⼝过来的资源达到限流条件时开启限流 6.6.2.1 直接流控模式 前⾯演示的案例就是这种. 6.6.2.2 关联流控模式 关联流控模式指的是当指定接⼝关联的接⼝达到限流条件时开启对指定接⼝开启限流。 场景:当两个资源之间具有资源争抢或者依赖关系的时候这两个资源便具有了关联。⽐如对数据库同⼀个字段的读操作和写操作存在争抢读的速度过⾼会影响写得速度写的速度过⾼会影响读的速度。如果放任读写操作争抢资源则争抢本身带来的开销会降低整体的吞吐量。可使⽤关联限流来避免具有关联关系的资源之间过度的争抢. 在SentinelController.java中增加⼀个⽅法重启订单服务 RequestMapping(/sentinel3) public String sentinel3(){return sentinel3; }配置限流规则, 将流控模式设置为关联关联资源设置为的 /sentinel2 通过postman软件向/sentinel2连续发送请求注意QPS⼀定要⼤于3 访问/sentinel3,会发现已经被限流 6.5.2.3 链路流控模式 链路流控模式指的是当从某个接⼝过来的资源达到限流条件时开启限流。 在shop-order-server项⽬的application.yml⽂件中新增如下配置: spring:cloud:sentinel:web-context-unify: false #关闭链路折叠 比如说(/trace1/tranceService /trace2/tranceService它就会把它当成/tranceService, 所以这里要把它的折叠给关了)在shop-order-server项⽬中新增TraceServiceImpl.java package com.xiaoge.service.impl;import com.alibaba.csp.sentinel.annotation.SentinelResource; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service;Service Slf4j public class TraceServiceImpl {SentinelResource(value tranceService)public void tranceService() {log.info(调⽤tranceService⽅法);} }在shop-order-server项⽬中新增TraceController.java package com.xiaoge.controller;import com.xiaoge.service.impl.TraceServiceImpl; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController;RestController public class TraceController {Autowiredprivate TraceServiceImpl traceService;RequestMapping(/trace1)public String trace1() {traceService.tranceService();return trace1;}RequestMapping(/trace2)public String trace2() {traceService.tranceService();return trace2;} }重新启动订单服务并添加链路流控规则 分别通过 /trace1 和 /trace2 访问, 发现/trace1没问题, /trace2的被限流了 6.6.3 流控效果 快速失败默认: 直接失败抛出异常不做任何额外的处理是最简单的效果 Warm Up它从开始阈值到最⼤QPS阈值会有⼀个缓冲阶段⼀开始的阈值是最⼤QPS阈值的1/3然后慢慢增⻓直到最⼤阈值适⽤于将突然增⼤的流量转换为缓步增⻓的场景。 排队等待让请求以均匀的速度通过单机阈值为每秒通过数量其余的排队等待 它还会让设置⼀个超时时间当请求超过超时间时间还未处理则会被丢弃。 6.7 Sentinel 规则 - 降级 降级规则就是设置当满⾜什么条件的时候对服务进⾏降级。Sentinel提供了三个衡量条件 慢调用比例: 选择以慢调⽤⽐例作为阈值需要设置允许的慢调⽤ RT即最⼤的响应时间请求的响应时间⼤于该值则统计为慢调⽤。当单位统计时⻓内请求数⽬⼤于设置的最⼩请求数⽬并且慢调⽤的⽐例⼤于阈值则接下来的熔断时⻓内请求会⾃动被熔断。经过熔断时⻓后熔断器会进⼊探测恢复状态HALF-OPEN 状态若接下来的⼀个请求响应时间⼩于设置的慢调⽤ RT 则结束熔断若⼤于设置的慢调⽤ RT 则会再次被熔断。 异常比例: 当单位统计时⻓内请求数⽬⼤于设置的最⼩请求数⽬并且异常的⽐例⼤于阈值则接下来的熔断时⻓内请求会⾃动被熔断。经过熔断时⻓后熔断器会进⼊探测恢复状态HALF-OPEN状态若接下来的⼀个请求成功完成没有错误则结束熔断否则会再次被熔断。异常⽐率的阈值范围是 [0.0, 1.0] 代表 0% - 100%。 异常数当单位统计时⻓内的异常数⽬超过阈值之后会⾃动进⾏熔断。经过熔断时⻓后熔断器会进⼊探测恢复状态HALF-OPEN 状态若接下来的⼀个请求成功完成没有错误则结束熔断否则会再次被熔断。 6.7.1 慢调⽤⽐例案例 在shop-order-server项⽬中新增FallBackController.java类,代码如下: RestController Slf4j public class FallBackController {RequestMapping(/fallBack1)public String fallBack1(){try {log.info(fallBack1执⾏业务逻辑);//模拟业务耗时TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}return fallBack1;} }新增降级规则: 上⾯配置表示如果在1S之内,有【超过1个的请求】且这些请求中【响应时间最⼤RT】的【请求数量⽐例10%】就会触发熔断在接下来的10s之内都不会调⽤真实⽅法直接⾛降级⽅法。 ⽐如: 最⼤RT900,⽐例阈值0.1,熔断时⻓10,最⼩请求数10 情况1: 1秒内的有20个请求只有10个请求响应时间900ms, 那慢调⽤⽐例0.5这种情况就会触发熔断 情况2: 1秒内的有20个请求只有1个请求响应时间900ms, 那慢调⽤⽐例0.05这种情况不会触发熔断 情况3: 1秒内的有8个请求只有6个请求响应时间900ms, 那慢调⽤⽐例0.75这种情况不会触发熔断因为最⼩请求数这个条件没有满⾜. 注意: 我们做实验的时候把最⼩请求数设置为1因为在1秒内⼿动操作很难在1s内发两个请求过去所以要做出效果,最好把最⼩请求数设置为1。 6.7.2 异常比例案例 在shop-order-server项⽬的FallBackController.java类新增fallBack2⽅法: int i0; RequestMapping(/fallBack2) public String fallBack2(){log.info(fallBack2执⾏业务逻辑);//模拟出现异常异常⽐例为33%if(i%30){throw new RuntimeException();}return fallBack2; }新增降级规则: 上⾯配置表示在1s之内,有【超过3个的请求】异常⽐例30%的情况下触发熔断熔断时⻓为10s. 6.7.3 异常数案例 在shop-order-server项⽬的FallBackController.java类新增fallBack3⽅法: RequestMapping(/fallBack3) public String fallBack3(String name){log.info(fallBack3执⾏业务逻辑);if(xiaogeCode.equals(name)){throw new RuntimeException();}return fallBack3; }新增降级规则 上⾯配置表示在1s之内,有【超过3个的请求】请求中超过2个请求出现异常就会触发熔断 熔断时⻓为10s 6.8 Sentinel 规则 - 热点 何为热点热点即经常访问的数据。很多时候我们希望统计某个热点数据中访问频次最⾼的 Top K 数据并对其访问进⾏限制。⽐如 商品 ID 为参数统计⼀段时间内最常购买的商品 ID 并进⾏限制 ⽤户 ID 为参数针对⼀段时间内频繁访问的⽤户 ID 进⾏限制 热点参数限流会统计传⼊参数中的热点参数并根据配置的限流阈值与模式对包含热点参数的资源调⽤进⾏限流。热点参数限流可以看做是⼀种特殊的流量控制仅对包含热点参数的资源调⽤⽣效。 在shop-order-server项⽬中新增HotSpotController.java,代码如下: package com.xiaoge.controller;import com.alibaba.csp.sentinel.annotation.SentinelResource; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController;import java.util.concurrent.TimeUnit;RestController Slf4j public class HotSpotController {RequestMapping(/hotSpot1)SentinelResource(value hotSpot1)public String hotSpot1(Long productId) throws InterruptedException {log.info(访问编号为:{}的商品, productId);TimeUnit.SECONDS.sleep(1);return hotSpot1;} }注意:⼀定需要在请求⽅法上贴SentinelResource注解否则热点规则⽆效 新增热点规则: 在热点规则中编辑规则,在编辑之前⼀定要先访问⼀下/hotSpot1,不然参数规则⽆法新增. 新增参数规则: 点击保存可以看到已经新增了参数规则. 访问http://localhost:8091/hotSpot?productId1 访问会降级 访问http://localhost:8091/hotSpot?productId2 访问不会降级 6.9 Sentinel 规则 - 授权 很多时候我们需要根据调⽤来源来判断该次请求是否允许放⾏这时候可以使⽤ Sentinel 的来源访问控制⿊⽩名单控制的功能。来源访问控制根据资源的请求来源 origin 限制资源是否通过若配置⽩名单则只有请求来源位于⽩名单内时才可通过若配置⿊名单则请求来源位于⿊名单时不通过其余的请求通过。 在shop-order-server中新建RequestOriginParserDefinition.java,定义请求来源如何获取 package com.xiaoge.controller;import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.RequestOriginParser; import org.springframework.stereotype.Component;import javax.servlet.http.HttpServletRequest;Component public class RequestOriginParserDefinition implements RequestOriginParser {Overridepublic String parseOrigin(HttpServletRequest request) {/*** 定义从请求的什么地⽅获取来源信息* ⽐如我们可以要求所有的客户端需要在请求头中携带来源信息*/String serviceName request.getParameter(serviceName);return serviceName;} }在shop-order-server中新建AuthController.java,代码如下: package com.xiaoge.controller;import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController;RestController Slf4j public class AuthController {RequestMapping(/auth1)public String auth1(String serviceName) {log.info(应⽤:{},访问接⼝, serviceName);return auth1;} }新增授权规则 访问测试 访问http://localhost:8091/auth1?serviceNamepc 不能访问 访问http://localhost:8091/auth1?serviceNameapp 可以访问 6.10 Sentinel 规则 - 系统规则 系统保护规则是从应⽤级别的⼊⼝流量进⾏控制从单台机器的 load、CPU 使⽤率、平均 RT、⼊⼝QPS 和并发线程数等⼏个维度监控应⽤指标让系统尽可能跑在最⼤吞吐量的同时保证系统整体的稳定性。 系统保护规则是应⽤整体维度的⽽不是资源维度的并且仅对入口流量⽣效。⼊⼝流量指的是进⼊应⽤的流量 EntryType.IN ⽐如 Web 服务或 Dubbo 服务端接收的请求都属于⼊⼝流量。 系统规则⽀持以下的模式 Load ⾃适应仅对 Linux/Unix-like 机器⽣效系统的 load1 作为启发指标进⾏⾃适应系统保护。当系统 load1 超过设定的启发值且系统当前的并发线程数超过估算的系统容量时才会触发系统保护BBR 阶段。系统容量由系统的 maxQps * minRt 估算得出。设定参考值⼀般是 CPUcores * 2.5 。 CPU usage1.5.0 版本当系统 CPU 使⽤率超过阈值即触发系统保护取值范围 0.0-1.0⽐较灵敏。 平均 RT当单台机器上所有⼊⼝流量的平均 RT 达到阈值即触发系统保护单位是毫秒。 并发线程数当单台机器上所有⼊⼝流量的并发线程数达到阈值即触发系统保护。 入口 QPS当单台机器上所有⼊⼝流量的 QPS 达到阈值即触发系统保护。 6.11 Sentinel ⾃定义异常返回 当前⾯设定的规则没有满⾜是我们可以⾃定义异常返回. FlowException 限流异常 DegradeException 降级异常 ParamFlowException 参数限流异常 AuthorityException 授权异常SystemBlockException 系统负载异常 在shop-order-server项⽬中定义异常返回处理类 package com.xiaoge.controller;import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.BlockExceptionHandler; import com.alibaba.csp.sentinel.slots.block.BlockException; import com.alibaba.csp.sentinel.slots.block.authority.AuthorityException; import com.alibaba.csp.sentinel.slots.block.degrade.DegradeException; import com.alibaba.csp.sentinel.slots.block.flow.FlowException; import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowException; import com.alibaba.csp.sentinel.slots.system.SystemBlockException; import com.alibaba.fastjson.JSON; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import org.springframework.stereotype.Component;import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse;Component public class ExceptionHandlerPage implements BlockExceptionHandler {Overridepublic void handle(HttpServletRequest request, HttpServletResponse response, BlockException e) throws Exception {response.setContentType(application/json;charsetutf-8);ResultData data null;if (e instanceof FlowException) {data new ResultData(-1, 接⼝被限流了);} else if (e instanceof DegradeException) {data new ResultData(-2, 接⼝被降级了);} else if (e instanceof ParamFlowException) {data new ResultData(-3, 参数限流异常);} else if (e instanceof AuthorityException) {data new ResultData(-4, 授权异常);} else if (e instanceof SystemBlockException) {data new ResultData(-5, 接⼝被降级了...);}response.getWriter().write(JSON.toJSONString(data));} }Data AllArgsConstructor//全参构造 NoArgsConstructor//⽆参构造 class ResultData {private int code;private String message; }6.12 SentinelResource 的使⽤ 在定义了资源点之后我们可以通过Dashboard来设置限流和降级策略来对资源点进⾏保护。同时还能通过SentinelResource来指定出现异常时的处理策略。 SentinelResource ⽤于定义资源并提供可选的异常处理和 fallback 配置项。 其主要参数如下: 属性作⽤value资源名称必需项不能为空entryTypeentry 类型可选项默认为 EntryType.OUT blockHandler / blockHandlerClassblockHandler 对应处理 BlockException 的函数名称可选项。blockHandler 函数访问范围需要是public 返回类型需要与原⽅法相匹配参数类型需要和原⽅法相匹配并且最后加⼀个额外的参数类型为BlockException 。blockHandler 函数默认需要和原⽅法在同⼀个类中。若希望使⽤其他类的函数则可以指定blockHandlerClass 为对应的类的 Class 对象注意对应的函数必需为 static 函数否则⽆法解析。fallback / fallbackClassfallback 函数名称可选项⽤于在抛出异常的时候提供fallback 处理逻辑。fallback 函数可以针对所有类型的异常除了 exceptionsToIgnore ⾥⾯排除掉的异常类型进⾏处理。fallback 函数签名和位置要求1. 返回值类型必须与原函数返回值类型⼀致2.⽅法参数列表需要和原函数⼀致或者可以额外多⼀个Throwable 类型的参数⽤于接收对应的异常。3.fallback 函数默认需要和原⽅法在同⼀个类中。若希望使⽤其他类的函数则可以指定 fallbackClass 为对应的类的 Class 对象注意对应的函数必需为 static 函数否则⽆法解析。defaultFallback默认的 fallback 函数名称可选项通常⽤于通⽤的fallback 逻辑即可以⽤于很多服务或⽅法。默认fallback 函数可以针对所有类型的异常除了exceptionsToIgnore ⾥⾯排除掉的异常类型进⾏处理。若同时配置了 fallback 和 defaultFallback则只有fallback 会⽣效。defaultFallback 函数签名要求1. 返回值类型必须与原函数返回值类型⼀致2. ⽅法参数列表需要为空或者可以额外多⼀个Throwable 类型的参数⽤于接收对应的异常。3.defaultFallback 函数默认需要和原⽅法在同⼀个类中。若希望使⽤其他类的函数则可以指定 fallbackClass为对应的类的 Class 对象注意对应的函数必需为 static函数否则⽆法解析。exceptionsToIgnore⽤于指定哪些异常被排除掉不会计⼊异常统计中也不会进⼊ fallback 逻辑中⽽是会原样抛出。 定义限流和降级后的处理⽅法 直接将限流和降级⽅法定义在⽅法中 package com.xiaoge.controller;import com.alibaba.csp.sentinel.annotation.SentinelResource; import com.alibaba.csp.sentinel.slots.block.BlockException; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController;RestController Slf4j public class AnnoController {RequestMapping(/anno1)SentinelResource(value anno1, blockHandler anno1BlockHandler, // todo 当前方法如果被限流或者降级会调用这个字符串对应的方法fallback anno1Fallback // todo 当方法报错之后, 会调用这个字符串对应方法)public String anno1(String name) {if (xiaogeCode.equals(name)) {throw new RuntimeException();}return anno1;}public String anno1BlockHandler(String name, BlockException ex) {log.error({}, ex);return 接⼝被限流或者降级了;}//Throwable时进⼊的⽅法public String anno1Fallback(String name, Throwable throwable) {log.error({}, throwable);return 接⼝发⽣异常了;} }6.13 Feign 整合 Sentinel 在shop-order-server项⽬的配置⽂件中开启feign对Sentinel的⽀持 # 开启feign整合sentinel feign:sentinel:enabled: true创建容错类 package com.xiaoge.feign;import com.xiaoge.entity.Product; import org.springframework.stereotype.Component;/*** TODO** author a hrefmailto:1330137071qq.comZhang Xiao/a* since*/ Component public class ProductFeignFallback implements ProductFeignClientApi {Overridepublic Product findByPid(Long pid) {Product product new Product();product.setPname(兜底商品);return product;} } 在feign接⼝中定义容错类 package com.xiaoge.feign;import com.xiaoge.entity.Product; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping;/*** TODO** author a hrefmailto:1330137071qq.comZhang Xiao/a* since*/ FeignClient(value product-service, fallback ProductFeignFallback.class) public interface ProductFeignClientApi {RequestMapping(/product/{pid})Product findByPid(PathVariable(pid) Long pid);}停⽌所有 商品服务,重启 shop-order 服务,访问请求,观察容错效果 可能上⾯的案例并不是特别恰当我们只是通过案例来演示Feign集成Sentinel实现降级的效果. 接下来我们具体更贴切的案例来讲解Feign降级的作⽤. ⽐如我们在购物的时候查看商品详情⻚⾯的时候⾥⾯包含库存信息,商品详情信息,评论信息这个需求包含的微服务如下: 假设现在评论服务宕机了,那是不是意味⽤户发出查看商品请求也⽆法正常显示了商品都看不到了那⽤户也⽆法进⾏下单的操作了. 但是对于⽤户来说评论看不到并不影响他购物所以这时候我们应该对评论服务进⾏及·降级处理返回⼀个兜底数据(空数据)这样⽤户的查看商品请求能正常显示只是评论数据看不到⽽已这样的话⽤户的下单请求也不会受到影响. 服务网关 Gateway ⼤家都都知道在微服务架构中⼀个系统会被拆分为很多个微服务。那么作为客户端要如何去调⽤这么多的微服务呢如果没有⽹关的存在我们只能在客户端记录每个微服务的地址然后分别去调⽤。 这样的架构会存在着诸多的问题 客户端多次请求不同的微服务增加客户端代码或配置编写的复杂性 认证复杂每个服务都需要独⽴认证。 微服务做集群的情况下客户端并没有负责均衡的功能 上⾯的这些问题可以借助API 网关来解决。 所谓的API⽹关就是指系统的统⼀⼊⼝它封装了应⽤程序的内部结构为客户端提供统⼀服务⼀些与业务本身功能⽆关的公共逻辑可以在这⾥实现诸如认证、鉴权、监控、路由转发等等。 添加上API⽹关之后系统的架构图变成了如下所示 ⽹关是如何知道微服务的地址?⽹关如何进⾏负载均衡呢 ⽹关需要将⾃⼰的信息注册到注册中⼼上并且拉取其他微服务的信息然后再调⽤的时候基于Ribbon实现负载均衡 7.1 常见网关介绍 Nginxlua 使⽤nginx的反向代理和负载均衡可实现对api服务器的负载均衡及⾼可⽤,lua是⼀种脚本语⾔,可以来编 写⼀些简单的逻辑, nginx⽀持lua脚本 Kong 基于NginxLua开发性能⾼稳定有多个可⽤的插件(限流、鉴权等等)可以开箱即⽤。 问题只⽀持Http协议⼆次开发⾃由扩展困难提供管理API缺乏更易⽤的管控、配置⽅式。 Zuul Netflflix开源的⽹关功能丰富使⽤JAVA开发易于⼆次开发 问题缺乏管控⽆法动态配置依赖组件较多处理Http请求依赖的是Web容器性能不如Nginx,Spring Cloud Gateway Spring公司为了替换Zuul⽽开发的⽹关服务将在下⾯具体介绍。 注意SpringCloud alibaba技术栈中并没有提供⾃⼰的⽹关我们可以采⽤Spring Cloud Gateway来做⽹关 7.2 Gateway 简介 Spring Cloud Gateway是Spring公司基于Spring 5.0Spring Boot 2.0 和 Project Reactor 等技术开发的⽹关它旨在为微服务架构提供⼀种简单有效的统⼀的 API 路由管理⽅式。它的⽬标是替代Netflflix Zuul其不仅提供统⼀的路由⽅式并且基于 Filter 链的⽅式提供了⽹关基本的功能例如安全监控和限流。 优点 性能强劲是第⼀代⽹关Zuul的1.6倍 功能强⼤内置了很多实⽤的功能例如转发、监控、限流等 设计优雅容易扩展 缺点 其实现依赖Netty与WebFlux不是传统的Servlet编程模型学习成本⾼ 不能将其部署在Tomcat、Jetty等Servlet容器⾥只能打成jar包执⾏ 需要Spring Boot 2.0及以上的版本才⽀持 7.3 Gateway 快速⼊⻔ 创建⼀个 api-gateway 的模块,导⼊相关依赖 ?xml version1.0 encodingUTF-8? project xmlnshttp://maven.apache.org/POM/4.0.0xmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsdmodelVersion4.0.0/modelVersionparentgroupIdcom.xiaoge/groupIdartifactIdshop-parent/artifactIdversion1.0-SNAPSHOT/version/parentartifactIdapi-gateway/artifactIddependencies!--gateway⽹关--dependencygroupIdorg.springframework.cloud/groupIdartifactIdspring-cloud-starter-gateway/artifactId/dependency!--nacos客户端--dependencygroupIdcom.alibaba.cloud/groupIdartifactIdspring-cloud-starter-alibaba-nacos-discovery/artifactId/dependencydependencygroupIdorg.projectlombok/groupIdartifactIdlombok/artifactId/dependency/dependencies/project编写启动类 package com.xiaoge;import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient;/*** TODO** author a hrefmailto:1330137071qq.comZhang Xiao/a* since*/ EnableDiscoveryClient SpringBootApplication public class GatewayApplication {public static void main(String[] args) {SpringApplication.run(GatewayApplication.class, args);} }编写配置⽂件 server:port: 9000 spring:application:name: api-gatewaycloud:nacos:discovery:server-addr: localhost:8848gateway:discovery:locator:enabled: true # 让gateway可以发现nacos中的微服务 # 注意网关不配置路由规则, 它有默认的规则, 就是你访问的服务名必须是对应的服务的应用名, 它就会转发到对应的服务下, 即使我们配置了规则, 默认规则还是存在 启动测试 7.4 ⾃定义路由规则 在application.yml中添加新的路由规则 spring:cloud: # 注意网关不配置路由规则, 它有默认的规则, 就是你访问的服务名必须是对应的服务的应用名, 它就会转发到对应的服务下, 即使我们配置了规则, 默认规则还是存在routes:- id: product_route # 路由名称保持唯一uri: lb://product-service # 符合条件的请求转发到那个服务, lb表示对服务进行负载均衡predicates: # 拦截那些请求- Path/product-serv/**filters: # 在转发请求之前, 将拦截到的路径的第一层路径删除掉- StripPrefix1- id: order_routeuri: lb://order-servicepredicates:- Path/order-serv/**filters:- StripPrefix1启动测试 7.5 Gateway 概念 路由(Route) 是 gateway 中最基本的组件之⼀表示⼀个具体的路由信息载体。主要定义了下⾯的⼏个信息: id路由标识符区别于其他 Route。 uri路由指向的⽬的地 uri即客户端请求最终被转发到的微服务。 order⽤于多个 Route 之间的排序数值越⼩排序越靠前匹配优先级越⾼。 predicate断⾔的作⽤是进⾏条件判断只有断⾔都返回真才会真正的执⾏路由。 filter过滤器⽤于修改请求和响应信息。 执⾏流程图: 7.6 过滤器 Filter 过滤器就是在请求的传递过程中,对请求和响应做⼀些⼿脚. 在Gateway中, Filter的⽣命周期只有两个“pre” 和 “post”。 PRE 这种过滤器在请求被路由之前调⽤。我们可利⽤这种过滤器实现身份验证、在集群中选择请求的微服务、记录调试信息等。 POST这种过滤器在路由到微服务以后执⾏。这种过滤器可⽤来为响应添加标准的HTTP Header、收集统计信息和指标、将响应从微服务发送给客户端等。 在Gateway中Filter的作⽤范围两种: GatewayFilter应⽤到单个路由或者⼀个分组的路由上。 GlobalFilter应⽤到所有的路由上 7.6.1 局部路由过滤器 局部过滤器是针对单个路由的过滤器,在SpringCloud Gateway中内置了很多不同类型的⽹关路由过滤器,有兴趣同学可以⾃⾏了解这⾥太多了我们就不⼀⼀讲解我们主要来讲⼀下⾃定义路由过滤器。 需求: 统计订单服务调⽤耗时. 编写Filter类注意名称是有固定格式xxxGatewayFilterFactory package com.xiaoge.filter;import lombok.Getter; import lombok.Setter; import org.springframework.cloud.gateway.filter.GatewayFilter; import org.springframework.cloud.gateway.filter.GatewayFilterChain; import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory; import org.springframework.stereotype.Component; import org.springframework.web.server.ServerWebExchange; import reactor.core.publisher.Mono;import java.util.Arrays; import java.util.List;/*** todo 自定义局部过滤器, 注意一定要请求我们定义了过滤器的那个路由负责, 该过滤器才会生效.* todo* gateway:* discovery:* locator:* enabled: true* 我们定义了这个配置文件, 它会让gateway可以发现nacos中的微服务, 就会有默认的规则, 就是你访问的服务名必须是对应的服务的应用名, 它就会转发到对应的服务下, 即使我们配置了规则, 默认规则还是存在*/ Component public class TimeGatewayFilterFactory extends AbstractGatewayFilterFactoryTimeGatewayFilterFactory.Config {private static final String BEGIN_TIME beginTime;//构造函数public TimeGatewayFilterFactory() {super(TimeGatewayFilterFactory.Config.class);}// 读取配置⽂件中的参数 赋值到 配置类中Overridepublic ListString shortcutFieldOrder() {/** todo application.yml 中配置的事 - Timetrue 所以只有一个值, 所以这里Arrays.asList(show)也只是一个值这里的值要跟application.yml中对应的值对应, 假设 - Timetrue,false, 那么这里Arrays.asList(show,abc) 值随便写(可以不对应, 但是asList里面的值必须比, application.yml中的值多)下面静态类Config里面属性的数量要跟Arrays.asList对应*/return Arrays.asList(show);}// todo 拦截到之后就会调用apply方法, 把创建对象时候反射创建出来的config传入进来Overridepublic GatewayFilter apply(Config config) {return new GatewayFilter() {Overridepublic MonoVoid filter(ServerWebExchange exchange, GatewayFilterChain chain) {if (!config.show) {return chain.filter(exchange);}exchange.getAttributes().put(BEGIN_TIME,System.currentTimeMillis());/*** pre的逻辑* chain.filter().then(Mono.fromRunable(()-{* post的逻辑* }))*/return chain.filter(exchange).then(Mono.fromRunnable(() - {Long startTime exchange.getAttribute(BEGIN_TIME);if (startTime ! null) {System.out.println(exchange.getRequest().getURI() 请求耗时: (System.currentTimeMillis() - startTime) ms);}}));}};}SetterGetterstatic class Config {private boolean show;} }在指定的路由中添加路由规则 server:port: 9000 spring:application:name: api-gatewaycloud:nacos:discovery:server-addr: localhost:8848gateway:discovery:locator:enabled: true # 让gateway可以发现nacos中的微服务 # 注意网关不配置路由规则, 它有默认的规则, 就是你访问的服务名必须是对应的服务的应用名, 它就会转发到对应的服务下, 即使我们配置了规则, 默认规则还是存在routes:- id: product_route # 路由名称保持唯一uri: lb://product-service # 符合条件的请求转发到那个服务, lb表示对服务进行负载均衡predicates: # 拦截那些请求- Path/product-serv/**filters: # 在转发请求之前, 将拦截到的路径的第一层路径删除掉- StripPrefix1- id: order_routeuri: lb://order-servicepredicates:- Path/order-serv/**filters:- StripPrefix1- Timetrue # 自定义过滤器 访问商品服务的时候是没有打印⽇志的访问订单服务的时候打印⼊职如下: 7.6.2 全局路由过滤器 全局过滤器作⽤于所有路由, ⽆需配置。通过全局过滤器可以实现对权限的统⼀校验安全性验证等功能。 SpringCloud Gateway内部也是通过⼀系列的内置全局过滤器对整个路由转发进⾏处理如下 需求: 实现统⼀鉴权的功能,我们需要在⽹关判断请求中是否包含token且如果没有则不转发路由有则执⾏正常逻辑。 编写全局过滤类 package com.xiaoge.filter;import org.apache.commons.lang3.StringUtils; import org.springframework.cloud.gateway.filter.GatewayFilterChain; import org.springframework.cloud.gateway.filter.GlobalFilter; import org.springframework.http.HttpStatus; import org.springframework.stereotype.Component; import org.springframework.web.server.ServerWebExchange; import reactor.core.publisher.Mono;/*** 自定义全局过滤器*/ Component public class AuthGlobalFilter implements GlobalFilter {Overridepublic MonoVoid filter(ServerWebExchange exchange, GatewayFilterChain chain) {String token exchange.getRequest().getQueryParams().getFirst(token);if (StringUtils.isBlank(token)) {System.out.println(鉴权失败);exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);// 不让它继续访问, 直接截断返回对应的responsereturn exchange.getResponse().setComplete();}return chain.filter(exchange);} }启动并测试 7.7 集成 Sentinel 实现网关限流 ⽹关是所有请求的公共⼊⼝所以可以在⽹关进⾏限流⽽且限流的⽅式也很多我们本次采⽤前⾯学过的Sentinel组件来实现⽹关的限流。Sentinel⽀持对SpringCloud Gateway、Zuul等主流⽹关进⾏限流。 从1.6.0版本开始Sentinel提供了SpringCloud Gateway的适配模块可以提供两种资源维度的限流 route维度即在Spring配置⽂件中配置的路由条⽬资源名为对应的routeId ⾃定义API维度⽤户可以利⽤Sentinel提供的API来⾃定义⼀些API分组 7.7.1 网关集成 Sentinel https://github.com/alibaba/Sentinel/wiki/⽹关限流 添加依赖 dependencygroupIdcom.alibaba.csp/groupIdartifactIdsentinel-spring-cloud-gateway-adapter/artifactId /dependency dependencygroupIdcom.alibaba.cloud/groupIdartifactIdspring-cloud-starter-alibaba-sentinel/artifactId /dependency dependencygroupIdcom.alibaba.cloud/groupIdartifactIdspring-cloud-alibaba-sentinel-gateway/artifactId /dependency添加配置 spring:cloud:sentinel:transport:port: 9999dashboard: localhost:8080重启⽹关服务并测试. 7.7.2 API 分组 Sentinel中⽀持按照API分组进⾏限流,就是我们可以按照特定规则进⾏限流. 在管控台⻚⾯中提供了三种⽅式的API分组管理 精准匹配 前缀匹配 正则匹配 现在我们定义了如下的接⼝地址 package com.xiaoge.controller;import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController;/*** TODO** author a hrefmailto:1330137071qq.comZhang Xiao/a* since*/ RestController RequestMapping(value v1) Slf4j public class TestController {RequestMapping(/test1)public String test1() {return test1;}RequestMapping(/test2)public String test2() {return test2;}RequestMapping(/test3/test)public String test3() {return test3;}} 精准匹配 在API管理中新建API分组匹配模式选择精准匹配匹配串写请求URL地址 在流控规则中API类型中选择API分组然后在API名称中选择我们刚刚定义的V1限流 此时上⾯三个请求中只有 /product-service/v1/test1会被限流 前缀匹配 在API管理中新建API分组匹配模式选择前缀匹配匹配串写请求URL地址 此时 /product-service/v1/test1 和 /product-service/v1/test2 会被限流 注意: 如果路径为/*表示匹配⼀级路径如果路径为/**表示多级路径 正则匹配 在API管理中新建API分组匹配模式选择正则匹配匹配串写请求URL地址 7.7.3 修改限流默认返回格式 在配置类GatewayConfiguration.java中添加如下配置 package com.xiaoge.config;import com.alibaba.csp.sentinel.adapter.gateway.sc.callback.BlockRequestHandler; import com.alibaba.csp.sentinel.adapter.gateway.sc.callback.GatewayCallbackManager; import org.springframework.context.annotation.Configuration; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.web.reactive.function.BodyInserters; import org.springframework.web.reactive.function.server.ServerResponse; import org.springframework.web.server.ServerWebExchange; import reactor.core.publisher.Mono;import javax.annotation.PostConstruct; import java.util.HashMap; import java.util.Map;/*** todo 自定义网关集成sentinel限流返回格式*/ Configuration public class GatewayConfiguration {PostConstructpublic void initBlockHandlers() {BlockRequestHandler blockRequestHandler new BlockRequestHandler() {public MonoServerResponse handleRequest(ServerWebExchange serverWebExchange, Throwable throwable) {Map map new HashMap();map.put(code, 0);map.put(message, 接⼝被限流了);return ServerResponse.status(HttpStatus.OK).contentType(MediaType.APPLICATION_JSON).body(BodyInserters.fromValue(map));}};GatewayCallbackManager.setBlockHandler(blockRequestHandler);}} 重启并测试 链路追踪 SleuthZipkin 微服务架构是⼀个分布式架构它按业务划分服务单元⼀个分布式系统往往有很多个服务单元。由于服务单元数量众多业务的复杂性如果出现了错误和异常很难去定位。主要体现在⼀个请求可能需要调⽤很多个服务⽽内部服务的调⽤复杂性决定了问题难以定位。所以微服务架构中必须实现分布式链路追踪去跟进⼀个请求到底有哪些服务参与参与的顺序⼜是怎样的从⽽达到每个请求的步骤清晰可⻅出了问题很快定位。 分布式链路追踪Distributed Tracing就是将⼀次分布式请求还原成调⽤链路进⾏⽇志记录性能监控并将⼀次分布式请求的调⽤情况集中展示。⽐如各个服务节点上的耗时、请求具体到达哪台机器上、每个服务节点的请求状态等等。 8.1 常见的链路追踪技术 cat 由⼤众点评开源基于Java开发的实时应⽤监控平台包括实时应⽤监控业务监控 。 集成⽅案是通过代码埋点的⽅式来实现监控⽐如 拦截器过滤器等。 对代码的侵⼊性很⼤集成成本较⾼。⻛险较⼤。 zipkin 由Twitter公司开源开放源代码分布式的跟踪系统⽤于收集服务的定时数据以解决微服务架构中的延迟问题包括数据的收集、存储、查找和展现。该产品结合spring-cloud-sleuth使⽤较为简单 集成很⽅便 但是功能较简单。 pinpoint Pinpoint是韩国⼈开源的基于字节码注⼊的调⽤链分析以及应⽤监控分析⼯具。特点是⽀持多种插件UI功能强⼤接⼊端⽆代码侵⼊。 skywalkingSkyWalking是本⼟开源的基于字节码注⼊的调⽤链分析以及应⽤监控分析⼯具。特点是⽀持多种插件UI功能较强接⼊端⽆代码侵⼊。⽬前已加⼊Apache孵化器。 Sleuth: SpringCloud 提供的分布式系统中链路追踪解决⽅案。 8.2 集成链路追踪组件 Sleuth 在product-server和order-server中添加sleuth依赖 !-- 日志链路追踪 -- dependencygroupIdorg.springframework.cloud/groupIdartifactIdspring-cloud-starter-sleuth/artifactId /dependency订单微服务调⽤商品微服务这个流程中通过Slfj打印⽇志.重启服务并访问测试订单服务⽇志结果: 商品服务⽇志结果: 8.3 ⽇志参数解释 ⽇志格式: [order-server,c323c72e7009c077,fba72d9c65745e60,false] 1、第⼀个值spring.application.name的值 2、第⼆个值c323c72e7009c077 sleuth⽣成的⼀个ID叫Trace ID⽤来标识⼀条请求链路⼀条请求链路中包含⼀个Trace ID多个Span ID 3、第三个值fba72d9c65745e60、spanID 基本的⼯作单元获取元数据如发送⼀个http 4、第四个值true是否要将该信息输出到zipkin服务中来收集和展示。 8.4 ZipkinSleuth 整合 zipkin是Twitter基于google的分布式监控系统Dapper论⽂的开发源实现zipkin⽤于跟踪分布式服务之间的应⽤数据链路分析处理延时帮助我们改进系统的性能和定位故障。 官⽹:https://zipkin.io/ 下载Zipkin的jar包在官⽹可以下载. 通过命令⾏输⼊下⾯的命令启动ZipKin Server java -jar zipkin-server-2.22.1-exec.jar通过浏览器访问 http://localhost:9411访问 在订单微服务和商品微服务中添加zipkin依赖 dependencygroupIdorg.springframework.cloud/groupIdartifactIdspring-cloud-starter-zipkin/artifactId /dependency在订单微服务和商品微服务中添加如下配置: spring:zipkin:base-url: http://127.0.0.1:9411/ #zipkin server的请求地址discoveryClientEnabled: false #让nacos把它当成⼀个URL⽽不要当做服务名, 这样127.0.0.1:9411这个地址就不会去nacos中找对应服务sleuth:sampler:probability: 1.0 #采样的百分⽐重启订单微服务和商品微服务,访问 http://localhost:8091/save?uid1pid1 访问zipkin的UI界⾯观察效果 配置中心 Nacos Config 9.1 服务配置中心介绍 ⾸先我们来看⼀下,微服务架构下关于配置⽂件的⼀些问题 配置⽂件相对分散。在⼀个微服务架构下配置⽂件会随着微服务的增多变的越来越多⽽且分散在各个微服务中不好统⼀配置和管理。 配置⽂件⽆法区分环境。微服务项⽬可能会有多个环境例如测试环境、预发布环境、⽣产环境。每⼀个环境所使⽤的配置理论上都是不同的⼀旦需要修改就需要我们去各个微服务下⼿动维护这⽐较困难。 配置⽂件⽆法实时更新。我们修改了配置⽂件之后必须重新启动微服务才能使配置⽣效这对⼀个正在运⾏的项⽬来说是⾮常不友好的。 基于上⾯这些问题我们就需要配置中心的加⼊来解决这些问题。 配置中心的思路是 ⾸先把项⽬中各种配置全部都放到⼀个集中的地⽅进⾏统⼀管理并提供⼀套标准的接⼝。 当各个服务需要获取配置的时候就来配置中⼼的接⼝拉取⾃⼰的配置。 当配置中⼼中的各种参数有更新的时候也能通知到各个服务实时的过来同步最新的信息使之动态更新。 当加⼊了服务配置中⼼之后我们的系统架构图会变成下⾯这样 9.2 常⻅的服务配置中心 Apollo Apollo是由携程开源的分布式配置中⼼。特点有很多⽐如配置更新之后可以实时⽣效⽀持灰度发布功能并且能对所有的配置进⾏版本管理、操作审计等功能提供开放平台API。并且资料也写的很详细。 Disconf Disconf是由百度开源的分布式配置中⼼。它是基于Zookeeper来实现配置变更后实时通知和⽣效的。 SpringCloud Config 这是Spring Cloud中带的配置中⼼组件。它和Spring是⽆缝集成使⽤起来⾮常⽅便并且它的配置存储⽀持Git。不过它没有可视化的操作界⾯配置的⽣效也不是实时的需要重启或去刷新。 Nacos 这是SpingCloud alibaba技术栈中的⼀个组件前⾯我们已经使⽤它做过服务注册中⼼。其实它也集成了服务配置的功能我们可以直接使⽤它作为服务配置中⼼。 9.3 Nacos Config ⼊⻔ 使⽤nacos作为配置中⼼其实就是将nacos当做⼀个服务端将各个微服务看成是客户端我们将各个微服务的配置⽂件统⼀存放在nacos上然后各个微服务从nacos上拉取配置即可。 接下来我们以商品微服务为例学习nacos config的使⽤。 搭建nacos环境【使⽤现有的nacos环境即可】 在商品微服务中引⼊nacos的依赖 dependencygroupIdcom.alibaba.cloud/groupIdartifactIdspring-cloud-starter-alibaba-nacos-config/artifactId /dependency在微服务中添加nacos config的配置 注意:不能使⽤原来的 application.yml 作为配置⽂件⽽是新建⼀个 bootstrap.yml 作为配置⽂件 配置⽂件优先级(由⾼到低): bootstrap.properties - bootstrap.yml - application.properties - application.ymlspring:application:name: product-servicecloud:nacos:config:server-addr: 127.0.0.1:8848 #nacos中⼼地址file-extension: yaml # 配置⽂件格式profiles:active: dev # 环境标识 # 使用了nacos配置中心, 它会自动去根据服务名称(order-service)和指定的环境信息(dev)和指定后置(yaml), 去nacos配置中心找到对应的配置(order-service-dev.yaml)加载到内存中, 使用了nacos配置中心, 本地application.yml也还在 # 相同配置nacos中的配置负载application.yml中的, application.yml中的覆盖bootstrap.yml中的在nacos中添加配置,然后把商品微服务application.yml配置复制到配置内容中. 注释本地的application.yam中的内容 启动程序进⾏测试 如果依旧可以成功访问程序说明我们nacos的配置中⼼功能已经实现 9.4 配置动态刷新 在⼊⻔案例中我们实现了配置的远程存放但是此时如果修改了配置我们的程序是⽆法读取到的因此我们需要开启配置的动态刷新功能. 在nacos中的product-service-dev.yaml配置项中添加下⾯配置: appConfig:name: product2020在商品微服务中新增NacosConfigControlller.java package com.xiaoge.controller;import org.springframework.beans.factory.annotation.Value; import org.springframework.cloud.context.config.annotation.RefreshScope; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController;RestController RefreshScope public class NacosConfigController {Value(${appConfig.name})private String appConfigName;RequestMapping(/nacosConfig1)public String nacosConfig() {return 远程信息: appConfigName;} }9.5 配置共享 当配置越来越多的时候我们就发现有很多配置是重复的这时候就考虑可不可以将公共配置⽂件提取出来然后实现共享呢当然是可以的。接下来我们就来探讨如何实现这⼀功能。 同⼀个微服务的不同环境之间共享配置 如果想在同⼀个微服务的不同环境之间实现配置共享其实很简单。只需要提取⼀个以spring.application.name 命名的配置⽂件然后将其所有环境的公共配置放在⾥⾯即可。 新建⼀个名为product-service.yaml配置存放商品微服务的公共配置,把之前的公共配置都存放进去. 新建⼀个名为product-service-test.yaml配置存放测试环境的配置 新建⼀个名为product-service-dev.yaml配置存放测试环境的配置 需要的配置信息具体如下: 在NacosConfigController.java中新增如下逻辑 RestController RefreshScope public class NacosConfigController {Value(${appConfig.name})private String appConfigName;Value(${env})private String env;RequestMapping(/nacosConfig1)public String nacosConfig(){return 远程信息:appConfigName;}RequestMapping(/nacosConfig2)public String nacosConfig2(){return 公共配置:appConfigName,环境配置信息:env;} }通过修改环境参看是否可以读取公共配置和环境独有配置 不同微服务中间共享配置 不同为服务之间实现配置共享的原理类似于⽂件引⼊就是定义⼀个公共配置然后在当前配置中引⼊。 在nacos中定义⼀个DataID为global-config.yaml的配置⽤于所有微服务共享 globalConfig: global修改bootstrap.yaml spring:application:name: order-servicecloud:nacos:config:server-addr: 127.0.0.1:8848 #nacos中⼼地址file-extension: yaml # 配置⽂件格式shared-configs:- data-id: global-config.yaml # 配置要引⼊的配置, 引入nacos中定义的配置 (这里什么配置文件都可以引入, 通过data-id, 需要引入多个全局配置就写多个data-id)refresh: true # 动态刷新profiles:active: dev # 环境标识 # 使用了nacos配置中心, 它会自动去根据服务名称(order-service)和指定的环境信息(dev)和指定后置(yaml), 去nacos配置中心找到对应的配置(order-service-dev.yaml)加载到内存中, 使用了nacos配置中心, 本地application.yml也还在 # 相同配置nacos中的配置负载application.yml中的, application.yml中的覆盖bootstrap.yml中的在NacosConfigController.java中新增⼀个⽅法 RestController RefreshScope public class NacosConfigController {Value(${appConfig.name})private String appConfigName;Value(${env})private String env;Value(${globalConfig})private String globalConfig;RequestMapping(/nacosConfig1)public String nacosConfig(){return 远程信息:appConfigName;}RequestMapping(/nacosConfig2)public String nacosConfig2(){return 公共配置:appConfigName,环境配置信息:env;}RequestMapping(/nacosConfig3)public String nacosConfig3(){return 全局配置:globalConfig,公共配置:appConfigName,环境配置信息:env;} }重启服务并测试. demo下载地址: https://download.csdn.net/download/zsx1314lovezyf/88282556
http://wiki.neutronadmin.com/news/202967/

相关文章:

  • 系部网站建设需求分析运行需求wpf做的网站
  • 网站推荐你了解我意思吧官网设计比较好看的网站
  • 做虚假网站犯法吗电子商务网站建设作业案例
  • 绵阳市住房和城乡建设局网站网站有什么功能
  • 网站建设山东聚搜网络c 还可以做网站
  • 宜兴营销型网站建设阿里云网站的网页怎么做
  • 长沙自助模板建站企业管理软件销售
  • 最先进的深圳网站建设山东坤泰建设集团网站
  • 行政单位网站建设立项依据乐华网络公司介绍
  • 24小时网站建设手机网站乱弹
  • 做t-shirt素材网站中企邮箱登录入口
  • 新建网站做优化建设公司起名
  • 江西赣建建设监理网站手机优化大师怎么退款
  • 建设个网站做彩票网站需要什么服务器
  • 交互型网站开发网站建设接单技巧
  • 自己编写网站四川成都新冠最新消息
  • 网站信息备案管理系统wordpress post slug codex
  • 珠海七中科技制作汕头seo网站管理
  • 国外炫酷网站设计网站设计模板图片
  • 外贸建站 知乎网站建设技术论文
  • 安徽合肥企业网页制作公司网站优化的文章
  • 做动态影集的网站郑州app开发公司
  • 淘宝客源码程序 爱淘宝风格+程序自动采集商品 淘宝客网站模板iis网站拒绝显示此网页
  • 网站模板如何优化wordpress简
  • 无锡网站制作电话多少河南省建设厅网站103
  • 南城区仿做网站免费友情链接网页
  • 带导航栏的网站个人博客网站如何做SEO
  • 手机网站建设app网站备案证书放到哪里
  • 制作网站 公司简介桂林做网站公司
  • 肇庆网站制作案例特产网站建设的目的