Linux下(乌班图)安装Memcache

apt-get update 简介:

在windows下安装软件,我们只需要有EXE文件,然后双击,下一步直接OK就可以了。但在LINUX下,不是这样的。每个LINUX的发行版,比如ubuntu(乌班图),都会维护一个自己的软件仓库,我们常用的几乎所有软件都在这里面。这里面的软件绝对安全,而且绝对的能正常安装。

那我们要怎么安装呢?在乌班图(ubuntu)下,我们维护一个源列表,源列表里面都是一些网址信息,这每一条网址就是一个源,这个地址指向的数据标识着这台源服务器上有哪些软件可以安装使用。

我们也可以在执行下面这段命令。然后再文本的最后面添加一些软件源(可以新增软件源,当然也可以注释一些)

sudo gedit /etc/apt/sources.list

例如:在文本的最后面添加 deb http://archive.ubuntu.com/ubuntu/trusty main universe restricted multiverse

然后保存退出

接着 我们再执行下面这段命令,来更新软件源列表(这个命令,会把本地已安装的软件,与刚下载的软件列表里对应软件进行对比,如果发现已安装的软件版本太低,就会提示你更新。)

sudo apt-get update

update后,可能需要更新一下软件。(也可能并不需要,反正更新下也没有问题) upgrade是更新软件的命令

那我们可以执行下面这段代码

sudo apt-get upgrade


Memcached的安装

第一步:

打开Linux终端 (管他三七二十一,我们先对软件源列表更新下,防止安装软件的时候出现无法定位软件包的问题)

执行更新软件源列表命令:sudo apt-get udpate

第二步:

由于memcached依赖于libevent;因此,还需要安装libevent

执行安装libevent命令: sudo apt-get install libevent-dev  

注意: 网上好多博文中的介绍安装libevent命令是:sudo apt-get install libevent  ,或者:sudo apt-get install libevent libevent-deve 在实践中会报如下错:unable to locate package libevent

第三步:

安装Memcached

执行安装memcached命令: sudo apt-get install memcached 

第四步:

安装完memcached后我们要开启这个memcached

执行开启memcached命令: memcached -d -m 512 -p 11211 -u root -c 1024 -l 127.0.0.1 -P /tmp/memcached.pid -s /tmp/memcached.sock 

参数解释:
    -d 设置为守护进程
    -m 设置内存大小(M)
    -p 设置监听端口
    -u 设置启动用户
    -l 是监听的服务器IP地址
    -c 选项是最大运行的并发连接数,默认是1024,按照你服务器的负载量来设定
    -P 是设置保存Memcache的pid文件
    -s 设置套接口

第五步:

修改memcache的配置文件,使其允许远程访问

执行打开memcached.conf配置文件的命令: sudo vi /etc/memcached.conf 

在开文件后,找到 -l 127.0.0.1 这一行 将它注释掉(改成:# -l 127.0.0.1)这样就可以使用任何IP登录memcache

 (注意:这样非常危险,只适合测试,如果想配置让指定的IP连接Memcached服务器,请参考这篇网站)

第六步:

重启memcached服务

执行重启memcached服务的命令: service memcached restart

第七步:在终端中使用telnet来测试连接是否成功

以上都算Memcached安装完毕了,现在我们来测试一下Memcached是否安装成功,测试连接下

执行连接memcached服务的命令,在终端中输入:telnet localhost 11211 

这时候会出现

Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.

我们可以在下面进行存取数据  例如:

set food 0 0 3
123
get food 0 3
VALUE 0 3

第八步: 在.net中连接测试连接是否成功

成功后,我们就可以用.net客户端来连接我们的部署在Linux下的Memcached服务了。

在终端中输入 ifconfig 命令查看Linux的IP  例如我的虚拟下的Linux的IP是 192.168.31.126 Memcached的端口是11211

那么我们就可以在.net连接中连接 192.168.31.126:11211 来连接我们的memcached

public sealed class MemcacheHelper
{
    private static MemcachedClient MemClient;
    static readonly object padlock = new object();

    //线程安全的单例模式
    static MemcacheHelper()
    {
        if (MemClient == null)
        {
            lock (padlock)
            {
                if (MemClient == null)
                {
                    MemClientInit();
                }
            }
        }
    }

    private static void MemClientInit()
    {
        //初始化缓存()
        MemcachedClientConfiguration memConfig = new MemcachedClientConfiguration();
        //IPAddress newaddress = IPAddress.Parse(Dns.GetHostEntry("127.0.0.1").AddressList[0].ToString());//"127.0.0.1"替换为内网地址
        //IPEndPoint ipEndPoint = new IPEndPoint(newaddress, 11211);
        // 配置文件 - ip
        //memConfig.Servers.Add(ipEndPoint);

        //这个数组为服务器ip(做集群用的),一般都是配置在数据库或者XML中的,这里写死在这里
        string[] servers = new string[] { "192.168.31.126" };//配置集群
        foreach (var server in servers)
        {
            //配置文件 - ip
            memConfig.Servers.Add(new IPEndPoint(IPAddress.Parse(server), 11211));
        }

        //Ketama是一种一致性哈希算法,常用于负载均衡
        //当我们有多Memcached服务器的时候,使用Ketama这种Hash算法来确定数据存储到哪台服务器中
        //打开memConfig.NodeLocatorFactory = new KetamaNodeLocatorFactory();这段代码后客户端
        //会根据自己的算法决定把数据写入哪个Memcached服务器,取数据库的时候再根据同样的定位算法去哪台服务器上去取。
        //它会自动给我们做类似负载均衡的功能(有多台Memcached服务器的时候才打开)
        //memConfig.NodeLocatorFactory = new KetamaNodeLocatorFactory();

        // 配置文件 - 协议 (保存数据采用二进制的形式序列化)
        memConfig.Protocol = MemcachedProtocol.Binary;

        // 配置文件-权限
        //(一般情况下我们的Memcached都是部署在内网的,如果你要把一个Memcached部署到公网则需要做安全验证了)
        //memConfig.Authentication.Type = typeof(PlainTextAuthenticator);
        //memConfig.Authentication.Parameters["zone"] = "";
        //memConfig.Authentication.Parameters["userName"] = "username";
        //memConfig.Authentication.Parameters["password"] = "password";

        //下面请根据实例的最大连接数进行设置
        memConfig.SocketPool.MinPoolSize = 5;
        memConfig.SocketPool.MaxPoolSize = 200;
        MemClient = new MemcachedClient(memConfig);
    }

    /// <summary>
    /// 写入缓存 【写入方式:Set】
    /// </summary>
    /// <param name="key">键</param>
    /// <param name="value">值</param>
    public static bool Set(string key, object value)
    {
        if (!value.GetType().IsSerializable)
        {
            throw new ArgumentException("Value必须是可序列化的对象");
        }
        return MemClient.Store(StoreMode.Set, key, value);
    }

    /// <summary>
    /// 写入缓存 【写入方式:Set】
    /// </summary>
    /// <param name="key">键</param>
    /// <param name="value">值</param>
    /// <param name="expires">过期时间</param>
    public static bool Set(string key, object value, TimeSpan expires)
    {
        if (!value.GetType().IsSerializable)
        {
            throw new ArgumentException("Value必须是可序列化的对象");
        }
        return MemClient.Store(StoreMode.Set, key, value, expires);
    }

    /// <summary>
    /// 写入缓存
    /// </summary>
    /// <param name="method">写入方式
    /// set:存在则覆盖,不存在则新增
    /// Replace:如果存在则覆盖,并且返回true;如果不存在则不处理,并且返回false;
    /// Add:如果不存在则新增,并且返回true;如果存在则不处理,并且返回false;
    /// </param>
    /// <param name="key">键</param>
    /// <param name="value">值</param>
    /// <param name="expires">过期时间</param>
    public static bool Set(StoreMode method, string key, object value)
    {
        if (!value.GetType().IsSerializable)
        {
            throw new ArgumentException("Value必须是可序列化的对象");
        }
        return MemClient.Store(method, key, value);
    }

    /// <summary>
    /// 写入缓存
    /// </summary>
    /// <param name="method">写入方式
    /// set:存在则覆盖,不存在则新增
    /// Replace:如果存在则覆盖,并且返回true;如果不存在则不处理,并且返回false;
    /// Add:如果不存在则新增,并且返回true;如果存在则不处理,并且返回false;
    /// </param>
    /// <param name="key">键</param>
    /// <param name="value">值</param>
    /// <param name="expires">过期时间</param>
    public static bool Set(StoreMode method, string key, object value, TimeSpan expires)
    {
        if (!value.GetType().IsSerializable)
        {
            throw new ArgumentException("Value必须是可序列化的对象");
        }
        return MemClient.Store(method, key, value, expires);
    }


    /// <summary>
    /// 写入缓存(返回写入成功或失败的详细信息)
    /// </summary>
    /// <param name="method">写入方式
    /// set:存在则覆盖,不存在则新增
    /// Replace:如果存在则覆盖,并且返回true;如果不存在则不处理,并且返回false;
    /// Add:如果不存在则新增,并且返回true;如果存在则不处理,并且返回false;
    /// </param>
    /// <param name="key">键</param>
    /// <param name="value">值</param>
    /// <param name="expires">过期时间</param>
    /// <returns>返回写入成功或失败的详细信息</returns>
    public static IStoreOperationResult ExecuteSet(StoreMode method, string key, object value, TimeSpan expires)
    {
        if (!value.GetType().IsSerializable)
        {
            throw new ArgumentException("Value必须是可序列化的对象");
        }
        return MemClient.ExecuteStore(method, key, value, expires);
    }

    /// <summary>
    /// 读取缓存
    /// </summary>
    /// <param name="key"></param>
    public static T Get<T>(string key)
    {
        return MemClient.Get<T>(key);
    }

    /// <summary>
    /// 读取缓存
    /// </summary>
    /// <param name="key">键</param>
    public static object Get(string key)
    {
        return MemClient.Get(key);
    }

    /// <summary>
    /// 读取缓存(返回读取成功或失败的详细信息)
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="key"></param>
    /// <returns>返回读取成功或失败的详细信息</returns>
    public static IGetOperationResult<T> ExecuteGet<T>(string key)
    {
        return MemClient.ExecuteGet<T>(key);
    }

    /// <summary>
    /// 删除缓存[如果键不存在,则返回false]
    /// </summary>
    /// <param name="key">键</param>
    /// <returns>true:删除成功 false:删除失败</returns>
    public static bool Remove(string key)
    {
        return MemClient.Remove(key);
    }

    /// <summary>
    /// 删除缓存(返回删除成功或失败的详细信息)
    /// </summary>
    /// <param name="key">键</param>
    /// <returns>返回删除成功或失败的详细信息</returns>
    public static IRemoveOperationResult ExecuteRemove(string key)
    {
        return MemClient.ExecuteRemove(key);
    }
}

测试:

class Program
{
    static void Main(string[] args)
    {
        MemcacheHelper.Set("Name", "中国"); //存入数据
        var name = MemcacheHelper.Get<string>("Name");//成功获取到“中国”
    }
}

由于Memcached重启后,所有缓存数据会被清空,这样就会造成短时间内大量的请求会涌入数据库,给数据库造成压力,解决这个的方法就是使用集群,有多台Memcached 服务器提供服务。

Memcached 服务器的“雪崩”问题:

如果所有缓存设置过期时间一样,那么每隔一段时间就会造成一次数据库访问的高峰:

解决的方法就是缓存时间设置不一样,比如加上一个随机数。


Memcached 的集群实现很简单,集群节点直接不进行通讯、同步,只要在多个服务器上启动多个Memcached 服务器即可,客户端决定把数据写入不同的实例,不搞主从复制,每个数据库实例保存一部分内容。

然后mcConfig.AddServer("127.0.0.1:11211");添加多个服务器ip 地址,然后客户端根据自己的算法决定把数据写入哪个Memcached 实例,取数据库的时候再根据同样的定位算法去哪台服务器上去取。

节点定位算法有很多种,最常用的有两种Ketama、VBucket。Ketama 是根据Key 算出一个hash 值,根据hash 值再算到服务器;而VBucket 也是根据key 算出hash 值,但是不是直接根据hash 值算出服务地址,而是维护一个VBucket 表,在表中指定不同的hash 值由不同的服务器处理,还可以临时改变指向。建议用Ketama 就可以了。节点定位算法会自动处理故障服务器。

memConfig.NodeLocatorFactory = new KetamaNodeLocatorFactory()。//在配置文件中加上这段代码,它就会以Ketama算法来决定将数据保存到哪台服务器,然后取的时候去哪台服务器取了。(不需要我们自己来计算)

缓存要求都不高。


猜你喜欢

转载自blog.csdn.net/Fanbin168/article/details/80868303