乱搭springcloud微服务demo!
首先,微服务不是一个具体的框架,它更应该理解为一个提升复杂多服务系统性能或扩展性的解决方案。但是,并不是所有项目都适合微服务的架构,一般来说,用nginx做服务端的负载均衡,已经可以满足大部分场景。而微服务,把复杂业务抽象成一个个单一职责的服务,达到系统解耦的目的,易维护易升级,由于服务间并不直接相连,因此某一服务失效也不会导致整个系统崩溃。然而,在运维层面上看,治理的难度和成本也会随之大幅度提升。
虽然,这种关乎到系统发展和公司愿景的架构选型都由大佬规划。但是,多了解一点总没错。以下学习macro大神的项目,结合自己的浅显理解,搭建一个demo练手。
附现有的微服务主流解决方案:
本文先以目前大众的Spring Cloud Netflix和官方提供的组件搭建微服务基础项目,下次将会把此项目的一些组件更换为现在很火的Spring Cloud Alibaba解决方案。
那么,开始乱搭之旅。
0.创建多模块项目
0-1.创建一个父工程
新项目创建过程不细说。创建完删除src目录,也可以直接创建maven空项目。
0-2.修改父工程pom文件
主要是添加modules
1 | <modules> |
1.以Eureka作为注册中心
1-1.新建module
勾选Eureka服务:
修改子工程pom文件:
1 | <?xml version="1.0" encoding="UTF-8"?> |
父工程的modules加上:
1 | <module>cloud-eureka</module> |
此时整个工程的目录:
后续所有模块都以这种方式创建,不再细说。
1-2.启动注册中心
启动方法添加@EnableEurekaServer:
1 | //启用Euerka注册中心功能 |
配置必要信息:
1 | server: |
启动,访问8001端口:
1-3.新建客户端
新建module,cloud-eureka-client:
启动方法添加@EnableDiscoveryClient:
1 | //作为Eureka客户端 |
配置文件:
1 | server: |
启动并刷新注册中心:
发现eureka-client已注册上。
实际上注册中心有可能会做集群,客户端可以同时注册到多个注册中心。
1-5.加上安全认证
注册中心添加依赖:
1 | <dependency> |
配置文件新增security用户名密码:
1 | spring: |
新增配合类WebSecurityConfig关闭csrf:
1 |
|
重新启动即可生效认证功能:
同时,客户端配置文件中的注册中心路径也要修改:
1 | defaultZone: http://root:123456@localhost:8001/eureka/ #配置注册中心地址 |
1-6.其他常用配置
1 | eureka: |
2.使用OpenFeign声明式服务调用
2-1.关于Ribbon和Hystrix
在使用OpenFeign前,先阐述一下两个组件:
- Ribbon负载均衡
RestTemplate大家都用过,它相当于一个HTTP客户端,对于后端开发,可以使用它来请求其他项目的服务。那么,当同一个服务做了集群,为了提高系统的可用性,负载均衡就成为一个必须考虑的问题。而Ribbon可以很好地实现负载均衡。
如何使用?
只需创建一个配置类:
1 |
|
这样,一个@LoadBalanced就自动赋予RestTemplate负载均衡的功能,剩下的,还是一样的使用方法,例如请求:
1 | "/say") ( |
- Hystrix熔断器
若服务服务由于某些原因长时间不能返回响应,随着请求数的增加,服务器的性能会被损耗很大甚至导致崩溃。那么,当出现这种情况,需要在一定时间内返回错误响应而不是长时间等待以保护服务器。Hystrix提供了服务降级、服务熔断、线程隔离、请求缓存、请求合并及服务监控等强大功能。
服务降级示例:
1 | // 服务调用方 |
当远程服务长时间(配置指定)得不到响应时,自动调用fallbackMethod的本地指定方法,返回默认值,也可以是一个错误消息。
2-2.准备工作
OpenFeign集成了以上两种功能。
新建两个module作为feign服务:
记得修改pom文件和配置文件。新建完启动去注册中心检验有没有注册到。
2-3.开始使用OpenFeign
创建完项目,现在增加业务代码测试,在cloud-feign-business1-server下:
新增User
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15public class User {
private int id;
private String name;
private String sex;
private int age;
public User(int id, String name, String sex, int age) {
this.id = id;
this.name = name;
this.sex = sex;
this.age = age;
}
...getset省略
}新增UserService,UserSerciceImpl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19public interface UserService {
User create();
User getById(int id);
}
public class UserServiceImpl implements UserService{
public User create() {
return new User(1,"xiaoming", "男", 10);
}
public User getById(int id) {
return new User(id,"xiaoming", "男", 10);
}
}新增UserController
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
"/user") (
public class UserController {
private UserService userService;
"/create") (
public User create() {
return userService.create();
}
"/getById") (
public User getById(@RequestParam int id) {
return userService.getById(id);
}
}
在cloud-feign-business2-server下:
新增UserTestService:
1
2
3
4
5
6
7
8
9
10
"feign-business1-server") (value =
public interface UserTestService {
"/user/create") (
User create();
"/user/getById") (
User getById(@RequestParam int id);
}这里的意思是,当调用UserTestService.create方法时,会去注册中心寻找名为”feign-business1-server”的服务,找到后,向它发起”/user/create”请求并得到相应,实现远程调用的效果。
新增UserTestController:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
"/test/user") (
public class UserTestController {
UserTestService userTestService;
"/create") (
public User create() {
return userTestService.create();
}
"/getById") (
public User getById(@RequestParam int id) {
return userTestService.getById(id);
}
}调用方需要在启动方法上加上@EnableFeignClients:
1
2
3
4
5
6
7
8
9
10
public class CloudBusiness2ServerApplication {
public static void main(String[] args) {
SpringApplication.run(CloudBusiness2ServerApplication.class, args);
}
}
启动项目,注册中心:
访问localhost:8004/test/user/create:
成功调用cloud-feign-business1-server里面的接口。
负载均衡可以自行启动多个cloud-feign-business1-server然后多次访问”localhost:8004/test/user/create“测试效果,这里不再给出。
2-4.服务降级
在cloud-feign-business2-server(调用方)下:
新增UserTestFallBack:
1
2
3
4
5
6
7
8
9
10
11
12
public class UserTestFallBack implements UserTestService {
public User create() {
return new User(-1, "这是默认用户", "无", -1);
}
public User getById(int id) {
return new User(-1, "这是默认用户", "无", -1);
}
}UserTestService指定fallback:
1
2"feign-business1-server",fallback = UserTestFallBack.class) (value =
public interface UserTestService {配置文件加上:
1
2
3feign:
hystrix:
enabled: true #在Feign中开启Hystrix
关闭cloud-feign-business1-server,访问localhost:8004/test/user/create:
在无法访问远程服务时,成功降级访问本地fallback方法。
3.使用Gateway网关服务
3-1.功能
Spring Cloud Gateway旨在提供一种简单而有效的方法来路由到API,并为它们提供跨领域的关注,例如:安全性,监视/度量和弹性。
Spring Cloud Gateway功能:
- 建立在Spring Framework 5,Project Reactor和Spring Boot 2.0之上
- 能够匹配任何请求属性上的路由。
- 谓词和过滤器特定于路由。
- Hystrix断路器集成。
- Spring Cloud DiscoveryClient集成
- 易于编写的谓词和过滤器
- 请求速率限制
- 路径改写
具体介绍和示例可参考官网。
3-2.初步尝试
创建cloud-gateway模块,选择gateway和eureka-client。
配置文件:
1 | server: |
启动
- 访问localhost:8005/user/create
- 访问localhost:8005/feign-business1-server/user/create
发现都被路由到/localhost:8003/user/create,即feign-business1-server的接口上。
3-3.predicates的多种效果
predicates叫做谓语、断言。个人理解为匹配规则。
Path Route Predicate
上面的例子就用的这种,- Path=/xxx/** 的意思就是当访问以”lalhost:8005/xxx/“开头的地址就会被匹配到指定的uri。
Before Route Predicate & After Route Predicate & Between Route Predicate
1
2
3
4
5
6
7
8spring:
cloud:
gateway:
routes:
- id: before_route
uri: http://www.baidu.com
predicates:
- Before=2020-01-01T12:00:00.000+08:00意思在东8区2020-01-01 12:00:00前,访问此服务的请求都会跳转到百度。After类似。Between需要传两个时间,用逗号隔开。
Cookie Route Predicate
1
2
3
4
5
6
7
8spring:
cloud:
gateway:
routes:
- id: cookie_route
uri: http://www.baidu.com
predicates:
- Cookie=cookiename, cookievalue匹配存在cookie名为cookiename,值为cookievalue的请求。
Header Route Predicate
1
2
3
4
5
6
7
8spring:
cloud:
gateway:
routes:
- id: header_route
uri: http://www.baidu.com
predicates:
- Header=X-Request-Id, \d+匹配存在Header为X-Request-Id,内容为数字的请求。
更多Predicate参考官方文档路由谓词工厂。
3-4.过滤器
AddRequestParameter GatewayFilter
1
2
3
4
5
6
7
8
9
10spring:
cloud:
gateway:
routes:
- id: add_request_parameter_route
uri: http://www.baidu.com
filters:
- AddRequestParameter=username, aaa
predicates:
- Method=GET对所有GET请求添加请求参数username,值为aaa。例如:xxx/xxx?username=aaa。
PrefixPath GatewayFilter
1
2
3
4
5
6
7
8
9
10spring:
cloud:
gateway:
routes:
- id: prefix_path_route
uri: http://www.baidu.com
predicates:
- Method=GET
filters:
- PrefixPath=/user对所有GET请求加上/user前缀。
过滤器功能多样,还有Hystrix GatewayFilter(实现断路器模式),RequestRateLimiter GatewayFilter(实现限流)等多种过滤器,具体用法参考官网文档GatrwayFilter工厂。
4.使用Spring Cloud Config配置中心
4-1.创建git仓库存放配置文件
共创建2个分支,6份配置文件。
4-2.创建cloud-config模块
依赖:
1 | <dependency> |
配置文件:
1 | server: |
启动方法j加上对应注解:
1 |
|
启动并访问localhost:8006/master/master-config-dev获取配置文件信息:
访问localhost:8006/master/master-config-dev.yml获取配置文件内容:
乱码问题先忽略:)
4-3.创建cloud-config-client模块
依赖:
1 | <dependency> |
配置文件:(这里用bootstrap而不是application)
1 | server: |
创建测试控制器:
1 |
|
启动访问localhost:8007/configInfo:
也就是说访问这个接口相当于拿到localhost:8006/master/master-config-dev.yml配置文件内容。
4-4.刷新配置
当git仓库的配置刷新了,需要获取配置的客户端也要刷新。
cloud-config-client加入依赖:
1 | <dependency> |
配置文件加入:
1 | management: |
ConfigClientController加上@RefreshScope注解:
1 |
|
修改git仓库的配置文件内容,先访问localhost:8007/actuator/refresh,然后再次访问localhost:8007/configInfo:
5.更多组件
Spring Cloud Bus消息总线、Spring Cloud Sleuth分布式请求链路跟踪等更多组件持续更新。。。
附本次demo地址。