redis是单线程应用程序,占用较少的内存,能够快速读写数据。web
在基于sql的关系型数据库中,开发者和数据库管理员经过将数据规范化为列、行、表,并经过外键关系创建关联的方式建立数据库模式。redis
mongdb 、elasticsearch这样的nosql 数据存储技术 须要在数据装载到实际存储以前 转换成json文档数据格式。算法
redis跳过这种中间转换,它为特定的数据结构(字符串、列表、哈希、集合、有序集合)提供了一系列命令。sql
经过算法和数据进行交互。以数据在redis中的存储方式及可用的命令直接构造解决方案,同时能以更直接的方式对目标操做系统的内存和磁盘空间进行调优和监控。数据库
-------------------------------------------------------------------------------------------------express
世界上大多数图书馆将它们的书目数据存储并构建于持久性二进制格式机读编目格式标准(MAchine-Readable Cataloging ,简称 MARC)。json
MARC格式是由固定长度+可变长度字段组成的,这些字段的数值范围从001~999,相应的能够有字符数据或者含有数据的子字段。此外,每一个字段能够包含最多两个指示符,用来修改字段的含义。缓存
MARC域中最经常使用且最为重要的两个是100 主要条目-我的名称 字段 和245题名说明字段。网络
以David Foster Wallace的书 Infinite jest 示例:数据结构
=100 1\$aWallace,David Foster =245 10$aInfinite jest:$ba novel$cDavid Foster Wallace
为了在redis里使用MARC数据,每条MARC记录都被建模表示为 marc:{counter} 的哈希键,其中counter是全局递增的计数器。每一个MARC字段都是一个哈希,其键为 marc:{counter}:{field}。因为部分MARC域会因不一样的信息而出现重复,所以哈希键会包含一个全局计数器,例如: marc:{counter}:{field-counter}。
简单地存储上述两个字段须要如下6条redis命令:
10.143.128.165:6379> INCR marc (integer) 1 10.143.128.165:6379> INCR marc:1:100 (integer) 1 10.143.128.165:6379> HSET marc:1:100:1 a "Wallace ,Divid Foster" (integer) 1 10.143.128.165:6379> INCR marc:1:245 (integer) 1 10.143.128.165:6379> HMSET marc:1:245:1 a "Infinite jest:" b "a novel" c "David Foster Wallace" OK 10.143.128.165:6379> HGETALL marc:1:245:1 1) "a" 2) "Infinite jest:" 3) "b" 4) "a novel" 5) "c" 6) "David Foster Wallace"
redis中键的结构以下图所示:
redis中MARC数据存储能够仅经过单个redis的哈希数据类型及一致的键语法结构完成。为了提高redis中书目数据的实用性,并实现以书名和做者名字数字排序的方式获取图书馆数据的列表记录,可使用诸如列表或者有序集合等redis中其余数据类型达成。
在redis中,使用哈希和列表来表达MARC字段和子字段能提供更多信息。
书目记录的功能性需求,FRBR,是一种能够替代MARC的文档,他基于实体-关系(ER)模型。FRBR ER 模型包含了根据抽象规则进行归类的属性组。最高抽象是Work(做品)类,表明了用来惟一识别一件富有智慧的做品最为通用的属性,包括标题、做者和学科。
Expression(内容表达)类由诸如版本和与父work有肯定关系的译本组成。
Manifestation(载体表现)和Item(单件)是最后两个FRBR类,包含更多详细的数据,其中item是一个具体的物理对象,是更为通用的Manifestation的具体实例。
仅有少数真实系统或者技术为图书馆数据实现了FRBR模型,而redis提供使用真实数据测试此类模型的方法。采用将MARC数据映射到FRBR的Work、Expression、Manifestation、Item上的方法,那么MARC 100和245就能在redis中映射到FRBR的Work。
10.143.128.165:6379> HMSET frbr:work:1 title "Infinite Jest" "created by" "David Foster Wallace" OK
新的做品frbr:work:1能够经过下列redis键和哈希从而关联到其他的类:
10.143.128.165:6379> HMSET frbr:expression:1 date 1996 "realization of" frbr:work:1 OK 10.143.128.165:6379> HMSET frbr:manifestation:1 publisher "Little ,Brown and Company" "physical embodiment of" frbr:expression:1 OK 10.143.128.165:6379> HMSET frbr:item:1 'exemplar of' frbr:manifestation:1 identifier 33027005910579 OK
在上述 expression 例子中,具体日期是经过 realization of 属性关联回 frbr:work:1 。一样,frbr:manifestation:1哈希拥有两个字段:出版社和物质载体。物质载体字段的值是 frbr:expression:1 键,它将manifestation关联回expression。最后的frbr:item:1哈希拥有一个条形识别码属性和关联到 frbr:manifestation:1哈希的键。
在对MARC和FRBR二者的实验中,redis哈希数据结构实体提供了基本表达。当具体的属性多于一个值时,例如当要表达做品的多个做者时,要解决多值属性的问题,经过像以前那样为每一个MARC字段建立一个计数器。举例来讲,针对电子书或者其余拥有网络可解析URL的材料,MARC 856字段(电子位置与存取)会为其存储URL。若是想为以前的MARC示例添加两个URL,例如在Google books里该书的连接地址及该书的wiki页面,对应命令以下:
10.143.128.165:6379> INCR global:marc:1:856 (integer) 1 10.143.128.165:6379> HMSET marc:1:856:1 ind1 4 ind2 u https://books.google.com/books?id=Ndxndx7djd OK 10.143.128.165:6379> HMSET marc:1:856:2 ind1 4 ind2 u https://infinitejest.wallacewiki.com/ OK
针对MARC键的命名方法知足重复MARC字段的需求,可是若是单一MARC域拥有多个、重复的子字段呢?首先想到的是 能够存储以某种分隔符分割的字符串,其中存储的每一个值是MARC中特定字段的值。这就要求客户端进行额外的解析工做来获取全部不一样的子字段,同时将失去将这些子字段直接存储至redis所带来的额外优点。解决MARC多值子字段问题的第二种方法是进一步扩展redis键语法,并为每一个子字段使用列表或者其余数据结构。下面扩展MARC 856这个例子,若是想添加第二个电子书的url,如 Amazon kindle版本的url连接:
0.143.128.165:6379> LPUSH marc:1:856:1:u https://books.google.com/books?id=Ndxndx7djd http://www.amazon.com/Infinite-Jest-David-Foster-Wallace/ (integer) 2 10.143.128.165:6379> HMSET marc:1:856:1 u marc:1:856:1:u OK
将多个子字段存储到redis列表 这样的方法工做的很好,可是若是但愿MARC字段的子字段没有重复的值 该怎么办?能够经过redis的集合类型数据解决。集合的定义就是 只包含惟一的值。使用集合存储子字段的值看起来是个很是棒的解决方案,但若是须要在子域中存放有序值,集合就显得捉襟见肘了。
redis的有序集合 确保集合中子字段惟1、没有重复,还保持了子字段的有序:
10.143.128.165:6379> DEL marc:1:856:1:u (integer) 1 10.143.128.165:6379> ZADD marc:1:856:1:u 1 https://books.google.com/books?id=Ndxndx7djd 2 http://www.amazon.com/Infinite-Jest-David-Foster-Wallace/ (integer) 2 10.143.128.165:6379> ZRANGE marc:1:856:1:u 0 -1 WITHSCORES 1) "https://books.google.com/books?id=Ndxndx7djd" 2) "1" 3) "http://www.amazon.com/Infinite-Jest-David-Foster-Wallace/" 4) "2"
在该示例中,研究了如何表示称为MARC的图书馆数据遗留格式,以及MARC的字段和子字段如何以哈希的形式存储到redis中。
--------------------------------------------------------------流行的使用模式
对于redis来讲,一种很是受欢迎的使用模式是做为web应用程序的内存缓存。
经过利用redis为键设置过时时间的功能,流行的redis缓存策略之一--最近最少使用(less recently userd,LRU)策略变得很是健壮,足以应对最大的网络站点。它将最受欢迎的内容保存在缓存中,同时将陈旧的、较少使用的数据驱逐出数据存储。这种缓存的使用场景并不假定原始的web元素或者页面是有redis中的数据产生的。最多见的使用模式是有其余来源的数据动态生成web内容,而将redis做为出色的web缓存层。
第二种流行的使用模式是将redis用做web页面使用状况和玩家排行榜上的用户行为等定量数据的指标存储。经过在字符串上进行位操做,redis能够很是高效地将二进制信息存储于特定的字符上。就拿网站使用来讲,有个从日期构造的键 page-usage:2016-11-01,它对应一个字符串,当该页面被用户访问时,就将其中 的一位设置为1.
网站在11月1日的每日使用状况能够经过page-usage:2016-11-01键上调用简单的redis的bitcount命令获取。
第三种流行的redis使用模式是经过发布/订阅(简称pub/sub)模型做为不一样系统之间的通讯层。在这种模型中,消息的发布方将消息发送至一到多个信道(channel)上,这些消息会被订阅或者监听信道上发来消息的其余系统处理。
一般,消息发布方无需知道具体的订阅方就能将消息发送给他们(相对点对点消息通讯模式来讲),发布方仅需知道消息内容和用于发送消息的信道便可。一样,订阅方也无需知道每一个发送方,只需关注信道接受消息便可。发布/订阅很是棒,由于它扩展起来很是容易,同时消息的发布方和订阅方能够是几乎彻底不一样的程序和系统。