.Net网站架构设计(五)消息中间件
消息中间件是异步化、解耦、流量削峰的利器
在设计互联架构是,往往遇到需要推送消息,而推送消息比较耗时。
做法
1:直接执行业务,调用推送
int main()
{
执行业务代码
doBussiness();//调用消息推送
NoteMessageObject obj = (NoteMessageObject)state;NoteXmppMessage nXmpp = new NoteXmppMessage(obj.noteInfo, obj.listNoteSendToObjects);
}
优点:开发简单
缺点:由于推送需要时间,所以返回到客户端时间有延迟,较长
2:开启线程执行推送
int main()
{
//执行业务代码
doBussiness();
Thread r=ThreadStart(doSendNoteMessage);
r.Start();
}
name="code" class="csharp">void doSendNoteMessage(object state)
{
try
{
//调用消息推送
NoteMessageObject obj = (NoteMessageObject)state; NoteXmppMessage nXmpp = new NoteXmppMessage(obj.noteInfo, obj.listNoteSendToObjects); nXmpp.SendMessage(); } catch(Exception e) { // MagicSales.CommonTools.Log.WriteLog(e.Message); // CommonTools.Log.WriteLog(e.Message); } }
优点:执行完代码不用管推送是否成功直接返回给客户端,把推送交给线程,提高了系统响应速度;
缺点:a大量消息并发,开启线程十分耗费资源,当线程开启到一定程度,会报一些莫名其妙的错误;
b需要维护系统重启,未完成的推送消息丢失。
3:利用线程池开启线程实现推送
int main()
{
//执行业务代码
doBussiness();
NoteMessageObject obj = new NoteMessageObject();
obj.noteInfo = noteInfo;
obj.listNoteSendToObjects = listNoteSendToObjects;
ThreadPool.QueueUserWorkItem(doSendNoteMessage, obj);//开启线程池
}
void doSendNoteMessage(object state)
{
try
{
//调用消息推送
NoteMessageObject obj = (NoteMessageObject)state;
NoteXmppMessage nXmpp = new NoteXmppMessage(obj.noteInfo, obj.listNoteSendToObjects);
nXmpp.SendMessage();
}
catch(Exception e)
{
// MagicSales.CommonTools.Log.WriteLog(e.Message);
// CommonTools.Log.WriteLog(e.Message);
}
}
优点:有了线程池管理线程,很好的解决的多线程时,线程资源的复用,大大提供了效率,减少了由于线程过多带来的问题。
缺点:随着推送消息的增多,大量消息堆积。系统负荷增大。
重启系统后,推送消息丢失。
4:利用消息队列实现。
1,第一要选用一种消息队列,可备选项目有:RabbitMQ,MSMQ,AcivityMQ,Kafka 有关他们几个的对比请参考
我这里选择RabbitMQ.net RabbitMQ参考
用RabbitMQ就要分生产者,和消费者
生产者代码:
static void Main(string[] args)
{
//执行业务代码
doBussiness();
var factory = new ConnectionFactory(); factory.HostName = "192.168.1.219"; factory.UserName = "lim";
factory.Password = "liming!123"; using (
var connection = factory.CreateConnection())
{
using (var channel = connection.CreateModel())
{
bool durable = true; channel.QueueDeclare("task_queue", durable, false, false, null);
NoteMessageObject obj = new NoteMessageObject();
obj.noteInfo = noteInfo; obj.listNoteSendToObjects = listNoteSendToObjects;
string message = Json.Convert(obj) ;//序列化
var properties = channel.CreateBasicProperties();
properties.SetPersistent(true);
var body = Encoding.UTF8.GetBytes(message);
channel.BasicPublish("", "task_queue", properties, body);
Console.WriteLine(" set {0}", message); }
} Console.ReadKey();
消费者代码:
static void Main(string[] args)
{
var factory = new ConnectionFactory();
factory.HostName = "192.168.1.219";
factory.UserName = "lim";
factory.Password = "liming!123";
using (var connection = factory.CreateConnection())
using (var channel = connection.CreateModel())
{
bool durable = true;
channel.QueueDeclare("task_queue", durable, false, false, null);
channel.BasicQos(0, 1, false);
var consumer = new QueueingBasicConsumer(channel);
channel.BasicConsume("task_queue", false, consumer);
while (true)
{
var ea = (BasicDeliverEventArgs)consumer.Queue.Dequeue();
var body = ea.Body;
var message = Encoding.UTF8.GetString(body);
NoteMessageObject obj = Json.DescConvert(message) ;//反序列化
NoteXmppMessage nXmpp = new NoteXmppMessage(obj.noteInfo, obj.listNoteSendToObjects);
nXmpp.SendMessage();
channel.BasicAck(ea.DeliveryTag, false); } } }
优点:a生产者,和消费者分离, b.消息持久化保存,重启RabbitMQ,和应用系统,消费者,生产者程序,都不会丢失消息。 c:当列队待处理消息大量滞留时,可以单纯的增加消费者个数来,提高消费能力。缺点:开发部署较为复杂