第四章 数据安全与性能保障 Redis In Action阅读总结

        前面的几章介绍了各式各样的Redis命令以及使用这些命令来操作数据结构的方法,还列举了几个使用Redis来解决实际问题的例子。 为了让读者做好使用Redis构建真实软件的准备, 本章将展示维护数据安全以及应对系统故障的方法。另外,本章还会介绍一些能够在保证数据完整性的前提下提升Redis性能的方法。

        本章首先会介绍Redis的各个持久化选项, 这些选项可以让用户将自己的数据存储到硬盘上面。接着本章将介绍如何通过Redis的复制特性,把不断更新的数据副本存储到附加的机器上面, 从而提升系统的性能和数据的可靠性。 之后本章将会说明同时使用复制和持久化的好处和坏处, 并通过一些例子来告诉读者应该如何去选择适合自己的持久化选项和复制选项。 最后本章将对Redis的事务特性和流水线特性进行介绍, 并讨论如何诊断某些性能问题。

        阅读这一章的重点是要弄懂更多的Redis运作原理,从而学会如何在首先保证数据正确的前提下,加快数据操作的执行速度。

        现在, 让我们来看看Redis是如何将数据存储到硬盘里面, 使得数据在Re山s重启之后仍然存在的。

4.1 持久化选项

        Redis提供了两种不同的持久化方法来将数据存储到硬盘里面。 一种方法叫快照(snapshotting)它可以将存在于某一时刻的所有数据都写入硬盘里面。另一种方法叫只追加文件(append-onlyfile, AOF), 它会在执行写命令时,将被执行的写命令复制到硬盘里面。这两种持久化方法既可以同时使用,又可以单独使用,在某些情况下甚至可以两种方法都不使用,具体选择哪种持久化方法需要根据用户的数据以及应用来决定。

        将内存中的数据存储到硬盘的一个主要原因是为了在之后重用数据,或者是为了防止系统故障而将数据备份到一个远程位置。另外 , 存储在Redis里面的数据有可能是经过长时间计算得出的,或者有程序正在使用Redis存储的数据进行计算 , 所以用户会希望自己可以将这些数据存储起来以便之后使用,这样就不必再重新计算了。对于一些Redis应用来说 , ”计算 ” 可能 只是简单地将另一个数据库的数据复制到Redis里面(2.4节中就介绍过这样的例子),但对 于另外一些Redis应用来说,Redis存储的数据可能是根据数十亿行日志进行聚合分析得出的结果。

        两组不同的配置选项控制着Redis将数据写入硬盘里面的方式,代码清单4-1展示了这些配置选项以及它们的示例配置值。因为之后的 4.1. l 节和 4.1.2 节会更详细地介绍这些选项,所以目前我们只要稍微了解一下这些选项就可以了。

        代码清单 4-1最开头的几个选项和快照持久化有关,比如:如何命名硬盘上的快照文件、多久执行一次自动快照操作、是否对快照文件进行压缩,以及在创建快照失败后是否仍然继续执行写命令。代码清单的第二组选项用于配置AOF子系统(subsystem): 这些选项告诉Redis 是否使用AOF持久化、多久才将写入的内容同步到硬盘、在对AOF进行压缩(compaction)的时候能否执行同步操作,以及多久执行一次AOF压缩。接下来的一节将介绍如何使用快照来保持数据安全。

4.1.1 快照持久化

        Redis可以通过创建快照来获得存储在内存里面的数据在某个时间点上的副本。在创建快照之后,用户可以对快照进行备份,可以将快照复制到其他服务器从而创建具有相同数据的服务器副本, 还可以将快照留在原地以便重启服务器时使用。

        根据配置, 快照将被写入dbfilename选项指定的文件里面, 并储存在dir选项指定的路径上面。 如果在新的快照文件创建完毕之前, Redis、 系统或者硬件这三者之中的任意一个崩溃了, 那么Reclis将丢失最近一次创建快照之后写入的所有数据。

        举个例子,假设Redis目前在内存里面存储了10GB的数据,上一个快照是在下午2:35开始创建的, 并且已经创建成功。 下午3:06时, Redis又开始创建新的快照, 并且在下午3:08快照文件创建完毕之前,有35个键进行了更新。 如果在下午3:06至下午3:08期间, 系统发生崩溃, 导致Redis无法完成新快照的创建工作,那么Redis将丢失下午2:35之后写入的所有数据。另一方面, 如果系统恰好在新的快照文件创建完毕之后崩溃,那么Redis将只丢失35个键的更新数据。

创建快照的办法有以下几种:

• 客户端可以通过向Redis发送BGSAVE命令来创建一个快照。 对千支持BGSAVE命令的平台来说(基本上所有平台都支持, 除了Windows平台),Redis会调用fork1D来创建一 个子进程, 然后子进程负责将快照写入硬盘, 而父进程则继续处理命令请求。

• 客户端还可以通过向Redis发送SAVE命令来创建一个快照, 接到SAVE命令的Redis服务器在快照创建完毕之前将不再响应任何其他命令。 SAVE命令并不常用,我们通常只会在没有足够内存去执行BGSAVE命令的清况下, 又或者即使等待持久化操作执行完毕也无所谓的情况下,才会使用这个命令。

• 如果用户设置了save配置选项, 比如save 60 10000, 那么从Redis最近一次创建快照之后开始算起,当"60秒之内有10 000次写入“ 这个条件被满足时,Redis就会自动触发BGSAVE命令。 如果用户设置了多个save配置选项, 那么当任意一个save配置选项所设置的条件被满足时,Re山s就会触发一次BGSAVE命令。

• 当Redis通过SHUTDOWN命令接收到关闭服务器的请求时, 或者接收到标准TERM信号时, 会执行一个SAVE命令, 阻塞所有客户端,不再执行客户端发送的任何命令, 并在SAVE命令执行完毕之后关闭服务器。

• 当一个Redis服务器连接另一个Redis服务器, 并向对方发送SYNC命令来开始一次复制操作的时候,如果主服务器目前没有在执行BGSAVE操作, 或者主服务器并非刚刚执行完BGSAVE操作, 那么主服务器就会执行BGSAVE命令。更多有关复制的信息请参考4.2节。

        在只使用快照持久化来保存数据时, 一定要记住:如果系统真的发生崩溃, 用户将丢失最近一次生成快照之后更改的所有数据。 因此,快照持久化只适用于那些即使丢失一部分数据也不会造成问题的应用程序, 而不能接受这种数据损失的应用程序则可以考虑使用4.1.2节中介绍的AOF持久化。

4.1.2 AOF持久化

        简单来说, AOF持久化会将被执行的写命令写到AOF文件的末尾, 以此来记录数据 发生的变化。 因此, Redis只要从头到尾重新执行一次AOF文件包含的所有写命令, 就可以恢复AOF文件所记录的数 据集。 AOF持久 化可以通 过设置代码清单4-1 所示的appendonly yes配置选项来打开。 表4-1展示了appendfsync配置选项对AOF文件的同步频率的影响。

\

        如果用户使用appendfsyncalways选项的话, 那么每个Redis 写命令都会被写入硬盘,从而将发生系统崩溃时出现的数据丢失减到最少。不过遗憾的是, 因为这种同步策略需要对硬盘进行大量写入, 所以Redis处理命令的速度会受到硬盘性能的限制:转盘式硬盘(spinning disk)在这种同步频率下每秒只能处理大约200 个写命令, 而固态硬盘(solid-state drive, SSD) 每秒大概也只能处理几万个写命令。

        为了兼顾数据安全和写入性能, 用户可以考虑使用appendfsync everysec选项,让Redis以每秒一次的频率对AOF 文件进行同步。Re山s每秒同步一次AOF 文件时的性能和不使用任何持久化特性时的性能相差无几, 而通过每秒同步一次AOF 文件,Re山s可以保证, 即使出现系统崩溃, 用户也最多只会丢失一秒之内产生的数据。当硬盘忙于执行写入操作的时候, Redis还会优雅地放慢自己的速度以便适应硬盘的最大写入速度。

        最后, 如果用户使用appendfsync no选项,那么Redis 将不对AOF 文件执行任何显式的同步操作, 而是由操作系统来决定应该在何时对AOF 文件进行同步。这个选项在一般情况下不会对Redis的性能带来影响, 但系统崩溃将导致使用这种选项的Redis服务器丢失不定数量的数据。另外, 如果用户的硬盘处理写入操作的速度不够快的话,那么当缓冲区被等待写入硬盘的数据填满时, Redis的写入操作将被阻塞, 并导致Redis处理命令请求的速度变慢。因为这个因,一般来说并不推荐使用appendfsyncno选项, 在这里介绍它只是为了完整列举appendfsync选项可用的3个值。

        虽然AOF 持久化非常灵活地提供了多种不同的选项来满足不同应用程序对数据安全的不同要求, 但AOF 持久化也有缺陷􀇐随就是AOF 文件的体积大小。

4.1.3 重写/压缩AOF文件

        在阅读了上一节对AOF 持久化的介绍之后, 读者可能会感到疑惑: AOF 持久化既可以将丢失数据的时间窗口降低至1秒(甚至不丢失任何数据), 又可以在极短的时间内完成定期的待久化操作, 那么我们有什么理由不使用AOF持久化呢?但是这个问题实际上并没有那么简单, 因为Redis会不断地将被执行的写命令记录到AOF文件里面, 所以随着Redis不断运行,AOF文件的体积也会不断增长, 在极端情况下, 体积不断增大的AOF文件甚至可能会用完硬盘的所有 可用空间 。还有另一个问题就是, 因为Redis在重启之后需要 通过重新执行AOF文件记录的所有写命令来还原数据集, 所以如果AOF文件的体积非常大, 那么还原操作执行的时间就可能会非常长

        为了解决AOF文件体积不断增大的问题, 用户可以向Redis发送BGREWRITEAOF命令, 这个命令会通过移除AOF文件中的冗余命令来重写(rewrite)AOF文件, 使AOF文件的体积变得尽可能地小。 BGREWRITEAOF的工作原理和 BGSAVE创建快照的工作原理非常相似: Redis会创 建一个子进程, 然后由子进程负责对AOF文件进行重写。 因为AOF文件重写也需要 用到子进程, 所以快照待久化因为创建子进程而导致的性能问题和内存占用问题, 在AOF持久化中也同样存 在。 更糟糕的是, 如果不加以控制的话,AOF 文件的体积可能会比快照文件的体积大好几倍,在进行AOF重写并删除旧AOF文件的时候, 删除一个体积达到数十GB大的旧AOF文件可能会导致操作系统挂起(hang)数秒。

        跟快照持久化可以通过设置 save选项来自动执行BGSAVE一样,AOF持久化也可以通过设置 auto-aof-rewrite-percentage选项和auto-aof-rewrite-rnin-size选项来自动执行BGREWRITEAOF。举个例子, 假设用户对Redis设置了配置选项auto-aof-rewrite-percentage 100和 auto-aof-rewrite-rnin-size 64rnb, 并且启用了AOF持久化, 那么当AOF文件的体积大于64MB, 并且AOF文件的体积比上 次重写之后的体积大了至少 倍(100%)的时候,Redis将执行BGREWRITEAOF命令。 如果AOF重写执行得过于频繁的话, 用户可以考虑将 auto-aof-rewrite-percentage选项的值设置为100以上, 这种做法可以让Redis在AOF 文件的体积变得更大之后才执行重写操作, 不过也会让Redis在启动时还原数据集所需的时间变得更长。

        无论是使用AOF待久化还是快照持久化, 将数据持久化到硬盘上都是非常有必要的, 但除 了进行持久化之外, 用户还必须对待久化所得的文件进行备份(最好是备份到多个不同的地方),这样才能尽量避免数据丢失事故发生。 如果条件允许的话, 最好能将快照文件和最新重写的AOF文件备份到不同的服务器上面。

        通过使用AOF持久化或者快照持久化, 用户可以在系统重启或者崩溃的情况下仍然保留数据。 随着负载量的上升, 或者数据的完整性变得越来越重要时, 用户可能需要使用复制特性。

4.2 复制

        对于有扩展平台以适应更高负载经验的工程师和管理员来说, 复制(replication)是不可或缺的 。复制可以让其他服务器拥有 个不断地更新的数据副本,从而使得拥有数据副本的服务器可以用于处理客户端发送的读请求。关系数据库通常会使用一个主服务器(master)向多个从服务器(slave)发送更新, 并使用从服务器来处理所有读请求。 Redis也采用了同样的方法来实现自己的复制特性,并将其用作扩展性能的一种手段。 本节将对Redis的复制配置选项进行讨论,并说明Redis在进行复制时的各个步骤。

        尽管Redis的性能非常优秀,但它也会遇上没办法快速地处理请求的情况, 特别是在对集合和有序集合进行操作的时候, 涉及的元素可能会有上万个甚至上百万个, 在这种情况下,执行操 作所花费的时间可能需要以秒来进行计算, 而不是毫秒或者微秒。但即使一个命令只需要花费10毫秒就能完成,单个Redis实例(ins画ce) 1秒也只能处理100个命令。

        在需要扩展读请求的时候,或者在需要写入临时数据的时候(第7章对此有详细的介绍),用户可以通过设置额外的Redis从服务器来保存数据集的副本。在接收到主服务器发送的数据初始副本(initialcopy of the data)之后,客户端每次向主服务器进行写入时,从服务器都会实时地得到更新。在部署好主从服务器之后, 客户端就可以向任意一个从服务器发送读请求了, 而不必再像之前一样, 总是把每个读请求都发送给主服务器(客户端通常会随机地选择使用哪个从服 务器,从而将负载平均分配到各个从服务器上)。

4.2.1 对Redis 的复制相关选项进行配置

        4.1.1节中曾经介绍过, 当从服务器连接主服务器的时候, 主服务器会执行BGSAVE操作。因此为了正确地使用复制特性, 用户需要保证主服务器已经正确地设置了代码清单4-1里面列出的dir选项和dbfilename选项, 并且这两个选项所指示的路径和文件对于Redis进程来说都是可写的(writable)。

        尽管有多个不同的选项可以控制从服务器自身的行为,但开启从服务器所必须的选项只有slaveof一个。如果用户在启动Redis服务器的时候,指定了一个包含slaveof host port选项的配置文件,那么Redis服务器将根据该选项给定的IP地址和端口号来连接主服务器。对于一个正在运行的Redis服务器, 用户可以通过发送SLAVEOF no one命令来让服务器终止复制操作,不再接受主服务器的数据更新;也可以通过发送SLAVEOF host port命令来让服务器开始复制一个新的主服务器。

        开启Redis的主从复制特性并不需要进行太多的配置, 但了解Redis服务器是如何变成主服务器或者从服务器的, 对于我们来说将是非常有用的和有趣的过程。

4.2.2 Redis 复制的启动过程

        本章前面曾经说过, 从服务器在连接一个主服务器的时候,主服务器会创建一个快照文件并将其发送至从服务器,但这只是主从复制执行过程的其中一步。 表4-2完整地列出了当从服务器连接主服务器时, 主从服务器执行的所有操作。

        通过使用表4-2所示的办法,Redis在复制进行期间也会尽可能地处理接收到的命令请求,但是, 如果主从服务器之间的网络带宽不足, 或者主服务器没有足够的内存来创建子进程和创建记录写命令的缓冲区, 那么Redis处理命令请求的效率就会受到影响。因此, 尽管这并不是必须的,但在实际中最好还是让主服务器只使用50%􀂎65%的内存, 留下30%􀂎45%的内存用于执行BGSAVE命令和创建记录写命令的缓冲区。

        设置从服务器的步骤非常简单, 用户既可以通过配置选项SLAVEOF host port来将一个Redis服务器设置为从服务器, 又可以通过向运行中的Redis服务器发送SLAVEOF命令来将其设置为从服务器。如果用户使用的是SLAVEOF配置选项, 那么Redis在启动时首先会载入当前可用的任何快照文件或者AOF文件, 然后连接主服务器并执行表4-2所示的复制过程。如果用户使用的是SLAVEOF命令, 那么Redis会立即尝试连接主服务器, 并在连接成功之后, 开始表4-2所示的复制过程。

        当多个从服务器尝试连接同一个主服务器的时候, 就会出现表 4-3 所示的两种情况中的其中 一种。

        在大部分情况下, Redis 都会尽可能地减少复制所需的工作, 然而,如果从服务器连接主服务器的时间并不凑巧, 那么主服务器就需要多做一些额外的工作。另一方面, 当多个从服务器同时连接主服务器的时候,同步多个从服务器所占用的带宽可能会使得其他命令请求难以传递给主服务器, 与主服务器位于同一网络中的其他硬件的网速可能也会因此而降低。

4.2.3 主从链

        有些用户发现 , 创建多个从服务器可能会造成网络不可用一当复制需要通过互联网进行或 者需要在不同数据中心之间进行时, 尤为如此。 因为 Redis 的主服务器和从服务器并没有特别不 同的地方, 所以从服务器也可以拥有自己的从服务器,并由此形成主从链 (master/slave chaining)。

        从服务器对从服务器进行复制在操作上和从服务器对主服务器进行复制的唯一区别在于 , 如果从服务器X拥有从服务器 Y, 那么当从服务器X在执行表 4-2 中的步骤 4 时 , 它将断开与从 服务器 Y的连接 , 导致从服务器 Y需要重新连接并重新同步 (resync)。

        当读请求的重要性明显高于写请求的重要性,并且读请求的数拭远远超出一台 Redis 服务器 可以处理的范围时,用户就需要添加新的从服务裸来处理读请求。 随着负载不断上升,主服务器 可能会无法快速地更新所有从服务器,或者因为重新连接和重新同步从服务器而导致系统超载。 为了缓解这个问题, 用户可以创建一个由 Redis 主从节点 (master/slave node) 组成的中间层来分担主服务器的复制工作,如图4-1所示。

        尽管主从服务器之间并不一定要像图4-1那样组成一个树状结构,但记住并理解这种树状结构对于Redis复制来说是可行的(possible)并且是合理的(reasonable)将有助于读者理解之后的内容。本书在前面的4.1.2节中曾经介绍过, AOF持久化的同步选项可以控制数据丢失的时间长度:通过将每个写命令同步到硬盘里面, 用户几乎可以不损失任何数据(除非系统崩溃或者硬盘驱动器损坏), 但这种做法会对服务器的性能造成影响;另一方面, 如果用户将同步的频率设置为每秒一次, 那么服务器的性能将回到正常水平, 但故障可能会造成1秒的数据丢失。通过同时使用复制和AOF持久化, 我们可以将数据持久化到多台机器上面。

        为了将数据保存到多台机器上面, 用户首先需要为主服务器设置多个从服务器, 然后对每个从服务器设置appendonly yes选项和appendfsync everysec选项(如果有需要的话,也可以对主服务器进行相同的设置), 这样的话, 用户就可以让多台服务器以每秒一次的频率将数据同步到硬盘上了。但这还只是第一步: 因为用户还必须等待主服务器发送的写命令到达从服务器, 并且在执行后续操作之前, 检查数据是否已经被同步到了硬盘里面。

4.4 Redis事务

        为了保证数据的正确性, 我们必须认识到这一点:在多个客户端同时处理相同的数据时, 不谨慎的操作很容易会导致数据出错。本节将介绍使用Redis事务来防止数据出错的方法, 以及在 某些情况下, 使用事务来提升性能的方法。

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

        在Redis里面也有简单的方法可以处理一连串相互一致的读操作和写操作。正如本书在3.7.2节中介绍的那样, Redis的事务以特殊命令MULTI为开始, 之后跟着用户传入的多个命令, 最后以EXEC为结束。但是由于这种简单的事务在EXEC命令被调用之前不会执行任何实际操作, 所以用户将没办法根据 读取到的数据来做决定。这个问题看上去似乎无足轻重, 但实际上无法以 一致的形式读取数据将导致某一类型的问题变得难以解决, 除此之外, 因为 在多个事务同时处理同一个对象时通常需要用到二阶提交(two-phase commit), 所以如果事务不能以 一致的形式读取数据, 那么二阶提交将无法实现, 从而导致一些原本可以成功执行的事务沦落至执行失败的地步。 

        为什么Redis没有实现典型的加锁功能? 在访问以写入为目的数据的时候(SQL中的 SELECT FOR UPDATE), 关系数据库会对被访问的数据行进行加锁, 直到事务被提交(COMMIT) 或者被回滚(ROLLBACK)为止 . 如果有其他客户端试图对被加锁的数据行进行写入, 那么该客户端将被阻塞, 直到笫一个事务执行完毕为止. 加锁在实际使用中非常有效, 基本上所有关系数据库都实现了这种加锁功能, 它的缺点在于, 持有锁的客户端运行越慢, 等待解锁的客户端被阻塞的时间就越长.

        因为加锁有可能会造成长时间的等待, 所以Redis为了尽可能地减少客户端的等待时问, 并不会在执行WATCH命令时对数据进行加锁. 相反地,Redis只会在数据已经被其他客户端抢先修改了的情况下 , 通知执行了 WATCH命令的客户端, 这种做法被称为乐观锁(optimitic locking), 而关系数据库实际执行的加锁操作则被称为悲观锁(pessimistic locking)。 乐观锁在实 际使用中同样非常有效, 因为客户端永远不必花时间去等待第一个取得锁的客户端——它们只 需要在自己的事务执行失败时进行重试就可以了.

        当有多个客户端同时对相同的数据进行操作时,正确地使用事务可以有效地防止数据错误发生。 而接下来的一节将向我们展示,在无需担心数据被其他客户端修改了的情况下,如何以 更快的速度执行操作。

4.5 非事务型流水线

        第3章在首次介绍 MULTI和EXEC的时候讨论过它们的 ”事务“ 性质——被MULTI和 EXEC包裹的命令在执行时不会被其他客户端打扰。 而使用事务的其中一个好处就是底层的客户 端会通过使用流水线来提高事务执行时的性能。本节将介绍如何在不使用事务的情况下, 通过 使用流水线来进一步提升命令的执行性能。

        第2章曾经介绍过一些可以接受多个参数的添加命令和更新命令, 如MGET、MSET、HMGET、 HMSET、 RPUSH和LPUSH、 SADD、 ZADD等。 这些命令简化了那些需要重复执行相同命令的操作,并且极大地提升了性能。尽管效果可能没有以上提到的命令那么显著 , 但使用非事务型流水线(non-transactional pipeline)同样可以获得相似的性能提升,并且可以让用户同时执行多个不同的命令。

4.6 关于性能方面的注意事项

        要对Redis的性能进行优化, 用户首先需要弄清楚各种类型的Redis命令到底能跑多快, 而 这一点可以通过调用Redis附带的性能测试程序redis-benchmark来得知,.

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,214评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,307评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,543评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,221评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,224评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,007评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,313评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,956评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,441评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,925评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,018评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,685评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,234评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,240评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,464评论 1 261
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,467评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,762评论 2 345

推荐阅读更多精彩内容

  • 前言 在上一篇文章中,介绍了Redis内存模型,从这篇文章开始,将依次介绍Redis高可用相关的知识——持久化、复...
    Java架构阅读 2,293评论 3 21
  • 来源:脚本之家 这篇文章主要介绍了超强、超详细Redis入门教程,本文详细介绍了Redis数据库各个方面的知识,需...
    超_onlyu阅读 1,124评论 0 17
  • 超强、超详细Redis入门教程 转载2017年03月04日 16:20:02 16916 转载自: http://...
    邵云涛阅读 17,431评论 3 313
  • 文章已经放到github上 ,如果对您有帮助 请给个star[https://github.com/qqxuanl...
    尼尔君阅读 2,281评论 0 22
  • 小时候,大年初一,母亲总会带我们去城里看社火。只容得下一人行走的土路两边,盖满了摩天大楼,我和几个兄弟姐妹怯怯拽...
    Taoist_Lee阅读 308评论 0 1