【背景介绍】
当前项目,需要设计一套架构,支持微服务的集群应用,其基础架构可以参考文章
项目中碰到的proxy实现以及相关架构演进
https://blog.csdn.net/weixin_44193239/article/details/131809668?spm=1001.2014.3001.5502
其实都是当前互联网界比较常见的一种C/S结构,特点是在Client端,user能够接触的都是各种不同微服务提供的proxy, user调用proxy实例接口,proxy组装rpc消息,这些不同proxy的消息,通过某一个context里面维护的连接,最终消息会抵达service端。
service端也存在出现某些场景,触发通知事件,该通知最终也会抵达client端,user作为observer,因为前期注册了消息处理的回调,最终该回调会得到调用。
上述是一个典型的observer/notifier模型。
另外,在设计时,也需要考虑到有可能短时间会接收大量不同service端发过来的通知/事件消息,如果只起一个线程来接收和处理消息,有可能该线程最终会在user注册的callback中耗时超出预期,导致时间窗口容许范围内,来不及接收更多消息,造成阻塞,形成实质上的瓶颈,则需要将接收消息和处理消息分隔开来。
上述又成为典型的生产者消费者模式的应用点。
observer/notifier模型,实现里面,最简单的一种就是根据key来注册callback
//核心结构以及变量
using SubscriberCb = std::function<void(int A, int B)>;
using Subscribers = std::map<std::string, SubscriberCb>;
Subscribers subscribers_;
std::mutex lock_;
//主要接口以及实现
void SubscriberManager::add(const std::string &key, SubscriberCb subscriberCb)
{
std::lock_guard lk{lock_};
subscribers_[key] = subscriberCb;
}
void SubscriberManager::callEventHandler(const std::string &module,
int A, int B)
{
std::lock_guard lk{lock_};
auto cit = findSubscriber(module);
if (cit != subscribers_.cend())
{
(cit->second)(A, B);
}
}
bool SubscriberManager::subscriberFound(const std::string &module)
{
std::lock_guard lk{lock_};
return findSubscriber(module) != subscribers_.cend();
}
SubscriberManager::Subscribers::const_iterator SubscriberManager::findSubscriber(const std::string &module) const
{
return subscribers_.find(module);
}
本文关注的是生产者消费者相关实现,直接上代码
#ifndef JTHREAD_SAMPLE_
#define JTHREAD_SAMPLE_
#include <memory>
#include <atomic>
#include <thread>
#include <queue>
struct NotificationMessage
{
NotificationMessage(const std::string &module_) :
module(module_)
{
}
std::string module;
};
using NotificationMessagePtr = std::unique_ptr<NotificationMessage>;
using NotificationMessages = std::queue<NotificationMessagePtr>;
class JthreadSample
{
public:
explicit JthreadSample();
~JthreadSample() override;
JthreadSample(const JthreadSample&) = delete;
JthreadSample(JthreadSample&&) = delete;
JthreadSample& operator=(const JthreadSample&) = delete;
JthreadSample& operator=(JthreadSample&&) = delete;
void dispatch() override;
protected:
virtual bool loopCondition(std::stop_token& stop_token);
virtual void notificationHandler(std::stop_token stop_token);
private:
NotificationMessages notification_messages_;
void threadForNotificationHandler();
void threadForEventHandler();
void handleNotificationMessage();
NotificationMessagePtr readOneNotificationMessage();
void notificationHandler(std::stop_token stop_token);
void receiveNotifications(std::stop_token &stop_token);
static NotificationMessagePtr recvNotification(const std::string &module);
void saveMessageAndNotifyChange(NotificationMessagePtr notify);
void eventHandler(std::stop_token stop_token);
std::shared_ptr<SubscriberManager> subscribers_;
std::mutex notification_message_lock_;
std::atomic_flag synFlag_ = ATOMIC_FLAG_INIT;
std::jthread event_handler_thread_; // consumer thread to handle notification message
std::jthread notify_thread_; // producer thread to receive notification message and nofity consumer thread
};
#endif // JTHREAD_SAMPLE_
原先预计的是可以整一个无锁结构,后来专家的建议是锁+原子变量
#include "JthreadSample.h"
JthreadSample::JthreadSample()
{
}
JthreadSample::~JthreadSample()
{
event_handler_thread_.request_stop();
synFlag_.test_and_set();
synFlag_.notify_one();
}
void JthreadSample::dispatch()
{
threadForNotificationHandler();
threadForEventHandler();
}
void JthreadSample::saveMessageAndNotifyChange(NotificationMessagePtr notify)
{
{
std::lock_guard lk{notification_message_lock_};
notification_messages_.push(std::move(notify));
}
// set atomic flag to true and notify event handler thread
synFlag_.test_and_set();
synFlag_.notify_one();
}
static NotificationMessagePtr recvNotification(const std::string &module)
{
return std::make_unique<NotificationMessage>(module);
}
void JthreadSample::receiveNotifications(std::stop_token &stop_token)
{
std::string module{"hello you"};
while (loopCondition(stop_token))
{
try
{
auto notify = recvNotification(module);
if (notify != nullptr)
{
saveMessageAndNotifyChange(std::move(notify));
}
}
catch (...)
{
// All sessions are not connected and can not receive anymore
// Resubscribe needed.
return;
}
}
}
void JthreadSample::notificationHandler(std::stop_token stop_token)
{
while (loopCondition(stop_token))
{
receiveNotifications(stop_token);
}
}
void JthreadSample::threadForNotificationHandler()
{
notify_thread_ = std::jthread([this](std::stop_token token)
{
this->notificationHandler(token);
});
}
bool JthreadSample::loopCondition(std::stop_token& stop_token)
{
return !stop_token.stop_requested();
}
NotificationMessagePtr JthreadSample::readOneNotificationMessage()
{
std::lock_guard lk{notification_message_lock_};
auto msg = std::move(notification_messages_.front());
notification_messages_.pop();
return msg;
}
void JthreadSample::handleNotificationMessage()
{
synFlag_.wait(false); // wait until notification thread notify, unblock if value is true.
synFlag_.clear(); // set value to false
while(notification_messages_.size())
{
auto msg = readOneNotificationMessage();
//do something
subscribers_->callEventHandler(msg->module);
}
}
void JthreadSample::eventHandler(std::stop_token stop_token)
{
while (loopCondition(stop_token))
{
handleNotificationMessage();
}
}
void JthreadSample::threadForEventHandler()
{
event_handler_thread_ = std::jthread([this](std::stop_token token)
{
this->eventHandler(token);
});
}