跳转至

12.4 ZMQ消息中间件

基于订单簿设计中的实现与ZeroMQ的简单消息中心

#include <atomic>
#include <chrono>
#include <iostream>
#include <mutex>
#include <sstream>
#include <string>
#include <thread>
#include <zmq.hpp>

#include "circular_array_orderbook.hpp"

#ifdef __linux__
#include <pthread.h>
#include <sched.h>
#endif

namespace json {
// 序列化单个订单
std::string serialize_order(const circular_array::Order& order) {
  std::stringstream ss;
  ss << "{" << "\"id\":" << order.id << "," << "\"price\":" << order.price
     << "," << "\"quantity\":" << order.quantity << "}";
  return ss.str();
}

// 序列化单个价格档位
template <typename OrderContainer>
std::string serialize_price_level(
    const circular_array::PriceLevel<OrderContainer>& level) {
  std::stringstream ss;
  ss << "{" << "\"price\":" << level.price << ","
     << "\"total_quantity\":" << level.total_quantity << ","
     << "\"orders\":[";  // 嵌套订单列表

  // 遍历档位下所有订单
  auto it = level.orders.begin();
  while (it != level.orders.end()) {
    ss << serialize_order(*it);
    ++it;
    if (it != level.orders.end()) {
      ss << ",";  // 最后一个订单后不加逗号
    }
  }

  ss << "]}";
  return ss.str();
}

// 序列化单个方向的所有档位
template <typename Container>
std::string serialize_side(const Container& side, int depth) {
  std::stringstream ss;
  ss << "[";

  bool has_valid_level = false;
  for (int i = 0; i < depth; ++i) {
    const auto& level = side[i];
    if (level.total_quantity > 0) {
      if (has_valid_level) {
        ss << ",";
      }
      ss << serialize_price_level(level);
      has_valid_level = true;
    }
  }

  ss << "]";
  return ss.str();
}

// 序列化完整订单簿快照(买盘+卖盘+元数据)
template <typename OrderBookType>
std::string serialize_full_book(const OrderBookType& order_book) {
  // 获取订单簿核心参数
  int depth = order_book.get_depth();
  int precision = order_book.get_precision();
  auto timestamp = std::chrono::duration_cast<std::chrono::microseconds>(
                       std::chrono::system_clock::now().time_since_epoch())
                       .count();

  std::stringstream ss;
  ss << "{" << "\"timestamp\":" << timestamp << ","
     << "\"precision\":" << precision << "," << "\"depth\":" << depth << ","
     << "\"bids\":" << serialize_side(order_book.get_bids(), depth) << ","
     << "\"offers\":" << serialize_side(order_book.get_offers(), depth) << "}";

  return ss.str();
}
}  // namespace json

// 消息中心
template <typename OrderBookType>
class MessagingHub {
 private:
  zmq::context_t context;
  zmq::socket_t publisher;
  OrderBookType& order_book;
  std::atomic<bool> running;
  int cpu_core;
  const int snapshot_interval_us;  // 全快照发布间隔(微秒,默认100ms)

  // 状态跟踪
  struct BookState {
    circular_array::LevelData best_bid;
    circular_array::LevelData best_offer;

    bool operator!=(const BookState& other) const {
      return best_bid.price != other.best_bid.price ||
             best_bid.total_quantity != other.best_bid.total_quantity ||
             best_offer.price != other.best_offer.price ||
             best_offer.total_quantity != other.best_offer.total_quantity;
    }
  };

  mutable std::mutex state_mutex;
  BookState last_state;
  std::chrono::microseconds last_snapshot_time;  // 上一次全快照发布时间

 public:
  MessagingHub(OrderBookType& lob,
               const std::string& bind_addr = "tcp://*:5556", int core = 0,
               int snapshot_interval_us = 100000)
      : context(1),
        publisher(context, ZMQ_PUB),
        order_book(lob),
        running(false),
        cpu_core(core),
        snapshot_interval_us(snapshot_interval_us),
        last_snapshot_time(std::chrono::microseconds(0)) {
    publisher.bind(bind_addr);
    std::cout << "MessagingHub: Bound to " << bind_addr << std::endl;
    std::cout << "MessagingHub: Full snapshot interval = "
              << snapshot_interval_us / 1000 << "ms" << std::endl;

    last_state = capture_current_state();
  }

  ~MessagingHub() { stop(); }

  void start() {
    running = true;
    std::thread(&MessagingHub::run_loop, this).detach();
  }

  void stop() { running = false; }

 private:
  void run_loop() {
    if (!set_cpu_affinity(cpu_core)) {
      std::cerr << "MessagingHub: Warn - Failed to bind CPU core " << cpu_core
                << std::endl;
    } else {
      std::cout << "MessagingHub: Running on CPU core " << cpu_core
                << std::endl;
    }

    while (running) {
      const auto now = std::chrono::high_resolution_clock::now();
      const auto now_us = std::chrono::duration_cast<std::chrono::microseconds>(
          now.time_since_epoch());

      // 1. 处理增量更新(仅关键行情变化时发布)
      handle_incremental_update();

      // 2. 处理定时全快照(达到间隔则发布)
      if (now_us - last_snapshot_time >=
          std::chrono::microseconds(snapshot_interval_us)) {
        handle_full_snapshot();
        last_snapshot_time = now_us;
      }

      std::this_thread::sleep_for(std::chrono::microseconds(100));
    }

    std::cout << "MessagingHub: Stopped" << std::endl;
  }

  // 捕获当前关键状态
  BookState capture_current_state() const {
    BookState state;
    state.best_bid = order_book.get_best_bid();
    state.best_offer = order_book.get_best_offer();
    return state;
  }

  // 处理增量更新(仅发布关键行情变化)
  void handle_incremental_update() {
    BookState current_state = capture_current_state();
    {
      std::lock_guard<std::mutex> lock(state_mutex);
      if (current_state != last_state) {
        send_zmq_message("inc_best_bid",
                         json::serialize_level(current_state.best_bid));
        send_zmq_message("inc_best_offer",
                         json::serialize_level(current_state.best_offer));
        last_state = current_state;
      }
    }
  }

  // 处理全快照发布(包含所有非空档位+订单明细)
  void handle_full_snapshot() {
    try {
      std::string full_snapshot = json::serialize_full_book(order_book);
      send_zmq_message("full_book", full_snapshot);
      std::cout << "MessagingHub: Published full snapshot (size: "
                << full_snapshot.size() << " bytes)" << std::endl;
    } catch (const std::exception& e) {
      std::cerr << "MessagingHub: Error publishing full snapshot - " << e.what()
                << std::endl;
    }
  }

  // 发送ZMQ消息(主题+内容,兼容ZMQ订阅过滤)
  void send_zmq_message(const std::string& topic, const std::string& content) {
    try {
      std::string msg = topic + " " + content;
      zmq::message_t zmq_msg(msg.size());
      memcpy(zmq_msg.data(), msg.data(), msg.size());
      publisher.send(zmq_msg, zmq::send_flags::none);
    } catch (const zmq::error_t& e) {
      std::cerr << "MessagingHub: ZMQ send error (" << topic << ") - "
                << e.what() << std::endl;
    }
  }

#ifdef __linux__
  bool set_cpu_affinity(int core_id) {
    int max_core = sysconf(_SC_NPROCESSORS_CONF) - 1;
    if (core_id < 0 || core_id > max_core) {
      std::cerr << "MessagingHub: Invalid CPU core " << core_id
                << " (max: " << max_core << ")" << std::endl;
      return false;
    }

    cpu_set_t cpuset;
    CPU_ZERO(&cpuset);
    CPU_SET(core_id, &cpuset);
    int ret =
        pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset);
    return ret == 0;
  }
#else
  bool set_cpu_affinity(int) { return false; }
#endif
};

消息中间件负责大型交易系统架构、集群式分布式交易系统的系统解耦和交互,分离关键路径和冷路径,以下是一个简单示例,将PMS、RMS划分为架构的上游,将OMS、EMS划分为架构的下游,其中下游往往是性能敏感的关键路径。

ZeroMQ 消息传输架构