提高微服務可用性的中間件CoralCache

提高微服務可用性的中間件CoralCache,針對這個問題,這篇文章詳細介紹了相對應的分析和解答,希望可以幫助更多想解決這個問題的小伙伴找到更簡單易行的方法。

目前成都創(chuàng)新互聯(lián)公司已為上千余家的企業(yè)提供了網(wǎng)站建設、域名、虛擬空間、網(wǎng)站改版維護、企業(yè)網(wǎng)站設計、昆明網(wǎng)站維護等服務,公司將堅持客戶導向、應用為本的策略,正道將秉承"和諧、參與、激情"的文化,與客戶和合作伙伴齊心協(xié)力一起成長,共同發(fā)展。

當數(shù)據(jù)庫出問題時能降級從本地緩存的數(shù)據(jù)中查詢數(shù)據(jù), CoralCache就是這樣一個提高微服務可用性的中間件。

背景

有些場景下,微服務依賴數(shù)據(jù)庫中一些配置項或者數(shù)量很少的數(shù)據(jù),但當數(shù)據(jù)庫本身有問題時候,即使數(shù)據(jù)量很少,這個服務是不能正常工作;因此需要考慮一種能支持全量+極少變更的全局數(shù)據(jù)的場景,當數(shù)據(jù)庫出問題時能降級從本地緩存的數(shù)據(jù)中查詢數(shù)據(jù),CoralCache就是這樣一個提高微服務可用性的中間件。

架構

CoralCache中間件架構如下圖所示,通過@EnableLocal注解開啟功能,應用啟動后將配置的表數(shù)據(jù)一次性加載到內存中,內存中的數(shù)據(jù)邏輯結構和數(shù)據(jù)庫中的邏輯結構一樣。

提高微服務可用性的中間件CoralCache

圖1. 架構圖

表達式計算引擎

內存查詢引擎的原理是數(shù)據(jù)庫查詢降級發(fā)生后,Intercepter將攔截到的原始SQL傳入查詢引擎中,查詢引擎解析SQL后得到表名、列名、where條件表達式,遍歷InnerDB中對應表的數(shù)據(jù)行,并通過表達式計算引擎計算結果,計算結果為真則添加到結果集中最后返回給調用方。

計算引擎結構如下圖所示,將where條件表達式轉為后綴表達式后依次遍歷后綴表達式,遇到操作數(shù)直接入棧,遇到操作符則根據(jù)操作符需要的操作數(shù)個數(shù)彈棧。

提高微服務可用性的中間件CoralCache

圖2. 表達式計算引擎結構

然后根據(jù)操作符和彈出的操作數(shù)進行計算,不同操作符對應不同的計算方法,并將計算后的結果重新作為操作數(shù)入棧執(zhí)到遍歷完成,核心計算流程代碼如下所示:

public Object calc(Expression where, InnerTable table, InnerRow row) {
        try {
            postTraversal(where);
        } catch (Exception e) {
            log.warn("calc error: {}", e.getMessage());
            return false;
        }
        for (ExprObj obj : exprList) {
            switch (obj.exprType()) {
                case ITEM:
                    stack.push(obj);
                    break;
                case BINARY_OP: {
                    ExprObj result = calcBinaryOperation(((ExprOperation) obj).getOperationType(), table, row);
                    stack.push(result);
                    break;
                }
                case UNARY_OP: {
                    ExprObj result = calcSingleOperation(((ExprOperation) obj).getOperationType(), table, row);
                    stack.push(result);
                    break;
                }
                case FUNCTION_OP: {
                    ExprObj result = calcFunctionOperation(((ExprOperation) obj).getOperationType(), table, row);
                    stack.push(result);
                    break;
                }
                default:
                    break;
            }
        }
        return stack.pop();
    }

常見運算符的實現(xiàn)

邏輯運算

邏輯常見運算符為<、<=、>、>=、=等,它們的共性都是需要2個操作數(shù)并且返回值是布爾類型。

public ExprItem logicalCalculus(InnerTable table, InnerRow row, LogicalOperation logicalOperation) {

        ExprObj second = stack.pop();
        ExprObj first = stack.pop();

        ExprItem result = new ExprItem();
        result.setItemType(ItemType.T_CONST_OBJ);
        Obj firstObj = getObj((ExprItem) first, table, row);
        Obj secondObj = getObj((ExprItem) second, table, row);
        boolean value = logicalOperation.apply(firstObj, secondObj);
        result.setValue(new Obj(value, ObjType.BOOL));
        return result;
    }

例子,以"="的實現(xiàn)來展示:

private ExprObj calcBinaryOperation(OperationType type, InnerTable table, InnerRow row) {
        ExprObj result = null;
        switch (type) {
            case T_OP_EQ:
                result = logicalCalculus(table, row, (a, b) -> ObjUtil.eq(a, b)); // 等于符號的實現(xiàn)
                break;
            ...
            default:
                break;
        }
        return result;
 }

public class ObjUtil {
    private static ObjType resultType(ObjType first, ObjType second) {
        return ObjType.RESULT_TYPE[first.ordinal()][second.ordinal()];
    }

    public static boolean eq(Obj first, Obj second) {
        ObjType type = resultType(first.getType(), second.getType());

        switch (type) {
            case LONG: {
                long firstValue = first.getValueAsLong();
                long secondValue = second.getValueAsLong();
                return firstValue == secondValue;
            }
            case DOUBLE: {
                double firstValue = first.getValueAsDouble();
                double secondValue = second.getValueAsDouble();
                return Double.compare(firstValue, secondValue) == 0;
            }
            case TIMESTAMP: {
                java.util.Date firstValue = first.getValueAsDate();
                java.util.Date secondValue = first.getValueAsDate();
                return firstValue.compareTo(secondValue) == 0;
            }
            ...
            default:
                break;
        }
        throw new UnsupportedOperationException(first.getType() + " and " + second.getType() + " not support '=' operation.");
    }
}

數(shù)學運算

數(shù)學運算和邏輯運算的流程都一樣,只不過運算后的結果為數(shù)字類型。

LIKE運算符

除了上面說的邏輯運算和數(shù)學運算外,還支持進行模糊匹配的特殊操作符LIKE。

LIKE表達式語法

常見用法如下

LIKE "%HUAWEI" 匹配以HUAWEI結尾的字符串
LIKE "HUAWEI%" 匹配以HUAWEI開頭的字符串
LIKE "A_B" 匹配以"A"起頭且以"Z"為結尾的字串
LIKE "A?B" 同上
LIKE "%[0-9]%" 匹配含有數(shù)字的字符串
LIKE "%[a-z]%" 匹配含有小寫字母字符串
LIKE "%[!0-9]%"匹配不含數(shù)字的字符串
?和_都表示單個字符

JAVA中實現(xiàn)LIKE的方案:將LIKE的模式轉為JAVA中的正則表達式。

LIKE詞法定義

expr := wild-card + expr
      | wild-char + expr
      | escape + expr
      | string + expr
      | ""

wild-card := %  
wild-char := _  
escape := [%|_]  
string := [^%_]+ (One or > more characters that are not wild-card or wild-char)

定義Token類

public abstract class Token {
    private final String value;

    public Token(String value) {
        this.value = value;
    }

    public abstract String convert();

    public String getValue() {
        return value;
    }
}

public class ConstantToken extends Token {
    public ConstantToken(String value) {
        super(value);
    }

    @Override
    public String convert() {
        return getValue();
    }
}

public class EscapeToken extends Token {
    public EscapeToken(String value) {
        super(value);
    }

    @Override
    public String convert() {
        return getValue();
    }
}

public class StringToken extends Token {
    public StringToken(String value) {
        super(value);
    }

    @Override
    public String convert() {
        return Pattern.quote(getValue());
    }
}

public class WildcardToken extends Token {
    public WildcardToken(String value) {
        super(value);
    }

    @Override
    public String convert() {
        return ".*";
    }
}

public class WildcharToken extends Token {
    public WildcharToken(String value) {
        super(value);
    }

    @Override
    public String convert() {
        return ".";
    }
}

創(chuàng)建Lexer(Tokenizer)

public class Tokenizer {

    private Collection<Tuple> patterns = new LinkedList<>();

    public <T extends Token> Tokenizer add(String regex, Function<String, Token> creator) {
        this.patterns.add(new Tuple<Pattern, Function<String, Token>>(Pattern.compile(regex), creator));
        return this;
    }

    public Collection<Token> tokenize(String clause) throws RuntimeException {
        Collection<Token> tokens = new ArrayList<>();
        String copy = String.copyValueOf(clause.toCharArray());

        int position = 0;
        while (!copy.equals("")) {
            boolean found = false;
            for (Tuple tuple : this.patterns) {
                Pattern pattern = (Pattern) tuple.getFirst();
                Matcher m = pattern.matcher(copy);
                if (m.find()) {
                    found = true;
                    String token = m.group(1);
                    Function<String, Token> fn = (Function<String, Token>) tuple.getSecond();
                    tokens.add(fn.apply(token));
                    copy = m.replaceFirst("");
                    position += token.length();
                    break;
                }
            }

            if (!found) {
                throw new RuntimeException("Unexpected sequence found in input string, at " + position);
            }
        }

        return tokens;

    }
}

創(chuàng)建LIKE到正則表達式的轉換映射

public class LikeTranspiler {
    private static Tokenizer TOKENIZER = new Tokenizer()
            .add("^(\\[[^]]*])", ConstantToken::new)
            .add("^(%)", WildcardToken::new)
            .add("^(_)", WildcharToken::new)
            .add("^([^\\[\\]%_]+)", StringToken::new);

    public static String toRegEx(String pattern) throws ParseException {
        StringBuilder sb = new StringBuilder().append("^");
        for (Token token : TOKENIZER.tokenize(pattern)) {
            sb.append(token.convert());
        }

        return sb.append("$").toString();
    }
}

直接調用LikeTranspiler的toRegEx方法將LIKE語法轉為JAVA中的正則表達式。

private ExprObj calcBinaryOperation(OperationType type, InnerTable table, InnerRow row) {
        ExprObj result = null;
        switch (type) {
            . . .
            case T_OP_LIKE:
                result = logicalCalculus(table, row, (a, b) -> ObjUtil.like(a, b));
                break;
            . . .
        }

        return result;
    }
public static boolean like(Obj first, Obj second) {
        Assert.state(first.getType() == ObjType.STRING, OperationType.T_OP_LIKE + " only support STRING.");
        Assert.state(second.getType() == ObjType.STRING, OperationType.T_OP_LIKE + " only support STRING.");

        String firstValue = (String) first.getRelValue();

        String secondValue = (String) second.getRelValue();

        String regEx = LikeTranspiler.toRegEx(secondValue);

        return Pattern.compile(regEx).matcher(firstValue).matches();
    }

通過創(chuàng)建詞法分析器并使用此方法進行轉換,我們可以防止LIKE像這樣的子句被轉換為正則表達式%abc[%]%,該子句應將其中的任何子字符串與其中的子字符串匹配,該子句將與子字符串或匹配任何字符串。abc%.abc[.].abc.abc。

類型計算轉換

不同數(shù)據(jù)類型在進行計算時需要轉型,具體的轉化入下二維數(shù)組中。

// 不同類型計算后的類型
ObjType[][] RESULT_TYPE = {
        //UNKNOWN  BYTE     SHORT    INT      LONG     FLOAT    DOUBLE   DECIMAL  BOOL     DATE       TIME       TIMESTAMP  STRING     NULL
        { UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN,   UNKNOWN,   UNKNOWN,   UNKNOWN,   UNKNOWN },// UNKNOWN
        { UNKNOWN, LONG,    LONG,    LONG,    LONG,    DOUBLE,  DOUBLE,  DECIMAL, BOOL,    UNKNOWN,   UNKNOWN,   UNKNOWN,   LONG,      UNKNOWN },// BYTE
        { UNKNOWN, LONG,    LONG,    LONG,    LONG,    DOUBLE,  DOUBLE,  DECIMAL, BOOL,    UNKNOWN,   UNKNOWN,   UNKNOWN,   LONG,      UNKNOWN },// SHORT
        { UNKNOWN, LONG,    LONG,    LONG,    LONG,    DOUBLE,  DOUBLE,  DECIMAL, BOOL,    UNKNOWN,   UNKNOWN,   UNKNOWN,   LONG,      UNKNOWN },// INT
        { UNKNOWN, LONG,    LONG,    LONG,    LONG,    DOUBLE,  DOUBLE,  DECIMAL, BOOL,    UNKNOWN,   UNKNOWN,   UNKNOWN,   LONG,      UNKNOWN },// LONG
        { UNKNOWN, DOUBLE,  DOUBLE,  DOUBLE,  DOUBLE,  DOUBLE,  DOUBLE,  DECIMAL, BOOL,    UNKNOWN,   UNKNOWN,   UNKNOWN,   DOUBLE,    UNKNOWN },// FLOAT
        { UNKNOWN, DOUBLE,  DOUBLE,  DOUBLE,  DOUBLE,  DOUBLE,  DOUBLE,  DECIMAL, BOOL,    UNKNOWN,   UNKNOWN,   UNKNOWN,   DOUBLE,    UNKNOWN },// DOUBLE
        { UNKNOWN, DECIMAL, DECIMAL, DECIMAL, DECIMAL, DECIMAL, DECIMAL, DECIMAL, UNKNOWN, UNKNOWN,   UNKNOWN,   UNKNOWN,   DECIMAL,   UNKNOWN },// DECIMAL
        { UNKNOWN, BOOL,    BOOL,    BOOL,    BOOL,    BOOL,    BOOL,    BOOL,    BOOL,    UNKNOWN,   UNKNOWN,   UNKNOWN,   BOOL,      UNKNOWN },// BOOL
        { UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, TIMESTAMP, TIMESTAMP, TIMESTAMP, TIMESTAMP, UNKNOWN },// DATE
        { UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, TIMESTAMP, TIMESTAMP, TIMESTAMP, TIMESTAMP, UNKNOWN },// TIME
        { UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, TIMESTAMP, TIMESTAMP, TIMESTAMP, TIMESTAMP, UNKNOWN },// TIMESTAMP
        { UNKNOWN, LONG,    LONG,    LONG,    LONG,    DOUBLE,  DOUBLE,  DECIMAL, BOOL,    TIMESTAMP, TIMESTAMP, TIMESTAMP, STRING,    UNKNOWN },// STRING
        { UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN,   UNKNOWN,   UNKNOWN,   UNKNOWN,   UNKNOWN },// NULL
};

點擊關注,第一時間了解華為云新鮮技術~

關于提高微服務可用性的中間件CoralCache問題的解答就分享到這里了,希望以上內容可以對大家有一定的幫助,如果你還有很多疑惑沒有解開,可以關注創(chuàng)新互聯(lián)行業(yè)資訊頻道了解更多相關知識。

文章標題:提高微服務可用性的中間件CoralCache
文章路徑:http://bm7419.com/article2/gijhic.html

成都網(wǎng)站建設公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站內鏈、定制網(wǎng)站做網(wǎng)站、微信公眾號電子商務、虛擬主機

廣告

聲明:本網(wǎng)站發(fā)布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內容未經(jīng)允許不得轉載,或轉載時需注明來源: 創(chuàng)新互聯(lián)

成都網(wǎng)站建設