Redis应用场景

Redis开创了一种新的数据存储思路,使用Redis,我们不用在面对功能单调的数据库时,把精力放在如何把大象放进冰箱这样的问题上,而是利用Redis灵活多变的数据结构和数据操作,为不同的大象构建不同的冰箱。

Redis常用数据类型

Redis最为常用的数据类型:

1.String   

2.Hash   

3.List  

4.Set   

5.Sorted set  

1、String

常用命令:  set,get,decr,incr,mget 等。

应用场景:String类型是最简单也是最常用的redis数据结构,key/value格式完全可以取代Memcached作为缓存服务器,单机的测试效果显示redis的效果更好。

set、get:最简单的数据缓存

mset、mget: 批量操作,把数据统一传回客户端,节省网络io时间

decr、incr:计数器

append命令:可以作为时间序列,配合getrange、setrange,对字符串进行操作,目前redis还木有修剪操作

setbit、getbit: 省内存的好命令,可以作为简单的布尔过滤器来判断用户是否执行过某些操作

2、List

常用命令:lpush,rpush,lpop,rpop,lrange等。

应用场景:List的应用场景很多,应用也相当广泛

lpush、lpop:天然的队列操作,轻松实现队列任务,Celery的存储容器我们选的就是redis

lpush、ltrim: 显示最新的数据,很好用的!比如:游戏上方的跑马灯,就可以用这两个命令来存储最新的50条记录

还有一些其他操作:堵塞式的blpop, lrange(O(n)), lindex(O(n)),linsert(O(n)), llen(O(1)),lrem(O(n)),lset(O(n))

3、Hash

常用命令:hget,hset,hgetall 等。

应用场景:以前在memcached中如果保存一个大的数据,经常用序列化之后保存,取出来反序列化后使用,即不经济实惠,在高并发下还存在原子性问题,在redis中, 用哈希实现,so easy啦!

hget、hset: 实现一个key对应一个数据集集合,数据集集合里包含多个单独的key/value键值对,操作依然是原子性的

hmget、hmset、hgetall: 批量操作,节省网络io时间哦

hincrby: 对哈希里域值,进行原子性的加1

其他操作: hdel(O(n))、 hkeys(O(n))、hexits(O(1))、hvals(O(n))、hscan(O(n))

4、Set

常用命令:

sadd,spop,smembers,sunion 等。

应用场景:set与list类似,只是set是经过去重的集合,需要一个不重复的数据结构,就要考虑考虑set

sadd: 存储一个不重复数据的数据集合

sunion、sdiff、sinter: 进行集合处理,例如微博中,将一个用户关注的所有人放入set集合中,通过并集、交集、差集操作,实现`共同关注`、`共同喜好`、`二度好友`等功能

其他操作:srem、spop、scard、sismember、smove、srandmember

5、Sorted Set

常用命令:

zadd,zrange,zrem,zcard等

应用场景:set是无序的,而Sorted set 顾名思义,它是有序的,由key、member和score组成,需要一个有序而且不重复的数据结构,就要考虑考虑sorted set

zadd:存储一个按照score排序的数据集合,添加时自动排序,例如:优先队列,普通消息的score为1,重要消息的score为2,然后工作线程可以选择按score的倒序来获取工作任务。让重要的任务优先执行。

zrange、zrangebyscore等等:按照score顺序获取数据集,例如:微博的时间流信息,把发布时间作为score。还可以用来处理过期数据。后台任务使用ZRANGE…SCORES查询排序集合,取出最新的10个项目。如果发现unix时间已经过期,则在数据库中删除条目。

zrank: 排行榜功能,score作为投票结果

其他操作:zcard、zcount、zincrby、zrem、zscore,以及set的集合操作

Redis 的 5 个常见使用场景

1、会话缓存(Session Cache)

最常用的一种使用Redis的情景是会话缓存(session cache)。用Redis缓存会话比其他存储(如Memcached)的优势在于:Redis提供持久化。当维护一个不是严格要求一致性的缓存时,如果用户的购物车信息全部丢失,大部分人都会不高兴的,现在,他们还会这样吗?

幸运的是,随着 Redis 这些年的改进,很容易找到怎么恰当的使用Redis来缓存会话的文档。甚至广为人知的商业平台Magento也提供Redis的插件。

2、全页缓存(FPC)

除基本的会话token之外,Redis还提供很简便的FPC平台。回到一致性问题,即使重启了Redis实例,因为有磁盘的持久化,用户也不会看到页面加载速度的下降,这是一个极大改进,类似PHP本地FPC。

再次以Magento为例,Magento提供一个插件来使用Redis作为全页缓存后端。

此外,对WordPress的用户来说,Pantheon有一个非常好的插件  wp-redis,这个插件能帮助你以最快速度加载你曾浏览过的页面。

3、队列

Reids在内存存储引擎领域的一大优点是提供 list 和 set 操作,这使得Redis能作为一个很好的消息队列平台来使用。Redis作为队列使用的操作,就类似于本地程序语言(如Python)对 list 的 push/pop 操作。

如果你快速的在Google中搜索“Redis queues”,你马上就能找到大量的开源项目,这些项目的目的就是利用Redis创建非常好的后端工具,以满足各种队列需求。例如,Celery有一个后台就是使用Redis作为broker,你可以从这里去查看。

排行榜/计数器

Redis在内存中对数字进行递增或递减的操作实现的非常好。集合(Set)和有序集合(Sorted Set)也使得我们在执行这些操作的时候变的非常简单,Redis只是正好提供了这两种数据结构。所以,我们要从排序集合中获取到排名最靠前的10个用户–我们称之为“user_scores”,我们只需要像下面一样执行即可:

当然,这是假定你是根据你用户的分数做递增的排序。如果你想返回用户及用户的分数,你需要这样执行:

ZRANGE user_scores 0 10 WITHSCORES

Agora Games就是一个很好的例子,用Ruby实现的,它的排行榜就是使用Redis来存储数据的,你可以在这里看到。

Redis实际应用场景

Redis在很多方面与其他数据库解决方案不同:它使用内存提供主存储支持,而仅使用硬盘做持久性的存储;它的数据模型非常独特,用的是单线程。另一个大区别在于,你可以在开发环境中使用Redis的功能,但却不需要转到Redis。

转向Redis当然也是可取的,许多开发者从一开始就把Redis作为首选数据库;但设想如果你的开发环境已经搭建好,应用已经在上面运行了,那么更换数据库框架显然不那么容易。另外在一些需要大容量数据集的应用,Redis也并不适合,因为它的数据集不会超过系统可用的内存。所以如果你有大数据应用,而且主要是读取访问模式,那么Redis并不是正确的选择。

然而我喜欢Redis的一点就是你可以把它融入到你的系统中来,这就能够解决很多问题,比如那些你现有的数据库处理起来感到缓慢的任务。这些你就可以通过Redis来进行优化,或者为应用创建些新的功能。在本文中,我就想探讨一些怎样将Redis加入到现有的环境中,并利用它的原语命令等功能来解决 传统环境中碰到的一些常见问题。在这些例子中,Redis都不是作为首选数据库。

Redis使用经验

一、Redis部署

本司由于平时的数据量不大,一直使用的三台redis实例,一主两从,三个哨兵sentinel分别监视三个redis实例作为高可用性的保障,这次活动的预估参与人数以及请求并发量很大,所以为了保证高可用性,在部署时做了一下变更方案:

更换SSD硬盘,并增加内存至128G (简单粗暴,效果显著)

双机房两组Redis实例,一组对外服务,另一组作为热备份,不提供服务并定时备份,服务中的实例出现故障,立即切换备份实例为服务实例

OS参数:vm.over_commit_memory配置  默认为0,改为1

Redis的快照、AOF文件重写、主备同步等功 能都依赖于fork系统调用,以快照(bgsave/save)为例,Redis会fork一个子进程出来,由子进程来将当前的数据存储为一个RDB文件。

vm.over_commit_memory会影响到内存分配,其值可以是:

0: 表示内核将检查是否有足够的可用内存供应用进程使用;如果有足够的可用内存,内存申请允许;否则,内存申请失败,并把错误返回给应用进程。

1: 表示内核允许分配所有的物理内存,而不管当前的内存状态如何。

2: 表示内核允许分配超过所有物理内存和交换空间总和的内存。

vm.over_commit_memory默认值为0,在该配置下,当Redis执行fork时,服务器可用内存必须大于Redis当前使用内存2倍时,fork才能成功。

而实际上Linux在fork时,使用COW(copy-on-write)技术,子进程共享父进程的地址空间,只有共享地址空间发生改变时,才需要复制改变部分的内存;大部分情况下,fork子进程并不会导致内存使用翻倍,为fork预留一倍的内存是完全没有必要的,Redis启动时也会建议使用者将vm.over_commit_memory设置为1。

OS参数:vm.swapiness设置为0

Redis是全内存的KV数据库,当服务器内存不足时,OS的swap机制可能会把Redis的部分数据换出到磁盘,访问Redis时,如果被访问的数据刚好不在内存里,则会产生缺页中断,从磁盘读取数据,这种行为会极大的影响Redis服务的性能。

为保证Redis服务的性能,应该尽量避免发生swap,将vm.swapiness设置为0(该参数可在0-100之间取值,默认为60,越高使用swap空间的可能性越大)。

OS参数:transparent hugepage

Linux-2.6.38内核引入透明大内存页的支持,这个参数对Redis有利有弊。

好处在于:大内存页意味着更小的页表,fork的开销会降低不少

坏处在于:大内存页,意味着页被修改的几率更大,COW时拷贝成本更高

二、压测过程中遇到的问题及解决方案

保证服务可靠性,对主要单接口压测,以及复合场景下的多接口压测,观察接口的响应时间以及服务的吞吐量,还有对突发情况下的Redis机器故障转移,如机房断电,主redis挂掉等情况。

问题:

业务逻辑复杂,频繁访问redis,接口响应时间有提升空间

线上要清空一个db的数据,执行flushdb后,数据依然存在(原因:该db内数据量大,清空操作超过3秒,sentinel发现3秒内,master无正确响应,就将slave拉起作为master,从进行同步,陷入循环。。。)

Redis目前的主从同步机制,主从连接断开后,如果从落后的数据超过1M(可配置,越大内存开销越大),则需要重新全量同步一次,一次全量同步会产生极大的内存、磁盘、CPU及网络开销。主从全量同步过程中,如果写入比较多,主从同步缓冲区就会不断累积写入的数据,当累积的数据超出限制时,主从连接就会断开,此时从又必须重新向主请求全量同步,如此往复... 导致同步一直不能成功

数据量很大时,redis的bgsave操作,虽然是子进程操作,但是也会阻塞redis,导致超时

   方案:

mysql读写分离,并分库,分表

redis数据分片,把重要、不重要的数据分开到两个redis实例分别存放

代码中减少redis网络IO请求,多用mget、hmget、pipeline等一次性读多条数据命令

代码中考虑用更合适的redis数据结构以及时间复杂度少的命令。 Instagram公司优化Redis使用内存案例

设计数据结构时,尽量减小单个key的value大小,如果单例redis中数据量过大,故障恢复或者同步过程会很慢。单例redis最大使用内存一定要小于机器最大内存的一半。

清空一个数据量很大的db前,先调大sentinel的自动故障转移时间,清空后再设置回来。

适当扩大client-output-buffer-limit slave 256mb 64mb 60 的配置值

一定要设置限流,运维层限制一道,代码层限制一道,保证整体服务器不宕机。

  备选方案:

复杂的redis操作,可以考虑用短小的lua脚本执行,用eval和evalsha命令执行(优点:充分利用CPU,减少网络IO时间。缺点:不方便维护,要保证脚本不阻塞)

传统的一主多从A--B&C 当把B拉起为master时,C仍然会清空自身数据来同步B,psync的断点续传对此无作用,所以考虑改为变为A--B--C同步结构

redis集群(时间紧,考虑但是暂时不会采用)

采用主不开持久化,从开持久化,不会出现数据量大,bgsave导致的连接超时情况(缺点:A--B&C模式下,A故障并自动拉起或者由sentinel把B被拉起为master,中间的心跳检测过程中,还是会有一个间隔,导致从同步主,发现A没有数据,会清空自身的数据,很危险!)

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,189评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,577评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,857评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,703评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,705评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,620评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,995评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,656评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,898评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,639评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,720评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,395评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,982评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,953评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,195评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,907评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,472评论 2 342

推荐阅读更多精彩内容