土法炼钢兴趣小组的算法知识备份

业务集成模式 (Business Integration Patterns)

目录

在写 Demo 时,我们通常只处理简单的 Echo 逻辑。但在真实业务中,我们需要查询数据库、调用下游微服务。这些操作往往耗时较长,如果直接在 Event Loop 中同步调用,会阻塞整个服务。

本篇探讨如何在 Libevent 中集成复杂的业务逻辑。

1. 数据库交互

1.1. 方案 A: 原生异步驱动 (推荐)

这是性能最好的方案。许多现代数据库驱动都提供了非阻塞 API,甚至直接支持 Libevent。

1.2. 方案 B: 线程池卸载 (通用)

如果你的数据库驱动只支持阻塞 API(如 ODBC, 老旧的 Oracle 驱动),或者业务逻辑包含大量 CPU 计算,必须使用线程池。

架构流程: 1. 主线程: 收到请求,封装成 Task 对象,推入 RequestQueue。 2. Worker 线程: 从队列取出 Task,执行阻塞的 DB 查询。 3. 通知: Worker 得到结果后,将结果写入 ResponseQueue,并通过 pipeevent_active 通知主线程。 4. 主线程: 收到通知,从 ResponseQueue 取出结果,发送给客户端。

Libevent 源码包中的 sample/http-server.c 其实并没有演示这一点,但在生产环境中这是标配。

2. RPC 与微服务集成

在微服务架构中,服务往往需要调用其他 HTTP/gRPC 服务。

2.1. 使用 evhttp 客户端

Libevent 自带的 evhttp 不仅是 Server,也是 Client。

struct evhttp_connection *conn = evhttp_connection_base_new(base, NULL, "127.0.0.1", 8080);
struct evhttp_request *req = evhttp_request_new(response_cb, arg);
evhttp_make_request(conn, req, EVHTTP_REQ_GET, "/api/v1/user");

这种方式完全非阻塞,非常适合高并发调用。

2.2. 避免回调地狱 (Callback Hell)

当业务逻辑变成:查询 Redis -> 没命中 -> 查询 MySQL -> 调用 RPC -> 返回,你会发现代码里嵌套了无数层回调。

解决方案: 1. 有限状态机 (FSM): 定义 STATE_INIT, STATE_REDIS, STATE_DB, STATE_RPC。所有回调都调用同一个 drive_machine(ctx) 函数,根据当前状态决定下一步操作。 2. C++20 协程 (Coroutines): 如果使用 C++,可以将 Libevent 的回调封装成 awaitable 对象,写出同步风格的异步代码。

// 伪代码:C++20 风格
Task handle_request(Request req) {
    auto val = co_await redis.get(req.key);
    if (!val) {
        val = co_await db.query(req.key);
    }
    co_await respond(val);
}

3. 总结


上一篇: 04-architecture/cpp-modern.md - C++ 现代化封装 下一篇: 05-protocols/http-server.md - 内置 HTTP Server

返回 Libevent 专题索引


By .