http://www.80iter.com/blog/1450851394326950
Redis在.net中的使用(3)简单的主从复制
在前面的两篇简单的实现了redis的安装和简单项目中的运用
Redis在.net中的使用学习(1)下载安装Redis Redis在.net中的使用学习(2).net项目中的Redis使用
在这里我们简单说说Redis的主从复制实现,Redis跟MySQL一样拥有强大的主从复制功能,还支持一个master可以拥有多个slave,而一个slave又可以拥有多个slave,从而形成强大的多级服务器集群架构,如下图:
Redis的主从复制功能是异步进行的,不会影响master的运行,也不会降低Redis的处理性能。Redis的主从架构中,可以考虑关闭Master的数据持久化功能,而只让Slave进行必要的持久化,这样就能提高主服务器的处理能力和性能,同时Slave设置为只读模式,这样可以避免Slave缓存的数据被误修改等。
1、配置安装两个Redis实例
处于测试考虑,我只在本机安装两个Redis实例来进行演示而已。复制一份redis文件件,修改conf文件的端口为6380,并启动,如下图:
注意:在同一台电脑上测试,Master和Slave的端口不要一样,否则是不能同时启动两个实例的。
这样,本机就启动了两个Redis实例服务了。
2、主从Redis服务绑定
在Slave 实例,增加:slaveof 127.0.0.1 6379,如下图:
配置完成之后,重新启动这两个实例,如果输出如下内容,说明主从复制的架构已经配置成功了,如下图:
这样,Redis的主从复制就设置完成了。
3、主从复制测试
连接上Master服务器和Slave 服务器,然后在Master写入一条测试缓存,然后在Slave中读取这条测试缓存,如下图:
4、C#中的调用测试
主从架构的Redis的读写其实和单一Redis实例的读写差不多,只是部分配置和读取区分了主从,如果不清楚C#中如何使用Redis,请移步:Redis在.net中的使用学习(2).net项目中的Redis使用
不过我们需要注意的是:ServiceStack.Redis中GetClient()的这个方法,默认只能拿到Master Redis中获取连接,而拿不到Slave的readonly连接。这样Slave起到了冗余备份的作用,读的功能没有发挥出来,如果并发请求太多的话,则Redis的性能会有影响。
因此,我们需要的写入和读取的时候做一个区分,写入的时候,调用client.GetClient()来获取writeHosts的Master的Redis链接。读取的时候则调用client.GetReadOnlyClient()来获取的readonlyHost的Slave的Redis链接,或者可以直接使用client.GetCacheClient()来获取一个连接,他会在写的时候调用GetClient获取连接,读的时候调用GetReadOnlyClient获取连接,这样可以做到读写分离,从而利用Redis的主从复制功能。
a、修改配置文件
1
2
3
4
5
6
7
<!-- redis Start -->
<add key=``"SessionExpireMinutes"
value=``"180"
/>
<add key=``"redis_server_master_session"
value=``"127.0.0.1:6379"
/>
<add key=``"redis_server_slave_session"
value=``"127.0.0.1:6380"
/>
<add key=``"redis_max_read_pool"
value=``"300"
/>
<add key=``"redis_max_write_pool"
value=``"100"
/>
<!--redis end-->
b、Redis操作公用类RedisCacheHelper的优化修改
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
public
class
RedisCacheHelper
{
private
static
readonly
PooledRedisClientManager pool =
null``;
private
static
readonly
string``[] writeHosts =
null``;
private
static
readonly
string``[] readHosts =
null``;
public
static
int
RedisMaxReadPool =
int``.Parse(ConfigurationManager.AppSettings[``"redis_max_read_pool"``]);
public
static
int
RedisMaxWritePool =
int``.Parse(ConfigurationManager.AppSettings[``"redis_max_write_pool"``]);
static
RedisCacheHelper()
{
var redisMasterHost = ConfigurationManager.AppSettings[``"redis_server_master_session"``];
var redisSlaveHost = ConfigurationManager.AppSettings[``"redis_server_slave_session"``];
if
(!``string``.IsNullOrEmpty(redisMasterHost))
{
writeHosts = redisMasterHost.Split(``','``);
readHosts = redisSlaveHost.Split(``','``);
if
(readHosts.Length > 0)
{
pool =
new
PooledRedisClientManager(writeHosts, readHosts,
new
RedisClientManagerConfig()
{
MaxWritePoolSize = RedisMaxWritePool,
MaxReadPoolSize = RedisMaxReadPool,
AutoStart =
true
});
}
}
}
public
static
void
Add<T>(``string
key, T value, DateTime expiry)
{
if
(value ==
null``)
{
return``;
}
if
(expiry <= DateTime.Now)
{
Remove(key);
return``;
}
try
{
if
(pool !=
null``)
{
using
(var r = pool.GetClient())
{
if
(r !=
null``)
{
r.SendTimeout = 1000;
r.Set(key, value, expiry - DateTime.Now);
}
}
}
}
catch
(Exception ex)
{
string
msg =
string``.Format(``"{0}:{1}发生异常!{2}"``,
"cache"``,
"存储"``, key);
}
}
public
static
void
Add<T>(``string
key, T value, TimeSpan slidingExpiration)
{
if
(value ==
null``)
{
return``;
}
if
(slidingExpiration.TotalSeconds <= 0)
{
Remove(key);
return``;
}
try
{
if
(pool !=
null``)
{
using
(var r = pool.GetClient())
{
if
(r !=
null``)
{
r.SendTimeout = 1000;
r.Set(key, value, slidingExpiration);
}
}
}
}
catch
(Exception ex)
{
string
msg =
string``.Format(``"{0}:{1}发生异常!{2}"``,
"cache"``,
"存储"``, key);
}
}
public
static
T Get<T>(``string
key)
{
if
(``string``.IsNullOrEmpty(key))
{
return
default``(T);
}
T obj =
default``(T);
try
{
if
(pool !=
null``)
{
using
(var r = pool.GetClient())
{
if
(r !=
null``)
{
r.SendTimeout = 1000;
obj = r.Get<T>(key);
}
}
}
}
catch
(Exception ex)
{
string
msg =
string``.Format(``"{0}:{1}发生异常!{2}"``,
"cache"``,
"获取"``, key);
}
return
obj;
}
public
static
void
Remove(``string
key)
{
try
{
if
(pool !=
null``)
{
using
(var r = pool.GetClient())
{
if
(r !=
null``)
{
r.SendTimeout = 1000;
r.Remove(key);
}
}
}
}
catch
(Exception ex)
{
string
msg =
string``.Format(``"{0}:{1}发生异常!{2}"``,
"cache"``,
"删除"``, key);
}
}
public
static
bool
Exists(``string
key)
{
try
{
if
(pool !=
null``)
{
using
(var r = pool.GetClient())
{
if
(r !=
null``)
{
r.SendTimeout = 1000;
return
r.ContainsKey(key);
}
}
}
}
catch
(Exception ex)
{
string
msg =
string``.Format(``"{0}:{1}发生异常!{2}"``,
"cache"``,
"是否存在"``, key);
}
return
false``;
}
public
static
IDictionary<``string``, T> GetAll<T>(IEnumerable<``string``> keys) where T :
class
{
if
(keys ==
null``)
{
return
null``;
}
keys = keys.Where(k => !``string``.IsNullOrWhiteSpace(k));
if
(keys.Count() == 1)
{
T obj = Get<T>(keys.Single());
if
(obj !=
null``)
{
return
new
Dictionary<``string``, T>() { { keys.Single(), obj } };
}
return
null``;
}
if
(!keys.Any())
{
return
null``;
}
IDictionary<``string``, T> dict =
null``;
if
(pool !=
null``)
{
keys.Select(s =>
new
{
Index = Math.Abs(s.GetHashCode()) % readHosts.Length,
KeyName = s
})
.GroupBy(p => p.Index)
.Select(g =>
{
try
{
using
(var r = pool.GetClient(g.Key))
{
if
(r !=
null``)
{
r.SendTimeout = 1000;
return
r.GetAll<T>(g.Select(p => p.KeyName));
}
}
}
catch
(Exception ex)
{
string
msg =
string``.Format(``"{0}:{1}发生异常!{2}"``,
"cache"``,
"获取"``, keys.Aggregate((a, b) => a +
","
+ b));
}
return
null``;
})
.Where(x => x !=
null``)
.ForEach(d =>
{
d.ForEach(x =>
{
if
(dict ==
null
|| !dict.Keys.Contains(x.Key))
{
if
(dict ==
null``)
{
dict =
new
Dictionary<``string``, T>();
}
dict.Add(x);
}
});
});
}
IEnumerable<Tuple<``string``, T>> result =
null``;
if
(dict !=
null``)
{
result = dict.Select(d =>
new
Tuple<``string``, T>(d.Key, d.Value));
}
else
{
result = keys.Select(key =>
new
Tuple<``string``, T>(key, Get<T>(key)));
}
return
result
.Select(d =>
new
Tuple<``string``[], T>(d.Item1.Split(``'_'``), d.Item2))
.Where(d => d.Item1.Length >= 2)
.ToDictionary(x => x.Item1[1], x => x.Item2);
}
}
至此,基本的Redis主从复制就简单实现了
手机扫一扫
移动阅读更方便
你可能感兴趣的文章