还是来看这张图:
由于此前redis分布式锁超时事故,所以中间那个线程池设置为有界队列,并配置了放弃策略,故当disruptor消费者不给力时,经阻塞模式的disruptor逆推到生产者阻塞,导致堆积的线程超出队列上限被放弃
那为什么消费者会不给力?
在消费者中,消费频率大约是一个合约每秒4次,在250毫秒中,对同一个合约的多空两个方向各进行一次rangebyscore redis io(撮合、止盈止损,使用redis zset触发股票成交) ,又由于是多消费者:(多行情消费者(多线程)两次并发事故)需要(io密集型,10个消费线程,redis在10连接下达到最大性能80%——redis 压力测试与pqs监控中的结论)
如果单引擎,则可使用ConcurrentHashMap.putifabsent(合约+人id+多/空)来加锁避免并发重复成交
但考虑可用性,部署多个进程,则要使用redis putifabsent来防治集群下的重复成交
这2个操作可同步在消费者中处理的,也可异步
同步:一个合约250ms内2次rangebyscore redis io + 2次putifabsent io
异步:一个合约250ms内2次rangebyscore redis io
后决定异步到MQ,由消费者单点成交,排重
经Jedis 压力测试与qps监控,认定redis rangebyscore为4.8w qps
250ms io/合约 1s io/合约(redis qps)
TD 总共3个合约
异步 2 8 24
A股总共3000个合约
异步 1 4 12000 只能做多
美股7679
异步 2 8 62000
港股1800
异步 2 8 15000
期货20个合约
异步 2 8 160
需要共9w qps
远超过redis 4.7w qps,考虑redis分四片,对合约hash取模