欢迎投稿

今日深度:

Redis源码分析(十七)--- multi事务操作,redismul

Redis源码分析(十七)--- multi事务操作,redismulti


        redis作为一非关系型数据库,竟然同样拥有与RDBMS的事务操作,不免让我觉得比较惊讶。在redis就专门有文件就是执行事务的相关操作的。也可以让我们领略一下,在Redis的代码中是如何实现事务操作。首先亮出mulic.c下面的一些API。

/* ================================ MULTI/EXEC ============================== */
void initClientMultiState(redisClient *c) /* 初始化客户端操作 */
void freeClientMultiState(redisClient *c) /* 释放客户端所有与multi/exec相关的资源 */
void queueMultiCommand(redisClient *c) /* 客户端的multi命令队列添加一条新的命令 */
void discardTransaction(redisClient *c) /* 撤销事务操作 */
void flagTransaction(redisClient *c) /* 标记一个事物为DIRTY_EXEC状态,最后这个事物会执行失败,,此方法调用于插入命令的时候 */
void multiCommand(redisClient *c) /* 加入multi命令 */
void discardCommand(redisClient *c) /* 撤销命令 */
void execCommandPropagateMulti(redisClient *c) /* 发送multi命令给所有的从客户端和aof文件 */
void execCommand(redisClient *c) /* 客户单执行Command命令 */
void watchForKey(redisClient *c, robj *key) /* 为客户端添加key监听 */
void unwatchAllKeys(redisClient *c) /* 客户端移除所有的key */
void touchWatchedKey(redisDb *db, robj *key) /* touch key的意思,表示key正在被监听,下一条执行操作将会失败 */
void touchWatchedKeysOnFlush(int dbid) /* 根据key所在的的db,把此db下的watched-key统统touch一遍 */
void watchCommand(redisClient *c) /* watch key 的命令方法,通过client中的参数传值 */
void unwatchCommand(redisClient *c) /* 取消监听key的命令方法 */
方法不是很多,但是里面出现了一个出现频率很高的词"key"。这个key在这里的确是起到了关键的作用。在muli的代码中主要包含了一些,加入命令,执行命令,还有一些撤销指令的操作,比如下面的撤销事务的操作。

/* 撤销事务 */
void discardTransaction(redisClient *c) {
    freeClientMultiState(c);
    initClientMultiState(c);
    c->flags &= ~(REDIS_MULTI|REDIS_DIRTY_CAS|REDIS_DIRTY_EXEC);
    //客户端取消监听所有的key
    unwatchAllKeys(c);
}
里面有个unwatchAllKeys()的方法。下面是事务操作的关键原理了:

/* 在事务处理中,存在2种mapping映射,key-->client lists ,表示所有列表中的Client都在监听这个key
	,当这个key的value发生改变了,可以标记这些Client为DIRTY状态,需要更新了,同时在Client内部也会维护
	一个key of list,表示一个客户端所监视的所有key,当Client发生free操作等,就要把key里面维护的Client列表
	做更新*/

/* touch key的意思,表示key正在被监听,下一条执行操作将会失败 */
也就是说,正在客户端正在监听的key,他的下一步命令将会执行失败,达到了同步的效果,

/* "Touch" a key, so that if this key is being WATCHed by some client the
 * next EXEC will fail. */
/* touch key的意思,表示key正在被监听,下一条执行操作将会失败 */
void touchWatchedKey(redisDb *db, robj *key) {
    list *clients;
    listIter li;
    listNode *ln;

    if (dictSize(db->watched_keys) == 0) return;
    clients = dictFetchValue(db->watched_keys, key);
    if (!clients) return;

    /* Mark all the clients watching this key as REDIS_DIRTY_CAS */
    /* Check if we are already watching for this key */
    listRewind(clients,&li);
    while((ln = listNext(&li))) {
        redisClient *c = listNodeValue(ln);
		
		//遍历该key拥有的Client,把flag标记为DIRTY_CAS状态
        c->flags |= REDIS_DIRTY_CAS;
    }
}
当客户端尝试用touch的方法去监听key的时候,Client的flag状态呗改为了DIRTY_CAS,不禁让我猜测,同步的方法是用CAS算法嘛,如果很多客户端都在用此算法,的确挺耗CPU的哦。总的来说,key维护了一个Client列表,一个Client同样拥有它所有watch的key列表,key的结构体很简单:

/* 定义了watchedKey结构体 */
typedef struct watchedKey {
    robj *key;
    redisDb *db;
} watchedKey;
key包含了它所属于的哪个数据库,所以刚刚撤销事务的操作,就要把客户端所监听的key都给移除掉了。


Java 开发 20: 现实世界中的 Redis :Redis 怎在包含大量读取操作的应用程序中战胜 memcached

这里就不再逐个讨论了,我将会在一个实际应用程序开发场景中介绍其中的一些。使用Redis 作为一个缓存解决方案 我之前提到过,Redis 可轻易地用作一个缓存解决方案,碰巧我现在正好需要这样一个!在该应用程序示例中,我将 Redis 集成到我基于定位的移动 Web 服务中,称之为 Magnus。 如果您没有关注本系列,那么我会先使用 Play 框架实现 Magnus,从那时起我就已经在各种实现中开发和重构它了。Magnus 是一个简单服务,可以通过 HTTP PUT 请求使用 JSON 文档。这些文档描述了特定帐号的位置,表示持有移动设备的人。 现在,我想要将缓存集成到 Magnus,也就是说我想要通过将不常更改的数据存储在内存中以减少 I/O 流量。Magnus 缓存! 在清单 5 中的第一步中,可以通过 get 调用了解新引入的帐户名称(一个键)是否为 REdis 中的一个键。get 调用可以将帐户 ID 作为一个值返回,或者将返回 null。如果返回一个值,我将用其作为我的 acctId 变量。如果返回的是 null(表明该帐户名称不是 Redis 中一个键),那么我将在 MongoDB 查找该帐户值,并通过 set 命令将其添加到 Redis。 这里的优势是速度:接下来,被请求的帐户将提交一个位置,这样我就能够从 Redis 中获取其 ID(作为内存缓存),而不是转到 MongoDB 并带来额外读取 I/O 成本。清单5. 使用 Redis 作为内存缓存 "/location/:account" { put { def jacksonMapper = new ObjectMapper() def json = jacksonMapper.readValue(request.contentText, Map.class) def formatter = new SimpleDateFormat("dd-MM-yyyy HH:mm") def dt = formatter.parse(json['timestamp']) def res = [:] try{ def jedis = pool.getResource() def acctId = jedis.get(request.parameters['account']) if(!acctId){ def acct = Account.findByName(request.parameters['account']) jedis.set(request.parameters['account'], acct.id.toString()) acctId = acct.id } pool.returnResource(jedis) new Location(acctId.toString(), dt, json['latitude'].doubleValue(), json['longitude'].doubleValue() ).save() res['status'] = 'success' }catch(exp){ res['status'] = "error ${exp.message}" } response.json = jacksonMapper.w......余下全文>>
 

Java 开发 20: 现实世界中的 Redis :Redis 怎在包含大量读取操作的应用程序中战胜 memcached

此外,我还讨论过较为常见的基于服务器的数据存储,比如 MongoDB 和 CouchDB。每个数据存储都有其优势和劣势,特别是当应用于特定领域时。 本期的 Java 开发 2.0 关注的是 Redis,一种轻量级键值对数据存储。多数 NoSQL 实现本质上都是键值对,但是 Redis 支持非常丰富的值集,其中包括字符串、列表、集以及散列。因此,Redis 通常被称为数据结构服务器。Redis 也以异常快速而闻名,这使得它成为某一特定类型使用案例的最优选择。 当我们想要了解一种新事物时,将其同熟知的事物进行比较可能会有所帮助,因此,我们将通过对比其与 memcached 的相似性以开启 Redis 探索之旅。接着我们将介绍 Redis 的主要功能,这些功能可以使其在某些应用场景可以胜过 memcached。最后我将向您展示如何将 Redis 作为一个传统数据存储用于模型对象。Redis 和 memcached Memcached 是一个众所周知的内存对象缓存系统,通过将目标键和值导入内存缓存运行。因此,Memcached 能回避读取磁盘时发生的 I/O 成本问题。在 Web 应用程序和数据库之间粘贴 memcached 时会产生更好的读取性能。因此,对于那些需要快速数据查询的应用程序,Memcached 是一个不错的选择。其中的一个例子为股票查询服务,需要另外访问数据库获取相对静态数据,如股票名称或价格信息。 MemcacheDB 将Redis 与 memcached 相比较并不公平,它与 MemcacheDB 相比要好的多,MemcacheDB 是一个分布式键值对存储系统,专为数据持久化而设计。MemcacheDB 与 Redis 较为相似,其新增优势可以使其轻松地与 memcached 实现的客户端进行通信。 但是memcached 也有其局限性,其中一个事实就是它所有的值均是简单的字符串。Redis 作为 memcached 的替代者,支持更加丰富的功能集。一些基准 (benchmarks) 也表明 Redis 的速度要比 memcached 快很多。Redis 提供的丰富数据类型使其可以在内存中存储更为复杂的数据,这是使用 memcached 无法实现的。同 memcached 不一样,Redis 可以持久化其数据。 Redis 解决了一个重大的缓存问题,而其丰富的功能集又为其找到了其他用途。由于 Redis 能够在磁盘上存储数据以及跨节点复制数据,因而可以作为数据仓库用于传统数据模式(也就是说,您可以使用 Redis,就像使用 RDBMS 一样)。Redis 还经常被用作队列系统。在本用例中,Redis 是备份和工作队列持久化存储(利用 Redis 的列表类型)的基础。GitHub 是以此种方法使用 Redis 的大规模基础架构示例准备好 Redis,立即开始! 要开始使用 Redis,您需要访问它,可以通过本地安装或者托管供应商来实现访问。如果您使用的 MAC,安装过程可能就不那么简单。如果您使用的是 Windows??,您需要先安装 Cygwin。如果您正在寻找一个托管供应商,Redis4You 拥有一个免费计划。不管您以何种方式访问,您都能够根据本文下列示例进行操作,但是我需要指出的是,使用一个托管供应商进行缓存可能并不是很好的缓存解决方案,因为网络延迟可能会抵消任何性能优势。 您需要通过命令与 Redis 进行交互,这就是说,这里没有 SQL 类查询语言。使用 Redis 工作非常类似于使用传统 map 数据结构,即所有的......余下全文>>
 

www.htsjk.Com true http://www.htsjk.com/shujukunews/4115.html NewsArticle Redis源码分析(十七)--- multi事务操作,redismulti redis作为一非关系型数据库,竟然同样拥有与RDBMS的事务操作,不免让我觉得比较惊讶。在redis就专门有文件就是执行事务的相关操作的。...
评论暂时关闭