文章目录
- 一.单体架构和分布式架构的区别
- 1.单体架构
- 2.分布式架构
- 二.微服务
- 1.微服务的架构特征
- 2.微服务技术对比
- 3.企业需求
- 4.微服务的远程定义
- 5.提供者与消费者
- 三.Eureka注册中心
- 1.eureka的作用
- 2.搭建EurekaServer
- 3.Eureka注册
- 3.服务拉取
- 四.Ribbon负载均衡
- 1.负载均衡流程
- 2.负载均衡策略
- 3.修改负载均衡策略
- 4.加载方式
- 五.Nacos注册中心
- 1.认识Nacos
- 2.服务注册到Nacos
- 3.Nacos服务分级存储模型
- 4.集群
- 5.根据权重负载均衡
- 6.环境隔离-namespace
- 7.临时实例和非临时实例
- 六.Nacos配置管理
- 1.统一配置管理
- 2.配置自动刷新
- 3.多环境配置共享
- 4.Nacos生产环境下一定要部署为集群状态
- 七.http客户端Feign
- 1.RestTemplate方式调用存在的问题
- 2.Feign的使用
- 3.自定义Feign的配置
- 八.统一网关GateWay
- 1.网关功能
- 2.网关的技术实现
- 3.搭建网关服务的步骤
一.单体架构和分布式架构的区别
1.单体架构
(1)什么是单体架构
将业务的所有功能集中在一个项目中开发,打成一个包部署
(2)单体架构的优缺点
优点:①架构简单②部署成本低
缺点:耦合度高(维护困难、升级困难)
2.分布式架构
(1)什么是分布式架构
根据业务功能对系统开发,每个业务功能模块作为独立项目开发,称为一个服务
(2)分布式架构的优缺点
优点:①降低服务耦合②有利于服务升级和扩展
缺点:服务调用关系错综复杂
二.微服务
1.微服务的架构特征
(1)单一职责:微服务拆分粒度更小,每个服务都对应唯一的业务能力,做到单一职责
(2)自治:团队独立、技术独立、数据独立,独立部署和交付
(3)面向服务:服务提供统一标准的接口,与语言和技术无关
(4)隔离性强:服务调用做好隔离、容错、降级,避免出现级联问题
微服务的上述特征其实是在给分布式架构制定一个标准,进一步降低服务之间的耦合度,提供服务的独立性和灵活性。做到
高内聚,低耦合。因此,可以认为微服务是一种经过良好架构设计的分布式架构方案。
2.微服务技术对比
3.企业需求
4.微服务的远程定义
(1)创建相关数据库和配置如下
①数据库cloud_user中的tb_user表:
②数据库cloud_order中的tb_order表:
③userservice服务的application.xml配置
server:
port: 8081
spring:
application:
name: userservice
datasource:
url: jdbc:mysql://localhost:3306/cloud_user?useSSL=false
username: root
password: root
driver-class-name: com.mysql.jdbc.Driver
④orderservice服务的application.xml配置
server:
port: 8001
spring:
application:
name: ordeservice
datasource:
url: jdbc:mysql://localhost:3306/cloud_order?useSSL=false
username: root
password: root
driver-class-name: com.mysql.jdbc.Driver
(2)创建RestTemplate并注入spring容器
(3)服务远程调用RestTemplate
(4)id为103的查询结果如下:
5.提供者与消费者
(1)服务提供者:一次业务中,被其他微服务调用的服务(提供接口给其他微服务)
(2)服务消费者:一次业务中,调用其他微服务的服务(调用其他微服务提供的接口)
(3)提供者与消费者角色其实是相对的,一个服务可以同时是服务提供者和服务消费者
三.Eureka注册中心
1.eureka的作用
(1)消费者该如何获取服务提供者具体信息?
①服务提供者启动时向eureka注册自己的信息
②eureka保存这些信息
③消费者根据服务名称向eureka拉取提供者信息
(2)如果有多个服务提供者,消费者该如何选择?
服务消费者利用负载均衡算法,从服务列表中挑选一个
(3)消费者如何感知服务提供者健康状态?
①服务提供者会每隔30秒向EurekaServer发送心跳请求,报告健康状态
②eureka会更新记录服务列表信息,心跳不正常会被剔除
③消费者就可以拉取到最新的信息
2.搭建EurekaServer
(1)创建项目,引入spring-cloud-starter-netflix-eureka-server的依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
(2)编写启动类,添加@EnableEurekaServer注解
(3)添加application.yml文件,编写配置
server:
port: 10086
spring:
application:
name: eurekaserver # eureka的服务器名称
eureka:
client:
service-url: # eureka的地址信息
defaultZone: http://127.0.0.1:10086/eureka/
3.Eureka注册
将user-service服务注册到EurekaServer步骤如下:
(1)在user-service项目中引入spring-cloud-starter-netflix-eureka-client的依赖
<!--eureka客户端依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
(2)在application.yml文件中,编写配置
spring:
application:
name: userservice
eureka:
client:
service-url: # eureka的地址信息
defaultZone: http://127.0.0.1:10086/eureka
(3)模拟多实例部署(为了避免端口冲突,需要修改端口设置)
3.服务拉取
服务拉取是基于服务名称获取服务列表,然后再对服务列表做负载均衡;在order-service完成服务拉取
(1)修改OrderService的代码,修改访问的url路径,用服务名代替ip、端口号:
String url = "http://orderservice/user/" + order.getUserId();
(2)在order-service项目的启动类OrderApplication中的RestTemplate添加负载均衡注解:
@LoadBalanced
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
四.Ribbon负载均衡
1.负载均衡流程
当请求进入Ribbon类以后,请求会被LoadBalancerInterceptor负载均衡拦截器给拦截,会得到请求中的服务名称(如userservice)。把它交给RibbonLoadBalancerClient,而RibbonLoadBalancerClient会把服务交给DynamicServiceListLoadBalancer,DynamicServiceListLoadBalancer它就会去eureka-server里拉取服务列表,得到多个服务的信息,找IRule做负载均衡,IRule会基于规则(比如轮询)把值返回给RibbonLoadBanlancerClient
2.负载均衡策略
3.修改负载均衡策略
(1)代码方式(全局配置,访问任何服务都可以):在order-service中的OrderApplication类中,定义一个新的IRule
@Bean
public IRule randomRule(){
return new RandomRule();
}
(2)配置文件方式(针对某个微服务而言):在order-service的application.yml文件中,添加新的配置也可以修改规则
userservice: # 服务名称
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule #负载均衡规则
4.加载方式
Ribbon默认采用的是懒加载,即第一次访问时才会创建LoadBalanceClient,请求时间会很长。而饥饿加载则会在
项目启动时创建,降低第一次访问的耗时,通过下面的配置开启饥饿加载:
ribbon:
eager-load:
enabled: true # 开启饥饿加载
clients: userservice # 指定对userservice这个服务饥饿加载
补充:
clients: # 指定对多个服务饥饿加载
- userservice
- xxxservice
五.Nacos注册中心
1.认识Nacos
Nacos是阿里巴巴的产品,现在是SpringCloud中的一个组件。相比Eureka功能更加丰富,在国内更受欢迎。
(1)在Nacos的GitHub页面,提供有下载链接,可以下载编译好的Nacos服务端或者源代码:
①GitHub主页:https://github.com/alibaba/nacos
②GitHub的Release下载页:https://github.com/alibaba/nacos/releases
(2)启动
进入bin目录,然后执行windows命令 startup.cmd -m standalone
单机启动
(3)成功页面如下(默认登陆账号密码都为nacos)
2.服务注册到Nacos
(1)在cloud-demo父工程中添加spring-cloud-alibaba的管理依赖
<!-- spring-cloud-alibaba -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2.2.6.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
(2)在order-service和user-service中添加nacos的客户端依赖
<!-- Nacos的客户端依赖 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
(3)配置user-service&order-service中的application.yml文件
spring:
cloud:
nacos:
server-addr: localhost:8848 # nacos服务端地址
(4)启动并测试
3.Nacos服务分级存储模型
(1)一级是服务,例如userservice(一个服务可以包含多个实例)
(2)二级是集群,例如上海或杭州
(3)三级是实例,例如杭州机房的某一台机器部署了userservice的服务器
4.集群
(1)在order-service中设置实例的集群属性
spring:
cloud:
nacos:
server-addr: localhost:8848 # nacos服务端地址
discovery:
cluster-name: HZ # 配置集群名称,也就是机房的位置,例如杭州
(2)在order-service中设置负载均衡的IRule为NacosRule,这个规则优先会寻找与自己同集群的服务:
userservice: # 服务名称
ribbon:
NFLoadBalancerRuleClassName: com.alibaba.cloud.nacos.ribbon.NacosRule #负载均衡规则
补充:NacosRule负载均衡策略
①优先选择同集群服务实例列表
②本地集群找不到提供者,才去其他集群寻找,并且会报警告
③确定了可用实例列表后,再采用随机负载均衡挑选实例
5.根据权重负载均衡
(1)在Nacos控制台可以设置实例的权重值(0~1之间)
(2)同集群内的多个实例,权重越高被访问的频率越高
(3)权重设置为0则完全不会被访问
6.环境隔离-namespace
Nacos中服务器和数据存储的最外层都是一个名为namespace的东西,用来做最外层隔离
(1)在Nacos控制台可以创建namespace,用来隔离不同环境
(2)然后填写一个新的命名空间信息
(3)保存之后会在控制台看到这个命名空间的id
(4)修改order-service的application.yml,添加namespace
spring:
cloud:
nacos:
server-addr: localhost:8848 # nacos服务端地址
discovery:
cluster-name: HZ # 配置集群名称,也就是机房的位置,例如杭州
namespace: 94cc0d41-4020-40fc-bc84-5ac7045a224e # 命名空间,填ID
(5)重启order-service后,再来看控制台:
(6)此时访问order-service,因为namespace不同,会导致找不到userservice,控制台会报错
补充:
①每个namespace都有唯一id
②服务设置namespace时要写id而不是全称
③不同namespace下的服务互相不可见
7.临时实例和非临时实例
服务注册到Nacos时,可以选择注册为临时或非临时实例,通过下面的配置来设置:
spring:
cloud:
nacos:
server-addr: localhost:8848 # nacos服务端地址
discovery:
cluster-name: HZ # 配置集群名称,也就是机房的位置,例如杭州
ephemeral: false # 设置为非临时实例
临时实例宕机时,会从nacos的服务列表中剔除,而非临时实例则不会
六.Nacos配置管理
1.统一配置管理
(1)在Nacos中添加配置信息
(2)在弹出表单中填写配置信息:
①Data ID:服务名称+当前项目的运行环境.后缀名(如:userservice-dev.yaml)
②Group:一般不用改,默认就行
③描述:介绍配置文件是干什么的
④配置内容:有热更新需求的配置在这里
(3)引入Nacos的配置管理客户端依赖:
(4)在userservice的resource目录下添加一个bootstrap.yml文件
注意:bootstrap.yml比application.yml优先级高很多,把nacos地址、文件相关信息等放到bootstrap.yml里面,就可以完成nacos配置
文件的读取
2.配置自动刷新
Nacos中的配置文件变更后,微服务无需重启就可以感知。不过需要通过下面两种配置实现:
(1)方式一:在@Value注入的变量所在的类上添加注解@RefreshScope
(2)方式二:使用@ConfigurationProperties注解
3.多环境配置共享
微服务启动时会从nacos中读取多个配置文件:
(1)服务名-环境.后缀,例如:userservice-dev.yaml
(2)服务名.后缀,例如:userservice.yaml
无论环境如何变化,服务名.后缀这个文件一定会被加载。因此,多环境共享配置可以写入这个文件
(3)多种配置的优先级:
4.Nacos生产环境下一定要部署为集群状态
七.http客户端Feign
1.RestTemplate方式调用存在的问题
(1)我们先来看看以前利用RestTemplate发起远程调用的代码:
String url = "http://userservice/user/" + order.getUserId();
User user = restTemplate.getForObject(url, User.class);
(2)存在下面的问题:
①代码可读性差,编程体验不统一
②参数复杂的URL难以维护
2.Feign的使用
Feign是一个声明式的http客户端,其作用就是帮助我们优雅的实现http请求的发送,解决RestTemplate
方式调用所存在的问题
(1)引入依赖:
<!-- Feign的依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
(2)在调用者(order-service)的启动类上添加注解并开启Feign的功能
(3)创建clients包,编写Feign的客户端
@FeignClient("userservice")
public interface UserClient {
@GetMapping("/user/{id}")
User findById(@PathVariable("id") Long id);
}
Feign的客户端主要是基于SpringMVC的注解来声明远程调用的信息,比如:
①服务名称:userservice
②请求方式:GET
③请求路径:/user/{id}
④请求参数:Long id
⑤返回值类型:User
(4)用Feign客户端代替RestTemplate
@Autowired
private UserClient userClient;
public Order queryOrderById(Long orderId) {
// 1.查询订单
Order order = orderMapper.findById(orderId);
//2.利用Feign发起http请求,查询用户
User user = userClient.findById(order.getUserId());
//3.封装User到Order
order.setUser(user);
//4.返回
return order;
3.自定义Feign的配置
(1)Feign运行自定义配置来覆盖默认配置,可以修改的配置如下:
注意:一般我们需要配置的就是日志级别
(2)配置Feign日志有两种方式
方式一:配置文件方式
①全局生效
②局部生效
方式二:java代码方式,需要先声明一个Bean:
(1)自定义一个配置类
public class FeignClientConfiguration {
@Bean
public Logger.Level feignLogLevel(){
return Logger.Level.BASIC;
}
}
①如果是全局配置,把它放到@EnableFeignClients这个注解中
@EnableFeignClients(defaultConfiguration = FeignClientConfiguration.class)
public class OrderApplication {
public static void main(String[] args) {
SpringApplication.run(OrderApplication.class, args);
}
②如果是局部配置,把它放到@FeignClient这个注解中
@FeignClient(value = "userservice",configuration = FeignClientConfiguration.class)
public interface UserClients {
@GetMapping("/user/{id}")
User findById(@PathVariable("id") Long id);
}
八.统一网关GateWay
1.网关功能
(1)身份认证和权限较验
(2)服务路由(选择需要的微服务)、负载均衡
(3)请求限流
2.网关的技术实现
在SpringCloud中网关的实现包括两种:
(1)gateway(2)zuul
Zuul是基于Servlet的实现,属于阻塞式编程。而SpringCloudGateway是基于Spring5中提供的WebFlux,属于响应式编程的实现,具备更好的性能。
3.搭建网关服务的步骤
(1)创建新的module,引入SpringCloudGateway的依赖和Nacos的服务发现依赖:
<!-- 网关依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!-- nacos服务发现依赖-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
(2)编写路由配置及nacos地址
server:
port: 10010 # 网关端口
spring:
application:
name: gateway # 服务名称
cloud:
nacos:
server-addr: localhost:8848 # nacos地址
gateway:
routes: # 网关路由配置
- id: user-service # 路由id,自定义,只要唯一即可
# uri: http://127.0.0.1:8081 # 路由的目标地址 http就是固定地址
uri: lb://userservice # 路由的目标地址 lb就是负载均衡,后面跟服务名称
predicates: # 路由断言,也就是判断请求是否符合路由规则的条件
- Path=/user/** # 这个是按照路径匹配,只要以/user/开头就符合要求
- id: order-service # 路由id,自定义,只要唯一即可
uri: lb://orderservice # 路由的目标地址 lb就是负载均衡,后面跟服务名称
predicates: # 路由断言,也就是判断请求是否符合路由规则的条件
- Path=/order/** # 这个是按照路径匹配,只要以/order/开头就符合要求
(3)网关路由可以配置的内容包括:
①路由id:路由唯一标识
②uri:路由目的地,支持lb和http两种
③predicates:路由断言,判断请求是否符合要求,符合则转发到路由目的地
④filters:路由过滤器,处理请求或响应