微服务01

单体项目:所有的业务功能集中在一个项目中开发,打包成一个包部署

优点:架构简单,部署成本低

缺点:团队协作成本高,系统发布效率低,系统可用性差

合适开发功能相对简单,规模较小的项目。不适合复杂的项目

微服务

微服务架构,是服务化思想指导下的一套最佳实践架构方案。服务化,就是把单体架构的功能模块拆分成多个独立的项目。

拆分要求:粒度小,团队自治(开发独立),服务自治(打包,编译独立)

缺点:运维难度高,

SpringCloud

SpringCloud框架是目前Java领域较为全面的微服务组件集合。依托于SpringBoot的自动装配能力,大大降低了其项目搭建、组件使用的成本。

Spring Cloud

微服务拆分
微服务拆分原则

一般情况下,对于一个初创的项目,首先要做的是验证项目的可行性。因此这一阶段的首要任务是敏捷开发,快速产出生产可用的产品,投入市场做验证。为了达成这一目的,该阶段项目架构往往会比较简单,很多情况下会直接采用单体架构,这样开发成本比较低,可以快速产出结果,一旦发现项目不符合市场,损失较小。

所以,对于大多数小型项目来说,一般是先采用单体架构 ,随着用户规模扩大、业务复杂后再逐渐拆分为 微服务架构。这样初期成本会比较低,可以快速试错。但是,这么做的问题就在于后期做服务拆分时,可能会遇到很多代码耦合带来的问题,拆分比较困难。

而对于一些大型项目,在立项之初目的就很明确,为了长远考虑,在架构设计时就直接选择微服务架构。虽然前期投入较多,但后期就少了拆分服务的烦恼。

拆分目标:

之前我们说过,微服务拆分时粒度要小,这其实是拆分的目标。具体可以从两个角度来分析:

高内聚:每个微服务的职责要尽量单一,包含的业务相互关联度高、完整度高。

耦合:每个微服务的功能要相对独立,尽量减少对其它微服务的依赖,或者依赖接口的稳定性要强。

并且一定要保证微服务对外接口的稳定性(即:尽量保证接口外观不变)。虽然出现了服务间调用,但此时无论你如何在一个服务做内部修改,都不会影响到其他微服务,服务间的耦合度就降低了。

拆分方式:

纵向 拆分:所谓纵向拆分,就是按照项目的功能模块来拆分。例如,有用户管理功能、订单管理功能、购物车功能、商品管理功能、支付功能等。那么按照功能模块将他们拆分为一个个服务,就属于纵向拆分。这种拆分模式可以尽可能提高服务的内聚性。

横向拆分:是看各个功能模块之间有没有公共的业务部分,如果有将其抽取出来作为通用服务。例如用户登录是需要发送消息通知,记录风控数据,下单时也要发送短信,记录风控数据。因此消息发送、风控数据记录就是通用的业务功能,因此可以将他们分别抽取为公共服务:消息中心服务、风控管理服务。这样可以提高业务的复用性,避免重复开发。同时通用业务一般接口稳定性较强,也不会使服务之间过分耦合。

工程结构

一般微服务项目有两种不同的工程结构:

  • 完全解耦:每一个微服务都创建为一个独立的工程,甚至可以使用不同的开发语言来开发,项目完全解耦。

    • 优点:服务之间耦合度低

    • 缺点:每个项目都有自己的独立仓库,管理起来比较麻烦

  • Maven聚合:整个项目为一个Project,然后每个微服务是其中的一个Module

    • 优点:项目代码集中,管理和运维方便

    • 缺点:服务之间耦合,编译时间较长

远程调用

微服务进行拆分后,服务与服务之间的代码和数据库都物理分隔开了,为解决服务与服务之间的数据查询我们可以在java程序之间进行http请求。

RestTemplate

Spring给我们提供了一个RestTemplate的API,可以方便的实现Http请求的发送。

其中提供了大量的方法,方便我们发送Http请求,例如:

1.先将RestTemplate注册为一个Bean:

@Configuration

public class RemoteCallConfig {

@Bean

public RestTemplate restTemplate() {

return new RestTemplate();

}

}

2.发送远程调用

服务治理

通过Http请求实现的跨微服务的远程调用,这个方式存在一些问题。

假如某个微服务被调用较多,为了应对更高的并发,我们进行了多实例部署

此时,每个微服务的实例其IP或端口不同,问题来了:

  • 这么多实例,其他微服务如何知道每一个实例的地址?

  • http请求要写url地址,其他服务到底该调用哪个实例呢?

  • 如果在运行过程中,某一个实例宕机,其他服务依然在调用该怎么办?

  • 如果并发太高,临时多部署了N台实例,其他服务如何知道新实例的地址?

为了解决上述问题,就必须引入注册中心的概念了。

注册中心

在微服务远程调用的过程中,包括两个角色:

服务提供者:提供接口供其它微服务访问

服务消费者:调用其它微服务提供的接口

在大型微服务项目中,服务提供者的数量会非常多,为了管理这些服务就引入了注册中心的概念。注册中心、服务提供者、服务消费者三者间关系如下:

流程如下:

  • 服务启动时就会注册自己的服务信息(服务名、IP、端口)到注册中心

  • 调用者可以从注册中心订阅想要的服务,获取服务对应的实例列表(1个服务可能多实例部署)

  • 调用者自己对实例列表负载均衡,挑选一个实例

  • 调用者向该实例发起远程调用

当服务提供者的实例宕机或者启动新实例时,调用者如何得知呢?

  • 服务提供者会定期向注册中心发送请求,报告自己的健康状态(心跳请求)

  • 当注册中心长时间收不到提供者的心跳时,会认为该实例宕机,将其从服务的实例列表中剔除

  • 当服务有新实例启动时,会发送注册服务请求,其信息会被记录在注册中心的服务实例列表

  • 当注册中心服务列表变更时,会主动通知微服务,更新本地服务列表

服务注册

(需要搭建nacos注册中心,按名称管理服务实例)

启动多个实例,打开nacos注册中心页面可以发现服务注册成功

服务发现

服务的消费者要去nacos订阅服务,这个过程就是服务发现,步骤如下:

1.引入依赖

复制代码
<dependency>
<groupId>com.alibaba.cloud</groupId> 
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> 
</dependency>

2.配置Nacos地址

复制代码
spring: 
        cloud: 
                nacos: 
                        server-addr: xxx.xxx.xxx.xxx:8848

3.发现并调用服务

注册中心有多个实例的信息,而真正发起调用时只需要知道一个实例的地址。

服务调用者必须利用负载均衡的算法,从多个实例中挑选一个去访问。常见的负载均衡算法有:

1.随机

2.轮询

3.IP的hash

4.最近最少访问

另外,服务发现需要用到一个工具DiscoveryClient,SpringCloud已经帮我们自动装配,我们可以直接注入使用:

OpenFeign

OpenFeigin是一个声明式的http客户端,是作用就是基于SpringMVC常见注解来实现http请求的发送

其实远程调用的关键点就在于四个:

1.请求方式

2.请求路径

3.请求参数

4.返回值类型

所以,OpenFeign就利用SpringMVC的相关注解来声明上述4个参数,然后基于动态代理帮我们生成远程调用的代码,而无需我们手动再编写。

1.引入依赖

<!--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>

2.在启动项中加入注解@EnableFeignClients启用OpenFeign

3.编写OpenFeign客户端

4.使用OpenFeign客户端,实现远程调用

feign替我们完成了服务拉取、负载均衡、发送http请求的所有工作

连接池

使用其他http框架

重启服务,连接池就生效了。

最佳实践

方法一 服务暴露的接口客户端由对应项目组编写 项目结构复杂

方法二 耦合度高 横向拆分

日志

在api模块下新建一个配置类,定义Feign的日志级别:

接下来,要让日志级别生效,还需要配置这个类。有两种方式:

局部生效:在某个FeignClient中配置,只对当前FeignClient生效

@FeignClient(value = "item-service", configuration = DefaultFeignConfig.class)

全局生效:在@EnableFeignClients中配置,针对所有FeignClient生效。

@EnableFeignClients(defaultConfiguration = DefaultFeignConfig.class)

相关推荐
程序猿追4 分钟前
深度解码昇腾 AI 算力引擎:CANN Runtime 核心架构与技术演进
人工智能·架构
晚霞的不甘11 分钟前
CANN 编译器深度解析:TBE 自定义算子开发实战
人工智能·架构·开源·音视频
Zfox_28 分钟前
CANN Catlass 算子模板库深度解析:高性能 GEMM 融合计算、Cube Unit Tiling 机制与编程范式实践
docker·云原生·容器·eureka
程序猿追43 分钟前
昇腾算力之锚:深度解读 CANN ascend-toolkit 异构计算架构与工程实践
架构
一枕眠秋雨>o<1 小时前
深入 CANN ops-nn:昇腾 NPU 算子开发的工程化实践与架构哲学
架构
未来龙皇小蓝1 小时前
RBAC前端架构-01:项目初始化
前端·架构
农民工老王1 小时前
K8s 1.31 私有化部署实战:从 Calico 崩溃到 NFS 挂载失败的排坑全记录
云原生·kubernetes
灰子学技术1 小时前
istio从0到1:如何解决分布式配置同步问题
分布式·云原生·istio
island13141 小时前
CANN Catlass 算子模板库深度解析:高性能 GEMM 架构、模板元编程与融合算子的显存管理策略
人工智能·神经网络·架构·智能路由器
晚霞的不甘1 小时前
CANN 支持强化学习:从 Isaac Gym 仿真到机械臂真机控制
人工智能·神经网络·架构·开源·音视频