Redis是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。本篇文章围绕Redis基础知识及集群搭建相关内容进行了分享,希望与各位同仁交流探讨。
一、Redis基础知识
1. Redis简介
Redis是什么?
Redis,典型的NoSQL数据库服务器,采用Key-Value存储结构,可以作为服务程序独立运行于自己的服务器主机,同时作为内存数据库,不用IO读取硬盘数据,能够快速响应请求。
Redis有什么特点?
支持持久化、支持多种数据结构、支持主从复制、免费。
与关系型数据库比较
redis由于其存储结构相对简单,因此并不能对复杂的逻辑关系提供很好的支持,然而在适用于Redis的场景中,我们却可以由此获得效率上的显著提升。
2. Redis的数据结构
作为NoSQL数据库之一的Redis,除了支持基本Key-Value方式,还支持结构化存储,以适应各类应用场景:
■String:字符串类型
■List::链表类型
■Hashes:哈希类型
■Set:集合类型
■Sorted-Sets:有序集合类型
字符串类型:String
String是最常用的一种数据类型,普通的Key/ Value存储都可以归为此类。当然,也可以存储图片,视频等序列化对象,Value最多可以容纳的数据长度是512M。
链表类型:List
List类型是按照插入顺序排序的字符串链表。和数据结构中的普通链表一样,我们可以在其头部(left)和尾部(right)添加新的元素。在插入时,如果该键并不存在,Redis将为该键创建一个新的链表。
场景:LIST可以作为消息队列,LPUSH链表头作为生产者插入消息,RPOP作为消费者取得消息。
哈希类型:Hashes
我们可以将Redis中的Hashes类型看成具有String Key和String Value的map容器。所以该类型非常适合于存储值对象的信息。
场景:AIOP中用户标签信息使用HASHMAP存储,存储结构为user:phone tag1 val1 tag2 val2 ,AIOP传递客户手机号,即可通过HGET user:phone tag1 tag2 取出标签值。
集合类型:Sets
在Redis中,我们可以将Set类型看作为没有排序的字符集合,就像什锦果冻,只是聚集在一起,没有顺序,这和List类型不一样,另外要注意Set集合中不允许出现重复的元素,而且Set支持多个Sets之间的差、并、交集操作。
场景:COC中将符合标签的用户进行聚类,存放到Set中,比如set1存放学生标签用户、set2存放低消费用户、set3存放非合约用户,那么取出可能购买小米的低消非合约学生用户群:
■ SINTERSTORE aset set1 set2
■ SDIFF aset set3
有序集合类型:Sorted-Sets
有序集合中也不允许有重复数据,它比Set多了一个score,Redis正是通过score来为集合中的成员进行从小到大的排序。需要注意的是,尽管Sorted-Sets中的成员必须是唯一的,但是分数(score)却是可以重复的。
场景:可以用于一个大型在线游戏的积分排行榜。每当玩家的分数发生变化时,可以执行ZADD命令更新玩家的分数,此后再通过ZRANGE命令获取积分TOP TEN的用户信息。当然我们也可以利用ZRANK命令通过username来获取玩家的排行信息。最后我们将组合使用ZRANGE和ZRANK命令快速的获取和某个玩家积分相近的其他用户的信息。
3. 其他操作
以上各类数据类型的操作全部是针对于Key关联的Value操作,Redis也提供了单独对Key值的操作。
Redis在设计之初就被定义为长时间不间断运行的服务进程,因此大多数系统配置参数都可以在不重新启动进程的情况下立即生效,本文用到的有:
■ Slaveof host port 修改主从关系
■ Info 当前系统信息
■ shutdown 关闭redis
■ flushall 清空所有keys
■ flushdb 清空当前数据库key
4. Redis主从复制
Redis主从复制的优势
①支持一主多从
②支持级联复制:master-slave-slave,分载master同步压力
③支持非阻塞式数据同步:数据同步与对外服务能力分离,互不影响
④支持slave只读模式
5. Redis持久化
RDB持久化
该机制是指在指定的时间间隔内将内存中的数据集快照写入磁盘。
优点:①只有一份rdb文件,可随时备份
②比AOF文件小,加载效率高
③只提供fork子进程,不阻塞主进程,IO操作比较少
AOF持久化
该机制将以日志的形式记录服务器所处理的每一个写操作,在Redis服务器启动之初会读取该文件来重新构建数据库,以保证启动后数据库中的数据是完整的。
优点:①每改动同步数据安全性好
②APPEND方式追加日志,不会对旧日志文件产生影响
无持久化
可以通过配置的方式禁用Redis服务器的持久化功能,这样就可以将Redis视为一个功能加强版的memcached了。
同时应用AOF和RDB
6. Redis持久化2
RDB持久化
Dump快照的机制:
①Redis先fork子进程。
②子进程将快照数据写入到临时RDB文件中。
③当子进程完成数据写入操作后,再用临时文件替换老的文件。
redis.conf配置修改:
save 900 1 #在900秒后,如果至少有1个key发生变化,则dump内存快照。
save 300 10 #在300秒后,如果至少有10个key发生变化,则dump内存快照。
save 60 10000 #在60秒之后,如果至少有10000个key发生变化,则dump内存快照。
(注释1:可以配置多个条件组成持久化策略)
(注释2:fork进程开销大,数据量太大时,消耗cpu和内存资源,影响父进程不能及时响应)
AOF持久化
redis.conf配置修改:
appendonly yes
appendfsync always #每次有数据修改发生时都会写入AOF文件。
appendfsync everysec #每秒钟同步一次,该策略为AOF的缺省策略。
appendfsync no #从不同步。高效但是数据不会被持久化。
(注释:一般选择always每修改同步,保证数据安全)
7. Redis内存优化思考
Redis作为内存数据库,所有数据都从内存中拿,省去读写磁盘的消耗(持久化是由fork子进程处理,主服务对外能力不受影响),响应速度极快。但我们不可能将所有的数据都读到内存中,所以内存资源显得非常可贵,我们就要优化存储结构,使得好钢用在刀刃上。
尽量使用hash
COC中每个客户会对应上千个标签,每个客户就是一个对象,我们如何存储它?
存储结构比较
①序列化对象:要求在Redis存储前对对象进行序列化操作,每次取出后还要执行反序列化操作,开销太大;如果只想取对象的某一个值,也需要将整个对象取出,还要解决并发、数据一致性、加锁等复杂问题。
②K-V模式:phone字段冗余
③HASHMAP:phone字段只出现一次,避免数据冗余
内存优化效果
比较K-V结构与HASHMAP结构对内存的影响:
前提假设COC有1千万用户对象,每个用户对象有1000个标签,Redis存储的phone_no格式为185XXXXXXXX。
①根据ASCII编码,每位数字占用单字节字符,每个phone_no占用11Byte
②K-V结构中,存放一个完成对象,每个phone_no需要重复1000次,所以存放1千万个对象phone_no为1000*1千万,所占空间为:1000次*10000000个*11B/1024/1024=102.45G
根据业务场景,考虑使用BITMAP
前面我们在讲String的时候提到过两个命令:setbit key offset 0/1和getbit key offset,这两个命令是在位上进行0/1赋值和取值。假设还是1000W用户,每个用户有1000个0/1标签,我们可以使用bitmap来存放这些数据:
所有标签总占用的内存为:0.000119MB*1000W=1.19GB,如果使用Key-Value结构(包括Hashes),内存占用至少是它的8倍。
BITMAP使用总结
①只适合01型标签
②需要位移位与标签的字典表,属于额外开销,但相对而言字典表Offset数字可共享Redis数字池,比直接存字符串要省空间。
③牺牲时间换空间:(1)维护字典表;(2)入库需要对应转化;(3)出库计算也需要转换
Redis基础总结
①本次Redis基础知识中,我们介绍了基本的数据结构及常用命令、数据类型的场景举例、Redis主从复制机制、持久化机制、以及内存优化。
②无论是数据结构选择还是内存优化,都要结合具体的业务场景和业务要求,没有通用的最佳推荐模式,只有最符合需求的模式,所以我们需要我们不断尝试、不断优化。(未完待续)