zoukankan      html  css  js  c++  java
  • Memcached 两款.NET客户端的郁闷事儿

    不久以后就要负责一个比较大的项目,有多大?反正就是挺大的。现在处于筹备阶段,我主要负责系统框架搭建,在系统缓存这一块决定采用Http运行时缓存+memcached。

      memcached 以前用过几次 不过也是小打小闹型,尚未正式大型应用过。这次也算是个难得的练手机会吧。memcached服务器打算分布在web应用服务器以及数据库服务器上。

    (两台服务器有点花大手笔了 两台Dell PowerEdge R810 自定义了配置 大约单台6.5万)。

      关于Memcached的.NET 客户端的选择这一块,主要有两款候选库,Memcached.ClientLibrary(discuz .net版本企业版使用的缓存客户端) 以及 Enyim 。

    这两款类库都比较好用,后者使用更加方便,只需简单的配置。我选择了Enyim。

      在测试的时候发现了一个共同的问题,假如在使用多个Memcached服务时,当其中一台服务器网络不通(其它至少存在一个可用的Memcached服务)的情况下,

    Memcached.ClientLibrary 的缓存功能失效,Enyim 在缓存操作的时候实例化socket对象时没有进行连接超时的处理(Memcached.ClientLibrary处理了)。

    一般都要等待10秒以上线程才能继续,线程被卡住不放了。在以往的应用中都是 memcached 与 web 共存在一台服务器上,所以没遇到过这个问题,

    但是这次打算 web 服务器上开一个memcached实例,数据库服务器上开一个memcached实例,所以才关注到了这个问题。一般情况下这个问题也不会有太大影响,

    但是心里总是感觉不爽。不打算使用Memcached.ClientLibrary ,所以找了 Enyim 的源代码,打算自己修改一下。

      翻看了一下源代码, Enyim 的问题主要存在于 Enyim.Caching.Memcached.PooledSocket,该类主要用于创建socket 连接 。

      以下是构造函数

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    internal PooledSocket(IPEndPoint endpoint, TimeSpan connectionTimeout, TimeSpan receiveTimeout, Action<PooledSocket> cleanupCallback)
     
             {
     
                  this.endpoint = endpoint;
     
                  this.cleanupCallback = cleanupCallback;
     
      
     
                  this.socket = new Socket(endpoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
     
      
     
                  this.socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendTimeout, connectionTimeout == TimeSpan.MaxValue ? Timeout.Infinite : (int)connectionTimeout.TotalMilliseconds);
     
                  this.socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, receiveTimeout == TimeSpan.MaxValue ? Timeout.Infinite : (int)receiveTimeout.TotalMilliseconds);
     
      
     
                  // all operations are "atomic", we do not send small chunks of data
     
                  this.socket.NoDelay = true;
     
      
     
                  this.socket.Connect(endpoint);
     
                  this.inputStream = new BufferedStream(new BasicNetworkStream(this.socket));
     
         }

      由于Socket (我对Socket没啥研究 几乎就是文盲)对象没法设置连接超时之类的属性(这下怎么办呀),并且在源代码中可以看出 this.socket.Connect(endpoint)

    的时候没有做任何处理,导致当连接有问题的服务时出现了较长时间的线程等待。我在网上找啊找,找到了类似问题的解决方案,就是使用线程池。

    网上找的代码修修改改 差不多能用了,创建了 Enyim.Caching.Memcached.SocketConnector,其中有一个核心的静态方法,用来创建Socket对象,并且运行定义超时时间。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    public static Socket GetConnectdSocket(IPEndPoint endpoint, TimeSpan connectionTimeout, TimeSpan receiveTimeout, intmillisecondsTimeout)
     
            {
     
                ConnectorState state = new ConnectorState();
     
                state.Endpoint = endpoint;
     
                state.ConnectionTimeout = connectionTimeout;
     
                state.ReceiveTimeout = receiveTimeout;
     
                ThreadPool.QueueUserWorkItem(new WaitCallback(SocketConnector.ConnectThreaded), state);
     
                if (state.Completed.WaitOne(millisecondsTimeout, false))
     
                {
     
                    if (state.Socket == null)
     
                    {
     
                        throw state.Exception;
     
                    }
     
                    return state.Socket;
     
                }
     
                state.Abort();
     
                throw new SocketException(0x2af9);
     
            }

    然后修改PooledSocket的构造为:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    internal PooledSocket(IPEndPoint endpoint, TimeSpan connectionTimeout, TimeSpan receiveTimeout, Action<PooledSocket> cleanupCallback)
     
            {
     
                this.endpoint = endpoint;
     
                this.cleanupCallback = cleanupCallback;
     
                this.socket = SocketConnector.GetConnectdSocket(endpoint, connectionTimeout, receiveTimeout, 100);
     
                this.inputStream = new BufferedStream(new BasicNetworkStream(this.socket));
     
            }

    我将连接超时设置为100毫秒,那个恶心的问题基本算是解决了。

  • 相关阅读:
    108. Convert Sorted Array to Binary Search Tree
    How to check if one path is a child of another path?
    Why there is two completely different version of Reverse for List and IEnumerable?
    在Jenkins中集成Sonarqube
    如何查看sonarqube的版本 how to check the version of sonarqube
    Queue
    BFS广度优先 vs DFS深度优先 for Binary Tree
    Depth-first search and Breadth-first search 深度优先搜索和广度优先搜索
    102. Binary Tree Level Order Traversal 广度优先遍历
    How do I check if a type is a subtype OR the type of an object?
  • 原文地址:https://www.cnblogs.com/Alex80/p/4422381.html
Copyright © 2011-2022 走看看