1. 什么是微服务
微服务最早由Martin Fowler与James Lewis于2014年共同提出,微服务架构风格是一种使用一套小服务来开发单个应用的方式途径,每个服务运行在自己的进程中,并使用轻量级机制通信,通常是HTTP API,这些服务基于业务能力构建,并能够通过自动化部署机制来独立部署,这些服务使用不同的编程语言实现,以及不同数据存储技术,并保持最低限度的集中式管理。
2. 为什么需要微服务
在传统的IT行业软件大多都是各种独立系统的堆砌,这些系统的问题总结来说就是扩展性差,可靠性不高,维护成本高。到后面引入了SOA服务化,但是,由于 SOA 早期均使用了总线模式,这种总线模式是与某种技术栈强绑定的,比如:J2EE。这导致很多企业的遗留系统很难对接,切换时间太长,成本太高,新系统稳定性的收敛也需要一些时间。
3.微服务与单体架构区别
(1)单体架构所有的模块全都耦合在一块,代码量大,维护困难。
微服务每个模块就相当于一个单独的项目,代码量明显减少,遇到问题也相对来说比较好解决。
复制代码
(2)单体架构所有的模块都共用一个数据库,存储方式比较单一。
微服务每个模块都可以使用不同的存储方式(比如有的用redis,有的用mysql等),数据库也是单个模块对应自己的数据库。
复制代码
(3)单体架构所有的模块开发所使用的技术一样。
微服务每个模块都可以使用不同的开发技术,开发模式更灵活。
复制代码
4. 微服务本质
(1)微服务,关键其实不仅仅是微服务本身,而是系统要提供一套基础的架构,这种架构使得微服务可以独立的部署、运行、升级,不仅如此,这个系统架构还让微服务与微服务之间在结构上“松耦合”,而在功能上则表现为一个统一的整体。这种所谓的“统一的整体”表现出来的是统一风格的界面,统一的权限管理,统一的安全策略,统一的上线过程,统一的日志和审计方法,统一的调度方式,统一的访问入口等等。
(2)微服务的目的是有效的拆分应用,实现敏捷开发和部署 。
(3)微服务提倡的理念团队间应该是 inter-operate, not integrate 。inter-operate是定义好系统的边界和接口,在一个团队内全栈,让团队自治,原因就是因为如果团队按照这样的方式组建,将沟通的成本维持在系统内部,每个子系统就会更加内聚,彼此的依赖耦合能变弱,跨系统的沟通成本也就能降低。
5. 微服务开发框架
目前微服务的开发框架,最常用的有以下四个:
Spring Cloud:projects.spring.io/spring-clou…
Dubbo:http://dubbo.io
Dropwizard:www.dropwizard.io (关注单个微服务的开发)
Consul、etcd&etc.(微服务的模块)
6. 什么是SpringCloud
Spring Cloud是一系列框架的集合。它利用Spring Boot的开发便利性简化了分布式系统基础设施的开发,如服务发现、服务注册、配置中心、消息总线、负载均衡、 熔断器、数据监控等,都可以用Spring Boot的开发风格做到一键启动和部署。Spring并没有重复制造轮子,它只是将目前各家公司开发的比较成熟、经得起实际考验的服务框架组合起来,通过SpringBoot风格进行再封装屏蔽掉了复杂的配置和实现原理,最终给开发者留出了一套简单易懂、易部署和易维护的分布式系统开发工具包
7. SpringBoot和SpringCloud关系
Spring Boot 是 Spring 的一套快速配置脚手架,可以基于Spring Boot 快速开发单个微服务,Spring Cloud是一个基于Spring Boot实现的开发工具;Spring Boot专注于快速、方便集成的单个微服务个体,Spring Cloud关注全局的服务治理框架; Spring Boot使用了默认大于配置的理念,很多集成方案已经帮你选择好了,能不配置就不配置,Spring Cloud很大的一部分是基于Spring Boot来实现,必须基于Spring Boot开发。可以单独使用Spring Boot开发项目,但是Spring Cloud离不开 Spring Boot。
8. SpringCloud相关基础服务组件
服务发现——Netflix Eureka (Nacos)
服务调用——Netflix Feign
熔断器——Netflix Hystrix
服务网关——Spring Cloud GateWay
分布式配置——Spring Cloud Config (Nacos)
消息总线 —— Spring Cloud Bus (Nacos)
8.1 nacos的使用
8.1.1 下载nacos
- 下载地址:github.com/alibaba/nac… 解压到任意目录即可
- 启动nacos服务
- Linux/Unix/Mac
启动命令(standalone代表着单机模式运行,非集群模式)
启动命令:sh startup.sh -m standalone
- Windows
启动命令:cmd startup.cmd 或者双击startup.cmd运行文件。
访问:http://localhost:8848/nacos
用户名密码:nacos/nacos
8.2 服务注册
1. 在模块中添加依赖
<!--服务注册-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
<version>****<version>
</dependency>
复制代码
2.在模块的application.properties配置文件中添加以下配置
#配置服务名称
spring.application.name=service-edu
# nacos服务地址
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
复制代码
3. 在该模块的启动类上添加注解
@EnableDiscoveryClient
复制代码
4. 在浏览器中启动nacos客户端
启动注册中心
启动已注册的微服务,可以在Nacos服务列表中看到被注册的微服务
8.3 服务调用 (Feign)
1. 在模块中添加依赖
<!--服务调用-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
复制代码
2. 在调用端的启动类上加上注解(如下图)
3. 在调用端模块中创建对应的包和接口
- 创建client包
- @FeignClient注解用于指定从哪个服务中调用功能 ,名称与被调用的服务名保持一致。
- @GetMapping注解用于对被调用的微服务进行地址映射。
- @PathVariable注解一定要指定参数名称,否则出错
- @Component注解防止,在其他位置注入CodClient时idea报错
接口内容如下:
4. 在业务层中注入该接口,即可进行调用了!
8.4 熔断器(Hystrix)
springCloud调用接口的过程如下:
(1)接口化请求调用当调用被@FeignClient注解修饰的接口时,在框架内部,将请求转换成Feign的请求实例feign.Request,交由Feign框架处理。
(2)Feign :转化请求Feign是一个http请求调用的轻量级框架,可以以Java接口注解的方式调用Http请求,封装了Http调用流程。
(3)Hystrix:熔断处理机制 Feign的调用关系,会被Hystrix代理拦截,对每一个Feign调用请求,Hystrix都会将其包装成HystrixCommand,参与Hystrix的流控和熔断规则。如果请求判断需要熔断,则Hystrix直接熔断,抛出异常或者使用FallbackFactory返回熔断Fallback结果;如果通过,则将调用请求传递给Ribbon组件。
(4)Ribbon:服务地址选择 当请求传递到Ribbon之后,Ribbon会根据自身维护的服务列表,根据服务的服务质量,如平均响应时间,Load等,结合特定的规则,从列表中挑选合适的服务实例,选择好机器之后,然后将机器实例的信息请求传递给Http Client客户端,HttpClient客户端来执行真正的Http接口调用;
(5)HttpClient :Http客户端,真正执行Http调用根据上层Ribbon传递过来的请求,已经指定了服务地址,则HttpClient开始执行真正的Http请求
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>
复制代码
- 在配置文件中开启熔断器配置
#开启熔断机制
feign.hystrix.enabled=true
# 设置hystrix超时时间,默认1000ms
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=6000
复制代码
- 在client(服务调用接口所在包)内创建熔断器的实现类
代码如下:
/**
* 当远程调用对应的方法失败发生熔断机制时将会执行这个类的方法!
* orderClient:服务调用类 见本文->8.3.3
*/
@Component
public class VodFileDegradeFeignClient implements OrderClient {
@Override
public R isBuyCourse(String courseId,String memberId) {
return R.error().message("删除视频失败!");
}
}
复制代码
- 修改orderClient接口的注解
- 进行测试即可!
8.5 服务网关 GateWay (可以看成是一个单独的服务模块)
1. 网关介绍
API 网关出现的原因是微服务架构的出现,不同的微服务一般会有不同的网络地址,而外部客户端可能需要调用多个服务的接口才能完成一个业务需求,如果让客户端直接与各个微服务通信,会有以下的问题:
(1)客户端会多次请求不同的微服务,增加了客户端的复杂性。
(2)存在跨域请求,在一定场景下处理相对复杂。
(3)认证复杂,每个服务都需要独立认证。
(4)难以重构,随着项目的迭代,可能需要重新划分微服务。例如,可能将多个服务合并成一个或者将一个服务拆分成多个。如果客户端直接与微服务通信,那么重构将会很难实施。
(5)某些微服务可能使用了防火墙 / 浏览器不友好的协议,直接访问会有一定的困难。
以上这些问题可以借助 API 网关解决。API 网关是介于客户端和服务器端之间的中间层,所有的外部请求都会先经过 API 网关这一层。也就是说,API 的实现方面更多的考虑业务逻辑,而安全、性能、监控可以交由 API 网关来做,这样既提高业务灵活性又不缺安全性
2. GateWay网关的使用
- 创建一个独立的GateWay模块
2. 导入依赖
<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-gateway</artifactId>
</dependency>
<!--gson-->
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
</dependency>
<!--服务调用-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
复制代码
- 编写application.properties配置文件
# 端口号
server.port=8010
#服务名字
spring.application.name=service-getway
#nacos服务地址
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
#使用服务发现路由 true才能发现nacos中的其他路由
spring.cloud.gateway.discovery.locator.enabled=true
#设置路由id
#******* id可以随便取,一般与服务名称相同 *******
spring.cloud.gateway.routes[0].id=service-edu
#设置路由的uri (必须为在nacos中的服务名称)
spring.cloud.gateway.routes[0].uri=lb://service-edu
#设置路由断言,代理servicerId为auth-service的/auth/路径
#**************** /eduservice/ 就是controller上的@RequestMapping注解中的路径,根据路径进行匹配转发*************
spring.cloud.gateway.routes[0].predicates= Path=/eduservice/**
#配置service-edu服务
spring.cloud.gateway.routes[1].id=service-oss
spring.cloud.gateway.routes[1].uri=lb://service-oss
spring.cloud.gateway.routes[1].predicates= Path=/eduoss/**
spring.cloud.gateway.routes[2].id=service-cms
spring.cloud.gateway.routes[2].uri=lb://service-cms
spring.cloud.gateway.routes[2].predicates= Path=/educms/**
spring.cloud.gateway.routes[3].id=service-ucenter
spring.cloud.gateway.routes[3].uri=lb://service-ucenter
spring.cloud.gateway.routes[3].predicates= Path=/eduucenter/**
spring.cloud.gateway.routes[4].id=service-statistics
spring.cloud.gateway.routes[4].uri=lb://service-statistics
spring.cloud.gateway.routes[4].predicates= Path=/edustatistics/**
spring.cloud.gateway.routes[5].id=service-order
spring.cloud.gateway.routes[5].uri=lb://service-order
spring.cloud.gateway.routes[5].predicates= Path=/eduorder/**
spring.cloud.gateway.routes[6].id=service-vod
spring.cloud.gateway.routes[6].uri=lb://service-vod
spring.cloud.gateway.routes[6].predicates= Path=/eduvod/**
spring.cloud.gateway.routes[7].id=service-acl
spring.cloud.gateway.routes[7].uri=lb://service-acl
spring.cloud.gateway.routes[7].predicates= Path=/*/acl/**
#spring.cloud.gateway.routes[7].id=service-oss
#spring.cloud.gateway.routes[7].uri=lb://service-oss
#spring.cloud.gateway.routes[7].predicates= Path=/eduoss/**
#....................
复制代码
- 编写启动类
@SpringBootApplication
@EnableDiscoveryClient
public class GetwayApplication {
public static void main(String[] args) {
SpringApplication.run(GetwayApplication.class,args);
}
}
复制代码
3. 网关相关的配置
1. 解决跨域问题
- 创建配置类
代码如下:
// 解决前后端跨域
@Configuration
public class CorsConfig {
@Bean
public CorsWebFilter corsFilter() {
CorsConfiguration config = new CorsConfiguration();
config.addAllowedMethod("*");
config.addAllowedOrigin("*");
config.addAllowedHeader("*");
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(new PathPatternParser());
source.registerCorsConfiguration("/**", config);
return new CorsWebFilter(source);
}
}
复制代码
结语:剩下的还有很多,但是自己目前还不太了解,当成一种学习记录,就先不继续深入下去了,以后学习更多了再慢慢不断完善!
推荐微服务介绍文章:www.zhihu.com/question/65…
内容参考:尚硅谷谷粒学院