国产精品电影_久久视频免费_欧美日韩国产激情_成年人视频免费在线播放_日本久久亚洲电影_久久都是精品_66av99_九色精品美女在线_蜜臀a∨国产成人精品_冲田杏梨av在线_欧美精品在线一区二区三区_麻豆mv在线看

詳解使用Redis作為消息隊列服務場景應用案例

存儲 存儲軟件 Redis
“消息”是在兩臺計算機間傳送的數據單位。消息可以非常簡單,例如只包含文本字符串;也可以更復雜,可能包含嵌入對象。消息被發送到隊列中,“消息隊列”是在消息的傳輸過程中保存消息的容器。

 一、消息隊列場景簡介

“消息”是在兩臺計算機間傳送的數據單位。消息可以非常簡單,例如只包含文本字符串;也可以更復雜,可能包含嵌入對象。消息被發送到隊列中,“消息隊列”是在消息的傳輸過程中保存消息的容器。

在目前廣泛的Web應用中,都會出現一種場景:在某一個時刻,網站會迎來一個用戶請求的高峰期(比如:淘寶的雙十一購物狂歡節,12306的春運搶票節等),一般的設計中,用戶的請求都會被直接寫入數據庫或文件中,在高并發的情形下會對數據庫服務器或文件服務器造成巨大的壓力,同時呢,也使響應延遲加劇。這也說明了,為什么我們當時那么地抱怨和吐槽這些網站的響應速度了。當時2011年的京東圖書促銷,曾一直出現在購物車中點擊“購買”按鈕后一直是“Service is too busy”,其實就是因為當時的并發訪問量過大,超過了系統的最大負載能力。當然,后邊,劉強東臨時購買了不少服務器進行擴展以求增強處理并發請求的能力,還請了信息部的人員“喝茶”,現在京東已經是超大型的網上商城了,我也有同學在京東成都研究院工作了。

[[224240]]

從京東當年的“Service is too busy”不難看出,高并發的用戶請求是網站成長過程中必不可少的過程,也是一個必須要解決的難題。在眾多的實踐當中,除了增加服務器數量配置服務器集群實現伸縮性架構設計之外,異步操作也被廣泛采用。而異步操作中最核心的就是使用消息隊列,通過消息隊列,將短時間高并發產生的事務消息存儲在消息隊列中,從而削平高峰期的并發事務,改善網站系統的性能。在京東之類的電子商務網站促銷活動中,合理地使用消息隊列,可以有效地抵御促銷活動剛開始就開始大量涌入的訂單對系統造成的沖擊。

記得我在實習期間,成都市XXXX局的一個價格信息采集發布系統項目中有一個采集任務發布的模塊,其中每個任務都是一個事務,這個事務中需要向數據庫中不斷地插入行,每個任務發布時都要往表中插入幾百行甚至幾千行的任務數據(比如價格采集日報,往往需要發布2-3年的任務數據,每一天都是一個任務,所以大約有2,3千行任務期號數據,還要發給很多個區縣的監測中心,因此數據庫寫操作量很大,更別說同時發布的并發操作),由于業務邏輯的處理比較復雜和往數據庫的寫操作量交大,所以在沒有采用消息隊列時點擊“發布”按鈕后往往需要等待1分鐘左右的時間才提示“發布成功”,用戶體驗極不友好。

這時,我們就可以使用消息隊列的思想來重構這個發布模塊,在用戶點擊“發布”按鈕后,系統只需要把往數據庫插入的這個事務信息插入到指定的任務發布消息隊列里邊去(入隊操作,這里一般有一臺獨立的消息隊列服務器來單獨存儲和處理),然后系統就可以立即對用戶的這個發布請求進行響應(比如給出一個發布成功的操作提示,這里暫不考慮消息隊列服務操作失敗的情形,如果失敗了,可以考慮采用給用戶發送郵件、短信或站內消息,讓其重新進行發布操作)。

最后,消息隊列服務器中有一個進程單獨對消息隊列進行處理,首先判斷消息隊列中是否有待處理的消息,如果有,則將其取出(出隊操作,堅持“先進先出”的順序,保證事務的準確性)進行相應地處理(比如這里是進行保存數據的操作,將數據插入到數據庫服務器中的指定數據庫里邊,實質還是文件的IO操作)。就這樣,通過消息隊列將高并發用戶請求進行異步操作,然后一一對消息隊列進行出隊的同步操作,也避免了并發控制的難題。

說到這里,大家可能會想到這尼瑪不就是生產者消費者模式么?對的,么么嗒,消息隊列就是生產者消費者模式的典型場景。簡單地說,客戶端不同用戶發送的操作請求就是生產者,他們將要處理的事務存儲到消息隊列中,然后消息隊列服務器的某個進程不停地將要處理的單個事務從消息隊列中一個一個地取出來進行相應地處理,這就是消費者消費的過程。

下面我們將以異常日志為案例,介紹在.Net中如何采用消息隊列的思想解決并發問題。當然,消息隊列只是解決并發問題的其中一種方式,在實際中往往需要結合多種不同的技術方式來共同解決,比如負載均衡、反向代理、集群等方案。這里,雖然以異常日志為案例,但是“麻雀雖小五臟俱全”,日志寫入文件的高并發操作也同樣適用于數據庫的高并發,所以,研究這個案例是具有實際意義的。

二、使用預置類型實現異常日志隊列

在日常的Web應用中,異常日志的記錄是一個十分重要的要點。因為,人無完人,系統也一樣,難免會在什么時候出一個測試階段未能完全測試到的異常。這時候,不能將異常信息直接顯示給客戶,那樣既不友好也不安全。所以,一般都采用將異常信息記錄到日志文件中(比如某個txt文件,數據庫中某個表等),然后技術支持人員通過查看異常日志,分析異常原因,改進BUG重新發布,保障系統正常運行。

在用戶的各種操作中,如果出現異常的時間一致,那么記錄異常日志的操作就會成為并發操作,而記錄異常日志又屬于文件的IO操作(其實數據庫的讀寫歸根結底也是對文件即對磁盤進行的IO操作),因此很有可能帶來并發控制的一系列問題。在以往的編碼實踐中,我們可以通過給不同的IO請求進行加鎖(C#中的lock),等第一個請求完成寫入后釋放鎖,第二個請求再獲得鎖,進行IO操作,然后釋放掉,一直到第N個請求釋放后結束。這種方式,雖然解決了并發操作帶來的問題,但是通過加鎖延遲了用戶響應請求的時間(比如第一個正在IO寫入操作時,后面的均處于等待狀態),并且加鎖也會給服務器帶來一定的性能負擔,造成服務器性能的下降。

基于以上原因,我們采用消息隊列的思想將異常日志的記錄操作改為隊列版,這里我們先不采用Redis,直接使用.Net為我們提供的預置類型-Queue。接下來,就讓我們動手開刀,寫起來。

(1)新建一個ASP.NET MVC 4項目,選擇“基本”類型,視圖引擎選擇“Razor”。

(2)既然是異常日志記錄,首先得有異常。這時,我們腦海中想到了那個經典的異常:DividedByZeroException。于是,在Controllers文件夾中新建一個Controller,取名為Home(這里因為Global文件中的默認路由就指向了Home控制器中的Index這個Action),在HomeController中修改Index這個Action的代碼如下:

  1. public ActionResult Index() 
  2.        { int a = 10; int b = 0; 
  3.         int c = a / b; 
  4.         //會拋一個DividedByZero的異常  
  5.         return View(); 
  6.        } 

(3)在ASP.NET MVC項目中,我們需要在Global.asax中的Application_Start這個事件中修改全局過濾器(主要是App_Start中的FilterConfig類的RegisterGlobalFilters這個方法),讓系統支持對異常的全局處理操作(我們這里主要是對異常進行記錄到指定文件中)。PS:Application_Start是整個Web應用的起始事件,主要進行一些配置(如過濾器配置、日志器配置、路由配置等等)的初始化操作,當然這些配置也只會進行一次。

  1. public class FilterConfig 
  2.     { public static void RegisterGlobalFilters 
  3.     (GlobalFilterCollection filters) 
  4.     { // MyExceptionFilterAttribute繼承自HandleError, 
  5.     主要作用是將異常信息寫入日志文件中 filters.Add 
  6.     (new MyExceptionFilterAttribute()); // 
  7.      默認的異常記錄類 filters.Add(new  
  8.      HandleErrorAttribute 
  9.      ()); 
  10.         } 
  11.     } 

通過改寫過濾器配置,我們向全局過濾器中注冊了一個異常處理的過濾器配置,那么這個MyExceptionFilterAttribute類又是如何編寫的呢?

通過使該類繼承HandlerErrorAttribute并使其覆寫OnException這個事件,代表在異常發生時可以進行的操作。而我們在這兒主要通過一個異常隊列將獲取的異常寫入隊列,然后跳轉到自定義錯誤頁:~/Common/CommonError.html,這個錯誤頁很簡單,就是簡單的顯示“系統發生錯誤,5秒后自動跳轉到首頁”

(4)走到這里,生產者消費者模式中生產者的任務已經完成了,接下來消費者就需要開始消費了。也就是說,消息隊列已經建好了,我們什么時候從隊列中去任務,在哪里執行?怎么樣執行?通過上面的介紹,我們知道,在專門的消息隊列服務器中有一個進程在始終不停地監視消息隊列,如果有需要待辦的任務信息,則會立即從隊列中取出來執行相應的操作,直到隊列為空為止。于是,思路有了,我們馬上來實現以下。這個消息監視的操作也是一個全局操作,在系統啟動時就會一直運行,于是它也應該寫在Application_Start這個全局起始事件里邊,于是按照標準的配置寫法,我們在Application_Start中添加了如下代碼:MessageQueueConfig.RegisterExceptionLogQueue();

  1. protected void Application_Start() 
  2.         { 
  3.             AreaRegistration.RegisterAllAreas(); 
  4.  
  5.             WebApiConfig.Register 
  6.             (GlobalConfiguration.Configuration); 
  7.             FilterConfig.RegisterGlobalFilters 
  8.             (GlobalFilters.Filters); 
  9.             RouteConfig.RegisterRoutes 
  10.             (RouteTable.Routes); 
  11.             BundleConfig.RegisterBundles 
  12.             (BundleTable.Bundles); 
  13.  
  14.             //自定義事件注冊 
  15.             MessageQueueConfig. 
  16.             RegisterExceptionLogQueue 
  17.             (); 
  18.         } 

那么,這個MessageQueueConfig.RegisterExceptionLogQueue()又是怎么寫的呢?

現在,讓我們來看看這段代碼:

①首先定義Log文件存放的文件夾目錄,這里我們一般放到App_Data里邊,因為放到這里邊外網是無法訪問到的,可以防止下載操作;

②其次通過線程池ThreadPool開啟一個線程,不停地監聽消息隊列里邊的待辦事項個數,如果個數>0,則進行出隊(FIFO,先入隊的先出隊)操作。這里主要是取出具體的異常實例對象,并將異常的具體堆棧信息追加寫入到指定命名格式的文件中。

PS:許多應用程序創建的線程都要在休眠狀態中消耗大量時間,以等待事件發生。其他線程可能進入休眠狀態,只被定期喚醒以輪詢更改或更新狀態信息。線程池通過為應用程序提供一個由系統管理的輔助線程池使您可以更為有效地使用線程。

③如果該線程檢測到消息隊列中無待辦事項,則使用Thread.Sleep使線程“休息”一會,避免了CPU空轉(從理論上來說,CPU資源是很珍貴的,應該盡量提高CPU的利用率)。

(5)最后,我們來看看效果如何?

①首先,高大上的VS捕捉到了異常-DividedByZeroException:

②按照我們的全局異常處理過濾器,會將此異常記入隊列中,并返回HTTP 302重定向跳轉到自定義錯誤頁面:

③最后,打開App_Data文件夾,查看日志文件:

到這里時,我們已經借助消息隊列的思想完成了一個自定義的異常日志隊列服務。但也許有朋友會說,這個跟Redis有關系么?異常日志不都是用Log4Net么?不要著急,后邊我們就會使用Redis+Log4Net來重構這個異常日志隊列服務

三、使用Redis重構異常日志隊列

(1)第一步,開啟Redis的服務,這里我們使用命令開啟Redis服務(之前已經將Redis注冊到了Windows系統服務中了嘛,么么嗒):net start redis-instance,當然,也可以通過在Windows服務列表中開啟。

(2)第二步,在剛剛的版本1的Demo中新建一個文件夾,命名為Lib,將ServiceStack.Redis的dll和Log4Net的dll都拷貝進去。然后,在引用中添加對Lib文件夾中所有dll的引用。

(3)第三步,重寫MyExceptionFilterAttribute這個全局異常信息過濾器。這里使用到了Redis的客戶端連接池,每次連接時都是從池中取,不需要每次都創建,節省了時間和資源,提高了資源利用率。對于,多臺Redis服務器組成的集群而言,這里需要指定多個形如 IP地址:端口號 的字符串數組。

(4)第四步,首先在Web.config中加入Log4Net的詳細配置。

 View Code

PS:Log4Net是用來記錄日志的一個常用組件(Log4J的移植版本),可以將程序運行過程中的信息輸出到一些地方(文件、數據庫、EventLog等)。由于Log4Net不是本篇博文介紹的重點,所以對Log4Net不熟悉的朋友,請在博客園首頁搜索:Log4Net,瀏覽其詳細的介紹。

其次,在App_Start文件夾中添加一個類,取名為LogConfig,定義一個靜態方法:RegisterLog4NetConfigure,具體代碼只有一行,實現了Log4Net配置的初始化操作。

  1. public class LogConfig 
  2.  { public static void RegisterLog4NetConfigure() 
  3.          
  4.  { //獲取Log4Net配置信息(配置信息定義在Web.config文件中) 
  5.    log4net.Config.XmlConfigurator.Configure(); 
  6.         } 
  7.     } 

最后,在Global.asax中的Application_Start方法中添加一行代碼,注冊Log4Net的配置:

(5)第五步,改寫MessageQueueConfig中的RegisterExceptionLogQueue方法。這里就不再需要從預置類型Queue中取任務了,而是Redis中取出任務出隊進行相應處理。這里,我們使用了Log4Net進行異常日志的記錄工作。PS:注意在代碼頂部添加對log4net的引用:using log4net;

 (6)最后一步,調試驗證是否能正常寫入App_Data文件的日志中,發現寫入的異常日志如下,格式好看,信息詳細,圓滿完成了我們的目的。

四、小結

使用消息隊列將調用異步化,可以改善網站系統的性能:消息隊列具有很好的削峰作用,即通過異步處理,將短時間高并發產生的事務消息存儲在消息隊列中,從而削平高峰期的并發事務。在電商網站的促銷活動中,合理使用消息隊列,可以有效地抵御促銷活動剛開始大量涌入的訂單對系統造成的沖擊。本文使用消息隊列的思想,借助Redis+Log4Net完成了一個超簡單的異常日志隊列的應用案例,可以有效地解決在多線程操作中對日志文件的并發操作帶來的一些問題。同樣地,借助消息隊列的思想,我們也可以完成對數據庫的高并發的消息隊列方案。

責任編輯:武曉燕 來源: PHP開源社區
相關推薦

2024-03-22 12:10:39

Redis消息隊列數據庫

2018-08-15 09:48:27

數據庫Redis應用場景

2024-03-29 08:33:10

應用場景存儲搜索

2024-05-29 14:34:07

2010-04-13 17:00:43

Unix消息隊列

2022-01-15 07:20:18

Redis List 消息隊列

2022-01-21 19:22:45

RedisList命令

2010-04-21 12:12:56

Unix 消息隊列

2022-04-12 11:15:31

Redis消息隊列數據庫

2022-05-31 08:21:07

MQ使用場景消費消息

2025-04-24 10:40:46

CatalogFlink SQL元數據

2018-04-26 15:18:49

RTOS應用MPU

2010-04-21 14:49:13

Unix消息隊列

2024-10-25 08:41:18

消息隊列RedisList

2023-12-30 13:47:48

Redis消息隊列機制

2021-03-11 06:01:41

Linux消息隊列

2024-04-19 08:32:07

Redis緩存數據庫

2009-06-25 15:33:13

Java消息服務JMS

2021-04-30 08:39:10

架構消息隊列高并發

2017-10-11 15:08:28

消息隊列常見
點贊
收藏

51CTO技術棧公眾號

麻豆影视在线观看_| 欧美国内亚洲| 色琪琪一区二区三区亚洲区| 亚洲久久中文字幕| 国产成人欧美日韩在线电影| 日韩免费av电影| 欧美日韩亚洲一区| 91精品久久久久久久久青青| 国产99亚洲| 97视频在线观看成人| 爱情电影网av一区二区| 亚洲欧洲视频在线| 亚洲人免费短视频| 亚洲午夜精品久久久久久性色| а√在线天堂官网| 日韩精品日韩在线观看| 国产精品186在线观看在线播放| 欧美日韩一区二区三区四区五区 | 婷婷视频在线播放| 日韩电影在线免费看| 久久国产精品99久久久久久丝袜| 黄色成人在线网站| 精品视频第一区| 一区二区三区国产在线| 精品一区二区三区免费毛片| 国产亚洲亚洲| 亚洲一区高清| 成人免费视频播放| 国产自偷自偷免费一区 | 国产精品一在线观看| 国产精品日韩精品| 91精品动漫在线观看| 国内成+人亚洲| 日本少妇一区二区| 亚洲区成人777777精品| 久久无码av三级| 国产一级大片| 色综合一区二区| jizzjizz亚洲| 一区二区三区天堂av| 亚洲无线观看| 91影视免费在线观看| 日韩中文字幕亚洲一区二区va在线 | 欧亚精品中文字幕| 欧美色图首页| 日韩免费电影一区二区| 成+人+亚洲+综合天堂| www.99色| 91麻豆精品久久久久蜜臀| 朝桐光一区二区| 国产成人91久久精品| 亚洲欧美日韩国产一区二区| 91丨porny丨探花| 亚洲黄一区二区三区| 奇米影视888狠狠狠777不卡| 亚洲黄色av女优在线观看| 亚洲精品18| 97人人做人人人难人人做| 麻豆精品精品国产自在97香蕉| 日韩一级在线免费观看| 一本到一区二区三区| 欧美日韩在线精品一区二区三区激情综合 | 99久久久久| 色婷婷精品国产一区二区三区| 99精品欧美一区二区三区综合在线| 久久.com| 精品国产乱子伦一区| 国产精品极品在线观看| 精品亚洲欧美日韩| 国产亚洲精久久久久久| 求av网址在线观看| 欧美激情中文字幕在线| 欧美在线综合| 黄色片av在线| 亚洲色图色老头| 久久精品久久久| av日韩一区二区三区| 色噜噜偷拍精品综合在线| 四虎影视国产精品| 国产欧美日韩一区二区三区| 国产亚洲综合在线| 高清全集视频免费在线| 97在线视频免费播放| 久久99热这里只有精品| 伊人影院在线播放| 久久综合久久88| 久久精品卡一| 老司机色在线视频| 久久久精品视频成人| 老鸭窝毛片一区二区三区| 天天干天天综合| 亚洲欧洲国产一区| 99伊人成综合| 免费高清在线| 久久91亚洲人成电影网站| 免费观看在线色综合| 四虎电影院在线观看| 久久免费视频这里只有精品| 国内精品第一页| 快射av在线播放一区| 国产精品视频自在线| 国产亚洲精品中文字幕| 97精品国产综合久久久动漫日韩 | 色悠久久久久综合欧美99| 国产免费区一区二区三视频免费 | 亚洲欧美国产视频| 激情欧美一区| 中文乱码字幕高清在线观看| 欧美成人激情图片网| 国产毛片一区二区| av网站免费在线观看| av日韩免费电影| 亚洲mv大片欧洲mv大片精品| 牛牛影视久久网| 麻豆三级在线观看| 久久五月天综合| 成人av网站大全| 日本一区二区电影| 97超碰人人澡| 最近日韩中文字幕中文| 国产精品一二三区| 国产一区二区精品调教| 免费无码毛片一区二三区| 伊人久久免费视频| 国产91精品露脸国语对白| 成人小电影网站| 337p亚洲精品色噜噜狠狠p| 亚洲国内高清视频| 国产一区二区按摩在线观看| 中文在线а√在线8| 97在线免费视频观看| 中文字幕日韩av| 久久综合九色综合久久久精品综合 | 欧美三级精品| h无码动漫在线观看| 一区二区三区www| 成人午夜电影网站| 中文字幕成人| 天天爱天天操天天干| 777777777亚洲妇女| 一区二区视频在线看| 精品国精品国产自在久国产应用| 日本高清好狼色视频| 亚洲va国产va天堂va久久| 色婷婷综合激情| 免费欧美日韩| 一区二区乱码| 日韩精品一区二区三区久久| 高清亚洲成在人网站天堂| 一区二区三区在线观看网站| 图片区亚洲欧美小说区| 日本a级在线| 亚洲av综合色区| 欧美大尺度在线观看| 一区二区三区四区在线| 午夜电影亚洲| 国产高清视频色在线www| 久久久亚洲精品无码| 激情国产一区| 久草在线资源福利站| 夜夜添无码一区二区三区| 久久久久久成人| 欧美视频不卡中文| 日本不卡中文字幕| 亚洲男女网站| 日本在线三级| 神马欧美一区二区| 久久国产精品偷| 欧美性猛交xxxx免费看| 久久99精品国产麻豆婷婷| 欧美久久一区二区三区| 一区二区三区高清在线视频| 亚洲最大免费| 欧美亚洲在线播放| 666欧美在线视频| 91年精品国产| 国内精品福利| 一级欧美视频| 第一页在线观看| 两根大肉大捧一进一出好爽视频| 国产精品视频区1| 亚洲欧美三级在线| 精品久久久久久久久久| 国产一区日韩二区欧美三区| 九九热线有精品视频99| a国产在线视频| y4480在线8影院| 欧美一级爱爱视频| 91香蕉电影院| 日韩中文字幕视频在线观看| 色婷婷综合久久久| 91香蕉国产在线观看软件| 在线免费高清一区二区三区| 日韩精品一级| 日本成人不卡| 亚洲男人都懂的网站| 久色视频在线播放| 精品国产乱码久久久久久丨区2区| 欧美风情在线观看| 亚洲娇小xxxx欧美娇小|