原文转自:http://www.tanjp.com (即时修正和更新)
Actor模式封装异步的MongoDB C驱动
MongoDB C驱动(MongoDB C Driver http://mongoc.org/),提供了同步的DB访问存储接口,在高并发的业务系统,同步操作会阻塞业务逻辑,是高并发的一大障碍。所以需要设计异步的接口来满足业务系统的需求。
利用Actor的特性,同一个Actor里面的行为,不需要加锁,也就是说Actor可以很方便地封装同步操作。
1、实现一个同步的MongoDB数据存取类型 SyncModb。
2、用Actor包装SyncModb,得到类型ActorMongodb。
3、实现ActorModb类型,该类型包含了单独的调度器(Scheduler)和舞台(Stage),和管理所有ActorMongodb。
4、ActoModb类型接收信件,创建N个ActorMongodb对象,每个ActorMongodb对象负责一个单独mongoc驱动连接,进行数据收发。
这样就实现了基于Actor模式实现可多连接并发异步接口。ActoModb对象的设计如下图:
首先,实现一个同步的MongoDB数据存取类型 SyncModb,也就是说,这些接口如果直接调用会阻塞业务层逻辑。
下面只粘贴部分代码演示使用方法:
class SyncModb
{
public:
SyncModb();
~SyncModb();
// 配置连接地址
// @ps_uri, mongod的URI,格式: mongodb://username:password@127.0.0.1:27017/?authSource=collectionname
// @return 执行结果集合。
ModbResult config(const std::string & ps_uri);
// 插入一条数据
// @ps_dbname, 数据库名称。
// @ps_colnname, 集合名称。
// @ps_json, 待插入数据,json格式。
// @ps_opts, 选项。默认为空,格式 { writeConcern : { w: <uint32>, j: <boolean>, wtimeout: <uint32> } }]
// @pn_retry, 失败时自动重试的次数(每次重试耗时不少于0.1秒),0表示不自动重试。
// @return 执行结果集合。
ModbResult insert_one(const std::string & ps_dbname, const std::string & ps_colnname,
const std::string & ps_json, const std::string & ps_opts = "");
// 关闭 mongodb 连接。
void close();
// @return mongodb已经建立连接返回true,如果未建立连接将尝试重连,重连失败返回false。
bool connected();
// @po_res, 根据结果集来判断网络是否有问题。
// @return 返回true表示网络有问题,否则返回false其他问题或没问题。
bool check_network_problem(const ModbResult & po_res);
// ping测试Mongodb连接是否可用,每0.1秒尝试一次。
// @ps_dbname, 数据库名称。
// @pn_try_times, 尝试次数,取值大于零。
// @return 0表示重试多次后还是失败,成功返回非0表示重试了多少次后成功。
uint32 ping(const std::string & ps_dbname, uint32 pn_try_times);
private:
mongoc_client_t * mp_client;
std::string ms_mongo_uri;
uint32 mn_ping_times; //ping次数,失败时每次不少于0.1秒,默认值600,不少于1分钟。
};
然后,用Actor包装同步的MongoDB数据存取类型 SyncModb,得到类型ActorMongodb。代码如下:
class ActorMongodb : public Actor
{
public:
explicit ActorMongodb(ActorModb * pp_parent, Stage * pp_stage, uint32 pn_actorid, uint32 pn_retry_times_on_disconnected = 1, uint32 pn_ping_times = 600);
~ActorMongodb();
void init() override;
private:
void sync_ping(const std::string & ps_dbname, uint32 pn_qid, uint32 pn_cur_try_times);
void op_config(Mail * pp_mail);
void op_insert_one(Mail * pp_mail);
void op_close(Mail * pp_mail);
private:
const uint32 kRetryTimes;
const uint32 kPingTimes;
ActorModb * mp_parent;
SyncModb * mp_modb;
};
ActorMongodb::ActorMongodb(ActorModb * pp_parent, Stage * pp_stage, uint32 pn_actorid, uint32 pn_retry_times_on_disconnected, uint32 pn_ping_times)
: Actor(pp_stage, pn_actorid), kRetryTimes(pn_retry_times_on_disconnected), kPingTimes(pn_ping_times)
, mp_parent(pp_parent), mp_modb(new SyncModb()){}
ActorMongodb::~ActorMongodb()
{
SAFE_DELETE(mp_modb);
}
void ActorMongodb::init()
{
set_operation(Ac