HSF源码剖析

article/2025/10/21 5:11:58

前言

HSF是一个分布式的远程服务调用框架,其实我更喜欢把分布式几个字去掉,因为HSF本身并不是一个单独的服务(指一个进程),他是附属在你的应用里的一个组件,一个RPC组件(远程过程调用——Remote Procedure Call,是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议。在OSI网络通信模型中,RPC跨越了传输层和应用层。RPC使得开发分布式应用更加容易),当然HSF完全的内容肯定不止这些。

说了那么久HSF全称是什么呢?High-Speed Service Framework

RPC

我们先来看一张图:

这里写图片描述

很多同学看了这张图可能会觉得这跟http的过程有什么区别?

有这么一个场景(本来想举一个便具体业务的例子,想想还是已技术实现相关的比较好),监控平台:监控所有主机的状态,这时候每台主机上有一个agent,每个几秒向监控平台上传一次数据(主机内存使用率、硬盘状况、CPU、load、进程信息等等)。

可能在开发的时候最简单的方式就是监控平台有一个http接口,agent每隔几秒请求一次,能够满足需求,但是如果主机数快速增长了很多、监控项越来越多、请求体越来越大,你会发现http的传输效率下降了,每一次调用的耗时增加了。

这时我们会去研究http协议,想去优化这个过程,发现http的过程是:建立连接、发送请求信息、发送响应信息、关闭连接,看到这个过程首先想优化的就是能不能不要每次都去建立连接关闭连接,因为数据上报是个持续的过程;紧接着去研究http头,发现很多协议用不到,繁杂,白白增加了消息体;后来又觉得http的协议解析还原过程很复杂,可以自己开发一个提升性能……

RPC来了,他能满足这些需求,但是前提是需要开发,需要前期成本,所以想项目设计时就要去衡量,不过没事,我们有HSF啊。

我们将上图稍微改造一下:

这里写图片描述

现在从图中可以看着,client和server之间有一条长连接,并且我们有自己的协议体:RpcRequest和RpcResponse。

RPC就讲到这里,毕竟重点是HSF,想要更多的了解RPC,可以上wiki或者网上查询。

HSF架构

其实在我们的应用中,一般情况下你的应用不仅仅是client,也是server,因为你不仅需要去调用其他应用提供的服务,也提供服务给其他应用,所以这样一来,整个hsf的服务调用链路也会很复杂。

从上面两幅图中我们很显然的发现一个问题,就是服务提供者如何告知客户端他提供的服务,所以需要有一个服务注册与发现的地方,在HSF架构中提供这个功能的是configserver,如下图:

这里写图片描述

从上图可以看出server端启动的时候会向configserver注册自己提供的服务,client会向configserver订阅需要的服务,configserver通过订阅信息将相关服务提供者的地址以及其他关键信息推送给client

上面已经实现了基本的能力,但是如何动态配置负载(线程池大小)、默认配置(configserver地址等)、还有一些特性功能(如路由规则),这时候就需要有一个持久化配置中心,如下图:

这里写图片描述

client和server启动的时候会先去diamond获取需要的配置信息,如最关键的服务注册中心的类型和地址,除此之外之外还有服务治理的类型和地址等。

重点说一下路由规则,举个例子:通过路由规则配置在服务调用的时候只调用同机房的server,这样子服务调用的耗时肯定比跨机房的耗时短。除此之外hsf里还单独写了unitService进行服务单元发布来区分中心发布,这些番外的东西以后有时间再写个番外篇,这里就不过多阐述了,毕竟这些有点偏场景偏业务的内容以后可能就改成别的方式了。

这里写图片描述

相信大家都用过hsf服务治理网站,通过这个网站可以看到有哪些服务、服务提供者的地址是多少、有多少提供者、具体的消费者是谁,hsf通过configserver、redis、diamond里的存储信息获取到这些信息。

redis功能:HSF使用Redis存储元数据,每一个HSF Consumer/Provider 都会在启动后、每隔一段时间向redis上报元数据,这些元数据采集起来又提供给HSFOPS做服务治理,包括应用名和服务的映射、服务的元数据等。

服务的注册与发布

这里写图片描述

接下来我们把这个server解开,看看里面是怎么样的。

<bean id="hsfTestService"class="com.test.service.impl.HsfTestServiceImpl" /><bean class="com.taobao.hsf.app.spring.util.HSFSpringProviderBean"init-method="init"><property name="serviceName" value="hsfTestService" /><property name="target" ref="hsfTestService" /><property name="serviceInterface"><value>com.test.service.HsfTestService</value></property><property name="serviceVersion"><value>${hsf.common.provider.version}</value></property></bean>

相信同学们对上面这段配置代码很熟悉,那么服务到底是怎么注册的呢,为什么这里配置了这个服务就可以被调用了呢?

从配置文件看到有个关键的bean——HSFSpringProviderBean,还有个关键的初始化方法init,其实init的过程就是服务发布的过程,我们来看看HSFSpringProviderBean中的部分代码:

public void init() throws Exception {// 避免被初始化多次if (!providerBean.getInited().compareAndSet(false, true)) {return;}LoggerInit.initHSFLog();SpasInit.initSpas();providerBean.checkConfig();publishIfNotInSpringContainer();}private void publishIfNotInSpringContainer() {if (!isInSpringContainer) {LOGGER.warn("[SpringProviderBean]不是在Spring容器中创建, 不推荐使用");providerBean.publish();}}

从代码中很明显的看到服务发布providerBean.publish(),先来看大致类图,类图中有些不是很关键的先省略了:

这里写图片描述

大致对类图进行解释一下,这也是服务发布的一个过程:

  1. 服务初始化,首先需要有一个提供服务的service实现类(spring bean)和接口;
  2. 初始化HSFSpringProviderBean,从配置文件获取服务名称、接口、实现类、版本等等;
  3. providerBean是HSFApiProviderBean在HSFSpringProviderBean中的变量,HSFSpringProviderBean会将从配置文件获取的服务名称、接口、实现类、版本等等赋值给providerBean;
  4. providerBean中有个服务实体类ServiceMetadata,providerBean会将服务发布的所有信息放在这里,如接口、实现类、版本等等,在整个发布过程中,ServiceMetadata是所有对象之间的传输对象;
  5. 这里先来解释一下为什么有HSFSpringProviderBean和HSFApiProviderBean,其实两个可以合并成一个,但是为什么要分开呢?我的理解是对于不同环境的不同实现,比如现在用的是spring环境,那就需要有个spring适配类HSFSpringProviderBean来获取配置信息,假如是其他环境那么就会有另一个适配类,最终把信息统一转成给HSFApiProviderBean,HSFApiProviderBean是来具体操作实现;
  6. 当执行providerBean.publish()时,会调用ProcessService的publish方法,具体实现类是ProcessComponent;
  7. 发布的具体流程就是ProcessComponent里:
    • 第一步,调用rpcProtocolService来注册发布RPC服务,这个动作是在server本地发布一个线程池,每一个服务都会申请一个线程池,当请求过来时从线程池获取executor进行执行并返回;
    • 第二步,检查单元化发布,就unitService在发布前检查是中心发布还是单元发布,对ServiceMetadata设置不同的发布路由;
    • 第三步,通过metadataService将ServiceMetadata发布到ConfigServer上;
    • 第四步,通过metadataInfoStoreService将ServiceMetadata保存到redis供服务治理或者其他用途。

服务注册发布大致就是这么一个过程。

HSF的Client

这里写图片描述

现在来看看client是如何去调用服务的。

<bean id="hsfTestService" class="com.taobao.hsf.app.spring.util.HSFSpringConsumerBean" init-method="init"><property name="interfaceName" value="com.test.service.hsfTestService"/><property name="version" value="1.0.0.daily"/>
</bean>

上面一段配置文件相信在项目中肯定也非常常见,那么他是怎么运作的呢?在spring注入的时候并没有具体的实现类啊,只有一个接口?怎么实现调用的呢?

其实这是我一个好奇心的地方,我想去看个究竟,hsf到底是用何种方式去实现的。

我们先来思考一个问题,那就是没有具体实现类,hsf是如何实现在spring中注册服务的呢?答案就是动态代理,类似mybatis的方式,mybatis在写dao层的时候只是写了个接口,并没有具体实现,hsf跟这种方式很相像。

客户端分两部分来讲解:服务的订阅和被推送,服务的调用。

服务的订阅和被推送

先来看类图:

这里写图片描述

一样我们通过类图来看服务的订阅和接收过程:

  1. 服务初始化,首先需要引入服务接口相关的pom,然后写配置文件;

  2. 将需要被调用的服务注册成spring bean,即上面配置文件中的内容。

    • 这里用到了动态代理,通过类图我们可以看到HSFSpringConsumerBean实现了FactoryBean;

    • FactoryBean:是一个Java Bean,但是它是一个能生产对象的工厂Bean,通过getObject方法返回具体的bean,在spring bean实例化bean的过程中会去判断是不是FactoryBean,如果不是就返回bean,否则返回FactoryBean生产的bean,具体同学们可以去看AbstractBeanFactory的doGetBean方法,里面会调用getObjectForBeanInstance方法,这个方法里有具体实现;

    • HSFSpringConsumerBean实现了FactoryBean,那么getObject方法具体返回了什么呢?怎么返回的呢?

      @Override
      public Object getObject() throws Exception {return consumerBean.getObject();
      }

      从代码看得出是调用了consumerBean(HSFApiConsumerBean)的getObject方法返回的,那么我们再来看getObject方法:

      public Object getObject() throws Exception {return metadata.getTarget();
      }

      这个方法返回的是metadata(ServiceMetadata)的target,那么target是怎么获取的呢?下面重点说明;

    • HSFSpringConsumerBean的init方法调用了consumerBean(HSFApiConsumerBean)的init方法,我们来看consumerBean里init方法的某一段代码:

      ProcessService processService = HSFServiceContainer.getInstance(ProcessService.class);
      try {metadata.setTarget(processService.consume(metadata));LOGGER.warn("成功生成对接口为[" + metadata.getInterfaceName() + "]版本为[" + metadata.getVersion() + "]的HSF服务调用的代理!");
      } catch (Exception e) {LOGGER.error("", "生成对接口为[" + metadata.getInterfaceName() + "]版本为[" + metadata.getVersion()+ "]的HSF服务调用的代理失败", e);// since 2007,一旦初始化异常就抛出throw e;
      }
      int waitTime = metadata.getMaxWaitTimeForCsAddress();
      if (waitTime > 0) {try {metadata.getCsAddressCountDownLatch().await(waitTime, TimeUnit.MILLISECONDS);} catch (InterruptedException e) {// ignore}
      }

      这一段代码包含了动态代理对象的具体生成和服务订阅以及服务信息接收;

    • 先说了一下代码逻辑,服务的订阅和服务信息的接收(被推送)在processService中执行,动态代理对象在processService中生成,下面的wait我推测是用来等目标服务信息的推送(当收到订阅的目标具体服务实现,接下来的调用过程才能走通);

    • 看来processService是一个很重要的组件,这边通过processService.consume(metadata)这样的方法调用实现了那么多步骤,target也在这里面生成,说一下这个方法内的逻辑:

      • 首先去缓存中找是否之前target有生成,有就返回;

      • 没有就通过java Proxy生成对象;

      • 订阅服务信息(返回的可调用地址);

      • 保存客户端metadata到redis,返回target。

      这里写图片描述

到此为止,服务代理对象的生成,服务的订阅都完成了,接下来看看服务的调用。

服务的调用

其实通过上面两个部分整个框架已经定好了,服务信息已经注册发布,客户端也获取到了服务的调用地址,接下去就是调用就行,调用呢就是真正的rpc请求了,hsf的rpc是通过netty实现的。

直接上类图:

这里写图片描述

之前说了动态代理,那么在方法执行时就行进入代理类执行,执行HSFServiceProxy的invoke方法,invoke方法会调用trueInvoke方法:

  • 在trueInvoke里调用RPCProtocolTemplateService,在这里封装HSFRequest,执行具体的invoke方法;
  • 具体的invoke方法调用RPCProtocolService,在这里主要是根据invokeType来确定具体的InvokeService实现,最基本的我们知道hsf服务有同步调用和异步调用,具体实现就在这里;
  • 最后在具体的实现类的获取NettyClient,跟server进行通信,返回HSFResponse。

简单说下服务端的流程:

  • 服务端会启动nettyServer,具体由NettyServerHandler来处理所有rpc请求;
  • NettyServerHandler会根据HSFRequest找到具体的handler,这边是RPCServerHandler,除此之外还有心跳啊等等handler;
  • 通过handler获取具体执行的executor(这个在之前服务注册那边有讲,每个服务本地会申请线程池,threadpoolexecutor);
  • new一个HandlerRunnable放进executor执行executor.execute(new HandlerRunnable);
  • 最终在handler里调用ProviderProcessor,ProviderProcessor会找到具体的服务实现类并执行,将执行结果封装成HSFResponse,向client返回HSFResponse。

这里写图片描述

写在最后

我在这里讲得更多的是主链路,里面有很多具体的细节比如路由、鹰眼追踪、日志、负载等等没有展开讲,其实每个点拿出来都可以写一篇文章,可能对于hsf的开发同学来说,每一个点都会有一个很好玩的故事,那么关于HSF就先讲到这里。


http://chatgpt.dhexx.cn/article/2q5jTdHm.shtml

相关文章

Java-RPC通信--HSF框架

最近leader给了KingYiFan一个任务&#xff0c;就是对接某国企的业务&#xff0c;人家用的淘宝的HSF框架RPC通信 根本不用httpclient what&#xff1f;&#xff1f;&#xff1f; RPC不是Dubbo底层协议吗&#xff1f;这怎么通讯呢&#xff1f;翻遍了整个百度没有我想要的。 有一个…

hsf服务的调用过程

目录&#xff1a; 写一个hsf服务并发布 写一个接口工程 写一个实现接口的实现工程 写一个发布接口工程和实现工程的服务工程 写一个应用实现借口 hsf服务调用的过程 通过JBoss/Tomcat启动服务 通过main口启动服务 过程&#xff1a; 写一个hsf服务并发布&#xff1a; 在上…

HSF 开发

HSF 简介 HSF(High Speed Service Framework)&#xff0c;高速服务框架&#xff0c;是阿里-主要采用的服务框架&#xff0c;其目的是 作为桥梁联通不同的业务系统&#xff0c;解耦系统之间的实现依赖。 1: RPC 远程过程调用(Remote Procedure Call)是一种通过网络从远程计算机程…

分布式服务框架 HSF

摘要&#xff1a; RPC 协议采用多路复用的 TCP 长连接方式&#xff0c;在服务提供者和调用者间有多个服务请求同时调用时会共用同一个长连接&#xff0c;即一个连接交替传输不同请求的字节块。它既避免了反复建立连接开销&#xff0c;也避免了连接的等待闲置从而减少了系统连接…

HSF (RPC远程调用框架)

HSF 1. HSF概述1.1 概述1.2 HSF架构1.3 功能1.4 应用开发方式 2. 使用 Ali-Tomcat 开发2.1 Ali-Tomcat概述2.2 安装及开发环境配置2.2.1 安装Ali-Tomcat和Pandora2.2.2 配置IntelliJ IDEA开发环境 2.3 开发HSF应用2.3.1 定义服务接口2.3.2 开发服务提供者2.3.3 开发服务消费者2…

分布式服务框架HSF简介

高速服务框架 HSF (High-speed Service Framework)&#xff0c;是在阿里巴巴内部广泛使用的分布式 RPC 服务框架。HSF 统一了分布式应用中服务的发布/调用方式&#xff0c;从而帮助您方便、快速的开发分布式应用 HSF 架构 HSF 作为一个纯客户端架构的 RPC 框架&#xff0c;本…

分布式服务框架HSF

HSF提供的是分布式服务开发框架&#xff0c;taobao内部使用较多&#xff0c;总体来说其提供的功能及一些实现基础&#xff1a; 1.标准Service方式的RPC 1&#xff09;、Service定义&#xff1a;基于OSGI的Service定义方式 2&#xff09;、TCP/IP通信&#xff1a; IO方式…

分布式 RPC 框架HSF

分布式 RPC 框架HSF 概述HSF架构调用方式优势应用场景 概述 HSF (High-speed Service Framework)&#xff0c;高速服务框架&#xff0c;是在阿里巴巴内部广泛使用的分布式 RPC 服务框架。HSF 作为阿里巴巴的基础中间件&#xff0c;联通不同的业务系统&#xff0c;解耦系统间的…

关于 HSF框架 (一)简单介绍

HSF介绍 HSF全称 high speed frameworkd, 是Alibaba内部使用的RPC框架&#xff0c;最初与Dubbo进行内部竞争&#xff0c;由于多方面的原因最终选择了HSF。 主要原因如下&#xff1a; HSF代码量少一些&#xff0c;轻量一些&#xff0c;代码量大概2/3, Dubbo设计更加全面功能更多…

hsaf框架

一.技术分层 a&#xff09;.前端展现层&#xff0c;泛指一切在客户端直接与用户打交道的客户界面&#xff08;&#xff09;&#xff0c;MVC架构中的view层 b&#xff09;.控制层&#xff1a;分为过滤器拦截器层&#xff0c;Controller控制器层 c&#xff09;.业务逻辑层&…

高速服务框架HSF

一、简述 HSF(High-speed Service Framework)&#xff0c;是在阿里巴巴内部广泛使用的分布式 RPC 服务框架。 HSF 连通不同的业务系统&#xff0c;解耦系统间的实现依赖。HSF 从分布式应用的层面&#xff0c;统一了服务的发布与调用方式&#xff0c;从而帮助用户更加方便、快…

阿里HSF(服务框架)

文章目录 HSF&#xff08;服务框架&#xff09;简介架构设计Provider——服务提供者Consumer——服务消费者ConfigServer——配置服务器Diamond——持久化配置中心addressServer——地址服务元数据存储 HSF&#xff08;服务框架&#xff09; 文章地址 简介 高速服务框架 HS…

MySQL的批量更新和批量新增优化

MySQL的批量更新和批量插入优化 如果需要批量插入和批量更新操作就需要进行sql 的优化&#xff0c;否则近30万条数据的插入或更新就会耗费几分钟甚至更多的时间&#xff0c; 此文仅批量插入和批量更新的几种优化。 批量插入篇&#xff08;使用多条insert语句、使用union all创…

mybatis 批量更新

1 更新单条记录 UPDATE course SET name course1 WHEREid id1; 2 更新多条记录的同一个字段为同一个值 UPDATE course SET name course1 WHERE id in (id1,id2,id3); 3 更新多条记录为多个字段为不同的值 3.1 比较普通的写法&#xff0c;是通过循环&#xff0c;依次执行…

Update批量更新(高性能、动态化)

文章目录 前言一、环境开发环境测试环境 二、灵光乍现MyBatis-Plus源码2.初见真正的批量更新语法 三、开工基础类搭建SysUser&#xff08;表sys_user实体类&#xff09;Stash&#xff08;拼接SQL服务&#xff0c;内部类&#xff09;TableCacheDTO&#xff08;数据表信息存储&am…

mybatis-plus批量更新updateBatchById

前言 在使用mybatis-plus过程中&#xff0c;有很多插件都特别优秀&#xff0c;不仅使我们代码更加优雅&#xff0c;也提升了效率。其中有个批量插入的插件insertBatchSomeColumn使用起来也挺方便的&#xff0c;但是批量更新一直没有官方插件&#xff0c;网络上面也没有找到靠谱…

mysql批量更新方法

目录 方法一 replace into 批量更新 方法二 insert into 批量更新 方法三 临时表 批量更新 方法四 case when 批量更新 本篇文章实验mysql版本为5.7.20 隔离级别为rr&#xff0c;加锁场景的问题在mysql8.0.18中为复现 方法一 replace into 批量更新 原理&#xff1a;replace i…

mybatis批量更新数据三种方法

具体的可以参考下面链接&#xff1a; ​​​​​​mybatis批量更新数据三种方法效率对比_PreciousLife的博客-CSDN博客_mybatis 批量更新 此处说明下&#xff0c;若是使用for循环遍历方式&#xff0c;来生成N条sql&#xff0c;那么就需要注意两个地方&#xff1a; 第一个地方…

MySql中4种批量更新的方法

https://yq.aliyun.com/ziliao/59813 MySql中4种批量更新的方法 最近在完成MySql项目集成的情况下&#xff0c;需要增加批量更新的功能&#xff0c;根据网上的资料整理了一下&#xff0c;很好用&#xff0c;都测试过&#xff0c;可以直接使用。 mysql 批量更新共有以下四种办法…

MySQL批量更新的四种方法

最近做一个需求&#xff0c;更新3w条数据&#xff0c;一个一个update去更新的&#xff0c;结果花了80分钟&#xff0c;这样性能上很差&#xff0c;也容易阻塞&#xff0c;所以就找了一些MySQL批量更新的方式&#xff0c;在此记录一下 方法一&#xff1b;replace into 这种更新…