项目中使用Redis的一些总结和体会

Posted 停下是为了更好的开始

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了项目中使用Redis的一些总结和体会相关的知识,希望对你有一定的参考价值。

第一部分:为什么我的项目中要使用Redis

 

我知道有些地方没说到位,希望大神们提出来,我会吸取教训,大家共同进步!

  • 注册时邮件激活的部分使用Redis
  • 发送邮件时使用Redis的消息队列,减轻网站压力。
  • 使用Lucene.Net在进行分词时使用Redis消息队列和多线程来避免界面卡死等性能问题。

 

  • 请大家先思考一个问题:这个问题在大并发、高负载的网站中必须考虑!大家思考如何让速度更快。

三种方法:(1)数据库(2)页面静态化(3)Redis、Memcached

第二部分:Redis是什么

概述:redis是一种nosql数据库,他的数据是保存在内存中,同时redis可以定时把内存数据同步到磁盘,即可以将数据持久化,并且他比memcached支持更多的数据结构(string,list列表[队列和栈],set[集合],sorted set[有序集合] hash(hash表))

2.1介绍:

  •  Redis是一个高性能的key-value存储系统。和Memcached类似,它支持存储的value类型相对更多,包括string(字符串)、list(链表)、set(集合)、zset(sorted set --有序集合)和hash(哈希类型)。
  • Redis 很大程度补偿了memcached这类key/value存储的不足,在部 分场合可以对关系数据库起到很好的补充作用。它提供了Python,Ruby,Erlang,php客户端,使用很方便。(注: 摘自百度全科),1.主要是支持持久化2.支持更多数据结构 3.支持主从同步
  • Redis支持主从同步。数据可以从主服务器向任意数量的从服务器上同步,从服务器可以是关联其他从服务器的主服务器。

2.2  memcached和redis的比较:

2.3Redis的优势:

 

2.4Redis在windows下的安装:

注:关于Redis的安装网上有很多文章,讲的要比我的好,建议大家去看那些大神的文章,这里我只简单介绍一下。

(1)解压Redisbin.zip
(2)注册成windows服务
安装RedisWatch,会把Redis注册为一个系统服务,然后到安装RedisWatch的文件夹下找到watcher.config,修改下面的两个地方,如下图:
 
特别提醒:作为一个专业的程序员文件放置的路径不要有特殊字符、空格、文件名不要有中文,否则就加班吧。
当然了,正式的生产环境还是Linux的效率高,因为在Linux上是源码安装。
(3)启动redis服务
(4)使用netstat -anb | more

如果你看到有6379 在监听,说明ok(默认的端口号时候:6379)

正确使用Redis的姿势:Redis在Linux(Ubuntu16.04)下的安装(可以直接忽略上面在Windows上Redis的操作,这里使用的Redis版本为Redis4.0.1稳定版)

 (1)到官网上下载安装包 redis-stable.tar.gz   https://redis.io/,官网只提供Linux版本,没有Windows版本的,只要Windows版本的都是微软移植过来的,而且官方推荐使用Linux版本。

(2)使用WinSCP把下载的安装包,放到Ubuntu中对应的目录中。

如果在登录的过程中有弹窗,不要慌,点击是即可。登录成之后的界面:

使用Linux的指令(mkdir src)创建一个目录,来放Redis的安装包:

由于之前测试,已经建了src目录,所以在这里我们可以直接把安装包,拖过来即可。

(3)解压

进入到src目录,执行  tar -zxvf  redis-stable.tar.gz 解压,解压的过程就不截图了,解压后的结果为:

 (4)编译源代码

进入到redis-stable目录中,再执行make

(5)使用ls指令,可以看到该目录下所有的文件:

该目录下用一个src的目录,使用cd src进入到该目录,再使用 ls指令

 

redis-benchmark(压力测试工具)、redis-check-aof(检查.aof文件完整性的工具)、redis-check-dump(检查数据文件完整性的工具)、redis-sentinel(监控集群运行状态)、redis-server(服务端)、redis-cli(客户端),还有一个文件 redis.conf 也拷贝到 myredis该文件在src的上级目录

拷贝到你的工作目录myredis 中:cp redis-* /home/gz/myredis/

 

 

 进入到myredis目录中,发现有多余的文件,然后再使用:

是不是干净多了。

(6)启动Redis

进入到myredis目录中,使用   ./redis-serve redis.conf来启动服务

如果我们的6379端口被监听,说明我们的服务已经成功启动了。

注意:

默认是前端启动,占用你的控制台,我们修改 redis.conf 文件为后台进行,将 daemonize  no 修改成yes。

 (7)C#连接Redis简单测试一下:

在这里回答一下@Partialsky的问题:用StackExchange.Redis ,而不是ServiceStack.Redis,因为StackExchange.Redis依赖组件少,而且操作更接近原生的redis操作,ServiceStack封装的太厉害,而且之前收费,反正最好还是用StackExchange.Redis。

step1:使用VS2017新建一个控制台程序

 

step2: Install-Package StackExchange.Redis

 step3:编写代码:

 1 using StackExchange.Redis;
 2 using System;
 3 using System.Collections.Generic;
 4 using System.Linq;
 5 using System.Text;
 6 using System.Threading.Tasks;
 7 
 8 namespace LinuxRedis
 9 {
10     class Program
11     {
12         static void Main(string[] args)
13         {
14             using (ConnectionMultiplexer redis = ConnectionMultiplexer.Connect("192.168.0.109:6379"))
15             {
16 
17                 IDatabase db = redis.GetDatabase();
18                 db.StringSet("guozheng", "hahaha");
19 
20                 var age = db.StringGet("guozheng");
21                 Console.WriteLine(age);
22             }
23                 
24 
25            
26 
27 
28             Console.ReadKey();
29         }
30     }
31 }

 

 

测试结果:

 再到Linux上看看输入是否存入到Redis中:

启动服务:

./redis-server redis.conf

连接到redis

./redis-cli -h ip地址 -p 端口

数据也成功存入到redis中了。好了,C#如何简单操作Redis就讲到这里。如果大家对如何安装Ubuntu和Linux的操作指令不太清楚,可以先看看其他园友的文章,有时间根据大家的反应,再去写篇关于Linux的文章。

 2.5Redis的数据结构:

前言:Redis中存储的数据都为字符串格式的。下面来分别介绍Redis中常用的数据结构。

  • string数据结构

太简单了,略过。

  •  list数据结构

概述: 什么是list ,list是一种数据结构,可以当做队列和栈来使用。

当你从左边添加数据,再从左边取数据,就模拟出栈;当你从右边添加数据,再从左边取数据,就模拟出队列。因此Redis真的很强大,看到栈和队列这样的数据结构,你难道就不激动吗?这样的数据结构太TM好了,能帮我们处理很多棘手的问题。这里我先卖个关子,下面会介绍我在项目中是如何使用Redis解决棘手的问题。

  • set集合

和list结构差不多,这里不再啰嗦。

下面就是操作set的一些命令。

  • hash数据结构

图中的"user:100"就相当于key,而它所指向的类似于表结构的数据就是value,这样的数据结构有利于存储对象数据。也是非常常用的方法。

强烈推荐:  Redis常用命令文档:http://redisdoc.com/  文档上有详细的操作案例和高级用法。

 

 注意:

redis指令不区分大小写,但是出于规范考虑,应该使用大写
redis中存放的键是区分大小写的.

 

第三部分:Redis如何使用

 3.1C#中如何使用Redis来解决邮箱激活的实效性。

首先思考个问题:为什么要进行邮件激活?激活码该存到哪里?(大家先思考,我不直接说,这样通过下面的例子你会体会的更深。)

原因:用户在注册的时候,虽然正则表达式能检查邮箱的格式是否正确,但是正则检查不了邮箱是否可用,于是让用户进行激活,就能避免用户填写一个不可用的邮箱。

 

传统方法的代码实现:

1)数据库表的设计:

在用户注册的表中添加一个字段:IsActive用来判断激活的状态。

该表用来存放激活码。

 代码实现:

BLL层代码:

 1 /// <summary>
 2 /// 2016-08-30
 3 /// 注册的时候看看是否已经存在该用户
 4 /// </summary>
 5 /// <param name="username"></param>
 6 /// <returns></returns>
 7 public T_Users GetByUserName(string username)
 8 {
 9 T_UsersDAL userDal = new T_UsersDAL();
10 return userDal.GetByUserName(username);
11 }
View Code
 1         /// <summary>
 2         /// 注册的时候看看邮箱是否已经被注册
 3         /// </summary>
 4         /// <returns></returns>
 5         public bool CheckEmailOnReg(string email)
 6         {
 7             T_UsersDAL userDal = new T_UsersDAL();
 8             T_Users user= userDal.CheckEmailOnReg(email);
 9             return user == null;
10         }
View Code

DAL层代码:

 1  /// <summary>
 2         /// 注册时候看看是否已经存在该用户名
 3         /// </summary>
 4         /// <param name="username"></param>
 5         /// <returns></returns>
 6         public T_Users GetByUserName(string username)
 7         {
 8             string sql = "select * from T_Users where UserName=@UserName";
 9             DataTable dt = SqlHelper.ExecuteQuery(sql, new SqlParameter("@UserName", username));
10             T_Users userInfo = null;
11             if (dt.Rows.Count > 0)
12             {
13                 foreach (DataRow dr in dt.Rows)
14                 {
15                     userInfo = RowToUserInfoByDataRow(dr);
16                 }
17             }
18             return userInfo;
19         }
View Code
 1 /// <summary>
 2         /// 注册的时候检查用户的邮箱是否被注册
 3         /// </summary>
 4         /// <param name="email"></param>
 5         /// <returns></returns>
 6         public T_Users CheckEmailOnReg(string email)
 7         {
 8             string sql = "select * from T_Users where Email=@Email ";
 9             DataTable dt = SqlHelper.ExecuteQuery(sql, new SqlParameter("@Email",email));
10 
11             T_Users userInfo = null;
12             if (dt.Rows.Count>0)
13             {
14                 foreach (DataRow dr in dt.Rows)
15                 {
16                     userInfo=RowToUserInfoByDataRow(dr);
17                 }
18             }
19             return userInfo;
20         }
View Code

UI层代码:

  1 <!--#include file="/html/head.html"-->
  2 <title>注册</title>
  3 <!--#include file="/html/linkscript.html"-->
  4 <script type="text/javascript">
  5     function checkPasswordLevel(value) {
  6         if (!value) {
  7             return 1;
  8         }
  9         if (value.length < 6) {
 10             return 1;
 11         }
 12         if (value.length == 6 && (/[0-9]/.test(value) || /[a-z]/.test(value))) {
 13             return 1;
 14         }
 15 
 16         if (value.length >= 6 && /[0-9]/.test(value) && /[a-z]/.test(value) && /(?=[\\x21-\\x7e]+)[^A-Za-z0-9]/.test(value)) {
 17             return 3;
 18         }
 19         return 2;
 20     }
 21     $(function () {
 22         $("#btnReg").click(function () {
 23             var username = $("#username").val();
 24             var password = $("#password").val();
 25             var password2 = $("#password2").val();
 26             var email = $("#email").val();
 27             var phone = $("#PhoneNum").val();
 28             var qq = $("#qq").val();
 29             var school = $("#school").val();
 30 
 31             var validCode = $("#validCode").val();
 32             //todo:非空验证。JQuery EasyUI
 33             if (phone == "") {
 34                 $("#phoneMsg").text("手机号不能为空!");
 35                 return;
 36             }
 37             else {
 38                 var reg = "^1(3[0-9]|4[57]|5[0-35-9]|7[01678]|8[0-9])\\\\d{8}$";
 39                 if (!reg.test(phone)) {
 40                     $("#phoneMsg").text("手机号不合法!");
 41                     return;
 42                 }
 43             }
 44             if (qq=="") {
 45                 $("#qqMsg").text("QQ号不能为空!");
 46                 return;
 47             }
 48             if (school=="") {
 49                 $("#schoolMsg").text("学校不能为空!");
 50             }
 51             if (validCode == "") {
 52                 $("#validateCodeMsg").text("验证码不能为空!");
 53                 return;
 54             }
 55             if (password == "") {
 56                 $("#userPasswordMsg").text("密码不能为空!");
 57                 return;
 58             }
 59             if (password != password2) {
 60                 $("#pwdError").text("两次输入的密码不一致!");
 61                 return;
 62             }
 63 
 64             $.ajax({
 65                 url: "UserController.ashx", type: "post",
 66                 dataType: "json",
 67                 data: { action: "registerSubmit", username: username, password: password, email: email, validCode: validCode, phone: phone, qq: qq, school: school },
 68                 success: function (data) {
 69                     if (data.status == "ok") {
 70                         alert("注册成功");
 71                         window.location.href = "index.shtml";
 72                     }
 73                     else {
 74                         alert("注册失败:" + data.msg);
 75                         //只有这句话刷新验证码是不安全的,需要后台也刷新验证码
 76                         $("#imgValidCode").attr("src", "UserController.ashx?action=createValideCode&id=" + new Date());
 77                        
 78                       
 79                     }
 80                 },
 81                 error: function () {
 82                     alert("注册请求失败");
 83                 }
 84             });
 85 
 86         });
 87 
 88         $("#password").keyup(function () {
 89 
 90             var level = checkPasswordLevel($("#password").val());
 91             switch (level) {
 92                 case 1: {
 93                     $("#td1").css("backgroundColor", "#FF8000");
 94                     $("#td2").css("backgroundColor", "");
 95                     $("#td3").css("backgroundColor", "");
 96                 }
 97                     break;
 98                 case 2: {
 99                     $("#td1").css("backgroundColor", "");
100                     $("#td2").css("backgroundColor", "#FF4000");
101                     $("#td3").css("backgroundColor", "");
102                 }
103                     break;
104                 case 3: {
105                     $("#td1").css("backgroundColor", "");
106                     $("#td2").css("backgroundColor", "");
107                     $("#td3").css("backgroundColor", "#5CB85C");
108                 }
109                     break;
110             }
111         })
112         $("#password2").blur(function () {
113             var password = $("#password").val();
114             var password2 = $("#password2").val();
115             if (password != password2) {
116                 $("#pwdError").text("两次输入的密码不一致!");
117                 return;
118             }
119             else {
120                 $("#pwdError").text("");
121             }
122         });
123         //todo:焦点离开email的时候,编写正则表达式检查email地址是否正确
124         //todo:前台用户的注册:邮件发送激活码,一个邮件只能注册一个账号。
125         $("#email").blur(function () {
126             var email = $(this).val();
127             if (email == "") {
128                 $("#userEmailMsg").text("邮箱不能为空!");
129                 return;
130             }
131             else {
132                 var re = /^\\w+@[a-z0-9]+(\\.[a-z]+){1,3}$/;
133                 if (re.test(email)) {
134                     $.ajax({
135                         url: "UserController.ashx", type: "post", dataType: "json",
136                         data: { action: "checkEmail", email: email },
137                         success: function (data) {
138                             if (data.status == "ok") {
139                                 $("#userEmailMsg").text(data.msg);
140                                 return;
141                             }
142                             项目管理心得:一个项目经理的个人体会经验总结

项目管理心得:一个项目经理的个人体会经验总结

项目管理心得:一个项目经理的个人体会经验总结

NodeJs爬虫抓取古代典籍,共计16000个页面心得体会总结及项目分享

项目管理心得:一个项目经理的个人体会经验总结

项目管理心得:一个项目经理的个人体会经验总结