Redis数据安全与性能保障--持久化与事务

redis

持久化选项

Redis提供了两种不同的持久化方法来将数据存储到硬盘上:
一种方法叫做:快照(snapshotting),它可以将存在于某一时刻的所有数据都写入到硬盘数据里面.
另一种方法叫只追加文件(append-only file, AOF),它会在执行写命令时,将被执行的写命令复制到硬盘中.

这两种持久化方案既可以同时使用,又可以单独使用.

将内存中的数据存储到硬盘的一个主要原因是为了在之后重用数据,或者是为了防止系统故障而将数据备份到一个远程位置.

Redis事务

Redis的事务和传统的关系型数据库的事务并不相同.在关系数据库中,用户首先向数据库服务器发送BEGIN,然后执行各个相互一致(consistent)的写操作和读操作,最后,用户可以选则COMMIT来确认之前所做的修改,或者发送 ROLLLBACK 来放弃那些修改.

Redis里面也有简单的方法可以处理一连串相互一致的读操作和写操作.Redis的事务以特殊命令MULTI为开始, 之后跟着用户传入的多个命令,最后以EXEC为结束.

延迟执行事务有助于提升性能:因为Redis在执行事务的过程中,会延迟执行已入队列的命令直到客户端发送EXEC命令为止.很多Redis客户端都会等到事务包含的所有命令都出现了之后,才一次性的将MULTI命令,要在事务中执行的一系列命令,以及EXEC命令全部发送给Redis,然后等待直到接收到所有命令的回复为止,这种”一次性发送多个命令,然后等待所有回复出现”的做法通常被称为流水线(pipelining), 它可以通过减少客户端与Redis服务器之间的网络通信次数来提升Redis在执行多个命令时的性能.

WATCH 

Redis中除了常常使用的MULTL命令和EXEC命令之外,还需要配合使用WATCH命令,有时候甚至还会用到UNWATCH或DISCARD命令.
在用户使用WATCH命令之后,直到用户执行EXEC命令的这段时间里面,如果有客户端抢先对任何被监视的键进行了替换,更新或删除等操作,那么当用户尝试执行EXEC命令的时候,事务将失败并返回一个错误(之后用户可以选择重试事务或者放弃事务).通过使用WATCH,MULTI/EXEC,UNWATCH/DISCARD等命令,程序可以在执行某些重要操作的时候,通过确保自己正在使用的数据没有发生变化来避免数据出错.

什么是DISCARD?
UNWATCH命令可以在WATCH命令执行之后,MULTI命令之前对连接进行重置(reset); 同样地,DISCARD命令也可以在MULTI命令执行之后,EXEC命令执行之前对连接进行重置,这也就是说,用户在使用WATCH监视一个或多个键,接着使用MULTI开始一个新的事务,并将多个命令入队列之后,仍然可以通过发送DISCARD命令来取消WATCH命令并清空所有已入队列命令.

为什么Redis没有实现典型的加锁功能?
在访问以写入为目的的数据的时候(SQL中的SELECT FOR UPDATE),关系数据库会对被访问的数据进行加锁,直到事务被提交(COMMIT)或者被回滚(ROLLBACK)为止,如果有其他客户端试图对被加锁的数据进行写入,那么该客户端将被阻塞,直到第一个事务执行完毕为止,加锁在实际使用中非常有效,基本上所有关系数据库都实现了这种加锁功能,它的缺点在于,锁持有的客户端运行越慢,等待解锁的客户端被阻塞的时间越长.
因为饿加锁有可能会造成长时间的等待,所以Redis为了尽可能地减少客户端的等待时间,并不会在执行WATCH命令时对数据加锁.相反地,Redis只会在数据已经被其他客户端抢先修改了的情况下,通知执行了WATCH命令的客户端,这种做法被称为乐观锁(optimistic locking),而关系数据库实际执行的加锁则被称为悲观锁(pessimistic locking).乐观锁在实际使用中同样非常有效,因为客户端永远不必花时间区等待一个取得锁的客户端--他们只需要在自己的事务执行失败时进行重试就可以了.

非事务型流水线

想要能够达到事务型的流水线可以使用 MULTI 和 EXEC, 但是,MULTI和EXEC并不是免费的--他们会消耗资源,并且可能会导致其他重要的命令被延迟执行,不过好消息是,实际上可以在不使用MULTI 和EXEC的情况下,获得流水线带来的好处
pipeline
如果用户在执行pipeline() 时传入True作为参数,或者不传入任何参数,那么客户段将使用MULTI和EXEC包裹起用户要执行的所有命令,另一方面,如果用户在执行pipeline() 时传入False 为参数,那么客户端同样会像执行事务那样收集用户要执行的所有命令,只是不再使用MULTI和EXEC包裹这些命令,如果用户需要向Redis发送多个命令,并且诶对于这些命令来说,一个命令的执行结果并不会影响另一个命令的输入,而且这些命令也不需要以事务的方式来执行的话,那么我们可以通过向pipeline() 方法传入Fasle 来进一步提升Redis的整体性能.

坚持原创技术分享,您的支持将鼓励我继续创作!