redis目前对事务的支持比较简单,只能保证一个客户端连接发起事务中的命令可以连续执行,而中间不会插入其他客户端的命令。

1.事务

一般情况下,redis接收到一个客户端发送的命令,立刻执行并返回结果。但是当连接发出multi命令时,此连接便进入事务上下文,redis把此连接发送的命令保存到一个列队当中,当此连接发送exec命令时,redis便开始按顺序执行列队中的所有命令,并将所有命令执行的结果大包一起返回给客户端连接,然后此连接便结束事务。

例如:

例子中可以看出set 命令发出后并没有立即执行,而是存放在消息列队中。调用exec命令,set命令才开始连续执行,最后返回执行结果。

如果取消事务,可以使用discard 命令取消一个事务例如:

discard命令的作用是清空事务列队中的命令,并退出事务。

另外,redis只能保证事务的每个命令能够连续执行,但是事务中如果有命令执行失败,redis并不会回滚操作。

2.持久化

redis 是基于内存的数据库,内存数据库有个严重的弊端:突然宕机或者断电时,内容的数据不会保存。为了解决这个问题,redis提供两种持久化方式:内存快照(snapshotting)和日志追加(append-only file).

内存快照方式是将内存中的数据以快照的方式写入二进制文件中,默认文件名为dump.rdb

redis每隔一段时间进行一次内存快照操作,客户端使用save或者bgsave命令告诉redis需要做一次快照操作。save命令在主线程中保存内存快照,redis由单线程处理所有请求,执行save命令肯可能阻塞其他客户端请求,从而不能快速的相应请求,所以建议不要使用save命令。另外要注意,内存快照每次都把数据完整的写入到硬盘,而不是只写入增量数据。所以如果数据量大,写入操作比较频繁,从而严重影响性能。

内存快照相关配置:

save  <seconds>  <changes>

上面的配置表示经过seconds秒或数据更改changes次进行一次快照操作。例如下面的配置

save 1000 1

表示 1000秒或者数据更改1次就进行快照。也可以设置多个方案

save 1000 1

save 300 39

save 19 1111

这样,其中一个成立,redis就会进行快照。

如果使用 bgsave 进行快照   只需要直接发送  bgsave 命令就可以了

如果成功会返回

bgsave命令执行之后立即返回 OK ,然后 Redis fork 出一个新子进程,原来的 Redis 进程(父进程)继续处理客户端请求,而子进程则负责将数据保存到磁盘,然后退出。

而save是直接调用主进程所以会引起阻塞.

日志追加(aof)方式是把增加,修改数据的命令通过write函数追加到文件尾部(默认是appendoly.aof)。redis重启时读取appendonly.aof文件中的所有命令并且执行,从而把数据写入内容中。

另外,操作系统内核的I/O接口可能存在缓存,所以日志追加方式不可能立即写入文件中,这样就有可能丢失部分数据。幸运的是redis提供了解决的方法,通过修改配置文件告诉redis应该在什么时候使用fsync函数强制操作系统把缓存写入磁盘。有一下三种方法:

appendonly yes #启动日志追加持久化方式(yes|no)

#appendfsync always #每次收到增加或者修改命令就立即强制写入磁盘

appendfsync everysec #每秒强制写入磁盘一次

#appendfync no#是否写入磁盘完全依赖操作系统

日志追加方式有效降低数据丢失的风险,同时也带来了另外一些问题,即持久化文件不断变大。例如调用 incr nums 命令100次,文件就会保存100条incr nums 命令,其中99条是多余的,因为回复数据只需要set nums 100

为了压缩日志文件,redis 提供bgrewriteaof命令。当redis收到此命令,就是用类似内存快照方式将内存的数据以命令的方式保存到临时文件中,最后替换原来的日志文件。

3.主从同步

主从同步可以防止主机坏掉导致网站不能正常运行,这种方法即把从机设置为主机即可。redis支持主从同步,而且配置很简单。redis主从同步的有点如下:

master(主)可以有多个slave(从)

多个slave连接到同一个master,slave还可以连接其他slave形成图形结构。

不会阻塞master。当一个或者多个slave与master初次同步数据时,master可以继续处理客户请求。相反,slave在初次同步数据时会阻塞而不能处理客户端的请求(2.2以后不会阻塞)。

主从同步用来提高系统的伸缩性,比如多个slave专门用户客户端的读请求。

在master服务器上禁止数据持久化,只在slave服务器上进行数据持久化。

redis主从同步非常简单,设置好slave(从)服务器后,slave自动和master建立连接,发送SYNC命令。无论是第一次同步建立的连接还是断开后重新建立的连接,master都启动一个后台进程,将内存数据以快照的形式写入文件中,同时master主进程开始收集新的写命令并且缓存起来。master后台进程完成内存快照后,把数据文件发给slave,slave将文件保存到磁盘上,然后把数据加载到内存中。接着master把缓存命令发给slave,后续master收到的写命令都通过开始建立的连接发送给slave,当master与slave断开连接,slave自动重新建立连接。如果master同时收到多个slave发来的请求,其只启动一个进程写数据库镜像,然后发送给所有slave。

redis主从同步过程分为两个阶段,第一阶段如下:

1.slave服务器主动连接到master服务器

2.slave服务器发送sycn命令到master服务器请求同步·

3.master服务器备份数据库到rdb文件

4.master服务器把rdb文件传输给slave服务器

5。slave服务器清空数据库数据,把rdb文件数据导入数据库

完成第一个阶段,接下来master服务器把用户所有更改数据的操作,通过命令的形似转发给slave服务器,slave服务器只需要执行master服务器发送过来的命令就可以达到同步的效果。

相对于mysql来说,redis主从复制的配置很简答,只需要在slave服务器配置文件下添加

slaveof   master服务器ip:端口

例如:

slaveof 192.168.1.123:6379

4.虚拟内存

redis的数据保存在内存中,可能出现物理内存不足的情况。物理内存不足时,redis会使用虚拟内存(VM)。

VM是redis2.0新加的功能,之前redis把数据库中的所有数据放在内存中,随着redis的不断运行,使用内存会越来越大,最终导致内存不住。redis的VM与操作系统的VM相似,把很少访问的vlaue保存到磁盘中。与此同时,redis把value对应的key放在内存中,为了能够让redis快速定位到被被换出的value所在的磁盘位置,从而将其导入的内存中。

操作系统也有虚拟内存功能,为什么redis要重复‘制造轮子‘呢?主要原因有两点:

1.操作系统的VM是基于页的概念,比如linux系统中内个页是4kb,而redis大多数对象远小于4kb,一页行可能有多个redis对象。另外redis的集合对象类型与list,set可能存放在多个页上面。故redis自己实现可能达到控制换入的粒度。

2.redis将交换到磁盘的对象压缩,保存到磁盘的对象可以取出指针和对象元素信息。一般压缩后的对象比内存中对象小10倍,这样redis的vm比操作系统的VM少做很多I/O操作。

配置redis的VM

#开启VM

vm-enabled yes

#交换出来的value文件保存路径

vm-swap-file /tmp/redis.swap

#redis使用最大内存上线,超过后开始使用交换空间  单位字节

vm-max-memory  268435456

#设置每个页面的大小为32字节

vm-page-size 32

#最多在文件使用多少页面,swap文件的大小等于vm-page-size * vm-page

vm-pages 134217728

#用于执行value对象换出换入的工作线程数。0表示不使用工作线程

vm-max-threads 4

redis的vm只把value交换到磁盘中,而key依然存储在内存中,目的是让开启VM的redis和完全使用内存的redis性能基本保持一致。如果由于太多key而造成内存不住问题,redis的VM并不能解决。

和炒作系统一样,redis也按照页交换对象。一页只能保存一个对象,但是一个对象可以保存在多页中。

当redis使用的内存没有超过设置的vm-max-memory之前,不把任何value交换到磁盘中;当超过最大内存限制后,redis根据一下算法寻找一个对象交换到磁盘中:

swappability=age*log(size_in_memory);

其中age代表这个对象距离上一次被访问的时间,size_in_memry是这个对象在内存中占用的空间大小。redis采取的策略是把那些很少访问,而且占用内存又比较大的对象交换的齿盘空间中,但是第二个因素所占的权重更低,所以在公式中取log值。因为交换大对象时,需要占用更多的I/O和cpu资源。

应该更具自己的应用设置vm-page-size,设置太大浪费磁盘空间,设置太小照成swap文件出现过多碎片。

vm-max-threads 表示用于交换任务的工作线程数量,建议不要将vm-max-threads设置为0,设置为0时交换过程在主线程进行,从而阻塞其他用户。但也不是设置越大越好,因为太多的工作线程导致操作系统使用更多的时间来切换线程,从而降低效率。推荐吧vm-max-threads设置为服务器的cpu核心数。

为了理解VM子系统如何工作,需要了解对象在swap文件中如何存储。

swap文件中采用rdb文件的存储格式。swap文件被分割成固定数量的页,每页占用指定的数量的字节空间。在redis.conf中更具自己业务需求配置一下两个参数:

vm-page-size 设置每页的大小,默认值为32.

vm-pages设置能够使用的页数,默认值为134217728

redis在内存中保存一个bitmap以映射这些页是否被占用,每bit代表一个对应磁盘空间的页是否被占用。内存中保存这样一份映射表极大的增强了redis性能,同时,对内存的使用又非常少。

在持久化备份的时候,也会备份swap 中的数据只不过在备份时swap变为只读了,父进程和后台主进程只能访问swap。而父进程不能将value换入。

当一个value 交换到磁盘时,value对应的redis object 将被VM Pointer,VM pointer保存value在磁盘的信息。

交换过程:

从内存交换到swap中:

第一步。计算保存这个对象需要占用swap文件中多少页

第二步:在swap中寻找一段连续的空白页空间保存这个对象

第三步:把对象写入swap

从swap中交换到内存中

从swap文件交换到内存比较简单,因为在VM Pointer 中已记录对象在swap文件的页起始地址和占用页数,只要更具VM Pointer 把磁盘的对象换入内存即可。

redis 事务,持久化,日志,主从,VM的更多相关文章

  1. Redis之持久化和主从同步

    Redis作为内存数据库,所有数据都保存在内存中, 一旦程序停止工作, 数据都将丢失. 需要我们重新从其他地方加载数据. 不过Redis提供了两种方式保存Redis中的数据一种是dump内存直接存入r ...

  2. 分布式缓存技术redis学习系列(三)——redis高级应用(主从、事务与锁、持久化)

    上文<详细讲解redis数据结构(内存模型)以及常用命令>介绍了redis的数据类型以及常用命令,本文我们来学习下redis的一些高级特性. 安全性设置 设置客户端操作秘密 redis安装 ...

  3. 分布式缓存技术redis学习(三)——redis高级应用(主从、事务与锁、持久化)

    上文<详细讲解redis数据结构(内存模型)以及常用命令>介绍了redis的数据类型以及常用命令,本文我们来学习下redis的一些高级特性.目录如下: 安全性设置 设置客户端操作秘密 客户 ...

  4. 分布式缓存技术redis系列(三)——redis高级应用(主从、事务与锁、持久化)

    上文<详细讲解redis数据结构(内存模型)以及常用命令>介绍了redis的数据类型以及常用命令,本文我们来学习下redis的一些高级特性. 安全性设置 设置客户端操作秘密 redis安装 ...

  5. Redis(一) 数据结构与底层存储 & 事务 & 持久化 & lua

    参考文档:redis持久化:http://blog.csdn.net/freebird_lb/article/details/7778981 https://blog.csdn.net/jy69240 ...

  6. Redis数据库 02事务| 持久化| 主从复制| 集群

    1. Redis事务 Redis不支持事务,此事务不是关系型数据库中的事务: Redis事务是一个单独的隔离操作:事务中的所有命令都会序列化.按顺序地执行.事务在执行的过程中,不会被其他客户端发送来的 ...

  7. redis持久化,主从及数据备份

    http://blog.csdn.net/lang_man_xing/article/details/38386113 现在在项目里已经大量使用redis了,为了提高redis的性能和可靠性我们需要知 ...

  8. 《吊打面试官》系列-Redis哨兵、持久化、主从、手撕LRU

    你知道的越多,你不知道的越多 点赞再看,养成习惯 前言 Redis在互联网技术存储方面使用如此广泛,几乎所有的后端技术面试官都要在Redis的使用和原理方面对小伙伴们进行360°的刁难.作为一个在互联 ...

  9. Redis系列五 - 哨兵、持久化、主从

    问:骚年,都说Redis很快,那你知道这是为什么吗? 答:英俊潇洒的面试官,您好.我们可以先看一下 关系型数据库 和 Redis 本质上的区别. Redis采用的是基于内存的,采用的是单进程单线程模型 ...

随机推荐

  1. [JLOI2013]删除物品

    嘟嘟嘟 只要每一次将优先级最高的上面的物品移走,就一定能保证是最优解. 所以我们只要想办法简化这个模拟移物品的过程,看完了题解后,发现可以这么想,我们可以把两个栈头碰头的挨在一起,然后设一个指针代表两 ...

  2. Python os.walk() 方法

    #coding=utf-8 import os #(dirpath, dirnames, filenames)[文件夹路径, 文件夹名字, 文件名] def file_name(file_dir): ...

  3. oracle 批量更新merge语句

    merge into (SELECT * FROM QUERY_DB1.test_MPOS  ) T1 using (SELECT FLAG FLAG1,IN_MNO FROM QUERY_DB1.t ...

  4. Android failed to start daemon

    异常描述:在Eclipse中运行Android项目时Console中出现: The connection to adb is down, and a severe error has occured. ...

  5. docker 端口映射错误解决方法

    今天搞了半天shipyard,在网页上打开时无法显示容器和镜像,最后发现是docker端口映射错误,由于防火墙未关闭: 4月 12 18:51:29 localhost firewalld[757]: ...

  6. Landen邀请码

    Y2PZ6U8 landen 输入邀请码,注册一年会额外赠送一个月,注册两年会额外赠送三个月.

  7. 2017-2018-2 20155224『网络对抗技术』Exp6:信息搜集与漏洞扫描

    实践内容 各种搜索技巧的应用 DNS IP注册信息的查询 基本的扫描技术:主机发现.端口扫描.OS及服务版本探测.具体服务的查点 漏洞扫描:会扫,会看报告,会查漏洞说明,会修补漏洞 基本问题回答 哪些 ...

  8. 20155232《网络对抗》Exp2 后门原理与实践

    20155232<网络对抗>Exp2 后门原理与实践 问题回答 1.例举你能想到的一个后门进入到你系统中的可能方式? 通过网页上弹出来的软件自动安装 2.例举你知道的后门如何启动起来(wi ...

  9. 蒙特卡罗方法 python 实现

    蒙特卡罗(Monte Carlo)方法的精髓:用统计结果去计算频率,从而得到真实值的近似值. 一.求圆周率的近似值,采用 投点法 import numpy as np import matplotli ...

  10. C++中前置声明介绍

    前置声明是指对类.函数.模板或者结构体进行声明,仅仅是声明,不包含相关具体的定义.在很多场合我们可以用前置声明来代替#include语句. 类的前置声明只是告诉编译器这是一个类型,但无法告知类型的大小 ...