微服务
微服务架构风格是一种使用一套小服务来开发单个应用的方式途径,每个服务运行在自己的进程中,并使用轻量级机制通信,通常是HTTP API,这些服务基于业务能力构建,并能够通过自动化部署机制来独立部署,这些服务使用不同的编程语言实现,以及不同数据存储技术,并保持最低限度的集中式管理。
微服务特点
- 模块独立,代码量减少
- 模块可采用不同的存储方式(redis、mysql等)
- 开发灵活,便于维护
微服务开发框架
目前微服务的开发框架,最常用的有以下四个:
Spring Cloud:http://projects.spring.io/spring-cloud(现在非常流行的微服务架构)
Dubbo:http//dubbo.io
Dropwizard:http://www.dropwizard.io (关注单个微服务的开发)
Consul、etcd&etc.(微服务的模块)
什么是SpringCloud
Spring Cloud并不是一种技术,他是一系列技术框架的集合。它利用 Spring Boot 的开发便利性简化了分布式系统基础设施的开发,如服务发现、服务注册、配置中心、消息总线、负载均衡、 熔断器、数据监控等,都可以用 SpringBoot 的开发风格做到一键启动和部署
Spring Cloud和Spring Boot是什么关系
SpringBoot:
- 快速开发单个微服务
- 专注于快速、方便集成的单个微服务个体
- 使用了默认大于配置的理念
- 可以单独使用
SpringCloud:
-
基于 Spring Boot 实现的开发工具,必须基于Spring Boot开发
-
关注全局的服务治理框架
Spring Cloud相关基础服务组件
-
服务发现——Netflix Eureka (
Nacos
) -
服务调用——Netflix Feign
-
熔断器 ——Netflix Hystrix
-
服务网关 ——Spring Cloud GateWay
-
分布式配置——Spring Cloud Config (
Nacos
) -
消息总线 —— Spring Cloud Bus (
Nacos
)
常见的注册中心:
-
Eureka(原生,2.0遇到性能瓶颈,停止维护)
-
Zookeeper(支持,专业的独立产品。例如:dubbo)
-
Consul(原生,GO语言开发)
-
Nacos
Nacos主要提供以下四大功能:
- 服务发现和服务健康监测
- 动态配置服务
- 动态DNS服务
- 服务及其元数据管理
Nacos下载和安装
下载地址:https://github.com/alibaba/nacos/releases
启动nacos服务
启动命令:cmd startup.cmd 或者双击startup.cmd运行文件。
访问:http://localhost:8848/nacos
用户名密码:nacos/nacos
服务注册
配置 Nacos 客户端的 pom 依赖
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
添加服务配置信息
# nacos注册中心
spring.cloud.nacos.discovery.server-addr= localhost:8848
添加Nacos客户端注解
在客户端微服务启动类中添加注解
@EnableDiscoveryClient //服务发现功能
启动客户端微服务
启动已注册的微服务,可以在 Nacos 服务列表中看到被注册的微服务
服务调用-Feign
Feign是Netflix开发的声明式、模板化的HTTP客户端, Feign可以帮助我们更快捷、优雅地调用HTTP API
Spring Cloud Feign是基于Netflix feign实现,整合了Spring Cloud Ribbon和Spring Cloud Hystrix,除了提供这两者的强大功能外,还提供了一种声明式的Web服务客户端定义的方式。
只需要创建一个接口并用注解方式配置它,即可完成服务提供方的接口绑定,简化了在使用Spring Cloud Ribbon时自行封装服务调用客户端的开发量。
调用端启动类注解
@EnableFeignClients
创建包和接口
@FeignClient注解
用于指定从哪个服务中调用功能 ,名称与被调用的服务名保持一致。
@GetMapping注解
用于对被调用的微服务进行地址映射。
@PathVariable注解
一定要指定参数名称,否则出错
@Component注解
防止,在其他位置注入VodClient时idea报错
@Component
@FeignClient("service-vod")//指定调用的服务名,前提要注册到nacos注册中心
public interface VodClient {//根据视频id删除阿里云视频@DeleteMapping("/eduvod/video/removeAliyunVideoById/{id}")public R removeAliyunVideoById(@PathVariable("id") String id);}
调用微服务
在【调用端】的VideoServiceImpl中调用client中的方法
@Autowired
private VodClient vodClient;//根据课程id删除小节
@Override
public void removeVideoByCourseId(String id) {//查询云端视频idEduVideo eduVideo = baseMapper.selectById(id);String videoSourceId = eduVideo.getVideoSourceId();//判断小节中是否有对应的视频文件if (!StringUtils.isEmpty(videoSourceId)){//有就删除vodClient.removeAliyunVideoById(videoSourceId);}//删除小节baseMapper.deleteById(id);}
Spring Cloud调用接口过程
Feign -----> Hystrix —> Ribbon —> Http Client
先接口化请求调用,对指定请求的地址进行设定,并交给Feign过来;Feign实际去请求远程提供的接口;如果中途出现异常由Hystrix来中断和熔断服务;如果请求是一个集群,当请求传递给Ribbon后,会根据各个因素和设定的规则来选择要请求的哪个服务器接口来处理,最后httpClient来获取请求并执行调用最后的方法并返回
Feign结合Hystrix使用
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
<!--hystrix依赖,主要是用 @HystrixCommand -->
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
<!--服务注册-->
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!--服务调用-->
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
hystrix配置
在调用端配置
#开启熔断机制
feign.hystrix.enabled=true# 设置hystrix超时时间,默认1000ms
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=6000
client包里面创建熔断器的实现类
@Component //教给spring管理
public class VodClientImpl implements VodClient {//出错之后会执行,兜底方法@Overridepublic R removeAliyunVideoById(String id) {return R.error().message("删除视频出错了");}@Overridepublic R removeBatch(List<String> videoIdList) {return R.error().message("删除多个视频出错了");}
}
修改VodClient接口的注解
@Component
@FeignClient(value = "service-vod",fallback = VodClientImpl.class)//指定调用的服务名,前提要注册到nacos注册中心中
public interface VodClient {//根据视频id删除阿里云视频@DeleteMapping("/eduvod/video/removeAliyunVideoById/{id}")public R removeAliyunVideoById(@PathVariable("id") String id);//根据多个视频id删除多个阿里云视频@DeleteMapping("/eduvod/video/removeBatch")public R removeBatch(@RequestParam("videoIdList") List<String> videoIdList);}