spring cloud介绍
spring cloud 是一系列框架的集合。它利用 spring boot 的开发便利性巧妙地简化了分布式系统基础设施的开发,如服务发现注册、配置中心、消息总线、负载均衡、断路器、数据监控等,都可以用 spring boot 的开发风格做到一键启动和部署。spring cloud 并没有重复制造轮子,它只是将目前各家公司开发的比较成熟、经得起实际考验的服务框架组合起来,通过 spring boot 风格进行再封装屏蔽掉了复杂的配置和实现原理,最终给开发者留出了一套简单易懂、易部署和易维护的分布式系统开发工具包。
spring cloud 对于中小型互联网公司来说是一种福音,因为这类公司往往没有实力或者没有足够的资金投入去开发自己的分布式系统基础设施,使用 spring cloud 一站式解决方案能在从容应对业务发展的同时大大减少开发成本。同时,随着近几年微服务架构和 docker 容器概念的火爆,也会让 spring cloud 在未来越来越“云”化的软件开发风格中立有一席之地,尤其是在目前五花八门的分布式解决方案中提供了标准化的、一站式的技术方案,意义可能会堪比当年 servlet 规范的诞生,有效推进服务端软件系统技术水平的进步。
spring cloud 技术组成
-
eureka
微服务治理,服务注册和发现 -
ribbon
负载均衡、请求重试 -
hystrix
断路器,服务降级、熔断
4. feign
ribbon + hystrix 集成,并提供声明式客户端
hystrix dashboard 和 turbine
hystrix 数据监控
5. zuul
API 网关,提供微服务的统一入口,并提供统一的权限验证
7. config
配置中心
8. bus
消息总线, 配置刷新
9. sleuth+zipkin
链路跟踪
Spring Cloud对比Dubbo
Spring Cloud:
优点:框架集,集成多种工具解决微服务中的多种问题;基于http协议,Rest调用;开源,易用,成本;
框架集
提供了一整套微服务解决方法(全家桶)
基于http调用,Rest API
Dubbo:
缺点:值解决远程调用问题;基于长连接,Java序列化调用;要解决微服务系统中其他问题,需要自己集成其他工具,或自研发解决方法
Dubbo只是一个远程嗲用(RPC)框架
默认基于长连接,支持多种序列化格式
Euraka
Euraka 和dubbo 对比
Eureka可以很好的应对网络故障导致部分节点失去联系的情况,而不会像zk那样因为选举导致整个集群不可用
dubbo + zk
当向注册中心查询服务注册列表时,可以容忍注册中心返回的是几分钟以前的注册信息,但是不能接受服务直接down掉不可用。服务注册功能对可用性的要求高于一致性。在zk选举的时候,整个集群不可用,这样就导致注册服务瘫痪,漫长的选举期间导致整个注册服务长期不可用
Eureka 的AP
在设计的时候优先保证可用性。eureka的各个节点都是平等的,几个节点down掉不会影响其他节点的提供注册和查询服务的功能。而Eureka的客户端在向牧歌Eureka注册如果链接失败,则会自动切换到其他节点,只要有一台Eureka正常工作,就能保证注册服务可用,只不过查询服务的结果可能不是最新的(不保证强一致性)。除此之外,Eureka还有一种自我保护机制,如果在15分钟内,85%的节点都没有正常的心跳,那么Eureka就认为客户端与注册中心出现了网络故障,此时会出现以下几种情况:
Eureka不再从注册列表中移除因为长时间没有收到心跳的而过期的服务;
Eureka仍然能够接收新的服务注册和查询请求,但不会同步到其他节点(保证当前节点依然可用);
当网络稳定时,当前实例新的注册信息会同步到其他节点;
Euraka功能
Register:服务注册
当Eureka客户端向Eureka Server注册时,它提供自身的元数据,比如IP地址、端口,运行状况指示符URL,主页等。
Renew:服务续约
Eureka客户会每隔30秒发送一次心跳来续约。 通过续约来告知Eureka Server该Eureka客户仍然存在,没有出现问题。 正常情况下,如果Eureka Server在90秒没有收到Eureka客户的续约,它会将实例从其注册表中删除。 建议不要更改续约间隔。
Fetch Registries:获取注册列表信息
Eureka客户端从服务器获取注册表信息,并将其缓存在本地。客户端会使用该信息查找其他服务,从而进行远程调用。该注册列表信息定期(每30秒钟)更新一次。每次返回注册列表信息可能与Eureka客户端的缓存信息不同, Eureka客户端自动处理。如果由于某种原因导致注册列表信息不能及时匹配,Eureka客户端则会重新获取整个注册表信息。 Eureka服务器缓存注册列表信息,整个注册表以及每个应用程序的信息进行了压缩,压缩内容和没有压缩的内容完全相同。Eureka客户端和Eureka 服务器可以使用JSON / XML格式进行通讯。在默认的情况下Eureka客户端使用压缩JSON格式来获取注册列表的信息。
Cancel:服务下线
Eureka客户端在程序关闭时向Eureka服务器发送取消请求。 发送请求后,该客户端实例信息将从服务器的实例注册表中删除。该下线请求不会自动完成,它需要调用以下内容:
DiscoveryManager.getInstance().shutdownComponent();
Eviction 服务剔除
在默认的情况下,当Eureka客户端连续90秒没有向Eureka服务器发送服务续约,即心跳,Eureka服务器会将该服务实例从服务注册列表删除,即服务剔除。
https://www.jianshu.com/p/eeb161b2a751
Eureka使用方法
1.引入依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>
spring-cloud-starter-netflix-eureka-server
</artifactId>
</dependency>
2.配置application.yml文件
#配置服务的名字
spring:
application:
name: eureka-server
#配置服务器端口号
server:
port: 2001
eureka:
instance:
#主机名:eureka集群中使用hostname来区分多台服务器
hostname: eureka1
server:
#自我保护模式开启,开发期间关闭保护模式
enable-self-preservation: false
client:
#集群中多台服务器要互相注册互相拉取
#单台服务器不注册不拉取
register-with-eureka: false
fetch-registry: false
3.在启动项上面加入@EnableEurekaServer
测试出现以下结果表示成功:
4.配置服务eureka的服务集群
4.0 修改host配置文件(SwitchHosts文件进行修改)
SwitchHosts下载链接:https://pan.baidu.com/s/1dET8Uq-W_0shVirDmyowUQ
提取码:2q39
4.1 在resources复制两个application.yml文件
取名分别为: application-eureka1.yml,application-eureka1.yml
application-eureka1.yml配置
eureka:
instance:
hostname: eureka1
client:
register-with-eureka: true
fetch-registry: true
service-url:
defaultZone: http://eureka2:2002/eureka
application-eureka2.yml配置
eureka:
instance:
hostname: eureka2
client:
fetch-registry: true
register-with-eureka: true
service-url:
defaultZone: http://eureka1:2001/eureka
4.2 创建多个eureka服务器集群
配置的数据: --spring.profiles.active=eureka1 --server.port=2001
配置的数据: --spring.profiles.active=eureka2 --server.port=2002
测试成功:
4.3 配置服务提供者(运行controller的启动项)
4.3.0 商店中加入EditStarters
4.3.1 添加服务提供者的依赖
命令:Alt+Insert
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
<exclusions>
<exclusion>
<artifactId>jackson-dataformat-xml</artifactId>
<groupId>com.fasterxml.jackson.dataformat</groupId>
</exclusion>
</exclusions>
</dependency>
4.3.2 配置application.yml配置文件
server:
port: 8001
spring:
application:
name: item-service
eureka:
client:
service-url:
defaultZone: http://eureka1:2001/eureka,http://eureka2:2002/eureka
4.3.3 配置多个服务提供者
4.3.4 启动项目
4.4 创建ribbon项目
4.4.1 创建ribbon项目
4.4.2 配置yml文件
spring:
application:
name: ribbon
server:
port: 3001
eureka:
client:
service-url:
defaultZone: http://eureka1:2001/eureka,http://eureka2:2002/eureka
4.4.3添加依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
<exclusions>
<exclusion>
<artifactId>jackson-dataformat-xml</artifactId>
<groupId>com.fasterxml.jackson.dataformat</groupId>
</exclusion>
</exclusions>
</dependency>
4.4.4 配置启动项
package cn.tedu.sp06;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
@SpringBootApplication
public class Sp06RibbonApplication {
public static void main(String[] args) {
SpringApplication.run(Sp06RibbonApplication.class, args);
}
@Bean
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
4.4.5 配置controller,加入你自己配置所有的controller路径
package cn.tedu.sp06.controller;
import cn.tedu.sp01.pojo.Item;
import cn.tedu.sp01.pojo.Order;
import cn.tedu.sp01.pojo.User;
import cn.tedu.web.util.JsonResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;
import javax.ws.rs.Path;
import java.util.List;
@RestController
public class RibboController {
@Autowired
public RestTemplate restTemplate;
@GetMapping("/item-service/{orderId}")
public JsonResult<List<Item>> getItemS(@PathVariable String orderId){
return restTemplate.getForObject("http://127.0.0.1:8001/{1}",JsonResult.class,orderId);
}
@PostMapping("/item-service/descreaseNumber")
public JsonResult<?> descreaseNumber(@RequestBody List<Item> items){
return restTemplate.postForObject("http://127.0.0.1:8001/descreaseNumber",items,JsonResult.class,items);
}
@GetMapping("/user-service/{userId}")
public JsonResult<User> getUser(@PathVariable Integer userId){
return restTemplate.getForObject("http://127.0.0.1:8101/{1}",JsonResult.class,userId);
}
@GetMapping("/user-server/{userId}/score")
public JsonResult addScore(@PathVariable Integer userId,Integer score){
return restTemplate.getForObject("http://127.0.0.1:8101/{1}/score",JsonResult.class,userId);
}
@GetMapping("/order-server/{orderId}")
public JsonResult<Order> getOrder(@PathVariable String orderId){
return restTemplate.getForObject("http://127.0.0.1:8201/{1}",JsonResult.class,orderId);
}
@GetMapping("/order-server/")
public JsonResult addOrder(){
return restTemplate.getForObject("http://127.0.0.1:8201/",JsonResult.class);
}
}