Two words don't say, directly on the goods. A lot of exchanges ha, thank all the gods
.
The main point is as follows:
Object object = redisTemplate.execute(redisUpdateOrderScript, //If there is a key here, add "{}" as the official website says, or it will be reported as an error. All three keys here should have the same prefix Arrays.asList(hkey, amountKey, key), //The value is not required. amount.longValueExact(),price.doubleValue(),price.doubleValue());
My own understanding is that executing scripts is the same as executing hget, except that the content of lua scripts is executed by Redis, but the requirements for sending commands are the same. So the above three key s must be prefixed with the same prefix
.
.
.
The business logic looks like this:
Put the 20th gear in Redis
1. Automatic price sorting with sorted set
ZADD key 0.0354 "0.0354"
2. Then take the value in hash according to the price. The val is the order quantity of this price
HGET key 0.0354
java code
Add dish mouth
public void addOrderForLua(BeforeMatchDTO model) { //Cache invalidation 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); }
Reduction of opening
public void subOrderForLua(String contract,BigDecimal price,BigDecimal amount,int direction) { //Cache invalidation 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(); //Turn negative 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); }
Query (focus on the value, please ignore the conversion)
public List<QuotationOrderRsgResp> query(String contract,int direction) { List<QuotationOrderRsgResp> result = new ArrayList<>(); String key = RedisKeyGen.getContractPositionZsetKey(contract, direction); log.info("getContractPositionZsetKey:{}",key); String hkey = RedisKeyGen.getContractPositionHashKey(contract, direction); log.info("getContractPositionHashKey:{}",hkey); Set<Object> objectSet = null; //Sell from low to high if(QuotationConstants.DIRECTION_SELL == direction) { objectSet = redisService.rangeByIndex(key, 0, 19); } else { //Buy from high to low 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 generation
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 script
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 end else 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 end end