redis的安装、启动、主从配置,以及.Net下StackE…
2018-06-17 19:55:02来源:未知 阅读 ()
开门见山,Linux下配个环境真是苦逼死了,这里记录一下,囧
一、环境
服务端:Ubuntu16.04 LTS(虚拟机,redis官方没有window发布版本,而且在Linux下运行更稳定)
客户端:win10、vs2015、.net4.0+
二、安装
sudo su
输入root密码
sudo apt-get install redis-server
一路Enter下去,直到完成,默认安装完成后,提几个被坑过的文件:
1、启动配置文件:/etc/redis/redis.conf,每一个配置的含义参考:http://www.cnblogs.com/kreo/p/4423362.html
2、rdb文件:/var/lib/redis/dump.rdb,搜索在redis.conf的dir可以看到
3、pidfile文件:/var/run/redis/redis-server.pid(配置slave时需要修改)
4、日志文件:/var/log/redis/redis-server.log(配置slave时需要修改)
5、修改个配置,注释bind 127.0.0.1,这样在本机可以使用虚拟机ip来访问,否则只能内网访问
注意:修改redis.conf之前,需要先更改权限,执行命令:
chmod 777 redis.conf
三、启动
默认安装好后可以直接使用redis命令,先启动服务端:
redis-server /etc/redis/redis.conf
注:带conf文件启动的目的,是为了后面区分启动从库实例
查看服务是否启动成功:
ps -ef |grep redis
启动客户端:
redis-cli -p 6379
随意测试下
四、设置master-salve
因为是Ubuntu系统,直接双击计算机进入到安装目录:/etc/redis/,可以看到步骤二中的启动主配置文件,redis.conf
右键->在终端打开,执行拷贝文件命令:
sudo cp redis.conf redis-slave.conf
同样,需要修改这个文件的权限:
chmod 777 redis-slave.conf
使用编辑器(vim、vscode等)打开redis-slave.conf,修改几个配置(列出来的是已经修改后的):
1、port 6380
2、pidfile:/var/run/redis/redis-server-6380.pid
3、logfile /var/log/redis/redis-server-slave.log
4、slaveof 127.0.0.1 6379
完成后,启动从库实例:
redis-server /etc/redis/redis-slave.conf
再次查看服务:ps -ef |grep redis
已经有两个redis服务端进程了,说明主从都已经启动了
五、客户端
1、启动主库客户端,重新打开一个终端窗口,执行:
redis-cli -p 6379
随意执行两个最简单的设置、获取命令:
根据主从同步的机制,此时slave从库中应该可以get到这个name,重开一个终端窗口,执行:
redis-cli -p 6380
get一下,没毛病,耶!
六、.Net操作redis
讲代码的园子里有很多,就不多在提了。这里给一个类以供大家学习使用,也是从github上搜刮下来的,地址我真忘记了,对不住作者了(如果有看到请留言,我会附上GitHub地址)
是基于StackExchange.Redis封装的
1 public static class StackExchangeRedisHelper
2 {
3 private static string Constr = "";
4
5 private static object _locker = new Object();
6 private static ConnectionMultiplexer _instance = null;
7
8 /// <summary>
9 /// 使用一个静态属性来返回已连接的实例,如下列中所示。这样,一旦 ConnectionMultiplexer 断开连接,便可以初始化新的连接实例。
10 /// </summary>
11 public static ConnectionMultiplexer Instance
12 {
13 get
14 {
15 if(Constr.Length == 0)
16 {
17 throw new Exception("连接字符串为设置!");
18 }
19 if (_instance == null)
20 {
21 lock (_locker)
22 {
23 if (_instance == null || !_instance.IsConnected)
24 {
25 _instance = ConnectionMultiplexer.Connect(Constr);
26 }
27 }
28 }
29 //注册如下事件
30 _instance.ConnectionFailed += MuxerConnectionFailed;
31 _instance.ConnectionRestored += MuxerConnectionRestored;
32 _instance.ErrorMessage += MuxerErrorMessage;
33 _instance.ConfigurationChanged += MuxerConfigurationChanged;
34 _instance.HashSlotMoved += MuxerHashSlotMoved;
35 _instance.InternalError += MuxerInternalError;
36 return _instance;
37 }
38 }
39
40 static StackExchangeRedisHelper()
41 {
42 }
43
44 public static void SetCon(string config)
45 {
46 Constr = config;
47 }
48
49 /// <summary>
50 ///
51 /// </summary>
52 /// <returns></returns>
53 public static IDatabase GetDatabase()
54 {
55 return Instance.GetDatabase();
56 }
57
58 /// <summary>
59 /// 这里的 MergeKey 用来拼接 Key 的前缀,具体不同的业务模块使用不同的前缀。
60 /// </summary>
61 /// <param name="key"></param>
62 /// <returns></returns>
63 private static string MergeKey(string key)
64 {
65 return key;
66 //return BaseSystemInfo.SystemCode + key;
67 }
68
69 /// <summary>
70 /// 根据key获取缓存对象
71 /// </summary>
72 /// <typeparam name="T"></typeparam>
73 /// <param name="key"></param>
74 /// <returns></returns>
75 public static T Get<T>(string key)
76 {
77 key = MergeKey(key);
78 return Deserialize<T>(GetDatabase().StringGet(key));
79 }
80
81 /// <summary>
82 /// 根据key获取缓存对象
83 /// </summary>
84 /// <param name="key"></param>
85 /// <returns></returns>
86 public static object Get(string key)
87 {
88 key = MergeKey(key);
89 return Deserialize<object>(GetDatabase().StringGet(key));
90 }
91
92 /// <summary>
93 /// 设置缓存
94 /// </summary>
95 /// <param name="key"></param>
96 /// <param name="value"></param>
97 /// <param name="expireMinutes"></param>
98 public static void Set(string key, object value, int expireMinutes = 0)
99 {
100 key = MergeKey(key);
101 if (expireMinutes > 0)
102 {
103 GetDatabase().StringSet(key, Serialize(value), TimeSpan.FromMinutes(expireMinutes));
104 }
105 else
106 {
107 GetDatabase().StringSet(key, Serialize(value));
108 }
109
110 }
111
112 /// <summary>
113 /// 判断在缓存中是否存在该key的缓存数据
114 /// </summary>
115 /// <param name="key"></param>
116 /// <returns></returns>
117 public static bool Exists(string key)
118 {
119 key = MergeKey(key);
120 return GetDatabase().KeyExists(key); //可直接调用
121 }
122
123 /// <summary>
124 /// 移除指定key的缓存
125 /// </summary>
126 /// <param name="key"></param>
127 /// <returns></returns>
128 public static bool Remove(string key)
129 {
130 key = MergeKey(key);
131 return GetDatabase().KeyDelete(key);
132 }
133
134 /// <summary>
135 /// 异步设置
136 /// </summary>
137 /// <param name="key"></param>
138 /// <param name="value"></param>
139 public static async Task SetAsync(string key, object value)
140 {
141 key = MergeKey(key);
142 await GetDatabase().StringSetAsync(key, Serialize(value));
143 }
144
145 /// <summary>
146 /// 根据key获取缓存对象
147 /// </summary>
148 /// <param name="key"></param>
149 /// <returns></returns>
150 public static async Task<object> GetAsync(string key)
151 {
152 key = MergeKey(key);
153 object value = await GetDatabase().StringGetAsync(key);
154 return value;
155 }
156
157 /// <summary>
158 /// 实现递增
159 /// </summary>
160 /// <param name="key"></param>
161 /// <returns></returns>
162 public static long Increment(string key)
163 {
164 key = MergeKey(key);
165 //三种命令模式
166 //Sync,同步模式会直接阻塞调用者,但是显然不会阻塞其他线程。
167 //Async,异步模式直接走的是Task模型。
168 //Fire - and - Forget,就是发送命令,然后完全不关心最终什么时候完成命令操作。
169 //即发即弃:通过配置 CommandFlags 来实现即发即弃功能,在该实例中该方法会立即返回,如果是string则返回null 如果是int则返回0.这个操作将会继续在后台运行,一个典型的用法页面计数器的实现:
170 return GetDatabase().StringIncrement(key, flags: CommandFlags.FireAndForget);
171 }
172
173 /// <summary>
174 /// 实现递减
175 /// </summary>
176 /// <param name="key"></param>
177 /// <param name="value"></param>
178 /// <returns></returns>
179 public static long Decrement(string key, string value)
180 {
181 key = MergeKey(key);
182 return GetDatabase().HashDecrement(key, value, flags: CommandFlags.FireAndForget);
183 }
184
185 /// <summary>
186 /// 序列化对象
187 /// </summary>
188 /// <param name="o"></param>
189 /// <returns></returns>
190 private static byte[] Serialize(object o)
191 {
192 if (o == null)
193 {
194 return null;
195 }
196 BinaryFormatter binaryFormatter = new BinaryFormatter();
197 using (MemoryStream memoryStream = new MemoryStream())
198 {
199 binaryFormatter.Serialize(memoryStream, o);
200 byte[] objectDataAsStream = memoryStream.ToArray();
201 return objectDataAsStream;
202 }
203 }
204
205 /// <summary>
206 /// 反序列化对象
207 /// </summary>
208 /// <typeparam name="T"></typeparam>
209 /// <param name="stream"></param>
210 /// <returns></returns>
211 private static T Deserialize<T>(byte[] stream)
212 {
213 if (stream == null)
214 {
215 return default(T);
216 }
217 BinaryFormatter binaryFormatter = new BinaryFormatter();
218 using (MemoryStream memoryStream = new MemoryStream(stream))
219 {
220 T result = (T) binaryFormatter.Deserialize(memoryStream);
221 return result;
222 }
223 }
224
225 /// <summary>
226 /// 配置更改时
227 /// </summary>
228 /// <param name="sender"></param>
229 /// <param name="e"></param>
230 private static void MuxerConfigurationChanged(object sender, EndPointEventArgs e)
231 {
232 //LogHelper.SafeLogMessage("Configuration changed: " + e.EndPoint);
233 }
234
235 /// <summary>
236 /// 发生错误时
237 /// </summary>
238 /// <param name="sender"></param>
239 /// <param name="e"></param>
240 private static void MuxerErrorMessage(object sender, RedisErrorEventArgs e)
241 {
242 //LogHelper.SafeLogMessage("ErrorMessage: " + e.Message);
243 }
244
245 /// <summary>
246 /// 重新建立连接之前的错误
247 /// </summary>
248 /// <param name="sender"></param>
249 /// <param name="e"></param>
250 private static void MuxerConnectionRestored(object sender, ConnectionFailedEventArgs e)
251 {
252 //LogHelper.SafeLogMessage("ConnectionRestored: " + e.EndPoint);
253 }
254
255 /// <summary>
256 /// 连接失败 , 如果重新连接成功你将不会收到这个通知
257 /// </summary>
258 /// <param name="sender"></param>
259 /// <param name="e"></param>
260 private static void MuxerConnectionFailed(object sender, ConnectionFailedEventArgs e)
261 {
262 //LogHelper.SafeLogMessage("重新连接:Endpoint failed: " + e.EndPoint + ", " + e.FailureType +(e.Exception == null ? "" : (", " + e.Exception.Message)));
263 }
264
265 /// <summary>
266 /// 更改集群
267 /// </summary>
268 /// <param name="sender"></param>
269 /// <param name="e"></param>
270 private static void MuxerHashSlotMoved(object sender, HashSlotMovedEventArgs e)
271 {
272 //LogHelper.SafeLogMessage("HashSlotMoved:NewEndPoint" + e.NewEndPoint + ", OldEndPoint" + e.OldEndPoint);
273 }
274
275 /// <summary>
276 /// redis类库错误
277 /// </summary>
278 /// <param name="sender"></param>
279 /// <param name="e"></param>
280 private static void MuxerInternalError(object sender, InternalErrorEventArgs e)
281 {
282 //LogHelper.SafeLogMessage("InternalError:Message" + e.Exception.Message);
283 }
284
285 //场景不一样,选择的模式便会不一样,大家可以按照自己系统架构情况合理选择长连接还是Lazy。
286 //建立连接后,通过调用ConnectionMultiplexer.GetDatabase 方法返回对 Redis Cache 数据库的引用。从 GetDatabase 方法返回的对象是一个轻量级直通对象,不需要进行存储。
287
288 /// <summary>
289 /// 使用的是Lazy,在真正需要连接时创建连接。
290 /// 延迟加载技术
291 /// 微软azure中的配置 连接模板
292 /// </summary>
293 //private static Lazy<ConnectionMultiplexer> lazyConnection = new Lazy<ConnectionMultiplexer>(() =>
294 //{
295 // //var options = ConfigurationOptions.Parse(constr);
296 // ////options.ClientName = GetAppName(); // only known at runtime
297 // //options.AllowAdmin = true;
298 // //return ConnectionMultiplexer.Connect(options);
299 // ConnectionMultiplexer muxer = ConnectionMultiplexer.Connect(Coonstr);
300 // muxer.ConnectionFailed += MuxerConnectionFailed;
301 // muxer.ConnectionRestored += MuxerConnectionRestored;
302 // muxer.ErrorMessage += MuxerErrorMessage;
303 // muxer.ConfigurationChanged += MuxerConfigurationChanged;
304 // muxer.HashSlotMoved += MuxerHashSlotMoved;
305 // muxer.InternalError += MuxerInternalError;
306 // return muxer;
307 //});
308
309
310 #region 当作消息代理中间件使用 一般使用更专业的消息队列来处理这种业务场景
311
312 /// <summary>
313 /// 当作消息代理中间件使用
314 /// 消息组建中,重要的概念便是生产者,消费者,消息中间件。
315 /// </summary>
316 /// <param name="channel"></param>
317 /// <param name="message"></param>
318 /// <returns></returns>
319 public static long Publish(string channel, string message)
320 {
321 ISubscriber sub = Instance.GetSubscriber();
322 //return sub.Publish("messages", "hello");
323 return sub.Publish(channel, message);
324 }
325
326 /// <summary>
327 /// 在消费者端得到该消息并输出
328 /// </summary>
329 /// <param name="channelFrom"></param>
330 /// <returns></returns>
331 public static void Subscribe(string channelFrom)
332 {
333 ISubscriber sub = Instance.GetSubscriber();
334 sub.Subscribe(channelFrom, (channel, message) =>
335 {
336 Console.WriteLine((string) message);
337 });
338 }
339
340 #endregion
341
342 /// <summary>
343 /// GetServer方法会接收一个EndPoint类或者一个唯一标识一台服务器的键值对
344 /// 有时候需要为单个服务器指定特定的命令
345 /// 使用IServer可以使用所有的shell命令,比如:
346 /// DateTime lastSave = server.LastSave();
347 /// ClientInfo[] clients = server.ClientList();
348 /// 如果报错在连接字符串后加 ,allowAdmin=true;
349 /// </summary>
350 /// <returns></returns>
351 public static IServer GetServer(string host, int port)
352 {
353 IServer server = Instance.GetServer(host, port);
354 return server;
355 }
356
357 /// <summary>
358 /// 获取全部终结点
359 /// </summary>
360 /// <returns></returns>
361 public static EndPoint[] GetEndPoints()
362 {
363 EndPoint[] endpoints = Instance.GetEndPoints();
364 return endpoints;
365 }
366 }
使用举例(控制台程序):
string redisCon = "192.168.0.108:6379";
StackExchangeRedisHelper.SetCon(redisCon);
//设置
StackExchangeRedisHelper.Set("uid", "zhangl");
//读取
Console.Write(StackExchangeRedisHelper.Get("uid"));
若要把redis用作MQ,最好使用发布订阅模式,例:
StackExchangeRedisHelper.Subscribe("Order");
一行代码搞定,订阅channel为“Order”的消息,此时我在服务端发布一个消息,控制台立马会输出订阅的消息:
7、管理工具
下载地址:https://redisdesktop.com/download
要FQ、FQ、FQ
安装后,连接到我虚拟机的redis主从库,可以看到例子中set的key都在,也就是说它们都同步到slave库了
8、总结
这篇文章简单的介绍了Ubuntu下redis的一些操作,复杂的问题需要深入研究,此仅为入门
比如流弊的玩法:http://www.open-open.com/lib/view/open1454502890526.html
文中如有错误之处,请留言指出,谢谢!
标签:
版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有
上一篇:Mybatis
- Python3安装impala 2019-08-13
- python指定pip安装源 2019-08-13
- python 安装impala包 2019-08-13
- Django基本知识 2019-08-13
- linux安装 uwsgi 测试 test.py 不显示hello world 的解决办 2019-08-13
IDC资讯: 主机资讯 注册资讯 托管资讯 vps资讯 网站建设
网站运营: 建站经验 策划盈利 搜索优化 网站推广 免费资源
网络编程: Asp.Net编程 Asp编程 Php编程 Xml编程 Access Mssql Mysql 其它
服务器技术: Web服务器 Ftp服务器 Mail服务器 Dns服务器 安全防护
软件技巧: 其它软件 Word Excel Powerpoint Ghost Vista QQ空间 QQ FlashGet 迅雷
网页制作: FrontPages Dreamweaver Javascript css photoshop fireworks Flash