当前位置: 首页 > news >正文

微服务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)

        

        

http://www.dtcms.com/a/359723.html

相关文章:

  • Java与分布式系统的集成与实现:从基础到应用!
  • 从 JDK 8 到 JDK 17
  • 【Python语法基础学习笔记】函数定义与使用
  • Spring Security 6.x 功能概览与代码示例
  • 【四位加密】2022-10-25
  • 电感值过大过小会影响什么
  • 基于VS平台的QT开发全流程指南
  • 杂谈:大模型与垂直场景融合的技术趋势
  • 线程池八股文
  • 语义分析:从读懂到理解的深度跨越
  • Python基础:函数
  • Visual Studio Code中launch.json的解析笔记
  • 【Canvas与旗帜】哥伦比亚旗圆饼
  • 【芯片测试篇】:LIN总线
  • 人工智能-python-深度学习-
  • 自制扫地机器人(一)20 元级机械自动避障扫地机器人——东方仙盟
  • 计算机网络---http(超文本传输协议)
  • 【开题答辩全过程】以 留守儿童志愿者服务系统为例,包含答辩的问题和答案
  • 从企业和业务视角来拒绝中台
  • 什么是 WAF?全面解读 Web 应用防火墙的原理与应用
  • Vue3 响应式基础
  • TFS-2002《Fuzzy Clustering With Viewpoints》
  • 在SAP系统中,如何查询已经被打上了删除标记的生产订单?
  • AI 赋能 Java 开发效率:全流程痛点解决与实践案例(一)
  • 云网络(参考自腾讯云计算工程师认证)
  • 【开题答辩全过程】以 基于微信小程序的教学辅助系统 为例,包含答辩的问题和答案
  • ES集群部署-EFK架构实战
  • 【Python基础】2. 常量与变量
  • c++ Effective c++ 条款5
  • Ubuntu24.04(Jazzy)从零开始实现环境配置和Gmapping建图