C# Redis学习笔记

介绍:

Redis 是一个开源的使用ANSIC语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库。Redis的出现,很大程度补偿了memcached这类key/value存储的不足,在部分场合可以对关系数据库起到很好的补充作用。
补充:

支持存储的value类型相对更多,包括string、list、set、zset(sortedset –有序集合) 和hash(哈希类型)。在此基础上,redis支持各种不同方式的排序。与memcached一样,为了保证效率,数据都是缓存在内存中。区别的是redis会周期性的把更新的数据写入磁盘或者把修改操作写入磁盘或者把修改操作写入追加的记录文件,并且再次基础上实现了master-slave(主从)同步。Redis支持主从同步,数据可以从主服务器向任意数量的从服务器上同步,从服务器可以是关联其他从服务器的主服务器,这使得Redis可执行单层树复制。存盘可以有意无意的对数据进行写操作。

Redus支持两种持久化方式:

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

2.    Append-only file(aof)的方式

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

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

文件说明:

Redis-server.exe : 服务程序

Redis-check-dumo.exe 本地数据库检查

Redis-check-aof.exe 更新日志检查

Redis-benchmark.exe 性能测试,用以模拟同时由N个客户端发送M个Sets/Gets查询

Redis-cli.exe 服务端开启后,我们的客户端就可以输入各种命令测试

 

Nuget 包安装

命令:Install-Packageservicestack.redis.5.0.2.nupkg

路径:C:\Program Files (x86)\Microsoft VisualStudio\2017\Enterprise\Common7\IDE   (对应VS版本,错误会提示)

 

Redis部署参考地址:http://keenwon.com/1275.html (亲测好使)

 

GitHub 源码地址:https://github.com/MicrosoftArchive/redis  注意的是3.0以上才可支持集群部署

注册服务:redis-server --service-install redis.windows.conf  --service-name RedisService_guanzhx

开启redis服务:redis-server--service-start  --service-name RedisService_guanzhx

停止服务:redis-server --service-stop  --service-name RedisService_guanzhx

 

卸载服务:redis-server --service-uninstall --service-nameRedisService_guanzhx

 

 

内存分配命令:

--maxmemory 例:redis-serverredis.windows.conf --maxmemory 200m

修改配置文件:redis.windows.conf

maxmemory 209715200  注意单位是字节

安装多实例:-port

命令:

redis-server --service-install–service-name redisService1 –port10001

redis-server --service-start –service-nameredisService1

redis-server --service-install–service-name redisService2 –port10002

redis-server --service-start –service-nameredisService2

redis-server --service-install–service-name redisService3 –port10003

redis-server --service-start –service-nameredisService3

     

C# 使用:

Nuget包获取到ServiceStack.Redis安装后可以得到下图所示的文件夹中的DLL,引用至项目即可。

RedisHelper类:

using ServiceStack.Redis;
using ServiceStack.Redis.Generic;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;


namespace ConsoleApp1
{
    public static class RedisHelper
    {
        private static RedisClient Redis = new RedisClient("127.0.0.1", 6379);
        //缓存池  
        static PooledRedisClientManager prcm = new PooledRedisClientManager();


        //默认缓存过期时间单位秒  
        private static int secondsTimeOut = 30 * 60;
        private static readonly Dictionary pools = new Dictionary();
        ///   
        /// 缓冲池  
        ///   
        ///   
        ///   
        ///   
        private static void CreateManager(
         string[] readWriteHosts, string[] readOnlyHosts)
        {
            for (int i = 0; i <= 15; i++)
            {
                PooledRedisClientManager prc = new PooledRedisClientManager(readWriteHosts, readOnlyHosts,
                new RedisClientManagerConfig
                {
                    MaxWritePoolSize = readWriteHosts.Length * 5,
                    MaxReadPoolSize = readOnlyHosts.Length * 5,
                    AutoStart = true,
                }, i, 200, 10);// { RedisClientFactory = (IRedisClientFactory)RedisCacheClientFactory.Instance.CreateRedisClient("127.0.0.1", 6379) }; 
                pools.Add(i, prc);
            }
        }
        public static PooledRedisClientManager ChooseRedisInstance(int database)
        {
            if (database > 16) return pools[0];
            return pools[database];
        }
        ///   
        /// 构造函数  
        ///   
        /// 是否开启缓冲池  
        static RedisHelper()
        {


            CreateManager(new string[] { "127.0.0.1:6379" }, new string[] { "127.0.0.1:6379" });
            //Redis = prcm.GetClient() as RedisClient;
        }


        #region Key/Value存储  
        ///   
        /// 设置缓存  
        ///   
        ///   
        /// 缓存建  
        /// 缓存值  
        /// 过期时间,单位秒,-1:不过期,0:默认过期时间  
        ///   
        public static bool Set(string key, T t, int timeout = 0, int db = 0)
        {
            Redis = (RedisClient)ChooseRedisInstance(db).GetClient();
            if (timeout >= 0)
            {
                if (timeout > 0)
                {
                    secondsTimeOut = timeout;
                }
                Redis.Expire(key, secondsTimeOut);
            }


            return Redis.Add(key, t);
        }
        ///   
        /// 获取  
        ///   
        ///   
        ///   
        ///   
        public static T Get(string key, int db = 0)
        {
            Redis = (RedisClient)ChooseRedisInstance(db).GetClient();
            return Redis.Get(key);
        }
        ///   
        /// 删除  
        ///   
        ///   
        ///   
        public static bool Remove(string key, int db = 0)
        {
            Redis = (RedisClient)ChooseRedisInstance(db).GetClient();
            return Redis.Remove(key);
        }


        //public static bool Add(string key, T t, int timeout)
        //{
        //    if (timeout >= 0)
        //    {
        //        if (timeout > 0)
        //        {
        //            secondsTimeOut = timeout;
        //        }
        //        Redis.Expire(key, secondsTimeOut);
        //    }
        //    return Redis.Add(key, t);
        //}
        #endregion


        #region 链表操作  
        ///   
        /// 根据IEnumerable数据添加链表  
        ///   
        ///   
        ///   
        ///   
        ///   
        //public static void AddList(string listId, IEnumerable values, int timeout = 0)
        //{
        //    Redis.Expire(listId, 60);
        //    IRedisTypedClient iredisClient = Redis.As();
        //    if (timeout >= 0)
        //    {
        //        if (timeout > 0)
        //        {
        //            secondsTimeOut = timeout;
        //        }
        //        Redis.Expire(listId, secondsTimeOut);
        //    }
        //    var redisList = iredisClient.Lists[listId];
        //    redisList.AddRange(values);
        //    iredisClient.Save();
        //}
        ///   
        /// 添加单个实体到链表中  
        ///   
        ///   
        ///   
        ///   
        ///   
        public static void AddEntityToList(string listId, T Item, int timeout = 0, int db = 0)
        {
            Redis = (RedisClient)ChooseRedisInstance(db).GetClient();
            IRedisTypedClient iredisClient = Redis.As();
            if (timeout >= 0)
            {
                if (timeout > 0)
                {
                    secondsTimeOut = timeout;
                }
                Redis.Expire(listId, secondsTimeOut);
            }
            var redisList = iredisClient.Lists[listId];
            redisList.Add(Item);
            iredisClient.Save();
        }
        ///   
        /// 获取链表  
        ///   
        ///   
        ///   
        ///   
        public static IEnumerable GetList(string listId, int db = 0)
        {
            Redis = (RedisClient)ChooseRedisInstance(db).GetClient();
            IRedisTypedClient iredisClient = Redis.As();
            return iredisClient.Lists[listId];
        }
        ///   
        /// 在链表中删除单个实体  
        ///   
        ///   
        ///   
        ///   
        public static void RemoveEntityFromList(string listId, T t, int db = 0)
        {
            Redis = (RedisClient)ChooseRedisInstance(db).GetClient();
            IRedisTypedClient iredisClient = Redis.As();
            var redisList = iredisClient.Lists[listId];
            redisList.RemoveValue(t);
            iredisClient.Save();
        }
        ///   
        /// 根据lambada表达式删除符合条件的实体  
        ///   
        ///   
        ///   
        ///   
        public static void RemoveEntityFromList(string listId, Func func)
        {
            //using (IRedisTypedClient iredisClient = Redis.As())
            //{
            //    var redisList = iredisClient.Lists[listId];
            //    T value = redisList.Where(func).FirstOrDefault();
            //    redisList.RemoveValue(value);
            //    iredisClient.Save();
            //}


            // 使用using 报错:
            // using 语句中使用的类型必须可隐式转换为“System.IDisposable”
            // using会自动调用System.IDisposable下的Dispose方法来释放非托管资源, 
            // IRedisTypedClient没有继承System.IDisposable的接口,所以不能用
            IRedisTypedClient iredisClient = Redis.As();
            var redisList = iredisClient.Lists[listId];
            T value = redisList.Where(func).FirstOrDefault();
            redisList.RemoveValue(value);
            iredisClient.Save();


        }
        public static void test()
        {
            string s1 = Redis.GetClient();
            List> s2 = Redis.GetClientsInfo();
            List s3 = Redis.GetAllKeys();
            string s4 = Redis.GetHostString();
            long s5 = Redis.Db;
        }
        #endregion
        //释放资源  
        public static void Dispose()
        {
            if (Redis != null)
            {
                Redis.Dispose();
                Redis = null;
            }
            GC.Collect();
        }
    }
}

调用:

            List mss = new List();
            MySelf ms = new MySelf();
            ms.code = "guanzhx";
            ms.name = "大帅哥";
            ms.description = "yes,is me,is cool";
            mss.Add(ms);
            RedisHelper.Set("001", ms,0,1);
            RedisHelper.Set>("002", mss,0,3);


            // 链表存储
            RedisHelper.AddEntityToList>("003", mss);
            RedisHelper.AddEntityToList("004", ms);

            Console.WriteLine(RedisHelper.Get("001", 1));
            Console.WriteLine(RedisHelper.Get>("002", 3));


如果想更方便的查看Redis的数据该怎么办?

Redis可视化工具:Redis Desktop Manager

官方下载地址:https://redisdesktop.com/ 

工具连接非常简单,端口默认6379,地址为本机,连接名随意取。

C# Redis学习笔记_第1张图片

关于Redis参数说明

参考资料:http://www.runoob.com/redis/redis-conf.html

redis.conf 配置项说明如下:

1. Redis默认不是以守护进程的方式运行,可以通过该配置项修改,使用yes启用守护进程

    daemonize no

2. Redis以守护进程方式运行时,Redis默认会把pid写入/var/run/redis.pid文件,可以通过pidfile指定

    pidfile/var/run/redis.pid

3. 指定Redis监听端口,默认端口为6379,作者在自己的一篇博文中解释了为什么选用6379作为默认端口,因为6379在手机按键上MERZ对应的号码,而MERZ取自意大利歌女Alessia Merz的名字

    port 6379

4. 绑定的主机地址

    bind 127.0.0.1

5.客户端闲置多长时间后关闭连接,如果指定为0,表示关闭该功能

    timeout 300

6. 指定日志记录级别,Redis总共支持四个级别:debugverbosenoticewarning,默认为verbose

    loglevel verbose

7. 日志记录方式,默认为标准输出,如果配置Redis为守护进程方式运行,而这里又配置为日志记录方式为标准输出,则日志将会发送给/dev/null

    logfile stdout

8. 设置数据库的数量,默认数据库为0,可以使用SELECT 命令在连接上指定数据库id

    databases 16

9. 指定在多长时间内,有多少次更新操作,就将数据同步到数据文件,可以多个条件配合

    save

    Redis默认配置文件中提供了三个条件:

    save 900 1

    save 300 10

    save 60 10000

    分别表示900秒(15分钟)内有1个更改,300秒(5分钟)内有10个更改以及60秒内有10000个更改。

 

10. 指定存储至本地数据库时是否压缩数据,默认为yesRedis采用LZF压缩,如果为了节省CPU时间,可以关闭该选项,但会导致数据库文件变的巨大

    rdbcompression yes

11. 指定本地数据库文件名,默认值为dump.rdb

    dbfilename dump.rdb

12. 指定本地数据库存放目录

    dir ./

13. 设置当本机为slav服务时,设置master服务的IP地址及端口,在Redis启动时,它会自动从master进行数据同步

    slaveof

14. master服务设置了密码保护时,slav服务连接master的密码

    masterauth

15. 设置Redis连接密码,如果配置了连接密码,客户端在连接Redis时需要通过AUTH命令提供密码,默认关闭

    requirepass foobared

16. 设置同一时间最大客户端连接数,默认无限制,Redis可以同时打开的客户端连接数为Redis进程可以打开的最大文件描述符数,如果设置 maxclients 0,表示不作限制。当客户端连接数到达限制时,Redis会关闭新的连接并向客户端返回max number ofclients reached错误信息

    maxclients 128

17. 指定Redis最大内存限制,Redis在启动时会把数据加载到内存中,达到最大内存后,Redis会先尝试清除已到期或即将到期的Key,当此方法处理后,仍然到达最大内存设置,将无法再进行写入操作,但仍然可以进行读取操作。Redis新的vm机制,会把Key存放内存,Value会存放在swap

    maxmemory

18. 指定是否在每次更新操作后进行日志记录,Redis在默认情况下是异步的把数据写入磁盘,如果不开启,可能会在断电时导致一段时间内的数据丢失。因为 redis本身同步数据文件是按上面save条件来同步的,所以有的数据会在一段时间内只存在于内存中。默认为no

    appendonly no

19. 指定更新日志文件名,默认为appendonly.aof

     appendfilenameappendonly.aof

20. 指定更新日志条件,共有3个可选值: 
    
no:表示等操作系统进行数据缓存同步到磁盘(快) 
    
always:表示每次更新操作后手动调用fsync()将数据写到磁盘(慢,安全) 
    
everysec:表示每秒同步一次(折衷,默认值)

    appendfsync everysec

 

21. 指定是否启用虚拟内存机制,默认值为no,简单的介绍一下,VM机制将数据分页存放,由Redis将访问量较少的页即冷数据swap到磁盘上,访问多的页面由磁盘自动换出到内存中(在后面的文章我会仔细分析RedisVM机制)

     vm-enabled no

22. 虚拟内存文件路径,默认值为/tmp/redis.swap,不可多个Redis实例共享

     vm-swap-file/tmp/redis.swap

23. 将所有大于vm-max-memory的数据存入虚拟内存,无论vm-max-memory设置多小,所有索引数据都是内存存储的(Redis的索引数据就是keys),也就是说,vm-max-memory设置为0的时候,其实是所有value都存在于磁盘。默认值为0

     vm-max-memory 0

24. Redis swap文件分成了很多的page,一个对象可以保存在多个page上面,但一个page上不能被多个对象共享,vm-page-size是要根据存储的数据大小来设定的,作者建议如果存储很多小对象,page大小最好设置为32或者64bytes;如果存储很大大对象,则可以使用更大的page,如果不确定,就使用默认值

     vm-page-size 32

25. 设置swap文件中的page数量,由于页表(一种表示页面空闲或使用的bitmap)是在放在内存中的,,在磁盘上每8pages将消耗1byte的内存。

     vm-pages 134217728

26. 设置访问swap文件的线程数,最好不要超过机器的核数,如果设置为0,那么所有对swap文件的操作都是串行的,可能会造成比较长时间的延迟。默认值为4

     vm-max-threads 4

27. 设置在向客户端应答时,是否把较小的包合并为一个包发送,默认为开启

    glueoutputbuf yes

28. 指定在超过一定的数量或者最大的元素超过某一临界值时,采用一种特殊的哈希算法

    hash-max-zipmap-entries64

    hash-max-zipmap-value 512

29. 指定是否激活重置哈希,默认为开启(后面在介绍Redis的哈希算法时具体介绍)

    activerehashing yes

30. 指定包含其它的配置文件,可以在同一主机上多个Redis实例之间使用同一份配置文件,而同时各个实例又拥有自己的特定配置文件

    include/path/to/local.conf

 

小结: 本篇笔记适用于初识Redis的同学借鉴学习,本人经过各方面的查阅资料,理解,验证,总结为自己的学习笔记,若有理解错误,可以不吝留言指正,一起学习一下。当然以后有时间我会继续更新Redis的进阶使用,谢谢。

你可能感兴趣的:(学习笔记)