目录
1.新建SpringBoot项目,SpringCloud是建立在SpringBoot基础之上的,所以以下所有工程都是SpingBoot工程
官方向导搭建boot应用:http://start.spring.io
2.建立Eureka(服务注册与发现)服务端与客户端,客户端既为实际微服务,也就是写业务代码的地方
服务端:加入spring cloud父POM及spring-cloud-starter-eureka-server
服务端:启动类增加注解@EnableEurekaServer
客户端:加入spring cloud父POM及spring-cloud-starter-eureka
客户端:启动类增加注解@EnableEurekaClient
客户端:增加负载均衡配置(默认策略为轮询),eureka默认引入了Ribbon依赖包,所以这里不需要显性引入
使用Hystrix注解@HystrixCommand实现降级逻辑
使用Turbine聚合监控数据(这里需要新建一个SpringBoot项目)
添加依赖并在启动类上增加注解@EnableZuulProxy,并将自己注册到Eureka
zuul聚合微服务,在zuul网关项目中编写controller
新建SpringCloudConfig服务端,添加依赖、添加配置
用Elasticsearch存储Zipkin的数据(需安装Elasticsearch)
一、微服务框架简介
微服务框架包括阿里系和SpringCloud系(C一致性,A可用性,P容错性),其中容错性是必须的,阿里系偏向于一致性,SpringCloud系偏向于可用性,本文主要介绍SpringCloud。
1.阿里系
- Zookeeper(hadoop,服务注册与发现,CP)
- Dubbo(客户端负载均衡)
- ……(待补充)
2.SpringCloud系
- Eureka(服务注册与发现,AP):Ribbon(客户端负载均衡)、Feign(PRC,声明式http客户端)
- Hystrix(服务隔离组件,容错,防止雪崩,降级,超时,熔断,限流):Hystrix与Feign结合、DashBoard(监控面板)与Turbine聚合
- Zuul(微服务网关,默认集成了Ribbon和Hystrix):聚合、裁减、路由、过滤、限流、容错、监控、认证
- SpringCloudConfig(配置中心):JEC(加密工具)、SpringBootActuator(单个手动刷新)、SpringCloudBus(统一自动刷新,需安装RabbitMQ)
- Sleuth(分布式链路跟踪):整合zipkin、用Elasticsearch存储zipkin数据(需安装Elasticsearch,也可以用ELK)
3.微服务涉及的其它技术
- 消息中间件:RabbitMQ、ActiveMQ、RocketMQ、Kafka
- 容器引擎:docker(部署工具K8s或jinkins)
二、SpringCloud图解
PS:自己画的图,不完善,有机会再更新
三、SpringCloud实操步骤
1.新建SpringBoot项目,SpringCloud是建立在SpringBoot基础之上的,所以以下所有工程都是SpingBoot工程
-
官方向导搭建boot应用:http://start.spring.io
-
普通maven工程搭建boot应用
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.10.RELEASE</version>
</parent>
2.建立Eureka(服务注册与发现)服务端与客户端,客户端既为实际微服务,也就是写业务代码的地方
-
服务端:加入spring cloud父POM及spring-cloud-starter-eureka-server
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Edgware.SR3</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka-server</artifactId>
</dependency>
-
服务端:application.properties
server.port=8761
#取消向eureka server(注册中心)注册
eureka.client.register-with-eureka=false
#取消向eureka server(注册中心)获取注册信息
eureka.client.fetch-registry=false
#eureka 提供服务发现的地址
eureka.client.service-url.defaultZone=http://localhost:8761/eureka
-
服务端:启动类增加注解@EnableEurekaServer
-
客户端:加入spring cloud父POM及spring-cloud-starter-eureka
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Edgware.SR3</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
-
客户端:application.properties
spring.application.name=microservice-order
server.port=8081
eureka.client.serviceUrl.defaultZone=http://user:password@localhost:8761/eureka
eureka.instance.prefer-ip-address=true
eureka.instance.instance-id=${spring.application.name}:${spring.application.instance_id:${server.port}}
-
客户端:启动类增加注解@EnableEurekaClient
-
客户端:增加负载均衡配置(默认策略为轮询),eureka默认引入了Ribbon依赖包,所以这里不需要显性引入
@Configuration
public class CommonConfig {
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
3、引入Hystrix(豪猪),提高系统容错性
-
消费端引入Springcloud Hystrix依赖
<dependency>
<groupId>org.spring-frameword.cloud</groupId>
<artifactId>spring-cloud_starter-netflix-hystrix</artifactId>
</dependency>
-
使用Hystrix注解@HystrixCommand实现降级逻辑
@RestController
public class OrderController {
@Autowired
private RestTemplate restTemplate;
@HystrixCommand(fallbackMethod = "findByIdFallback")
@GetMapping("/user/{id}")
public User findById(@PathVariable Long id) {
// 请求用户中心接口
return this.restTemplate.getForObject("http://microservice-provider-user/" + id, User.class);
}
public User findByIdFallback(Long id) {
User user = new User();
user.setId(-1L);
user.setName("默认用户");
return user;
}
}
-
Hystrix超时、熔断配置
#超时时间(默认2000毫秒)
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=2000
#熔断阈值(默认20次)
hystrix.command.default.circuitBreaker.requestVolumeThreshold=20
#熔断时间(默认5000毫秒)
hystrix.command.default.circuitBreaker.sleepWindowInMilliseconds=5000
-
Hystrix限流配置
@RestController
public class OrderController {
@Autowired
private RestTemplate restTemplate;
@HystrixCommand(fallbackMethod = "findByIdFallback", // 全局唯一标识服务分组
groupKey = "orderUserGroup", // 全局唯一标识服务名称
threadPoolKey = "orderUserIdThreadPool", // 全局唯一标识线程池名称
threadPoolProperties = {
@HystrixProperty(name = "coreSize", value = "2"), // 线程池大小,一般只配置这一个就可以了
// @HystrixProperty(name = "maxQueueSize", value = "2"), // 线程池队列最大大小
// @HystrixProperty(name = "queueSizeRejectionThreshold", value = "1") // 限定当前队列大小,即实际队列大小由这个参数决定
})
@GetMapping("/user/{id}")
public User findById(@PathVariable Long id) {
// 请求用户中心接口
return restTemplate.getForObject("http://microservice-provider-user/" + id, User.class);
}
public User findByIdFallback(Long id) {
User user = new User();
user.setId(-1L);
user.setName("默认用户");
return user;
}
}
-
Feign整合Hystrix
/**
* Feign的fallback测试
* 使用@FeignClient的fallback属性指定回退类
*/
@FeignClient(name = "microservice-provider-user", fallback = FeignClientFallback.class/*, configuration = FeignDisableHystrixConfiguration.class*/)
public interface UserFeignClient {
@RequestMapping(value = "/{id}", method = RequestMethod.GET)
public User findById(@PathVariable("id") Long id);
}
/**
* 回退类FeignClientFallback需实现Feign Client接口
* FeignClientFallback也可以是public class,没有区别
*/
@Component
class FeignClientFallback implements UserFeignClient {
@Override
public User findById(Long id) {
User user = new User();
user.setId(-1L);
user.setUsername("默认用户");
return user;
}
}
-
Histrix监控
在启动类上增加@EnableCircuitBreaker,这样就可以使用 /hystrix.stream 端点监控 Hystrix了
-
Hystrix Dashboard可视化监控数据
引入依赖,并在启动类上增加注解@EnableHystrixDashboard,通过 /hystrix 访问
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
</dependency>
</dependencies>
-
使用Turbine聚合监控数据(这里需要新建一个SpringBoot项目)
添加依赖,并在启动类上增加注解@EnableTurbine
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-turbine</artifactId>
</dependency>
</dependencies>
编写配置文件application.properties
turbine.appConfig=microservice-order1,microservice-order2
turbine.clusterNameExpression=default
访问turbine监控地址 /turbine.stream,可以看到turbine的聚合监控数据
访问dashboard地址 /hystrix,将该turbine的监控地址输入 dashboard,查看可视化监控数据
4.zuul微服务网关
-
添加依赖并在启动类上增加注解@EnableZuulProxy,并将自己注册到Eureka
zuul会代理所有注册到eureka server的微服务,并使用ribbon做负载均衡,zuul的路由规则如下:
http://ZUUL_HOST:ZUUL_PORT/微服务在Eureka上的serviceId/**
zuul还自动整合了hystrix,访问地址:http://ZUUL_HOST:ZUUL_PORT/hystrix.stream
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
</dependencies>
-
zuul聚合微服务,在zuul网关项目中编写controller
示例如下:
@RestController
public class AggregationController {
@Autowired
private RestTemplate restTemplate;
@GetMapping("/aggregate/{id}")
public Map<String, User> findById(@PathVariable Long id) throws Exception {
Map<String, User> dataMap = new HashMap<>();
User user = restTemplate.getForObject("http://microservice-provider-user/" + id, User.class);
User orderUser = restTemplate.getForObject("http://microservice-consumer-order/user/" + id, User.class);
dataMap.put("user", user);
dataMap.put("orderUser", orderUser);
return dataMap;
}
}
-
zuul的路由配置
#指定微服务地址,既改变微服务的原地址
zuul.routes=microservice-provider-user:/user/**
#忽略指定微服务(黑名单)
zuul.ignored-services=microservice-provider-user
#忽略所有微服务,只路由指定的微服务(白名单)
zuul.ignored-services=*
zuul.routes=microservice-provider-user:/user/**
#指定特定微服务的service-id和路径,其中user-route是自定义名称
zuul.routes.user-route.service-id=microservice-provider-user
zuul.routes.user-route.path=/user/**
#指定URL,这种方式访问不会作为HystrixCommand执行,也不能使用ribbon来负载多个URL
zuul.routes.user-route.url=localhost:8080
#上面如果想要指定URL,而不破坏zuul的Hystrix和Ribbon特性,可以如下配置
#禁用掉ribbon的eureka使用
ribbon.eureka.enabled=false
microservice-provider-user.ribbon.listOfServers=localhost:8000,localhost:8001
#给zuul添加映射前缀
zuul.prefix=/api
zuul.strip-prefix=false
#给单个微服务添加映射前缀
zuul.routes.microservice-provider-user.path=/user/**
zuul.routes.microservice-provider-user.strip-prefix=false
#忽略某些路径
zuul.ignoredPatterns=/**/admin/**
#本地转发
zuul.routes.route-name.path=/path-a/**
zuul.routes.route-name.url=forward:/path-b
-
zuul过滤器
zuul过滤器的类型有:pre、 route、 post、 erro
-
zuul的容错与回退
zuul默认已经整合了hystrix,也就是zuul也是可以利用hystrix做降级容错处理的,但是 zuul监控的粒度是微服务级别,而不是某个API
5.SpringCloudConfig分布式集中配置中心
-
新建SpringCloudConfig服务端,添加依赖、添加配置
添加依赖
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
</dependencies>
添加配置
spring.application.name=microservice-config-server
#配置Git仓库的地址
spring.cloud.config.server.git.uri=https://gitee.com/user/spring-cloud-config.git
#Git仓库的账号
spring.cloud.config.server.git.username=username
#Git仓库的密码
spring.cloud.config.server.git.password=123456
启动项目,访问地址:http://localhost:8080/ms-config/dev,得到整个项目的配置信息
访问地址:http://localhost:8080/ms-config-dev.properties,得到配置文件内容
-
编写config配置中心客户端
添加依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
添加配置
spring.cloud.config.uri: http://localhost:8080
#profile对应config server所获取的配置文件中的{profile}
spring.cloud.config.profile=dev
#指定Git仓库的分支,对应config server所获取的配置文件的{label}
spring.cloud.config.label=master
启动项目,访问地址:http://localhost:8081/profile,得到config配置中心的配置文件内容
-
配置信息的加解密安全处理
安装JCE
config server的加解密功能依赖Java Cryptography Extension(JCE) Java8 JCE
下载地址: http://www.oracle.com/technetwork/java/javase/downloads/jce8-download2133166.html
下载JCE并解压,将其中的jar包覆盖到JDK/jre/lib/security目录中
对称加密
config server提供了加密与解密的接口,分别是/encrypt与/decrypt
增加一个配置文件bootstrap.properties,配置对称加密的密钥
#设置对称密钥
encrypt.key=mykey
运行项目,验证加解密
加密:curl http://localhost:8080/encrypt -d mySecret
解密:curl http://localhost:8080/decrypt -d 767552394ee539201214199d55b0a91b1485d959b667eeabad29a101b9c1c61e
config server能自动解密配置内容。一些场景下,想要让 config server直接返回密文本身,而并非解密后的内容,可设置
spring.cloud.config.server.encrypt.enabled=false,这时可由 ConfigCIient自行解密
-
配置信息手动刷新
客服端添加依赖如下,其中spring-boot-starter-actuator提供了/refresh端点,用于配置的刷新
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
在Controller上添加注解@RefreshScope,添加这个注解的类会在配置更改时得到特殊的处理
@RestController
@RefreshScope
public class ConfigClientController {
@Value("${profile}")
private String profile;
@GetMapping("/profile")
public String hello() {
return this.profile;
}
}
发送post请求:http://localhost:8081/refresh,手动刷新配置
-
配置信息自动刷新(需安装rabbitMQ)
服务端和客户端都添加如下依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
服务端和客户端的配置文件都增加rabbitmq配置
rabbitmq.host=localhost
rabbitmq.port=5672
rabbitmq.username=guest
rabbitmq.password=guest
post方式请求地址服务端地址:http://localhost:8080/bus/refresh,如果返回成功,则config的所有客户端的配置都会动态刷新
6.Sleuth分布式链路跟踪
-
客户端整合sleuth,添加依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>
-
新建Zipkin Server项目,添加依赖
<dependency>
<groupId>io.zipkin.java</groupId>
<artifactId>zipkin-autoconfigure-ui</artifactId>
</dependency>
<dependency>
<groupId>io.zipkin.java</groupId>
<artifactId>zipkin-server</artifactId>
</dependency>
启动项目,访问地址:http://localhost:9411/zipkin/
-
客服端整合Zipkin,添加依赖,配置文件
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-sleuth-zipkin</artifactId>
</dependency>
spring.zipkin.base-url=http://localhost:9411
#指定需采样的请求的百分比,默认值是0.1,即10%
spring.sleuth.sampler.percentage=1.0
然后再次查看Zipkin服务:http://localhost:9411/zipkin/,能查询到微服务调用的跟踪日志
-
用Elasticsearch存储Zipkin的数据(需安装Elasticsearch)
服务端添加依赖,配置文件里增加elasticsearch连接配置
<dependency>
<groupId>io.zipkin.java</groupId>
<artifactId>zipkin-autoconfigure-storage-elasticsearch-http</artifactId>
<version>2.3.1</version>
</dependency>
zipkin.storage.type=elasticsearch
zipkin.storage.elasticsearch.cluster=elasticsearch
zipkin.storage.elasticsearch.hosts=http://localhost:9200
zipkin.storage.elasticsearch.index=zipkin
zipkin.storage.elasticsearch.index-shards=5
zipkin.storage.elasticsearch.index-replicas=1
如有错误,欢迎指正,万分感谢!