基于XMemcache 的分布式 Memcache的实现

来源:互联网 发布:adobe pl是什么软件 编辑:程序博客网 时间:2024/04/28 08:55

MemcachedClientKeeper 完成对XMemcached连接的保持,并提供心跳 维护自身状态

Java代码 复制代码 收藏代码
  1. package com.iuwcity.memcached.group;   
  2.   
  3. import java.io.IOException;   
  4. import java.net.InetSocketAddress;   
  5. import java.util.Map;   
  6. import java.util.concurrent.Callable;   
  7. import java.util.concurrent.Executors;   
  8. import java.util.concurrent.ScheduledExecutorService;   
  9. import java.util.concurrent.TimeUnit;   
  10.   
  11. import net.rubyeye.xmemcached.XMemcachedClient;   
  12.   
  13. public class MemcachedClientKeeper {   
  14.        
  15.     public static final String OP_SUC = "0";   
  16.        
  17.     public static final String OP_FAL = "1";   
  18.   
  19.     private XMemcachedClient client;   
  20.        
  21.     private String host;   
  22.        
  23.     private int port;   
  24.   
  25.     private long breathTime = 5;   
  26.   
  27.     private long initalTime = 5;   
  28.        
  29.     private int breathBreakThreshold = 5//心跳异常允许的次数  
  30.        
  31.     private int breathBreak = 0//当前心跳异常次数  
  32.   
  33.     private int status = MemcachedGroup.READ_WRITE;   
  34.        
  35.     private int beforeStatus = status;   
  36.   
  37.     private BreathLogic breathLogic = new BreathLogic();   
  38.        
  39.     public PutLogic putLogic = new PutLogic("",0,"");   
  40.        
  41.     public GetLogic getLogic = new GetLogic("");   
  42.   
  43.     private ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);   
  44.        
  45.     private boolean isLaunched = false;   
  46.   
  47.     public MemcachedClientKeeper(final String host, final int port) throws IOException {   
  48.         this.host = host;   
  49.         this.port = port;   
  50.         this.client = new XMemcachedClient(host, port);   
  51.     }   
  52.   
  53.     public XMemcachedClient getClient() {   
  54.         return client;   
  55.     }   
  56.   
  57.     public long getBreathTime() {   
  58.         return breathTime;   
  59.     }   
  60.   
  61.     public void setBreathTime(long breathTime) {   
  62.         this.breathTime = breathTime;   
  63.     }   
  64.   
  65.     public long getInitalTime() {   
  66.         return initalTime;   
  67.     }   
  68.   
  69.     public void setInitalTime(long initalTime) {   
  70.         this.initalTime = initalTime;   
  71.     }   
  72.   
  73.     public int getStatus() {   
  74.         return status;   
  75.     }   
  76.   
  77.     public void setStatus(int status) {   
  78.         this.status = status;   
  79.     }   
  80.        
  81.        
  82.     public int getBreathBreakThreshold() {   
  83.         return breathBreakThreshold;   
  84.     }   
  85.   
  86.     public void setBreathBreakThreshold(int breathBreakThreshold) {   
  87.         this.breathBreakThreshold = breathBreakThreshold;   
  88.     }   
  89.   
  90.     public int getBreathBreak() {   
  91.         return breathBreak;   
  92.     }   
  93.   
  94.     public void setBreathBreak(int breathBreak) {   
  95.         this.breathBreak = breathBreak;   
  96.     }   
  97.   
  98.     /**  
  99.      * 启动  
  100.      */  
  101.     public void launch(){   
  102.         if(!isLaunched){   
  103.             scheduler.scheduleAtFixedRate(this.breathLogic, this.initalTime,   
  104.                     this.breathTime, TimeUnit.SECONDS);   
  105.             isLaunched = !isLaunched;   
  106.         }   
  107.     }   
  108.        
  109.     public BreathLogic getBreathLogic() {   
  110.         return breathLogic;   
  111.     }   
  112.   
  113.     public void setBreathLogic(BreathLogic breathLogic) {   
  114.         this.breathLogic = breathLogic;   
  115.     }   
  116.        
  117.   
  118.     public ScheduledExecutorService getScheduler() {   
  119.         return scheduler;   
  120.     }   
  121.   
  122.     public void setScheduler(ScheduledExecutorService scheduler) {   
  123.         this.scheduler = scheduler;   
  124.     }   
  125.        
  126.   
  127.     public String getHost() {   
  128.         return host;   
  129.     }   
  130.   
  131.     public void setHost(String host) {   
  132.         this.host = host;   
  133.     }   
  134.   
  135.     public int getPort() {   
  136.         return port;   
  137.     }   
  138.   
  139.     public void setPort(int port) {   
  140.         this.port = port;   
  141.     }   
  142.   
  143.     public int getBeforeStatus() {   
  144.         return beforeStatus;   
  145.     }   
  146.   
  147.     public void setBeforeStatus(int beforeStatus) {   
  148.         this.beforeStatus = beforeStatus;   
  149.     }   
  150.   
  151.   
  152.   
  153.     /**  
  154.      * 心跳逻辑  
  155.      *   
  156.      * @author xuchen  
  157.      *   
  158.      */  
  159.     public class BreathLogic implements Runnable {   
  160.   
  161.         public void run() {   
  162.             try {   
  163.                 Map<String,String> stat = client.stats(new InetSocketAddress(host,port));   
  164.                 System.out.println("breath : " + stat);   
  165.             } catch (Exception e) {   
  166.                 //心跳异常    
  167.                 breathBreak ++;   
  168.                 if(breathBreak >= breathBreakThreshold ){ //达到允许次数  
  169.                     breathBreak = 0;   
  170.                     //记录服务节点之前的状态   
  171.                     beforeStatus = status;   
  172.                     status = MemcachedGroup.NOT_READY;   
  173.                        
  174.                     //todo 发出报警   
  175.                 }   
  176.                 e.printStackTrace();   
  177.                 return ;   
  178.             }   
  179.             //判断如果服务器正常 则恢复到出现问题之前的状态   
  180.             if(MemcachedGroup.NOT_READY == status){   
  181.                 status = beforeStatus;   
  182.             }   
  183.         }   
  184.   
  185.     }   
  186.        
  187.     public class PutLogic implements Callable<Object> {   
  188.            
  189.         private String key ;   
  190.            
  191.         private int exp = 0;   
  192.            
  193.         private Object value;   
  194.            
  195.            
  196.         public String getKey() {   
  197.             return key;   
  198.         }   
  199.   
  200.         public void setKey(String key) {   
  201.             this.key = key;   
  202.         }   
  203.   
  204.         public int getExp() {   
  205.             return exp;   
  206.         }   
  207.   
  208.         public void setExp(int exp) {   
  209.             this.exp = exp;   
  210.         }   
  211.   
  212.         public Object getValue() {   
  213.             return value;   
  214.         }   
  215.   
  216.         public void setValue(Object value) {   
  217.             this.value = value;   
  218.         }   
  219.   
  220.         public PutLogic(final String key,final Object value){   
  221.             this(key,0,value);   
  222.         }   
  223.            
  224.         public PutLogic(final String key,final int exp,final Object value){   
  225.             this.key = key;   
  226.             this.exp = exp;   
  227.             this.value = value;   
  228.         }   
  229.   
  230.         public Object call() throws Exception {   
  231.             try {   
  232.                 if(client.add(key, exp, value)){   
  233.                     return OP_SUC + "|" + host + ":" + port;   
  234.                 }else {   
  235.                     return OP_FAL + "|" + host + ":" + port;   
  236.                 }   
  237.             }catch (Exception e){   
  238.                 e.printStackTrace();   
  239.                 return OP_FAL + "|" + host + ":" + port;   
  240.             }   
  241.         }   
  242.            
  243.     }   
  244.        
  245.     /**  
  246.      * @author xuchen  
  247.      *  
  248.      */  
  249.     public class GetLogic implements Callable<Object> {   
  250.            
  251.         private String key;   
  252.            
  253.         public String getKey() {   
  254.             return key;   
  255.         }   
  256.   
  257.         public void setKey(String key) {   
  258.             this.key = key;   
  259.         }   
  260.   
  261.            
  262.         public GetLogic(final String key){   
  263.             this.key = key;   
  264.         }   
  265.   
  266.         public Object call() throws Exception {   
  267.             return client.get(this.key);   
  268.         }   
  269.            
  270.     }   
  271.   
  272. }  

 

MemcachedGroupHandle 保持一组Keeper 简单的操作 put/get 

put方式只是遍历当前可写节点进行写操作

 

get方式也比较简单 对可读的节点 目前默认取第一个 进行读

 

Java代码 复制代码 收藏代码
  1. package com.iuwcity.memcached.group;   
  2.   
  3. import java.io.IOException;   
  4. import java.util.ArrayList;   
  5. import java.util.List;   
  6. import java.util.concurrent.ExecutorService;   
  7. import java.util.concurrent.Executors;   
  8. import java.util.concurrent.Future;   
  9.   
  10. import net.rubyeye.xmemcached.XMemcachedClient;   
  11.   
  12. public class MemcachedGroupHandle implements MemcachedGroup {   
  13.   
  14.     // FIX ME   
  15.     private List<MemcachedClientKeeper> serverKeepers = new ArrayList<MemcachedClientKeeper>();   
  16.   
  17.     private ExecutorService service = Executors.newCachedThreadPool();   
  18.   
  19.     public void addServer(final String host, final int port) throws IOException {   
  20.         MemcachedClientKeeper keeper = new MemcachedClientKeeper(host, port);   
  21.         this.addServer(keeper);   
  22.     }   
  23.   
  24.     public void addServer(MemcachedClientKeeper keeper) throws IOException {   
  25.         keeper.launch();   
  26.         this.serverKeepers.add(keeper);   
  27.     }   
  28.   
  29.     public void putByFuture(final String key, final int exp, final Object value) throws Exception {   
  30.   
  31.         List<Future<Object>> futures = new ArrayList<Future<Object>>();   
  32.   
  33.         // 遍历所有服务器进行写操作 此处有待优化   
  34.         for (MemcachedClientKeeper keeper : serverKeepers) {   
  35.             if (keeper.getStatus() != MemcachedGroup.NOT_READY && keeper.getStatus() != MemcachedGroup.READ_ONLY) {   
  36.                 keeper.putLogic.setKey(key);   
  37.                 keeper.putLogic.setExp(exp);   
  38.                 keeper.putLogic.setValue(value);   
  39.                 Future<Object> f = service.submit(keeper.putLogic);   
  40.                 futures.add(f);   
  41.             }   
  42.         }   
  43.   
  44.         for (Future<Object> f : futures) {   
  45.             if (f.get() != null) {   
  46.                 String result = f.get().toString();   
  47.                 if (result.startsWith(MemcachedClientKeeper.OP_FAL)) {   
  48.                     // 写失败操作   
  49.                 }   
  50.             }   
  51.         }   
  52.     }   
  53.        
  54.     /**  
  55.      * 遍历第一个可读节点即返回  
  56.      * @param key  
  57.      * @return  
  58.      * @throws Exception  
  59.      */  
  60.     public Object getByFuture(final String key) throws Exception {   
  61.   
  62.         // 遍历所有服务器进行写操作 此处有待优化   
  63.         for (MemcachedClientKeeper keeper : serverKeepers) {   
  64.             if (keeper.getStatus() != MemcachedGroup.NOT_READY && keeper.getStatus() != MemcachedGroup.WRITE_ONLY) {   
  65.                 keeper.getLogic.setKey(key);   
  66.                 Future<Object> f = service.submit(keeper.getLogic);   
  67.                 return f.get();   
  68.             }   
  69.         }   
  70.         return null;   
  71.     }   
  72.        
  73.     /**  
  74.      * 遍历第一个可读节点即返回  
  75.      * @param key  
  76.      * @return  
  77.      * @throws Exception  
  78.      */  
  79.     public Object get(final String key) throws Exception {   
  80.   
  81.         // 遍历所有服务器进行写操作 此处有待优化   
  82.         for (MemcachedClientKeeper keeper : serverKeepers) {   
  83.             if (keeper.getStatus() != MemcachedGroup.NOT_READY && keeper.getStatus() != MemcachedGroup.WRITE_ONLY) {   
  84.                 return keeper.getClient().get(key);   
  85.             }   
  86.         }   
  87.         return null;   
  88.     }   
  89.   
  90.     public void put(final String key, final int exp, final Object value) throws Exception {   
  91.   
  92.         // 遍历所有服务器进行写操作 此处有待优化   
  93.         for (MemcachedClientKeeper keeper : serverKeepers) {   
  94.             if (keeper.getStatus() != MemcachedGroup.NOT_READY && keeper.getStatus() != MemcachedGroup.READ_ONLY) {   
  95.                 XMemcachedClient client = keeper.getClient();   
  96.                 if(client.add(key, exp, value)){   
  97.                     //todo写异常   
  98.                        
  99.                 }   
  100.                    
  101.             }   
  102.         }   
  103.     }   
  104.   
  105.     public ExecutorService getService() {   
  106.         return service;   
  107.     }   
  108.   
  109.     public void setService(ExecutorService service) {   
  110.         this.service = service;   
  111.     }   
  112.   
  113. }  

 

还有个接口类 方法定义没家进去 里边还有很多FIXME TODO 主要看看大家的看法 听说XMemcached 的作者要加入集群功能了 首先对此表示非常的感谢

 

Java代码 复制代码 收藏代码
  1. package com.iuwcity.memcached.group;   
  2.   
  3. public interface MemcachedGroup {   
  4.        
  5.     public static final int READ_ONLY = 1;   
  6.        
  7.     public static final int WRITE_ONLY = 2;   
  8.        
  9.     public static final int READ_WRITE = 3;   
  10.        
  11.     public static final int NOT_READY = 4;   
  12.        
  13.     public static final int WRITE_NO_READ = 5;   
  14.        
  15. }  

 

公司要求可能要用到集群 自己无聊写了一个 与ali的机群客户端一起测试过 由于是基于XMemcached 所以在多线程下速度相对ali较高 

 

欢迎大家给点看法

 

附件里有写代码是没用的 不用看 就这三类有用