[你必须知道的NOSQL系列]专题二:Redis快速入门

一、前言

   在前一篇博文介绍了MongoDB基本操作,本来打算这篇博文继续介绍MongoDB的相关内容的,例如索引,主从备份等内容的,但是发现这些内容都可以通过官方文档都可以看到,并且都非常详细,所以这里就不想继续介绍了,需要用到的朋友到官方文档进行查阅:http://docs.mongodb.org/manual/tutorial/remove-indexes/。本专题将介绍另一个NoSQL——Redis的相关内容。

二、Redis介绍

  关于Redis大家肯定多多少少都有所了解,Redis一般都用来做缓存的,当然也可以作为消息队列。这里就直接网上一段比较好的介绍:

  Redis是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,和Memcached类似,它支持存储的value类型相对更多,包括string(字符串)、list(链表)、set(集合)、zset(sorted set --有序集合)和hash(哈希类型)。在此基础上,redis支持各种不同方式的排序。与memcached一样,为了保证效率,数据都是缓存在内存中。区别的是redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,并且在此基础上实现了master-slave(主从)同步。

  Redis支持主从同步。数据可以从主服务器向任意数量的从服务器上同步,从服务器可以是关联其他从服务器的主服务器。这使得Redis可执行单层树复制。存盘可以有意无意的对数据进行写操作。

Redis支持两种持久化方式:

   (1):snapshotting(快照)也是默认方式.(把数据做一个备份,将数据存储到文件)

   (2)Append-only file(缩写aof)的方式 

   快照是默认的持久化方式,这种方式是将内存中数据以快照的方式写到二进制文件中,默认的文件名称为dump.rdb.可以通过配置设置自动做快照持久化的方式。我们可以配置redis在n秒内如果超过m个key键修改就自动做快照.

   aof方式:由于快照方式是在一定间隔时间做一次的,所以如果redis意外down掉的话,就会丢失最后一次快照后的所有修改。aof比快照方式有更好的持久化性,是由于在使用aof时,redis会将每一个收到的写命令都通过write函数追加到文件中,当redis重启时会通过重新执行文件中保存的写命令来在内存中重建整个数据库的内容。 

三、Windows下Redis的安装

  Redis官方下载(官方地址:http://redis.io/download)只能用于Linux环境下,所以要在Windows环境下安装Redis就不能从官方进行下载了。为了能够在Windows平台安装Redis,微软的Microsoft Open Tech团队为我们开发了Windows版本下Redis。下载地址为:https://github.com/MSOpenTech/redis,但是Microsoft Open Tech团队开发的最新版本只能应用于64位操作系统,但是我使用的还是32位操作系统,那是不是我就不能安装Redis了呢?幸好微软之前开发的Redis之前版本还是支持32位系统的,所以我本机只能安装之前的版本了。这里我选择的是2.6版本,下载地址:https://github.com/MSOpenTech/redis/tree/2.6/bin/release。下载redisbin.zip文件之后直接解压到指定目录就完成了Redis的安装了,解压成功后,你将看到如下几个Dll:

  • redis-server.exe:服务程序  
  • redis-check-dump.exe:本地数据库检查 
  • redis-check-aof.exe:更新日志检查 
  • redis-benchmark.exe:性能测试,用以模拟同时由N个客户端发送M个 SETs/GETs 查询.
  • redis-cli.exe: 服务端开启后,我们的客户端就可以输入各种命令测试了 

  接下来,只需要双击redis-server.exe程序就可以启动Redis服务,在2.6版本中可以不指定config路径,不像网上的Redis介绍文章都需要指定config文件,因为它们下载一般都是更早的版本,如2.4等版本。在2.6版本不需要特别指定config文件就可以启动成功,启动成功的界面如下图所示:

  服务启动成功后,我们就可以像MongoDB一样,开启redis-cli.exe客户端程序要操作Redis服务器,关于使用redis-cli.exe客户端命令的方式这里就不介绍了,更多可以参考官方文档,因为对我们来说,更常用的是使用C#、Java来操作Redis服务。在第四部分我将介绍使用C#来操作Redis。

  一般服务我们都是用Windows Service来启动的,对于最新版本的Redis安装为Windows Service官方有详细的介绍,由于这里我不是用的最新版本,并且还是32位的,所以这里我安装Windows Service是通过sc(http://www.cnblogs.com/jankie/archive/2011/08/03/2126249.html)命令来安装的,具体的安装脚本如下所示:

sc create Redis start= auto DisplayName= Redis binpath= "F:\Study\No-Sql\Redis\redis-windows\RedisService.exe"

  其中RedisService是Redis注册Windows服务的启动程序,具体下载地址为:http://files.cnblogs.com/files/zhili/RedisService.zip

   通过上面的脚本就可以成功安装Redis为Windows Service了,然后每次系统启动的时候,就会自动开启Redis服务,而不需要我们每次去手动运行redis-server.exe命令了。

四、C#如何操作Redis

   前面我们已经准备成功开启Redis服务,其端口号为6379,接下来我们就看看如何使用C#语言来操作Redis。就如MongoDB一样,要操作Redis服务,自然就需要下载C#的客户端,这里通过Nuget下载了“ServiceStack.Redis”客户端,引入成功之后,就可以使用C#来对Redis服务进行操作了。

  由于Redis一般是用来作为缓存的,也就是一般我们把一些不经常改变的数据通过Redis缓存起来,之后用户的请求就不需要再访问数据库,而可以直接从Redis缓存中直接获取,这样就可以减轻数据库服务器的压力以及加快响应速度。既然是用来做缓存的,也就是通过指定key值来把对应Value保存起来,之后再根据key值来获得之前缓存的值。具体的操作代码如下所示,这里就不过多介绍了。

class Program
    {
        static void Main(string[] args)
        {
            //在Redis中存储常用的5种数据类型:String,Hash,List,SetSorted set
            var client = new RedisClient("127.0.0.1", 6379);
            //AddString(client);
            //AddHash(client);
            //AddList(client);
            //AddSet(client);
            AddSetSorted(client);

            Console.ReadLine();
        }

        private static void AddString(RedisClient client)
        {
            var timeOut = new TimeSpan(0,0,0,30);
            client.Add("Test", "Learninghard", timeOut);
            while (true)
            {
                if (client.ContainsKey("Test"))
                {
                    Console.WriteLine("String Key: Test -Value: {0}, 当前时间: {1}", client.Get<string>("Test"), DateTime.Now);
                    Thread.Sleep(10000);
                }
                else
                {
                    Console.WriteLine("Value 已经过期了,当前时间:{0}", DateTime.Now);
                    break;
                }
            }

            var person = new Person() {Name = "Learninghard", Age = 26};
            client.Add("lh", person);
            var cachePerson = client.Get<Person>("lh");
            Console.WriteLine("Person's Name is : {0}, Age: {1}", cachePerson.Name, cachePerson.Age);
        }

        private static void AddHash(RedisClient client)
        {
            if (client == null) throw new ArgumentNullException("client");

            client.SetEntryInHash("HashId", "Name", "Learninghard");
            client.SetEntryInHash("HashId", "Age", "26");
            client.SetEntryInHash("HashId", "Sex", "");

            var hashKeys = client.GetHashKeys("HashId");
            foreach (var key in hashKeys)
            {
                Console.WriteLine("HashId--Key:{0}", key);
            }

            var haskValues = client.GetHashValues("HashId");
            foreach (var value in haskValues)
            {
                Console.WriteLine("HashId--Value:{0}", value);
            }

            var allKeys = client.GetAllKeys(); //获取所有的key。
            foreach (var key in allKeys)
            {
                Console.WriteLine("AllKey--Key:{0}", key);
            }
        }

        private static void AddList(RedisClient client)
        {
            if (client == null) throw new ArgumentNullException("client");

            client.EnqueueItemOnList("QueueListId", "1.Learnghard");  //入队
            client.EnqueueItemOnList("QueueListId", "2.张三");
            client.EnqueueItemOnList("QueueListId", "3.李四");
            client.EnqueueItemOnList("QueueListId", "4.王五");
            var queueCount = client.GetListCount("QueueListId");

            for (var i = 0; i < queueCount; i++)
            {
                Console.WriteLine("QueueListId出队值:{0}", client.DequeueItemFromList("QueueListId"));   //出队(队列先进先出)
            }

            client.PushItemToList("StackListId", "1.Learninghard");  //入栈
            client.PushItemToList("StackListId", "2.张三");
            client.PushItemToList("StackListId", "3.李四");
            client.PushItemToList("StackListId", "4.王五");

            var stackCount = client.GetListCount("StackListId");
            for (var i = 0; i < stackCount; i++)
            {
                Console.WriteLine("StackListId出栈值:{0}", client.PopItemFromList("StackListId"));   //出栈(栈先进后出)
            }
        }

      
        //它是string类型的无序集合。set是通过hash table实现的,添加,删除和查找,对集合我们可以取并集,交集,差集
        private static void AddSet(RedisClient client)
        {
            if (client == null) throw new ArgumentNullException("client");

            client.AddItemToSet("Set1001", "A");
            client.AddItemToSet("Set1001", "B");
            client.AddItemToSet("Set1001", "C");
            client.AddItemToSet("Set1001", "D");
            var hastset1 = client.GetAllItemsFromSet("Set1001");
            foreach (var item in hastset1)
            {
                Console.WriteLine("Set无序集合Value:{0}", item); //出来的结果是无须的
            }

            client.AddItemToSet("Set1002", "K");
            client.AddItemToSet("Set1002", "C");
            client.AddItemToSet("Set1002", "A");
            client.AddItemToSet("Set1002", "J");
            var hastset2 = client.GetAllItemsFromSet("Set1002");
            foreach (var item in hastset2)
            {
                Console.WriteLine("Set无序集合ValueB:{0}", item); //出来的结果是无须的
            }

            var hashUnion = client.GetUnionFromSets(new string[] { "Set1001", "Set1002" });
            foreach (var item in hashUnion)
            {
                Console.WriteLine("求Set1001和Set1002的并集:{0}", item); //并集
            }

            var hashG = client.GetIntersectFromSets(new string[] { "Set1001", "Set1002" });
            foreach (var item in hashG)
            {
                Console.WriteLine("求Set1001和Set1002的交集:{0}", item);  //交集
            }

            var hashD = client.GetDifferencesFromSet("Set1001", new string[] { "Set1002" });  //[返回存在于第一个集合,但是不存在于其他集合的数据。差集]
            foreach (var item in hashD)
            {
                Console.WriteLine("求Set1001和Set1002的差集:{0}", item);  //差集
            }

        }

        /*
        sorted set 是set的一个升级版本,它在set的基础上增加了一个顺序的属性,这一属性在添加修改.元素的时候可以指定,
        * 每次指定后,zset(表示有序集合)会自动重新按新的值调整顺序。可以理解为有列的表,一列存 value,一列存顺序。操作中key理解为zset的名字.
        */
        private static void AddSetSorted(RedisClient client)
        {
            if (client == null) throw new ArgumentNullException("client");

            client.AddItemToSortedSet("SetSorted1001", "A");
            client.AddItemToSortedSet("SetSorted1001", "B");
            client.AddItemToSortedSet("SetSorted1001", "C");
            var listSetSorted = client.GetAllItemsFromSortedSet("SetSorted1001");
            foreach (var item in listSetSorted)
            {
                Console.WriteLine("SetSorted有序集合{0}", item);
            }

            client.AddItemToSortedSet("SetSorted1002", "A", 400);
            client.AddItemToSortedSet("SetSorted1002", "D", 200);
            client.AddItemToSortedSet("SetSorted1002", "B", 300);

            // 升序获取第一个值:"D"
            var list = client.GetRangeFromSortedSet("SetSorted1002", 0, 0);

            foreach (var item in list)
            {
                Console.WriteLine(item);
            }

            //降序获取第一个值:"A"
            list = client.GetRangeFromSortedSetDesc("SetSorted1002", 0, 0);

            foreach (var item in list)
            {
                Console.WriteLine(item);
            }
        }
    }

    class Person
    {
        public string Name { get; set; }
        public int Age { get; set; }
    }

  如何要想查看自己操作是否成功,也可以像MongoDB那样下载一个客户端工具,这里推荐一款Redis Desktop Manager。这个工具就相当于SQL Server的客户端工具一样。通过这款工具可以查看Redis服务器中保存的数据和对应格式。其使用也非常简单,只需要添加一个Redis服务连接即可。该工具的下载地址为:http://pan.baidu.com/s/1sjp55Ul

五、小结

   到此,本专题的内容就介绍结束了。关于Redis更深入的内容我觉得大家可以在项目中用到了可以自己深入研究,这里只是作为一个快速入门的教程。所以该NoSQL系列可能会先告一段落,接下来将计划一个全新的系列:Web API和Windows Azure系列。

  本文所有源码下载地址:http://files.cnblogs.com/files/zhili/RedisQuickStart.zip

posted @ 2015-07-11 23:26 Learning hard 阅读(...) 评论(...) 编辑 收藏