Redis总结(七)Redis运维常用命令

redis 服务器端命令

redis 127.0.0.1:6380> time  ,显示服务器时间 , 时间戳(秒), 微秒数

1) “1375270361”

2) “504511”

 

redis 127.0.0.1:6380> dbsize  // 当前数据库的key的数量

(integer) 2

redis 127.0.0.1:6380> select 2

OK

redis 127.0.0.1:6380[2]> dbsize

(integer) 0

redis 127.0.0.1:6380[2]>

 

 

BGREWRITEAOF 后台进程重写AOF

BGSAVE       后台保存rdb快照

SAVE         保存rdb快照

LASTSAVE     上次保存时间

 

Slaveof master-Host port  , 把当前实例设为master的slave

 

Flushall  清空所有库所有键

Flushdb  清空当前库所有键

Showdown [save/nosave]

 

注: 如果不小心运行了flushall, 立即 shutdown nosave ,关闭服务器

然后 手工编辑aof文件, 去掉文件中的 “flushall ”相关行, 然后开启服务器,就可以导入回原来数据.

 

如果,flushall之后,系统恰好bgrewriteaof了,那么aof就清空了,数据丢失.

 

Slowlog 显示慢查询

注:多慢才叫慢?

答: 由slowlog-log-slower-than 10000 ,来指定,(单位是微秒)

 

服务器储存多少条慢查询的记录?

答: 由 slowlog-max-len 128 ,来做限制

 

Info [Replication/CPU/Memory..]

查看redis服务器的信息

 

Config get 配置项

Config set 配置项 值 (特殊的选项,不允许用此命令设置,如slave-of, 需要用单独的slaveof命令来设置)

 

Redis运维时需要注意的参数

1: 内存

# Memory

used_memory:859192 数据结构的空间

used_memory_rss:7634944 实占空间

mem_fragmentation_ratio:8.89 前2者的比例,1.N为佳,如果此值过大,说明redis的内存的碎片化严重,可以导出再导入一次.

2: 主从复制

# Replication

role:slave

master_host:192.168.1.128

master_port:6379

master_link_status:up

 

3:持久化

# Persistence

rdb_changes_since_last_save:0

rdb_last_save_time:1375224063

 

4: fork耗时

#Status

latest_fork_usec:936  上次导出rdb快照,持久化花费微秒

注意: 如果某实例有10G内容,导出需要2分钟,

每分钟写入10000次,导致不断的rdb导出,磁盘始处于高IO状态.

 

 

5: 慢日志

config get/set slowlog-log-slower-than

CONFIG get/SET slowlog-max-len

slowlog get N 获取慢日志

 

运行时更改master-slave

修改一台slave(设为A)为new master

1) 命令该服务不做其他redis服务的slave

命令: slaveof no one

2) 修改其readonly为yes

 

其他的slave再指向new master A

1) 命令该服务为new master A的slave

命令格式 slaveof IP port

redis总结(四)redis的持久化RDB和AOF

前面已经总结了Redis 的安装和使用今天讲下Redis 的持久化。

redis跟memcached类似,都是内存数据库,不过redis支持数据持久化,也就是说redis可以将内存中的数据同步到磁盘来持久化,以确保redis 的数据安全。

 

 redis持久化的两种方式

redis提供了两种持久化的方式,分别是RDB(Redis DataBase)和AOF(Append Only File)。

RDB,简而言之,就是将存储的数据快照的方式存储到磁盘上,

AOF,则是将redis执行过的所有写指令记录下来,通过write函数追加到AOF文件的末尾。在下次redis重新启动时,只要把这些写指令从前到后再重复执行一遍,就可以实现数据恢复了。

 

其实RDB和AOF两种方式也可以同时使用,在这种情况下,如果redis重启的话,则会优先采用AOF方式来进行数据恢复,这是因为AOF方式的数据恢复完整度更高。

如果你没有数据持久化的需求,也完全可以关闭RDB和AOF方式,这样的话,redis将变成一个纯内存数据库,就像memcache一样。

 

 RDB

RDB(Redis DataBase),是将redis某一时刻的数据持久化到磁盘中,是一种快照式的持久化方法。默认的文件名为dump.rdb。

redis在进行数据持久化的过程中,会先将数据写入到一个临时文件中,待持久化过程都结束了,才会用这个临时文件替换上次持久化好的文件,以确保数据完整可用。

  save 300 10  #300秒内容如超过10个key被修改,则发起快照保存

  

不过,由于快照方式是在一定间隔时间做一次的,如果对数据的完整性非常敏感,那么RDB方式就不太适合你,因为即使你每2分钟都持久化一次,当redis故障时,仍然会有近2分钟的数据丢失。所以,redis还提供了另一种持久化方式,那就是AOF。


 

 AOF

AOF(Append Only File),即只允许追加不允许改写的文件。

Redis会将收到的每一个写操作(如SET等)通过write函数追加到AOF文件的末尾。默认的AOF持久化策略是每秒钟fsync一次(把缓存中的写指令记录到磁盘中)。

 

当Redis重启时会通过重新执行文件中保存的写命令来在内存中重建整个数据库的内容。

  appendonly yes           #启用aof持久化方式
  # appendfsync always    #每次收到写命令就立即强制写入磁盘,最慢的,但是保证完全的持久化,不推荐使用
  appendfsync everysec     #每秒钟强制写入磁盘一次,在性能和持久化方面做了很好的折中,推荐
  # appendfsync no       #完全依赖os,性能最好,持久化没保证

但AOF方式是将所有的命令记录下来,所以AOF文件要比RDB文件的体积大。而且,恢复速度也要慢于RDB方式。

 

redis提供了bgrewriteaof命令,会重新生成一个全新的AOF文件,其中便包括了可以恢复现有数据的最少的命令集。

 

需要注意到是重写aof文件的操作,并没有读取旧的aof文件,而是将整个内存中的数据库内容用命令的方式重写了一个新的aof文件,这点和快照有点类似。

 

 如何选择RDB和AOF

对于我们应该选择RDB还是AOF,取决于具体的应用场景,官方的建议是两个同时使用。这样可以提供更可靠的持久化方案。

 

Redis总结(三)Redis 的主从复制

接着上一篇,前面两篇我总结了《Redis总结(一)Redis安装》和《Redis总结(二)C#中如何使用redis》 所以这一篇,会讲讲Redis 的主从复制以及C#中如何调用。

Redis跟MySQL一样,拥有非常强大的主从复制功能,而且还支持一个master可以拥有多个slave,而一个slave又可以拥有多个slave,从而形成强大的多级服务器集群架构。

redis的主从复制是异步进行的,它不会影响master的运行,所以不会降低redis的处理性能。主从架构中,可以考虑关闭Master的数据持久化功能,只让Slave进行持久化,这样可以提高主服务器的处理性能。同时Slave为只读模式,这样可以避免Slave缓存的数据被误修改。

 1.配置

实际生产中,主从架构是在几个不同服务器上安装相应的Redis服务。为了测试方便,我这边的主从备份的配置,都是在我Windows 本机上测试。

1. 安装两个Redis 实例,Master和Slave。将Master端口设置为6379,Slave 端口设置为6380 。bind 都设置为:127.0.0.1。 具体Redis安装步骤,请参考前一篇博文 《Redis总结(一)Redis安装》。

2. 在Slave 实例 ,增加:slaveof 127.0.0.1 6379 配置。如下图所示:

    

 

    配置完成之后,启动这两个实例,如果输出如下内容,说明主从复制的架构已经配置成功了。

 

注意:在同一台电脑上测试,Master和Slave的端口不要一样,否则是不能同时启动两个实例的。

 2.测试

在命令行,分别连接上Master服务器和Slave 服务器。然后在Master 写入缓存,然后在Slave 中读取。如下图所示:

 3.C#中调用

主从架构的Redis的读写其实和单台Redis 的读写差不多,只是部分配置和读取区分了主从,如果不清楚C#中如何使用redis,请参考我这篇文章 《Redis总结(二)C#中如何使用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的主从复制功能。

1. 配置文件 app.config

    
    "SessionExpireMinutes" value="180" />
    "redis_server_master_session" value="127.0.0.1:6379" />
    "redis_server_slave_session" value="127.0.0.1:6380" />
    "redis_max_read_pool" value="300" />
    "redis_max_write_pool" value="100" />
    

 

2. Redis操作的公用类RedisCacheHelper

using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Text;
using System.Web;
using ServiceStack.Common.Extensions;
using ServiceStack.Redis;
using ServiceStack.Logging;

namespace Weiz.Redis.Common 
{
    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(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(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(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(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(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(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(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(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);
        }
    }
}

View Code

 

Redis总结(二)C#中如何使用redis

  上一篇讲述了安装redis《Redis总结(一)Redis安装》,同时也大致介绍了redis的优势和应用场景。本篇着重讲解.NET中如何使用redis和C#。

  Redis官网提供了很多开源的C#客户端。例如,Nhiredis ,ServiceStack.Redis ,StackExchange.Redis等。其中ServiceStack.Redis应该算是比较流行的。它提供了一整套从Redis数据结构都强类型对象转换的机制并将对象json序列化。所以这里只介绍ServiceStack.Redis,它也是目前我们产品中所使用的客户端。

  ServiceStack.Redis地址https://github.com/ServiceStack/ServiceStack.Redis

  1. 建立一个控制台应用程序,并引用以下ServiceStack.Redis相关的四个类库。或者通过Nuget进行安装Redis常用组件ServiceStack.Redis。 下载示例代码

 

2. 创建一个Redis操作的公用类RedisCacheHelper,

using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Text;
using System.Web;
using ServiceStack.Common.Extensions;
using ServiceStack.Redis;
using ServiceStack.Logging;

namespace Weiz.Redis.RedisTest
{
    public class RedisCacheHelper
    {
        private static readonly PooledRedisClientManager pool = null;
        private static readonly string[] redisHosts = 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 redisHostStr = ConfigurationManager.AppSettings["redis_server_session"];

            if (!string.IsNullOrEmpty(redisHostStr))
            {
                redisHosts = redisHostStr.Split(',');

                if (redisHosts.Length > 0)
                {
                    pool = new PooledRedisClientManager(redisHosts, redisHosts,
                        new RedisClientManagerConfig()
                        {
                            MaxWritePoolSize = RedisMaxWritePool,
                            MaxReadPoolSize = RedisMaxReadPool,
                            AutoStart = true
                        });
                }
            }
        }
        public static void Add(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(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(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(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;
        }
    }
}

说明:RedisCacheHelper 使用的是客户端链接池模式,这样的存取效率应该是最高的。同时也更方便的支持读写分离,均衡负载。

 

3. 配置文件

    
    
    
    
    
    

4. 测试程序调用

class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Redis写入缓存:zhong");

            RedisCacheHelper.Add("zhong", "zhongzhongzhong", DateTime.Now.AddDays(1));

            Console.WriteLine("Redis获取缓存:zhong");

            string str3 = RedisCacheHelper.Get("zhong");

            Console.WriteLine(str3);

            Console.WriteLine("Redis获取缓存:nihao");
            string str = RedisCacheHelper.Get("nihao");
            Console.WriteLine(str);


            Console.WriteLine("Redis获取缓存:wei");
            string str1 = RedisCacheHelper.Get("wei");
            Console.WriteLine(str1);

            Console.ReadKey();
        }
    }

5. 输出结果

Redis总结(一)Redis安装

最近项目中需要使用Redis,刚好这两天有时间,便总结记录一下Redis的安装,以及如何在.NET中使用Redis。

 

Redis是一个用的比较广泛的Key/Value的内存数据库。目前新浪微博、Github、StackOverflow 等大型应用中都用其作为缓存,和Memcached类似,但是支持数据的持久化,解决了断电后数据完全丢失的情况。而且它支持更多的类型,除了string外,还支持lists(链表)、sets(集合)和zsets(有序集合)几种数据类型。

 

Redis的官网为: http://redis.io/

 

 1.Redis安装

redis的安装非常的简单,而且Redis并不依赖其他环境和标准库,很容易上手,这可能也是它流行的一个原因。这里为了测试方便,用的都是windows 环境下测试。下载Windows版本Redis

redis.windows.conf 是redis的配置文件。

redis-server.exe  服务器端。

redis-cli  命令行客户端。

redis-benchmark:Redis性能测试工具,测试Redis在你的系统及你的配置下的读写性能。

 

 2.启动服务

在命令行输入如下命令 :redis-server  redis.windows.conf。

同时也可以该命令保存为文件 startup.bat,下次就可以直接启动了。

如果提示redis-server 不是内部命令。将该目录加到环境变量里面即可。

 

3. redis相关配置

1. port 端口号,例如6379

2. bind 实例绑定的访问地址127.0.0.1

3. requirepass 访问的密码

4. maxheap 记得把这个配置节点打开,否者redis 服务无法启动。例如maxheap 1024000000

5. timeout:请求超时时间

6. logfile:log文件位置

7. databases:开启数据库的数量

8. dbfilename:数据快照文件名(只是文件名,不包括目录)

 

 4. 连接测试

在命令行输入如下命令:redis-cli –h 127.0.0.1 –p 6379

参数分别为host、port,如果设置了密码,则必须要加上-a 123456,123456为登录密码。否则会提示没有权限登录系统。

如下图所示。