專有云傳統HSF升級Pandora Boot開發

簡介:專有云傳統HSF升級Pandora Boot開發

 title=

本次最佳實踐,分析傳統HSF應用的劣勢及升級至Pandora Boot開發的優點。將結合HSF代碼和Pandora Boot代碼進行詳解傳統HSF應用如何升級至Pandora Boot開發。前端

背景信息

HSF開發應用的劣勢在於HSF要使用指定的Ali-Tomcat容器,還須要在Ali-Tomcat等容器中加入sar包擴展,對用戶運行環境的侵入性大。而HSF開發的應用程序最終以WAR包的形式運行,不符合微服務設計的輕量應用理念。而且開發過程注入Bean須要編寫較多的xml文件配置。java

而Pandora Boot開發應用的優點就在於依賴容器Pandora,不須要Ali-Tomcat。並且Pandora Boot開發也兼容了完整的HSF功能,同時與Spring Boot無縫集成。因此使用Pandora Boot的同時也能夠引入Spring Boot提供開箱即用的依賴模板。快速、敏捷的開發Spring框架的應用程序,享受開發的便利。react

Pandora Boot開發的應用最終以FatJar包的形式運行,而且Pandora環境也能夠直接在IDE中啓動,開發調試等效率將獲得極大的提升。而Pandora Boot注入Bean經過註解的方式,也減小了繁雜的xml配置文件編寫,提升開發效率。web

由於在傳統客戶中有HSF應用升級至Pandora Boot開發的需求,因此針對客戶的須要,本次最佳實踐將詳細描述傳統HSF應用和PandoraBoot應用的開發,使單體微服務應用的敏捷開發及拓展性有所提升。spring

HSF環境介紹及準備

產品組件

  • Ali-Tomcat是EDAS中的服務運行依賴的一個容器,支持Servlet 3.0規範,支持WebSocket。包含服務的發佈、訂閱、調用鏈追蹤等一系列的核心功能。
  • Pandora是一個輕量級的隔離容器-taobao-hsf.sar,它用來隔離Webapp和中間件的依賴,也用來隔離中間件之間的依賴,並實現部署與應用分離。
  • 輕量級配置中心(Diamond)是淘寶內部普遍使用的配置中心,提供持久化管理和動態配置推送服務。應用方發佈的配置會經過持久化存儲保存,與發佈者的生命週期無關。
  • 動態配置推送是Diamond的核心功能,在淘寶內部有不少應用場景,如數據庫動態切換和擴容,業務系統開關配置運行時變動等。
  • 輕量級註冊中心(ConfigServer):主要用於非持久數據的發佈和訂閱、數據的生命週期和TCP鏈接生命週期綁定、產品架構基於發佈訂閱模型和去中心無master設計,保證了系統的可擴展性、高可用。在集團內部主要場景爲分佈式消息系統Notify、分佈式RPC框架HSF提供地址發現服務。

基本結構

HSF結構分爲6個部分,共同組合在一塊兒能夠提供全功能的分佈式服務,分別是:數據庫

  • 服務消費方:消費服務提供方提供的服務,服務消費者經過地址註冊中心訂閱服務,根據訂閱到的地址信息發起調用,地址註冊中心做爲旁路不參與調用。
  • 服務提供方: 在服務框架中真正提供服務功能實現的應用實例,爲了保障服務提供的高可用性,通常均是集羣部署,同時將地址信息發佈到地址註冊中心。
  • 地址註冊中心:接受服務提供方發佈的地址,當服務消費方根據服務進行訂閱時,會將地址信息推送給服務消費方,註冊中心就是服務信息的中介,提供服務發現的能力
  • 持久化配置中心:持久化的配置中心用於存儲 HSF 服務的各類治理規則,HSF 客戶端在啓動的過程當中會向持久化配置中心訂閱各類服務治理規則,如路由規則、歸組規則、權重規則等,從而根據規則對調用過程的選址邏輯進行干預。
  • 元數據存儲中心:元數據是指 HSF 服務對應的方法列表以及參數結構等信息,元數據不會對 HSF 的調用過程產生影響,所以元數據存儲中心也並非必須的。但考慮到服務運維的便捷性,HSF客戶端在啓動時會將元數據上報到元數據存儲中心,以便提供給服務運維使用
  • HSF運維平臺(HSF控制檯):HSF 控制檯經過打通地址註冊中心 ConfigServer、持久化配置中心 Diamond、元數據存儲中心Redis,爲用戶提供了一些列服務運維功能,包括服務查詢、服務治理規則管理、服務測試、服務 Mock、單機運維等,旨在提升 HSF 服務研發的效率、運維的便捷性。

環境準備流程步驟

在進行開發前,須要準備如下基本內容:apache

  1. JDK基礎運行環境:正確安裝JDK 7+,正確配置JAVA\_HOME環境變量。
  2. MAVEN環境及構建HSF MAVEN工程:添加打war包與HSF開發編譯依賴。
  3. 開發IDE:推薦Eclipse或IDEA。
  4. Eclipse配置:Tomcat4e插件+Pandora配置。
  5. IDEA:配置AliTomcat+Pandora。
  6. 輕量級配置中心:HSF服務的發佈與訂閱。

Pandora Boot環境介紹及準備

產品組件

  • Pandora:一個輕量級的隔離容器-taobao-hsf.sar,它用來隔離Webapp和中間件的依賴,也用來隔離中間件之間的依賴,也實現部署與應用分離。
  • 輕量級配置及註冊中心:對於開發者能夠在本地使用輕量級配置及註冊中心實現應用的註冊、發現與配置管理,完成應用的開發和測試。本地開發完應用託管到EDAS服務上,EDAS內置註冊及配置中心,所以註冊及配置功能仍然能夠正常使用。

基本結構

HSF結構分爲6個部分,共同組合在一塊兒能夠提供全功能的分佈式服務,分別是:json

  • 服務消費方:消費服務提供方提供的服務,服務消費者經過地址註冊中心訂閱服務,根據訂閱到的地址信息發起調用,地址註冊中心做爲旁路不參與調用。
  • 服務提供方: 在服務框架中真正提供服務功能實現的應用實例,爲了保障服務提供的高可用性,通常均是集羣部署,同時將地址信息發佈到地址註冊中心。
  • 地址註冊中心:接受服務提供方發佈的地址,當服務消費方根據服務進行訂閱時,會將地址信息推送給服務消費方,註冊中心就是服務信息的中介,提供服務發現的能力
  • 持久化配置中心:持久化的配置中心用於存儲 HSF 服務的各類治理規則,HSF 客戶端在啓動的過程當中會向持久化配置中心訂閱各類服務治理規則,如路由規則、歸組規則、權重規則等,從而根據規則對調用過程的選址邏輯進行干預。
  • 元數據存儲中心:元數據是指 HSF 服務對應的方法列表以及參數結構等信息,元數據不會對 HSF 的調用過程產生影響,所以元數據存儲中心也並非必須的。但考慮到服務運維的便捷性,HSF客戶端在啓動時會將元數據上報到元數據存儲中心,以便提供給服務運維使用
  • HSF運維平臺(HSF控制檯):HSF 控制檯經過打通地址註冊中心 ConfigServer、持久化配置中心 Diamond、元數據存儲中心Redis,爲用戶提供了一些列服務運維功能,包括服務查詢、服務治理規則管理、服務測試、服務 Mock、單機運維等,旨在提升 HSF 服務研發的效率、運維的便捷性。

環境準備流程步驟

在進行開發前,須要準備一下基本內容:api

  1. JDK基礎運行環境:正確安裝JDK 7+,正確配置JAVA\_HOME環境變量。
  2. MAVEN環境及構建Pandora Boot MAVEN工程:添加打FatJar包與Pandora Boot開發編譯依賴。
  3. 開發IDE:推薦Eclipse或IDEA。
  4. Eclipse配置:啓動Pandora Boot應用主函數自動加載Pandora容器。
  5. IDEA配置:啓動Pandora Boot應用主函數自動加載Pandora容器。
  6. 輕量級註冊及配置中心:Pandora Boot應用的註冊、發現及配置管理。

HSF開發流程及流程圖

開發流程節點:

  1. 服務接口:HSF的服務基於接口實現,接口需在服務設計時預先定義設計好,生產者將實現該接口以提供具體的實現來提供服務,消費者也是基於此接口做爲服務去訂閱。
  2. 服務生產者:生產者將實現以前定義的服務接口以提供具體實現,除了代碼實現的工做以外,因爲HSF是基於Spring框架來實現的,因此還須要再定義服務發佈的XML文件。
  3. 服務消費者:消費者基於接口使用服務,具體調用時須要作兩個步驟
    1. Pandora Boot 的配置文件使用註解@HSFConsumer定義好一個 Bean。
    2. 在使用的時候從 Spring 的 context 中將 Bean 取出。

 title=

圖 1. 流程圖數組

開發HSF應用

背景信息

  1. 無縫兼容:HSF與Spring無縫兼容,標準用法使用Spring的xml配置。
  2. 標準schema:提供hsf:provider,hsf:consumer兩個標準的xml格式。
  3. 代碼無侵入:使用xml方式開發時,代碼不須要感知HSF框架,並且POM中只須要引入edas-sdk。
  4. 框架與WAR包分離:最終輸入的war,不須要包含HSF框架,HSF框架依賴AliTomcat+Pandora方式提供。

您須要按如下步驟構建HSF maven工程:

  1. 構建maven工程,建立完maven工程後,在pom.xml文件中定義添加edas-sdk和spring的依賴。
<dependencies>
    <!-- 添加 servlet 的依賴 -->
    <dependency>
           <groupId>javax.servlet</groupId>
           <artifactId>servlet-api</artifactId>
           <version>2.5</version>
           <scope>provided</scope>
    </dependency>
    <dependency>
           <groupId>org.springframework</groupId>
           <artifactId>spring</artifactId>
           <version>2.5.6</version>
           <type>jar</type>
           <scope>compile</scope>
    </dependency>
    <!-- 添加 edas-sdk 的依賴 -->
    <dependency>
           <groupId>com.alibaba.edas</groupId>
           <artifactId>edas-sdk</artifactId>
           <version>1.5.4</version>
    </dependency>
</dependencies>
  1. 在pom.xml文件中添加HSF應用的maven打包插件。
<build>
    <finalName>itemcenter</finalName>
    <plugins>
           <plugin>
                  <groupId>org.apache.maven.plugins</groupId>
                  <artifactId>maven-compiler-plugin</artifactId>
                  <version>3.1</version>
                  <configuration>
                         <source>1.6</source>
                         <target>1.6</target>
                  </configuration>
           </plugin>
    </plugins>
</build>

定義服務接口

HSF服務基於接口實現調用,定義好接口Sayhello後,生產者將使用該接口實現具體的服務,消費者也基於此接口訂閱服務,因此通常會將接口定義在一個工程中,它會打成一個jar包,發佈到maven倉庫中。下面是公共模塊edasdemo-api接口定義代碼:

package com.edas.demo;
public interface Sayhello {
    public String sayHello();
    public String sayHello(String name);
}

編寫HSF服務提供者

  1. 編寫HSF提供者服務除構建HSF maven工程外,服務提供者須要在pom.xml文件中引入公共模塊工程的依賴。
<dependency>
    <groupId>com.edas.demo</groupId>
    <artifactId>edasdemo-api</artifactId>
    <version>0.0.1-SNAPSHOT</version>
</dependency>
  1. 服務提供者實現接口提供具體的服務,而後發佈對應的服務。
package com.edas.demo;
public class SayhelloImpl implements Sayhello {
    public String sayHello() {
           System.out.println("INFO:執行一次Hello");
           return "Hello!";
    }
    public String sayHello(String name) {
           return "你好"+name;
    }
}
  1. 在hsf-provider-beans.xml中Spring配置HSF服務。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xmlns:hsf="http://www.taobao.com/hsf"
      xmlns="http://www.springframework.org/schema/beans"
      xsi:schemaLocation="http://www.springframework.org/schema/beans
      http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
       http://www.taobao.com/hsf
       http://www.taobao.com/hsf/hsf.xsd" default-autowire="byName">
    <bean id="sayHello" class="com.edas.demo.SayhelloImpl" />
    <!-- 提供一個服務示例 -->
    <hsf:provider id="sayHelloProvider" interface="com.edas.demo.Sayhello"
        ref="sayHello" version="1.0.0">
    </hsf:provider>
</beans>

編寫HSF服務消費者

  1. 編寫消費者服務除構建HSF maven工程外,服務消費者須要在pom.xml文件中引入公共模塊工程的依賴。
<dependency>
    <groupId>com.edas.demo</groupId>
    <artifactId>edasdemo-api</artifactId>
    <version>0.0.1-SNAPSHOT</version>
</dependency>
  1. 在hsf-consumer-beans.xml中Spring配置HSF服務。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:hsf="http://www.taobao.com/hsf"
       xmlns="http://www.springframework.org/schema/beans"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
       http://www.taobao.com/hsf
       http://www.taobao.com/hsf/hsf.xsd" default-autowire="byName"> 
    <!-- 消費一個服務示例 -->
    <hsf:consumer id="sayHello" interface="com.edas.demo.Sayhello"
    version="1.0.0">
    </hsf:consumer>
</beans>
  1. 編寫服務消費者基於接口調用服務提供者的代碼SayhelloServlet。
public class SayhelloServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;
    public SayhelloServlet() {
        super();
    }
    /**
     * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doGet(HttpServletRequest request, HttpServletResponse response) 
                  throws ServletException, IOException {
           ApplicationContext ctx = WebApplicationContextUtils.getWebApplicationContext(sce.getServletContext());
           // 根據 Spring 配置中的 Bean ID "item" 獲取訂閱到的服務
           final Sayhello sayHello = (Sayhello) ctx.getBean("sayHello");
           Thread thread = new Thread( new Runnable() {
                  @Override
                  public void run() {
                         while ( true ) {
                                try {
                                       Thread.sleep(500l);
                                       System.out.println(sayHello.sayHello());
                                       System.out.println(sayHello.sayHello("tom"));
                                } catch ( Throwable e ) {
                                       e.printStackTrace();
                                }
                         }
                  }
           });
           thread.start();
    }
    protected void doPost(HttpServletRequest request, HttpServletResponse response) 
                  throws ServletException, IOException {
           doGet(request, response);
    }
}

開發HSF異步調用

異步調用

對於客戶端來講,並非全部的HSF服務都須要同步等待服務端返回結果,對於這些場景,HSF提供異步調用的方式,讓客戶端沒必要同步阻塞在HSF操做上。在HSF服務發起異步調用,調用結果都是返回的默認值。而真正的結果要在HSFResponseFuture或者回調函數callback中獲取。

Futrue異步調用

HSF與Spring框架無縫集成,可使用Spring XML的方式進行Future異步調用配置。

<bean id="orderService"
class="com.taobao.hsf.app.spring.util.HSFSpringConsumerBean">
<property name="interfaceName"
value="com.alibaba.middleware.hsf.guide.api.service.OrderService"/>
<property name="version"
value="1.0.0"/>
<property name="group"
value="HSF"/>
<!--[設置] 訂閱服務的接口-->
<property name="asyncallMethods">
    <list>
           <value>name:queryOrder;type:future</value>
    </list>
 </property>
</bean>

Callback異步調用

使用Spring XML進行Callback異步調用配置。

<bean id="CallHelloWorld"
class="com.taobao.hsf.app.spring.util.HSFSpringConsumerBean">
    <property name="interfaceName" 
    value="com.alibaba.middleware.hsf.guide.api.service.OrderService"/>
    <property name="version" value="1.0.0"/>
    <property name="group" value="HSF"/>
    <property name="asyncallMethods">
        <list>
            <!--name:methodName;type:future|callback-->   
    <value>name:queryOrder;type:callback;listener:com.alibaba.middleware.hsf.CallbackHandler</value>
        </list>
     </property>
</bean>

開發HSF泛化調用

背景信息

相對於依賴業務客戶端Jar包的正常調用,須要依賴二方包,使用特定的GenericService接口,而傳入須要調用的方法名,方法簽名和參數值進行調用服務。泛化調用更適用於一些網關應用,其中hsfops服務測試也是依賴泛化調用功能。

API形式配置HSF服務

將HSFConsumerBean,配置generic爲true,標識客戶端忽略加載不到接口的異常。

HSFApiConsumerBean hsfApiConsumerBean = new
HSFApiConsumerBean();
hsfApiConsumerBean.setInterfaceName("com.alibaba.middleware.hsf.guide.api.service.OrderService");
hsfApiConsumerBean.setVersion("1.0.0");
hsfApiConsumerBean.setGroup("HSF");
// [設置] 泛化配置
hsfApiConsumerBean.setGeneric("true");
hsfApiConsumerBean.init(true);
//使用泛化接口獲取代理
GenericService genericOrderService = (GenericService) 
hsfApiConsumerBean.getObject();
// ---------------------- 調用 -----------------------//
// [調用] 發起HSF泛化調用, 返回map類型的result。
Map orderModelMap = (Map) genericOrderService.$invoke("queryOrder", 
                            new String[] { Long.class.getName() },
                            new Object[] { 1L });

GenericService提供的$invoke方法包含了真實調用的方法名、入參類型和參數,以便服務端找到改方法。因爲沒有依賴服務端的API jar包,傳入的參數若是是自定義的DTO,須要轉成客戶端能夠序列化的Map類型。

Spring配置HSF服務

上面描述了經過API配置HSF服務,也能夠經過Spring XML配置HSF服務。

<bean id="CallHelloWorld"
class="com.taobao.hsf.app.spring.util.HSFSpringConsumerBean">
    <!--[設置] 訂閱服務的接口-->
    <property name="interfaceName"
value="com.alibaba.middleware.hsf.guide.api.service.OrderService"/>
    <!--[設置] 服務的版本-->
    <property name="version" value="1.0.0"/>
    <!--[設置] 服務的歸組-->
    <property name="group" value="HSF"/>
    <property name="generic" value="true"/>
</bean>

調用上下文

背景信息

請求上下文包括一次性調用相關的屬性,好比調用的地址,調用方的應用名,超時時間等屬性和用戶在接口定義的參數以外傳遞自定義的數據。

設置和獲取本次調用上下文

com.taobao.hsf.util.RequestCtxUtil提供設置和獲取調用上下文的靜態方法,基於ThreadLocal工做,getXXX操做會將XXX屬性從當前ThreadLocal變量中remove掉,僅做用於當前線程的單次調用。

 表1. 客戶端

名稱 描述
setRequestTimeout() 設置單次調用的超時時間
setUserId() 設置本次調用的單元化服務的userId(泛化調用中須要經過此方法配置)
getProviderIp() 獲取【最近一次】調用的服務端的IP
setTargetServerIp(String ip) 設置當前線程下一次調用的目標服務器IP(此IP必須包含在內存已提供服務的地址列表裏)
setDirectTargetServerIp(String targetIp) 設置當前線程下一次調用的目標服務器IP(繞過註冊中心,忽略內存裏的地址列表)

表 2. 服務端

名稱 描述
getClientIp() 服務端獲取調用方IP
getAppNameOfClient() 服務端獲取調用方的應用名
isHttpRequest() 是不是http調用
getHttpHeader(String key) 獲取http請求的header屬性

傳遞自定義請求上下文

RpcContext提供一種不修改接口,向服務端額外傳遞數據的方式。參數能夠是自定義的DO或者基本類型。要保證對端也有該對應的類型,而且能夠可以被序列化。

  1. 傳遞自定義上下文開發示例 ,在構建的Maven項目中導入下面依賴。
<dependency>
    <groupId>com.taobao.hsf</groupId>
    <artifactId>hsf-feature-context</artifactId>
</dependency>
  1. 客戶端發起調用前,設置上下文。
RPCContext rpcContext = RPCContext.getClientContext();
rpcContext.putAttachment("tetantId", "123");
orderService.queryOrder(1L);
  1. 服務端業務方法內,獲取上下文。
RPCContext rpcContext = RPCContext.getServerContext();
String myContext = (String)rpcContext.getAttachment("tetantId");

配置序列化

序列化的過程是將JAVA對象轉成byte數組在網絡中傳輸,反序列化會將byte數組轉成JAVA對象。

序列化方式配置

序列化的選擇須要考慮兼容性,性能等因素,HSF的序列化方式支持JAVA、hessian、hessian二、JSON、kyro,默認是hessian2。這些序列化方式的對比和配置(只在服務端配置HSFApiProviderBean)以下表所示:

序列化方式 maven依賴 配置 兼容性 性能
hessian2 <artifactId>hsf-io-serialize-hessian2</artifactId> setPreferSerializeType("hessian2")
java <artifactId>hsf-io-serialize-java</artifactId> setPreferSerializeType("java") 最好 通常
fastjson <artifactId>hsf-io-serialize-json</artifactId> setPreferSerializeType("json")
kryo <artifactId>hsf-io-serialize-kryo</artifactId> setPreferSerializeType("kryo") 通常 最好

API形式配置HSF服務

HSFApiProviderBean hsfApiProviderBean = new HSFApiProviderBean();
hsfApiProviderBean.setPreferSerializeType("hessian2");

Spring配置HSF服務

Spring框架是在應用中普遍使用的組件,若是不想經過API的形式配置HSF服務,可使用Spring XML的形式進行配置,上述例子中的API配置等同於以下XML配置:

<bean class="com.taobao.hsf.app.spring.util.HSFSpringProviderBean" init-method="init">
    <!--[設置] 發佈服務的接口-->
    <property name="serviceInterface" value="com.alibaba.middleware.hsf.guide.api.service.OrderService"/>
    <!--[設置] 服務的實現對象 target必須配置[ref],爲須要發佈爲HSF服務的spring bean id-->
    <property name="target" ref="引用的BeanId"/>
    <!--[設置] 服務的版本-->
    <property name="serviceVersion" value="1.0.0"/>
    <!--[設置] 服務的歸組-->
    <property name="serviceGroup" value="HSF"/>
    <!--[設置] 服務的響應時間-->
    <property name="clientTimeout" value="3000"/>
    <!--[設置]  服務傳輸業務對象時的序列化類型-->
    <property name="preferSerializeType" value="hessian2"/>
</bean>

超時設置

背景信息

有關網絡調用的請求,都須要配置超時,HSF的默認超時時間是3000ms。客戶端和服務端均可以設置超時,默認優先採用客戶端的配置,若是客戶端沒有配置,使用服務端的超時配置。在服務端設置超時時,須要考慮到業務自己的執行耗時,加上序列化和網絡通信的時間。因此推薦服務端給每一個服務都配置個默認的時間。固然客戶端也能夠根據本身的業務場景配置超時時間,好比一些前端應用,須要用戶快速看到結果,能夠把超時時間設置小一些。

客戶端超時配置

客戶端超時配置有如下兩種方式:

  • API形式配置HSF服務,配置HSFApiConsumerBean的clientTimeout屬性,單位是ms,咱們把接口的超時配置爲1000ms,方法queryOrder配置爲100ms,代碼以下:
HSFApiConsumerBean consumerBean = new HSFApiConsumerBean();
//接口級別超時配置
consumerBean.setClientTimeout(1000);
//xxx
MethodSpecial methodSpecial = new MethodSpecial();
methodSpecial.setMethodName("queryOrder");
//方法級別超時配置,優先於接口超時配置
methodSpecial.setClientTimeout(100);
consumerBean.setMethodSpecials(new MethodSpecial[]{methodSpecial});
  • Spring配置HSF服務,上述例子中的API配置等同於以下XML配置:
<bean id="CallHelloWorld" class="com.taobao.hsf.app.spring.util.HSFSpringConsumerBean">
    ...
    <property name="clientTimeout" value="1000" />
    <property name="methodSpecials">
      <list>
        <bean class="com.taobao.hsf.model.metadata.MethodSpecial">
          <property name="methodName" value="queryOrder" />
          <property name="clientTimeout" value="100" />
        </bean>
      </list>
    </property>
    ...
</bean>

服務端超時配置

服務端超時配置也有兩種不一樣的方式:

  • API形式配置HSF服務,配置HSFApiProviderBean的clientTimeout屬性,單位是ms,代碼以下:
HSFApiProviderBean providerBean = new HSFApiProviderBean();
//接口級別超時配置
providerBean.setClientTimeout(1000);
//xxx
MethodSpecial methodSpecial = new MethodSpecial();
methodSpecial.setMethodName("queryOrder");
//方法級別超時配置,優先於接口超時配置
methodSpecial.setClientTimeout(100);
providerBean.setMethodSpecials(new MethodSpecial[]{methodSpecial});
  • Spring配置HSF服務,上述例子中的API配置等同於以下XML配置:
<bean class="com.taobao.hsf.app.spring.util.HSFSpringProviderBean" init-method="init">
    ...
    <property name="clientTimeout" value="1000" />
    <property name="methodSpecials">
      <list>
        <bean class="com.taobao.hsf.model.metadata.MethodSpecial">
          <property name="methodName" value="queryOrder" />
          <property name="clientTimeout" value="2000" />
        </bean>
      </list>
    </property>
    ...
</bean>

服務端線程池配置

HSF服務端線程池主要分爲IO線程和業務線程,其中IO線程模型就是netty reactor網絡模型中使用的。

默認線程池配置

服務端線程池是用來執行業務邏輯的線程池,線程池默認的core size是50,max size是720,keepAliveTime 500s。隊列使用的是SynchronousQueue,沒有緩存隊列,不會堆積用戶請求。 當服務端線程池全部線程(720)都在處理請求時,對於新的請求,會當即拒絕,返回Thread pool is full異常。可使用下面VM參數(-D參數)進行配置。

  • 線程池最小配置:-Dhsf.server.min.poolsize
  • 線程池最大的配置:-Dhsf.server.max.poolsize
  • 線程收斂的存活時間:-Dhsf.server.thread.keepalive

服務線程池配置

對於一些慢服務、併發高,能夠爲其單獨配置線程池,以避免佔用過多的業務線程,影響應用的其餘服務的調用,你能夠經過如下兩種方式配置HSF應用:

  • API形式配置HSF應用:
HSFApiProviderBean hsfApiProviderBean = new HSFApiProviderBean();
//...
hsfApiProviderBean.setCorePoolSize("50");
hsfApiProviderBean.setMaxPoolSize("200");
  • Spring配置HSF應用:
<bean class="com.taobao.hsf.app.spring.util.HSFSpringProviderBean" init-method="init">
    <!--[設置] 發佈服務的接口-->
    <property name="serviceInterface" value="com.alibaba.middleware.hsf.guide.api.service.OrderService"/>
    <property name="corePoolSize" value="50" />
    <property name="maxPoolSize" value="200" />
</bean>

Pandora Boot開發流程

開發流程節點:

  1. 服務接口:Pandora Boot 的服務基於接口實現,接口需在服務設計時預先定義設計好,生產者將實現該接口以提供具體的實現來提供服務,消費者也是基於此接口做爲服務去訂閱。
  2. 服務生產者:生產者將實現以前定義的服務接口以提供具體實現,除了代碼實現的工做以外,因此還須要再定義服務發佈的註解@HSFProvider配置標識爲服務提供者。
  3. 服務消費者:消費者基於接口使用服務,具體調用時須要作兩個步驟:
    1. Spring 的配置文件使用標籤訂義好一個Bean。
    2. 在使用的時候從Spring的context中將Bean取出。

開發Pandora Boot應用

構建Pandora Boot maven工程

  1. 構建maven工程,建立完maven工程後,在pom.xml文件中配置EDAS的私服庫地址和插件私服庫地址。
<repositories>
     <repository>
            <id>central</id>
            <url>http://repo1.maven.org/maven2</url>
            <releases>
                   <enabled>true</enabled>
            </releases>
            <snapshots>
                   <enabled>true</enabled>
            </snapshots>
     </repository>
     <repository>
            <id>edas-oss-central</id>
            <name>taobao mirror central</name>
            <url>http://edas-public.oss-example.aliyuncs.com/repository</url>
            <snapshots>
                   <enabled>true</enabled>
            </snapshots>
            <releases>
                   <enabled>true</enabled>
            </releases>
     </repository>
</repositories>
<pluginRepositories>
     <pluginRepository>
            <id>central</id>
            <url>http://repo1.maven.org/maven2</url>
            <releases>
                   <enabled>true</enabled>
            </releases>
            <snapshots>
                   <enabled>true</enabled>
            </snapshots>
     </pluginRepository>
     <pluginRepository>
            <id>edas-oss-plugin-central</id>
            <url>http://edas-public.oss-example.aliyuncs.com/repository</url>
            <snapshots>
                   <enabled>true</enabled>
            </snapshots>
            <releases>
                   <enabled>true</enabled>
            </releases>
     </pluginRepository>
</pluginRepositories>
  1. 構建maven工程,建立完maven工程後,在pom.xml文件中定義添加pandora boot和spring boot依賴的版本。
<properties>
     <spring-boot.version>2.1.6.RELEASE</spring-boot.version>
     <pandora-boot.version>2019-06-stable</pandora-boot.version>
</properties>
<dependencyManagement>
     <dependencies>
            <dependency>
                   <groupId>org.springframework.boot</groupId>
                   <artifactId>spring-boot-dependencies</artifactId>
                   <version>${spring-boot.version}</version>
                   <type>pom</type>
                   <scope>import</scope>
            </dependency>
            <dependency>
                   <groupId>com.taobao.pandora</groupId>
                   <artifactId>pandora-boot-starter-bom</artifactId>
                   <version>${pandora-boot.version}</version>
                   <type>pom</type>
                   <scope>import</scope>
            </dependency>
</dependencyManagement>
  1. 在pom.xml添加pandora boot 和spring boot開發的依賴。
<dependencies>
        <dependency>
            <groupId>com.alibaba.boot</groupId>
            <artifactId>pandora-hsf-spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
           <groupId>org.slf4j</groupId>
           <artifactId>jcl-over-slf4j</artifactId>
        </dependency>
        <dependency>
            <groupId>com.taobao.pandora</groupId>
            <artifactId>pandora-boot-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <!-- Use Swagger UI for REST API test -->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
            <version>2.6.1</version>
        </dependency>
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>2.6.1</version>
        </dependency>
    </dependencies>
  1. 在pom.xml文件中添加pandora boot應用的maven打包插件。
<build>
     <plugins>
            <plugin>
                   <groupId>com.taobao.pandora</groupId>
                   <artifactId>pandora-boot-maven-plugin</artifactId>
                   <version>2.1.11.8</version>
                   <executions>
                          <execution>
                                 <phase>package</phase>
                                 <goals>
                                        <goal>repackage</goal>
                                 </goals>
                          </execution>
                   </executions>
            </plugin>
     </plugins>
</build>
  1. 在工程目錄resources下的application.properties文件中配置應用名和監聽端口號。
spring.application.name=hsf-provider
server.port=8082
spring.hsf.version=1.0.0
spring.hsf.timeout=1000
  1. 添加服務啓動的main函數入口。
@SpringBootApplication
public class HSFProviderApplication {
    public static void main(String[] args) {
        // 啓動 Pandora Boot 用於加載 Pandora 容器
        PandoraBootstrap.run(args);
        SpringApplication.run(HSFProviderApplication.class, args);
        // 標記服務啓動完成,並設置線程 wait。防止用戶業務代碼運行完畢退出後,致使容器退出。
        PandoraBootstrap.markStartupAndWait();
    }
}

編寫Pandora Boot服務提供者

  1. 對於服務提供者,其建立過程與以上構建Pandora Boot maven工程步驟一致外,須要定義服務接口EchoService提供給消費者訂閱。
public interface EchoService {
    String echo(String string);
    String echoFuture(String str);
    String echoCallback(String str);
    String echoHSFMix(int id);
    String echoMQConsumer(String str);
}
  1. 建立服務提供者的具體實現類EchoServiceImpl,並經過註解方式發佈服務。
@HSFProvider(serviceInterface = EchoService.class, serviceGroup = "HSF", serviceVersion = "1.0.0")
public class EchoServiceImpl implements EchoService {
    @Autowired
    private EchoDao echoDao;
    @Autowired
    private SimpleMQConsumer simpleMQConsumer;
    @Autowired
    private SimpleMQProduce simpleMQProduce;
    public String echo(String str) {
        return "hello --" + str;
    }
    public String echoFuture(String str) {
        return "welcome --" + str;
    }
    public String echoCallback(String str) {
        return "welcome --" + str;
    }
    public String echoHSFMix(int id) {
        //寫消息
        simpleMQProduce.sendMsg(id+"");
        return echoDao.findById(id).getUserName();
    }
    public String echoMQConsumer(String str) {
        //訂閱消息
        simpleMQConsumer.receive();
        return str;
    }
}

編寫Pandora Boot消費者服務

  1. 對於服務消費者,其建立過程與以上構建Pandora Boot maven工程步驟一致,添加服務提供者定義的接口複製到消費者服務工程。
public interface EchoService {
    String echo(String string);
    String echoFuture(String str);
    String echoCallback(String str);
    String echoHSFMix(int id);
    String echoMQConsumer(String str);
}
  1. 添加消費者服務配置類及業務邏輯代碼。
消費者服務配置類:
@Configuration
public class HsfConfig {
    //經過註解的方式將服務消費者的實例注入到Spring的Context中,同步調用
     @HSFConsumer(clientTimeout = 3000, serviceVersion = "1.0.0")
    private EchoService echoService;
}
消費者服務實現調用HSF服務提供者:
@RestController
@RequestMapping(value = "/poc")
@Api(description = "HSF-POC功能測試接口")
public class ConsumerController {
    @Autowired
    private EchoService echoService;
    @NacosValue(value = "${useLocalCache:false}", autoRefreshed = true)
    private String useLocalCache;
    @ApiOperation(value = "獲取服務者返回信息 A->C")
    @RequestMapping(value = "/hsf-echo", method = RequestMethod.GET)
    public String echo(@RequestParam("str") String str) {
        return echoService.echo(str) + "\r\n";
    }
    @ApiOperation(value = "經過ID查詢數據庫獲取返回信息、RocketMQ寫信息 A->C")
    @RequestMapping(value = "/hsf-echo-mix", method = RequestMethod.GET)
    public String echoHSFMix(@RequestParam("id") int id) {
        return echoService.echoHSFMix(id) + "\r\n";
    }
    @ApiOperation(value = "RocketMQ訂閱消息 A->C")
    @RequestMapping(value = "/hsf-echo-mq", method = RequestMethod.GET)
    public String echoMQConsumer(@RequestParam("str") String str) {
        return echoService.echoMQConsumer(str) + "\r\n";
    }
    @ApiOperation(value = "獲取版本信息")
    @RequestMapping(value = "/echo-version", method = RequestMethod.GET)
    public String echoVersion() {
        return "This is pandora boot version 2" + "\r\n";
    }
}

開發Pandora Boot異步調用

對於客戶端來講,並非全部的HSF服務都是須要同步等待服務端返回結果的,對於這些場景,HSF提供異步調用的方式,讓客戶端沒必要同步阻塞在HSF操做上。在HSF服務發起異步調用,調用結果都是返回的默認值。而真正的結果要在HSFResponseFuture或者回調函數callback中獲取。

Futrue異步調用

  1. 對於服務提供者,其建立過程與以上構建Pandora Boot maven工程步驟一致外,須要定義服務接口EchoService提供給消費者訂閱,在EchoService添加Future異步調用的接口及實現類。
public interface EchoService {
    String echoFuture(String str);
}
接口實現類:
@HSFProvider(serviceInterface = EchoService.class, serviceGroup = "HSF", serviceVersion =
"1.0.0")
public class EchoServiceImpl implements EchoService {
    public String echoFuture(String str) {
        return "welcome --" + str;
    }
}
  1. 對於服務消費者,其建立過程與以上構建Pandora Boot maven工程步驟一致外,編寫Future異步調用代碼。
在配置類經過註解配置HSF接口方法爲異步調用:
//Future異步調用
@HSFConsumer(serviceGroup = "HSF", serviceVersion = "1.0.0", futureMethods = "echoFuture")
private EchoService echoService;
編寫對外暴露請求的Future異步調用代碼:
@RequestMapping(value = "/hsf-echo-future", method = RequestMethod.GET)
public String echoFuture(@RequestParam("str") String str) {
       String resp = echoService.echoFuture(str) + "\r\n";
       System.out.println(resp);
       //及時在當前調用上下文中,獲取 future 對象;由於該對象是放在ThreadLocal中,同一線程中後續調用會覆蓋future對象,因此要及時取出。
       HSFFuture hsfFuture = HSFResponseFuture.getFuture();
       //這裏才真正地獲取結果,若是調用還未完成,將阻塞等待結果,5000ms是等待結果的最大時間
       try {
              System.out.println(hsfFuture.getResponse(5000));
       } catch (Throwable throwable) {
              throwable.printStackTrace();
       }
       return resp;
}

Callback異步調用

  1. 對於服務提供者,其建立過程與以上構建Pandora Boot maven一致外,須要定義服務接口EchoService提供給消費者訂閱,在EchoService添加Callback異步調用的接口及實現類。
public interface EchoService {
    String echoFuture(String str);
}
接口實現類:
@HSFProvider(serviceInterface = EchoService.class, serviceGroup = "HSF", serviceVersion = "1.0.0")
public class EchoServiceImpl implements EchoService {
    public String echoFuture(String str) {
        return "welcome --" + str;
    }
}
  1. 對於服務消費者,其建立過程與以上構建Pandora Boot maven步驟一致外,編寫Future異步調用代碼。
註解配置HSF接口方法爲callback調用:
@AsyncOn(interfaceName = EchoService.class, methodName = "echoCallback")
public class CallbackHandler implements HSFResponseCallback {
    public void onAppException(Throwable t) {
        t.printStackTrace();
    }
    public void onAppResponse(Object result) {
        //取 callback 調用時設置的上下文
        Object context = CallbackInvocationContext.getContext();
        System.out.println(result.toString());
        System.out.println(context);
    }
    public void onHSFException(HSFException e) {
        e.printStackTrace();
    }
}
編寫對外暴露請求的Callback異步調用代碼:
@RequestMapping(value = "/hsf-echo-callback", method = RequestMethod.GET)
public String echoCallback(@RequestParam("str") String str) {
       String resp = echoService.echoCallback(str) + "\r\n";
       System.out.println(resp);
       return resp;
}

開發Pandora Boot超時設置

背景信息

註解配置HSF服務,SpringBoot普遍使用的今天,使用註解裝配SpringBean也成爲一種選擇,HSF也支持使用註解進行配置,用來訂閱服務。

客戶端註解超時配置

  1. 首先在Maven項目pom.xml文件中添加依賴Starter:
<dependency>
    <groupId>com.alibaba.boot</groupId>
    <artifactId>pandora-hsf-spring-boot-starter</artifactId>
</dependency>
  1. 一般一個HSF Consumer須要在多個地方使用,但並不須要在每次使用的地方都用@HSFConsumer來標記。只須要寫一個統一個Config類,而後在其它須要使用的地方,直接@Autowired注入便可上述例子中的API配置等同於以下註解配置:
@HSFConsumer(clientTimeout = 1000, methodSpecials =
@HSFConsumer.ConsumerMethodSpecial(methodName = "queryOrder", clientTimeout = "100"))
private OderService orderService;

服務端註解超時配置

  1. 首先在Maven項目pom.xml文件中添加依賴Starter:
<dependency>
    <groupId>com.alibaba.boot</groupId>
    <artifactId>pandora-hsf-spring-boot-starter</artifactId>
</dependency>
  1. 服務端註解配置HSF服務超時設置:
@HSFProvider(serviceInterface = OrderService.class, clientTimeout = 3000)
public class OrderServiceImpl implements OrderService {
    @Autowired
    private OrderDAO orderDAO;
    @Override 
    public OrderModel queryOrder(Long id) {
        return orderDAO.queryOrder(id);
    }
}

開發Pandora Boot服務線程池配置

背景信息

註解配置HSF服務,SpringBoot被普遍使用的今天,使用註解裝配SpringBean也成爲一種選擇,HSF也支持使用註解進行配置,用來訂閱服務。

  1. 首先在Maven項目pom.xml文件中添加依賴Starter。
<dependency>
    <groupId>com.alibaba.boot</groupId>
    <artifactId>pandora-hsf-spring-boot-starter</artifactId>
</dependency>
  1. 將@HSFProvider配置到實現的類型上,上述例子中的API配置等同於以下註解配置。
@HSFProvider(serviceInterface = OrderService.class, corePoolSize = 50, maxPoolSize = 200)
public class OrderServiceImpl implements OrderService {
    @Autowired
    private OrderDAO orderDAO;
    @Override
    public OrderModel queryOrder(Long id) {
        return orderDAO.queryOrder(id);
    }
}

咱們是阿里雲智能全球技術服務-SRE團隊,咱們致力成爲一個以技術爲基礎、面向服務、保障業務系統高可用的工程師團隊;提供專業、體系化的SRE服務,幫助廣大客戶更好地使用雲、基於雲構建更加穩定可靠的業務系統,提高業務穩定性。咱們指望可以分享更多幫助企業客戶上雲、用好雲,讓客戶雲上業務運行更加穩定可靠的技術,您可用釘釘掃描下方二維碼,加入阿里雲SRE技術學院釘釘圈子,和更多雲上人交流關於雲平臺的那些事。

本文內容由阿里雲實名註冊用戶自發貢獻,版權歸原做者全部,阿里雲開發者社區不擁有其著做權,亦不承擔相應法律責任。具體規則請查看《阿里雲開發者社區用戶服務協議》和《阿里雲開發者社區知識產權保護指引》。若是您發現本社區中有涉嫌抄襲的內容,填寫侵權投訴表單進行舉報,一經查實,本社區將馬上刪除涉嫌侵權內容。
相關文章
相關標籤/搜索