分佈式中使用 Redis 實現 Session 共享(上)

上一篇介紹瞭如何使用nginx+iis部署一個簡單的分佈式系統,文章結尾留下了幾個問題,其中一個是”如何解決多站點下Session共享”。這篇文章將會介紹如何使用Redis,下一篇在此基礎上實現Session。

這裏特別說明一下,其實沒有必要使用Redis來解決Session共享。Asp.net提供了StateServer模式來共享Session,這裏重複造輪子的目的1:熟悉Redis的基本知識和使用 2.學習和鞏固Session的實現原理。

 

Redis安裝配置

redis是一個key-value存儲系統。和Memcached類似,它支持存儲的value類型相對更多,包括string(字符串)、list(鏈表)、set(集合)、zset(sorted set –有序集合)和hash(哈希類型)。這些數據類型都支持push/pop、add/remove及取交集並集和差集及更豐富的操作,而且這些操作都是原子性的。在此基礎上,redis支持各種不同方式的排序。與memcached一樣,爲了保證效率,數據都是緩存在內存中。區別的是redis會週期性的把更新的數據寫入磁盤或者把修改操作寫入追加的記錄文件,並且在此基礎上實現了master-slave(主從)同步。

最新版本的redis版本爲3.0.3,支持集羣功能。我這下載的是window版本的,實際場景都是安裝在linux系統下的。下載地址:redis-2.8.19.rar 。更多下載地址:

官網 :http://redis.io/download MSOpenTech:https://github.com/MSOpenTech/redis  dmajkic:https://github.com/dmajkic/redis/downloads
下載完成之後解壓運行redis-server.exe就啓動了redis了,啓動後會在進程裏面看到reids。

1.讀寫分離配置

redis的讀寫分離需要修改配置文件,把解壓的文件複製了一份。兩份文件是一樣的,分別命名爲MasterRedis-2.8.19(主redis服務),SlaveRedis-2.8.19(從redis服務)。redis默認綁定的是6379端口,

我們保持主服務配置不變,修改從服務配置。

  • 修改從服務綁定端口(修改時可以直接搜索port關鍵字)

  • 修改從服務對應的主服務地址(修改時可以直接搜索slaveof關鍵字)

  • 配置文件修改完成以後,分別啓動主服務和從服務

從服務啓動以後,主服務會發送一條同步的sync命令,同步從服務器的緩存數據。
五種數據類型使用

服務搭建好以後可以使用.net版本redis操作類庫ServiceStack.Redis來操作redis,本文會用到以下三個dll。

初始化RedisClient對象

1
var client = new RedisClient("120.26.197.185", 6379);

1.String

String是最常用的一種數據類型,普通的key/value存儲都可以歸爲此類,value其實不僅是String,也可以是數字:比如想知道什麼時候封鎖一個IP地址(訪問超過幾次)。INCRBY命令讓這些變得很容易,通過原子遞增保持計數。

1
2
3
4
5
6
7
8
9
10
#region "字符串類型"
client.Set<string>("name", "laowang");
string userName = client.Get<string>("name");
Console.WriteLine(userName);
//訪問次數
client.Set<int>("IpAccessCount", 0);
//次數遞增
client.Incr("IpAccessCount");
Console.WriteLine(client.Get<int>("IpAccessCount"));
#endregion


2.Hash

一個hashid可以存儲多項信息,每一項信息也有自己的key

1
2
3
4
5
6
client.SetEntryInHash("userInfoId", "name", "zhangsan");
client.SetEntryInHash("userInfoId", "name1", "zhangsan1");
client.SetEntryInHash("userInfoId", "name2", "zhangsan2");
client.SetEntryInHash("userInfoId", "name3", "zhangsan3");
client.GetHashKeys("userInfoId").ForEach(e => Console.WriteLine(e));
client.GetHashValues("userInfoId").ForEach(e => Console.WriteLine(e));


3.List

應用場景:

  • Redis list的應用場景非常多,也是Redis最重要的數據結構之一。
  • 我們可以輕鬆地實現最新消息排行等功能。
  • Lists的另一個應用就是消息隊列,可以利用Lists的PUSH操作,將任務存在Lists中,然後工作線程再用POP操作將任務取出進行執行。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#region "List類型"
 
client.AddItemToList("userInfoId1", "123");
client.AddItemToList("userInfoId1", "1234");
 
Console.WriteLine("List數據項條數:" + client.GetListCount("userInfoId1"));
Console.WriteLine("List數據項第一條數據:" + client.GetItemFromList("userInfoId1", 0));
Console.WriteLine("List所有數據");
client.GetAllItemsFromList("userInfoId1").ForEach(e => Console.WriteLine(e));
#endregion
 
#region "List類型做爲隊列和棧使用"
Console.WriteLine(client.GetListCount("userInfoId1"));
//隊列先進先出
//Console.WriteLine(client.DequeueItemFromList("userInfoId1"));
//Console.WriteLine(client.DequeueItemFromList("userInfoId1"));
 
//棧後進先出
Console.WriteLine("出棧"+client.PopItemFromList("userInfoId1"));
Console.WriteLine("出棧"+client.PopItemFromList("userInfoId1"));
#endregion


4.Set

應用場景:

  • Redis set對外提供的功能與list類似是一個列表的功能,特殊之處在於set是可以自動排重的,當你需要存儲一個列表數據,又不希望出現重複數據時,set是一個很好的選擇,並且set提供了判斷某個成員是否在一個set集合內的重要接口,這個也是list所不能提供的。
  • 比如在微博應用中,每個人的好友存在一個集合(set)中,這樣求兩個人的共同好友的操作,可能就只需要用求交集命令即可。
  • Redis還爲集合提供了求交集、並集、差集等操作,可以非常方便的實
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
client.AddItemToSet("A", "B");
client.AddItemToSet("A", "C");
client.AddItemToSet("A", "D");
client.AddItemToSet("A", "E");
client.AddItemToSet("A", "F");
 
client.AddItemToSet("B", "C");
client.AddItemToSet("B", "F");
 
//求差集
Console.WriteLine("A,B集合差集");
client.GetDifferencesFromSet("A", "B").ToList<string>().ForEach(e => Console.Write(e + ","));
 
//求集合交集
Console.WriteLine("\nA,B集合交集");
client.GetIntersectFromSets(new string[] { "A", "B" }).ToList<string>().ForEach(e => Console.Write(e + ","));
 
//求集合並集
Console.WriteLine("\nA,B集合並集");
client.GetUnionFromSets(new string[] { "A", "B" }).ToList<string>().ForEach(e => Console.Write(e + ","));

5.Sort Set(排序)

應用場景:

  • 以某個條件爲權重,比如按頂的次數排序.
  • ZREVRANGE命令可以用來按照得分來獲取前100名的用戶,ZRANK可以用來獲取用戶排名,非常直接而且操作容易。
  • Redis sorted set的使用場景與set類似,區別是set不是自動有序的,而sorted set可以通過用戶額外提供一個優先級(score)的參數來爲成員排序,並且是插入有序的,即自動排序。
  • 比如:twitter 的public timeline可以以發表時間作爲score來存儲,這樣獲取時就是自動按時間排好序的。
  • 比如:全班同學成績的SortedSets,value可以是同學的學號,而score就可以是其考試得分,這樣數據插入集合的,就已經進行了天然的排序。
  • 另外還可以用Sorted Sets來做帶權重的隊列,比如普通消息的score爲1,重要消息的score爲2,然後工作線程可以選擇按score的倒序來獲取工作任務。讓重要的任務優先執行。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#region "有序Set操作"
client.AddItemToSortedSet("SA", "B", 2);
client.AddItemToSortedSet("SA", "C", 1);
client.AddItemToSortedSet("SA", "D", 5);
client.AddItemToSortedSet("SA", "E", 3);
client.AddItemToSortedSet("SA", "F", 4);
 
//有序集合降序排列
Console.WriteLine("\n有序集合降序排列");
client.GetAllItemsFromSortedSetDesc("SA").ForEach(e => Console.Write(e + ","));
Console.WriteLine("\n有序集合升序序排列");
client.GetAllItemsFromSortedSet("SA").ForEach(e => Console.Write(e + ","));
 
client.AddItemToSortedSet("SB", "C", 2);
client.AddItemToSortedSet("SB", "F", 1);
client.AddItemToSortedSet("SB", "D", 3);
 
Console.WriteLine("\n獲得某個值在有序集合中的排名,按分數的升序排列");
Console.WriteLine(client.GetItemIndexInSortedSet("SB", "D"));
 
Console.WriteLine("\n獲得有序集合中某個值得分數");
Console.WriteLine(client.GetItemScoreInSortedSet("SB", "D"));
 
Console.WriteLine("\n獲得有序集合中,某個排名範圍的所有值");
client.GetRangeFromSortedSet("SA", 0, 3).ForEach(e => Console.Write(e + ","));
 
#endregion

 

封裝拓展

最後提供一份別人寫好的Redis操作的幫助類,用到了PooledRedisClientManager連接池來獲取RedisClient,同時用到了讀寫分離的概念,可以直接拿來使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ServiceStack.Redis;
 
namespace Com.Redis
{
    /// <summary>
    /// 來源:http://blog.wx6.org/2013/349.htm
    /// </summary>
    public class RedisBase
    {
        private static string[] ReadWriteHosts = System.Configuration.ConfigurationSettings.AppSettings["readWriteHosts"].Split(new char[] { ';' });
        private static string[] ReadOnlyHosts = System.Configuration.ConfigurationSettings.AppSettings["readOnlyHosts"].Split(new char[] { ';' });
 
        #region -- 連接信息 --
        public static PooledRedisClientManager prcm = CreateManager(ReadWriteHosts, ReadOnlyHosts);
 
        private static PooledRedisClientManager CreateManager(string[] readWriteHosts, string[] readOnlyHosts)
        {
            // 支持讀寫分離,均衡負載 
            return new PooledRedisClientManager(readWriteHosts, readOnlyHosts, new RedisClientManagerConfig
            {
                MaxWritePoolSize = 5, // “寫”鏈接池鏈接數 
                MaxReadPoolSize = 5, // “讀”鏈接池鏈接數 
                AutoStart = true,
            });
        }
        #endregion
 
        #region -- Item --
        /// <summary>
        /// 設置單體
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <param name="t"></param>
        /// <param name="timeSpan"></param>
        /// <returns></returns>
        public static bool Item_Set<T>(string key, T t)
        {
            try
            {
                using (IRedisClient redis = prcm.GetClient())
                {
                    return redis.Set<T>(key, t, new TimeSpan(1, 0, 0));
                }
            }
            catch (Exception ex)
            {
                // LogInfo
            }
            return false;
        }
 
        /// <summary>
        /// 獲取單體
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <returns></returns>
        public static T Item_Get<T>(string key) where T : class
        {
            using (IRedisClient redis = prcm.GetClient())
            {
                return redis.Get<T>(key);
            }
        }
 
        /// <summary>
        /// 移除單體
        /// </summary>
        /// <param name="key"></param>
        public static bool Item_Remove(string key)
        {
            using (IRedisClient redis = prcm.GetClient())
            {
                return redis.Remove(key);
            }
        }
 
        #endregion
 
        #region -- List --
 
        public static void List_Add<T>(string key, T t)
        {
            using (IRedisClient redis = prcm.GetClient())
            {
                var redisTypedClient = redis.GetTypedClient<T>();
                redisTypedClient.AddItemToList(redisTypedClient.Lists[key], t);
            }
        }
 
        public static bool List_Remove<T>(string key, T t)
        {
            using (IRedisClient redis = prcm.GetClient())
            {
                var redisTypedClient = redis.GetTypedClient<T>();
                return redisTypedClient.RemoveItemFromList(redisTypedClient.Lists[key], t) > 0;
            }
        }
        public static void List_RemoveAll<T>(string key)
        {
            using (IRedisClient redis = prcm.GetClient())
            {
                var redisTypedClient = redis.GetTypedClient<T>();
                redisTypedClient.Lists[key].RemoveAll();
            }
        }
 
        public static int List_Count(string key)
        {
            using (IRedisClient redis = prcm.GetReadOnlyClient())
            {
                return redis.GetListCount(key);
            }
        }
 
        public static List<T> List_GetRange<T>(string key, int start, int count)
        {
            using (IRedisClient redis = prcm.GetReadOnlyClient())
            {
                var c = redis.GetTypedClient<T>();
                return c.Lists[key].GetRange(start, start + count - 1);
            }
        }
 
        public static List<T> List_GetList<T>(string key)
        {
            using (IRedisClient redis = prcm.GetReadOnlyClient())
            {
                var c = redis.GetTypedClient<T>();
                return c.Lists[key].GetRange(0, c.Lists[key].Count);
            }
        }
 
        public static List<T> List_GetList<T>(string key, int pageIndex, int pageSize)
        {
            int start = pageSize * (pageIndex - 1);
            return List_GetRange<T>(key, start, pageSize);
        }
 
        /// <summary>
        /// 設置緩存過期
        /// </summary>
        /// <param name="key"></param>
        /// <param name="datetime"></param>
        public static void List_SetExpire(string key, DateTime datetime)
        {
            using (IRedisClient redis = prcm.GetClient())
            {
                redis.ExpireEntryAt(key, datetime);
            }
        }
        #endregion
 
        #region -- Set --
        public static void Set_Add<T>(string key, T t)
        {
            using (IRedisClient redis = prcm.GetClient())
            {
                var redisTypedClient = redis.GetTypedClient<T>();
                redisTypedClient.Sets[key].Add(t);
            }
        }
        public static bool Set_Contains<T>(string key, T t)
        {
            using (IRedisClient redis = prcm.GetClient())
            {
                var redisTypedClient = redis.GetTypedClient<T>();
                return redisTypedClient.Sets[key].Contains(t);
            }
        }
        public static bool Set_Remove<T>(string key, T t)
        {
            using (IRedisClient redis = prcm.GetClient())
            {
                var redisTypedClient = redis.GetTypedClient<T>();
                return redisTypedClient.Sets[key].Remove(t);
            }
        }
        #endregion
 
        #region -- Hash --
        /// <summary>
        /// 判斷某個數據是否已經被緩存
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <param name="dataKey"></param>
        /// <returns></returns>
        public static bool Hash_Exist<T>(string key, string dataKey)
        {
            using (IRedisClient redis = prcm.GetReadOnlyClient())
            {
                return redis.HashContainsEntry(key, dataKey);
            }
        }
 
        /// <summary>
        /// 存儲數據到hash表
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <param name="dataKey"></param>
        /// <returns></returns>
        public static bool Hash_Set<T>(string key, string dataKey, T t)
        {
            using (IRedisClient redis = prcm.GetClient())
            {
                string value = ServiceStack.Text.JsonSerializer.SerializeToString<T>(t);
                return redis.SetEntryInHash(key, dataKey, value);
            }
        }
        /// <summary>
        /// 移除hash中的某值
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <param name="dataKey"></param>
        /// <returns></returns>
        public static bool Hash_Remove(string key, string dataKey)
        {
            using (IRedisClient redis = prcm.GetClient())
            {
                return redis.RemoveEntryFromHash(key, dataKey);
            }
        }
        /// <summary>
        /// 移除整個hash
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <param name="dataKey"></param>
        /// <returns></returns>
        public static bool Hash_Remove(string key)
        {
            using (IRedisClient redis = prcm.GetClient())
            {
                return redis.Remove(key);
            }
        }
        /// <summary>
        /// 從hash表獲取數據
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <param name="dataKey"></param>
        /// <returns></returns>
        public static T Hash_Get<T>(string key, string dataKey)
        {
            using (IRedisClient redis = prcm.GetReadOnlyClient())
            {
                string value = redis.GetValueFromHash(key, dataKey);
                return ServiceStack.Text.JsonSerializer.DeserializeFromString<T>(value);
            }
        }
        /// <summary>
        /// 獲取整個hash的數據
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <returns></returns>
        public static List<T> Hash_GetAll<T>(string key)
        {
            using (IRedisClient redis = prcm.GetReadOnlyClient())
            {
                var list = redis.GetHashValues(key);
                if (list != null && list.Count > 0)
                {
                    List<T> result = new List<T>();
                    foreach (var item in list)
                    {
                        var value = ServiceStack.Text.JsonSerializer.DeserializeFromString<T>(item);
                        result.Add(value);
                    }
                    return result;
                }
                return null;
            }
        }
        /// <summary>
        /// 設置緩存過期
        /// </summary>
        /// <param name="key"></param>
        /// <param name="datetime"></param>
        public static void Hash_SetExpire(string key, DateTime datetime)
        {
            using (IRedisClient redis = prcm.GetClient())
            {
                redis.ExpireEntryAt(key, datetime);
            }
        }
        #endregion
 
        #region -- SortedSet --
        /// <summary>
        ///  添加數據到 SortedSet
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <param name="t"></param>
        /// <param name="score"></param>
        public static bool SortedSet_Add<T>(string key, T t, double score)
        {
            using (IRedisClient redis = prcm.GetClient())
            {
                string value = ServiceStack.Text.JsonSerializer.SerializeToString<T>(t);
                return redis.AddItemToSortedSet(key, value, score);
            }
        }
        /// <summary>
        /// 移除數據從SortedSet
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <param name="t"></param>
        /// <returns></returns>
        public static bool SortedSet_Remove<T>(string key, T t)
        {
            using (IRedisClient redis = prcm.GetClient())
            {
                string value = ServiceStack.Text.JsonSerializer.SerializeToString<T>(t);
                return redis.RemoveItemFromSortedSet(key, value);
            }
        }
        /// <summary>
        /// 修剪SortedSet
        /// </summary>
        /// <param name="key"></param>
        /// <param name="size">保留的條數</param>
        /// <returns></returns>
        public static int SortedSet_Trim(string key, int size)
        {
            using (IRedisClient redis = prcm.GetClient())
            {
                return redis.RemoveRangeFromSortedSet(key, size, 9999999);
            }
        }
        /// <summary>
        /// 獲取SortedSet的長度
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public static int SortedSet_Count(string key)
        {
            using (IRedisClient redis = prcm.GetReadOnlyClient())
            {
                return redis.GetSortedSetCount(key);
            }
        }
 
        /// <summary>
        /// 獲取SortedSet的分頁數據
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <param name="pageIndex"></param>
        /// <param name="pageSize"></param>
        /// <returns></returns>
        public static List<T> SortedSet_GetList<T>(string key, int pageIndex, int pageSize)
        {
            using (IRedisClient redis = prcm.GetReadOnlyClient())
            {
                var list = redis.GetRangeFromSortedSet(key, (pageIndex - 1) * pageSize, pageIndex * pageSize - 1);
                if (list != null && list.Count > 0)
                {
                    List<T> result = new List<T>();
                    foreach (var item in list)
                    {
                        var data = ServiceStack.Text.JsonSerializer.DeserializeFromString<T>(item);
                        result.Add(data);
                    }
                    return result;
                }
            }
            return null;
        }
 
        /// <summary>
        /// 獲取SortedSet的全部數據
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <param name="pageIndex"></param>
        /// <param name="pageSize"></param>
        /// <returns></returns>
        public static List<T> SortedSet_GetListALL<T>(string key)
        {
            using (IRedisClient redis = prcm.GetReadOnlyClient())
            {
                var list = redis.GetRangeFromSortedSet(key, 0, 9999999);
                if (list != null && list.Count > 0)
                {
                    List<T> result = new List<T>();
                    foreach (var item in list)
                    {
                        var data = ServiceStack.Text.JsonSerializer.DeserializeFromString<T>(item);
                        result.Add(data);
                    }
                    return result;
                }
            }
            return null;
        }
 
        /// <summary>
        /// 設置緩存過期
        /// </summary>
        /// <param name="key"></param>
        /// <param name="datetime"></param>
        public static void SortedSet_SetExpire(string key, DateTime datetime)
        {
            using (IRedisClient redis = prcm.GetClient())
            {
                redis.ExpireEntryAt(key, datetime);
            }
        }
        #endregion
    }
}

使用很簡單,幾行代碼

1
2
3
4
5
//會往主服務裏面寫入
RedisBase.Hash_Set<string>("PooledRedisClientManager", "one", "123");
 
//從服務裏面讀取信息
RedisBase.Hash_Get<string>("PooledRedisClientManager", "one");

連接池的初始化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
private static string[] ReadWriteHosts = System.Configuration.ConfigurationSettings.AppSettings["readWriteHosts"].Split(new char[] { ';' });
private static string[] ReadOnlyHosts = System.Configuration.ConfigurationSettings.AppSettings["readOnlyHosts"].Split(new char[] { ';' });
 
#region -- 連接信息 --
public static PooledRedisClientManager prcm = CreateManager(ReadWriteHosts, ReadOnlyHosts);
 
private static PooledRedisClientManager CreateManager(string[] readWriteHosts, string[] readOnlyHosts)
{
    // 支持讀寫分離,均衡負載 
    return new PooledRedisClientManager(readWriteHosts, readOnlyHosts, new RedisClientManagerConfig
    {
        MaxWritePoolSize = 5, // “寫”鏈接池鏈接數 
        MaxReadPoolSize = 5, // “讀”鏈接池鏈接數 
        AutoStart = true,
    });
}

配置文件

總結

1.其實php,java等多種語言都能使用redis,在我接觸的項目中見到使用redis做爲消息隊列和緩存組件,當然它的功能遠不止於此。後面的文章將詳細介紹redis的幾個使用案例。

2.可以使用redis desktop manager管理工具查看服務器緩存中的數據

 1 贊  3 收藏  評論

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章