千家信息网

Redis 集群 lua 实现

发表于:2025-02-01 作者:千家信息网编辑
千家信息网最后更新 2025年02月01日,二话不说,直接上货.多多交流哈,谢谢各路大神..重点就是下面这段:Object object = redisTemplate.execute(redisUpdateOrderScript,//这里有k
千家信息网最后更新 2025年02月01日Redis 集群 lua 实现

二话不说,直接上货.多多交流哈,谢谢各路大神.
.
重点就是下面这段:

Object object = redisTemplate.execute(redisUpdateOrderScript,//这里有key 要像官网说的那样加个"{}",不然就报错了,这里3个key都要前缀一致Arrays.asList(hkey, amountKey, key),//值无要求amount.longValueExact(),price.doubleValue(),price.doubleValue());

我自己的理解是,执行脚本和执行hget 是一样的,只是lua脚本内容由Redis执行,但发送命令的要求是一样的.所以上面3个key 都得加一样的前缀.
.
.
.

业务逻辑是这样子的:
把20档盘口放到Redis里面
1.用有序集合(sorted set)进行自动价格排序

ZADD key 0.0354 "0.0354"

2.然后再根据价格到hash里去取值,取的val 就是这个价格的下单量

HGET key 0.0354

java 代码

加盘口

 public void addOrderForLua(BeforeMatchDTO model) {        //缓存失效        redisService.remove(RedisService.getPositionKey(model.getContract()));        BigDecimal price = model.getPrice();        BigDecimal amount = model.getAmount().multiply(PRECISION_DOUBLE);        String key = RedisKeyGen.getContractPositionZsetKey(model.getContract(), model.getDirection());        log.info("getContractPositionZsetKey:{}",key);        String hkey = RedisKeyGen.getContractPositionHashKey(model.getContract(), model.getDirection());        log.info("getContractPositionHashKey:{}",hkey);        String amountKey = RedisKeyGen.getContractPositionAmountKey(model.getContract(),price.stripTrailingZeros().toPlainString());        log.info("getContractPositionAmountKey:{}",amountKey);        log.info("addOrderForLua contract:{}, value:{}", model.getContract(), amount.longValueExact());        Object object = redisTemplate.execute(redisUpdateOrderScript, Arrays.asList(hkey, amountKey, key), amount.longValueExact(),price.doubleValue(),price.doubleValue());        log.info("addOrderForLua" + object);    }

减盘口

public void subOrderForLua(String contract,BigDecimal price,BigDecimal amount,int direction) {        //缓存失效        redisService.remove(RedisService.getPositionKey(contract));        String key = RedisKeyGen.getContractPositionZsetKey(contract, direction);        log.info("getContractPositionZsetKey:{}",key);        String hkey = RedisKeyGen.getContractPositionHashKey(contract, direction);        log.info("getContractPositionHashKey:{}",hkey);        String amountKey = RedisKeyGen.getContractPositionAmountKey(contract,price.stripTrailingZeros().toPlainString());        log.info("getContractPositionAmountKey:{}",amountKey);        log.info("subOrderForLua contract:{}, value:{}", contract, amount.doubleValue());        BigDecimal amountTag = amount.multiply(PRECISION_DOUBLE).negate();  //转成负数        Object nowAmount = redisService.hmGet(hkey, price.toPlainString());        log.info("subOrderForLua nowAmount:{},direction:{}", nowAmount, direction);        Object object = redisTemplate.execute(redisUpdateOrderScript, Arrays.asList(hkey, amountKey, key), amountTag.longValueExact(),price.doubleValue(),price.doubleValue());        log.info("subOrderForLua" + object);    }

查询(重点看取值的地方,转换请忽略)

public List query(String contract,int direction) {        List result = new ArrayList<>();        String key = RedisKeyGen.getContractPositionZsetKey(contract, direction);        log.info("getContractPositionZsetKey:{}",key);        String hkey = RedisKeyGen.getContractPositionHashKey(contract, direction);        log.info("getContractPositionHashKey:{}",hkey);        Set objectSet = null;        //卖从低到高        if(QuotationConstants.DIRECTION_SELL == direction) {            objectSet = redisService.rangeByIndex(key, 0, 19);        } else {            //买从高到低            objectSet = redisService.reverseRangeByIndex(key, 0, 19);        }        if (objectSet != null && objectSet.size() > 0) {            Integer [] digits = convertService.getContractDigitsForInt(contract);            for (Object obj : objectSet) {                log.info("query class:{},val:{}",obj.getClass(),JSON.toJSONString(obj));                BigDecimal price = new BigDecimal(obj.toString());                String amountKey = RedisKeyGen.getContractPositionAmountKey(contract,price.stripTrailingZeros().toPlainString());                Object object = redisService.hmGet(hkey, amountKey);                log.info("getContractPositionAmountKey hmGet key:{},val:{}",amountKey,object);                BigDecimal valTemp = getBigDecimal(object);                if(valTemp.compareTo(BigDecimal.ZERO) == 0) continue;                BigDecimal val = valTemp.divide(PRECISION_DOUBLE);                QuotationOrderRsgResp resp = new QuotationOrderRsgResp();                resp.setContract(contract);                resp.setDirection(direction);                resp.setPrice(convertService.setScale(price, digits[0]));                resp.setVolume(convertService.setScale(val,digits[1]));                resp.setTotal(convertService.setScale(price.multiply(val),add(digits[0] ,digits[1])));                result.add(resp);            }        } else {            log.info("query redis is null! contract:{},direction:{}", contract, direction);        }        return result;    }

key 生成

 public static final String getContractPositionZsetKey(String contract,int direction){        return "{POSITION:"+contract+"}.POSITION-ORDER-" + contract + "-" + direction;    }    public static final String getContractPositionHashKey(String contract,int direction){        return "{POSITION:"+contract+"}.POSITION-ORDER-VAL-" + contract + "-" + direction;    }    public static final String getContractPositionAmountKey(String contract,String amount){        return "{POSITION:"+contract+"}." + amount;    }

lua 脚本

local val1 = '"'local valAmount = redis.call('hget',KEYS[1],KEYS[2])if not valAmount then    redis.pcall('hset',KEYS[1],KEYS[2],ARGV[1])    if tonumber(ARGV[1]) > 0 then        local val2 = val1 .. ARGV[3] .. val1        return redis.pcall('ZADD', KEYS[3], tonumber(ARGV[2]), val2)    else        return 1    endelse    local tagAmount = tonumber(valAmount) + ARGV[1]    redis.pcall('hset',KEYS[1],KEYS[2],tagAmount)    local val2 = val1 .. ARGV[3] .. val1    local zset = redis.pcall('ZRANK', KEYS[3], val2)    if tagAmount <= 0 then        if not zset then            return 1        else            return redis.pcall('ZREMRANGEBYSCORE', KEYS[3], tonumber(ARGV[2]), tonumber(ARGV[2]))        end    else        if not zset then            local val2 = val1 .. ARGV[3] .. val1            return redis.pcall('ZADD', KEYS[3], tonumber(ARGV[2]), val2)        else            return 1        end    endend
0