高速服务框架HSF的基本原理(上)

本文涉及的产品
传统型负载均衡 CLB,每月750个小时 15LCU
应用型负载均衡 ALB,每月750个小时 15LCU
EMR Serverless StarRocks,5000CU*H 48000GB*H
简介: 高速服务框架HSF的基本原理(上)



SOA解决方案——HSF(High-speed Service Framework)是阿里系主要采用的服务框架,其目的是作为桥梁联通不同的业务系统,解耦系统之间的实现依赖。


image.png

HSF简介


 背景


单体应用的主要问题是不同的业务相互纠缠在一起,面对快速发展的业务,这种开发模型和架构不利于业务发展。为了解决这个问题,需要对应用进行拆分。将不同的业务分拆到多个应用中,让不同的应用分别承担不同的功能。
在单体应用时代,某个服务想要调用其他服务在本地就可以完成,而应用拆分为多个系统后,相互之间进行通信的方式就不能依赖本地,而必须要走远程,此时,一个高效、稳定的RPC框架就变得非常重要。
随着业务的不断发展,承载不同业务的应用数量以及单个应用下的服务数量都急剧膨胀,对于服务的管理变得愈发重要,在RPC框架刚开始使用的时候,可能只有几个应用,几十个服务,如果规模扩充到上万应用,几十万个服务,RPC调用反而不是重头戏,而重要的是如何能高效的组织这些服务。
一款优秀的RPC框架一般需要(或者最好能够具备)以下服务治理能力:

  1. 服务的方便检索,查询服务,包括服务的提供者与消费者信息
  2. 服务的快捷测试,能够简单、高效的进行服务测试
  3. 服务的路由,根据调用的服务名等运行时信息,服务消费方能够路由到对应的服务提供方指定的机器上
  4. 服务的归组,能够在统一机器资源维度上,让服务提供方具备服务自动归组的能力


这些特性都已经超越了一个普通RPC框架的范畴,而提供这些能力的RPC框架才能被称之为SOA(Service-Oriented Architecture)框架。

 是什么


阿里SOA解决方案——HSF(High-speed Service Framework),高速服务框架。该框架是阿里系主要采用的服务框架,其目的是作为桥梁联通不同的业务系统,解耦系统之间的实现依赖。其高速体现在底层的非阻塞I/O以及优秀的序列化机制上,实现了同步和异步调用方式,并且有一套软负载体系,实现分布式应用。

 特性


  • 高性能的服务调用


低侵入,HSF基于Java接口完成透明的RPC调用,用户对服务是否在本地不做感知,不侵入用户代码。

高性能,HSF提供基于非阻塞I/O上的高性能调用。

多语言,多语言支持完善,提供了C++以及Node.js客户端,支持HTTP REST调用。


  • 大流量的场景应对


客户端负载均衡,HSF在客户端基于服务地址列表做负载均衡,不需要借助其他负载均衡设备,高效完成负载均衡工作。

多种选址策略,HSF客户端在调用时提供了多种选址策略。

上下线策略,HSF提供了优雅上下线的能力,保证服务在重启时对客户端的影响面减到最小,客户端调用在服务端重启时表现平滑。


  • 全方位的服务治理


服务管理功能,HSF运维平台提供了服务查询、测试和Mock功能,支持用户通过服务名(一般是接口名+版本号)查询服务的提供者,或者通过输入参数对已有的服务进行调用测试。

规则管理功能,HSF运维平台支持使用归组、路由以及同机房等规则对客户端发起的调用进行干预,使客户端调用变得更加智能。


 基本结构


功能结构图


HSF功能结构上分为6个部分,分别是:「服务消费方」、「服务提供方」、「地址注册中心」、「持久化配置中心」、「元数据存储中心」和「HSF运维平台」(HSF 控制台),它们组合在一起可以提供全功能的分布式服务,其中服务消费方、服务提供方和地址注册中心是必需的,上述功能结构的介绍如下表:


 调用过程



作为服务消费方,客户端线程首先会将用户的参数也就是请求对象进行序列化,将序列化之后的内容放置到请求通信对象中,请求通信对象对应的是HSF协议,它包含诸如请求Id等多个与请求对象无关的内容。请求通信对象会提交给I/O线程,在I/O线程中完成编码,最终发送到服务提供方,此时客户端线程会等待结果返回,处于等待状态。


服务提供方的I/O线程接收到二进制内容,解码后生成通信请求对象并将其递交给HSF服务端线程,在HSF服务端线程完成反序列化还原成请求对象,然后发起反射调用,得到结果,也就是响应对象。响应对象会在HSF服务端线程中完成序列化,并放置到通信响应对象中。HSF服务端线程会将通信响应对象提交给I/O线程,在I/O线程中完成编码,最终发送回服务消费方。


服务消费方收到二进制内容,在I/O线程中完成解码,生成响应通信对象,并唤醒客户端线程,客户端线程会根据响应通信对象中的内容完成反序列化,最终拿到响应对象,一次远程调用结束。、


image.png

基本使用


 服务接口定义


在接口定义模块中定义接口,将其打为jar包,发布到Maven仓库中。


public interface HelloWorldService {

    /**
     * 根据参数中指定的名字,生成问候语
     *
     * @param name 被问候的姓名
     * @return 问候语
     */
    String sayHi(String name);
}


 业务代码实现


业务模块依赖接口定义模块,实现接口,编写业务代码。

<!-- 依赖接口定义模块 -->
<dependency>
    <groupId>com.alibaba.middleware</groupId>
    <artifactId>hsf-guide-api</artifactId>
</dependency>


// 实现接口
public class HelloWorldServiceImpl implements HelloWorldService {

    @Override
    public String sayHi(String name) {
        // 编写业务代码
        if (name == null || name.length() == 0) {
            return null;
        }
        return "Hi, " + name + "! Welcome to the HSF world.";
    }
}


 服务发布


  • API的方式

<!-- 依赖业务模块 -->
<dependency>
    <groupId>com.alibaba.middleware</groupId>
    <artifactId>hsf-guide-biz</artifactId>
</dependency>

<!-- 依赖HSF -->
<dependency>
    <groupId>com.taobao.hsf</groupId>
    <artifactId>hsf-all</artifactId>
</dependency>


在Main方法中将服务发布出去。

// [定义] 服务的实现
Object target = new HelloWorldServiceImpl();

// [设置] HSF服务发布逻辑
HSFApiProviderBean hsfApiProviderBean = new HSFApiProviderBean();
// [设置] 发布服务的接口
hsfApiProviderBean.setServiceInterface("com.alibaba.middleware.hsf.guide.api.service.HelloWorldService");
// [设置] 服务的实现对象
hsfApiProviderBean.setTarget(target);
// [设置] 服务的版本
hsfApiProviderBean.setServiceVersion("1.0.0");
// [设置] 服务的归组
hsfApiProviderBean.setServiceGroup("HSF");
// [设置] 服务的响应时间
hsfApiProviderBean.setClientTimeout(3000);
// [设置] 服务传输业务对象时的序列化类型
hsfApiProviderBean.setSerializeType("hessian2");

// [发布] HSF服务
hsfApiProviderBean.init();


  • 注解的方式


<!-- 依赖starter -->
<dependency>
    <groupId>com.alibaba.boot</groupId>
    <artifactId>pandora-hsf-spring-boot-starter</artifactId>
    <version>2023-04-release</version>
</dependency>


@HSFProvider配置到业务模块的实现类上。


@HSFProvider(serviceInterface = HelloWorldService.class, serviceGroup = "HSF", serviceVersion = "1.0.0", clientTimeout = 3000, serializeType = "hessian2")
public class HelloWorldServiceImpl implements HelloWorldService {

    @Override
    public String sayHi(String name) {
        if (name == null || name.length() == 0) {
            return null;
        }
        return "Hi, " + name + "! Welcome to the HSF world.";
    }
}


 服务调用


  • API的方式


在Main方法中调用服务端业务代码。


HSFApiConsumerBean hsfApiConsumerBean = new HSFApiConsumerBean();
// [设置] 订阅服务的接口
hsfApiConsumerBean.setInterfaceName("com.alibaba.middleware.hsf.guide.api.service.HelloWorldService");
// [设置] 服务的版本
hsfApiConsumerBean.setVersion("1.0.0");
// [设置] 服务的组别
hsfApiConsumerBean.setGroup("HSF");

// [订阅] HSF服务,同步等待地址推送,默认false(异步),同步默认超时时间为3000ms
hsfApiConsumerBean.init(true);

// [代理] 获取HSF代理
HelloWorldService helloWorldService = (HelloWorldService) hsfApiConsumerBean.getObject();

// [调用] 像调用本地接口一样,发起HSF调用
String hi = helloWorldService.sayHi("松张");
System.out.println(hi);


  • 注解的方式


建配置类,@HSFConsumer标记要调用的接口


@Configuration
public class HsfConfig {

    @HSFConsumer(serviceVersion = "1.0.0", serviceGroup = "HSF")
    HelloWorldService helloWorldService;
}


通过注入的方式使用。


@Autowired
HelloWorldService helloWorldService;


image.png

调用方式


同步调用也可以叫阻塞调用,它将阻塞当前线程,然后执行调用,调用完毕后再继续向下进行。


HSF的IO操作都是异步的,客户端同步调用的本质是做future.get(timeout)操作,等待服务端的结果返回,这里的timeout就是客户端生效的超时时间(默认3000ms)。


HSF默认的同步调用时序图:


对于客户端来说,并不是所有的HSF服务都是需要同步等待服务端返回结果的,对于这些服务,HSF提供异步调用的形式,让客户端不必同步阻塞在HSF操作上。异步调用在发起调用时,HSF服务的调用结果都是返回类型的默认值,如返回类型是int,则会返回0,返回类型是Object,则会返回null。而真正的结果,是在HSFResponseFuture或者回调函数(callback)中获得的。


 Future异步调用


HSF发起调用后,用户可以在上下文中获取跟返回结果关联HSFFuture对象,然后用户可以在任意时刻调用HSFFuture.getResponse(timeout)获取服务端的返回结果。Future异步调用时序图:


API配置客户端Future异步调用。


HSFApiConsumerBean hsfApiConsumerBean = new HSFApiConsumerBean();
hsfApiConsumerBean.setInterfaceName("com.alibaba.middleware.hsf.guide.api.service.HelloWorldService");
hsfApiConsumerBean.setVersion("1.0.0");
hsfApiConsumerBean.setGroup("HSF");

// [设置] 异步future调用
List<String> asyncCallMethods = new ArrayList<String>();
// [格式] name:{methodName};type:future
asyncCallMethods.add("name:sayHi;type:future");
hsfApiConsumerBean.setAsyncallMethods(asyncCallMethods);

hsfApiConsumerBean.init(true);

HelloWorldService helloWorldService = (HelloWorldService) hsfApiConsumerBean.getObject();

String hi = helloWorldService.sayHi("松张");
// 运行后控制台打印null
System.out.println(hi);

// 及时在当前调用上下文中获取future对象;因为该对象是放在ThreadLocal中的,同一线程中后续调用会覆盖future对象,所以要及时取出
HSFFuture hsfFuture = HSFResponseFuture.getFuture();

// do something else

try {
    // 这里才是真正地获取结果,如果调用还未完成,将阻塞等待结果,3000ms是等待结果的最大时间
    System.out.println(hsfFuture.getResponse(3000));
} catch (Throwable e) {
    e.printStackTrace();
}


 Callback异步调用


客户端配置为Callback方式调用时,需要配置一个实现了HSFResponseCallback接口的Listener,结果返回之后,HSF会调用HSFResponseCallback中的onAppResponse方法。

// 实现了HSFResponseCallback接口的Listener
public class MyCallbackHandler implements HSFResponseCallback {

    @Override
    public void onAppException(Throwable t) {
        t.printStackTrace();
    }

    @Override
    public void onAppResponse(Object o) {
        // 取callback调用时设置的上下文
        Object context = CallbackInvocationContext.getContext();
        // 打印远程调用结果 + callback调用时设置的上下文
        System.out.println(o.toString() + context);
    }

    @Override
    public void onHSFException(HSFException e) {
        e.printStackTrace();
    }
}


Callback异步调用时序图:

API配置客户端Callback异步调用:

HSFApiConsumerBean hsfApiConsumerBean = new HSFApiConsumerBean();
hsfApiConsumerBean.setInterfaceName("com.alibaba.middleware.hsf.guide.api.service.HelloWorldService");
hsfApiConsumerBean.setVersion("1.0.0");
hsfApiConsumerBean.setGroup("HSF");

// [设置] 异步callback调用
List<String> asyncCallMethods = new ArrayList<String>();
// [格式] name:{methodName};type:callback;listener:{listenerFullyQualifiedName}
asyncCallMethods.add("name:sayHi;type:callback;listener:com.alibaba.middleware.hsf.guide.client.handler.CallbackHandler");
hsfApiConsumerBean.setAsyncallMethods(asyncCallMethods);

hsfApiConsumerBean.init(true);

HelloWorldService helloWorldService = (HelloWorldService) hsfApiConsumerBean.getObject();

// 可选步骤,设置上下文。CallbackHandler中通过api可以获取到
CallbackInvocationContext.setContext(" in callback");

String hi = helloWorldService.sayHi("松张");
// 运行后控制台打印null
System.out.println(hi);

// 清理上下文
CallbackInvocationContext.setContext(null);

// do something else


高速服务框架HSF的基本原理(下):https://developer.aliyun.com/article/1480830

相关实践学习
SLB负载均衡实践
本场景通过使用阿里云负载均衡 SLB 以及对负载均衡 SLB 后端服务器 ECS 的权重进行修改,快速解决服务器响应速度慢的问题
负载均衡入门与产品使用指南
负载均衡(Server Load Balancer)是对多台云服务器进行流量分发的负载均衡服务,可以通过流量分发扩展应用系统对外的服务能力,通过消除单点故障提升应用系统的可用性。 本课程主要介绍负载均衡的相关技术以及阿里云负载均衡产品的使用方法。
目录
相关文章
|
6月前
|
设计模式 Java 应用服务中间件
高速服务框架HSF的基本原理(下)
高速服务框架HSF的基本原理(下)
370 0
|
监控 Dubbo Java
阿里分布式服务框架Dubbo的架构总结
Dubbo是Alibaba开源的分布式服务框架,它最大的特点是按照分层的方式来架构,使用这种方式可以使各个层之间解耦合(或者最大限度地松耦合)。从服务模型的角度来看,Dubbo采用的是一种非常简单的模型,要么是提供方提供服务,要么是消费方消费服务,所以基于这一点可以抽象出服务提供方(Provider)和服务消费方(Consumer)两个角色。
3075 0
|
6月前
|
监控 Dubbo Java
深入理解 Dubbo:构建分布式服务治理体系
深入理解 Dubbo:构建分布式服务治理体系
|
6月前
|
Kubernetes Cloud Native 微服务
作者推荐|剖析云原生服务框架中服务发现机制的核心原理与实现机制
作者推荐|剖析云原生服务框架中服务发现机制的核心原理与实现机制
243 0
|
6月前
|
Dubbo 网络协议 应用服务中间件
分布式微服务框架dubbo原理与机制
分布式微服务框架dubbo原理与机制
|
6月前
|
存储 缓存 负载均衡
服务治理和分布式 基础
服务治理和分布式 基础
|
负载均衡 Dubbo NoSQL
【完整解析】Dubbo分布式服务框架:优点、架构和未来趋势(一)
【完整解析】Dubbo分布式服务框架:优点、架构和未来趋势
912 2
|
JSON 负载均衡 监控
【完整解析】Dubbo分布式服务框架:优点、架构和未来趋势(三)
【完整解析】Dubbo分布式服务框架:优点、架构和未来趋势
285 0
|
XML 负载均衡 Dubbo
【完整解析】Dubbo分布式服务框架:优点、架构和未来趋势(二)
【完整解析】Dubbo分布式服务框架:优点、架构和未来趋势
141 0
|
消息中间件 缓存 运维
【微服务】如何实现微服务集群的高可靠?
实现微服务高可靠11连问,你能扛住几问?
432 1
【微服务】如何实现微服务集群的高可靠?