目录
一、微服务的诞生
▪ 随着用户的规模越来越大,业务需求越来越复杂,过去的单体架构无法支撑更大规模的并发量需求,且单个计算机的计算能力是有限的。
▪ 同时,用户规模越来越大,业务为了迎合不同用户的需求,所以整个业务体系会越来越复杂,项目的规模越来越大,迭代的效率和周期比较长!
▪ 所以为了解决单体架构项目的痛点,微服务诞生了,对于服务的更进一步的颗粒度拆分,实现敏捷迭代和单元隔离,通过分布式计算,用N台计算机组成一个计算机集群,提高并发计算能力。
▪ 分布式计算,意味着需要把同一个系统的不同业务维度的计算需求,拆分到不同的计算机上,通过系统的聚合,来达成完整的用户业务的链路!
关于SOA架构与微服务架构:
过去SOA架构是面向服务,以服务为单元,进行提炼和抽离;但面向服务的单个业务服务的颗粒度依然很大!而微服务则更进一步优化,是对于服务的更进一步的颗粒度拆分,主要达到敏捷迭代和单元隔离。
二、服务注册和发现
2.1 需求的产生
✅假设在流量突增的情况下,某个微服务被调用较多,为了应对更高的并发,我们进行了多实例部署,如图案例:
✅此时,每个item-service
的实例其IP或端口不同,那么就有以下几个问题:
-
item-service
这么多实例,cart-service
如何知道每一个实例的地址? -
http请求要写url地址,
cart-service
服务到底该调用哪个实例呢? -
如果在运行过程中,某一个
item-service
实例宕机,cart-service
依然在调用该怎么办? -
如果并发太高,
item-service
临时多部署了N台实例,cart-service
如何知道新实例的地址?
为了解决上述问题,就必须引入注册中心的概念了!
2.2 注册中心原理
✅注册中心是用于服务的注册与发现,管理微服务的地址信息。常见的组件包括:
▪ Spring Cloud Netflix:Eureka、Consul
▪ Spring Cloud Alibaba:Nacos
✅在微服务远程调用的过程中,包括两个角色:
-
服务提供者:提供接口供其它微服务访问,比如上面提到的
item-service
商品服务
-
服务消费者:调用其它微服务提供的接口,比如
cart-service购物车服务
注册中心、服务提供者、服务消费者三者间关系如下:
✅流程如下:
-
服务启动时就会注册自己的服务信息(服务名、IP、端口)到注册中心
-
调用者可以从注册中心订阅想要的服务,获取服务对应的实例列表(1个服务可能多实例部署)
-
调用者自己对实例列表负载均衡,挑选一个实例
-
调用者向该实例发起远程调用
✅当服务提供者的实例宕机或者启动新实例时,调用者如何得知呢?
-
服务提供者会定期向注册中心发送请求,报告自己的健康状态(心跳请求)
-
当注册中心长时间收不到提供者的心跳时,会认为该实例宕机,将其从服务的实例列表中剔除
-
当服务有新实例启动时,会发送注册服务请求,其信息会被记录在注册中心的服务实例列表
-
当注册中心服务列表变更时,会主动通知微服务,更新本地服务列表
2.3 Nacos注册中心
✅Nacos 是一个动态服务发现、配置管理和服务管理平台。
-
服务发现:Nacos 支持服务注册与发现,帮助微服务之间相互发现和调用。
-
配置管理:Nacos 提供统一的配置管理,支持动态配置更新。
-
服务管理:Nacos 提供了服务的健康检查、流量管理等功能。
2.4 Nacos安装部署教程
✅官网地址如下:
Nacos官网| Nacos 配置中心 | Nacos 下载| Nacos 官方社区 | Nacos 官网https://nacos.io/
✅在官网中下载nacos的tar包:(Docker镜像)
✅这里由于是基于Docker来部署Nacos的注册中心,首先我们要准备MySQL数据库表,用来存储Nacos的数据,最终表结构如图:
✅创建一个nacos文件夹,并新建一个custom.env文件,将下面的配置复制到该文件中:
PREFER_HOST_MODE=hostname
MODE=standalone
SPRING_DATASOURCE_PLATFORM=mysql
MYSQL_SERVICE_HOST=自己的虚拟机地址
MYSQL_SERVICE_DB_NAME=nacos
MYSQL_SERVICE_PORT=3306
MYSQL_SERVICE_USER=root
MYSQL_SERVICE_PASSWORD=root
MYSQL_SERVICE_DB_PARAM=characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai
注意要将自己的虚拟机地址写正确,这样nacos才能连接到我们的Mysql :
在虚拟机中导入我们下载的nacos.tar包和创建的nacos文件夹(在/root目录即可)
✅加载nacos镜像
docker load -i nacos.tar
✅加载完成后通过命令查看镜像是否加载成功
✅运用 Docker 来运行 Nacos 服务
docker run -d \
--name nacos \
--env-file ./nacos/custom.env \
-p 8848:8848 \
-p 9848:9848 \
-p 9849:9849 \
--restart=always \
nacos/nacos-server:v2.1.0-slim
✅通过docker ps 命令查看docker容器中的运行情况,若出现nacos则说明nacos服务启动成功!
✅我们可以通过命令查看Nacos运行日志,并且nacos的端口号为8848
docker logs -f nacos
✅在浏览器中访问 虚拟机地址 : 端口 / nacos
✅然后进入登录页面,用户名和密码均为nacos
✅登录成功我们就可以看到nacos的控制面板了!
到此,我们Nacos的安装和部署就完成了!
2.5 配置Nacos
✅引入依赖
<!--nacos 服务注册发现-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
✅在yml文件中进行配置
spring:
application:
name: item-service # 服务名称
cloud:
nacos:
server-addr: 192.168.31.128:8848 # nacos地址
✅ 复制启动项,模拟多实例(这里是对商品服务进行多实例部署)
✅新创建一个名字,并换一个端口(端口不能冲突)
✅启动购物车服务和商品服务(商品服务启动了两个实例)
✅启动后我们可以在nacos中看见car-service注册成功,实例数为1,item-service注册成功,实例数为2
到此关于Nacos的部署以及配置就完成了!接下来看看服务间是如何通过远程调用实现数据传输以及上游服务有时怎样从多个下游服务的实例中进行挑选的?
三、OpenFeign
3.1 认识OpenFeign
✅什么是OpenFeign?
OpenFeign是一个声明式的http客户端,是SpringCloud在Eureka公司开源的Fegin基础上改造而来,起作用就是基于SpringMVC常见注解,帮助我们更加方便优雅的实现http请求的发送。
简单来说,OpenFeign就是为了让我们在远程调用时可以像调用本地方法一样简单。
✅远程调用的关键点就在于四个:
• 请求方式
• 请求路径
• 请求参数
• 返回值类型
✅官网地址:
3.2 快速入门
由于OpenFeign已经被SpringCloud自动装配,所以实现起来非常简单!
3.2.1 引入依赖
✅引入OpenFeign依赖以及负载均衡组件SpringCloudLoadBalancer
<!--openFeign-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!--负载均衡器-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
▪ SpringCloud之前使用的负载均衡是Ribbon,现在则使用的是loadbalancer
3.2.2 启动OpenFeign
✅通过@EnableFeignClients注解,启动OpenFeign功能(在服务的启动类上添加)
3.2.3 编写OpenFeign客户端
✅定义一个新的接口,编写FeignClient
▪ 以购物车服务(cart-service)为例,我们需要远程调用商品服务(item-service)
▪ 有了上述信息,OpenFeign就可以利用动态代理帮我们实现这个方法,并且向http://item-service/items
发送一个GET
请求,携带 ids为请求参数,并自动将返回值处理为List<ItemDTO>
。
▪ 这样我们只需要直接调用这个方法,即可实现远程调用了。
▼ 源代码
package com.hmall.cart.client;
import com.hmall.cart.domain.dto.ItemDTO;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import java.util.Collection;
import java.util.List;
@FeignClient("item-service")
public interface ItemClient {
@GetMapping("/items")
List<ItemDTO> queryItemByIds(@RequestParam("ids") Collection<Long> ids);
}
3.2.4 使用FeignClient
✅使用FeignClient,实现远程调用
我们在 CartServiceImpl
中直接调用 ItemClient
的方法
这样,Feign就替我们完成了服务拉取、负载均衡、发送http请求的所有工作,看起来就方便优雅许多了。
我们可以通过swagger进行测试,访问购物车服务中的查询购物车列表接口,可以发现成功的查到了相关商品的信息!
3.3 连接池
✅Feign底层发起http请求,依赖于其它的框架,其底层支持的http客户端实现包括:
-
HttpURLConnection:默认实现,不支持连接池
-
Apache HttpClient :支持连接池
-
OKHttp:支持连接池
因此我们通常会使用带有连接池的客户端来代替默认的HttpURLConnection,这里我使用OKHttp作为示例来进行演示如何配置。
3.3.1 引入依赖
<!--OK http 的依赖 -->
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-okhttp</artifactId>
</dependency>
3.3.2 开启配置
在服务的 application.yml
配置文件中开启Feign的连接池功能:
feign:
okhttp:
enabled: true # 开启OKHttp功能
(重启服务,连接池就生效了)