標籤:
Redis的安裝及使用
在前面介紹了三篇關於MongoDB資料庫的開發使用文章,嚴格來講這個不能歸類於MongoDB資料庫開發,不過Redis又有著和MongoDB資料庫非常密切的關係,它們兩者很接近,Redis主要是記憶體中的NoSQL資料庫,用來提高效能的;MongoDB資料庫則是檔案中的NoSQL資料庫,做資料序號儲存使用的,它們兩者關係密切又有所區別。本篇主要介紹Redis的安裝及使用,為後面Redis和MongoDB資料庫的聯合使用先鋪下基礎。
1、Redis基礎及安裝
Redis是一個開源的使用ANSI C語言編寫、支援網路、可基於記憶體亦可持久化的日誌型、Key-Value資料庫,和Memcached類似,它支援儲存的value類型相對更多,包括string(字串)、list(鏈表)、set(集合)、zset(sorted set --有序集合)和hash(雜湊類型)。在此基礎上,redis支援各種不同方式的排序。與memcached一樣,為了保證效率,資料都是緩衝在記憶體中。區別的是redis會周期性的把更新的資料寫入磁碟或者把修改操作寫入追加的記錄檔案,並且在此基礎上實現了master-slave(主從)同步。
Redis的代碼遵循ANSI-C編寫,可以在所有POSIX系統(如Linux, *BSD, Mac OS X, Solaris等)上安裝運行。而且Redis並不依賴任何非標準庫,也沒有編譯參數必需添加。
1)Redis支援兩種持久化方式:
(1):snapshotting(快照)也是預設.(把資料做一個備份,將資料存放區到檔案)
(2)Append-only file(縮寫aof)的方式
快照是預設的持久化方式,這種方式是將記憶體中資料以快照的方式寫到二進位檔案中,預設的檔案名稱為dump.rdb.可以通過配置設定自動做快照持久化的方式。我們可以配置redis在n秒內如果超過m個key鍵修改就自動做快照.
aof方式:由於快照方式是在一定間隔時間做一次的,所以如果Redis意外down掉的話,就會丟失最後一次快照後的所有修改。aof比快照方式有更好的持久化性,是由於在使用aof時,redis會將每一個收到的寫命令都通過write函數追加到檔案中,當redis重啟時會通過重新執行檔案中儲存的寫命令來在記憶體中重建整個資料庫的內容。
2)Redis資料結構
Redis 的作者antirez曾稱其為一個資料結構伺服器(data structures server),這是一個非常準確的表述,Redis的所有功能就是將資料以其固有的幾種結構儲存,並提供給使用者操作這幾種結構的介面。我們可以想象我們在各種語言中的那些固有資料類型及其操作。
Redis目前提供四種資料類型:string,list,set及zset(sorted set)和Hash。
- string是最簡單的類型,你可以理解成與Memcached一模一個的類型,一個key對應一個value,其上支援的操作與Memcached的操作類似。但它的功能更豐富。
- list是一個鏈表結構,主要功能是push、pop、擷取一個範圍的所有值等等。操作中key理解為鏈表的名字。
- set是集合,和我們數學中的集合概念相似,對集合的操作有添加刪除元素,有對多個集合求交並差等操作。操作中key理解為集合的名字。
- zset是set的一個升級版本,他在set的基礎上增加了一個順序屬性,這一屬性在添加修改元素的時候可以指定,每次指定後,zset會自動重新按新的值調整順序。可以理解了有兩列的mysql表,一列存value,一列存順序。操作中key理解為zset的名字。
- Hash資料類型允許使用者用Redis儲存物件類型,Hash資料類型的一個重要優點是,當你儲存的資料對象只有很少幾個key值時,資料存放區的記憶體消耗會很小.更多關於Hash資料類型的說明請見: http://code.google.com/p/redis/wiki/Hashes
3)Redis資料存放區
Redis的儲存分為記憶體儲存、磁碟儲存和log檔案三部分,設定檔中有三個參數對其進行配置。
save seconds updates,save配置,指出在多長時間內,有多少次更新操作,就將資料同步到資料檔案。這個可以多個條件配合,比如預設設定檔中的設定,就設定了三個條件。
appendonly yes/no ,appendonly配置,指出是否在每次更新操作後進行日誌記錄,如果不開啟,可能會在斷電時導致一段時間內的資料丟失。因為redis本身同步資料檔案是按上面的save條件來同步的,所以有的資料會在一段時間內只存在於記憶體中。
appendfsync no/always/everysec ,appendfsync配置,no表示等作業系統進行資料緩衝同步到磁碟,always表示每次更新操作後手動調用fsync()將資料寫到磁碟,everysec表示每秒同步一次。
4)Redis的安裝
Redis可以在不同的平台運行,不過我主要基於Windows進行開發工作,所以下面主要是基於Windows平台進行介紹。
Redis可以安裝以DOS視窗啟動的,也可以安裝為Windows服務的,一般為了方便,我們更願意把它安裝為Windows服務,這樣可以比較方便管理。:https://github.com/MSOpenTech/redis/releases下載,安裝為Windows服務即可。
當前可以下載到最新的Windows安裝版本為3.0,安裝後作為Windows服務運行,安裝後可以在系統的服務裡面看到Redis的服務在運行了,如所示。
安裝好Redis後,還有一個Redis伴侶Redis Desktop Manager需要安裝,這樣可以即時查看Redis緩衝裡面有哪些資料,具體地址如下:http://redisdesktop.com/download
下載屬於自己平台的版本即可
下載安裝後,開啟運行介面,如果我們往裡面添加索引值的資料,那麼可以看到裡面的資料了。
2、Redis的C#使用
Redis目前提供四種資料類型:string,list,set及zset(sorted set)和Hash。因此它在C#裡面也有對應的封裝處理,而且有很多人對他進行了封裝,提供了很多的響應開發包,具體可以訪問http://redis.io/clients#c 進行瞭解。一般建議用ServiceStack.Redis的封裝驅動比較好,具體的使用可以參考https://github.com/ServiceStack/ServiceStack.Redis。
我們開發C#代碼的時候,可以在NuGet程式包上面進行添加對應的ServiceStack.Redis引用,如下所示。
在彈出的NuGet程式包裡面,輸入ServiceStack.Redis進行搜尋,並添加下面的驅動引用即可。
這樣會在項目引用裡面添加了幾個對應的程式集,如下所示。
在C#裡面使用Redis,首先需要執行個體化一個Redis的用戶端類,如下所示。
//建立一個Redis的用戶端類 RedisClient client = new RedisClient("127.0.0.1", 6379);
在使用前,我們需要清空所有的KVStore for Redis,使用FushAll方法即可,如下所示
//Redis FlushAll 命令用於清空整個 Redis 伺服器的資料(刪除所有資料庫的所有 key )。 client.FlushAll();
根據上面的驅動,可以為不同類型的處理編寫一些示範代碼,下面代碼是摘錄網上的案例進行介紹。
#region string類型的測試代碼 client.Add<string>("StringValueTime", "帶有有效期間的字串", DateTime.Now.AddMilliseconds(10000)); while (true) { if (client.ContainsKey("StringValueTime")) { Console.WriteLine("String.鍵:StringValue, 值:{0} {1}", client.Get<string>("StringValueTime"), DateTime.Now); Thread.Sleep(10000); } else { Console.WriteLine("鍵:StringValue, 值:已到期 {0}", DateTime.Now); break; } } client.Add<string>("StringValue", " String和Memcached操作方法差不多"); Console.WriteLine("資料類型為:String.鍵:StringValue, 值:{0}", client.Get<string>("StringValue")); Student stud = new Student() { id = "1001", name = "李四" }; client.Add<Student>("StringEntity", stud); Student Get_stud = client.Get<Student>("StringEntity"); Console.WriteLine("資料類型為:String.鍵:StringEntity, 值:{0} {1}", Get_stud.id, Get_stud.name); #endregion #region Hash類型的測試代碼 client.SetEntryInHash("HashID", "Name", "張三"); client.SetEntryInHash("HashID", "Age", "24"); client.SetEntryInHash("HashID", "Sex", "男"); client.SetEntryInHash("HashID", "Address", "上海市XX號XX室"); List<string> HaskKey = client.GetHashKeys("HashID"); foreach (string key in HaskKey) { Console.WriteLine("HashID--Key:{0}", key); } List<string> HaskValue = client.GetHashValues("HashID"); foreach (string value in HaskValue) { Console.WriteLine("HashID--Value:{0}", value); } List<string> AllKey = client.GetAllKeys(); //擷取所有的key。 foreach (string Key in AllKey) { Console.WriteLine("AllKey--Key:{0}", Key); } #endregion #region List類型的測試代碼 /* * list是一個鏈表結構,主要功能是push,pop,擷取一個範圍的所有的值等,操作中key理解為鏈表名字。 * Redis的list類型其實就是一個每個子項目都是string類型的雙向鏈表。我們可以通過push,pop操作從鏈表的頭部或者尾部添加刪除元素, * 這樣list既可以作為棧,又可以作為隊列。Redis list的實現為一個雙向鏈表,即可以支援反向尋找和遍曆,更方便操作,不過帶來了部分額外的記憶體開銷, * Redis內部的很多實現,包括髮送緩衝隊列等也都是用的這個資料結構 */ client.EnqueueItemOnList("QueueListId", "1.張三"); //入隊 client.EnqueueItemOnList("QueueListId", "2.張四"); client.EnqueueItemOnList("QueueListId", "3.王五"); client.EnqueueItemOnList("QueueListId", "4.王麻子"); long q = client.GetListCount("QueueListId"); Console.WriteLine(client.GetItemFromList("QueueListId", 0)); for (int i = 0; i < q; i++) { Console.WriteLine("QueueListId出隊值:{0}", client.DequeueItemFromList("QueueListId")); //出隊(隊列先進先出) } q = client.GetListCount("QueueListId"); Console.WriteLine(q); client.PushItemToList("StackListId", "1.張三"); //入棧 client.PushItemToList("StackListId", "2.張四"); client.PushItemToList("StackListId", "3.王五"); client.PushItemToList("StackListId", "4.王麻子"); long p = client.GetListCount("StackListId"); for (int i = 0; i < p; i++) { Console.WriteLine("StackListId出棧值:{0}", client.PopItemFromList("StackListId")); //出棧(棧先進後出) } q = client.GetListCount("StackListId"); Console.WriteLine(q); #endregion #region Set無序集合的測試代碼 /* 它是string類型的無序集合。set是通過hash table實現的,添加,刪除和尋找,對集合我們可以取並集,交集,差集 */ client.AddItemToSet("Set1001", "小A"); client.AddItemToSet("Set1001", "小B"); client.AddItemToSet("Set1001", "小C"); client.AddItemToSet("Set1001", "小D"); HashSet<string> hastsetA = client.GetAllItemsFromSet("Set1001"); foreach (string item in hastsetA) { Console.WriteLine("Set無序集合ValueA:{0}", item); //出來的結果是無須的 } client.AddItemToSet("Set1002", "小K"); client.AddItemToSet("Set1002", "小C"); client.AddItemToSet("Set1002", "小A"); client.AddItemToSet("Set1002", "小J"); HashSet<string> hastsetB = client.GetAllItemsFromSet("Set1002"); foreach (string item in hastsetB) { Console.WriteLine("Set無序集合ValueB:{0}", item); //出來的結果是無須的 } HashSet<string> hashUnion = client.GetUnionFromSets(new string[] { "Set1001", "Set1002" }); foreach (string item in hashUnion) { Console.WriteLine("求Set1001和Set1002的並集:{0}", item); //並集 } HashSet<string> hashG = client.GetIntersectFromSets(new string[] { "Set1001", "Set1002" }); foreach (string item in hashG) { Console.WriteLine("求Set1001和Set1002的交集:{0}", item); //交集 } HashSet<string> hashD = client.GetDifferencesFromSet("Set1001", new string[] { "Set1002" }); //[返回存在於第一個集合,但是不存在於其他集合的資料。差集] foreach (string item in hashD) { Console.WriteLine("求Set1001和Set1002的差集:{0}", item); //差集 } #endregion #region SetSorted 有序集合的測試代碼 /* sorted set 是set的一個升級版本,它在set的基礎上增加了一個順序的屬性,這一屬性在添加修改.元素的時候可以指定, * 每次指定後,zset(表示有序集合)會自動重新按新的值調整順序。可以理解為有列的表,一列存 value,一列存順序。操作中key理解為zset的名字. */ client.AddItemToSortedSet("SetSorted1001", "1.劉仔"); client.AddItemToSortedSet("SetSorted1001", "2.星仔"); client.AddItemToSortedSet("SetSorted1001", "3.豬仔"); List<string> listSetSorted = client.GetAllItemsFromSortedSet("SetSorted1001"); foreach (string item in listSetSorted) { Console.WriteLine("SetSorted有序集合{0}", item); } #endregion
對於具體類型的類對象,也可以使用As方法進行轉換為對應的處理對象進行處理,如下所示
IRedisTypedClient<Phone> phones = client.As<Phone>();
具體的測試代碼如下所示。
/// <summary> /// Redis對對象類的處理例子 /// </summary> private void btnTypeValue_Click(object sender, EventArgs e) { IRedisTypedClient<Phone> phones = client.As<Phone>(); Phone phoneFive = phones.GetValue("5"); if (phoneFive == null) { Thread.Sleep(50); phoneFive = new Phone { Id = 5, Manufacturer = "Apple", Model = "xxxxx", Owner = new Person { Id = 1, Age = 100, Name = "伍華聰", Profession = "電腦", Surname = "wuhuacong" } }; phones.SetEntry(phoneFive.Id.ToString(), phoneFive); } client.Store<Phone>( new Phone { Id = 2, Manufacturer = "LG", Model = "test-xxx", Owner = new Person { Id = 2, Age = 40, Name = "test", Profession = "teacher", Surname = "wuhuacong" } }); var message = "Phone model is " + phoneFive.Manufacturer + ","; message += "Phone Owner Name is: " + phoneFive.Owner.Name; Console.WriteLine(message); }
以上就是關於Redis的安裝以及簡單的例子使用說明,在具體中,我們可以利用Redis的高效能特性,來構建我們的快取資料,並且可以利用Redis和MongoDB資料庫的完美銜接,可以整合一起做的更好,為相關的後台提供更高效的資料處理操作,畢竟在互連網的大環境下,效能是非常重要的。
Redis的安裝及使用