赞
踩
作用 | 组件 |
---|---|
服务注册与发现、分布式配置中心 | Alibaba-nacos |
服务熔断,降级与限流 | Alibaba-sentinel |
分布式事务 | Alibaba-seata |
远程调用 | SpringCloud-openfeign |
负载均衡 | SpringCloud-loadbalancer |
网关 | SpringCloud-Gateway |
链路追踪 | SpringCloud-zipkin |
组件 | 版本 |
---|---|
jdk | 1.8 |
spring-boot | 2.6.3 |
spring-cloud | 2021.0.0 |
spring-cloud-alibaba | 2021.1 |
组件 | 版本 |
---|---|
nacos | 2.0.3 |
sentinel | 1.8.1 |
seata | 1.3.0 |
zipkin | 2.23.16 |
各类客户端组件已经在SpringCloud、SpringCloudAlibaba父POM中定义好了版本,在子模块POM不需要再次指定版本。
<!--链路追踪 zipkin依赖,其中包含Sleuth的依赖--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-zipkin</artifactId> <version>2.2.8.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-sleuth-zipkin</artifactId> <version>3.1.1</version> </dependency> <!--mybatis-plus--> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.5.1</version> </dependency> <!-- swagger --> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger2</artifactId> <version>2.9.2</version> </dependency> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger-ui</artifactId> <version>2.9.2</version> </dependency>
官方文档:https://nacos.io/zh-cn/docs/quick-start-spring-cloud.html
Nacos 致力于帮助您发现、配置和管理微服务。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据及流量管理。
nacos与eureka区别:
模块 | Nacos | Eureka | 说明 |
---|---|---|---|
注册中心 | 是 | 是 | 服务治理基本功能,负责服务中心化注册 |
配置中心 | 是 | 否 | Eureka需要配合Config实现配置中心,且不提供管理界面 |
动态刷新 | 是 | 否 | Eureka需要配合MQ实现配置动态刷新,Nacos采用Netty保持TCP长连接实时推送 |
可用区AZ | 是 | 是 | 对服务集群划分不同区域,实现区域隔离,并提供容灾自动切换 |
分组 | 是 | 否 | Nacos可用根据业务和环境进行分组管理 |
元数据 | 是 | 是 | 提供服务标签数据,例如环境或服务标识 |
权重 | 是 | 否 | Nacos默认提供权重设置功能,调整承载流量压力 |
健康检查 | 是 | 是 | Nacos支持由客户端或服务端发起的健康检查,Eureka是由客户端发起心跳 |
负载均衡 | 是 | 是 | 均提供负载均衡策略,Eureka采用Ribion |
管理界面 | 是 | 否 | Nacos支持对服务在线管理,Eureka只是预览服务状态 |
下载地址:https://github.com/alibaba/nacos/releases
进入nacos的bin目录
cd /nacos/bin
启动命令(standalone代表着单机模式运行,非集群模式):
sh startup.sh -m standalone
如果您使用的是ubuntu系统,或者运行脚本报错提示[[符号找不到,可尝试如下运行:
bash startup.sh -m standalone
启动命令(standalone代表着单机模式运行,非集群模式):
startup.cmd -m standalone
访问:localhost:8848/nacos 登录名和密码默认都是: nacos
打开mysql创建nacos数据库
将conf目录下的nacos-mysql.sql导入nacos数据库中
将conf目录下的cluster.conf.example拷贝重命名为cluster.conf
配置集群的**真实**IP地址及端口(3个及以上)
192.168.0.100:8848
192.168.0.100:8850
192.168.0.100:8855
修改conf目录下的applicaiton.prooperty配置文件(端口,数据库连接)
### Default web server port: server.port=8848 #*************** Network Related Configurations ***************# ### If prefer hostname over ip for Nacos server addresses in cluster.conf: # nacos.inetutils.prefer-hostname-over-ip=false ### Specify local server's IP: # nacos.inetutils.ip-address= #*************** Config Module Related Configurations ***************# ### If use MySQL as datasource: spring.datasource.platform=mysql ### Count of DB: db.num=1 ### Connect URL of DB: db.url.0=jdbc:mysql://127.0.0.1:3306/nacos?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTC db.user.0=root db.password.0=123456
拷贝3份nacos,修改每一份的conf/application.property的server.port 为刚刚在cluster.conf配置的端口
分别进入3个nacos的bin目录中启动(不加 -m cluster 默认也是集群方式启动)
sh startup.sh -m cluster
打开nacos控制台,查看集群管理。看到其他的服务说明集群配置成功。
sh shutdown.sh
shutdown.cmd
或者双击shutdown.cmd运行文件。
<!--新版本的springboot不能直接在编写bootstrap.yml,需要导入这个包才可以-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bootstrap</artifactId>
</dependency>
<!--springcloud nacos服务发现客户端-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
spring:
application:
name: userServer
cloud:
nacos:
discovery:
server-addr: localhost:8848 #服务注册中心地址
3. 主启动类开启服务发现 @EnableDiscoveryClient
package top.scsoul.userserviceserver;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@EnableDiscoveryClient
@SpringBootApplication
public class UserServiceServerApplication {
public static void main(String[] args) {
SpringApplication.run(UserServiceServerApplication.class, args);
}
}
<!--新版本的springboot不能直接在编写bootstrap.yml,需要导入这个包才可以-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bootstrap</artifactId>
</dependency>
<!--springcloud nacos分布式配置客户端-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
spring:
application:
name: userServer
cloud:
nacos:
config:
server-addr: localhost:8848
file-extension: yml
3. 编写配置文件applicaiton.yml
server:
port: 8001
spring:
application:
name: userServer
abc: application #这里是动态配置
3. 配置类开启配置动态刷新 @RefreshScope
package top.scsoul.userserviceserver.controller; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; import org.springframework.cloud.context.config.annotation.RefreshScope; import top.scsoul.common.model.dao.User; import top.scsoul.userserviceserver.service.UserService; import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; @RefreshScope @RestController @RequestMapping("/api/user") public class UserController { private static final Logger log = LoggerFactory.getLogger(UserController.class); @Value("${abc}") private String a; @RequestMapping("a") public String a() { return a; } }
删除data目录
官方文档:https://github.com/alibaba/Sentinel
Sentinel是阿里开源的项目,提供了流量控制、熔断降级、系统负载保护等多个维度来保障服务之间的稳定性。
sentinel和hystrix区别:
下载地址:https://github.com/alibaba/Sentinel/releases
java -Dserver.port=8080 -Dcsp.sentinel.dashboard.server=localhost:8080 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard-1.8.1.jar
访问:localhost:8080 登录名和密码默认都是: sentinel
<!--springcloud sentinel客户端-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
server:
port: 9001
spring:
application:
name: payServer
cloud:
sentinel:
transport:
dashboard: localhost:8080
# 若要导入了feign 需要开启feign对sentinel的支持,才可以使用feign的fallback
#feign:
# sentinel:
# enabled: true
3. 添加sentinel资源 @SentinelResource
package top.scsoul.payserviceserver.controller; import com.alibaba.csp.sentinel.annotation.SentinelResource; import io.seata.spring.annotation.GlobalTransactional; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import top.scsoul.common.model.dao.User; import top.scsoul.payserviceserver.feign.UserService; import javax.annotation.Resource; import java.math.BigDecimal; import java.util.HashMap; import java.util.Map; @RestController @RequestMapping("/api/pay") public class PayController { private static final Logger log = LoggerFactory.getLogger(PayController.class); @Resource UserService userService; @GlobalTransactional @SentinelResource(value = "test", defaultFallback = "defaultFallback") @RequestMapping("userPay") public Map<String, Object> userPay(String id, BigDecimal money) { User user = userService.selectOne(id); log.info("user:{}", user); return new HashMap<String, Object>() {{ put("status", 200); put("id", id); put("money", money); put("user", user); }}; } public Map<String, Object> defaultFallback() { return new HashMap<String, Object>() {{ put("status", 500); put("err", "太拥挤了 ~ 请稍后重试 "); }}; } }
4. 登录sentinel监控面板即可看到当前服务,在簇点链路中对相应的url可视化配置服务限流,服务降级等
注意:
- 由于sentinel是懒加载机制,微服务启动后,需要先手动调用一下接口,才会在sentinel面板显示当前微服务。或者在配置文件中关闭懒加载eager: true
- 直接在控制台配置的服务限流,服务降级等信息都是基于内存的,微服务重启后都会失效。Sentinel提供了多种持久化的方案,可以集成redis,mysql,nacos等。请参照博客https://blog.csdn.net/zhangcongyi420/article/details/109412042
官方文档:https://seata.io/zh-cn/
Seata是一款开源的分布式事务解决方案,致力于在微服务架构下提供高性能和简单易用的分布式事务服务;
Seata为用户提供了AT、TCC、SAGA和XA事务模式,为用户打造一站式的分布式解决方案;
四种事务模式中,XA模式正在开发中…,其他事务模式已经实现;
目前使用的流行度情况是:AT > TCC > Saga;
seata的1+3模式 :1个全局的xid,三个角色:
TC (Transaction Coordinator) - 事务协调者:维护全局和分支事务的状态,驱动全局事务提交或回滚;
TM (Transaction Manager) - 事务管理器:定义全局事务的范围:开始全局事务、提交或回滚全局事务;
RM (Resource Manager) - 资源管理器:管理分支事务处理的资源,与TC交互以注册分支事务和报告分支事务的状态,并驱动分支事务提交或回滚;
其中TC为单独部署的 Server 服务端,TM和RM为嵌入到应用中的 Client 客户端;
借助某某谷老师的比喻:
TC:培训讲师
TM:班主任
RM:学生
班主任TM向培训讲师TC申请开课生成唯一的课程号xid
课程号xid在每一个学生RM中传播开
每一个学生RM加入到课程号为xid的课程中,与培训讲师互动
班主任TM向培训讲师TC沟通上课情况
或者
下载地址:https://github.com/seata/seata/releases
进入seata/conf目录
主要关注以下两个配置文件
这里以配置单机seata服务为例:
打开registry.conf,找到registry下的type,将其改为nacos,并配置nacos的基本信息
registry { # file 、nacos 、eureka、redis、zk、consul、etcd3、sofa type = "nacos" nacos { application = "seata-server" serverAddr = "127.0.0.1:8848" group = "SEATA_GROUP" namespace = "public" cluster = "default" username = "nacos" password = "nacos" } eureka { serviceUrl = "http://localhost:8761/eureka" application = "default" weight = "1" } redis { serverAddr = "localhost:6379" db = 0 password = "" cluster = "default" timeout = 0 } zk { cluster = "default" serverAddr = "127.0.0.1:2181" sessionTimeout = 6000 connectTimeout = 2000 username = "" password = "" } consul { cluster = "default" serverAddr = "127.0.0.1:8500" } etcd3 { cluster = "default" serverAddr = "http://localhost:2379" } sofa { serverAddr = "127.0.0.1:9603" application = "default" region = "DEFAULT_ZONE" datacenter = "DefaultDataCenter" cluster = "default" group = "SEATA_GROUP" addressWaitTime = "3000" } file { name = "file.conf" } } config { # file、nacos 、apollo、zk、consul、etcd3 type = "file" nacos { serverAddr = "127.0.0.1:8848" namespace = "public" group = "SEATA_GROUP" username = "nacos" password = "nacos" dataId = "seataServer.properties" } consul { serverAddr = "127.0.0.1:8500" } apollo { appId = "seata-server" apolloMeta = "http://192.168.1.204:8801" namespace = "application" } zk { serverAddr = "127.0.0.1:2181" sessionTimeout = 6000 connectTimeout = 2000 username = "" password = "" } etcd3 { serverAddr = "http://localhost:2379" } file { name = "file.conf" } }
由于我们在register.conf的config下的type为file,即采用文件形式的配置。
打开file.conf文件,在下方添加:
service {
#transaction service group mapping
vgroupMapping.my_test_tx_group = "default"
#only support when registry.type=file, please don't set multiple addresses
default.grouplist = "127.0.0.1:8091"
#degrade, current not support
enableDegrade = false
#disable seata
disableGlobalTransaction = false
}
sh seata-server.sh -p 8091 -h 127.0.0.1 -m file
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-seata</artifactId>
</dependency>
编写配置文件application.yml
注意:tx-service-group 必须要与在file.conf中配置的vgroupMapping一致
server: port: 9001 spring: application: name: payServer cloud: alibaba: seata: tx-service-group: my_test_tx_group seata: application-id: ${spring.application.name} tx-service-group: my_test_tx_group # 配置事物组 registry: # 注册中心为nacos type: nacos nacos: server-addr: 127.0.0.1:8848 username: nacos password: nacos namespace: public group: SEATA_GROUP
3. 在需要控制分布式事务的方法上添加 @GlobalTransactional
4. 在每一个分布式数据库添加undo_log表
-- for AT mode you must to init this sql for you business database. the seata server not need it.
CREATE TABLE IF NOT EXISTS `undo_log`
(
`branch_id` BIGINT(20) NOT NULL COMMENT 'branch transaction id',
`xid` VARCHAR(100) NOT NULL COMMENT 'global transaction id',
`context` VARCHAR(128) NOT NULL COMMENT 'undo_log context,such as serialization',
`rollback_info` LONGBLOB NOT NULL COMMENT 'rollback info',
`log_status` INT(11) NOT NULL COMMENT '0:normal status,1:defense status',
`log_created` DATETIME(6) NOT NULL COMMENT 'create datetime',
`log_modified` DATETIME(6) NOT NULL COMMENT 'modify datetime',
UNIQUE KEY `ux_undo_log` (`xid`, `branch_id`)
) ENGINE = InnoDB
AUTO_INCREMENT = 1
DEFAULT CHARSET = utf8 COMMENT ='AT transaction mode undo table';
启动服务后,稍等片刻控制台会打印TM、RM的注册日志
调用接口控制台有事物执行的日志打印。
SpringCloud Gateway需要自己搭建服务器,在项目搭建中有代码示例
官方网站:https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/
Spring Cloud Gateway 是 Spring Cloud 新推出的网关框架,之前是 Netflix Zuul。网关通常在项目中为了简化
前端的调用逻辑,同时也简化内部服务之间互相调用的复杂度;具体作用就是转发服务,接收并转发所有内外
部的客户端调用;其他常见的功能还有权限认证,限流控制等等。
Zuul 对比 Gateway:
Zuul1是Netflix在2013年开源的网关组件,大规模的应用在Netflix的生产环境中,经受了实践考验。它可以与Eureka、Ribbon、Hystrix等组件配合使用,实现路由转发、负载均衡、熔断等功能。Zuul1的核心是一系列过滤器,过滤器简单易于扩展,已经有一些三方库如spring-cloud-zuul-ratelimit
等提供了过滤器支持。
Zuul1基于Servlet构建,使用的是阻塞的IO,引入了线程池来处理请求。每个请求都需要独立的线程来处理,从线程池中取出一个工作线程执行,下游微服务返回响应之前这个工作线程一直是阻塞的。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hJFevuDe-1654054026792)(https://bbsmax.ikafan.com/static/L3Byb3h5L2h0dHBzL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20veWl6aGlzaGkveWl6aGlzaGkuZ2l0aHViLmlvL21hc3Rlci9pbWFnZXMvenV1bDEtbXVsdGl0aHJlYWRlZC1zeXN0ZW0tYXJjaGl0ZWN0dXJlLnBuZw==.jpg)]
Spring Cloud Gateway 是Spring Cloud的一个全新的API网关项目,目的是为了替换掉Zuul1。Gateway可以与Spring Cloud Discovery Client(如Eureka)、Ribbon、Hystrix等组件配合使用,实现路由转发、负载均衡、熔断等功能,并且Gateway还内置了限流过滤器,实现了限流的功能。
Gateway基于Spring 5、Spring boot 2和Reactor构建,使用Netty作为运行时环境,比较完美的支持异步非阻塞编程。Netty使用非阻塞的IO,线程处理模型建立在主从Reactors多线程模型上。其中Boss Group轮询到新连接后与Client建立连接,生成NioSocketChannel,将channel绑定到Worker;Worker Group轮询并处理Read、Write事件。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jhkSQlAA-1654054026793)(https://bbsmax.ikafan.com/static/L3Byb3h5L2h0dHBzL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20veWl6aGlzaGkveWl6aGlzaGkuZ2l0aHViLmlvL21hc3Rlci9pbWFnZXMvbmV0dHktc2ltcGxlLXRocmVhZC1tb2RlbC5wbmc=.jpg)]
对比项 | Zuul1.x | Gateway |
---|---|---|
实现 | 基于Servlet2.x构建,使用阻塞的API。 | 基于Spring 5、Project Reactor、Spring Boot 2,使用非阻塞式的API。 |
长连接 | 不支持 | 支持 |
不适用场景 | 后端服务响应慢或者高并发场景下,因为线程数量是固定(有限)的,线程容易被耗尽,导致新请求被拒绝。 | 中小流量的项目,使用Zuul1.x更合适。 |
限流 | 无 | 内置限流过滤器 |
上手难度 | 同步编程,上手简单 | 门槛较高,上手难度中等 |
技术栈沉淀 | Zuul1开源近9年,经受考验,稳定成熟。 | / |
Zipkin是 Twitter 的一个开源项目,基于 Google Dapper实现。可以使用它来收集各个服务器上请求链路的跟踪数据,并通过它提供的 REST API 接口来辅助我们查询跟踪数据以实现对分布式系统的监控程序,从而及时地发现系统中出现的延迟升高问题并找出系统性能瓶颈的根源。除了面向开发的API接口之外,它也提供了方便的 UI 组件帮助我们直观的搜索跟踪信息和分析请求链路明细,比如:可以查询某段时间内各用户请求的处理时间等。
上图展示了Zipkin的基础架构,主要由4个核心组件构成:
Collector:收集器组件,它主要用于处理从外部系统发送过来的跟踪信息,将这些信息转换为Zipkin内部处理的Span格式,以支持后续的存储、分析、展示等功能。
Storage:存储组件,它主要对处理收集器接收到的跟踪信息,默认会将这些信息存储在内存中,我们也可以修改此存储策略,通过使用其他存储组件将跟踪信息存储到 数据库或es 中。
RESTful API:API组件,它主要用来提供外部访问接口。比如给客户端展示跟踪信息,或是外接系统访问以实现监控等。
Web UI:UI组件,基于API组件实现的上层应用。通过UI组件用户可以方便而有直观地查询和分析跟踪信息。
zipkin相关概念
Trace、Span、annotations注释
https://zipkin.io/pages/quickstart.html
java -jar zipkin-server-2.23.16-exec.jar
创建zipkin数据库,导入sql文件:
-- -- Copyright 2015-2019 The OpenZipkin Authors -- -- Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except -- in compliance with the License. You may obtain a copy of the License at -- -- http://www.apache.org/licenses/LICENSE-2.0 -- -- Unless required by applicable law or agreed to in writing, software distributed under the License -- is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express -- or implied. See the License for the specific language governing permissions and limitations under -- the License. -- CREATE TABLE IF NOT EXISTS zipkin_spans ( `trace_id_high` BIGINT NOT NULL DEFAULT 0 COMMENT 'If non zero, this means the trace uses 128 bit traceIds instead of 64 bit', `trace_id` BIGINT NOT NULL, `id` BIGINT NOT NULL, `name` VARCHAR(255) NOT NULL, `remote_service_name` VARCHAR(255), `parent_id` BIGINT, `debug` BIT(1), `start_ts` BIGINT COMMENT 'Span.timestamp(): epoch micros used for endTs query and to implement TTL', `duration` BIGINT COMMENT 'Span.duration(): micros used for minDuration and maxDuration query', PRIMARY KEY (`trace_id_high`, `trace_id`, `id`) ) ENGINE=InnoDB ROW_FORMAT=COMPRESSED CHARACTER SET=utf8 COLLATE utf8_general_ci; ALTER TABLE zipkin_spans ADD INDEX(`trace_id_high`, `trace_id`) COMMENT 'for getTracesByIds'; ALTER TABLE zipkin_spans ADD INDEX(`name`) COMMENT 'for getTraces and getSpanNames'; ALTER TABLE zipkin_spans ADD INDEX(`remote_service_name`) COMMENT 'for getTraces and getRemoteServiceNames'; ALTER TABLE zipkin_spans ADD INDEX(`start_ts`) COMMENT 'for getTraces ordering and range'; CREATE TABLE IF NOT EXISTS zipkin_annotations ( `trace_id_high` BIGINT NOT NULL DEFAULT 0 COMMENT 'If non zero, this means the trace uses 128 bit traceIds instead of 64 bit', `trace_id` BIGINT NOT NULL COMMENT 'coincides with zipkin_spans.trace_id', `span_id` BIGINT NOT NULL COMMENT 'coincides with zipkin_spans.id', `a_key` VARCHAR(255) NOT NULL COMMENT 'BinaryAnnotation.key or Annotation.value if type == -1', `a_value` BLOB COMMENT 'BinaryAnnotation.value(), which must be smaller than 64KB', `a_type` INT NOT NULL COMMENT 'BinaryAnnotation.type() or -1 if Annotation', `a_timestamp` BIGINT COMMENT 'Used to implement TTL; Annotation.timestamp or zipkin_spans.timestamp', `endpoint_ipv4` INT COMMENT 'Null when Binary/Annotation.endpoint is null', `endpoint_ipv6` BINARY(16) COMMENT 'Null when Binary/Annotation.endpoint is null, or no IPv6 address', `endpoint_port` SMALLINT COMMENT 'Null when Binary/Annotation.endpoint is null', `endpoint_service_name` VARCHAR(255) COMMENT 'Null when Binary/Annotation.endpoint is null' ) ENGINE=InnoDB ROW_FORMAT=COMPRESSED CHARACTER SET=utf8 COLLATE utf8_general_ci; ALTER TABLE zipkin_annotations ADD UNIQUE KEY(`trace_id_high`, `trace_id`, `span_id`, `a_key`, `a_timestamp`) COMMENT 'Ignore insert on duplicate'; ALTER TABLE zipkin_annotations ADD INDEX(`trace_id_high`, `trace_id`, `span_id`) COMMENT 'for joining with zipkin_spans'; ALTER TABLE zipkin_annotations ADD INDEX(`trace_id_high`, `trace_id`) COMMENT 'for getTraces/ByIds'; ALTER TABLE zipkin_annotations ADD INDEX(`endpoint_service_name`) COMMENT 'for getTraces and getServiceNames'; ALTER TABLE zipkin_annotations ADD INDEX(`a_type`) COMMENT 'for getTraces and autocomplete values'; ALTER TABLE zipkin_annotations ADD INDEX(`a_key`) COMMENT 'for getTraces and autocomplete values'; ALTER TABLE zipkin_annotations ADD INDEX(`trace_id`, `span_id`, `a_key`) COMMENT 'for dependencies job'; CREATE TABLE IF NOT EXISTS zipkin_dependencies ( `day` DATE NOT NULL, `parent` VARCHAR(255) NOT NULL, `child` VARCHAR(255) NOT NULL, `call_count` BIGINT, `error_count` BIGINT, PRIMARY KEY (`day`, `parent`, `child`) ) ENGINE=InnoDB ROW_FORMAT=COMPRESSED CHARACTER SET=utf8 COLLATE utf8_general_ci;
java -jar zipkin-server-2.23.16-exec.jar --STORAGE_TYPE=mysql --MYSQL_HOST=localhost --MYSQL_TCP_PORT=3306 --MYSQL_DB=zipkin --MYSQL_USER=root --MYSQL_PASS=123456
<!--链路追踪 zipkin依赖,其中包含Sleuth的依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zipkin</artifactId>
<version>2.2.8.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-sleuth-zipkin</artifactId>
<version>3.1.1</version>
</dependency>
spring:
sleuth:
sampler:
probability: 1.0
zipkin:
base-url: http://127.0.0.1:9411
discovery-client-enabled: false
sender:
type: web
日志格式化:
[traceId: %X{traceId:-},spanId: %X{spanId:-}]
请确保你的电脑上已经成功开启了nacos,sentinel,seata服务
pom.xml
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>top.scsoul</groupId> <artifactId>cloud</artifactId> <version>1.0-SNAPSHOT</version> <packaging>pom</packaging> <modules> <module>userServiceServer</module> <module>payServiceServer</module> <module>common</module> <module>gateway</module> </modules> <properties> <maven.compiler.source>8</maven.compiler.source> <maven.compiler.target>8</maven.compiler.target> <spring-boot.version>2.6.3</spring-boot.version> <spring-cloud.version>2021.0.0</spring-cloud.version> <spring-cloud-alibaba.version>2021.1</spring-cloud-alibaba.version> </properties> <!-- 依赖声明 --> <dependencyManagement> <dependencies> <!-- SpringCloud 微服务 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> <!-- SpringBoot 依赖配置 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>${spring-boot.version}</version> <type>pom</type> <scope>import</scope> </dependency> <!--springCloudAlibaba--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-alibaba-dependencies</artifactId> <version>${spring-cloud-alibaba.version}</version> <type>pom</type> <scope>import</scope> </dependency> <!--mybatis--> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.2.0</version> </dependency> <dependency> <groupId>top.scsoul</groupId> <artifactId>common</artifactId> <version>1.0-SNAPSHOT</version> </dependency> </dependencies> </dependencyManagement> </project>
pom.xml
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>cloud</artifactId> <groupId>top.scsoul</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>userServiceServer</artifactId> <properties> <maven.compiler.source>8</maven.compiler.source> <maven.compiler.target>8</maven.compiler.target> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-bootstrap</artifactId> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> </dependency> <dependency> <groupId>top.scsoul</groupId> <artifactId>common</artifactId> </dependency> </dependencies> </project>
bootstrap.yml
spring:
application:
name: userServer
cloud:
nacos:
discovery:
server-addr: localhost:8848 #服务注册中心地址
config:
server-addr: localhost:8848 #服务配置中心地址
file-extension: yml #配置中心配置文件格式
application.yml
server: port: 8001 spring: application: name: userServer datasource: url: jdbc:mysql://127.0.0.1:3306/cloud?useSSL=false&serverTimezone=Asia/Shanghai&characterEncoding=utf8&allowPublicKeyRetrieval=true&allowMultiQueries=true #数据库链接 driver-class-name: com.mysql.cj.jdbc.Driver #数据库驱动 username: root #数据库账号 password: 123456 #数据库密码 mybatis: mapper-locations: classpath*:/mapper/**/*.xml #myabtis mapper文件位置 configuration: map-underscore-to-camel-case: true #下划线—>小驼峰 log-impl: org.apache.ibatis.logging.stdout.StdOutImpl abc: application
配置@EnableDiscoveryClient
package top.scsoul.userserviceserver;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@EnableDiscoveryClient//开启服务发现
@SpringBootApplication
public class UserServiceServerApplication {
public static void main(String[] args) {
SpringApplication.run(UserServiceServerApplication.class, args);
}
}
这里省略userService调用数据库的代码
package top.scsoul.userserviceserver.controller; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; import org.springframework.cloud.context.config.annotation.RefreshScope; import top.scsoul.common.model.dao.User; import top.scsoul.userserviceserver.service.UserService; import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; /** * (User)表控制层 * * @author makejava * @since 2022-02-17 09:45:05 */ @RefreshScope//配置动态刷新 @RestController @RequestMapping("/api/user") public class UserController { private static final Logger log = LoggerFactory.getLogger(UserController.class); /** * 服务对象 */ @Resource private UserService userService; /** * 通过主键查询单条数据 * * @param id 主键 * @return 单条数据 */ @RequestMapping("selectOne") public User selectOne(Integer id, HttpServletRequest request) { log.info("port:{}", request.getServerPort()); // int i = 1 / 0; return this.userService.queryById(id); } @Value("${abc}") private String a; //测试配置中心的修改 @RequestMapping("a") public String a() { return a; } }
打开nacos控制台:localhost:8848/nacos 登录查看服务列表中是否包含userServer,如果服务存在就说明服务注册成功。
打开nacos控制台:localhost:8848/nacos 登录添加配置文件,dataId为:userServer.yml内容为:
abc: nacos
访问localhost:8001/api/user/a
若返回nacos则说明获取配置中心的配置动态刷新成功!且服务控制台会打印相应的日志。
dataId 不能随意乱填写,其规范应该为 a p p l i c a i t o n N a m e − {applicaitonName}- applicaitonName−{profiles.active}.${file-extension}
并且需要在微服务的bootstrap.yml中指定服务名称,当前启用的配置文件,配置文件文件后缀名
例如:
spring:
application:
name: userServer
cloud:
nacos:
discovery:
server-addr: localhost:8848
config:
server-addr: localhost:8848
file-extension: yml
此时没有指定环境,则会从配置中心拉取userServer.yml配置文件。
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>cloud</artifactId> <groupId>top.scsoul</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>payServiceServer</artifactId> <properties> <maven.compiler.source>8</maven.compiler.source> <maven.compiler.target>8</maven.compiler.target> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-bootstrap</artifactId> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> </dependency> <!--openfeign--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-loadbalancer</artifactId> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId> </dependency> <!-- seata--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-seata</artifactId> </dependency> <dependency> <groupId>top.scsoul</groupId> <artifactId>common</artifactId> </dependency> </dependencies> </project>
bootstrap.yml
spring:
application:
name: payServer
cloud:
nacos:
discovery:
server-addr: localhost:8848 #服务注册中心地址
config:
server-addr: localhost:8848 #配置中心地址
file-extension: yml #配置中心文件格式
application.yml
server: port: 9001 spring: application: name: payServer cloud: sentinel: transport: dashboard: localhost:8080 # sentinel 监控地址 alibaba: seata: tx-service-group: my_test_tx_group #seata事务组 main: allow-circular-references: true allow-bean-definition-overriding: true seata: application-id: ${spring.application.name} tx-service-group: my_test_tx_group registry: type: nacos nacos: server-addr: 127.0.0.1:8848 username: nacos password: nacos namespace: public group: SEATA_GROUP feign: sentinel: enabled: true #开启对sentinel的支持
@EnableFeignClients
@EnableDiscoveryClient
package top.scsoul.payserviceserver; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.client.loadbalancer.LoadBalanced; import org.springframework.cloud.context.config.annotation.RefreshScope; import org.springframework.cloud.openfeign.EnableFeignClients; import org.springframework.context.annotation.Bean; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.client.RestTemplate; @RefreshScope @EnableFeignClients @EnableDiscoveryClient @RestController @SpringBootApplication public class PayServiceServerApplication { @RequestMapping("/") public String home() { return "PayServiceServerApplication"; } @Bean @LoadBalanced public RestTemplate getRestTemplate() { return new RestTemplate(); } public static void main(String[] args) { SpringApplication.run(PayServiceServerApplication.class, args); } }
package top.scsoul.payserviceserver.feign;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import top.scsoul.common.model.dao.User;
@FeignClient(value = "userServer", fallback = UserServiceFallback.class)
public interface UserService {
@GetMapping("/api/user/selectOne")
public User selectOne(@RequestParam(name = "id") String id);
}
package top.scsoul.payserviceserver.feign;
import org.springframework.stereotype.Component;
import top.scsoul.common.model.dao.User;
@Component
public class UserServiceFallback implements UserService {
@Override
public User selectOne(String id) {
User user = new User();
System.out.println("服务熔断");
return user;
}
}
package top.scsoul.payserviceserver.controller; import com.alibaba.csp.sentinel.annotation.SentinelResource; import io.seata.spring.annotation.GlobalTransactional; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import top.scsoul.common.model.dao.User; import top.scsoul.payserviceserver.feign.UserService; import javax.annotation.Resource; import java.math.BigDecimal; import java.util.HashMap; import java.util.Map; @RestController @RequestMapping("/api/pay") public class PayController { private static final Logger log = LoggerFactory.getLogger(PayController.class); @Resource UserService userService; @GlobalTransactional @SentinelResource(value = "test", defaultFallback = "defaultFallback") @RequestMapping("userPay") public Map<String, Object> userPay(String id, BigDecimal money) { User user = userService.selectOne(id); log.info("user:{}", user); return new HashMap<String, Object>() {{ put("status", 200); put("id", id); put("money", money); put("user", user); }}; } public Map<String, Object> defaultFallback() { return new HashMap<String, Object>() {{ put("status", 500); put("err", "太拥挤了 ~ 请稍后重试 "); }}; } }
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>cloud</artifactId> <groupId>top.scsoul</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>gateway</artifactId> <properties> <maven.compiler.source>8</maven.compiler.source> <maven.compiler.target>8</maven.compiler.target> </properties> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-gateway</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-bootstrap</artifactId> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-loadbalancer</artifactId> </dependency> </dependencies> </project>
bootsrap.yml
spring:
application:
name: gateway
cloud:
nacos:
discovery:
server-addr: localhost:8848
config:
server-addr: localhost:8848
file-extension: yaml
applicaiton.yml
server: port: 80 spring: application: name: gateway cloud: gateway: routes: - id: payServer uri: lb://payServer #lb代表轮询调用payServer predicates: - Path=/p/** # 拦截p开头的请求转发到payServer filters: - StripPrefix=1 # 过滤规则 discovery: locator: enabled: false #是否直接使用应用名称调用服务
package top.scsoul.gateway;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@EnableDiscoveryClient
@SpringBootApplication
public class GateWayapplication {
public static void main(String[] args) {
SpringApplication.run(GateWayapplication.class, args);
}
}
此时就可以通过网关转发请求了!
例如访问 localhost/p/api/pay/userPay?id=1,将会被转发到payServer服务下,localhost:9001/api/pay/userPay?id=1或者是通过负载均衡到其他的payServer集群服务。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。