[原]Redis使用场景及使用经验
Redis is an open source (BSD licensed), in-memory data structure store!
欢迎转载,转载请注明出处
刚刚结束一个游戏类的活动项目,由于预估的参与人数较多,产生的数据量会很大,为了达到更好的游戏效果,所以决定抛弃之前Mysql为主Redis为辅的存储方式,而是Redis为主,Mysql为辅(负责落地一些重要的用户数据),期间收货了很多。
一、Redis中的数据结构以及常见的使用场景
常用的Redis数据结构:
- String # 键值对
- List # 列表
- Hash # 哈希
- Set # 集合
- 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使用经验
先贴出来国内外三家重度使用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的配置文件, 内容如下:(配置文件详细介绍请点这里)
daemonize yes
pidfile "./redis.pid"
port 6379
timeout 0
tcp-keepalive 60
loglevel notice
logfile "./redis.log"
databases 16
save 900 1
save 300 10
save 60 10000
tcp-backlog 511
stop-writes-on-bgsave-error yes
rdbcompression yes
rdbchecksum yes
dbfilename "redis.rdb"
dir "./redis"
slave-serve-stale-data yes
slave-read-only yes
repl-disable-tcp-nodelay no
slave-priority 100
maxclients 20000
maxmemory 60gb
maxmemory-policy noeviction
appendonly no # 可以忍受一小段时间内的数据丢失,所以关闭了aof持久化
appendfilename "appendonly.aof"
appendfsync everysec
no-appendfsync-on-rewrite yes
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
lua-time-limit 5000
slowlog-log-slower-than 10000
slowlog-max-len 128
hash-max-ziplist-entries 512
hash-max-ziplist-value 512
list-max-ziplist-entries 512
list-max-ziplist-value 64
set-max-intset-entries 512
zset-max-ziplist-entries 128
zset-max-ziplist-value 64
activerehashing yes
client-output-buffer-limit normal 0 0 0
client-output-buffer-limit slave 256mb 64mb 60
client-output-buffer-limit pubsub 32mb 8mb 60
hz 10
aof-rewrite-incremental-fsync yes
# Generated by CONFIG REWRITE # 由sentinel自动故障转移生成的
#slaveof 10.181.60.113 6382
slaveof 10.181.254.157 6379
二、压测过程中遇到的问题及解决方案
保证服务可靠性,对主要单接口压测,以及复合场景下的多接口压测,观察接口的响应时间以及服务的吞吐量,还有对突发情况下的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没有数据,会清空自身的数据,很危险!)
[原]Redis使用场景及使用经验的更多相关文章
- (转)Redis使用场景及使用经验
Redis is an open source (BSD licensed), in-memory data structure store! 刚刚结束一个游戏类的活动项目,由于预估的参与人数较多,产 ...
- Redis应用场景-转载
1. MySql+Memcached架构的问题 实际MySQL是适合进行海量数据存储的,通过Memcached将热点数据加载到cache,加速访问,很多公司都曾经使用过这样的架构,但随着业务数据量的 ...
- <转>Redis 应用场景
http://blog.csdn.net/hguisu/article/details/8836819 1. MySql+Memcached 架构的问题 Memcached采用客户端-服务器的架构, ...
- Redis应用场景-整理
1. MySql+Memcached架构的问题 Memcached采用客户端-服务器的架构,客户端和服务器端的通讯使用自定义的协议标准,只要满足协议格式要求,客户端Library可以用任何语言实现. ...
- 详解 Redis 应用场景及原理
本文转自https://blog.csdn.net/niucsd/article/details/50966733,描述了redis实现原理和应用场景,篇幅较长,有意学习redis的同学可耐心阅读. ...
- Redis应用场景(转)
(来源:http://www.cnblogs.com/shanyou/archive/2012/09/04/2670972.html) Redis常用数据类型 Redis最为常用的数据类型主要有以下五 ...
- redis(二)Redis适用场景,如何正确的使用
网络IO模型 Memcached是多线程,非阻塞IO复用的网络模型,分为监听主线程和worker子线程,监听线程监听网络连接,接受请求后,将连接描述字pipe 传递给worker线程,进行读写IO, ...
- redis使用场景
Redis应用场景 Redis开创了一种新的数据存储思路,使用Redis,我们不用在面对功能单调的数据库时,把精力放在如何把大象放进冰箱这样的问题上,而是利用Redis灵活多变的数据结构和数据操作 ...
- Redis作者谈Redis应用场景
Redis作者谈Redis应用场景 毫无疑问,Redis开创了一种新的数据存储思路,使用Redis,我们不用在面对功能单调的数据库时,把精力放在如何把大象放进冰箱这样的问题上,而是利用Redis灵活多 ...
随机推荐
- 安装 Google BBR 加速VPS网络
Google BBR就是谷歌公司提出的一个开源TCP拥塞控制的算法.详情可以看这儿:https://lwn.net/Articles/701165.https://blog.sometimesnaiv ...
- defer用途
package main /* defer :程序退出时执行,先进后执行 defer庸碌: 1.关闭文件句柄 2.锁资源释放 3.数据库连接释放 */ import ( "fmt" ...
- 分布式系统的负载均衡以及ngnix负载均衡的五种策略
一般而言,有以下几种常见的负载均衡策略: 一.轮询. 特点:给每个请求标记一个序号,然后将请求依次派发到服务器节点中,适用于集群中各个节点提供服务能力等同且无状态的场景. 缺点:该策略将节点视为等同, ...
- HDU 6194 string string string 2017沈阳网络赛 后缀数组
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6194 题意:告诉你一个字符串和k , 求这个字符串中有多少不同的子串恰好出现了k 次. 解法:后缀数组 ...
- NFS挂载报如下错误信息:mount.nfs: Stale NFS file handle解决
1)用fuser杀掉占用那个目录的进程 linux:~ # fuser -k /home/msgplus/msgplus/remote_dir 2)强制umount linux:~ # umount ...
- C中常用格式格式码
一.常用printf格式码 二.常用scanf格式码
- C/C++——C语言跳出多重循环方法
c语言的break语句只能跳出离它最近的一层循环,但是我们有时候需要跳出多层循环,以下有几种跳出多重循环的方法: 1. 使用goto ; i < MAX1; i++) { ; j < MA ...
- [ python ] 正则表达式及re模块
正则表达式 正则表达式描述: 正则表达式是对字符串操作的一种逻辑公式,就是用事先定义好的一些特定字符.及这些特定字符的组合,组成一个‘规则字符串’,这个‘规则字符串’用来 表达对字符串的一种过滤 ...
- 自己实现的SVM源码
首先是DATA类 import java.awt.print.Printable; import java.io.File; import java.io.FileNotFoundException; ...
- cgi与html相互调用
html中调用cgi.<form action="/cgi-bin/mult.cgi" method="get" target="_blank& ...