虽说公司一直在使用redis,但一直没有系统的学习redis相关知识,故此,趁有空系统的学习了一下:
以下为学习笔记,以备以后复习:
redis 学习笔记: 数据库随着数据量和访问量的压力增大,模式升级如下: 一个数据库---》加缓存---》mysql主从复制------(写出现瓶颈)---》分库分表(1到3000条记录进库1,3001到6000条记录进库2) 知识点:mysql的引擎myISAM使用表锁,InnoDB引擎使用的行锁. 3v+3高: 大数据时代的3V:海量(Volnme),多样(Variety),实时(Velocity)。 互联网需求的3高:高并发,高可扩,高性能。 redis读写性能:读11万/秒 , 写8万/秒。 vk+cache+presistence; 1.多文字信息描述类,IO读写性能差 使用文档数据库MongDB. 2.图片, 分布式的文件系统. (淘宝的TFS,Google的GFS, Hadoop的HDFS). 3.搜索框关键字(redis,淘宝的Isearch,tair等). 4.某个时期的热点高频信息(内存数据库tair,redis,Memcache). 5.商品的交易,价格计算,计分累计(外部系统,外部第三方支付接口,如支付宝). 高并发的操作不建议有关联查询, 互联网公司用冗余数据来避免关联查询, 分布式事物是支持不了太多的并发的. redisKV键值:典型介绍 : 新浪:BerkeleyDB+redis; 美团:redis+tair; 阿里,百度:memcache+redis. 传统数据库原理CAP+BASE: 传统的ACID分别是什么: A(Atomicity)原子性 C(Consistency)一致性 I(Isolation)独立性 D(Durability)持久性 CAP: C:Consistency(强一致性) A:Availability(可用性) ----稳定性+抗容灾能力 P:Partition tolerance(分区容忍性) ----分布式系统在遇到任何网络分区故障的时候,任然能够保证对外提供满足一致性和可用性的服务,除非整个网络环境都发生了故障. CAP的3进2 : CAP理论的核心:一个分布式系统不可能同时很好的满足一致性,可用性,分区容忍性三个需求,最多只能满足两个. 因此,根据CAP原理,讲nosql数据库分成了满足CA原则,CP原则,AP原则 三大类: CA:单点集群,满足一致性,可用性的系统,通常在可扩展性上不太强.(传统数据库) CP: 满足一致性,分区容忍性,通常性能不太高.(MongDB,HBase,Redis) AP:满足可用性,分区容忍性的系统,通常可能对一致性要求低一些.(CouchDB)---放弃数据的强一致性,保证最终一致性. CAP理论就是说在分布式存储系统中,最多只能实现上面的两点。 而由于当前网络硬件肯定会出现------延迟丢包-----等问题,所以--------分区容忍性是我们必须要实现的. 所以我们只能在一致性和可用性之间进行权衡,没有nosql系统能同时保证这三点. 网络分区:指在分布式系统中,不同节点分布在不同的子网络(机房或异地网络等)中,由于一些特殊原因导致这些子网络之间出现网络不连通的状况,但各个子网络的内部网络是正常的,从而导致整个系统的网络环境被切分成若干个孤立的的区域. 需要注意的是,组成一个分布式系统的每个节点的家如何退出都可以看作是一个特殊的网络分区. AP 大多数网站架构的选择(在数据强一致性+低可用性 和 数据弱一致性+高可用); CP Redis,Mongodb 任何大数据量的web系统,都非常忌讳多个大表的关联查询,以及复杂的数据分析类型的报表查询,特别是SNS类型的网站。 BASE其实是下面三个属于的缩写: --------------BASE是为了解决关系数据库强一致性引起的问题而引起的可用性降低而提出的解决方案. 基本可用(Basically Available) 软状态(Soft state) 最终状态(Eventually consistent) 它的思想是:通过让系统放松对某一时刻数据的一致性的要求来换取系统整体伸缩性和性能上改观.为什么这么说呢,缘由就在于 大型系统往往由于地域分布和极高性能的要求,不可能采用分布式事务来完成这些指标,要想获得这些指标,我们必须采用另外一种方式来完成,这里BASE就是解决这个问题的办法. 分布式:? 集群? 由多台计算机和通信的软件组件通过计算机网络连接(本地网络或者广域网)组成.分布式系统是建立在网络上的软件系统.正是因为软件的特性,所以分布式系统具有高度的内聚性和透明性. 因此网路和分布式系统之间的区别更多在于高层软件(特别是互联网系统),而不是硬件.分布式系统可以应用在不同的平台上如:PC,工作站,局域网和广域网上等. 简单来说: 1.分布式:不同的多台服务器上面部署 不同的服务模块(工程),他们之间通过Rpc/Rmi之间通信和调用,对外提供服务和组内协作. 2.集群:不同的多台服务器上面部署 相同的服务模块 ,通过分布式调度软件进行统一的调度.对外提供服务和访问. 负载均衡? 举例: 三只羊剪羊毛, 不只拔一只羊的毛,而是通过调度,对三只羊 都进行 次数合理的拔羊毛. 入门: 是什么? C语言编写,遵守BSD协议 三个特点:支持持久化,多种数据存储结构,支持数据备份. 能干什么? 内存存储+持久化; 模拟类似于HttpSession这种需要设定过期时间的功能; 发布,订阅消息系统; 定时器,计数器. 怎么玩? 数据类型,基本操作和配置; 持久化和复制,RDB/AOF; 事务的控制; 复制; 解析Redis配置文件(redis.conf) 1.Units单位 1.配置大小单位,开头定义了一些基本的度量单位,只支持bytes,不支持bit. 2.对大小写不敏感. Tcp-keepalive 单位如果设置成0,则不会进行keepalive检测,建议设置成60. loglevel 日志级别 debg verbose notice warning logfile 日志文件 syslog-enabled 是否把日志输出到syslog中 syslog-ident 指定syslog里的日志标志 (默认reidis) syslog-facility 指定syslog设备, 值可以是USER或LOCAL0-LOCAL7 dabases 数据库大小(默认16) Maxmemory-policy 最大内存的缓存清除策略 volatile-lru: 使用LRU算法移除key,只对设置了过期时间的键; allkeys-lru: 使用LRU算法移除key; volatile-random:在过期集合中移除随机的key,只对设置了过期时间的键; allkeys-random: 随机移除的key; volatile-ttl: 移除那些TTL值最小的key,即那些最近要过期的key; noeviction: 不进行移除.针对写操作,只返回错误信息. Maxmemry-samples 设置样本数量,LRU算法和最小TTL算法都并非是精确的算法,而只是估算值,所以你可以设置样本的大小,redis默认会检查这么多个key并选择其中LRU的那个. 持久化 rdb(redis database ) aof(append only file) rdb 是什么: 在指定的时间间隔内将内存中的 数据及快照 写入磁盘. 也就是行话讲的 snaapshot快照, 它恢复时 是将 快照文件直接读到内存. redis会单独创建(fork[复制])一个子进程来进行持久化,会先将数据写入到一个临时文件中,待持久化过程结束,再用这个临时文件替换上次持久化好的文件. 整个过程,主进程是不进行任何io操作的,这就确保了极高的性能. 如果需要进行大规模数据的恢复,且对于数据恢复的完整性不是非常敏感,namerdb比aop方式更加高效.rdb的缺点是最后一次持久化的数据可能丢失. fork的作用是复制一个与当前进程,一样的进程.新进程的所有数据(变量,环境,程序计数器等)数值都和原进程一致,但是是一个全新的进程,并作为原进程的子进程. 配置: save <seconds> <changes> save "" 禁用 save 900 1 save 300 10 save 60 10000 shutdown的时候,会将内存中的数据 压如 dump.rdb中; stop-writes-on-bgsave-error rdbbcompression : 对于存储到硬盘的快照,可以通过设置是否进行压缩存储。如果是的话,redis会进行LZF算法进行压缩,如果不想小号cpu来进行压缩,可以设置为关闭此功能. rdbchecksum : 在存储快照后,还可以让redis使用crc64算法来进行数据校验,但是这样做会增加大约10%的性能消耗,如果希望获取最大的性能提升,可以关闭此功能. dbfilename dir save :直接调用 rdbSave ,阻塞 Redis 主进程,直到保存完成为止。在主进程阻塞期间,服务器不能处理客户端的任何请求。 bgsave :fork 出一个子进程,子进程负责调用 rdbSave ,并在保存完成之后向主进程发送信号,通知保存已完成。因为 rdbSave 在子进程被调用,所以 Redis 服务器在BGSAVE 执行期间仍然可以继续处理客户端的请求。 执行flushall 也会产生快照文件,但是是空的. rdb优劣势: 1.适合大规模的数据恢复.(对数据完整性和一致性要求不高) 2.fork的时候,内存中的数据被克隆了一份,大致需要两倍的膨胀性需要考虑。 如何停止: 动态停止:redis-cli config set save "" rdbSave:内存中的数据对象 -----》磁盘中的rdb文件 rdbLoad:磁盘中的rdb文件 ----->内存中的数据对象 AOF 以日志的形式来记录每个写操作,将redis执行过的所有写指令记录下来.(读操作不记录) 只许追加文件,不允许改写文件,redis启动之初会读取改文件重新构建数据,换言之,redis重启的话,就根据日志文件的内容,将指令从前到后执行一次以完成数据恢复. appendonly(默认 no) appendfilename(默认 appendonly.aof) appendfsync(always+everysec+no 默认 everysec) no-appendfsync-on-rewrite:重写时,是否可以运用appendfsync,用默认no即可,保证数据完全性. 设置重写的基准值 auto-aof-rewrite-percentage(默认 100) auto-aof-rewrite-min-size(默认 64mb) 重写(rewrite): 是什么: aof采用文件追加方式,文件会越来越大,为了避免出现此种情况,新增了重写机制,当AOF文件的大小超过所设定的阈值时,redis就会启动AOF文件的内容压缩,只保留可以恢复数据的最小指令集.可以使用命令bgrewriteaof. 重写原理: aof文件持续增长而过大时,会fork出一条新进程,来将文件重写(也是先写临时文件最后再rename), 遍历新进程的内存中数据,每条记录有一条的set语句. 重写aof的操作,并没有读取旧的aop文件,而是将整个内存中的数据库用命令的方式重写了一个新的aof文件,这点和快照类似. 重写机制: redis会记录上次重写时的aof大小,默认配置是当aof文件大小是上次rewrite后大小的一倍且文件大于64M时出发. aof优势: 每秒同步:appendfsync 同步机制的粒度可控,从同步每个写操作,到不同步; aof劣势: 相同数据集的数据而言,aof文件要远大于rdb文件,恢复速度慢于rdb. aof运行效率要慢于rdb,每秒同步策略效率最好,不同步效率和rdb相同. rdb和aof比较: 两者可以共存,但redis实例启动时,首先会加载aof中的数据.(因为在通常情况下,aof文件保存的数据集比rdb文件保存的数据集要完整.) 当由于网络丢包或者人为 等原因,使得appendonly.aof文件里有不符合redis语法的数据存在,可使用redis-check-aof 命令来 删除这些不符合redis语法的字符串:redis-check-aof --fix appendonly.aof. 性能建议: 因为RDB文件只用作后备用途,建议只在Slave上持久化rdb文件,而且只要15分钟备份一次就够了,只保留save 900 1 这条规则. 如果Enable AOF ,好处是在最恶劣情况下也只会丢失不超过两秒数据,启动脚本较简单,只load自己的AOF文件就可以了.代价一是带来了持续的IO,二是AOF rewrite的最后将rewrite过程中产生的新数据写到新文件造成的阻塞几乎不可避免.只要硬盘许可,应该尽量减少AOF rewrite的频率,AOF重写的基础默认值64M太小,可以设到5G以上.默认超过原大小100%大小时重写可以改到适当的数值. 如果不Enable AOF ,仅靠Master-Slave Replication 实现高可用性也可以.能省掉一大笔IO,也减少了rewrite时带来的系统波动.代价是如果Master/Slave同时挂掉,会丢失十几分钟的数据,启动脚本也要比较两个Master/Slave中的RDB文件,载入小心的那个。(新浪微博就选用了这种架构) 事务: multi 开始标志 exec 执行队列里的命令 discard 放弃 watch key [key ...] 监视一个或多个key,如果在事务执行之前这些key被其他命令所改动,那么事务将被打断. unwatch 取消watch命令对所有key的监控. 全体连坐: 若某一条命令在加入执行队列时错误,则exec时, 这个队列里的所有命令都执行失败. 冤有头债有主: 若某一条命令成功加入了执行队列, 但exec时,改条命令报错, 则 不影响 这个队列里其他命令的执行. redis对事物部分支持,不像spring那样 若报错, 则整个回滚. watch监控 1.乐观锁/悲观锁/CAS(Check And Set) 悲观锁:认为每次拿数据的时候,都认为别人会修改,所以每次在拿收据的时候都会上锁,这样比人想拿这个数据就会block直到它拿到锁. 传统的关系型数据库里就用到了这种锁机制.比如 行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁. 当备份数据的时候,也应该选择悲观锁,保证数据一致. 乐观锁:认为每次拿数据的时候,都认为别人不会修改,所以不会上锁,但是在更新的时候,会判断一下在此期间别人有没有去更新这个数据,可以使用版本号等机制, 乐观锁适用于多读的应用类型,这样可以提高吞吐量. 乐观锁策略:提交版本必须大于记录当前版本才能执行更新. watch命令,类似于乐观锁,事务提交时,如果key的值已被别的客户端改变,比如某个list已被别的客户端push/pop过了,整个事务队列都不会被执行(此处 和 冤有头债有主 规则 不一致). 通过watch命令在事务执行前监控了多个keys,倘若在watch之后,任何key的值发生变化,exec命令执行的事务都将被放弃,同时返回nullmulti-bulk应答以通知调用者事务执行失败(在虚拟机中,版本3.2.8执行并未显示任何报错). 特性: 单独的隔离操作: 事务中所有的命令都会序列化,按顺序执行,事务在执行过程中,不会被其它客户端发送的请求所打断. 没有隔离级别的概念:队列中的命令没有提交之前都不会实际的被执行,因为事务提交前任何指令都不会被实际执行,也就不会存在“事务内的查询要看到事务里的更新,在事务外查询不能看到”这个让人头疼的问题. 不保证原子性: redis同一个事务中如果有一条命令执行失败,其后的命令仍然会被执行,没有回滚. 发布订阅 publish channel message subscribe channel [channel ...] 主从复制(master/slaver) 是什么:主机数据更新后,根据配置和策略,自动同步到备机的master/slavre机制,master以写为主,从机以读为主. 怎么玩: 1.配从不配主. 2.从库配置:slaveof 主库ip 主库端口(每次与master断开后,都需要重新连接) info replication 一主二从: 1.从机只能读,不能写; 2.一主二从,主机死了,从机并不会升级为master,可通过info repication 查看 3.当主机死了,重新启动后,从机会自动连接,当从机死了,重新启动,若配置文件中有指定slaveof 则会自动连接,否则不会自动连接 薪火相传: 1.上一个slave可以是下一个slave的master,slave同样可以接受其他slaves的连接和同步请求,那么该slave作为了链条中下一个master,可以有效减轻master的写压力. 2.中途变更专向:会清除之前的数据,重新建立拷贝最新的slaveof 新主库的ip 新主库端口. 反客为主: 1.slaveof no one 设置当前redis数据库停止与其他数据库的同步,转为主数据库. 复制原理: 1.slave启动成功连接到master后会发送一个sync命令,master接到请求命令,启动后台的盘存进程,同时收集所有接受大的用于修改数据集命令, 在后台进程执行完毕后,master将传送整个数据文件到slave,以完成一次完全同步. 2.全量复制:而slave服务在接收到数据库文件后,将其盘存并加载到内存中. 3.增量复制:master继续将新的所有收集到的秀改命令依次传给slave,完成同步. 4.但是只要是重新连接master,一次完全同步(全量复制)将被自动执行. 哨兵模式(反客为主的自动版): 是什么:反客为主的自动版,能够后台监控主机是否故障,如果故障了根据投票数自动将从库转换为主库. 操作: 增加配置文件:sentinel.conf,配置该文件:sentinel monitor 主机名 主机ip 端口号 投票数 启动命令:reids-sentinel sentinel.conf 若挂掉的redis重新启动后,自动变为新mater的slave. 复制的缺点: 由于所有的写操作都是先在master上操作,然后同步更新到slave上,所有从master同步到slave机器有一定的延迟,当系统繁忙的时候,延迟问题会更加严重,slave机器数量的增加也会是这个问题更加严重.
以下为哨兵部署练手test(在虚拟机上部署):
如上,已启动三个redis节点(在一台机器上).
三者都是主机:
现在设置端口号6379的节点为主机,其它两个(端口号为6380和6381)节点为从机;
如下:
现在编辑 哨兵配置文件sentinel.conf;
主要是如下一行:
sentinel monitor mymaster 127.0.0.1 6379 1
先设置端口6379的节点为主机,其它两个节点为从机;
启动哨兵(redis-sentinel config/sentinel/sentinel.conf ),现将端口为6379的节点shutdown掉,再看如下:
发现,端口号为6380的节点自动升级为主节点,端口号为6381的节点的主节点变为6380节点;
以上为哨兵的简单部署测试;
同时,若重新启动节点6379,会发现,节点6379也会变为节点6380的子节点,如下图:
这时,如果打开 三个节点的配置文件redis.conf中,
会发现节点6379的配置文件中增加了这么一行:slaveof 127.0.0.1 6380;
会发现节点6381的配置文件中也增加了这么一行:slaveof 127.0.0.1 6380;
同时哨兵配置文件sentinel.con中,
也多了几行文字:
# Generated by CONFIG REWRIT
sentinel known-slave mymaster 127.0.0.1 6379
# Generated by CONFIG REWRITE
sentinel known-slave mymaster 127.0.0.1 6381
sentinel current-epoch 2.
以上为这次redis系统学习的部分,此外,redis还有漂移和集群的知识有待学习.