昨天我安静地坐着,像往常一样,我不打扰任何人。在这里,他们来自两个不同的联系人,几乎同时将链接发送到SQL中有关JSON的著名推文。其中一条消息如下所示:
这已经是直接的挑战。我不能不理him他。因此,我决定讲一个仍然引起我内心矛盾的故事。三年后。
在那个幸福的时刻,每个人都梦想着使用加密货币,从事ICO和雕刻加密货币交易所。这真的是新东西。我有创建经典资产管理系统(股票,债券等)的经验。问题在于它是围绕会计系统形成的。我想通过交流来实现自我。毫不奇怪,我高兴地跳入这沸腾的大锅中。
这就是背景。有很多有趣的事情,但是今天我想谈一个具体案例-我们如何创建匹配器。
Matcher,这是交流的核心。正是在其中进行交易。在经典的构造型中,这是一个高性能子系统。但这对于大型交易所是正确的。那里有数十万个开放的买卖应用程序。
“跪下”创建的交易所无法赶上这种流量。她被迫寻找利基。其中一种方法是创建吸引某些大型交易所用户的特定工具。最愚蠢的方法是倾销佣金以进行加密货币存取。
在我们的案例中,对话大约是每天数百笔交易。
我们有一个来自第三方供应商的Java匹配器。这件事经常崩溃,需要资源,并且花钱注册。此外,它具有自己的生态系统,未经供应商许可,无法开发。从这里开始,我们根本无法为交易者提供非常“独特”的工具。这就是让我写自己的匹配器的原因。
. , , “” . . , 270 . RabbitMQ. ….
. . 2 . , , . , , .
. . .. , … , .. . - :
! ()
, . . … . .
, . , . , . — .
, . , 100, 5. 100 7 . , .
SQL . , . MySQL . , MySQL . .. . :
SET depth_sell.`limit` = depth_sell.`limit` - IF(
((@tofill := IF(
depth_sell.`limit` <= @limit,
depth_sell.`limit`,
@limit
))
+ (@limit := @limit - @tofill)),
@tofill,
@tofill
),
depth_sell.`executed` = @tofill
WHERE @limit > 0;
@limit := @limit - @tofill
() .
IN MEMORY . .. . .
. — . . , , .
CREATE TABLE transactions
(
id INT AUTO_INCREMENT PRIMARY KEY,
moment TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,
side1 INT NOT NULL,
side2 INT NOT NULL,
price BIGINT NOT NULL,
volume BIGINT NOT NULL
);
CREATE TABLE depth_buy
(
id BIGINT PRIMARY KEY NOT NULL AUTO_INCREMENT,
order_id BIGINT NOT NULL,
type INT DEFAULT '0' NOT NULL,
market INT DEFAULT '0' NOT NULL,
account INT NOT NULL,
price BIGINT DEFAULT '0' NOT NULL,
`limit` BIGINT DEFAULT '0' NOT NULL,
taker INT,
rev_price BIGINT NOT NULL,
executed BIGINT
) ENGINE = MEMORY;
CREATE TABLE depth_sell
(
id BIGINT PRIMARY KEY NOT NULL AUTO_INCREMENT,
order_id INT NOT NULL,
type INT DEFAULT '0' NOT NULL,
market INT DEFAULT '0' NOT NULL,
account INT NOT NULL,
price BIGINT DEFAULT '0' NOT NULL,
`limit` BIGINT DEFAULT '0' NOT NULL,
taker INT,
rev_price BIGINT NOT NULL,
executed BIGINT
) ENGINE = MEMORY;
CREATE PROCEDURE `make_order_v2`(IN order_id INT,
IN order_type INT,
IN order_account INT,
IN order_market INT,
IN order_limit BIGINT,
IN order_price BIGINT)
BEGIN
START TRANSACTION;
SET @limit := order_limit;
IF order_type = 21 THEN
UPDATE depth_sell
INNER JOIN (
SELECT id
FROM depth_sell
WHERE market = order_market
AND depth_sell.price <= order_price
ORDER BY depth_sell.price + id ASC
) source ON depth_sell.id = source.id
SET depth_sell.taker = order_id,
depth_sell.`limit` = depth_sell.`limit` - IF(
((@tofill := IF(
depth_sell.`limit` <= @limit,
depth_sell.`limit`,
@limit
))
+ (@limit := @limit - @tofill)),
@tofill,
@tofill
),
depth_sell.`executed` = @tofill
WHERE @limit > 0;
INSERT INTO transactions (moment, side1, side2, price, volume)
SELECT now(), depth_sell.id, order_id, depth_sell.price, depth_sell.executed
FROM depth_sell
WHERE depth_sell.`taker` = order_id;
DELETE
FROM depth_sell
WHERE market = order_market
AND depth_sell.`limit` = 0;
IF @limit > 0 THEN
INSERT INTO depth_buy (order_id, type, market, account, price, rev_price, `limit`)
VALUES (order_id, order_type, order_market, order_account, order_price, -order_price, @limit);
END IF;
ELSE
UPDATE depth_buy
INNER JOIN (
SELECT id
FROM depth_buy
WHERE market = order_market
AND depth_buy.price >= order_price
ORDER BY depth_buy.rev_price - id ASC
) source ON depth_buy.id = source.id
SET depth_buy.taker = order_id,
depth_buy.`limit` = depth_buy.`limit` - IF(
((@tofill := IF(
depth_buy.`limit` <= @limit,
depth_buy.`limit`,
@limit
))
+ (@limit := @limit - @tofill)),
@tofill,
@tofill
),
depth_buy.`executed` = @tofill
WHERE @limit > 0;
INSERT INTO transactions (moment, side1, side2, price, volume)
SELECT now(), depth_buy.id, order_id, depth_buy.price, depth_buy.executed
FROM depth_buy
WHERE depth_buy.`taker` = order_id;
DELETE
FROM depth_buy
WHERE market = order_market
AND depth_buy.`limit` = 0;
IF @limit > 0 THEN
INSERT INTO depth_sell (order_id, type, market, account, price, rev_price, `limit`)
VALUES (order_id, order_type, order_market, order_account, order_price, -order_price, @limit);
END IF;
END IF;
COMMIT;
END;
CREATE PROCEDURE do_load_matcher_v2(IN market INT)
BEGIN
DECLARE count INT DEFAULT 100000;
WHILE count > 0 DO
call make_order_v2(
count,
IF(count % 2 = 0, 21, 22),
1,
market,
FLOOR(1 + (RAND() * 1000)),
FLOOR(1 + (RAND() * 1000))
);
SET count = count - 1;
END WHILE;
END;
, .. . :
- depth_buy — ;
- depth_sell — ;
- transaction — = .
make_order_v2 :
- order_id — .
- order_type — . 21 — , 22 — .
- order_account — ( ).
- order_market — . .
- order_limit — . . , 100. .. 1.15btc 115.
- order_price — . .
, . — . , . .
, .
, . . 100 . 95 . 1.46 . 570 . .
, . . , . . .. .
, ? :
- . .
- , , . .
:
- . , . .
- . . .
当然,我不同意原始帖子作者的乐观看法,即一切都可以通过DBMS来完成,但是经验表明,一切都可以通过DBMS来完成。如果你想。因此,您需要注意自己的欲望。否则,您将不得不经历数年的精神痛苦。
都好!
原始推文