zoukankan      html  css  js  c++  java
  • Redis Sentinel高可用配置及C#访问

    转自:https://www.cnblogs.com/madyina/p/4198768.html

    本文环境如下:

    操作系统:ubuntu-14.04.1-desktop-amd64

    Redis:2.8.19

    如果使用虚拟机则将每台的网络设置为桥接,否则他们之间能连上,局域网连不上。

    系统设计如图:

    image

    一、安装Redis

    可以参考之前文章,采用离线安装,本次以Sentinel配置为重,所以以联网安装为例。

    呼出ubuntu终端,依次执行下面命令:

    wget http://download.redis.io/releases/redis-2.8.19.tar.gz
    tar xzf redis-2.8.19.tar.gz
    cd redis-2.8.19
    make

    即可安装成功,4台机器依次按照相同步骤安装。

    二、配置主从关系(主子关系)

    本部分和Data4无关。

    如上图Data1为Master机,则不用做任何配置,直接启动就行,启动命令和下面的一样,跳过。

    依次进入Data2、Data3的Redis-2.8.19目录,将redis.conf文件原目录复制粘贴一份,改名为redis10.conf、redis11.conf(就当是为了怕配置坏而备份吧),然后打开这个配置文件找到主从配置项,配置成如下:

    slaveof 192.168.1.9 6379

    注意将前面的#去掉。

    然后依次启动3个服务,新开一个终端,启动命令如:

    cd redis-2.8.19
    src/redis-server redis.conf

    其他机器为:

    src/redis-server redis10.conf

    然后在Master上面再次新开一个终端,存入Key/value数据:

    cd redis-2.8.19
    src/redis-cli
    set name zhangsan
    get name

    如果能看到”zhangsan”则成功,然后依次到各Slave机器上打开终端键入:

    get name

    同样应该能看到”zhangsan”

    相反如果键入

    set name lisi

    则会报错。

    原因是:Master-Slave模式只有主可以读写,然后分发给各个从机,从机只能读,不能写。由此可以实现读写分离和备份。

    三、配置Sentinel

    Data4至此还未动过,进入redis-2.8.19目录,新建一个文本文件,名为SentinelMaster.conf,内容为(只有这几行,再没其他的了):

    复制代码
    port 6379
    logfile log.log
    #master1
    sentinel monitor master1 192.168.9.18 6379 1
    sentinel down-after-milliseconds master1 5000
    sentinel failover-timeout master1 900000
    sentinel can-failover master1 yes
    sentinel parallel-syncs master1 2
    复制代码

    以上配置说明如下:

    monitor :表示监控哪个Master主机。

    down-after-milliseconds:是当一个sentinel在以毫秒为单位的时间段内无法达到一个实例时(或者实例不答复PINGs亦或者答复错误)它就认为实例已经关闭所需要的时间值。

    can-failover用来决定一个sentinel是否在实例处于objectively down状态时启动故障转移。你可以配置所有的Sentinels执行故障切换,如果需要的话,你还可以配置为只用几个哨兵达成协议,另一些实际负责执行故障转移。

    parallel-syncs 选项指定了在执行故障转移时, 最多可以有多少个从服务器同时对新的主服务器进行同步, 这个数字越小, 完成故障转移所需的时间就越长,但越大就意味着越多的从服务器因为复制而不可用。可以通过将这个值设为 1 来保证每次只有一个从服务器处于不能处理命令请求的状态。

    然后启动Sentinel:

    cd redis-2.8.19
    src/redis-sentinel SentinelMaster.conf

    然后打开日志文件即可看到已经连上主机并且已经获取到从机信息。

    四、模拟故障转移:

    在Data1上新开一个终端,键入:

    cd redis-2.8.19
    src/redis-cli
    shutdown

    查看服务启动终端或者日志最后一行应该是bye bye说明下线成功。

    然后,在Data2和Data3上面分别写入和读出一个Key/Value测试出哪个成为新的主机,然后去Data4的日志中去对照即可。

    当Data1重新启动之后就成为一个新的Slave而不再是Master了。

    五、使用C#连接集群一(csredis)

    本例使用csredis这个客户端,自从某个开源客户端商业化之后,浪费了不少时间寻找新的全功能客户端(至少要支持Sentinel)。

    思路是先连接Sentinel获取在线服务地址和端口号,然后只读操作连接Slave,增删改操作连接Master即可。获取Sentinel信息的代码如下:

     public class RedisManager
        {
            /// <summary>
            /// redis配置文件信息
            /// </summary>
            private static string[] RediswritePath = null;
            private static string[] RedisReadPath = null;
            private static PooledRedisClientManager _prcm;
            /// <summary>
            /// 静态构造方法,初始化链接池管理对象
            /// </summary>
            static RedisManager()
            {
                using (var sentinel = new RedisSentinelClient("192.168.148.131", 26379))
                {               
                    var master = sentinel.Master("mymaster");//得到主机器信息  
                   
                    Console.WriteLine("master:" + master);
                    var slave = sentinel.Slaves("mymaster");
                    RediswritePath = new string[] { master.Ip + ":" + master.Port };
                    RedisReadPath = new string[slave.Length];
                    int i = 0;
                    foreach (var item in slave)
                    {
                        RedisReadPath[i] = item.Ip + ":" + item.Port;
                        i++;               
                    }
                }
    
                CreateManager();
            }
            /// <summary>
            /// 创建链接池管理对象
            /// </summary>
            private static void CreateManager()
            {
                _prcm = CreateManager(RediswritePath, RedisReadPath);
            }
            private static PooledRedisClientManager CreateManager(string[] readWriteHosts, string[] readOnlyHosts)
            {
                return new PooledRedisClientManager(readWriteHosts, readOnlyHosts, new RedisClientManagerConfig
                {
                    MaxWritePoolSize = 5000, // “写”链接池链接数 
                    MaxReadPoolSize = 5000, // “读”链接池链接数 
                    AutoStart = true,
                });
            }
            private static IEnumerable<string> SplitString(string strSource, string split)
            {
                return strSource.Split(split.ToArray());
            }
            /// <summary>
            /// 客户端缓存操作对象
            /// </summary>
            public static ServiceStack.Redis.IRedisClient GetClient()
            {
                if (_prcm == null)
                {
                    CreateManager();
                }
                return _prcm.GetClient();
            }
    
        }
    

    调用方式

      using (IRedisClient Redis = RedisManager.GetClient())

      {
        List<string> tts = Redis.Get<List<string>>($"dianxin{i}");
        Console.WriteLine(i);
      }

     

    六、使用C#连接集群二(ServiceStack.Redis)

    推荐使用这种方法

     public class redistest
        {
            private static IRedisClientsManager redisManager = GetRedisSentinel();
            private static IRedisClientsManager GetRedisSentinel()
            {
                IRedisClientsManager redisManager = null;
    
                try
                {
                    List<string> listSentinels = new List<string>();
                    listSentinels.Add("192.168.148.131:26379");//sentinel地址1
                    listSentinels.Add("192.168.148.132:26379");// 地址2
                    listSentinels.Add("192.168.148.133:26379");// 地址3  集群可做负载 或者高可用
    
                    RedisSentinel redisSentinel = new RedisSentinel(listSentinels, "mymaster");
                    redisSentinel.SentinelWorkerConnectTimeoutMs = 500;
                    redisManager = redisSentinel.Start();
                }
                catch (Exception ex)
                {
    
                }
    
                return redisManager;
            }
    
            public static object GetRedisCache<T>(string key)
            {
                object myObject = null;
    
                //naming convention [PLATFORM]:[PROJECT]:[FUNCTION]:[PARAMETERS…]
                string redisKey = key;
                //Open Redis
                if (redisManager != null)
                {
                    try
                    {
                        using (RedisClient redis = (RedisClient)redisManager.GetClient())
                        {
                            redis.Get<T>(redisKey);
                        }
                    }
                    catch (Exception ex)
                    {
                        throw;
                    }
                }
    
    
                return myObject;
            }
    
            public static int SaveRedisCache(string myObject, string key, DateTime? expireDateTime = null)
            {
                if (expireDateTime == null)
                    expireDateTime = DateTime.Now.AddMinutes(20);
    
                //naming convention [PLATFORM]:[PROJECT]:[FUNCTION]:[PARAMETERS…]
                string redisKey = key;
    
                if (myObject != null)
                {              
    
                    if (redisManager != null)
                    {
                        try
                        {
                            using (RedisClient redis = (RedisClient)redisManager.GetClient())
                            {
                                bool b= redis.Set(redisKey, myObject, (DateTime)expireDateTime);
                            }
                            return 0;
                        }
                        catch (Exception ex)
                        {
                            return -1;
                            throw;
                        }
                    }
                }
    
    
                return -1;
            }      
        }
    

     调用方式

      int b = redistest.SaveRedisCache(value, $"yuyu{k}");
      var yu = redistest.GetRedisCache<string>($"yuyu{k}");
    

    ps aux | grep redis

    src/redis-cli -h 127.0.0.1 -p 6000 shutdown

  • 相关阅读:
    在C#程序中模拟发送键盘按键消息
    C# UDPCLIENT多线程实例
    【转】WINFORM下FTP客户端的实现
    抓取屏幕或窗体并保存成图片
    c# 判断窗体已打开则显示为焦点
    【转】C#中dataGridView用法实例分析
    【转】VC6控件小记
    .Net部署二三事之一——如何为VS安装文件MSI制作更新补丁MSP
    [转]C#串口serialPort操作
    VS向IIS发布C#或VB应用程序
  • 原文地址:https://www.cnblogs.com/lijiasnong/p/7908223.html
Copyright © 2011-2022 走看看