SpringCloud-Project-Netflix方案
- Eureka 注册中心:独立服务端
- OpenFeign 远程服务调用
- Ribbon 负载均衡
- Hystrix 断路器
- Gateway 网关中心:独立服务端
- Config 配置中心:独立服务端
第一部分:各个模块部分
1、添加依赖
<!-- Eureka 注册中心客户端-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!--Openfeign 远程RPC,注意已经包含了Ribbon-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</dependency>
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-okhttp</artifactId>
</dependency>
<!-- Hystrix 断路器-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix</artifactId>
<version>1.4.7.RELEASE</version>
</dependency>
<!--config 配置中心-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<!--actuator 健康检查-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!--RabbitMQ消息总线,用于刷新配置-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
<!--使用zuul网关-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zuul</artifactId>
</dependency>
<!--ziplink 服务端以及UI界面-->
<dependency>
<groupId>io.zipkin.java</groupId>
<artifactId>zipkin-server</artifactId>
<version>2.4.3</version>
</dependency>
<dependency>
<groupId>io.zipkin.java</groupId>
<artifactId>zipkin-autoconfigure-ui</artifactId>
<version>2.4.3</version>
</dependency>
2、Eureka-Config-gateway客户端配置
默认配置
- client.refresh.interval=30s
- client.heartbeat.threadPoolSize=5
- client.heartbeat.exponentialBackOffBound=10
- client.cacheRefresh.threadPoolSize=5
- client.cacheRefresh.exponentialBackOffBound=10
server:
port: 8089
spring:
application:
name: foobar
# 启用压缩
compression:
enabled: true
mime-types: ["text/html", "text/xml", "text/plain", "text/css", "text/javascript", "application/javascript", "application/xml", "application/json"]
min-response-size: 512
cloud:
## 连接配置中心
config:
uri: http://localhost:12000 # 配置中心的具体地址,即 config-server
name: config-client # 对应 {application} 部分
profile: dev # 对应 {profile} 部分
label: master # 对应 {label} 部分,即 Git 的分支。如果配置中心使用的是本地存储,则该参数无用
username: user
password: password123
discovery:
enabled: true
service-id: microservice-config-server-eureka
## 配置中心消息总线 RabbitMQ配置
rabbitmq:
host: localhost
port: 5672
username: guest
password: guest
# 注册中心
eureka:
client: # Eureka客户端配置,放在Eureka服务端
# 关闭eureka client
enabled: false
# 注册自身到eureka服务器,默认是true
register-with-eureka: true
# 表示是否从eureka服务器获取注册信息,默认是false
fetch-registry: false
# 客户端从Eureka Server集群里更新Eureka Server信息的频率
eureka-service-url-poll-interval-seconds: 60
# 定义从注册中心获取注册服务的信息
registry-fetch-interval-seconds: 5
# 设置eureka服务器所在的地址,查询服务和注册服务都需要依赖这个地址
serviceUrl:
# 设置eureka服务器所在的地址,可以同时向多个服务注册服务
defaultZone: http://127.0.0.1:8000/eureka/
# 远程调度服务
feign:
compression: #请求压缩
request:
enabled: true
mime-types: ["text/xml", "application/xml", "application/json"]
min-request-size: 512
response:
enabled: true
## 使用HTTPClient
httpclient:
enabled: true # 使用httpClient
maxConnections: 20480 # 最大连接时间
maxConnectionsPerRoute: 512 # 单个路径最大连接数
timeToLive: 60
connectionTimeout: 10000 # 连接超时时间
## 使用OkHttp 注意:HTTPClient和OKHttp只能二选一
okhttp:
enabled: false
maxConnections: 20480 # 最大连接时间
maxConnectionsPerRoute: 512 # 单个路径最大连接数
timeToLive: 60
connectionTimeout: 10000 # 连接超时时间
client:
config:
default: # key 为default时表示的是全局配置
loggerLevel: basic # 配置日志级别
product-provider-01: # 为具体的服务提供者的spring.application.name的值,表示单独为这个工程配置
loggerLevel: full
#Ribbon负载均衡配置
ribbon:
ConnectTimeout: 2000 # 请求连接的超时时间
ReadTimeout: 5000 # 请求处理的超时时间
OkToRetryOnAllOperations: true
## 服务的负载均衡策略
foobar:
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RoundRobinRule #设置负载均衡
#NFLoadBalancerRuleClassName: com.netflix.loadbalancer.WeightedResponseTimeRule # 权重规则
#NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule #设置负载均衡
#NFLoadBalancerRuleClassName: com.netflix.loadbalancer.BestAvailableRule #设置负载均衡
#NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule #设置负载均衡
#NFLoadBalancerRuleClassName: com.netflix.loadbalancer.AvailabilityFilteringRule # 可用服务规则
#NFLoadBalancerRuleClassName: com.netflix.loadbalancer.ZoneAvoidanceRule # 区域可用规则
## 日志
logging:
level:
com:
tuling:
feignapi: DEBUG
3、启动类
@SpringBootApplication
public class ConfigServerApplication {
public static void main(String[] args) {
SpringApplication.run(ConfigServerApplication.class, args);
}
}
4、全局配置类
@EnableDiscoveryClient 注册中心客户端启动
@EnableHystrix 断路器
@EnableCircuitBreaker 断路器
@RefreshScope 配置中心自动刷新
@EnableFeignClients RPC消费端
@Configuration
@EnableDiscoveryClient
@EnableHystrix
@EnableCircuitBreaker
@RefreshScope
@EnableFeignClients
public class GlobalConfig{
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
// 如果使用httpClient连接池配置
@Bean
public HttpClient httpClient(){
// 生成默认请求配置
RequestConfig.Builder requestConfigBuilder = RequestConfig.custom();
requestConfigBuilder.setSocketTimeout(5 * 1000);
requestConfigBuilder.setConnectTimeout(5 * 1000);
RequestConfig defaultRequestConfig = requestConfigBuilder.build();
//请求连接池
final PoolingHttpClientConnectionManager pollingConnectionManager = new PoolingHttpClientConnectionManager(30, TimeUnit.MILLISECONDS);
pollingConnectionManager.setMaxTotal(5000);
pollingConnectionManager.setDefaultMaxPerRoute(100);
HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();
httpClientBuilder.setKeepAliveStrategy(new DefaultConnectionKeepAliveStrategy());
httpClientBuilder.setConnectionManager(pollingConnectionManager);
httpClientBuilder.setDefaultRequestConfig(defaultRequestConfig);
HttpClient client = httpClientBuilder.build();
// 启动定时器,定时回收过期的连接, 最重要。 如果没有定义回收策略。连接池会在运行一段时间后失效。
Timer timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
pollingConnectionManager.closeExpiredConnections();
pollingConnectionManager.closeIdleConnections(5, TimeUnit.SECONDS);
}
}, 10 * 1000, 5 * 1000);
System.out.println("===== Apache httpclient 初始化连接池===");
return client;
}
}
5、FeignCliet服务消费端
- @FeignClient 注解作用是指定调用的外部的接口
- name 对外的服务名称,这里和eureka上注册名称相同
- value 同name
- contextId 指定唯一的名称
- url 选填,如果填写后,会指定调用某个服务
- qualifier 判断
- decode404 404解码
- configuration 自定义配置
- fallback 失败回调
- fallbackFactory 失败回调工厂类
- path 类似于@RequestMapping用于类上地址
- primary 是否主要
- fallbackFactory 服务降级
- fallback 服务降级 二选一
// 指定user-center
@FeignClient(contextId = "user-center",name = "UserClient", url = "http://127.0.0.1:8001",
fallbackFactory = HelloRollBackFactory.class,
fallback = HystrixClientFallback.class)
public interface UserCenterClient {
//注意这里需要对应的是服务提供者的接口相对应
@RequestMapping(method = RequestMethod.GET, value = "/participate")
String getUserByForm(@RequestParam Map<String, Object> params);
}
//服务降级
@Slf4j
@Component
public class HelloRollBackFactory implements FallbackFactory<HelloService> {
@Override
public HelloService create(Throwable throwable) {
//可以抓取异常
log.info("fallback; reason was: {}", throwable.getMessage());
//返回实现的一个回调接口
return new HelloService(){
@Override
public User findById(String name) {
log.info("UserFeignClient#findById#id={}服务降级了",id);
User user = new User();
user.setId(0L);
return user;
}
}
}
}
//服务降级2
@Slf4j
@Component
public class HystrixClientFallback implements UserFeignClient {
//回调类,返回一个默认的user,防止调用出现空指针的问题
@Override
public User findById(Long id) {
log.info("UserFeignClient#findById#id={}服务降级了",id);
User user = new User();
user.setId(0L);
return user;
}
}
6、使用FeignClient
public class courseService{
@Autowired
private UserCenterClient userCenterClient;
public Result useClien(){
//省略参数
return userCenterClient.getUserByForm(....);
}
}
第二部分:独立服务搭建
一、Eureka注册中心客户端
- 可以搭建集成环境
1、添加依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
2、Eureka服务端配置添加配置
- appinfo.replicate.interval=30s
- appinfo.initial.replicate.time=40s
- serviceUrlPollIntervalMs=30s
- eurekaServer.readTimeout=8s
- eurekaServer.connectTimeout=5s
- eurekaServer.maxTotalConnections=200s
- eurekaServer.maxConnectionsPerHost=50
- eurekaserver.connectionIdleTimeoutInSeconds=30s
## Eureka服务端配置
eureka:
instance:
hostname: T231
# 使用IP注册,Spring就会自动为我们获取第一个非回环IP地址
prefer-ip-address: true
# 心跳间隔
lease-renewal-interval-in-seconds: 3
# 服务失效时间: 如果多久没有收到请求,则可以删除服务,默认是30s
lease-expiration-duration-in-seconds: 7
server: #Eureka服务端配置,放在Eureka客户端
# renewal-percent-threshold: 0.1
# 关闭自我保护模式
enable-self-preservation: false
# Eureka Server 自我保护系数,当enable-self-preservation=true时,启作用
# renewal-percent-threshold:
# 设置清理间隔,单位为毫秒,默认为0
eviction-interval-timer-in-ms: 3000
# 设置如果Eureka Server启动时无法从临近Eureka Server节点获取注册信息,它多久不对外提供注册服务
wait-time-in-ms-when-sync-empty: 6000000
# 集群之间相互更新节点信息的时间频率
peer-eureka-nodes-update-interval-ms: 60000
3、启动类
启动类添加@EnableEurekaServer
二、配置中心
注意配置中心也需要作为Eureka的客户端,为避免重复,这里相关的依赖和配置省略
使用时需要注意
1、添加依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
2、添加配置项
环境配置规则
- application:配置通用名:例如application
- profile:处理名例如dev
- label: 对应git的分支内容,例如master
/{application}/{profile}[/{label}]
/{application}-{profile}.yml
/{label}/{application}-{profile}.yml
/{application}-{profile}.properties
/{label}/{application}-{profile}.properties
spring:
cloud:
config:
server:
git:
uri: https://git.oschina.net/it-much/config-repo-51cto-video # 公用
# uri: https://git.oschina.net/it-much/{application} #通配符
username: #账号
password: #密码
repos:
simple: https://git.oschina.net/it-much/simple
special:
pattern: special*/dev*,special*/test* # 模式
uri: https://git.oschina.net/it-much/special
cloneOnStart: false # 关闭cloneOnStart
search-paths: # 搜索路径
- foo # foo路径
- bar # bar路径
## 为配置中心添加安全访问
security:
basic:
enabled: true
user:
name: user
password: password123
3、启动类添加注解
@SpringBootApplication
@EnableConfigServer
@EnableDiscoveryClient
public class ConfigServerApplication {
public static void main(String[] args) {
SpringApplication.run(ConfigServerApplication.class, args);
}
}
4、测试获取配置
浏览器打开:http://localhost:12000/config-client/dev
三、网关中心Gateway
网关中心服务需要链入Eureka
1、添加依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
2、添加配置项
- datetime :请求时间限制在之前,之间,之后
- After=2018-01-20T06:06:06+08:00[Asia/Shanghai]
- Before=2018-01-20T06:06:06+08:00[Asia/Shanghai]
- Between=2018-01-20T06:06:06+08:00[Asia/Shanghai]
- cookie :请求指定的Cookie
- Cookie=ityouknow, kee.e
- header :请求指定的Header的正则配置和指定名称
- Header=X-Request-Id, \d+
- host :请求指定的Host
- Host=**.ityouknow.com
- method :请求指定的方法
- Method=GET,POST,OPTIONS
- path :请求指定的路径
- Path=/foo/{segment}
- QueryParam :请求指定的参数值
- Query=channel_web
- RemoteAddr :请求指定的远程地址
- RemoteAddr=192.168.1.1/24
spring:
cloud:
gateway:
discovery:
locator:
enabled: true #开启gateway的客户端发现
routes: #路由规则
- id: course #路由规则
uri: /v1/api/course #映射地址
order: 1 #排序
predicates: #配置预处理器
- Path=/**
filters: #配置过滤器
- SetPath=
- RewritePath=/CONSUMER/(?<segment>.*), /$\{segment}
- StripPrefix=2 # 请求路径修改过滤器 StripPrefix=2就代表截取路径的个数,
- PrefixPath=/mypath # 跟StripPrefix相反,会添加后转发
- Auth # 自定义的权限过滤器
- IPForbid=0:0:0:0:0:0:0:1 #自定义的IP拦截器
- ResponseBody #自定义的响应结果拦截器
3、启动类设置为Eureka的客户端
@EnableDiscoveryClient
@SpringBootApplication
public class GateWayApplication {
public static void main(String[] args) {
SpringApplication.run(GateWayApplication.class, args);
}
}
四、使用Zull网关中心
1、添加配置项
zuul: # zuul配置
ignoredServices: zuul-server
routes:
microservice-provider-user: /user/**
2、添加配置类
@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
@EnableZuulProxy
@EnableEurekaClient
@SpringCloudApplication
public class ApiGatewayMicroApplication {
public static void main(String[] args) {
SpringApplication.run(ApiGatewayMicroApplication.class, args);
}
}
1、自定义拦截器
Zull有请求过滤的功能,其过滤器可以在Http请求的发起和响应返回期间执行一系列的过滤器。Zuul包扩以下四种过滤器:
- PRE: 该类型的filters在Request routing到源web-service之前执行。可以进行一些权限认证,日志记录,或者额外给Request增加一些属性供后续的filter使用;
- ROUTING:该类型的filters用于把Request routing到源web-service,源web-service是实现业务逻辑的服务。这里使用HttpClient请求web-service;
- POST:该类型的filters在ROUTING返回Response后执行。用来实现对Response结果进行修改,收集统计数据以及把Response传输会客户端;
- ERROR:上面三个过程中任何一个出现错误都交由ERROR类型的filters进行处理。
Zuul过滤器具有以下关键特性:
- Type(类型):Zuul过滤器的类型,这个类型决定过滤器在哪个阶段执行,例如:pre,post等阶段;
- Execution Order(执行顺序):规定了过滤器的执行顺序,Order的值越小,越先执行;
- Criteria(标准):Filters执行所需条件
- Action(行动):如果符合执行条件,则执行Action(具体逻辑代码)
(1)定义前置拦截器
public class PreZuulFilter extends ZuulFilter {
private static final Logger LOGGER = LoggerFactory.getLogger(PreZuulFilter.class);
@Override
public Object run() {
//获取请求内容
RequestContext ctx = RequestContext.getCurrentContext();
HttpServletRequest request = ctx.getRequest();
String param = request.getParameter("XXXX");
//TODO 这里可以进行参数验签解密,权限验证,日志记录,或者额外提供一些信息
String host = request.getRemoteHost();
PreZuulFilter.LOGGER.info("请求的host:{}", host);
return null;
}
@Override
public boolean shouldFilter() {
return true;
}
@Override
public String filterType() {
return "pre"; //定义拦截器类型
}
@Override
public int filterOrder() {
return 0;
}
}
(3)、鉴权拦截器
@Configuration
public class ApiGatewayFilter extends ZuulFilter {
@Override
public String filterType() {
return "pre";
}
@Override
public int filterOrder() {
return 0;
}
@Override
public boolean shouldFilter() {
return true;
}
@Override
public Object run() throws ZuulException {
RequestContext context = RequestContext.getCurrentContext();
HttpServletRequest request = context.getRequest();
Principal principal = request.getUserPrincipal();
//获取用户的登录id
String userId = principal.getName();
context.addZuulRequestHeader("X-AUTH-ID",userId);
return null;
}
}
(4)配置类中增加拦截器
@Bean
public PreZuulFilter preZuulFilter() {
return new PreZuulFilter();
}
2、设置熔断
MyFallbackProvider 实现ZuulFallbackProvider接口
@Component
public class CustomerFallbackProvider implements ZuulFallbackProvider {
@Override
public String getRoute() {
return "*";//设置路由,可以是所有的服务或者指定服务
}
@Override
public ClientHttpResponse fallbackResponse() {
return new ClientHttpResponse() {
@Override
public HttpStatus getStatusCode() throws IOException {
return HttpStatus.BAD_REQUEST;
}
@Override
public int getRawStatusCode() throws IOException {
return HttpStatus.BAD_REQUEST.value();
}
@Override
public String getStatusText() throws IOException {
return HttpStatus.BAD_REQUEST.getReasonPhrase();
}
@Override
public void close() {
}
@Override
public InputStream getBody() throws IOException {
return new ByteArrayInputStream(("fallback" +
MyFallbackProvider.this.getRoute()).getBytes());
}
@Override
public HttpHeaders getHeaders() {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
return headers;
}
};
}
}
3、使用正则表达式处理,启动类添加PatternServiceRouteMapper
@SpringBootApplication
@EnableZuulProxy
public class ZuulApplication {
public static void main(String[] args) {
SpringApplication.run(ZuulApplication.class, args);
}
@Bean
public PatternServiceRouteMapper serviceRouteMapper() {
return new PatternServiceRouteMapper("(?<name>^.+)-(?<version>v.+$)", "${version}/${name}");
}
}