中间件框架知识进阶

news2024/11/18 1:47:47

概述

近期从不同渠道了解到了一些中间件相关的新的知识,记录一下收获。涉及到的中间件包括RPC调用、动态配置中心、MQ、缓存、数据库、限流等,通过对比加深理解,方便实际应用时候更明确如何进行设计和技术选型。


一、RPC框架中间件系列

1、选型对比相关

目前主流的RPC中间件包括Dubbo、HSF、Thrift、GRPC、Spring Cloud等。结合自己的具体场景选择合适的框架。从性能、通信方式、序列化、语言、易用性、生态等方面对比分析如下:

名称语言支持底层通信方式序列化协议注册中心性能
Dubbojava开发TCP长连接hessian,json,java默认的序列化等ZK等**(还可以)
HSFjava为主,支持C++Netty框架,本质TCP长连接默认Hessian2ConfigServer等**(还可以)
Thrift通过IDL构建支持跨语言自定义的协议,在Tcp上层包装ThriftConsul等****(比grpc快2-5倍)
GRPC跨语言Http2.0Protobufetcd(go)等***(平均比Dubbo略好一点)
Spring Cloudjava开发HttpJackson、FastJson等Nacos等*(也够用)

2、Dubbo中比较核心的SPI的概念

SPI(Service Provider Interface),本质原理----策略模式+配置+反射:将接口实现类的全限定名配置在文件中,并由服务加载器读取配置文件,加载实现类。这样可以在运行时,动态为接口替换实现类。我们需要搞清楚java的SPI和Dubbo的SPI区别:

java的SPI:

基本原理:Java的SPI|用来设计给服务提供商做插件使用的。基于策略模式来实现动态加载的机制。我们在程序只定义一个接口,具体的实现交个不同的服务提供者;在程序启动的时候,读取配置文件,由配置确定要调用哪一个实现。
实现过程:需要在 classpath 下创建一个目录,该目录命名必须是:META-INF/service2)在该目录下创建一个 文本文件,该文件需要满足以下几个条件文件名必须是扩展的接口的全路径名称文件内部描述的是该扩展接口的所有实现类文件的编码格式是 UTF-83)通过 java.util.ServiceLoader 的加载机制来加载服务。
工作流程:1)当调用 ServiceLoader.load(Class clz) 方法时,会到jar中中的目录 “META-INF/services/“ + clz.getName 进行文件读取,2)当在调用ServiceLoader.forEach()方法时,实际走的是LazyIterator,当在调用LazyIterator.hasNext() 时,在文件中读取到实际的服务实现类并把它们通过调用 Class.forName(String name, boolean initialize,ClassLoader loader)。
应用:javaSPI我们最熟悉的应用就是数据库驱动了,mysql和oracle驱动针对JDBC分别有自己的实现,这就有赖于java的SPI机制。

Dubbo的SPI:

基本原理:在dubbo中也有SPI机制,虽然都需要将接口全限定名配置在文件中,但是dubbo并没有使用java的spi机制,而是重新实现了一套功能更强的 SPI 机制, 支持了AOP与依赖注入,并且 利用缓存提高加载实现类的性能,同时 支持实现类的灵活获取。基于 SPI,我们可以很容易的对 Dubbo 进行拓展。例如dubbo当中的protocol,LoadBalance等都是通过SPI机制扩展。
实现过程:1)需要在 classpath 下创建一个目录,该目录命名可以是:META-INF/service/、META-INF/dubbo/、META-INF/dubbo/internal/2)在该目录下创建一个 文本文件,该文件需要满足以下几个条件文件名必须是扩展的接口的全路径名称文件内部描述的是该扩展接口的所有实现类,将服务实现类写成KV键值对的形式,Key是拓展类的name,Value是扩展的全限定名实现类。3)通过 org.apache.dubbo.common.extension.ExtensionLoader 的加载机制来加载服务
工作流程:两次SPI过程 1)我们首先通过 ExtensionLoader的 getExtensionLoader 方法获取一个接口的 ExtensionLoader 实例,然后再通过 ExtensionLoader 的 getExtension 方法获取拓展类对象 2)通过 ExtensionLoader.getExtensionLoader取到接口的加载器Loader之后,再通过 getExtension方法获取需要拓展类对象。
补充几个核心机制:服务发现机制 SPI、自适应机制 Adaptive、包装机制 Wrapper 与激活机制 Activate;参考https://juejin.cn/post/7112764945120362526?searchId=202401142324596D6049137EA11C7B3412
应用:例如dubbo的多协议的实现等。

区别点
(1)Java SPI在加载扩展点的时候,会一次性加载所有可用的扩展点,很多是不需要的,会浪费系统资源。
(2)dubboSPI有选择性地加载所需要的SPI接口。javaSPI配置文件中只是简单的列出了所有的扩展实现,而没有给他们命名。导致在程序中很难去准确的引用它们。而dubboSPI配置文件中以键值对的形式有别名,易于区分。
(3)SPI扩展如果依赖其他的扩展,javaspi做不到自动注入和装配,dubbo可以实现自动注入。
(4)javaSPI不提供类似于Spring的IOC和AOP功能,dubboSPI是支持的

以上参考链接:https://www.zhihu.com/question/389551161/answer/2615909871

3、几种调用方式的区分

同步调用

发起调用后线程阻塞住同步等待调用结果,适用耗时短的场景。Dubbo有容错机制,包括以下:FailoverClusterInvoker
(dubbo默认的容错机制)失败重试机制。失败自动切换,当出现失败,重试其它服务器。支持重试的,查询接口,支持幂等的写接口
FailsafeClusterInvoker
如果调用失败的化,不用抛出错误,直接打印一个异常log日志就可以了。一般来说,你要是写一些类似与远程日志数据,审计数据,或者是一些可有可无的,可以丢失的一些数据
ForkingClusterInvoker
就是会并行的调用几个服务,如果谁能先返回结果,就用谁的。cpu负载过高。
FailfastClusterInvoker
一旦调用的时候遇到了异常,直接抛出异常,不在进行重试了。
FailbackClusterInvoker
如果调用失败了,会把这个请求记录存储起来。后续根据时间轮的策略,再去隔一段时间去重试。默认是3次调用以后就会进行存储到失败列表中
BroadcastClusterInvoker
广播的形式的。所有的invoker服务实例都会接收到请求

异步RPC的实现:目前成熟的RPC框架​都会支持异步调用、异步监听、callback调用
https://blog.csdn.net/qq_34760272/article/details/123830970

Future阻塞等待结果

客户端发起请求之后,不必等待获取结果,第一次执行返回Null,随后通过Future.get()阻塞获取执行结果。

异步listener监听

有时候我们发起一个调用请求之后,并不想通过Future的get获取结果,因为get的时候是阻塞的,而是希望调用请求之后可以去做其他事情,通过一个监听去监测,当有结果返回的时候直接获取结果,然后进行逻辑处理。

异步callback回调

callback回调支持同步/异步方式,观察者模式可以伴随异步监听或者回调。
RPC是以TCP全双工的协议进行通信的,基于长连接,服务端便具备了可以“调用”客户端callback函数的能力。如果在服务端接口里面完成一个业务逻辑功能有3个过程,那么这3个过程中可以分别调用callback方法,形成“一次调用,多次通知”的机制,这一点在异步监听中是没有办法实现的,异步回调更像是“一次性买卖”。在高并发场景下建议使用异步监听的方式,因为callback方式客户端会对Callback实例的个数有限制。

参考文章地址:https://blog.csdn.net/qq_34760272/article/details/123830970

补充一个异步注解@Async
https://blog.csdn.net/weixin_47872288/article/details/125512173?utm_medium=distribute.pc_relevant.none-task-blog-2defaultbaidujs_baidulandingword~default-5-125512173-blog-51165251.235v40pc_relevant_anti_vip&spm=1001.2101.3001.4242.4&utm_relevant_index=8

以上内容参考:
https://blog.csdn.net/asdcls/article/details/121661651
https://zhuanlan.zhihu.com/p/458254270
https://www.zhihu.com/question/389551161?utm_id=0

二、HTTP/TCP 长短连接/长短轮询

1.TCP长短连接

HTTP协议是基于请求/响应模式的,因此只要服务端给了响应,本次HTTP连接就结束了,或者更准确的说,是本次HTTP请求就结束了,根本没有长连接这一说,那么自然也就没有短连接这一说了;网上所说的长连接、短连接,本质其实说的是TCP连接。TCP连接是一个双向通道,它是可以保持一段时间不关闭,因此TCP才有正真的长连接、短连接 。Http1.1以前是短连接,单次请求后关闭连接,下次重新TCP三次握手建立连接。长连接回保持TCP连接,使得多个HTTP请求可以复用同一个TCP连接。
短连接的操作步骤是:
建立连接——数据传输——关闭连接…建立连接——数据传输——关闭连接
长连接的操作步骤是:
建立连接——数据传输…(保持连接)…数据传输——关闭连接
优缺点:长连接可以省去较多的TCP建立和关闭的操作,减少浪费,节约时间。对于频繁请求资源的客户来说,较适用长连接。在长连接的应用场景下,client 端一般不会主动关闭它们之间的连接,Client与server之间的连接如果一直不关闭的话,会存在一个问题,随着客户端连接越来越多,server早晚有扛不住的时候。
应用场景:一般用于实时通信,比如Dubbo和HSF框架的注册中心和服务的发布与订阅者之间的通信。以及RocketMQ(MetaQ支持推push与拉poll模型)的NameServer和Broker与生产者、消费者之间的通信。
参考:https://www.jianshu.com/p/f36f83684f93
https://www.cnblogs.com/zhaozl/p/11168185.html

2.HTTP长短轮询

短轮询由客户端定时向服务器发送Ajax请求,服务器接到请求后马上返回响应信息并关闭连接;即在特定的的时间间隔(如每1秒),由浏览器对服务器发出HTTP request,然后由服务器返回最新的数据给客户端的浏览器(可以理解为TCP连接不复用)。
长轮询:请求进来,有数据就返回,没有就hang住(先不把请求响应给前端),直到有数据或者超时再返回(然后立即再发起一个请求过来)。客户端向服务器发送Ajax请求,服务器接到请求后hold住连接,直到有新消息才返回响应信息并关闭连接,客户端处理完响应信息后再向服务器发送新的请求。
轮询:客户端每隔一段时间ajax
长轮询:客户端请求1——服务端hold——服务端返回——客户端请求2
优缺点:短轮询实现容易,当请求中有大半是无用,难于维护,浪费带宽和服务器资源;响应的结果没有顺序(因为是异步请求,当发送的请求没有返回结果的时候,后面的请求又被发送。而此时如果后面的请求比前面的请 求要先返回结果,那么当前面的请求返回结果数据时已经是过时无效的数据了)。长轮询在无消息的情况下不会频繁的请求,耗费资源小,HTTP连接都不会复用TCP连接。
应用场景:动态配置中心,大量客户端请求,但是更新不频繁的请求与推送场景。比如Diamond持久化配置中心的动态更新通知,支持基于HTTP短轮询的“拉模型”和基于HTTP长轮询的“推模型”。

这里做简要解释,长连接是基于传输层的TCP连接通道,具备实时的双向传输能力,建立连接的过程中,就算server不回应,client也可以源源不断的向server发消息,连接不能“挂起”,需要一直保持连接状态,TCP连接多了,会对server造成很大连接负担。
长轮询是基于HTTP的连接,必须是请求—响应模式的,server可以不做出响应,将HTTP连接“挂起”,去处理其他的HTTP连接,对服务器的负担较小,因为server可以处理其他的HTTP请求,不用一直关注被“挂起”的HTTP连接。
实质上Diamond即支持由server向client动态的推送最新的配置,也支持client如果有需要可以主动从server拉最新的配置,非常灵活,可以适应各种业务场景。

参考:https://blog.csdn.net/dddgg__/article/details/133251289
参考https://www.cnblogs.com/Joeris/articles/10999373.html
https://blog.csdn.net/H200102/article/details/107354799

从兼容性角度考虑,短轮询 > 长轮询 > 长连接SSE > WebSocket;
从性能方面考虑,WebSocket > 长连接SSE > 长轮询 > 短轮询。
https://blog.csdn.net/sugelachao/article/details/124490112

HTTP与TCP通信区别:
Http是无转态的连接,TCP是有状态的长连接。
传输内容上:HTTP超文本传输,包的大小比TCP大。tcp比http快,是因为发送同样的有效数据,http比tcp多封装一次,也就是硬件实际要发送的数据量更大,那么自然耗时更多。
RPC为什么比HTTP快:
假设
这里的RPC服务一般是指基于TCP/IP协议上开发的二进制协议服务
Http服务一般是指基于Http1.0 / Http1.1协议上开发的REST服务
对比
序列化方式:
RPC服务序列化是针对二进制协议(0/1)来做序列化和反序列化,所以性能高。
而Http服务是基于文本的序列化和反序列化,需要读一行一行的文本(比如json格式的),进行序列化和反序列化,所以性能低。
报文长度:
RPC服务是自定义的传输协议,传输的报文都是干货。
而Http服务里面包括很多没用的报文内容,比如Http Header里面的accept,referer等等
连接的复用:
RPC服务是基于TCP/IP协议的,是长连接。
而Http服务大都是短连接,虽然Http1.1支持长连接,但是这个也是要取决于服务端是否支持长连接,不太可控。
结论
在追求性能的场合,用RPC服务(基于TCP/IP传输协议)
在追求兼容性多语言的场合,用REST服务
企业内部一般微服务互相调用用基于TCP的高性能RPC,对外网关支持HTTP请求。
https://blog.csdn.net/u013531487/article/details/130337143
https://blog.csdn.net/hudmhacker/article/details/108375757

三、缓存与数据库

数据库分库分表:对比ShardingJDBC和MyCat的设计。
缓存的热点数据处理:基于集群分片多级缓存打散读请求,合并写请求。
分库分表的主键ID选择:为什么不推荐UUID 全局自增 雪花算法
https://blog.csdn.net/qq_43665821/article/details/123883614?spm=1001.2101.3001.6650.1&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7ERate-1-123883614-blog-112151582.235%5Ev40%5Epc_relevant_anti_vip&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7ERate-1-123883614-blog-112151582.235%5Ev40%5Epc_relevant_anti_vip&utm_relevant_index=2
https://zhuanlan.zhihu.com/p/459357903

四、分布式锁实现与应用

常见的几种实现包括:基于Redis的SetNX、LUA脚本、Redission红锁框架、ZK的临时顺序节点创建&监听等。
主要区别:基于CAP和BASE理论,基于Redis的分布式锁是AP系统(集群数据同步机制是Gossip协议,会有短期的数据不一致问题),ZK的是CP系统(集群数据同步采用ZAB协议,会牺牲掉一部分的可用性)
在这里插入图片描述
关于分布式系统的一致性协议划分:
强一致性,保证系统改变提交以后立即改变集群的状态,有以下几个模型:Paxos、Raft、Zab
弱一致性,也叫最终一致性,不用保证提交立刻在集群内全部生效,但需要随着时间的推移生效,有以下几个模型:DNS系统、Gossip协议
协议介绍参考:https://zhuanlan.zhihu.com/p/617831925

关于是否支持可重入锁、支持公平/非公平锁:
其实Redisson和ZK都能实现,具体实现方式参考如下:
https://www.jianshu.com/p/cee3c8092aa5
https://blog.51cto.com/u_15162069/2806447

总结

本文总结了一些中间件框架的进阶知识,涉及到的中间件包括RPC调用、动态配置中心、MQ、缓存、数据库、限流等。主要通过对比的方式增强记忆和理解,方便实际应用过程中进行技术方案的设计和选择。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1390270.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

slint 1.3.2 官方文档翻译04

主要使用 有道翻译。希望能够对 初学者 有所帮助 翻译自:Builtin Enumerations - Slint 1.3.2 Reference Builtin Enumerations 内置的枚举 AccessibleRole 可访问角色 This enum represents the different values for the accessible-role property, used to d…

新手学习指南:用Scala采集外卖平台

学习爬虫不是一蹴而就的,在掌握相关的知识点的同时,还要多加练习,学习是一部分,更多的还是需要自己上手操作,这里配合自己学习的基础,以及使用一些爬虫的专有库,就可以轻松达到自己想要的数据。…

DaisyDisk for mac 中文激活版 可视化磁盘清理工具

DaisyDisk 是一款专为 Mac 设计的磁盘空间分析工具。它以直观、图形化的方式展示硬盘使用情况,帮助用户迅速找到占用空间大的文件和文件夹。通过扫描磁盘,DaisyDisk 生成彩色的扇形图表,每个扇区代表一个文件或文件夹,大小直观反映…

leetcode 67. 二进制求和

一、题目 二、解答 1.思路 1.1 思路1 转成2个二进制数字相加,之后再转回字符串 1.2 思路2 遍历字符串挨个相加: 补齐2个字符串到同样长度 while循环,如果指针>0不断循环如果a短,给字符串前插入(a长度-b长度&a…

Chrome禁用第三方Cookie,有什么影响?

2024年,Chrome将要正式禁用第三方Cookie了,这个变化对Web开发者来说是非常重要的,因为它将改变开发者如何设计网站以及如何搜集和使用用户数据。这是怎么一回事,到底有什么具体影响? 什么是Cookie? 随着互…

python flask学生管理系统

预览 前端 jquery css html bootstrap: 4.x 后端 python: 3.6.x flask: 2.0.x 数据库 mysql: 5.7 学生管理模块 登录、退出查看个人信息、修改个人信息成绩查询查看已选课程选课、取消选课搜索课程课程列表分页功能 教师模块 登录、退出查看个人信息、修改个人信息录入…

Gazebo的模型下载。

git clone zouxu634866/gazebo_modelshttps://gitee.com/zouxu6348660/gazebo_models.git,并完成路径配置。 (本文提供了gitee下载,国外的Github下载较慢。)

JDK8-JDK17版本升级

局部变量类型推断 switch表达式 文本块 Records 记录Records是添加到 Java 14 的一项新功能。它允许你创建用于存储数据的类。它类似于 POJO 类,但代码少得多;大多数开发人员使用 Lombok 生成 POJO 类,但是有了记录,你就不需要使…

通过生成mcs、bin文件将程序固化到FPGA

通过将程序固化到FPGA,可以做到断电不丢失程序,上电之后就自动启动程序的作用,整个固化步骤主要分为3步,一是修改约束文件,二是生成mcs或bin文件,三是将程序固化到开发板flash 1.修改约束文件 生成固化文…

meter报OOM错误,如何解决?

根据在之前的压测过程碰到的问题,今天稍微总结总结,以后方便自己查找。 一、单台Mac进行压测时候,压测客户端Jmeter启动超过2000个线程,Jmeter报OOM错误,如何解决? 解答:单台Mac配置内存为8G&…

蓝桥杯准备

书籍获取:Z-Library – 世界上最大的电子图书馆。自由访问知识和文化。 (zlibrary-east.se) 书评:(豆瓣) (douban.com) 一、观千曲而后晓声 别人常说蓝桥杯拿奖很简单,但是拿奖是一回事,拿什么奖又是一回事。况且,如果…

liunx安装redis

安装redis 1.向Xftp7上传Redis压缩包 进行解压:tar -zxvf redis-6.0.8.tar.gz 解压后预编译: cd redis-6.0.8 make 创建文件: mkdir -p /opt/redis 安装到指定目录: make install PREFIX/opt/redis 进入安装文件 bin 目录:cd /opt/redis/bin ./redis-se…

【python入门】day27: 模拟高铁售票系统

界面 代码 #-*- coding:utf-8 -*- import prettytable as pt#---------导入漂亮表格 import os.path filename ticket.txt#更新座位状态 def update(row_num):#------更新购票状态with open(filename,w,encodingutf-8) as wfile:for i in range(row_num):lst1 [f{i1},有票,有…

Springboot + websocket 实现 一对一 单人聊天

Springboot websocket 实现 一对一 单人聊天 要使用websocket ,需要添加 jar 打开项目中的pom.xml,添加以下内容 创建java端代码 配置websocke的endpoints 配置websocket的server ServerEndpoint(value "/websocket/{username}") 这句话 一定要注意, 这里 路…

寻找峰值题目解析

一、题目描述 162. 寻找峰值 峰值元素是指其值严格大于左右相邻值的元素。 给你一个整数数组 nums,找到峰值元素并返回其索引。数组可能包含多个峰值,在这种情况下,返回 任何一个峰值 所在位置即可。 你可以假设 nums[-1] nums[n] -∞ …

hcip-4

ISIS:中央系统到中央系统 基于OSI模型开发; 集成的ISIS,基于OSI开发后转移到TCP/IP模型执行; 故集成的ISIS既可以在OSI模型,也可在TCP/IP模型工作; ISIS是在ISP中使用的一个IGP协议,其归属于无类别链路状…

x-cmd pkg | duf - df 命令的现代化替代品

目录 简介用户首次快速实验指南技术特点竞品和相关作品进一步探索 简介 Duf (Disk Usage/Free Utility)是一个磁盘分析工具。其直观的输出和多样化的自定义选项,帮助用户更好地管理和优化存储资源。 用户首次快速实验指南 使用 x duf 即可自…

系统性学习vue-组件及脚手架

书接上文 Vue组件及脚手架 初始化脚手架说明步骤 分析脚手架结构render函数修改默认配置ref属性props配置mixin 混入/混合定义混合局部混合全局混合 插件scoped样式安装less-loader 浏览器的本地存储 webStoragelocalStroage 本地存储sessionStorage 会话存储 组件自定义事件绑…

Spring高手之路-Spring的AOP失效场景详解

目录 前言 1.非Spring管理的对象 2.同一个Bean内部方法调用 3.静态方法 4.final方法 5.异步方法 总结 前言 Spring的AOP(面向切面编程)是一种强大的技术,用于在应用程序中实现横切关注点的模块化。虽然Spring的AOP在大多数情况下都是…

如何画出优秀的系统架构图-架构师系列-学习总结

--- 后之视今,亦犹今之视昔! 目录 早期系统架构图 早期系统架构视图 41视图解读 41架构视图缺点 现代系统架构图的指导实践 业务架构 例子 使用场景 画图技巧 客户端架构、前端架构 例子 使用场景 画图技巧 系统架构 例子 定义 使用场…