SpringCloud和SpringCloudAlibaba
说在前面,SpringCloud还没有完全熟悉呢,这突然又出现了一个SpringCloudAlibaba,技术更新的太快,而学习又太慢,这真是发自内心的感慨,怪不得程序员掉头发呢。最开始比较的是SpringCloud和Dubbo各自的优缺点,这俩个都不是一个量级上的为什么要比较呢,SpringCloud是分布式的一站式解决方案,而Dubbo呢,是远程通讯框架,RPC框架,这个比较啥吗?现在由于SpringCloud的分布式解决方案中Netflix提供的一系列组件不在维护了,所以Alibaba提供了一系列的替代品,所以说现在比较也是比较SpringCloud-Netflix和SpringCloudAlibaba
功能 | SpringCloud-Netflix | SpringCloudAlibaba |
---|---|---|
服务治理 | Eurka | Nacos |
服务熔断 | Hystrix | Resilience4j |
负载均衡 | Ribbon | SpringCloudLoadbalancer |
路由网关 | Zuul | SpringCloudGateway |
搭建微服务项目关注的是什么
- 服务注册与发现,也就是服务管理
- 模块之间如何通讯
- API网关即服务路由
- 服务熔断和降级
服务注册与发现/Nacos
docker 搭建Nacos
docker run --env MODE=standalone --name nacos -d -p 8840:8848 nacos/nacos-server
图形化界面
地址:http://宿主机IP地址:8840/nacos/index.html
创建分布式项目
- 父类pom 要注意的解决的问题,这里比较坑
- SpringCloudAlibaba官网对应了SpringBoot的版本,在根据SpringBoot 对应SpringCloud版本
- SpringCloud 版本 Greenwich.SR3
- SpringCloudAlibaba 版本 2.1.0.RELEASE
- SpringBoot 版本 2.1.9.RELEASE
<?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>spring-cloud-alibaba-demo</groupId>
<artifactId>mall</artifactId>
<packaging>pom</packaging>
<version>1.0-SNAPSHOT</version>
<modules>
<module>provider</module>
<module>consumer</module>
</modules>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.9.RELEASE</version>
</parent>
<properties>
<!-- Environment Settings -->
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<!-- Spring Settings -->
<spring-cloud-alibaba.version>2.1.0.RELEASE</spring-cloud-alibaba.version>
<spring.cloud.version>Greenwich.SR3</spring.cloud.version>
</properties>
<dependencyManagement>
<dependencies>
<!--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>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring.cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
</project>
创建服务提供者
pom依赖
<?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>mall</artifactId>
<groupId>spring-cloud-alibaba-demo</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>provider</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
application.yml 配置文件配置
server:
port: 9001
# 服务注册到nacos
spring:
application:
name: provider
cloud:
nacos:
discovery:
server-addr: nacosIP:8840
#服务监控
management:
endpoints:
web:
exposure:
include: '*'
@SpringBootApplication
@EnableDiscoveryClient
public class Provider {
public static void main(String[] args) {
SpringApplication.run(Provider.class, args);
}
@RestController
public class EchoController {
@GetMapping(value = "/echo/{string}")
public String echo(@PathVariable String string) {
return "Hello Nacos Discovery " + string;
}
}
}
启动一下服务,在访问一下nacos 我们已经发现服务提供者了
服务消费者
以上这句话摘抄自spring.io官方网站:我大概翻译一下,不像服务提供者那么容易,因为服务消费者需要调用RESTful 服务,在这个例子中,我们通过最原始的方式,结合LoadBalanceClient和RestTemolate明确的指定调用那个服务,你可以按照1.2章的pom文件和application配置文件,下面就是具体例子的代码。
application.yml配置文件修改服务名称以及端口号即可
@SpringBootApplication
@EnableDiscoveryClient
public class Consumer {
public static void main(String[] args) {
SpringApplication.run(Consumer.class, args);
}
//Instantiate RestTemplate Instance
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
@RestController
public class NacosController {
@Autowired
private LoadBalancerClient loadBalancerClient;
@Autowired
private RestTemplate restTemplate;
@Value("${spring.application.name}")
private String appName;
@GetMapping("/echo/app-name")
public String echoAppName(){
//Access through the combination of LoadBalanceClient and RestTemplate
ServiceInstance serviceInstance = loadBalancerClient.choose("provider");
String path = String.format("http://%s:%s/echo/%s",serviceInstance.getHost(),serviceInstance.getPort(),appName);
System.out.println("request path:" +path);
return restTemplate.getForObject(path,String.class);
}
}
直接访问 服务提供者 http://localhost:9001/echo/test
直接访问 服务消费者 http://localhost:9002/echo/app-name
ok,至此一次基础的服务调用已经完成了,相信这种硬编码的形式不能被接受,也不够智能,继续探索。
基于openFeign调用远程服务
第一步
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
第二步
@EnableFeignClients
第三步
@FeignClient(value = "provider-config", name = "provider-config" )
public interface ConsumerService {
@GetMapping("/echo/{applicationName}")
String echo(@PathVariable("applicationName") String applicationName);
}
基于Sentinel实现服务熔断
什么是服务熔断:服务熔断的作用类似于我们家用的保险丝,当某服务出现不可用或响应超时的情况时,为了防止整个系统出现雪崩,暂时停止对该服务的调用
什么是服务降级:服务降级是当服务器压力剧增的情况下,根据当前业务情况及流量对一些服务和页面有策略的降级,以此释放服务器资源以保证核心任务的正常运行
什么是服务限流:有限时间内指定流量限制
Sentinel服务熔断实现
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
实现你要熔断的接口,就是有@FeignClient的接口
@Component
public class ConsumerServiceFallback implements ConsumerService {
@Override
public String echo(@PathVariable("applicationName") String applicationName) {
return "您请求的服务已经不工作了";
}
}
修改一下接口,指定调用不通后的返回值
@FeignClient(value = "provider-config", name = "provider-config",
fallback = ConsumerServiceFallback.class)
public interface ConsumerService {
@GetMapping("/echo/{applicationName}")
String echo(@PathVariable("applicationName") String applicationName);
}
Docker安装Sentinel图形化界面
docker pull bladex/sentinel-dashboard
docker run --name sentinel -id -p 8858:8858 bladex/sentinel-dashboard
Sentinel可以通过图形化界面控制,服务降级规则,以及服务流量控制
应用中配置Sentinel-dashBoard
spring:
cloud:
sentinel:
transport:
port: 8001
dashboard: dashboadIp:8858
基于Nacos的服务配置
Tips:以前SpringCloudConfig是基于github的形式配置的,如果基于SpringCloudAlibaba的可以直接基于Nacos,也就是说Nacos即使服务注册发现中心,也是可以是配置文件中心
在服务提供者和服务消费者pom中均加入一下依赖
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
修改application.yml为bootstrap.yml 原因就是加载顺序的问题
bootstrap.properties->bootstrap.yml->
application.properties->application.yml
nacos上的配置的配置文件Data Id要和bootstrap配置文件中的applicaiton-name一样
spring官网上说,nacos 也支持Yaml格式,只需要2步,第一步在配置文件中指定文件的扩展格式,第二个就是dataID 要和服务名称一样,注意带有后缀的。
bootstrap.yml如下
spring:
application:
name: provider-config
cloud:
nacos:
config:
server-addr: nacosip:8840
file-extension: yaml
牛逼的地方来了,支持动态刷新,spring-cloud-config需要通过spring-cloud-bus来刷新,现在不需要了,这个地方必须点赞
**支持多环境配置 **
基于SpringCloudGateWay实现路由网关
官网上说,第一 GateWay 是基于SpringBoot2.x和Spring WebFlux开发的,导致很多模块不能使用了,比如Spring Data 和 Spring Security,当然这里包括不需要引入web-starter 模块,所以pom文件中不要引入
第二点,GateWay不能运行在传统的Servlet容器中同时也不能构建成一个war包。
新建一个GateWay maven 子模块
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
server:
port: 9003
spring:
application:
name: spring-cloud-gateway
cloud:
nacos:
discovery:
server-addr: nacosip:8840
gateway:
routes:
- id: consumer-config
uri: lb://consumer-config
predicates:
- Method=GET,POST,PUT,DELETE
discovery:
locator:
enabled: true
management:
endpoints:
web:
exposure:
include: '*'
简单的路由配置可以了。
discover.locator.enabled=true
网关可以通过设置与注册中心的路由规则匹配,也就是开启这个注解。
Websockets may be load-balanced by prefixing the URI with lb, such as lb:ws://serviceid.
路由规则中,lb即为负载均衡的意思
GateWay 最重点的在于各种 predicates 和filter。可以配合官网看一下。
Sky walking 链路追踪
skywalking 官方文档中的docker-compose.yml中的镜像仓库是基于自己的私服的,所以要略作修改
version: '3.3'
services:
elasticsearch:
image: elasticsearch:6.8.0
container_name: skywalking-es
restart: always
ports:
- 9200:9200
- 9300:9300
environment:
discovery.type: single-node
TZ: Asia/Shanghai
oap:
image: apache/skywalking-oap-server:6.1.0
container_name: skywalking-oap
depends_on:
- elasticsearch
links:
- elasticsearch
restart: always
#前边为外网端口号,后边为容器应用端口号
ports:
- 11800:11800
- 12800:12800
environment:
# 设置时区
TZ: Asia/Shanghai
# volumes:
# - /home/skywalking/apache-skywalking-apm-bin/config/application.yml
# - ./config:/skywalking/config:ro
ui:
image: apache/skywalking-ui:6.1.0
container_name: skywalking-ui
depends_on:
- oap
links:
- oap
restart: always
ports:
- 18080:8080
#设置环境,配置覆盖yml的配置
environment:
collector.ribbon.listOfServers: oap:12800
security.user.admin.password: adminsou888!
由于我原来有ES,所以我是逐个构建的
docker run -id --name skywalking-oap --link es -p 11800:11800 -p 12800:12800 apache/skywalking-oap-server:6.1.0
docker run -id --name skywalking-ui -p 18080:8080 --link skywalking-oap -e collector.ribbon.listOfServers=skywalking-oap:12800 -e security.user.admin.password=admin apache/skywalking-ui:6.1.0
探针-agent 下载地址:https://archive.apache.org/dist/skywalking/
最后需要在idea中添加启动参数,skywalking-oapIP 换成你自己的skywalking-ip地址
-javaagent:/Users/wangjian/IdeaProjects/mall/skywalking-agent/agent/skywalking-agent.jar
-Dskywalking.agent.service_name=provider-config
-Dskywalking.collector.backend_service=skywalking-oapIP:11800
ok,到此为止,SpringCloudAlibaba的基础使用基础已经完成了,还有很多需要完善的地方。需要结合实战经验,以及具体项目来落实。
如:sentinel 设置限流规则以及测试
gateway 各种路由规则,各种过滤器如何使用,权限设计等等。
总体来说使用起来比较方便,当然排除刚开搭建的时候遇到的坑。
如果按照我这个步骤有搭建失败的欢迎交流。