千家信息网

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

发表于:2025-01-29 作者:千家信息网编辑
千家信息网最后更新 2025年01月29日,提高微服务可用性的中间件CoralCache,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。当数据库出问题时能降级从本地缓存的数据中查
千家信息网最后更新 2025年01月29日提高微服务可用性的中间件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安全错误 数据库的锁怎样保障安全 安卓软件开发 图形开发 临沂市委网信办网络安全 软件开发的收入来源 网络安全单位 中华人民共和国网络安全法自营 网络安全协议不可用 数据库空洞怎么修 毕业论文被万方数据库收录 青岛浪潮服务器供应商 linux搭建矿池中转服务器 苏州信息网络技术服务 老头环无法登录服务器怎么办 锦江区声动软件开发工作室 java链接sql数据库 福州软件园网络安全 教育网络安全工作研讨 棋牌类软件开发需要学什么 云南北斗时钟监控网关服务器 老链接新连接服务器 国产服务器如何查看系统版本 网络连接成功服务器连接 信息来自于数据库对不对 网络安全菏泽大数据中心中心 德风软件开发商 贵州pdu服务器电源哪个牌子好 代理服务器app免费 如何用数据库查询各学生的年龄 旅游公司服务器搭建 服务器放到哪里声音小 网络安全工程师职业资格证
0