<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??一站式輕松地調用各大LLM模型接口,支持GPT4、智譜、豆包、星火、月之暗面及文生圖、文生視頻 廣告
                [JMS-使用消息隊列優化網站性能](http://www.tuicool.com/articles/QfEri2) [TOC=1,3] 在當今互聯網和電商盛行的情況下,網站的性能受到了極大地挑戰。大數據,高并發成為大型網站的標志。無論淘寶的雙11優惠,還是小米搶購,它們都有一個共同的特點,那就是在短時間內,突然涌入超出平時數倍的用戶。 如果每個用戶從請求,到訂單處理,再到響應返回均在一個請求中同步處理的話,用戶的響應時間將會隨著并發量的提高越來越久,直到最后服務器崩潰。在這種情況下,可以使用JMS消息隊列,異步處理訂單。用戶發出請求,服務器接收請求以后,向消息隊列中發送一個消息,就立刻返回“訂單正處理”的消息給用戶。而訂單處理服務器可以不停的從消息隊列中取出消息,按照自己的節奏進行處理。這就像生產者-消費者模式一樣。通過這種異步的處理方式,用戶響應時間得到縮減,服務器的壓力也可以被時間分擔,從而避過洪峰期。 在之前的文章?[JavaMail發送google email](http://my.oschina.net/xpbug/blog/263974)?中,我使用的是同步方式發送email,可以一個用戶的響應有多慢。今天我將使用JMS的方式,改進郵件發送系統。 ## JMS 首先還是要簡單的介紹下JMS(Java Messaging Service)。太基礎的就不再嘮叨了,這里只列出JMS的兩種消息模式: 1. PTP模式 PTP模式中,消息是Queue的形式從一端到另一端。無論client2是否連接,運行中,?JMS的可靠性使得?Msg都不會丟失。當client2恢復運行時,Queue會繼續傳輸。Queue的兩端可以有多個clients,但是每一個消息,只能被一個consumer client消費。所以,對于消費客戶端們而言,也屬于爭搶式消費。 ![](http://img2.tuicool.com/fQbMf2.png!web) 2. Pub/Sub模式 在發布訂閱的模式中,則是以topic,subscription,client的方式。所有的訂閱者均可受到消息,一個消息會被重復的發送給不同的消費者。 ![](http://img2.tuicool.com/jY7ZVb.png!web) 一個topic下面可以掛很多的subscription,但是這些subscription只有4種類型,這4中類型如下圖: ![](http://img1.tuicool.com/emeuUb.png!web) Subscription:只能有一個client,當client斷開連接,subscription則自動銷毀。 Durable Subscription:只能有一個client,當client斷開連接后,Message會被存在subscription中,一旦client重新連接,則繼續發送消息。 Shared Subscription:可以有多個client同時掛在一個subscription上,這樣可以有多個client并行的處理此Subscription下的消息。記住,消息只能被其中一個client所消費,不能被多個client同時消費。 Shared Durable Subscription:區別在durable上,即client斷線,subscription會繼續存在。 PTP適合單一消息類型,單一消費者類型。而Pub/Sub適合多種類消息,和多種消費者類型。 此外,消息可以是可持久化的,也可以是非持久化的。持久化的消息將被寫入硬盤,當MQ server重啟后,消息不會丟失。 消息的消費方式也存在兩種模式: 1. JMS client API調用。此種方式的缺點在于,需要自己維護多線程。 2. MDB(Message Driven Bean)。使用EJB的方式,可以由EJB容器幫忙管理多線程。其中MDB是多實例的,每個消息過來都是一個新的線程。 ## JMS服務器 一般,稱為MQ server。當前最火的是Apache ActiveMQ,也有使用JBoss Messaging的。但本文將使用Oracle的Glassfish Open MQ。 Open MQ是Oracle Glassfish下的一款MQ server,它是第一個實現了JMS2.0標準的MQ server。它可以單獨使用,搭建集群,也可以內嵌到Glassfish中使用。在Glassfish4中,OpenMQ已經集成在Glassfish4中。Glassfish4可以使用內嵌的OpenMQ來滿足小型網站的異步消息處理,也可以使用外部的OpemMQ集群來滿足大型網站的異步消息處理。 有人會很糾結,ActiveMQ,OpenMQ到底哪一個好?其實我覺得每一款軟件都有各自的特點,它們均能支撐起一個大型網站的架構,問題在于你如何使用它們。Glassfish是一個縮小型的WebLogic,輕巧易用。OpenMQ支持JMS2.0,易集成于Glassfish,又為Oracle支持的開源項目,其能力一樣強悍。唯一的缺點是,集成于Glassfish中的OpenMQ不支持C客戶端。 接下來,我將使用JMS消息隊列來優化郵件發送系統。 ## 小型網站的郵件發送系統 ### 必備軟件 Glassfish4,版本4是必須的,因為4中集成了OpenMQ,我們可以直接在Glassfish4中使用本地JMS服務。針對大型網站的遠程JMS服務,我們將在下一篇文章中實現。 ### 改造方案 本文將嘗試兩種改造方案: 1. JMS client API + threadPool,自己在后臺啟動線程監聽,并管理多線程。 2. MDB, EJB容器進行Message監聽,并幫助管理多線程。 **應該使用多少線程?**?線程的數量與CPU的數量和IO阻塞時間有關系。如果線程沒有任何IO阻塞,那么,線程數量應該和CPU數量相同。因為多余的線程需要等待CPU。如果存在IO阻塞,則需要多余CPU數量的線程,一個線程阻塞在IO上的時候,CPU不至于空閑,可以去執行其它線程。仔細推導,可以能通過IO阻塞時間跟運行時間的比例,可以計算出所需線程的數量?。 顯然,方案二是最明智的做法。家下來,開始實現方案二。 ### 配置JMS Resources? 打開Glassfish管理頁面?[http://localhost:4848](http://localhost:4848/)?? 1. 配置JMS ConnectionFactory。可以使用glassfish默認的。 ![](http://img2.tuicool.com/2MzEFf.png!web) 2. 配置Destination Resources. 展開Resources->JMS Resources->Destination Resources. 創建一個Queue resource。 ![](http://img1.tuicool.com/7v2M7v.png!web) ### 配置Java Mail Session 請在上一篇文章中?[http://my.oschina.net/xpbug/blog/263974#OSC_h2_3](http://my.oschina.net/xpbug/blog/263974#OSC_h2_3)??找到Gmail的配置方法。 ### 創建一個Web項目 創建一個名為sample的web項目。? ### 創建MDB 創建接收JMS消息的MDB,我們使用簡單的text message。email地址在message體中。MDB會向地址中發送一個簡單郵件。 ~~~ package com.mycompany; import java.util.logging.Level; import java.util.logging.Logger; import javax.ejb.ActivationConfigProperty; import javax.ejb.MessageDriven; import javax.jms.JMSException; import javax.jms.Message; import javax.jms.MessageListener; import javax.mail.Address; import javax.mail.MessagingException; import javax.mail.Session; import javax.mail.Transport; import javax.mail.internet.InternetAddress; import javax.mail.internet.MimeMessage; import javax.naming.Context; import javax.naming.InitialContext; import javax.naming.NamingException; /** * * @author none2 */ @MessageDriven(activationConfig = { @ActivationConfigProperty(propertyName = "destinationLookup", propertyValue = "jms/myQueue"), @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue") }) public class EmailMessageBean implements MessageListener { private final Session mySession; public EmailMessageBean() throws NamingException { Context initCtx = new InitialContext(); mySession = (Session) initCtx.lookup("mail/mySession"); } @Override public void onMessage(Message message) { try { String address = message.getBody(String.class); javax.mail.Message mail = new MimeMessage(mySession); mail.setFrom(new InternetAddress("joey.zhangpeng@gmail.com")); Address toAddress = new InternetAddress(address); mail.addRecipient(javax.mail.Message.RecipientType.TO, toAddress); mail.setSubject("Hello"); mail.setText("A notification."); Transport.send(mail); } catch (MessagingException | JMSException ex) { Logger.getLogger(EmailMessageBean.class.getName()).log(Level.SEVERE, null, ex); } } } ~~~ ### index.html 創建網站的默認頁面 ~~~ <html> <head> <title>TODO supply a title</title> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> </head> <body> <form method="post" action="/sample/NotifyServlet"> Email:<input name="email" value=""/> <input type="submit" value="Buy" name="submit"/> </form> </body> </html> ~~~ ### 創建NotifyServlet 在servlet中,使用jms client,發送jms消息到queue中。 ~~~ package com.mycompany; import java.io.IOException; import java.io.PrintWriter; import javax.annotation.Resource; import javax.jms.ConnectionFactory; import javax.jms.JMSContext; import javax.jms.Queue; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * * @author none2 */ @WebServlet(name = "NotifyServlet", urlPatterns = {"/NotifyServlet"}) public class NotifyServlet extends HttpServlet { @Resource(lookup = "java:comp/DefaultJMSConnectionFactory") private ConnectionFactory connectionFactory; @Resource(lookup = "jms/myQueue") private Queue queue; @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String email = request.getParameter("email"); try (JMSContext context = connectionFactory.createContext();) { context.createProducer().send(queue, email); } response.setContentType("text/html;charset=UTF-8"); try (PrintWriter out = response.getWriter()) { /* TODO output your page here. You may use following sample code. */ out.println("<!DOCTYPE html>"); out.println("<html>"); out.println("<head>"); out.println("<title>Servlet NotifyServlet</title>"); out.println("</head>"); out.println("<body>"); out.println("<h1>You have send a notification to " + email + "</h1>"); out.println("</body>"); out.println("</html>"); } } } ~~~ 最后,進行項目打包并部署。訪問?[http://localhost:8080/sample/](http://localhost:8080/sample/)??來測試一下。 ## 后續,使用遠程MQ server增加伸縮性
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看