.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
- {
- <pre name="code" class="csharp">
- NoteMessageObject obj = (NoteMessageObject)state; NoteXmppMessage nXmpp = new NoteXmppMessage(obj.noteInfo, obj.listNoteSendToObjects); nXmpp.SendMessage(); } catch(Exception e) {
优点:执行完代码不用管推送是否成功直接返回给客户端,把推送交给线程,提高了系统响应速度;
缺点: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)
- {
-
-
- }
- }
优点:有了线程池管理线程,很好的解决的多线程时,线程资源的复用,大大提供了效率,减少了由于线程过多带来的问题。缺点:随着推送消息的增多,大量消息堆积。系统负荷增大。
重启系统后,推送消息丢失。
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();
- <pre>
消费者代码:
- 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:当列队待处理消息大量滞留时,可以单纯的增加消费者个数来,提高消费能力。缺点:开发部署较为复杂