自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

解鎖轉(zhuǎn)轉(zhuǎn)門店業(yè)務(wù)靈活性:如何利用MVEL引擎優(yōu)化結(jié)算流程

開發(fā)
隨著門店結(jié)算業(yè)務(wù)的不斷擴(kuò)展,我們面臨了日益增長的復(fù)雜性。目前,需要聚合計算的結(jié)算指標(biāo)數(shù)量龐大,每個指標(biāo)都依托于一套復(fù)雜的公式,而這些公式又是由眾多業(yè)務(wù)配置參數(shù)構(gòu)成的。

1 業(yè)務(wù)現(xiàn)狀

隨著門店結(jié)算業(yè)務(wù)的不斷擴(kuò)展,我們面臨了日益增長的復(fù)雜性。目前,需要聚合計算的結(jié)算指標(biāo)數(shù)量龐大,每個指標(biāo)都依托于一套復(fù)雜的公式,而這些公式又是由眾多業(yè)務(wù)配置參數(shù)構(gòu)成的。業(yè)務(wù)的復(fù)雜化導(dǎo)致需要維護(hù)的公式數(shù)量急劇增加,帶來了一系列挑戰(zhàn):

  1. 配置分散問題:業(yè)務(wù)配置目前分散在代碼、Apollo配置中心以及數(shù)據(jù)庫中,這種分散性使得維護(hù)工作變得繁瑣且低效。
  2. 頻繁更新問題:隨著業(yè)務(wù)的不斷調(diào)整,結(jié)算公式需要頻繁更新。每一次微小的改動都要求進(jìn)行系統(tǒng)上線,這增加了開發(fā)的負(fù)擔(dān)。
  3. 代碼維護(hù)問題:每次新公式的上線,都需要保留舊版本的指標(biāo)公式。這導(dǎo)致在代碼中需要同時維護(hù)多套指標(biāo)公式,嚴(yán)重影響了代碼的可讀性和可維護(hù)性。

圖片

指標(biāo)計算流程

基于這些問題,我們的優(yōu)化方案是建立一個公式管理中心,將所有的這些指標(biāo)運(yùn)算進(jìn)行收攏。同時引入了強(qiáng)大的表達(dá)式引擎來處理這些運(yùn)算,本文就如何使用表達(dá)式引擎解決這些問題展開分析。

2 調(diào)研分析

2.1 為什么選擇表達(dá)式引擎

在門店結(jié)算業(yè)務(wù)的核心環(huán)節(jié),我們專注于對關(guān)鍵指標(biāo)的公式進(jìn)行精確計算,并有效管理不同版本的公式。通過引入表達(dá)式引擎,我們能夠?qū)⒂嬎氵壿嫃臉I(yè)務(wù)代碼中解耦,實(shí)現(xiàn)業(yè)務(wù)邏輯與計算邏輯的分離。這種方法不僅集中化了指標(biāo)公式的管理,而且由于許多表達(dá)式引擎原生支持高精度的BigDecimal類型,它還確保了金融級精度的貨幣計算需求得到滿足。

此外,表達(dá)式引擎的動態(tài)執(zhí)行特性允許我們在不重新部署的情況下實(shí)時更新公式,這樣的靈活性對于快速響應(yīng)業(yè)務(wù)需求變化至關(guān)重要,大大提升了業(yè)務(wù)調(diào)整的敏捷性和系統(tǒng)的可維護(hù)性。

2.2 表達(dá)式引擎的對比

本文主要對幾種常見的表達(dá)式引擎AviatorScript MVEL QLExpress OGNL 進(jìn)行對比分析。

2.2.1 簡介

AviatorScript: 是一款高性能、輕量級的Java語言實(shí)現(xiàn)的表達(dá)式求值引擎,Aviator可直接將表達(dá)式編譯成Java字節(jié)碼,交給JVM去執(zhí)行。
MVEL(MVFLEX Expression Language): 是一種動態(tài)/靜態(tài)的可嵌入的表達(dá)式語言和為Java平臺提供Runtime(運(yùn)行時)的語言,在很大程度上受到了Java語法的啟發(fā),支持解釋模式執(zhí)行,也支持編譯模式執(zhí)行。
QLExpress(Quick Language Express):  是阿里巴巴開源的一門動態(tài)腳本引擎解析工具,起源于阿里巴巴的電商業(yè)務(wù),旨在解決業(yè)務(wù)規(guī)則、表達(dá)式、數(shù)學(xué)計算等動態(tài)腳本的解析問題。具有線程安全、高效執(zhí)行、代碼依賴小等特性。
OGNL(Object-Graph Navigation Language): 即對象圖導(dǎo)航語言,是一種功能強(qiáng)大的開源表達(dá)式語言,通過簡單一致的表達(dá)式語法,可以存取對象的任意屬性,調(diào)用對象的方法,遍歷整個對象的結(jié)構(gòu)圖,并實(shí)現(xiàn)字段類型的轉(zhuǎn)化等功能,常用于Java中。

2.2.2 性能分析

性能測試工具使用JMH(Java Microbenchmark Harness),是由 OpenJDK/Oracle 官方發(fā)布的工具,他們對JIT和JVM對于基準(zhǔn)測試影響非常了解,能得到一個更好的結(jié)果。
在當(dāng)前的業(yè)務(wù)場景中,主要對帶有變量和條件判斷的表達(dá)式進(jìn)行高精度的求值,測試表達(dá)式:(cate==101&&brand==1276)?((a*18 +b*3)*x/y)-c%3+99.64 : a*18

圖片

在本機(jī)環(huán)境下,執(zhí)行五次,AviatorScript的性能要略優(yōu)于 OGNL 優(yōu)于 MVEL ,前三者的性能遠(yuǎn)遠(yuǎn)優(yōu)于QLExpress。

2.2.3 社區(qū)活躍度

社區(qū)活躍度主要看這幾個項目在GitHub上的 StarFork、Watch、Last Commit 來進(jìn)行分析,截止到發(fā)稿時間的對比如下:

項目

Star

Fork

watch

Last Commit

AviatorScript

4.4K

821

171

Jun 11, 2024

MVEL

1.1K

305

78

May 16, 2024

OGNL

215

77

19

Jul 21, 2024

QLExpress

4.7K

1.1K

215

Jul 16, 2024

通過對比可以看到 AviatorScript、MVEL、QLExpress的 Star、Fork、Watch 更高,說明他們的影響力更高,更受歡迎。

2.3 最終選擇

通過以上的對比分析,最終選擇使用 MVEL,因?yàn)樵谛阅?、社區(qū)活躍度上都有很大的優(yōu)勢,在語法上更加的接近Java語法,更容易上手。在一些開源項目中都有使用如:DroolsQuartz Scheduler、JBPM 等。
MVEL的執(zhí)行流程:

圖片

MVEL執(zhí)行流程

每次執(zhí)行都要去解析,編譯,再執(zhí)行表達(dá)式,這種在表達(dá)式執(zhí)行比較頻繁的場景下會很消耗性能。MVEL 提供了兩種執(zhí)行模式來應(yīng)對不同的需求:

解釋模式:這種模式在每次執(zhí)行時都會重新編譯表達(dá)式,雖然提供了動態(tài)執(zhí)行的能力,但頻繁的編譯過程會顯著影響性能。

編譯模式:編譯模式通過將表達(dá)式預(yù)先編譯成字節(jié)碼,然后在后續(xù)執(zhí)行中直接運(yùn)行這些字節(jié)碼,從而避免了每次執(zhí)行時的編譯開銷。這種方法顯著提高了執(zhí)行效率,但需要一種機(jī)制來處理在系統(tǒng)運(yùn)行期間對公式的實(shí)時更新。

通過這兩種模式,我們可以根據(jù)實(shí)際需求選擇最合適的執(zhí)行策略,以實(shí)現(xiàn)性能和靈活性的最佳平衡。

3 業(yè)務(wù)應(yīng)用

3.1 整體設(shè)計

抽取出三個模塊,配置中心、公式管理中心、公式運(yùn)算中心。配置中心維護(hù)指標(biāo)配置數(shù)據(jù),公式中心維護(hù)指標(biāo)公式,公式運(yùn)算中心在前兩者維護(hù)好的基礎(chǔ)上運(yùn)算獲取結(jié)果。

圖片

新的指標(biāo)運(yùn)算流程

3.2 表結(jié)構(gòu)設(shè)計

需要兩張表來存儲配置數(shù)據(jù),業(yè)務(wù)指標(biāo)配置和計算公式配置。

CREATE TABLE `business_config` (
  `id` bigint(20) NOT NULL DEFAULT '0' COMMENT '主鍵',
  `indicator_key` varchar(255) NOT NULL DEFAULT '' COMMENT '指標(biāo)key',
  `attribute_key` varchar(255) NOT NULL DEFAULT '' COMMENT '屬性key',
  `attribute_desc` varchar(255) NOT NULL DEFAULT '' COMMENT '屬性詳細(xì)描述',
  `attribute_value` varchar(255) NOT NULL DEFAULT '' COMMENT '屬性值',
  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '創(chuàng)建時間',
  `create_by` varchar(32) NOT NULL DEFAULT '' COMMENT '創(chuàng)建人',
  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '更新時間',
  `update_by` varchar(32) NOT NULL DEFAULT '' COMMENT '更新人',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uniq_indicator` (`indicator_key`) USING BTREE COMMENT '指標(biāo)唯一索引'
) ENGINE=InnoDB COMMENT='業(yè)務(wù)指標(biāo)配置表';
CREATE TABLE `formula_config`  (
  `id` bigint NOT NULL DEFAULT 0 COMMENT '主鍵',
  `indicator_key` varchar(255) NOT NULL DEFAULT '' COMMENT '指標(biāo)key',
  `formula` varchar(500) NOT NULL DEFAULT '' COMMENT '公式',
  `effective_timestamp` bigint NOT NULL DEFAULT 0 COMMENT '生效的時間戳',
  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '創(chuàng)建時間',
  `create_by` varchar(32) NOT NULL DEFAULT '' COMMENT '創(chuàng)建人',
  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '更新時間',
  `update_by` varchar(32) NOT NULL DEFAULT '' COMMENT '更新人',
  PRIMARY KEY (`id`) 
  INDEX `idx_business_key`(`business_key`) USING BTREE
) ENGINE=InnoDB COMMENT='計算公式表';

3.3 公式運(yùn)算主代碼流程

public BigDecimal cal(String businessKey, Map<String, Object> paramMap) {
        //1.根據(jù)businessKey 獲取配置數(shù)據(jù)
        Map<String, Object> configMap = qfConfigService.getConfigMapByBusinessKey(businessKey);
        //添加業(yè)務(wù)單據(jù)參數(shù)
        configMap.putAll(paramMap);
        //2.根據(jù)businessKey 和時間戳獲取 計算公式
        String formula = getFormula(businessKey, System.currentTimeMillis());
        //3.引擎計算
        return MvelExecutor.evalExpression(formula, configMap);
    }

所有的指標(biāo)運(yùn)算都復(fù)用了同一套運(yùn)算邏輯,配置和公式解耦。
這里說的兩者之間的解耦并不是公式一點(diǎn)都不關(guān)心運(yùn)算需要的配置參數(shù),而是指兩者在遵守約定的前提下,在公式運(yùn)算中,會根據(jù)屬性配置自動填充公式的參數(shù)。

舉個例子,現(xiàn)在有一個指標(biāo)的公式為 (cate==101&&brand==1276)?26:38 在這個公式中有 cate 和 brand 兩個參數(shù),這兩個參數(shù)會提前在配置中心配好,在配置表中就是 attribute_key 這個字段。attribute_key 和 attribute_value 會作為表達(dá)式運(yùn)算參數(shù)的 key 和 value 參與運(yùn)算。

Object object = MVEL.executeExpression(expression, paramMap);

3.4 編譯模式下的緩存策略

考慮到系統(tǒng)的性能問題,項目中使用了編譯執(zhí)行模式,通過一次性編譯并緩存結(jié)果,實(shí)現(xiàn)了多次高效運(yùn)行。這就需要在系統(tǒng)運(yùn)行過程中,對于實(shí)時改變的公式,能夠及時刷新緩存,公式及時生效。由于隨著業(yè)務(wù)的發(fā)展,指標(biāo)越來越多,使用本地緩存,可能會造成內(nèi)存占用過高,所以使用Redis緩存編譯后的公式。每次公式修改,就刪除緩存,下次執(zhí)行重新編譯,從而確保緩存中始終存儲的是最新版本的公式。

/**
      *  執(zhí)行表達(dá)式
     **/
    public  BigDecimal evalExpression(String expression, Map<String, Object> map) {
        Serializable cache = getCache(DesEncryptUtil.encrypt(expression));
        Object object = MVEL.executeExpression(cache, map);
        return (BigDecimal) object;
    }

    private  Serializable getCache(String expression) {
        String cacheExpression = redisUtils.get(expression);
        if (StringUtils.isNotEmpty(cacheExpression)) {
            return JsonUtil.silentString2Object(cacheExpression, Serializable.class);
        }
        Serializable compileExpression = MVEL.compileExpression(expression);
        redisUtils.setex(expression,ONE_DAY,JsonUtil.silentObject2String(compileExpression));
        return compileExpression;
    }

3.5 業(yè)務(wù)指標(biāo)遷移

明確了設(shè)計方案后,具體的遷移過程不是一蹴而就的,要考慮在不影響線上業(yè)務(wù)的前提下,有計劃的逐步完成。遷移主要分代碼邏輯遷移和配置遷移,新的遷移邏輯已經(jīng)在上文的設(shè)計方案里有介紹了,不同的指標(biāo)運(yùn)算是一個統(tǒng)一的調(diào)用入口,只需要在不同的指標(biāo)運(yùn)算處替換即可。配置遷移主要包含指標(biāo)配置遷移和公式遷移。
具體遷移過程分五步進(jìn)行:

  1. 代碼邏輯遷移
    將指標(biāo)運(yùn)算邏輯替換為新邏輯。
  2. 指標(biāo)配置整理入庫管理
    整理代碼中、Apollo配置中、數(shù)據(jù)庫中不同的指標(biāo)配置,包括歷史改變的版本,都加入配置表,以生效時間判定生效的版本。
  3. 公式整理入庫管理
    遷移前所有的公式都在代碼中,把代碼中的計算公式,同樣包含歷史的版本,轉(zhuǎn)化為MVEL表達(dá)式,加入公式表,以生效時間判定生效的版本。
  4. 數(shù)據(jù)準(zhǔn)確性驗(yàn)證
    以線上最近兩個月的數(shù)據(jù)為數(shù)據(jù)源,計算遷移后指標(biāo)的運(yùn)算結(jié)果,與遷移前的指標(biāo)運(yùn)算結(jié)果作對比。如果有不一致的結(jié)果,定位原因并修復(fù),然后重新跑數(shù)據(jù)對比,直到完全一致為止。
  5. 灰度&全量
    先在2個門店開放新邏輯,先灰度幾個指標(biāo),如果沒有問題,就開放所有指標(biāo),最后再開放全量門店。

4 總結(jié)

本文就如何在業(yè)務(wù)中使用MVEL表達(dá)式引擎進(jìn)行了分析,旨在解決當(dāng)前結(jié)算系統(tǒng)面臨的若干關(guān)鍵問題:

  1. 集中管理配置:通過建立一個公式管理中心,實(shí)現(xiàn)配置的統(tǒng)一管理,簡化維護(hù)流程。
  2. 即時生效的公式修改:對公式很小的改動,直接修改公式立即生效,無需代碼上線。
  3. 降低代碼復(fù)雜度:通過將公式的歷史版本存儲在數(shù)據(jù)庫中,并根據(jù)時間戳獲取當(dāng)前生效的公式,減少了代碼中多套公式的維護(hù)負(fù)擔(dān)。

當(dāng)然實(shí)際使用,還需結(jié)合具體的使用場景具體分析決定是否要使用,對于比較簡單的場景,沒有必要引入,這樣會增加系統(tǒng)的復(fù)雜度,一定是系統(tǒng)存在痛點(diǎn)情況下的綜合考量。

5 參考資料

責(zé)任編輯:龐桂玉 來源: 轉(zhuǎn)轉(zhuǎn)技術(shù)
相關(guān)推薦

2024-07-31 20:45:45

2016-11-08 13:50:57

2012-02-24 09:03:11

云計算虛擬化

2023-07-27 07:00:01

轉(zhuǎn)轉(zhuǎn)門店商編程

2024-01-22 09:00:00

編程C++代碼

2010-02-01 18:23:54

Python

2009-01-01 22:08:15

企業(yè)網(wǎng)絡(luò)提高

2011-03-21 09:34:48

SET選項客戶端靈活性

2012-03-07 15:22:02

2013-10-12 16:48:14

SAP

2021-02-09 10:55:10

物聯(lián)網(wǎng)人工智能邊緣計算

2013-02-26 10:44:26

2021-09-17 16:05:09

戴爾科技

2015-12-31 09:44:56

公有云谷歌云評測

2019-09-05 10:34:02

云計算云管理架構(gòu)

2010-02-23 17:04:32

Python編程語言

2010-07-22 10:08:39

JavaFXJava

2014-04-30 15:52:59

紅帽

2022-10-10 18:39:01

legendapp前端框架

2010-01-06 12:16:46

Ubuntu軟件包
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號