分布式缓存系统 Memcached 【转发】

本文转发自

前提:先搭建好本地的单机运转品种:http://www.cnblogs.com/EasonJim/p/7643630.html

http://www.cnblogs.com/zjneter/archive/2007/07/19/822780.html

表明:下边包车型大巴演示是依照Spring
Boot搭建的,对于Spring项目基本通用。迁移旧项目标配备下1篇表明,那里先就什么高效的集成Client和收获配置的值举行实施。

 

0、上边的以身作则都是依照官方提供的课程去实施的,可以参考如下网站:

缘起:
在数据驱动的web开发中,平日要重新从数据库中取出相同的数额,那种重新不小的加码了数据库负载。缓存是缓解那一个题目标好法子。可是ASP.NET中的即使已经足以达成对页面局地进展缓存,但要么不够利索。此时Memcached可能是你想要的。
Memcached是什么? Memcached是由Danga
Interactive开发的,高品质的,分布式的内部存款和储蓄器对象缓存系统,用于在动态应用中裁减数据库负载,提高访问速度。
Memcached能缓存什么? 透过在内部存款和储蓄器里维护2个联合的皇皇的hash表,Memcached能够用来储存各类格式的数量,包蕴图像、摄像、文件以及数据库检索的结果等。
澳门美高梅手机网站,Memcached快么?
非常快。Memcached使用了libevent(假若能够的话,在linux下使用epoll)来平均任何数据的开辟链接,使用非阻塞的互连网I/O,对里面对象实现引用计数(因而,针对文山会海的客户端,对象足以处在多种的景观),
使用自个儿的页块分配器和哈希表,
由此虚拟内部存款和储蓄器不会发出碎片并且虚拟内存分配的时光复杂度能够有限援助为O(一).。
Danga Interactive为升级Danga
Interactive的速度研究开发了Memcached。近期,LiveJournal.com每日已经在向一百万用户提供多达贰仟万次的页面访问。而这几个,是由二个由web服务器和数据库服务器组成的集群完毕的。Memcached大致全盘扬弃了其它数据都从数据库读取的章程,同时,它还浓缩了用户查看页面包车型地铁速度、更加好的能源分配办公室法,以及Memcache失效时对数据库的访问速度。
Memcached的特点
Memcached的缓存是一种分布式的,可以让不一样主机上的三个用户同时做客,
由此消除了共享内部存款和储蓄器只可以单机应用的局限,更不会冒出使用数据库做类似事情的时候,磁盘耗费和围堵的发出。
Memcached的使用
Memcached服务器端的安装 (此处将其作为系统服务安装)
  下载文件:memcached 1.2.1 for Win32 binaries (Dec 23,
2006)

   壹 解压缩文件到c:\memcached
   二 命令行输入 ‘c:\memcached\memcached.exe -d install’
   三 命令行输入 ‘c:\memcached\memcached.exe -d start’ ,该命令启动Memcached ,私下认可监听端口为 1121一
  通过 memcached.exe -h 能够查看其协理
二   .NET memcached client library
   下载文件:https://sourceforge.net/projects/memcacheddotnet/

https://github.com/ctripcorp/apollo/wiki/Java%E5%AE%A2%E6%88%B7%E7%AB%AF%E4%BD%BF%E7%94%A8%E6%8C%87%E5%8D%97

   里面有.net1.1  和 .net贰.0的二种版本  还有一个不易的事例。

https://github.com/ctripcorp/apollo/wiki/Apollo%E5%BC%80%E5%8F%91%E6%8C%87%E5%8D%97#23-java%E6%A0%B7%E4%BE%8B%E5%AE%A2%E6%88%B7%E7%AB%AF%E5%90%AF%E5%8A%A8

三  应用

壹、先新建好Spring
Boot项目,那里运用了Web做测试,所以引用了Thymeleaf模板。

  1
将Commons.dll,ICSharpCode.SharpZipLib.dll,log4net.dll,Memcached.ClientLibrary.dll
等放到bin目录
  2 引用Memcached.ClientLibrary.dll
  3 代码

搭建参考:http://www.cnblogs.com/EasonJim/p/7519854.html

1 namespace Memcached.MemcachedBench
2 {
3 using System;
4 using System.Collections;
5
6 using Memcached.ClientLibrary;
7
8 public class MemcachedBench
9     {
10         [STAThread]
11 public static void Main(String[] args)
12         {
13 string[] serverlist = { “10.0.0.131:11211”, “10.0.0.132:11211” };
14
一五 //初步化池
16             SockIOPool pool = SockIOPool.GetInstance();
17             pool.SetServers(serverlist);
18
19             pool.InitConnections = 3;
20             pool.MinConnections = 3;
21             pool.MaxConnections = 5;
22
23             pool.SocketConnectTimeout = 1000;
24             pool.SocketTimeout = 3000;
25
26             pool.MaintenanceSleep = 30;
27             pool.Failover = true;
28
29             pool.Nagle = false;
30             pool.Initialize();
31
3二 // 获得客户端实例
33             MemcachedClient mc = new MemcachedClient();
34             mc.EnableCompression = false;
35
36             Console.WriteLine(“————测  试———–“);
3七             mc.Set(“test”, “my value”); 
//存储数据到缓存服务器,那里将字符串”my value”缓存,key 是”test”
38
3九 if (mc.KeyExists(“test”))   //测试缓存存在key为test的系列
40             {
41                 Console.WriteLine(“test is Exists”);
4二                 Console.WriteLine(mc.Get(“test”).ToString()); 
//在缓存中拿走key为test的项目
43             }
44 else
45             {
46                 Console.WriteLine(“test not Exists”);
47             }
48
49             Console.ReadLine();
50
51             mc.Delete(“test”);  //移除缓存中key为test的种类
52
53 if (mc.KeyExists(“test”))
54             {
55                 Console.WriteLine(“test is Exists”);
56                 Console.WriteLine(mc.Get(“test”).ToString());
57             }
58 else
59             {
60                 Console.WriteLine(“test not Exists”);
61             }
62             Console.ReadLine();
63
64             SockIOPool.GetInstance().Shutdown();  //关闭池,
关闭sockets
65         }
66     }
67 }

二、登录阿Polo上新建App和连锁的陈设项,能够参见如下配置:

  4 运营结果

澳门美高梅手机网站 1

澳门美高梅手机网站 2

三、在POM上引进Client的依靠,此时会有两个包引进Client和Core。

        <dependency>
            <groupId>com.ctrip.framework.apollo</groupId>
            <artifactId>apollo-client</artifactId>
            <version>0.8.0</version>
        </dependency>

四、在档次上布置方面安装的app.id,注意此时是经过新建META-INF/app.properties文件落实的。

澳门美高梅手机网站 3

伍、代码达成

完成的成效是透过配备中央修改后,再一次刷新页面而不重启应用的动静下能观察值的改动。

兑现形式重点二种在三种,一为经过API的花样增添监听回调函数来监听值的更动后直接修改,二为经过注入Bean的措施选用Bean下的专用监听评释落成回调监听。

5.1、通过API的方式

代码达成如下:

package com.jsoft.springboottest.springboottest1.controller;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import com.ctrip.framework.apollo.Config;
import com.ctrip.framework.apollo.ConfigChangeListener;
import com.ctrip.framework.apollo.ConfigService;
import com.ctrip.framework.apollo.model.ConfigChange;
import com.ctrip.framework.apollo.model.ConfigChangeEvent;
import com.ctrip.framework.apollo.spring.annotation.EnableApolloConfig;

@Controller
public class IndexController {

    private static final Logger logger = LoggerFactory.getLogger(IndexController.class);

    private Config config;
   private int timeout;
    private int batch;
    private String url;

    @RequestMapping(value = "/index", method = RequestMethod.GET)
    public String index(Model model) {
        Entry entry = new Entry();
        entry.setText("Text");
        entry.setTitle("Title");
        model.addAttribute("entries", entry);
        model.addAttribute("entry", new Entry());

        model.addAttribute("url", url);
        model.addAttribute("timeout",timeout);
        model.addAttribute("batch",batch);

        logger.info("timeout:{}", timeout);
        logger.info("batch:{}", batch);
        logger.info("url:{}", url);

        return "index";
    }

    public IndexController() {
        config = ConfigService.getAppConfig();
        config.addChangeListener(new ConfigChangeListener() {
            @Override
            public void onChange(ConfigChangeEvent changeEvent) {
                logger.info("Changes for namespace {}", changeEvent.getNamespace());
                for (String key : changeEvent.changedKeys()) {
                    ConfigChange change = changeEvent.getChange(key);
                    logger.info("Change - key: {}, oldValue: {}, newValue: {}, changeType: {}", change.getPropertyName(), change.getOldValue(), change.getNewValue(), change.getChangeType());

                    if (key.equals("url")) {
                        url = change.getNewValue();
                    }
                    if(key.equals("batch")) {
                        batch = Integer.valueOf(change.getNewValue());
                    }
                    if (key.equals("timeout")) {
                        timeout = Integer.valueOf(change.getNewValue());
                    }
                }                    
            }
        });
    }

}

说明:

经过新建Config对象,使用的是ConfigService.getAppConfig()获取默许配置,也正是安顿基本中的application.properties的,当然,getAppConfig能够钦命不可能的namespage。

因而获得Config对象扩充监听回调函数addChangeListener。监听钦命的值变化后,重新赋值变量。

那种措施应该是最简便易行的,不用写特殊的笺注去实现,可是可能在运营时也会发现,程序在一运维时不会去取得默许的布署值,比如timeout那一个是空的,要化解这一个题材时必要在Class上加码@Enable阿PoloConfig的笺注,然后在质量上加码@Value的值即可,改动如下:

package com.jsoft.springboottest.springboottest1.controller;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import com.ctrip.framework.apollo.Config;
import com.ctrip.framework.apollo.ConfigChangeListener;
import com.ctrip.framework.apollo.ConfigService;
import com.ctrip.framework.apollo.model.ConfigChange;
import com.ctrip.framework.apollo.model.ConfigChangeEvent;
import com.ctrip.framework.apollo.spring.annotation.EnableApolloConfig;

@Controller
@EnableApolloConfig
public class IndexController {

    private static final Logger logger = LoggerFactory.getLogger(IndexController.class);

    private Config config;

    @Value("${timeout:200}")
    private int timeout;
    @Value("${batch:200}")
    private int batch;
    @Value("${url:http://easonjim.com}")
    private String url;

    @RequestMapping(value = "/index", method = RequestMethod.GET)
    public String index(Model model) {
        Entry entry = new Entry();
        entry.setText("Text");
        entry.setTitle("Title");
        model.addAttribute("entries", entry);
        model.addAttribute("entry", new Entry());

        model.addAttribute("url", url);
        model.addAttribute("timeout",timeout);
        model.addAttribute("batch",batch);

        logger.info("timeout:{}", timeout);
        logger.info("batch:{}", batch);
        logger.info("url:{}", url);

        return "index";
    }

    public IndexController() {
        config = ConfigService.getAppConfig();
        config.addChangeListener(new ConfigChangeListener() {
            @Override
            public void onChange(ConfigChangeEvent changeEvent) {
                logger.info("Changes for namespace {}", changeEvent.getNamespace());
                for (String key : changeEvent.changedKeys()) {
                    ConfigChange change = changeEvent.getChange(key);
                    logger.info("Change - key: {}, oldValue: {}, newValue: {}, changeType: {}", change.getPropertyName(), change.getOldValue(), change.getNewValue(), change.getChangeType());

                    if (key.equals("url")) {
                        url = change.getNewValue();
                    }
                    if(key.equals("batch")) {
                        batch = Integer.valueOf(change.getNewValue());
                    }
                    if (key.equals("timeout")) {
                        timeout = Integer.valueOf(change.getNewValue());
                    }
                }                    
            }
        });
    }

}

表达:约定俗成,在@Value上取得值时记得增添暗中认可值,以免患获取为空。

上边代码只怕有些冗余,能够再提炼一下,因为config对象的值会实时更新,所以也不要求监听onChange事件,也不须要团结创制多个变量,最终代码实现如下:

package com.jsoft.springboottest.springboottest1.controller;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import com.ctrip.framework.apollo.Config;
import com.ctrip.framework.apollo.ConfigChangeListener;
import com.ctrip.framework.apollo.ConfigService;
import com.ctrip.framework.apollo.model.ConfigChange;
import com.ctrip.framework.apollo.model.ConfigChangeEvent;
import com.ctrip.framework.apollo.spring.annotation.EnableApolloConfig;

@Controller
public class IndexController2 {

    private static final Logger logger = LoggerFactory.getLogger(IndexController2.class);

    private Config config = ConfigService.getAppConfig();

    @RequestMapping(value = "/index2", method = RequestMethod.GET)
    public String index(Model model) {
        Entry entry = new Entry();
        entry.setText("Text");
        entry.setTitle("Title");
        model.addAttribute("entries", entry);
        model.addAttribute("entry", new Entry());

        model.addAttribute("url", config.getProperty("url", ""));
        model.addAttribute("timeout",config.getProperty("timeout", ""));
        model.addAttribute("batch",config.getProperty("batch", ""));

        logger.info("timeout:{}", config.getProperty("timeout", ""));
        logger.info("batch:{}", config.getProperty("batch", ""));
        logger.info("url:{}", config.getProperty("url", ""));

        return "index";
    }

}

5.2、通过注入Bean的点子

5.2.1、新建的Bean如下:

package com.jsoft.springboottest.springboottest1.controller;

import com.ctrip.framework.apollo.Config;
import com.ctrip.framework.apollo.model.ConfigChange;
import com.ctrip.framework.apollo.model.ConfigChangeEvent;
import com.ctrip.framework.apollo.spring.annotation.ApolloConfig;
import com.ctrip.framework.apollo.spring.annotation.ApolloConfigChangeListener;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;

import javax.annotation.PostConstruct;

public class AnnotatedBean {
    private static final Logger logger = LoggerFactory.getLogger(AnnotatedBean.class);

    @Value("${timeout:200}")
    private int timeout;
    private int batch;

    @ApolloConfig
    private Config config;
    @ApolloConfig("FX.apollo")
    private Config anotherConfig;

    @PostConstruct
    void initialize() {
        logger.info("timeout is {}", timeout);
        logger.info("batch is {}", batch);

        logger.info("Keys for config: {}", config.getPropertyNames());
        logger.info("Keys for anotherConfig: {}", anotherConfig.getPropertyNames());
    }

    @Value("${batch:100}")
    public void setBatch(int batch) {
        this.batch = batch;
    }

    public int getBatch() {
        return batch;
    }

    public int getTimeout() {
        return timeout;
    }

    @ApolloConfigChangeListener("application")
    private void someChangeHandler(ConfigChangeEvent changeEvent) {
        logger.info("[someChangeHandler]Changes for namespace {}", changeEvent.getNamespace());
        if (changeEvent.isChanged("timeout")) {
            refreshTimeout();
        }
        if (changeEvent.isChanged("batch")) {
            setBatch(Integer.valueOf(changeEvent.getChange("batch").getNewValue()));
        }
    }

    @ApolloConfigChangeListener({ "application", "FX.apollo" })
    private void anotherChangeHandler(ConfigChangeEvent changeEvent) {
        logger.info("[anotherChangeHandler]Changes for namespace {}", changeEvent.getNamespace());
        for (String key : changeEvent.changedKeys()) {
            ConfigChange change = changeEvent.getChange(key);
            logger.info("[anotherChangeHandler]Change - key: {}, oldValue: {}, newValue: {}, changeType: {}", change.getPropertyName(), change.getOldValue(), change.getNewValue(), change.getChangeType());
        }
    }

    private void refreshTimeout() {
        // do some custom logic to update placeholder value
        timeout = config.getIntProperty("timeout", timeout);
        logger.info("Refreshing timeout to {}", timeout);
    }
}

伍.2.2、通过@Configuration注入那些Bean,代码如下:

package com.jsoft.springboottest.springboottest1.controller;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.ctrip.framework.apollo.spring.annotation.EnableApolloConfig;

@Configuration
@EnableApolloConfig
public class AnnotatedConfig {

    @Bean
    public AnnotatedBean annotatedBean() {
        return new AnnotatedBean();
    }
}

留意:要加进@Enable阿PoloConfig和@Configuration,不然不会生效。并且留意到@Bean的表明,如若没有这些时,@ApolloConfigChangeListener不会生效。那个是关键所在,@阿PoloConfigChangeListener只好用于Bean注入上,这一个和API的办法有明显差别。

在代码上使用:

package com.jsoft.springboottest.springboottest1.controller;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class TestController {

    private static final Logger logger = LoggerFactory.getLogger(TestController.class);

    @Autowired
    private AnnotatedBean annotatedBean;

    @RequestMapping("/show")
    public String show(){

        logger.info("batch:{}",annotatedBean.getBatch());
        logger.info("timeout:{}",annotatedBean.getTimeout());

        return "Hello World"+" batch:"+annotatedBean.getBatch()+" timeout:"+annotatedBean.getTimeout();        
    }
}

表达:能够看到,只要@Autowired注入刚才的Bean就能够直接行使。

陆、运转,壹般只需求在/opt/settings/server.properties中布局了env=DEV就能够直接直接开发银行(因为Client在本地仓库的包相月经有了meta_server的音信),可是在IDE上也足以透过点名VM的参数,扩大系统品质变量-D来落到实处调节和测试,配置如下:

澳门美高梅手机网站 4

假定肆方JA福睿斯运转,直接java -jar
Spring-Boot-德姆o.jar即可,不供给追加哪些参数(但前提是布局了/opt/settings/server.properties的env的值)。

 

测试代码:https://github.com/easonjim/5_java_example/tree/master/apollotest/test1 

发表评论

电子邮件地址不会被公开。 必填项已用*标注