千家信息网

提高微服务可用性的中间件CoralCache

发表于:2026-11-03 作者:千家信息网编辑
千家信息网最后更新 2026年11月03日,提高微服务可用性的中间件CoralCache,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。当数据库出问题时能降级从本地缓存的数据中查
千家信息网最后更新 2026年11月03日提高微服务可用性的中间件CoralCache

提高微服务可用性的中间件CoralCache,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。

当数据库出问题时能降级从本地缓存的数据中查询数据, CoralCache就是这样一个提高微服务可用性的中间件。

背景

有些场景下,微服务依赖数据库中一些配置项或者数量很少的数据,但当数据库本身有问题时候,即使数据量很少,这个服务是不能正常工作;因此需要考虑一种能支持全量+极少变更的全局数据的场景,当数据库出问题时能降级从本地缓存的数据中查询数据,CoralCache就是这样一个提高微服务可用性的中间件。

架构

CoralCache中间件架构如下图所示,通过@EnableLocal注解开启功能,应用启动后将配置的表数据一次性加载到内存中,内存中的数据逻辑结构和数据库中的逻辑结构一样。

图1. 架构图

表达式计算引擎

内存查询引擎的原理是数据库查询降级发生后,Intercepter将拦截到的原始SQL传入查询引擎中,查询引擎解析SQL后得到表名、列名、where条件表达式,遍历InnerDB中对应表的数据行,并通过表达式计算引擎计算结果,计算结果为真则添加到结果集中最后返回给调用方。

计算引擎结构如下图所示,将where条件表达式转为后缀表达式后依次遍历后缀表达式,遇到操作数直接入栈,遇到操作符则根据操作符需要的操作数个数弹栈。

图2. 表达式计算引擎结构

然后根据操作符和弹出的操作数进行计算,不同操作符对应不同的计算方法,并将计算后的结果重新作为操作数入栈执到遍历完成,核心计算流程代码如下所示:

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();    }

常见运算符的实现

逻辑运算

逻辑常见运算符为<、<=、>、>=、=等,它们的共性都是需要2个操作数并且返回值是布尔类型。

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;    }

例子,以"="的实现来展示:

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)); // 等于符号的实现                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.");    }}

数学运算

数学运算和逻辑运算的流程都一样,只不过运算后的结果为数字类型。

LIKE运算符

除了上面说的逻辑运算和数学运算外,还支持进行模糊匹配的特殊操作符LIKE。

LIKE表达式语法

常见用法如下

LIKE "%HUAWEI" 匹配以HUAWEI结尾的字符串
LIKE "HUAWEI%" 匹配以HUAWEI开头的字符串
LIKE "A_B" 匹配以"A"起头且以"Z"为结尾的字串
LIKE "A?B" 同上
LIKE "%[0-9]%" 匹配含有数字的字符串
LIKE "%[a-z]%" 匹配含有小写字母字符串
LIKE "%[!0-9]%"匹配不含数字的字符串
?和_都表示单个字符

JAVA中实现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 ".";    }}

创建Lexer(Tokenizer)

public class Tokenizer {    private Collection patterns = new LinkedList<>();    public  Tokenizer add(String regex, Function creator) {        this.patterns.add(new Tuple>(Pattern.compile(regex), creator));        return this;    }    public Collection tokenize(String clause) throws RuntimeException {        Collection 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 fn = (Function) 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;    }}

创建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();    }

通过创建词法分析器并使用此方法进行转换,我们可以防止LIKE像这样的子句被转换为正则表达式%abc[%]%,该子句应将其中的任何子字符串与其中的子字符串匹配,该子句将与子字符串或匹配任何字符串。abc%.abc[.].abc.abc。

类型计算转换

不同数据类型在进行计算时需要转型,具体的转化入下二维数组中。

// 不同类型计算后的类型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问题的解答就分享到这里了,希望以上内容可以对大家有一定的帮助,如果你还有很多疑惑没有解开,可以关注行业资讯频道了解更多相关知识。

数据 表达式 字符 运算 字符串 引擎 服务 数据库 类型 逻辑 问题 查询 中间件 操作数 操作符 结果 可用性 不同 正则 结构 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 云南咖啡 互联网科技海报 华服互联网科技怎么样 疫情对互联网科技公司影响 互联网金融 科技金融 美国互联网科技 互联网金融科技创新 互联网科技上市公司 上海卓越科技 互联网 互联网企业和科技型企业 中国航天科技大学国际工业互联网 西安小鹰速贷互联网科技有限公司 合肥互联网科技公司公章图片 福州德业互联网科技 互联网科技企业商标注意事项 艺电能源互联网科技有限公司招聘 互联网金融运营模式中的金融科技 易租星互联网科技有限公司 米泉互联网科技专业怎么样 绵阳真晨互联网科技有限公司 广州互联网络科技有限公司 科技互联网创业计划书 滨湖区互联网智能科技产品供应 恒生科技互联网指数分析 宝灵互联网科技有限公司 移动互联网年度科技创新 互联网媒体平台算高科技产业 坤平互联网科技 洛阳共同富裕互联网科技有限公司 张家口科技产业互联网平台
0