Redis3
Redis到底该如何利用
上两篇受益匪浅,秉着趁热打铁,不挖到最深不罢休的精神,我决定追加这篇。上一篇里最后我有提到实现分级缓存管理应该是个可行的方案,因此今天特别实践了一下。不过缓存分级之后也发现了一些问题,例如下图:

当appServerA修改了数据,并同步到Redis/DB之后,如何让appServerB也能更新本地缓存呢?虽然Redis的出现是为了解决这个问题的,但是分级方案里,MemoryCache还是需要保留。那么如何保存呢?我尝试了下面的几种方式,现在我们逐一来看。
全数据增量同步
所谓全数据校验,即所有的缓存数据首先都同步至Redis,然后根据数据的时间戳来进行同步。分解步骤如下:
- 首先将缓存的数据初始化,同步至Redis和MemoryCache,保持初始数据的同步
- 第二步,每当操作了数据之后,给记录一个时间戳标识最近的更新。
- MemoryCache定时或者每次取数据的时候,以最近的一个同步的时间戳开始同步到现在的时间戳
上面的方案咱们落地到.NET+Redis又该怎么处理呢?
第一步很简单直接跳过,第二步就有点问题了,这个时间戳要便于redis的排序和获取,考虑到这些问题,我觉得取Linux的数字型时间戳比较靠谱,再配合SortSet来建立索引,进行同步,看起来的确不错。那么来看下代码:
本篇还是以User为例,可能场景不适合,大家将就理解

public void UpdateToRedis(User user)
{
var redis = ConnectionMultiplexer.Connect("localhost");
var db = redis.GetDatabase(); TimeSpan ts = DateTime.Now.ToUniversalTime() - new DateTime(1970, 1, 1, 0, 0, 0, 0);
double time = Convert.ToInt64(ts.TotalSeconds);//计算Unix时间戳
db.SortedSetAdd("capqueen:user:index", user.Id, time);//更新记录
var json = JsonConvert.SerializeObject(user);
db.StringSet("capqueen:user" + user.Id, json);//user记录
}

同步:

public void Sync(double timespan)
{
var redis = ConnectionMultiplexer.Connect("localhost");
var db = redis.GetDatabase(); TimeSpan ts = DateTime.Now.ToUniversalTime() - new DateTime(1970, 1, 1, 0, 0, 0, 0);
double time = Convert.ToInt64(ts.TotalSeconds);//计算Unix时间戳 //同步时间范围内的记录,这里增加时间范围,以防止一些数据不准确的问题
var members = db.SortedSetRangeByScore("capqueen:user:index", timespan, time); var keys = members.ToList().Select<RedisValue, RedisKey>(i => i.ToString());
var values = db.StringGet(keys.ToArray()); //构造List Json以加速解析
var portsJson = new StringBuilder("["); values.ToList().ForEach(item =>
{
if (!string.IsNullOrWhiteSpace(item))
{
portsJson.Append(item).Append(",");
}
}); portsJson.Append("]"); var users = JsonConvert.DeserializeObject<List<User>>(portsJson.ToString()); //和内存的List<User>做同步
...
//END
}

上面的代码只是实例,实际运行的时候感觉还不是特别靠谱。
消息通知
增量同步是好,但是同时时机也是个问题,时机不对,就会影响用户体验。而且感觉我们还是无法很好的掌控数据。那么有没有一种方式可以及时的通知到appServer更新缓存呢?这里我脑子里冒出来的是.NET Event机制。
我觉得.NET因为有了优秀的Event机制,才让我觉得它使用起来很方便
但是这里是服务器之间的通信,我想非Scoket莫属了,之间做过Scoket双向通信,印象特别深刻,这样的场景让我自然而然的想到了这个方案。可是特别的增加一个socket,本身复杂的架构要更复杂了,还是寻求一个靠谱的中间件比较适合。看过Redis的功能列表的同学,一定没忘记Redis还有一个订阅发布,pub/sub功能。于是我就利用了这个功能,设计了如下的方案:
- 为app增加一个sub线程,用于接收redis订阅消息
- 在每一个缓存对象更新的同时,增加异步pub消息到redis
先来看下Redis的,pub/sub功能,请看文档
redis提供指定channel的订阅发布功能,每一个Client可以订阅指定的channel消息,也可以向指定的channel发送消息。
利用ServiceStack.Redis的pub/sub功能实现如下:

using (var redisConsumer = new RedisClient(TestConfig.SingleHost))
using (var subscription = redisConsumer.CreateSubscription())
{
subscription.OnSubscribe = channel =>
{
//订阅事件
};
subscription.OnUnSubscribe = channel =>
{
//退订事件
};
subscription.OnMessage = (channel, msg) =>
{
// 这里的msg,我为了测试定义成了userid
var user= redisConsumer.As<User>().GetById(msg);//从Redis获取记录
UpdateLocalCache(user);//更新本地
}; subscription.SubscribeToChannels("capqueen:redis:events"); //blocking
}

发送:
using (var redisPublisher = new RedisClient("localhost"))
{
redisPublisher.PublishMessage("capqueen:redis:events", userId);//发送消息
}
这里我觉得message应该定义成一个消息体,接收处理应该根据具体的消息定义来具体处理,因为订阅发布的通道显然应该是合理利用,如果一个业务一个通道,有点太多了。
当然这个实现起来又要讲一大篇了,这里不多说明。
总结
本篇文章,根据上一篇提的方案做了一些实现,不足之处太多了。例如事件丢了怎么办?如何正确的处理消息缺失,记录少了之类的特殊情况应该是很重要的。我暂时还没想到方案,不知道前辈们如何看待这样的问题。可能我还是滥用了Redis,为了技术而技术了,不过不尝试碰下壁,怎么能得到成长。所谓兼听则明 偏信则暗,我感觉自己有点不见棺材不落泪了。请前辈们不吝指教!
Redis3的更多相关文章
- 烂泥:redis3.2.3安装与配置
本文由ilanniweb提供友情赞助,首发于烂泥行天下 想要获得更多的文章,可以关注我的微信ilanniweb 前一段时间写过一篇codis集群的文章,写那篇文章主要是因为当时的项目不支持redis自 ...
- CentOS 6.5 安装 Redis-3.2.6
到官网下载最新版的 Redis-3.2.6, 我把它放到文件夹:/usr/local/src/centos-sdk/source2/redis 安装脚本 redis-3.2.6.sh #!/bin/b ...
- Redis3重建Cluster
1.关闭cluster全部节点2.删除所有nodes.conf文件3.开启全部节点4.依次flushall5.重建集群即可 Share the post "Redis3重建Cluster&q ...
- 在 CentOS7 之部署 Redis3
CentOS7 之 Redis3 学习笔记 1 Redis 官网: http://www.redis.io/ 2 Redis 的下载地址: http://download.redis.io/relea ...
- Redis3 本地安装集群的记录
引用CSDN文章 环境 centos6.7 目标 redis 三主三从的集群 step 1 编译,如果出错,则根据提示安装依赖 tar -zxvf redis-3.0.0.tar.gz mv redi ...
- CentOS 7 上安装 redis3.2.3安装与配置
前一段时间写过一篇codis集群的文章,写那篇文章主要是因为当时的项目不支持redis自身集群的功能. 而现在最新的项目是需要redis集群的,这篇文章我们就来介绍下有关redis的安装与配置. 一. ...
- Mac Pro 编译安装 Redis-3.2.3
Redis官方下载地址:http://redis.io/download Redis安装 cd /usr/local/src/redis-3.2.3 sudo make sudo make insta ...
- Redis3.0 配置文件说明
背景: 以前有篇文章已经结果过了,现在复习一下,对Redis3.0进行说明: 参数说明: #redis.conf # Redis configuration file example. # ./red ...
- redis-3.2.5 make 报错
make[]: Entering directory `/usr/local/src/redis-/src' CC adlist.o In file included : zmalloc.h::: e ...
- redis3.0.6安装(linux和windows)
官网上描述安装方法如下:$ wget http://download.redis.io/releases/redis-3.0.6.tar.gz$ tar xzf redis-3.0.6.tar.gz$ ...
随机推荐
- 读改善c#代码157个建议:建议7~9
目录: 建议7:将0值作为枚举的默认值 建议8:避免给枚举类型的元素提供显示的值 建议9:习惯运算符重载 一.建议7:将0值作为枚举的默认值 允许使用的枚举类型有:byte.sbyte.short.u ...
- android4.4组件分析--service组件-bindService源代码分析
6.1.1. bindService 由于有前面分析startService的代码实现过程,则对于bindService的代码分析就不用那么具体介绍,在介绍流程的同一时候更关注一些细节上的部分. ...
- 【SSH2(理论+实践)】--Hibernate步步(一个)
前几个博客讨论SSH2该框架Struts,它代表层,集成封装.和使用WebWork作为核心处理,依赖映射是它的处理核心.在使用时需要Struts.xml配置相应Action和Interceptor够完 ...
- VB6基本数据库应用(五):数据的查找与筛选
同系列的第五篇,上一篇在:http://blog.csdn.net/jiluoxingren/article/details/9633139 数据的查找与筛选 第4篇发布到现在已经过了4天,很抱歉,学 ...
- c++读取文本文件
#include<iostream> #include<fstream> using namespace std; int main() { int a,b=-100000,c ...
- JavaScript-2.2 document.write 输出到页面的内容
<html> <head> <meta http-equiv="content-type" content="text/html;chars ...
- 采用Visual Stuidio 2010 创建网站栏
采用Visual Stuidio 2010 创建网站栏 Visual Stuidio 2010 该项目模板使创建网站栏/内容类型和列表变得非常方便. 1. 管理员身份打开Visual Stuidio ...
- iOS学习 plist读取和写入文件
干iOS开发时间.后经常用来plist文件, 那plist什么文件是它? 它的全称是:Property List.属性列表文件.它是一种用来存储串行化后的对象的文件.属性列表文件的扩展名为.plis ...
- GeeksforGeeks - Adjacency List邻接矩阵C\C++代码
邻接矩阵的图示: 构建一个这种无向邻接矩阵. 參考站点: http://www.geeksforgeeks.org/graph-and-its-representations/ 这里写了个类,添加删除 ...
- VS解决方案创建
示例VS解决方案的创建(一) 进行项目开发的第一步,是创建出适合自己团队习惯的VS解决方案,虽然我已经提供了项目示例,但毕竟是我创建的,你直接使用可能并不合适,另外你如果尝试模仿重新创建该示例,中 ...