SpringCloud
SpringCloud
入门问题
- 微服务概念
- 微服务之间如何通信
- SpringCloud与Dubbo的区别
- SpringBoot与SpringCloud的关系
- 服务熔断和服务降级概念
- 微服务的优缺点
- 微服务技术栈
- eureka和zookeeper的区别
微服务概述
微服务起源:微服务
微服务将单一应用程序划分为一组小服务,每个服务独立在及自己的进程中,通过Restful方式互相沟通、调用。每个服务提供单个业务功能,去耦合。
微服务与微服务架构
微服务:指系统中的一个服务应用。
微服务架构:架构风格,即包括微服务及微服务之间的通信。
微服务的优缺点
优点
- 服务高内聚,完成一个细微化的业务或功能
- 单个服务的开发更便捷,开发简单、开发效率高
- 微服务可由独立团队开发
- 松耦合,开发及部署都独立
- 可以由不同语言开发,易于集成
- 前后端分离、灵活分配数据库
缺点
- 分布式系统的复杂性
- 运维难度增加,系统部署依赖问题
- 服务间通信额外花费
- 数据一致性、系统集成测试难度
- 性能监控难
微服务技术栈
微服务 | 技术 |
---|---|
开发 | Spring、SpringBoot、SpringMVC |
配置管理 | Archaius(Netflix)、Diamond(Ali) |
注册与实现 | Eureka、Consul、Zookeeper |
调用 | Rest、RPC、gRPC |
熔断器 | Hystrix、Envoy |
负载均衡 | Ribbon、Nginx |
接口调用工具 | Feign |
消息队列 | Kaflka、RabbitMQ、ActiveMQ |
配置中心管理 | SpringCloudConfig、Chef |
路由(API网关) | Zuul |
监控 | Zabbix、Nagios、Metrics、Spectator |
全链路追踪 | ZipKin、Brave、Dapper |
部署 | Docker、OpenStack、Kubernates |
数据流操作 | SpringCloud Steam(Redis、Rabbit...) |
事件消息总线 | Spring Cloud Bus |
SpringCloud 架构
主流选用
厂商 | 技术选用 |
---|---|
阿里 | Dubbo/HSF |
京东 | JSF |
新浪微博 | Motan |
当当 | Dubbo |
框架对比
功能 | Spring Cloud | Motan | gRPC | Thrift | Dubbo/DubboX |
---|---|---|---|---|---|
定位 | 完整微服务 | RPC+ZK/Consul | RPC | RPC | RPC |
Rest | 支持 | 否 | 否 | 否 | 否 |
RPC | 否 | 是 | 是 | 是 | 是 |
多语言 | 是 | 否 | 是 | 是 | 否 |
注册/发现 | (Eurka) | Zookeeper/Consul | 否 | 否 | 是 |
负载均衡 | Zuul+Ribbon | 是 | 否 | 否 | 是 |
配置服务 | Archaius/sp config servier | ||||
调用链监控 | Zuul API | ||||
高可用/容错 | Hystrix Ribbon | ||||
其他 |
SpringCloud简介
SpringCloud微服务架构,涵盖了服务注册/发现、配置中心、全链路监控、服务网管、负载均衡、熔断器等,使用SpringBooot简化开发,提供快速构建分布式系统的工具,包括配置管理、服务发现、断路器、路由、微代理、事件总线、全局锁、决策精选、分布式会话等,都可以使用SpringBoot开发进行快速启动和部署。
SpringCloud:一站式分布式微服务解决方案
Dubbo 对比 SpringCloud
对比 | Dubbo | SpringCloud |
---|---|---|
注册中心 | Zookeeper | Eureka |
调用方式 | RPC | REST API |
监控 | Dubbo-minitor | spring boot admin |
断路器 | 不完善 | SC Netfilx Hystrix |
网管 | 无 | SC Netfilx Zull |
分布式配置 | 无 | SC config |
跟踪 | 无 | SC Sleuth |
消息总线 | 无 | SC Bus |
数据流 | 无 | SC Stream |
批量任务 | 无 | SC Task |
... |
文档
实战
版本
- Cloud: Dalston.SR1
- Boot: 1.5.9
创建工程
创建父工程Maven配置打包类型为Pom
在父工程中创建子工程模块
创建子工程
Eureka
服务注册与发现,注册订阅后可以依据服务标识符访问服务,不需要修改配置文件,功能和Zookeeper类似,遵循AP原则。
功能对比 | Eurka | Zookeeper |
---|---|---|
架构 | CS架构 Server端注册服务器 | RPC |
稳定性 | 冗余备份,所有集群均可独立工作 | 主从备份,选举费时 |
Eureka简介
服务端:提供服务注册服务,存储所有可用服务节点的信息。
客户端:Java客户端,简化同服务端的交互,包含负载均衡器,启动后会向服务端周期发送心跳(默认30s),当服务器在多个周期中未受到某节点心跳(默认90s),节点将会移除。
注册中心
server:
port: 7001
eureka:
instance:
hostname: localhost
client:
register-with-eureka: false #不注册自身
fetch-registry: false #服务端
service-url:
defalutZone: http://${eureka.instance.hostname}:${s
@SpringBootApplication
@EnableEurekaServer
public class EurekaServer7001_App {
public static void main(String[] args) {
SpringApplication.run(EurekaServer7001_App.class,args);
}
}
服务提供者
eureka:
client: #客户端注册进eureka服务列表内
service-url:
defaultZone: http://localhost:7001/eureka
#defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
instance:
instance-id: microservicecloud-dept-8001
prefer-ip-address: true #访问路径可以显示IP地址
@EnableEurekaClient
@SpringBootApplication
public class DeptProvider8001_App {
public static void main(String[] args) {
SpringApplication.run(DeptProvider8001_App.class,args);
}
}
服务消费者
server:
port: 80
@Configuration
public class ConfigBean
{
@Bean
@LoadBalanced//Spring Cloud Ribbon 负载均衡的工具。
public RestTemplate getRestTemplate()
{
return new RestTemplate();
}
}
private static final String REST_URL_PREFIX = "http://localhost:8001";
//private static final String REST_URL_PREFIX = "http://MICROSERVICECLOUD-DEPT";
@Autowired
private RestTemplate restTemplate;
@RequestMapping(value = "/consumer/dept/add")
public boolean add(Dept dept)
{
return restTemplate.postForObject(REST_URL_PREFIX + "/dept/add", dept, Boolean.class);
}
@RequestMapping(value = "/consumer/dept/get/{id}")
public Dept get(@PathVariable("id") Long id)
{
return restTemplate.getForObject(REST_URL_PREFIX + "/dept/get/" + id, Dept.class);
}
@SuppressWarnings("unchecked")
@RequestMapping(value = "/consumer/dept/list")
public List<Dept> list()
{
return restTemplate.getForObject(REST_URL_PREFIX + "/dept/list", List.class);
}
// 测试@EnableDiscoveryClient,消费端可以调用服务发现
@RequestMapping(value = "/consumer/dept/discovery")
public Object discovery()
{
return restTemplate.getForObject(REST_URL_PREFIX + "/dept/discovery", Object.class);
}
负载均衡
Ribbon
客户端负载均衡工具
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-ribbon</artifactId>
</dependency>
@Configuration
public class ConfigBean
{
@Bean
@LoadBalanced//Spring Cloud Ribbon 负载均衡的工具。
public RestTemplate getRestTemplate()
{
return new RestTemplate();
}
}
@Bean
public IRule myRule()
{
//return new RoundRobinRule();
//return new RandomRule();//达到的目的,用我们重新选择的随机算法替代默认的轮询。
return new RetryRule();
}
算法
-
RoundRobinRule
轮询
-
RandomRule
随机
-
AvaliabilityFilteringRule
过滤访问导致故障处于断路器跳闸的服务、超并发阈值服务,剩余轮询
-
WeightedResponseTimeRule
根据平均响应时间分配权重,权重大的被选中几率大,服务启动使用轮询,后切换为WeightedResponseTimeRule。
-
RetryRule
按照轮询获取服务,失败时,在指定时间内重试。
-
BestAvaliableRule
过滤故障跳闸服务,选择并发量小的服务。
-
ZoneAvoidanceRule
默认规则,复合判断服务性能和选择可用服务。
自定义负载均衡策略
import com.wang.myrule.MySelfRule;
/////////////////
@RibbonClient(name="microservicecloud-dept",configration=MySelfRule.class)
/////////////////
@EnableEurekaClient
@SpringBootApplication
public class ConsumerDept80 {
public static void main(String[] args) {
SpringApplication.run(ConsumerDept80.class,args);
}
}
//自动配置类 不能载SpringBoot的自动扫描范围
//如果被扫描 所有的客户端将共享这个配置
package com.wang.myrule;//与主配置并列包
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RoundRobinRule;
@Configuration
public class MySelfRule
{
@Bean
public IRule myRule()
{
//return new RandomRule();
//return new RoundRobinRule();
return new RandomRule();// 自己编写的类
}
}
自定义规则编写
自定义策略类
package com.atguigu.myrule;
import java.util.List;
import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.AbstractLoadBalancerRule;
import com.netflix.loadbalancer.ILoadBalancer;
import com.netflix.loadbalancer.Server;
public class RandomRuleUserDefined extends AbstractLoadBalancerRule
{
// total = 0 // 当total==5以后,我们指针才能往下走,
// index = 0 // 当前对外提供服务的服务器地址,
// total需要重新置为零,但是已经达到过一个5次,我们的index = 1
// 分析:我们5次,但是微服务只有8001 8002 8003 三台,OK?
//
private int total = 0; // 总共被调用的次数,目前要求每台被调用5次
private int currentIndex = 0; // 当前提供服务的机器号
public Server choose(ILoadBalancer lb, Object key)
{
if (lb == null) {
return null;
}
Server server = null;
while (server == null) {
if (Thread.interrupted()) {
return null;
}
List<Server> upList = lb.getReachableServers();
List<Server> allList = lb.getAllServers();
int serverCount = allList.size();
if (serverCount == 0) {
/*
* No servers. End regardless of pass, because subsequent passes only get more
* restrictive.
*/
return null;
}
// int index = rand.nextInt(serverCount);// java.util.Random().nextInt(3);
// server = upList.get(index);
// private int total = 0; // 总共被调用的次数,目前要求每台被调用5次
// private int currentIndex = 0; // 当前提供服务的机器号
if(total < 5)
{
server = upList.get(currentIndex);
total++;
}else {
total = 0;
currentIndex++;
if(currentIndex >= upList.size())
{
currentIndex = 0;
}
}
if (server == null) {
/*
* The only time this should happen is if the server list were somehow trimmed.
* This is a transient condition. Retry after yielding.
*/
Thread.yield();
continue;
}
if (server.isAlive()) {
return (server);
}
// Shouldn't actually happen.. but must be transient or a bug.
server = null;
Thread.yield();
}
return server;
}
@Override
public Server choose(Object key)
{
return choose(getLoadBalancer(), key);
}
@Override
public void initWithNiwsConfig(IClientConfig clientConfig)
{
// TODO Auto-generated method stub
}
}
策略类继承关系
Feign
声明式Rest客户端,使得编写Web服务客户端更简单,可以与Eurek、Rebbon组合使用。
定义一个接口添加注解,即可使用。
Ribbon+RestTemplate:调用
接口+注解:调用
依赖
<dependency>
<groupId>cn.springcloud.feign</groupId>
<artifactId>venus-cloud-starter-feign</artifactId>
</dependency>
接口+注解
//@FeignClient(value = "MICROSERVICECLOUD-DEPT",fallbackFactory=DeptClientServiceFallbackFactory.class) //熔断器类
@FeignClient(value = "MICROSERVICECLOUD-DEPT")
public interface DeptClientService
{
@RequestMapping(value = "/dept/get/{id}", method = RequestMethod.GET)
public Dept get(@PathVariable("id") long id);
@RequestMapping(value = "/dept/list", method = RequestMethod.GET)
public List<Dept> list();
@RequestMapping(value = "/dept/add", method = RequestMethod.POST)
public boolean add(Dept dept);
}
Controller
@RestController
public class DeptController_Consumer
{
@Autowired
private DeptClientService service;
@RequestMapping(value = "/consumer/dept/get/{id}")
public Dept get(@PathVariable("id") Long id)
{
return this.service.get(id);
}
@RequestMapping(value = "/consumer/dept/list")
public List<Dept> list()
{
return this.service.list();
}
@RequestMapping(value = "/consumer/dept/add")
public Object add(Dept dept)
{
return this.service.add(dept);
}
}
集成了Rabbon,Ribbon+RestTemplate调用微服务 ==》接口+注解,调用接口的方式调用服务,即是在调用某个微服务的方式从使用RestTemplate的方式转为使用接口方式调用,Fegin还是可以使用Rabbon的负载均衡。
Hystrix
处理分布式系统的延迟和容错的开源库,分布式系统中,服务调用不可避免会有调用失败、超时、异常出现,Hystrix保证在服务出现为题时,不会导致整体服务失败,避免级联故障,提高分布式系统的弹性。当某个服务出现故障,通关断路器的故障监控,向调用方法返回一个符合预期的、可处理的备选响应,而不是进行等待或抛出异常,保证调用线程不会长时间等待、返回无用信息,避免故障蔓延。
使用方法
依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix</artifactId>
</dependency>
启用
@SpringBootApplication
@EnableEurekaClient
@EnableDiscoveryClient
@EnableCircuitBreaker //对hystrix熔断机制的支持
public class DeptProviderHystrix
{
public static void main(String[] args)
{
SpringApplication.run(DeptProviderHystrixp.class, args);
}
}
Controller
@RestController
public class DeptController
{
@Autowired
private DeptService service = null;
//调用服务方法失败并抛出了错误信息
//自动调用@HystrixCommand标注好的fallbackMethod调用类中的指定方法
@HystrixCommand(fallbackMethod = "processHystrix_Get")
@RequestMapping(value = "/dept/get/{id}", method = RequestMethod.GET)
public Dept get(@PathVariable("id") Long id)
{
Dept dept = this.service.get(id);
if (null == dept) {
throw new RuntimeException("该ID:" + id + "没有没有对应的信息");
}
return dept;
}
//类似异常通知
public Dept processHystrix_Get(@PathVariable("id") Long id)
{
return new Dept().setDeptno(id).setDname("该ID:" +id + "没有没有对应的信息,null--@HystrixCommand")
.setDb_source("no this database in MySQL");
}
}
熔断机制,当微服务在某个服务处发生了超时、异常时,由Hystrix返回一个结果,结果符合调用服务者的要求。举例实际使用,需要重写FallbackFactory接口并在Feign注解中配置fallbackFactory,即可实现异常处理与业务模块分离,解耦和。
服务降级
服务降级在客户端完成,暂时关闭服务,为其他服务节省资源,当服务关闭后,Hystrix依旧会为接口调用时返回一个信息。
//实现FallbackFactory接口
@Component
public class DeptClientServiceFallbackFactory implements FallbackFactory<DeptClientService>
{
@Override
public DeptClientService create(Throwable throwable)
{
return new DeptClientService() {
@Override
public Dept get(long id)
{
return new Dept().setDeptno(id).setDname("该ID:" + id + "没有没有对应的信息")
.setDb_source("no this database in MySQL");
//,Consumer客户端提供的降级信息,此刻服务Provider已经关闭
}
@Override
public List<Dept> list()
{
return null;
}
@Override
public boolean add(Dept dept)
{
return false;
}
};
}
}
HystrixDashboard
服务监控,持续记录通过Hystrix发起的请求的执行信息,并以统计报表和图形的形式展现给用户,即微服务的图形化监控。
依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix-dashboard</artifactId>
</dependency>
主类
@SpringBootApplication
@EnableHystrixDashboard
public class DeptConsumerDashBoard
{
public static void main(String[] args)
{
SpringApplication.run(DeptConsumerDashBoard.class, args);
}
}
服务
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
监控指标
- Delay:轮询监控信息的延迟事件,默认2000毫秒
- Title:监控标题
- 失败
- 超时
- 成功
- 错误请求
- 拒绝
- 短路
- 错误
Zuul路由网关
路由功能,对外部请求进行转发,即外部访问与服务的路由网关,提供过滤、路由功能,将以一个服务注册到Eureka中,同时实现网关功能,可以配置其他服务的路由访问规则。
依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zuul</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
配置
server:
port: 9527 //server_port
//服务将通过路由进行访问
spring:
application:
name: microservicecloud-zuul-gateway
eureka:
client:
service-url:
defaultZone: eureka-ip
instance:
instance-id: intance_id
prefer-ip-address: true
zuul: //服务地址映射定义
#ignored-services: microservicecloud-dept //过滤服务地址访问
prefix: /prefix //公共前缀
ignored-services: "*" //过滤全部服务地址
routes:
mydept.serviceId: microservicecloud-dept
mydept.path: /myurl/**
info:
分布式配置中心
针对当出现大量的微服务时,提供一个配置中心,对微服务的配置进行集中管理。
服务端
-
在github中创建一个库并保存地址
-
在本地创建库并克隆创建的库
-
创建文件配置文件application.yml(UTF-8)
-
提交文件
server:
port: 3344
spring:
application:
name: microservicecloud-config
cloud:
config:
server:
git:
uri: *:*.git #GitHub上面的git仓库名字
客户端
bootstrap.xml
spring:
cloud:
config:
name: microservicecloud-config-client #需要从github上读取的资源名称,
#注意没有yml后缀名
profile: test #本次访问的配置项
label: master
uri: ip/url:3344 #本微服务启动后先去找3344号服务,
#通过SpringCloudConfig获取GitHub的服务地址
依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>