1. 程式人生 > >NoSQL初探之人人都愛Redis:(3)使用Redis作為訊息佇列服務場景應用案例

NoSQL初探之人人都愛Redis:(3)使用Redis作為訊息佇列服務場景應用案例

一、訊息佇列場景簡介

  “訊息”是在兩臺計算機間傳送的資料單位。訊息可以非常簡單,例如只包含文字字串;也可以更復雜,可能包含嵌入物件。訊息被髮送到佇列中,“訊息佇列”是在訊息的傳輸過程中儲存訊息的容器

  在目前廣泛的Web應用中,都會出現一種場景:在某一個時刻,網站會迎來一個使用者請求的高峰期(比如:淘寶的雙十一購物狂歡節,12306的春運搶票節等),一般的設計中,使用者的請求都會被直接寫入資料庫或檔案中,在高併發的情形下會對資料庫伺服器或檔案伺服器造成巨大的壓力,同時呢,也使響應延遲加劇。這也說明了,為什麼我們當時那麼地抱怨和吐槽這些網站的響應速度了。當時2011年的京東圖書促銷,曾一直出現在購物車中點選“購買”按鈕後一直是“Service is too busy

”,其實就是因為當時的併發訪問量過大,超過了系統的最大負載能力。當然,後邊,劉強東臨時購買了不少伺服器進行擴充套件以求增強處理併發請求的能力,還請了資訊部的人員“喝茶”,現在京東已經是超大型的網上商城了,我也有同學在京東成都研究院工作了。

使用訊息佇列

  從京東當年的“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的程式碼如下:

        public ActionResult Index()
        {
            int a = 10;
            int b = 0;
            int c = a / b; //會拋一個DividedByZero的異常

            return View();
        }

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

    public class FilterConfig
    {
        public static void RegisterGlobalFilters(GlobalFilterCollection filters)
        {
            // MyExceptionFilterAttribute繼承自HandleError,主要作用是將異常資訊寫入日誌檔案中
            filters.Add(new MyExceptionFilterAttribute());
            // 預設的異常記錄類
            filters.Add(new HandleErrorAttribute());
        }
    }

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

    public class MyExceptionFilterAttribute : HandleErrorAttribute
    {
        //版本1:使用預置佇列型別儲存異常物件
        public static Queue<Exception> ExceptionQueue = new Queue<Exception>();

        public override void OnException(ExceptionContext filterContext)
        {
            //將異常資訊入隊
            ExceptionQueue.Enqueue(filterContext.Exception);
            //跳轉到自定義錯誤頁
            filterContext.HttpContext.Response.Redirect("~/Common/CommonError.html");

            base.OnException(filterContext);
        }
    }

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

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <meta name="viewport" content="width=device-width" />
    <title>錯誤</title>
    <style type="text/css">
        .timecss
        {
            color: red;
            font-weight: bold;
        }
    </style>
    <script type="text/javascript">
        function delayJump(url) {
            var timeValue = parseInt(document.getElementById("time").innerHTML);
            if (timeValue > 0) {
                timeValue--;
                document.getElementById("time").innerHTML = timeValue;
            }
            else {
                window.location.href = url;
            }
            setTimeout("delayJump('" + url + "')", 1000);
        }
    </script>
</head>
<body>
    <h2>抱歉,處理您的請求時出錯。將會在<span id="time" class="timecss">5</span>秒後自動跳轉到首頁,請耐心等候。
    </h2>
</body>
<script type="text/javascript">
    var destUrl = "/Home/NoError";
    delayJump(destUrl);
</script>
</html>
View Code

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

        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();

            WebApiConfig.Register(GlobalConfiguration.Configuration);
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);

            //自定義事件註冊
            MessageQueueConfig.RegisterExceptionLogQueue();
        }

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

  public class MessageQueueConfig
    {
        public static void RegisterExceptionLogQueue()
        {
            string logFilePath = HttpContext.Current.Server.MapPath("/App_Data/");
            //通過執行緒池開啟執行緒,不停地從佇列中獲取異常資訊並將其寫入日誌檔案
            ThreadPool.QueueUserWorkItem(o =>
            {
                while (true)
                {
                    try
                    {
                        if (MyExceptionFilterAttribute.ExceptionQueue.Count > 0)
                        {
                            Exception ex = MyExceptionFilterAttribute.ExceptionQueue.Dequeue(); //從佇列中出隊,獲取異常物件
                            if (ex != null)
                            {
                                //構建完整的日誌檔名
                                string logFileName = logFilePath + DateTime.Now.ToString("yyyy-MM-dd") + ".txt";
                                //獲得異常堆疊資訊
                                string exceptionMsg = ex.ToString();
                                //將異常資訊寫入日誌檔案中
                                File.AppendAllText(logFileName, exceptionMsg, Encoding.Default);
                            }
                        }
                        else
                        {
                            Thread.Sleep(1000); //為避免CPU空轉,在佇列為空時休息1秒
                        }
                    }
                    catch (Exception ex)
                    {
                        MyExceptionFilterAttribute.ExceptionQueue.Enqueue(ex);
                    }
                }
            }, logFilePath);
        }
    }

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

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

  ②其次通過執行緒池ThreadPool開啟一個執行緒,不停地監聽訊息佇列裡邊的待辦事項個數,如果個數>0,則進行出隊(FIFO,先入隊的先出隊)操作。這裡主要是取出具體的異常例項物件,並將異常的具體堆疊資訊追加寫入到指定命名格式的檔案中。

PS:許多應用程式建立的執行緒都要在休眠狀態中消耗大量時間,以等待事件發生。其他執行緒可能進入休眠狀態,只被定期喚醒以輪詢更改或更新狀態資訊。執行緒池通過為應用程式提供一個由系統管理的輔助執行緒池使您可以更為有效地使用執行緒。關於執行緒池的更多資訊請訪問:http://msdn.microsoft.com/zh-cn/library/system.threading.threadpool(v=VS.90).aspx

  ③如果該執行緒檢測到訊息佇列中無待辦事項,則使用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地址:埠號 的字串陣列。

    public class MyExceptionFilterAttribute : HandleErrorAttribute
    {
        //版本2:使用Redis的客戶端管理器(物件池)
        public static IRedisClientsManager redisClientManager = new PooledRedisClientManager(new string[] 
        {
            //如果是Redis叢集則配置多個{IP地址:埠號}即可
            //例如: "10.0.0.1:6379","10.0.0.2:6379","10.0.0.3:6379"
            "127.0.0.1:6379"
        });
        //從池中獲取Redis客戶端例項
        public static IRedisClient redisClient = redisClientManager.GetClient();

        public override void OnException(ExceptionContext filterContext)
        {
            //將異常資訊入隊
            redisClient.EnqueueItemOnList("ExceptionLog", filterContext.Exception.ToString());
            //跳轉到自定義錯誤頁
            filterContext.HttpContext.Response.Redirect("~/Common/CommonError.html");

            base.OnException(filterContext);
        }
    }

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

<configSections>
    <!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
    <section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=4.4.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
    <!-- Log4Net配置宣告 -->
    <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler,log4net"/>
  </configSections>
  <!-- Log4Net具體配置 -->
  <log4net>
    <!-- OFF, FATAL, ERROR, WARN, INFO, DEBUG, ALL -->
    <!-- Set root logger level to ERROR and its appenders -->
    <root>
      <level value="ALL"/>
      <appender-ref ref="SysAppender"/>
    </root>
    <!-- Print only messages of level DEBUG or above in the packages -->
    <logger name="WebLogger">
      <level value="DEBUG"/>
    </logger>
    <appender name="SysAppender" type="log4net.Appender.RollingFileAppender,log4net" >
      <param name="File" value="App_Data/" />
      <param name="AppendToFile" value="true" />
      <param name="RollingStyle" value="Date" />
      <param name="DatePattern" value="&quot;Logs_&quot;yyyyMMdd&quot;.txt&quot;" />
      <param name="StaticLogFileName" value="false" />
      <layout type="log4net.Layout.PatternLayout,log4net">
        <!--<param name="ConversionPattern" value="%d [%t] %-5p %c - %m%n" />-->
        <param name="ConversionPattern" value="記錄時間:%date %n執行緒ID: [%thread] %n日誌級別:%-5level %n出錯類:%logger property: [%property{NDC}] - %n錯誤描述:%message%newline %n" />
        <param name="Header" value="-------------------------------------------------------header-----------------------------------------------------------&#13;&#10;" />
        <param name="Footer" value="-------------------------------------------------------footer-----------------------------------------------------------&#13;&#10;" />
      </layout>
    </appender>
    <appender name="consoleApp" type="log4net.Appender.ConsoleAppender,log4net">
      <layout type="log4net.Layout.PatternLayout,log4net">
        <param name="ConversionPattern" value="%d [%t] %-5p %c - %m%n" />
      </layout>
    </appender>
  </log4net>
View Code

PS:Log4Net是用來記錄日誌的一個常用元件(Log4J的移植版本),可以將程式執行過程中的資訊輸出到一些地方(檔案、資料庫、EventLog等)。由於Log4Net不是本篇博文介紹的重點,所以對Log4Net不熟悉的朋友,請在部落格園首頁搜尋:Log4Net,瀏覽其詳細的介紹。

  其次,在App_Start資料夾中新增一個類,取名為LogConfig,定義一個靜態方法:RegisterLog4NetConfigure,具體程式碼只有一行,實現了Log4Net配置的初始化操作。

    public class LogConfig
    {
        public static void RegisterLog4NetConfigure()
        {
            //獲取Log4Net配置資訊(配置資訊定義在Web.config檔案中)
            log4net.Config.XmlConfigurator.Configure();
        }
    }

  最後,在Global.asax中的Application_Start方法中新增一行程式碼,註冊Log4Net的配置:

        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();

            WebApiConfig.Register(GlobalConfiguration.Configuration);
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);


            //自定義事件註冊
            MessageQueueConfig.RegisterExceptionLogQueue();
            LogConfig.RegisterLog4NetConfigure();
        }

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

      public static void RegisterExceptionLogQueue()
        {
            //通過執行緒池開啟執行緒,不停地從佇列中獲取異常資訊並將其寫入日誌檔案
            ThreadPool.QueueUserWorkItem(o =>
            {
                while (true)
                {
                    try
                    {
                        if (MyExceptionFilterAttribute.redisClient.GetListCount("ExceptionLog") > 0)
                        {
                            //從佇列中出隊,獲取異常物件
                            string errorMsg = MyExceptionFilterAttribute.redisClient.DequeueItemFromList("ExceptionLog");
                            if (!string.IsNullOrEmpty(errorMsg))
                            {
                                //使用Log4Net寫入異常日誌
                                ILog logger = LogManager.GetLogger("Log");
                                logger.Error(errorMsg);
                            }
                        }
                        else
                        {
                            Thread.Sleep(1000); //為避免CPU空轉,在佇列為空時休息1秒
                        }
                    }
                    catch (Exception ex)
                    {
                        MyExceptionFilterAttribute.redisClient.EnqueueItemOnList("ExceptionLog", ex.ToString());
                    }
                }
            });
        }

   (6)最後一步,除錯驗證是否能正常寫入App_Data檔案的日誌中,發現寫入的異常日誌如下,格式好看,資訊詳細,圓滿完成了我們的目的。

四、小結

  使用訊息佇列將呼叫非同步化,可以改善網站系統的效能:訊息佇列具有很好的削峰作用,即通過非同步處理,將短時間高併發產生的事務訊息儲存在訊息佇列中,從而削平高峰期的併發事務。在電商網站的促銷活動中,合理使用訊息佇列,可以有效地抵禦促銷活動剛開始大量湧入的訂單對系統造成的衝擊。本文使用訊息佇列的思想,藉助Redis+Log4Net完成了一個超簡單的異常日誌佇列的應用案例,可以有效地解決在多執行緒操作中對日誌檔案的併發操作帶來的一些問題。同樣地,藉助訊息佇列的思想,我們也可以完成對資料庫的高併發的訊息佇列方案。所以,麻雀雖小五臟俱全,理解好了這個案例,相信對我們這些菜鳥碼農是有所裨益的。同樣,也請大牛們一笑而過,多多指教菜鳥們一步一步地提高,謝謝了!後邊,我們會探索一下Redis的叢集、主從複製,以及在VMWare中建立幾臺虛擬機器來構建主從結構,並使用Redis記錄網站中重要的Session會話物件,或者是電商專案中常見的商品類目資訊等。但是,本人資質尚淺,並且都是一些初探性質的學習,如有錯誤和不當,還請各位園友多多指教!

參考文獻

(1)傳智播客.Net學院王承偉,資料優化技術之Redis公開課,http://bbs.itcast.cn/thread-26525-1-1.html

(2)Sanfilippo/賈隆譯,《幾點建議,讓Redis在你的系統中發揮更大作用》,http://database.51cto.com/art/201107/276333.htm

(3)NoSQLFan,《Redis作者談Redis應用場景》,http://blog.nosqlfan.com/html/2235.html

(4)善心如水,《C#中使用Log4Net記錄日誌》,http://www.cnblogs.com/wangsaiming/archive/2013/01/11/2856253.html

(5)逆心,《ServiceStack.Redis之IRedisClient》,http://www.cnblogs.com/kissdodog/p/3572084.html

(6)李智慧,《大型網站技術架構-核心原理與案例分析》,http://item.jd.com/11322972.html

附件下載

作者:周旭龍

本文版權歸作者和部落格園共有,歡迎轉載,但未經作者同意必須保留此段宣告,且在文章頁面明顯位置給出原文連結。

相關推薦

NoSQL初探人人Redis3使用Redis作為訊息佇列服務場景應用案例

一、訊息佇列場景簡介   “訊息”是在兩臺計算機間傳送的資料單位。訊息可以非常簡單,例如只包含文字字串;也可以更復雜,可能包含嵌入物件。訊息被髮送到佇列中,“訊息佇列”是在訊息的傳輸過程中儲存訊息的容器。   在目前廣泛的Web應用中,都會出現一種場景:在某一個時刻,網站會迎來一個使用者請求的高峰期(

NoSQL初探人人Redis3使用Redis作為消息隊列服務場景應用案例

public 系統服務 就是 toolbar logfile manager 客戶端連接 狀態信息 朋友 http://www.cnblogs.com/edisonchou/p/3825682.html 一、消息隊列場景簡介   “消息”是在兩臺

redis入門3redis的配置獲取和修改

配置 daemonize rip require str 無限 文件的操作 idf master 一、Redis 配置 Redis 的配置文件位於 Redis 安裝目錄下,文件名為 redis.conf。 你可以通過 CONFIG 命令查看或設置配置項。 二、使用配置 1、

Redis學習3-redis啟動

clas CA shu 本機 運行 指定 默認端口 bsp moni 前端啟動 tomcat,redis,mysql的端口號: mysql 3306 tomcat 8088 redis 6379 一,啟動redis服務: 例如當前位置在

曹工說Redis原始碼3-- redis server 啟動過程完整解析

文章導航 Redis原始碼系列的初衷,是幫助我們更好地理解Redis,更懂Redis,而怎麼才能懂,光看是不夠的,建議跟著下面的這一篇,把環境搭建起來,後續可以自己閱讀原始碼,或者跟著我這邊一起閱讀。由於我用c也是好幾年以前了,些許錯誤在所難免,希望讀者能不吝指出。 曹工說Redis原始碼(1)-- redi

人人是產品經理

技術分享 com .com log bsp png logs -1 img 人人都是產品經理(五)

人人是產品經理

pan image com tro size spa .cn 溝通 -s 職場中的群體溝通: 人人都是產品經理(六)

redis學習redis持久化RDB、AOF

出現 add 停用 nbsp 滿足 相同 客戶 -a 工具 redis是內存數據庫,它把數據存儲在內存中,這樣在加快讀取速度的同時也對數據安全性產生了新的問題,即當redis所在服務器發生宕機後,redis數據庫裏的所有數據將會全部丟失。為了解決這個問題,redis提供了持

資料庫redis1—— redis資料庫安裝,簡單使用

簡介 reids,由Salvatore Sanfilippo寫的一個高效能的key-value資料庫,並且它是非關係型資料庫,也就是沒有像mysql那樣多表連結操作,並且它是是完全開源免費的,遵守BSD協議。   reids 與其他 key - value 快取產品有以下三個特點: r

資料庫redis2—— redis配置檔案,常用命令,效能測試工具

redis配置 如果你是找網上的其他教程來完成以上操作的話,相信你見過有的啟動命令是這樣的:   啟動命令帶了這個引數:redis.windows.conf,由於我測試環境是windows平臺,所以是這個,有的是redis.conf。顧名思義,redis.conf就是配置檔案,然後啟動時加

數據庫redis1—— redis數據庫安裝,簡單使用

容器 keys val entos 隨機 數據結構 ubunt 基本 hal 簡介 reids,由Salvatore Sanfilippo寫的一個高性能的key-value數據庫,並且它是非關系型數據庫,也就是沒有像mysql那樣多表鏈接操作,並且它是是完全開源免費的,遵

高效能網站架構設計快取篇3- Redis 的配置

我們說Redis是一個強大的Key-Value儲存系統,在前面我們已遇到了兩個問題: 1、redis server 啟動後,獨佔程序,能不能修改為後臺服務呢? 2、redis server 服務是單執行緒的,而我的機器是多核的,能不能在同一臺機器上開啟多個例項更充分的利用 cpu 資源呢?但6379埠已經

Redis學習 Redis 持久化RDB和AOF

Redis 持久化提供了多種不同級別的持久化方式:一種是RDB,另一種是AOF.   RDB 持久化可以在指定的時間間隔內生成資料集的時間點快照(point-in-time snapshot)。   AOF 持久化記錄伺服器執行的所有寫操作命令,並在伺服器啟動時,通過重新執行這些命令來還原資

Redis專題3鎖的基本概念到Redis分散式鎖實現

拓展閱讀:Redis閒談(1):構建知識圖譜 Redis專題(2):Redis資料結構底層探祕 近來,分散式的問題被廣泛提及,比如分散式事務、分散式框架、ZooKeeper、SpringCloud等等。本文先回顧鎖的概念,再介紹分散式鎖,以及如何用Redis來實現分散式鎖。 一、鎖的基本瞭解 首先,回顧一下我

Redis基礎Redis持久化RDB與AOF

什麼是Redis持久化? --- Redis是鍵值對的記憶體資料庫,它將資料儲存在記憶體裡。客戶端傳送命令到伺服器,再由伺服器到記憶體裡查詢資料。 ![image](https://yxl-article.oss-cn-shenzhen.aliyuncs.com/images/redis-basic/03

軟工作業 3用戶體驗分析

span 基礎 管理 用戶體驗 過程 在線 菜單 ges log 一.作業目標及要求 http://www.cnblogs.com/juking/p/7660646.html 二、分析過程及內容 (一)滿意的地方 1.必要的提示和幫助文檔 ①在公共號服務未出現故障的情況

2017軟工作業 3用戶體驗分析

調整 進行 提供服務 src http -a 快速 在線 使用 1.目標:基於實例分析,體會用戶體驗設計的7條準則 (1)給用戶及時快速反饋; (2)界面符合慣例; (3)用戶控制權(主人); (4)一致性和標準化; (5)適合各類用戶(不絕對) (6)幫助用戶排除軟件缺陷

從0開始的微服務架構如何快速體驗微服務架構?

常常 原來 人員 google tty 打包 第三方 江湖 ces 雖然已經紅了很久,但是“微服務架構”正變得越來越重要,也將繼續火下去。各個公司與技術人員都在分享微服務架構的相關知識與實踐經驗,但我們發現,目前網上的這些相關文章中,要麽上來就是很有借鑒意義的幹貨,要麽就是

Redis學習2-redis安裝

註意 編譯依賴 redis啟動 依賴 環境 code 技術分享 c-c++ spa 安裝redis需要先從官網下載的源碼進行編譯,編譯依賴GCC環境,如果沒有GCC環境,需要安裝GCC。 yum install gcc-c++ 步驟1:上傳 將Win

Redis學習8-redis其他特性

font 提前 redis學習 清空 exec 自己 mysql數據庫 data 批量執行 消息訂閱與發布 subscribe  Channel:訂閱頻道 psubscribe  channel*:批量訂閱頻道:例如:psubscribe  S*,訂閱以S開頭的頻道。 pu