Drogon 支持 Redis,Redis是一种非常快速的内存数据存储。 可以用作数据库缓存或消息代理。 与 Drogon 中其他组件一樣,Redis的操作是异步的。 这确保了 Drogon 即使在重负载下也能以非常高的并发性运行。

Redis 支持依赖于hiredis 库。 如果在构建 Drogon 时hiredis 不可用,则Redis支持将不可用。

创建客户端

Redis 客户端可以通过以下方式以方式创建:

  1. app().createRedisClient("127.0.0.1", 6379);
  2. ...
  3. // After app.run()
  4. RedisClientPtr redisClient = app().getRedisClient();

另外,与Database客户端一样,Redis客户端也支持config文件配置,也支持配置成Fast模式,具体配置如下:

  1. "redis_clients": [
  2. {
  3. //name: 客户端名字, 默认值是'default'
  4. //"name":"",
  5. //host: 服务端IP, 默认值是127.0.0.1
  6. "host": "127.0.0.1",
  7. //port: 服务端端口号, 默认值是6379
  8. "port": 6379,
  9. //passwd: 密码,默认为空
  10. "passwd": "",
  11. //db index: 默认值是0
  12. "db": 0,
  13. //is_fast: 默认值是false, 是否是fast模式,如果为true,会以更高效的方式运行,但是只能在IO线程或主线程中使用, 并且不能使用同步接口。
  14. "is_fast": false,
  15. //number_of_connections: 连接数, 默认值是1, 如果is_fasttrue, 该数字表示每个IO线程或主线程内的连接数, 否则表示该客户端所有连接数
  16. "number_of_connections": 1,
  17. //timeout: 超时值,默认值是-1.0, 单位是秒,表示一条命令的超时时间,超过这个时间未得到结果将返回超时错误,0或者负值表示没有超时限制
  18. "timeout": -1.0
  19. }
  20. ]

使用Redis

execCommandAsync 以异步方式执行 Redis 命令。 它至少需要3个参数,第一个和第二个是在Redis命令成功或失败时调用的回调。 第三是命令本身。 该命令可以是C风格的格式字符串。 其余部分是格式字符串的参数。 例如,要设置 namedrogon

  1. redisClient->execCommandAsync(
  2. [](const drogon::nosql::RedisResult &r) {},
  3. [](const std::exception &err) {
  4. LOG_ERROR << "something failed!!! " << err.what();
  5. },
  6. "set name drogon");

或者将 myid 设置为 587d-4709-86e4

  1. redisClient->execCommandAsync(
  2. [](const drogon::nosql::RedisResult &r) {},
  3. [](const std::exception &err) {
  4. LOG_ERROR << "something failed!!! " << err.what();
  5. },
  6. "set myid %s", "587d-4709-86e4");

同样的 execCommandAsync 也可以从 Redis 取得数据。

  1. redisClient->execCommandAsync(
  2. [](const drogon::nosql::RedisResult &r) {
  3. if (r.type() == RedisResultType::kNil)
  4. LOG_INFO << "Cannot find variable associated with the key 'name'";
  5. else
  6. LOG_INFO << "Name is " << r.asString();
  7. },
  8. [](const std::exception &err) {
  9. LOG_ERROR << "something failed!!! " << err.what();
  10. },
  11. "get name");

Redis 事务

Redis 事务允许在一个步骤中执行多个命令。 事务中的所有命令都按顺序执行,其他客户端的命令不会在事务中间执行。 注意redis的事务不是原子操作,也就是说收到 EXEC 命令后进入事务执行,事务中任意命令执行失败,其余的命令依然被执行。redis事务没有回滚操作。

newTransactionAsync 方法创建一个新事务。 然后就可以像普通的 RedisClient 一样使用事务。 最后,RedisTransaction::execute 方法执行事务。

  1. redisClient->newTransactionAsync([](const RedisTransactionPtr &transPtr) {
  2. transPtr->execCommandAsync(
  3. [](const drogon::nosql::RedisResult &r) { /* this command works */ },
  4. [](const std::exception &err) { /* this command failed */ },
  5. "set name drogon");
  6. transPtr->execute(
  7. [](const drogon::nosql::RedisResult &r) { /* transaction worked */ },
  8. [](const std::exception &err) { /* transaction failed */ });
  9. });

协程

Redis 客户端也支持协程. 需要GCC 11或者更新的编译器,并且使用cmake -DCMAKE_CXX_FLAGS="-std=c++20" 来使能它。見协程取得细节

  1. try
  2. {
  3. auto transaction = co_await redisClient->newTransactionCoro();
  4. co_await transaction->execCommandCoro("set zzz 123");
  5. co_await transaction->execCommandCoro("set mening 42");
  6. co_await transaction->executeCoro();
  7. }
  8. catch(const std::exception& e)
  9. {
  10. LOG_ERROR << "Redis failed: " << e.what();
  11. }