解密Redis持久化

justjavac 发表于 2012-04-13

本文内容来源于Redis 作者博文,Redis作者说,他看到的所有针对Redis的讨论中,对Redis持久化 的误解是最大的,于是他写了一篇长文来对Redis的持久化进行了系统性的论述。

什么是持久化,简单来讲就是将数据放到断电后数据不会丢失的设备中。也就是我们通常理解的硬盘上。

写操作的流程

首先我们来看一下数据库在进行写操作时到底做了哪些事,主要有下面五个过程。

  1. 客户端向服务端发送写操作(数据在客户端的内存中)
  2. 数据库服务端接收到写请求的数据(数据在服务端的内存中)
  3. 服务端调用write(2) 这个系统调用,将数据往磁盘上写(数据在系统内存的缓冲区中)
  4. 操作系统将缓冲区中的数据转移到磁盘控制器上(数据在磁盘缓存中)
  5. 磁盘控制器将数据写到磁盘的物理介质中(数据真正落到磁盘上)

写操作大致有上面5个流程,下面我们结合上面的5个流程看一下各种级别的故障。

  • 当数据库系统故障时,这时候系统内核还是OK的,那么此时只要我们执行完了第3步,那么数据就是安全的,因为后续操作系统会来完成后面几步,保证数据最终会落到磁盘上。
  • 当系统断电,这时候上面5项中提到的所有缓存都会失效,并且数据库和操作系统都会停止工作。所以只有当数据在完成第5步后,机器断电才能保证数据不丢失,在上述四步中的数据都会丢失。

通过上面5步的了解,可能我们会希望搞清下面一些问题:

  • 数据库多长时间调用一次write(2),将数据写到内核缓冲区
  • 内核多长时间会将系统缓冲区中的数据写到磁盘控制器
  • 磁盘控制器又在什么时候把缓存中的数据写到物理介质上

对于第一个问题,通常数据库层面会进行全面控制。而对第二个问题,操作系统有其默认的策略,但是我们也可以通过POSIX API提供的fsync系列命令强制操作系统将数据从内核区写到磁盘控制器上。对于第三个问题,好像数据库已经无法触及,但实际上,大多数情况下磁盘缓存是被设置关闭的。或者是只开启为读缓存,也就是写操作不会进行缓存,直接写到磁盘。建议的做法是仅仅当你的磁盘设备有备用电池时才开启写缓存。

所谓数据损坏,就是数据无法恢复,上面我们讲的都是如何保证数据是确实写到磁盘上去,但是写到磁盘上可能并不意味着数据不会损坏。比如我们可能一次写请求会进行两次不同的写操作,当意外发生时,可能会导致一次写操作安全完成,但是另一次还没有进行。如果数据库的数据文件结构组织不合理,可能就会导致数据完全不能恢复的状况出现。

这里通常也有三种策略来组织数据,以防止数据文件损坏到无法恢复的情况:

  1. 第一种是最粗糙的处理,就是不通过数据的组织形式保证数据的可恢复性。而是通过配置数据同步备份的方式,在数据文件损坏后通过数据备份来进行恢复。实际上MongoDB在不开启journaling日志,通过配置Replica Sets时就是这种情况。
  2. 另一种是在上面基础上添加一个操作日志,每次操作时记一下操作的行为,这样我们可以通过操作日志来进行数据恢复。因为操作日志是顺序追加的方式写的,所以不会出现操作日志也无法恢复的情况。这也类似于MongoDB开启了journaling日志的情况。
  3. 更保险的做法是数据库不进行老数据的修改,只是以追加方式去完成写操作,这样数据本身就是一份日志,这样就永远不会出现数据无法恢复的情况了。实际上CouchDB就是此做法的优秀范例。
...

Python实用技巧-成为Pythoner必经之路

justjavac 发表于 2012-04-13

前言

本文主要记录 Python 中一些常用技巧,本文重点描述的是告诉你怎么写才是更好?

  • 如果你并不熟悉Python语法,希望你能在下面代码片段中看到Python的简单、优雅;
  • 如果你象我这样,对 Python 有兴趣或并正在学习,我相信下面的技巧并不会让你失望;
  • 如果你已经是一名 Pythoner ,那么很乐于你分享你的经验和技巧。

目录

  • Python 禅道
  • 代码风格: 提高可读性
  • PEP 8: Python 代码风格指南
  • 空格(行)使用 (1)
  • 空格(行)使用 (2)
  • 命名
  • 较长代码行
  • 较长字符串
  • 复合语句
  • 字符串文档 & 注释
  • 交换变量
  • 更多关于 Tuples
  • 关于 "_"
  • 创建String: 从列表中创建
  • ...

简明 Python 编程规范

justjavac 发表于 2012-04-13

编码

所有的 Python 脚本文件都应在文件头标上 # -*- coding:utf-8 -*-。 设置编辑器,默认保存为 utf-8 格式。

注释

业界普遍认同 Python 的注释分为两种的概念,一种是由 # 开头的“真正的”注释,另一种是 docstrings。 前者表明为何选择当前实现以及这种实现的原理和难点, 后者表明如何使用这个包、模块、类、函数(方法),甚至包括使用示例和单元测试。

坚持适当注释原则。 对不存在技术难点的代码坚持不注释,对存在技术难点的代码必须注释。 但与注释不同,推荐对每一个包、模块、类、函数(方法)写 docstrings,除非代码一目了然,非常简单。

缩进

Python 依赖缩进来确定代码块的层次,行首空白符主要有两种:tab 和空格,但严禁两者混用。 如果使用 tab 缩进,设定 tab 为 4 个空格。

推荐使用 4...

一天时间用python写门语言

justjavac 发表于 2012-04-13

今天没事做, 就又练习写计算器程序了. 本来打算用python来写一个简单的支持加减乘除括号的计算器, 后来有加上了变量复制, 比较符, 条件判断, 循环, 最后还加上了函数, 几乎可以说是一个简单的语言了. 以后我也可以说写过一门语言了哈哈.

回到正题. 这里面整理一下这个简单的程序用到的方法, 代码在: https://bitbucket.org/linjunhalida/code-example/src/tip/python/calculator/

一开始, 我希望实现一个简单的支持加减乘除括号的计算器, 我不打算用python自带的方式(eval), 而是自己写一个.

虽然有种种取巧的方式, 我还是采用教科书般的方法, 首先词法分析, 然后语法分析+计算结果.

词法分析

词法分析的函数是syntax_analysis, 输入一个字符串, 拆分成一个个的词, 解析整型和浮点.

比如: “2 * 3 + 1” 就拆分成 2, ’*’, 3, ’+’,...

多个github帐号的SSH key切换

justjavac 发表于 2012-04-13

github使用SSH与客户端连接。如果是单用户(first),生成密钥对后,将公钥保存至github, 每次连接时SSH客户端发送本地私钥(默认~/.ssh/id_rsa)到服务端验证。 单用户情况下,连接的服务器上保存的公钥和发送的私钥自然是配对的。

但是如果是多用户(first,second),我们在连接到second的帐号时, second保存的是自己的公钥,但是SSH客户端依然发送默认私钥,即first的私钥, 那么这个验证自然无法通过。 不过,要实现多帐号下的SSH key切换在客户端做一些配置即可。

首先cd到~/.ssh 使用 ssh-keygen -t -rsa -C 'second@mail.com' 生成新的SSH key:id_rsa_second,生成完后将新的SSH public key添加到github。

ssh-keygen -t -rsa -C 'second@mail.com'

默认SSH只会读取id_rsa,所以为了让SSH识别新的私钥,需要将其添加到SSH agent

ssh-add ~/.ssh/id_rsa_second

该命令如果报错:Could not open a connection to your authentication agent. 无法连接到ssh agent,可执行ssh-agent bash命令后再执行ssh-add命令。

...