一、微服务集群
1、为什么要?
提高并发量
2、结构
3、服务消费者负载均衡调用
3.1. 为什么需要负载均衡
1)服务提供者集群
2)服务消费者负载均衡都用
3.2. 有哪些技术
ribbon feign
3.3.常见的负载均衡策略
轮休 可用性检查 权重
3.4. Ribbon负载均衡调用
<dependencies>
<!--公共代码依赖-->
<dependency>
<groupId>cn.itsource.springcloud</groupId>
<artifactId>User_interface</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!--springboot支持-->
<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>
</dependency>
<!--eureka客户端,服务消费者也要从注册中心获取可用服务列表-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!--客户端负载均衡实现 ribbon-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
</dependencies>
配置
server:
port: 9002
eureka:
client:
registerWithEureka: false #不注册到Eureka,不在注册中心显示
service-url:
#defaultZone: http://localhost:7001/eureka
defaultZone: http://eureka-7001.com:7001/eureka,http://eureka-7002.com:7002/eureka
代码
@Configuration
public class CfgBean {
@Bean
@LoadBalanced //开启负载均衡
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
}
@RestController
@RequestMapping("/consumer")
public class UserController {
//多个方法调用只需改一处就ok
//public static final String URL_PREFIX = "http://localhost:8001";
public static final String URL_PREFIX = "http://USER-PROVIDER"; //通过服务名从注册中心获取服务列表,通过负载均衡调用
@Autowired
private RestTemplate restTemplate;
@RequestMapping("/user/{id}")
public User getUser(@PathVariable("id")Long id){
//调用远程服务 http请求
String url = URL_PREFIX+"/provider/user/"+id;
return restTemplate.getForObject(url,User.class );
}
}
不断刷新会出现轮询效果
3.5. Feign负载均衡
Feign是以接口方式进行调用,而不是通过RestTemplate来调用,feign底层还是ribbon,它进行了封装,让我们调用起来更加happy.
<dependencies>
<!--公共代码依赖-->
<dependency>
<groupId>cn.itsource.springcloud</groupId>
<artifactId>User_interface</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!--springboot支持-->
<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>
</dependency>
<!--eureka客户端,服务消费者也要从注册中心获取可用服务列表-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!--feign的支持-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
</dependencies>
配置yml
server:
port: 9003
eureka:
client:
registerWithEureka: false #不注册到Eureka,不在注册中心显示
service-url:
#defaultZone: http://localhost:7001/eureka
defaultZone: http://eureka-7001.com:7001/eureka,http://eureka-7002.com:7002/eureka
Java类
@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients(basePackages = "cn.itsource.microservice") //不在当前包下面
public class UserConsumerFeign9002Application {
public static void main(String[] args) {
SpringApplication.run(UserConsumerFeign9002Application.class, args);
}
}
代码实现:
代码
//调用服务名字
@FeignClient(value = "USER-PROVIDER")
@RequestMapping("/provider")
public interface UserCilent {
@RequestMapping("/user/{id}") //user/1
User getUser(@PathVariable("id") Long id);
}
注意:要和服务提供者里面访问地址和参数等保持一致。
代码
@RestController
@RequestMapping("/consumer")
public class UserController {
@Autowired
private UserCilent userCilent;
@RequestMapping("/user/{id}")
public User getUser(@PathVariable("id")Long id){
System.out.println(userCilent.getClass());
return userCilent.getUser(id);
}
}
注意:client只是服务消费者使用,不是属于公共,不应该放到interface.可以直接放到服务消费者里面或者另开一个模块但是只给服务消费依赖。
二、Hystrix断路器
1.是什么?
微服务架构处理服务健壮性的框架
2.为什么?
解决微服务架构的雪崩线下
3.措施?
隔离&熔断&降级
4.Hystrix实现(服务提供者实现)
<!--断路器-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
5.Feign实现
feign熔断机制是封装hystrix
package cn.itsource.springcloud.client;
import cn.itsource.springcloud.domain.User;
import feign.hystrix.FallbackFactory;
import org.springframework.stereotype.Component;
@Component
//UserClient 表示对那个接口进行托底处理
public class UserClientHystrixFallbackFactory implements FallbackFactory<UserClient> {
@Override
public UserClient create(Throwable throwable) {
return new UserClient() {
@Override
public User getUser(Long id) {
return new User(id,"出异常,请联系管理员!");
}
};
}
}
//调用服务名字
@FeignClient(value = "USER-PROVIDER",fallbackFactory = UserClientHystrixFallbackFactory.class)
@RequestMapping("/provider")
public interface UserClient {
@RequestMapping("/user/{id}")
User getUser(@PathVariable("id") Long id);
}
如果我们服务消费者实现的技术为ribbon,必须在服务提供者方通过Hystrix的断路器.
如果我们服务消费者实现的技术为feign,必须在服务消费者通过feign的断路器,feign断路器底层还是Hystrix的断路器.
三、Zuul路由网关
1.是什么?
为外部访问提供统一的入口,并且我们同可以通过过滤完成过渡,并且封装负载均衡ribbon,封装了熔断hystrix
2.为什么需要
Zuul为我们外部调用提供了统一的入口,由于zuul注册达到Eureka当中,就能获取Eureka里面管理的服务。
3.基本配置
<!--springboot支持-->
<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>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
yml
server:
port: 4399
spring:
application:
name: ZUUL-GATEWAY
eureka:
client:
service-url:
defaultZone: http://localhost:7001/eureka #集群环境配置需要改一下
instance:
instance-id: gateway-9527.com
prefer-ip-address: false
4. 路由访问映射规则
- 安全加固:不用服务名,映射路径
2) 忽略原来服务名访问:原来模式不可以访问
3) 加上统一前缀
zuul:
routes:
myUser.serviceId: user-provider # 服务名
myUser.path: /myUser/** # 把myUser打头的所有请求都转发给user-provider
ignored-services: "*" #所有服务都不允许以服务名来访问
prefix: "/services" #加一个统一前缀
5. 自定义过滤器
@Component
public class LoginFilter extends ZuulFilter{
@Override
public String filterType() {
// 登录校验,肯定是在前置拦截
return "pre";
}
@Override
public int filterOrder() {
// 顺序设置为1
return 1;
}
@Override
public boolean shouldFilter() {
// 返回true,代表过滤器生效。
return true;
}
@Override
public Object run() throws ZuulException {
// 登录校验逻辑。
// 1)获取Zuul提供的请求上下文对象
RequestContext ctx = RequestContext.getCurrentContext();
// 2) 从上下文中获取request对象
HttpServletRequest req = ctx.getRequest();
// 3) 从请求中获取token
String token = request.getHeader("token");
// 4) 判断
if(token == null || "".equals(token.trim())){
// 没有token,登录校验失败,拦截
ctx.setSendZuulResponse(false);
// 返回401状态码。也可以考虑重定向到登录页。
ctx.setResponseStatusCode(HttpStatus.UNAUTHORIZED.value());
}
// 校验通过,可以考虑把用户信息放入上下文,继续向后执行
return null;
}
}
6.负载均衡与熔断
zuul:
retryable: true
ribbon:
ConnectTimeout: 250 # 连接超时时间(ms)
ReadTimeout: 2000 # 通信超时时间(ms)
OkToRetryOnAllOperations: true # 是否对所有操作重试
MaxAutoRetriesNextServer: 2 # 同一服务不同实例的重试次数
MaxAutoRetries: 1 # 同一实例的重试次数
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMillisecond: 3000 # 熔断超时时长:3000ms
四、SpringCloud Config分布式配置中心
1.为什么需要?
配置文件统一管理
2.服务端配置
1)github创建配置文件
<dependencies>
<!--springboot支持-->
<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>
</dependency>
<!--eureka客户端-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!--配置中心支持-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
</dependencies>
yml
server:
port: 1299
eureka:
client:
service-url:
defaultZone: http://eureka-7001.com:7001/eureka,http://eureka-7002.com:7002/eureka # 集群
instance:
prefer-ip-address: true
spring:
application:
name: spring-cloud-config-server
cloud:
config:
server:
git:
uri: https://github.com/hpyao/microservice-config.git
username: hpyao
password: Itsource20190329
启动·
@SpringBootApplication
@EnableEurekaClient //加入注册中心
@EnableConfigServer //启用配置服务端
public class ConfigServerApplication_1299 {
public static void main(String[] args) {
SpringApplication.run(ConfigServerApplication_1299.class);
}
}
3. 客户端配置
<dependencies>
<!--springboot支持-->
<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>
</dependency>
<!--eureka客户端-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!--configclient端-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
</dependencies>
全局bootstrap.yml
spring:
Application
Name
cloud:
config:
name: application-user #github上面名称
profile: test #环境
label: master #分支
uri: http://127.0.0.1:1299 #配置服务器
eureka:
client:
service-url:
defaultZone: http://eureka-7001.com:7001/eureka,http://eureka-7002.com:7002/eureka # 集群
instance:
prefer-ip-address: true #显示客户端真实ip
如果读取到就会有application.name,这个名字