客戶端服務器(qì)模式

​ 在客戶端服務器(qì)模式下,包含URule Pro Console模塊的應用被部署成一個(gè)獨立的Server,在這個(gè)Server上(shàng)創建規則項目,在項目中根據業務需求添加決策集、決策表、交叉決策表、決策樹(shù)、評分卡、複雜評分卡、決策流等,再把這些(xiē)文件打包到知識包中,最後通(tōng)過HTTP協議暴露給各個(gè)客戶端業務系統使用。

​ 其運行(xíng)示意圖如下所示:

​ 在客戶端服務器(qì)模式下,URule Server上(shàng)給客戶端提供的是若幹個(gè)已經構建好的知識包對象。 ​ 當客戶端需要進行(xíng)規則計(jì)算(suàn)時(shí),它會(huì)檢查當前客戶端中配置的urule.knowledgeUpdateCycle屬性值,如果為(wèi)0,那(nà)麽就直接請(qǐng)求URule Server獲取指知識包;如果為(wèi)1,那(nà)麽它會(huì)首先檢查客戶端本地緩存當中是否存在指定的知識包,如果存在,就取本地緩存中的,如果不存在,則到URule Server下請(qǐng)求指定的知識包,然後将請(qǐng)求到的知識包緩存到客戶端內(nèi)存中,這樣下次就不再到URule Server上(shàng)下載;如果urule.knowledgeUpdateCycle屬性值大(dà)于1,那(nà)麽客戶端會(huì)首先檢查本地緩存中是否存在指定的知識包,如果存在,那(nà)麽就拿(ná)當前時(shí)間(jiān)與本地緩存中的知識包的時(shí)間(jiān)戳進行(xíng)比較,如果小(xiǎo)于urule.knowledgeUpdateCycle屬性值,那(nà)麽就直接取這個(gè)知識包,如果大(dà)于它,那(nà)麽就到URule Server上(shàng)通(tōng)過時(shí)間(jiān)戳檢查當前知識包有(yǒu)沒有(yǒu)更新,如果有(yǒu)更新則取到客戶端,同時(shí)更新客戶端緩存裏對應的知識包;如果沒有(yǒu)更新,那(nà)麽就直接采用當前客戶端緩存裏的知識包。

urule.knowledgeUpdateCycle屬性默認值為(wèi)0,一般情況下,如果我們的客戶端為(wèi)一個(gè)Java Web應用,隻需要将這個(gè)屬性置為(wèi)1即可(kě),因為(wèi)客戶端為(wèi)Web應用,服務端會(huì)通(tōng)過推送方式讓客戶端知識包與服務端時(shí)刻保持一緻。

​ 如果客戶端為(wèi)非Web應用,那(nà)麽才需要修改urule.knowledgeUpdateCycle屬性值為(wèi)一個(gè)大(dà)于1的數(shù)值,以實現定期檢查服務端知識包是否有(yǒu)更新功能。

搭建Server應用

​ 搭建URule Server應用的與安裝與配置一節中介紹的完全相同,就是在一個(gè)普通(tōng)的java web應用中将URule Pro Console模塊和(hé)URule Pro Core添加進去。需要注意的是,在URule Server應用搭建好了之後,要保證“/urule/loadknowledge”這個(gè)URL在可(kě)以匿名訪問,比如輸入類似下面的地址,看看應用會(huì)有(yǒu)什麽樣的響應。

http://localhost:8080/urule-server/urule/loadknowledge

​ 在系統未登錄的情況下,訪問上(shàng)述URL看到的不是一個(gè)登錄頁面,那(nà)麽就說明(míng)“/urule/loadknowledge”這個(gè)URL在可(kě)以匿名訪問,是OK的。

​ 如果出現我們應用中的登錄界面之類,那(nà)就說明(míng)“/urule/loadknowledge”這個(gè)URL被我們自己系統內(nèi)部的權限模塊給攔截了,需要我們在系統中對內(nèi)部的權限進行(xíng)配置,使得(de)“/urule/loadknowledge”URL在可(kě)以匿名訪問。做(zuò)好這個(gè)工作(zuò),那(nà)麽URule Server的搭建工作(zuò)就完成了,下面我們看看如果配置客戶端應用。

配置客戶端應用

​ 配置客戶端應用,首先要解決的是如果将URule Pro客戶端所需要的jar包添加到項目中,這裏我們分maven項目以及非maven項目分别進行(xíng)討(tǎo)論。

maven項目配置

如果當前客戶端是基于maven的項目,那(nà)麽我們需要在其pom.xml中添加以下依賴:

<dependency>
    <groupId>com.bstek.urule</groupId>
    <artifactId>urule-core-pro</artifactId>
    <version>4.0.0</version>
</dependency>

​ 可(kě)以看到,在客戶端當中就不再需要urule-console-pro模塊了,隻需要一個(gè)urule-core-pro模塊即可(kě)。

上(shàng)面的maven依賴中,我們使用的是4.0.0版本,實際使用時(shí),可(kě)以在網頁中打開(kāi)https://search.maven.org/,查詢“urule-core-pro”關鍵字,找到最新的urule-core-pro的版本信息,以确定在依賴中version位置要輸入的版本号信息。

​ 到這裏,pom的配置就完成了,我們再來(lái)看看一個(gè)标準的非maven的Web項目如何配置成URule Pro客戶端。

非maven項目配置

​ 如果是一個(gè)非maven普通(tōng)的java web項目,添加URule Pro客戶端就是将urule-core-pro的jar包及其依賴的第三方jar包放到客戶端應用的/WEB-INF/lib目錄下即可(kě),urule-core-pro的jar包我們可(kě)以到https://search.maven.org/上(shàng)下載最新的urule-core-pro-4.x的jar包,對于依賴的第三方jar包,可(kě)以點擊此處下載。

加載spring配置文件

​ URule Pro客戶端所需要的jar包添加到客戶端項目中後,接下來(lái)我們還(hái)需要加載urule-core-pro模塊中的spring配置文件。urule-core-pro模塊中的spring配置文件位于classpath根下,名為(wèi)urule-core-context.xml。

​ 如果我們的客戶端項目沒有(yǒu)采用spring框架,那(nà)麽可(kě)以在web.xml中添加如下所示Listener來(lái)加載urule-core模塊中的spring配置文件:

<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:urule-core-context.xml</param-value>
</context-param>

​ 如果我們的項目也采用了spring框架,那(nà)麽隻需要打開(kāi)項目中任意一個(gè)spring配置文件,在其中添加如下配置即可(kě):

<import resource="classpath:urule-core-context.xml"/>

​ 這樣urule-core-pro的spring配置文件的加載配置就完成了。

配置服務器(qì)地址

​ 對于URule Pro客戶端應用來(lái)說,在進行(xíng)規則計(jì)算(suàn)時(shí),如果客戶端本地緩存沒有(yǒu)相應的知識包,那(nà)麽它會(huì)到URule Server上(shàng)請(qǐng)求對應的知識包,要給URule Pro客戶端應用配置對應的URule Server地址,我們需要添加一個(gè)properties文件,比如在項目的WEB-INF目錄下新建一個(gè)名為(wèi)configure的properties文件,然後在我們項目中任意一個(gè)spring配置文件中添加如下配置加載這個(gè)properties文件:

<bean parent="urule.props">
    <property name="location">
        <value>/WEB-INF/configure.properties</value>
    </property>
</bean>

​ 打開(kāi)這個(gè)configure.properties文件,在其中添加一個(gè)名為(wèi)“urule.resporityServerUrl”屬性,比如 urule.resporityServerUrl=http://192.168.18.11:8080/urule-server , 就表明(míng)我們為(wèi)當前URule客戶端應用配置的URule Server為(wèi)"http://192.168.18.11:8080/urule-server",這樣在進行(xíng)規則計(jì)算(suàn)時(shí),如果客戶端本地緩存沒有(yǒu)相應的知識包,那(nà)麽它會(huì)到“http://192.168.18.11:8080/urule-server” 上(shàng)請(qǐng)求對應的知識包。

如果同步不成功需要檢查url配置,确保url的末尾沒有(yǒu)添加/,例如:“http://192.168.18.11:8080/urule-server/” 是不允許的

URule Pro中提供了動态加載Jar包及Spring配置文件功能,在客戶端配置了urule.resporityServerUrl屬性後,客戶端在啓動時(shí)會(huì)自動到服務端檢查是否有(yǒu)新的動态Jar文件信息需要加載,如果有(yǒu)則下載到客戶端并加載,所以這時(shí)服務端的“urule/dynamic/checkLatestJarsDir”和(hé)“urule/dynamic/loadDynamicJars”這兩個(gè)URL要保證匿名可(kě)訪問(URULE框架默認允許匿名訪問),否則客戶端啓動時(shí)會(huì)産生(shēng)錯誤。

注意:當前如果客戶端上(shàng)配置了urule.resporityServerUrl屬性值,但(dàn)這個(gè)屬性對應的Server不存在,或無法訪問,那(nà)麽客戶端在啓動到服務端檢查是否有(yǒu)新的動态Jar文件信息需要加載操作(zuò)就會(huì)報錯,導緻客戶端啓用失敗。

​ 到這裏,URule Pro客戶端的配置就全部完成了,通(tōng)過指定urule.resporityServerUrl屬性值,我們的客戶端無論是标準的Java Web應用還(hái)是普通(tōng)的Java應用,都可(kě)以與URule Server連接,從而在運行(xíng)時(shí)獲取到相應的知識包。

​ 但(dàn)是,如果我們的客戶端應用是标準的Java Web應用,那(nà)麽除了可(kě)以通(tōng)過urule.resporityServerUrl屬性指定URule Server地址,從而主動獲取知識包外,還(hái)可(kě)以通(tōng)過配置一個(gè)Servlet被動接收URule Server推送過來(lái)的知識包,這樣模式,相比主動獲取知識包方式要高(gāo)效的多(duō),同時(shí)還(hái)可(kě)以時(shí)刻與Server上(shàng)的知識包保持同步。

​ 下面就來(lái)看看如何給一個(gè)類型為(wèi)标準Java Web應用的客戶端配置接收服務端推送過來(lái)知識包的Servlet。

配置web.xml

​ 在之前內(nèi)容中我們就提過,URule Pro的客戶端即可(kě)以是标準的Java Web應用,也可(kě)以是普通(tōng)的Java應用。如果是普通(tōng)Java應用,那(nà)麽上(shàng)面的那(nà)麽配置就可(kě)以了;如果是标準的Java Web應用,那(nà)麽我們還(hái)可(kě)以做(zuò)些(xiē)配置,使得(de)其以主動接收來(lái)自URule Server上(shàng)推送過來(lái)的最新的知識包。

​ 對于URule Server來(lái)說,如果在規則項目中配置了URule的客戶端地址,那(nà)麽在知識包發布時(shí)會(huì)自動推送到這些(xiē)客戶端。所以我們的URule Pro客戶端如果是個(gè)标準的Java Web應用,那(nà)麽可(kě)以配置一個(gè)可(kě)以接收URule Server推送的知識包的Servlet。

打開(kāi)項目的web.xml,在其中添加如下servlet配置:

<servlet>
    <servlet-name>uruleClientServlet</servlet-name>
    <servlet-class>com.bstek.urule.KnowledgePackageReceiverServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>uruleClientServlet</servlet-name>
    <url-pattern>/knowledgepackagereceiver</url-pattern>
</servlet-mapping>

在上(shàng)面的servlet配置中,url-pattern項的“/knowledgepackagereceiver”值是固定的,不能修改為(wèi)其它值,否則将無法收到URule Server上(shàng)推送過來(lái)的知識包。 同時(shí),客戶端中的這個(gè)用于接收知識包推送的Servlet還(hái)要保證其可(kě)以匿名訪問,也就是客戶端中如果被權限框架包裹,那(nà)麽要保證“/knowledgepackagereceiver”這個(gè)URL在不登錄的情況下就可(kě)以訪問, 否則服務端将無法把知識包推送到目标客戶端。

​ 要實現推送功能,除了要配置對應Java Web客戶端上(shàng)的Servlet,還(hái)需要在URule Server上(shàng)對可(kě)以接收推送的客戶端進行(xíng)定義。

URule Server上(shàng)客戶端配置

​ 如果當前登錄用戶為(wèi)團隊創建人(rén)員,那(nà)麽在登錄系統後,可(kě)以看到客戶端配置入口,如下圖:

​ 我們可(kě)以添中多(duō)個(gè)客戶端,這樣在當前項目發布知識包時(shí)就可(kě)以自動推送到這裏的客戶端上(shàng),如下圖:

​ 配置完成後,進行(xíng)項目的知識包管理(lǐ)頁面,查看某個(gè)知識包的已發布知識包,在彈出窗口可(kě)以看到已發布的知識包列表,選中某條需要推送到客戶端的知識包,點擊右鍵,在彈出菜單中選擇推送到客戶端,如下圖:

​ 點擊該菜單項,系統會(huì)嘗試向這些(xiē)客戶端推送當前發布的知識包對象,如果這些(xiē)客戶端是存在的,就可(kě)以發布成功,這樣對應的客戶端本地緩存中就會(huì)存儲這個(gè)發布的知識包對象。

客戶端動态配置

​ 實際使用時(shí),我們可(kě)能會(huì)在諸如docker之類的容器(qì)中部署客戶端應用,在這種情況下,客戶端的IP地址不是固定的,此時(shí)要在服務端指定客戶地址的話(huà),采用上(shàng)面的方法就行(xíng)不通(tōng)了。 ​ 為(wèi)了兼容這種客戶端IP地址動态變化的場(chǎng)景,URule Pro當中還(hái)提供了一個(gè)名為(wèi)ClientProvider接口,通(tōng)過實現這個(gè)接口來(lái)動态指定客戶端IP地址,ClientProvider接口類源碼如下:

package com.bstek.urule.console;

import java.util.List;

import com.bstek.urule.console.database.model.UrlConfig;

/**
* @author Jacky.Gao
* @since 2021年9月26日
*/
public interface ClientProvider {
    List<UrlConfig> loadClients(String groupId);
}

​ 實現了ClientProvider接口後,隻需要将實現類配置到Spring上(shàng)下文當中,使之成為(wèi)一個(gè)标準的Spring Bean即可(kě),這樣引擎在獲取配置的客戶端信息時(shí)就會(huì)嘗試從這個(gè)實現類中獲取。

​ 一旦我們實現了該接口,并将其配置到Spring中,重啓應用,在客戶端配置頁面就可(kě)以看到該接口實現類中加載的客戶端列表,同時(shí)該頁面也不再提供客戶端信息的編輯功能。

Spring-Cloud框架

例如在spring-cloud中我們可(kě)以通(tōng)過DiscoveryClient的getInstances獲得(de)對應服務的ip地址列表 參考代碼:

public class MemberClientProvider implements ClientProvider {

    @Override
    public List<UrlConfig> loadClients(String arg0) {
        List<ServiceInstance> instances = Utils.getApplicationContext().getBean(DiscoveryClient).getInstances("consul-member");
        List<UrlConfig> clients = new ArrayList<UrlConfig>();
        for (ServiceInstance instance:instances) {
            UrlConfig client = new UrlConfig();
            client.setName(instance.getHost());
            client.setType(UrlType.client);
            client.setGroupId("bstek");
            client.setUrl("http:"+instance.getHost()+":"+instance.getPort());
            clients.add(client)j;
        }
        return clients;
    }

}

K8S

如果不是spring-cloud框架,直接K8S部署,可(kě)以通(tōng)過K8S提供的client-java的SDK獲取到IP地址列表,詳細辦法參考K8S官方文檔。 一篇簡單的參考文檔:

http://events.jianshu.io/p/d8a073f8d416

前面我們介紹了在URule Pro客戶端中配置“urule.knowledgeUpdateCycle”屬性的含義及目的,對于客戶端為(wèi)Web應用類型,一旦我們在URule Server中配置了客戶端地址,那(nà)麽知識包每次發布都會(huì)被推送到這些(xiē)客戶端。這樣在生(shēng)産環境下,對于客戶端來(lái)說,“urule.knowledgeUpdateCycle”屬性值隻要設置成1即可(kě),也就是每次都在客戶端本地緩存中查找目标知識包是否存在,如果存在直接使用。如果知識包有(yǒu)更新,URule Server會(huì)動推送到目标客戶端,對于客戶端來(lái)說直接從本地緩存中就可(kě)以取到最新的知識包,這樣可(kě)以剔除所有(yǒu)不必要的客戶端與服務端的交互,節省網絡資源,同時(shí)可(kě)以大(dà)幅提高(gāo)客戶端規則計(jì)算(suàn)性能。

我們在對URule Pro進行(xíng)性能測試時(shí),一定要将“urule.knowledgeUpdateCycle”屬性值隻要設置成1,因為(wèi)“urule.knowledgeUpdateCycle”屬性值默認為(wèi)0,所以每次執行(xíng)規則都會(huì)編譯一次規則包,這樣會(huì)帶來(lái)很(hěn)差的測試結果,所以這點非常關鍵; 在客戶端中,将“urule.knowledgeUpdateCycle”設置成1後,檢驗該屬性是否生(shēng)效最好的方法是在客戶端調用服務端知識包時(shí)觀察控制(zhì)台是否有(yǒu)類似“Load knowledgepackage [ packageId ] from remote...”這樣的字符輸出,如果有(yǒu)類似輸出,則說明(míng)urule.knowledgeUpdateCycle=1未生(shēng)效, 我們需要進一步檢查配置,找到未生(shēng)效的原因。 同時(shí),名為(wèi)"urule.debug"的屬性也會(huì)對性能産生(shēng)一點影(yǐng)響,這個(gè)屬性值默認為(wèi)true,表示允許進行(xíng)調試信息輸出,這樣對于性能測試來(lái)說無疑會(huì)造成影(yǐng)響,所以在性能測試或生(shēng)産環境中建議将“urule.debug”屬性設置為(wèi)false,這樣可(kě)以減少(shǎo)不必要的調試信息輸出,可(kě)顯著提升性能。

results matching ""

    No results matching ""