zoukankan      html  css  js  c++  java
  • Redis项目实战 .net StackExchange.Redis

    StackExchange.Redis 免费、支持异步、用的最多

    常用对象

    源码地址:https://github.com/StackExchange/StackExchange.Redis    用vs2017打开

    ConnectionMultiplexer

    中文意思  连接复用器

    注释:Represents an inter-related group of connections to redis servers      表示一群相互关联的redis服务,就相当于一个对redis数据库操作的类。

    使用注意事项:ConnectionMultiplexer实例是线程安全的,被设计为共享重用,也就是设计为单例(创建一个这种实例是很昂贵的,没有池化)。这里有个和 ServiceStack.Redis 大的区别是没有默认的连接池管理了。没有连接池自然有其利弊,最大的好处在于等待获取连接的等待时间没有了,也不会因为连接池里面的连接由于没有正确释放等原因导致无限等待而处于死锁状态。缺点在于一些低质量的代码可能导致服务器资源耗尽。不过提供连接池等阻塞和等待的手段是和作者的设计理念相违背的。StackExchange.Redis这里使用管道和多路复用的技术来实现减少连接

    方法:

    Connect

    //
    // 摘要:
    //     Create a new ConnectionMultiplexer instance
    public static ConnectionMultiplexer Connect(string configuration, TextWriter log = null);
    //
    // 摘要:
    //     Create a new ConnectionMultiplexer instance
    public static ConnectionMultiplexer Connect(ConfigurationOptions configuration, TextWriter log = null);
    View Code

    创建一个ConnectionMultiplexer实例,

     Configure

    根据现有配置重新配置当前连接。

     Close

    关闭所有连接并释放与此对象关联的所有资源

    Dispose

    释放对象相关联的所有资源。

    GetCounters

    获取与此服务器相关的汇总统计信息。

    GetDatabase

    在redis中获得与数据库的一个数据库。默认为-1   (ConfigurationOptions可以指定默认数据库)。0表示第一个数据库,1表示第二个数据库。

    源码中如下

    GetEndPoints

    获取所有的rendis实例服务。

    GetServer

    GetServer方法会接收一个EndPoint类或者一个唯一标识一台服务器的键值对
    有时候需要为单个服务器指定特定的命令
    使用IServer可以使用所有的shell命令,比如:
    DateTime lastSave = server.LastSave();
    ClientInfo[] clients = server.ClientList();
    如果报错在连接字符串后加 ,allowAdmin=true;

    GetSubscriber

    订阅一个频道。

    ISubscriber sub = ConnectionMultiplexer.GetSubscriber();
    sub.Subscribe()
    sub.Publish()

    属性: 

    //
    // 摘要:
    //     Provides a way of overriding the default Task Factory. If not set, it will use
    //     the default Task.Factory. Useful when top level code sets it's own factory which
    //     may interfere with Redis queries.
    public static TaskFactory Factory { get; set; }
    //
    // 摘要:
    //     Gets the client-name that will be used on all new connections
    public string ClientName { get; }
    //
    // 摘要:
    //     Gets the configuration of the connection
    public string Configuration { get; }
    //
    // 摘要:
    //     Should exceptions include identifiable details? (key names, additional .Data
    //     annotations)
    public bool IncludeDetailInExceptions { get; set; }
    //
    // 摘要:
    //     Should exceptions include performance counter details? (CPU usage, etc - note
    //     that this can be problematic on some platforms)
    public bool IncludePerformanceCountersInExceptions { get; set; }
    //
    // 摘要:
    //     Indicates whether any servers are connected
    public bool IsConnected { get; }
    //
    // 摘要:
    //     The number of operations that have been performed on all connections
    public long OperationCount { get; }
    //
    // 摘要:
    //     Gets or sets whether asynchronous operations should be invoked in a way that
    //     guarantees their original delivery order
    public bool PreserveAsyncOrder { get; set; }
    //
    // 摘要:
    //     Limit at which to start recording unusual busy patterns (only one log will be
    //     retained at a time; set to a negative value to disable this feature)
    public int StormLogThreshold { get; set; }
    //
    // 摘要:
    //     Gets the timeout associated with the connections
    public int TimeoutMilliseconds { get; }
    View Code

    ClientName

    连接服务器的客户端名字。

    Configuration

    连接配置字符串,  也就是ConnectionMultiplexer.Connect(config)这个字符串参数。

    IncludeDetailInExceptions

    异常是否应该包括可识别的细节?(关键的名字,额外的数据注释)

    IncludePerformanceCountersInExceptions

    是否应该包括性能计数器细节?(CPU使用率,等等——注意这在某些平台上可能会有问题)

    IsConnected

    是否已经连接数据库。

    OperationCount

    在所有连接上执行的操作数。

    PreserveAsyncOrder

    获取或设置是否应该以保证其原始交付顺序的方式调用异步操作。

    TimeoutMilliseconds

    连接超时时间。

    事件:

    //
    // 摘要:
    //     Raised when configuration changes are detected
    public event EventHandler<EndPointEventArgs> ConfigurationChanged;
    //
    // 摘要:
    //     Raised when nodes are explicitly requested to reconfigure via broadcast; this
    //     usually means master/slave changes
    public event EventHandler<EndPointEventArgs> ConfigurationChangedBroadcast;
    //
    // 摘要:
    //     Raised whenever a physical connection fails
    public event EventHandler<ConnectionFailedEventArgs> ConnectionFailed;
    //
    // 摘要:
    //     Raised whenever a physical connection is established
    public event EventHandler<ConnectionFailedEventArgs> ConnectionRestored;
    //
    // 摘要:
    //     A server replied with an error message;
    public event EventHandler<RedisErrorEventArgs> ErrorMessage;
    //
    // 摘要:
    //     Raised when a hash-slot has been relocated
    public event EventHandler<HashSlotMovedEventArgs> HashSlotMoved;
    //
    // 摘要:
    //     Raised whenever an internal error occurs (this is primarily for debugging)
    public event EventHandler<InternalErrorEventArgs> InternalError;
    View Code

    ConfigurationChanged

    配置修改时执行。

    ConfigurationChangedBroadcast

     广播,主从更改是执行。

    ConnectionFailed

    连接失败是执行。

    ConnectionRestored

    连接建立时执行。

    ErrorMessage

    服务器发生错误是执行

    HashSlotMoved

    哈希槽重新分配是执行。  集群的时候

    InternalError

    出现内部错误时执行,主要用于调试。

    http://www.cnblogs.com/liqingwen/p/6672452.html

    ConfigurationOptions

    配置选项。创建实例的时候配置参数。

    ConfigurationOptions config = new ConfigurationOptions() {
        //是一个列表,一个复杂的的场景中可能包含有主从复制 , 对于这种情况,只需要指定所有地址在连接字符串中
        //(它将会自动识别出主服务器)假设这里找到了两台主服务器,将会对两台服务进行裁决选出一台作为主服务器
        //来解决这个问题 , 这种情况是非常罕见的 ,我们也应该避免这种情况的发生。
        EndPoints = { { "127.0.0.1", 11111 }, { "127.0.0.1", 12111 } }
    };
    //服务器秘密
    config.Password = "123456";
    //客户端名字
    config.ClientName = "127.0.0.1";
    //服务器名字
    config.ServiceName = "127.0.0.1";
    //true表示管理员身份,可以用一些危险的指令。
    config.AllowAdmin = true;
    //获取或设置是否应该通过TimeoutException显式通知连接 / 配置超时。
    config.AbortOnConnectFail = true;
    //你可以禁用或者重命名一个命令。   配置文件里面也可以配置, 对于敏感的命令做处理(比如说清空整个库  config这种命令)。
    config.CommandMap = null;
    //每n秒检查配置(默认情况下每分钟)
    config.ConfigCheckSeconds = 60;
    //如果没有服务器及时响应,重复初始连接周期的次数。
    config.ConnectRetry = 1;
    //超时时间       指定应该允许连接的毫秒数(默认为5秒,除非SyncTimeout更高)
    config.ConnectTimeout = 5;
    //默认0到-1          指定要使用的默认数据库当调用ConnectionMultiplexer.GetDatabase()没有任何参数
    //config.DefaultDatabase = 1;
    //版本号
    config.DefaultVersion = new Version(2, 8, 8);
    //使用ThreadPriority。对于SocketManager阅读器和写入器线程(默认情况下是正确的)来说,这是正常的。如果错误,ThreadPriority。将使用正常。
    //config.HighPrioritySocketThreads = true;
    //保存x秒的活动连接
    config.KeepAlive = 180;
    //代理 枚举类型           http://blog.csdn.net/u010601183/article/details/54426289
    config.Proxy = Proxy.Twemproxy;
    View Code

    Connect方法有两个重载。

    ConnectionMultiplexer.Connect(config);
    ConnectionMultiplexer.Connect(config.ToString());

    tostring方法覆写了。

    https://www.cnblogs.com/soundcode/p/6214287.html

    redis主从读写分离落地

    搭建Redis主从哨兵

    地址:http://www.cnblogs.com/wudequn/p/8109798.html   在网页中搜索 redis哨兵配置下载  然后下载配置文件。

    安装说明配置好redis服务。

    运行代码测试

    //准备过程
    //1 http://www.cnblogs.com/wudequn/p/8109798.html  页面中有下载主从哨兵配置文件(页面搜索文字   redis哨兵配置下载   ) 并搭redis主从 哨兵。
    //2 运行代码测试
    
    public static IConnectionMultiplexer RedisConnect;
    public static IDatabase DefaultDB;
    public static ISubscriber sentinelsub;
    private static ConnectionMultiplexer _sentinel;
    
    /// <summary>
    /// 创建redis连接
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void button1_Click(object sender, EventArgs e)
    {
        ConfigurationOptions config = new ConfigurationOptions()
        {
            //是一个列表,一个复杂的的场景中可能包含有主从复制 , 对于这种情况,只需要指定所有地址在连接字符串中
            //(它将会自动识别出主服务器 set值得时候用的主服务器)假设这里找到了两台主服务器,将会对两台服务进行裁决选出一台作为主服务器
            //来解决这个问题 , 这种情况是非常罕见的 ,我们也应该避免这种情况的发生。
            //
            EndPoints = { { "127.0.0.1", 11111 }, { "127.0.0.1", 12111 }, { "127.0.0.1", 13111 } }
        };
        //服务器秘密
        config.Password = "123456";
        //客户端名字
        config.ClientName = "127.0.0.1";
        //服务器名字
        config.ServiceName = "127.0.0.1";
        //true表示管理员身份,可以用一些危险的指令。
        config.AllowAdmin = true;
        RedisConnect = ConnectionMultiplexer.Connect(config);
        DefaultDB = RedisConnect.GetDatabase();
        Console.WriteLine("---------------------------Redis主从连接实例创建---------------------------");
        Console.WriteLine(RedisConnect.GetStatus());
        Console.WriteLine("---------------------------------------------------------------------------");
    }
    
    /// <summary>
    /// 监控哨兵主从切换
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void button2_Click(object sender, EventArgs e)
    {
        ConfigurationOptions sentineloption = new ConfigurationOptions();
        sentineloption.TieBreaker = "";//sentinel模式一定要写
    
        //三个哨兵
        sentineloption.EndPoints.Add("127.0.0.1", 11121);
        sentineloption.EndPoints.Add("127.0.0.1", 11131);
        sentineloption.EndPoints.Add("127.0.0.1", 11141);
    
        //哨兵连接模式
        sentineloption.CommandMap = CommandMap.Sentinel;
        sentineloption.ServiceName = "mymaster";
        //我们可以成功的连接一个sentinel服务器,对这个连接的实际意义在于:当一个主从进行切换后,如果它外层有Twemproxy代理,我们可以在这个时机(+switch-master事件)通
    Twemproxy代理服务器,并更新它的配置文件里的master服务器的地址,然后从起你的Twemproxy服务,这样你的主从切换才算真正完成。
        //一般没有代理服务器,直接更改从数据库配置文件,将其升级为主数据库。
        _sentinel = ConnectionMultiplexer.Connect(sentineloption);
        sentinelsub = _sentinel.GetSubscriber();
    
        sentinelsub.Subscribe("+switch-master", (ch, mg) =>
        {
            Console.WriteLine((string)mg);
        });
    }
    
    /// <summary>
    /// 读写测试
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void button3_Click(object sender, EventArgs e)
    {
        //读写数据
        string key = "WYX";
        string value = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff");
        //默认写入主库。
        DefaultDB.StringSet(key, value);
        Console.WriteLine($"写入成功Key{key}:Value{value}");
        Thread.Sleep(2000);
        //CommandFlags.PreferSlave参数表示读取从库数据   貌似是随机你从不同的slave中读取的。
    
    
        //关注问题:https://github.com/StackExchange/StackExchange.Redis/issues/593
        //关注问题:https://github.com/StackExchange/StackExchange.Redis/issues/547
        var getvalue = DefaultDB.StringGet(key,CommandFlags.PreferSlave);
        Console.WriteLine($"写入读取Key{key}:Value{getvalue}");
    }
    
    private void button4_Click(object sender, EventArgs e)
    {
        Console.WriteLine("这样redis就落地了,读写分离。");
    }
    View Code

    测试项目下载

    字典

     一般为页面下拉选项类型的,但是一般为一层的,但是也有树状多层的。

    可以存储在string类型中,json格式存入。

    类、类列表

     存在hash中。key就是主键。

    页面Module

     代码中建立一个页面的额数据模型,把对应的页面数据json存放在string类型中,key就是页面的url表示。

    缓存与数据库交互模式

     1、读取数据

    2、添加修改删除数据

    优点:这个流程的主要目的是把Redis当作数据库使用,更新获取数据比DB快。非常适合大数据量的频繁变动(比如微博)。
    缺点:对Redis的依赖很大,要做好宕机时的数据保存。(不过可以使用redis的快照AOF,快速恢复的话,应该不会有多大影响(即使是AOf也可能有1秒左右的数据缺失),因为就算Redis不工作了,也不会影响后续数据的处理。)
    难点:在前期规划key的格式,存储类型很重要,因为这会影响能否把数据同步到DB。

  • 相关阅读:
    Hadoop 3.1.1
    java乐观锁和悲观锁
    git push时提示The authenticity of host 'github.com (52.74.223.119)' can't be established.
    github 提交使用git commit,报错Please tell me who you are
    Mac adb 提示 command not found. 解决办法
    Mac系统下安卓使用uiautomator配置SDK及真机环境配置
    python随笔:启动django报错
    ERROR: Could not install packages due to an EnvironmentError: [Errno 13] Permission denied: '/Library/Python/2.7/site-packages/Django-1.11.23.dist-info' Consider using the `--user` option or check the
    Python中安装bs4后,pycharm依然报错ModuleNotFoundError: No module named 'bs4'
    Python中__init__和self的意义和作用
  • 原文地址:https://www.cnblogs.com/wudequn/p/8080091.html
Copyright © 2011-2022 走看看