Zookeeper + Guava loading cache 实现分布式缓存
1. 概述
项目中,创建的活动内容存入redis,然后需要用到活动内容的地方,从redis去取,然后参与计算。
活动数据的一个特点是更新不频繁、数据量不大。因为项目部署一般是多机器、多实例,除了redis,有没有其他实现呢?
Guava的 loading cache是本地缓存,数据量不是很大时 可以适用(如果有大量的key-value数据缓存本地,本机也吃不消啊),
然后多机器多实例怎么同步呢?想到了zookeeper....
2. 代码
2.1 模拟多实例
package TestZK; import org.apache.curator.RetryPolicy;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.recipes.cache.PathChildrenCache;
import org.apache.curator.framework.recipes.cache.PathChildrenCacheEvent;
import org.apache.curator.framework.recipes.cache.PathChildrenCacheListener;
import org.apache.curator.retry.ExponentialBackoffRetry; /**
* @Author: rocky
* @Date: Created in 2018/5/20.
*/
public class InstanceOne {
private static final String ADDRESS = "xxx:2181";
private static final String PATH = "/strategy";
private static CuratorFramework client;
static {
RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 3);
client = CuratorFrameworkFactory.builder()
.connectString(ADDRESS)
.sessionTimeoutMs(5000)
.connectionTimeoutMs(5000)
.retryPolicy(retryPolicy)
// .namespace(BASE)
.build();
client.start();
} public static void main(String[] args) throws Exception {
startCache();
Thread.sleep(Integer.MAX_VALUE);
} private static void startCache() throws Exception {
PathChildrenCache childrenCache = new PathChildrenCache(client, PATH, true);
childrenCache.start();
childrenCache.getListenable().addListener(new PathChildrenCacheListener() {
public void childEvent(CuratorFramework curatorFramework, PathChildrenCacheEvent event) throws Exception {
System.out.println("catch that: the path of changed node "+ event.getData().getPath()
+ ", the data of changed node is " + new String(event.getData().getData()));
//load data to loading cache(guava)
doSomething();
}
});
}
//load data to loading cache
private static void doSomething() {
// LoadingCache<String, Map<Integer, DriverIntegral>> driverIntegralCache = CacheBuilder.newBuilder().maximumSize(500)
// .expireAfterWrite(5, TimeUnit.MINUTES).build(new CacheLoader<String, Map<Integer, DriverIntegral>>() {
// @Override
// public Map<Integer, DriverIntegral> load(String key) throws Exception {
// Map<Integer, DriverIntegral> integerDriverIntegralMap = ..;
// logger.info("guava load ::driverIntegralMap"+integerDriverIntegralMap!=null?integerDriverIntegralMap.toString():"");
// return integerDriverIntegralMap;
// }
// });
//
// Map<Integer, DriverIntegral> driverIntegralMap = driverIntegralCache.get(INTEGRAL);
}
} package TestZK; import org.apache.curator.RetryPolicy;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.recipes.cache.PathChildrenCache;
import org.apache.curator.framework.recipes.cache.PathChildrenCacheEvent;
import org.apache.curator.framework.recipes.cache.PathChildrenCacheListener;
import org.apache.curator.retry.ExponentialBackoffRetry; /**
* @Author: rocky
* @Date: Created in 2018/5/20.
*/
public class InstanceTwo {
private static final String ADDRESS = "xxx:2181";
private static final String PATH = "/strategy";
private static CuratorFramework client;
static {
RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 3);
client = CuratorFrameworkFactory.builder()
.connectString(ADDRESS)
.sessionTimeoutMs(5000)
.connectionTimeoutMs(5000)
.retryPolicy(retryPolicy)
// .namespace(BASE)
.build();
client.start();
} public static void main(String[] args) throws Exception {
startCache();
Thread.sleep(Integer.MAX_VALUE);
} private static void startCache() throws Exception {
PathChildrenCache childrenCache = new PathChildrenCache(client, PATH, true);
childrenCache.start();
childrenCache.getListenable().addListener(new PathChildrenCacheListener() {
public void childEvent(CuratorFramework curatorFramework, PathChildrenCacheEvent event) throws Exception {
System.out.println("catch that: the path of changed node "+ event.getData().getPath()
+ ", the data of changed node is " + new String(event.getData().getData()));
}
});
}
} package TestZK; import org.apache.curator.RetryPolicy;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.recipes.cache.PathChildrenCache;
import org.apache.curator.framework.recipes.cache.PathChildrenCacheEvent;
import org.apache.curator.framework.recipes.cache.PathChildrenCacheListener;
import org.apache.curator.retry.ExponentialBackoffRetry; /**
* @Author: rocky
* @Date: Created in 2018/5/20.
*/
public class InstanceThree {
private static final String ADDRESS = "xxx:2181";
private static final String PATH = "/strategy";
private static CuratorFramework client;
static {
RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 3);
client = CuratorFrameworkFactory.builder()
.connectString(ADDRESS)
.sessionTimeoutMs(5000)
.connectionTimeoutMs(5000)
.retryPolicy(retryPolicy)
// .namespace(BASE)
.build();
client.start();
} public static void main(String[] args) throws Exception {
startCache();
Thread.sleep(Integer.MAX_VALUE);
} private static void startCache() throws Exception {
PathChildrenCache childrenCache = new PathChildrenCache(client, PATH, true);
childrenCache.start();
childrenCache.getListenable().addListener(new PathChildrenCacheListener() {
public void childEvent(CuratorFramework curatorFramework, PathChildrenCacheEvent event) throws Exception {
System.out.println("catch that: the path of changed node is "+ event.getData().getPath()
+ ", the data of changed node is " + new String(event.getData().getData()));
}
});
}
}
监听zk孩子节点,有变化时(创建、更新、删除),重新从DB加载活动数据,缓存到loading cache,用到活动数据的地方,从cache中取。
2.2 模拟客户端
package TestZK; import org.apache.curator.RetryPolicy;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.retry.ExponentialBackoffRetry; /**
* @Author: rocky
* @Date: Created in 2018/5/20.
*/
public class NodeChangeTest {
private static final String ADDRESS = "xxx:2181";
private static final String PATH = "/strategy";
private static CuratorFramework client;
static {
RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 3);
client = CuratorFrameworkFactory.builder()
.connectString(ADDRESS)
.sessionTimeoutMs(5000)
.connectionTimeoutMs(5000)
.retryPolicy(retryPolicy)
// .namespace(BASE)
.build();
client.start();
} public static void main(String[] args) throws Exception {
String path_node_1 = PATH + "/node_1";
//create
client.create().creatingParentsIfNeeded().forPath(path_node_1);
Thread.sleep(2000);
//change
client.setData().forPath(path_node_1, "yahahaha".getBytes());
Thread.sleep(2000);
//delete
client.delete().forPath(path_node_1);
Thread.sleep(Integer.MAX_VALUE);
}
}
客户端实际上可能是某个后台,在后台创建、修改、或删除某活动,然后对应操作zookeeper节点,其他监听到节点变化的地方,做相应操作(如查询DB并缓存数据)
控制台

3. 说明
Zookeeper原生的API只能实现一次监听,这里用到的Curator的封装jar包,免去了手动重复注册。另外Curator的NodeCache和TreeCache分别监听本节点及分支所有节点,
该实例演示的PathChildrenCache只能监控一级子节点(即儿子节点、孙子节点也不能监控),根据需要选择相应NodeCache.
很low的实现,请多指教^_^
Zookeeper Curator API 使用 www.cnblogs.com/rocky-fang/p/9037509.html
Zookeeper JAVA API的使用 http://www.cnblogs.com/rocky-fang/p/9030438.html
Zookeeper + Guava loading cache 实现分布式缓存的更多相关文章
- 基于redis分布式缓存实现
Redis的复制功能是完全建立在之前我们讨论过的基 于内存快照的持久化策略基础上的,也就是说无论你的持久化策略选择的是什么,只要用到了Redis的复制功能,就一定会有内存快照发生,那么首先要注意你 的 ...
- 分布式缓存重建并发冲突和zookeeper分布式锁解决方案
如果缓存服务在本地的ehcache中都读取不到数据. 这个时候就意味着,需要重新到源头的服务中去拉去数据,拉取到数据之后,赶紧先给nginx的请求返回,同时将数据写入ehcache和redis中 分布 ...
- 本地缓存google.guava及分布式缓存redis 随笔
近期项目用到了缓存,我选用的是主流的google.guava作本地缓存,redis作分布式 缓存,先说说我对本地缓存和分布式缓存的理解吧,可能不太成熟的地方,大家指出,一起 学习.本地缓存的特点是速度 ...
- 【开源项目系列】如何基于 Spring Cache 实现多级缓存(同时整合本地缓存 Ehcache 和分布式缓存 Redis)
一.缓存 当系统的并发量上来了,如果我们频繁地去访问数据库,那么会使数据库的压力不断增大,在高峰时甚至可以出现数据库崩溃的现象.所以一般我们会使用缓存来解决这个数据库并发访问问题,用户访问进来,会先从 ...
- 分布式缓存HttpRuntime.cache应用到单点登陆中_优化登陆
以前的设计方案,是我们在数据库中放一个表,用作存储验证登陆成功的用户,并且生成用户TOKEN(令牌) 分布式缓存+集群的解决方案图: 相应的代码: DE层中配置文件: receiveTimeout=& ...
- Distributed Cache(分布式缓存)-SqlServer
分布式缓存是由多个应用服务器共享的缓存,通常作为外部服务存储在单个应用服务器上,常用的有SqlServer,Redis,NCache. 分布式缓存可以提高ASP.NET Core应用程序的性能和可伸缩 ...
- Flink分布式缓存Distributed Cache
1 分布式缓存 Flink提供了一个分布式缓存,类似于hadoop,可以使用户在并行函数中很方便的读取本地文件,并把它放在taskmanager节点中,防止task重复拉取. 此缓存的工作机制如下:程 ...
- 用guava快速打造两级缓存能力
首先,咱们都有一共识,即可以使用缓存来提升系统的访问速度! 现如今,分布式缓存这么强大,所以,大部分时候,我们可能都不会去关注本地缓存了! 而在一起高并发的场景,如果我们一味使用nosql式的缓存,如 ...
- Guava的两种本地缓存策略
Guava的两种缓存策略 缓存在很多场景下都需要使用,如果电商网站的商品类别的查询,订单查询,用户基本信息的查询等等,针对这种读多写少的业务,都可以考虑使用到缓存.在一般的缓存系统中,除了分布式缓存, ...
随机推荐
- Laravel 的核心概念
工欲善其事,必先利其器.在开发Xblog的过程中,稍微领悟了一点Laravel的思想.确实如此,这篇文章读完你可能并不能从无到有写出一个博客,但知道Laravel的核心概念之后,当你再次写起Larav ...
- QuantLib 金融计算——数学工具之插值
目录 QuantLib 金融计算--数学工具之插值 概述 一维插值方法 二维插值方法 如果未做特别说明,文中的程序都是 Python3 代码. QuantLib 金融计算--数学工具之插值 载入模块 ...
- Flask中的before_request装饰器和after_request装饰器以及WTForms组件
一.before_request装饰器和after_request装饰器 我们现在有一个Flask程序其中有3个路由和视图函数 from flask import Flask app = Flask( ...
- 毫秒查询9位数qq号码是否存在-BitMap算法应用
实现详情请查看博客园 https://www.cnblogs.com/caoke/p/10793885.html 随机注册10万个放入BitMap,然后查询qq号码是否已存在,算法复杂度O(1). / ...
- 【Sonarqube】windows下更改Temp文件夹的位置
下载的最新Sonarqube版本(4.5.1),通过StartSonar.bat文件可以启动,但是无法通过StartNTService.bat文件启动,原因为默认的Temp文件不可写入, java.l ...
- mp3转speex的一些研究(貌似不能播放,暂存着)
思路是,先从mp3中提取pcm(raw原始数据),再将原始数据转成speex. 貌似不能播放,可能还存在其他问题,需要继续研究. 使用了两个类库NSpeex和NAudio using (var wav ...
- android 签名验证防止重打包
网上资料很多,这里只做一个笔记反编译 dex 修改重新打包签名后 apk 的签名信息肯定会改变,所以可以在代码中判断签名信息是否被改变过,如果签名不一致就退出程序,以防止 apk 被重新打包. 1 j ...
- Bug解决方案:org.xml.sax.SAXParseException; lineNumber: 1; columnNumber: 8; 不允许有匹配 "[xX][mM][lL]" 的处理指令目标
十月 17, 2016 10:14:30 下午 org.springframework.context.support.AbstractApplicationContext prepareRefres ...
- HttpClient使用详细教程
Http协议的重要性相信不用我多说了,HttpClient相比传统JDK自带的URLConnection,增加了易用性和灵活性(具体区别,日后我们再讨论),它不仅是客户端发送Http请求变得容易,而且 ...
- android开发之提高应用启动速度_splash页面瞬间响应_避免APP启动闪白屏
Application和Activity中的onCreate都进行了优化,基本没有耗时操作,但是启动应用之后还是会闪现一下白色背景,然后才进入Splash页面,对比了一下QQ.微信.微博等客户端,点击 ...