Warning: call_user_func_array() expects parameter 1 to be a valid callback, no array or string given in /home/wushaobo/wushaobo.info/wp-includes/class-wp-hook.php on line 298
» Uncategorized Shaobo Wu's blog
RSS

Category Archives: Uncategorized

Vagrant 知识澄清与杂症诊治

版权声明:转载时请以超链接形式标明文章原始出处和作者信息及本声明
http://wushaobo.info/?p=83

Vagrant让虚拟化技术走近寻常家。脚踏实地地说,网络上类似“两分钟入门”的文章有不少,但求助各种问题的帖子更多,因为vagrant官网的文档太简洁了,这里头有些道理有些坑,都没涉及到。即便是O’Reilly两天前出版的《Vagrant: Up and Running》也含糊着某些问题。因而在Google了各种的前人零碎经验的基础上、以自己实践证明之后,有了我这篇文章,希望对涉及到的这些问题能汇总知识做一个澄清,并给读者一个可操作的指导。

文章结构

vagrant 的便利
vagrant 怎么玩
vagrant 到底怎么玩
vagrant 基础模板哪儿找
辨析 vagrant box | *.box文件 | VM | *.iso文件
Vagrantfile 怎么配
——- [HOWTO] 指定要使用的vagrant box和设置VM名称
——- [HOWTO] 设置VM对宿主机和外部机器的网络连接
——- [HOWTO] 配置并启动VM后运行后续安装脚本
疑难杂症
VM上端口的可访问性
修改默认ssh端口
将VM打包成*.box文件前清理网络设置上的障碍
设置共享目录位置与读写权限
多个VM的配置和启动

vagrant 的便利

  • 打造Virtual Machine的过程中可放手做尝试,反复从某个基础模板开始安装或设置。可快速推倒重来,可步步为营。
  • 可快速在一台宿主机上搭建多VM的EndToEnd环境。
  • 管理开发环境,可脚本化复制、操纵等行为,提高自动化程度。

vagrant 怎么玩

简单点说,三步走:

  • 安装vagrant、VM软件(Virtualbox是主流,后文也默认以此为例)
  • 给vagrant添加基础模板(box)
  • 配置Vagrantfile后用vagrant启动VM

满共就三个命令,有些人玩到这就觉得已经伟大的不得了了,至此ssh上VM各种虐。

你还差得远 !

vagrant 到底怎么玩

vagrant 基础模板哪儿找

www.vagrantbox.es介绍了vagrant的基础模板,并提供了满足各种需求的*.box文件供下载。

推荐选择 minimal + guest additions + puppet|chef 的box,理由:

  • 小,就意味着资源占用少
  • Virtualbox共享目录需要guest additions
  • 预装puppet或chef并非必选。它们对未来提升VM配置自动化有好处,本身不大

辨析 vagrant box | *.box文件 | VM | *.iso文件

解释词汇:

  • 打包了操作系统的*.iso文件是无法被vagrant直接使用的
  • VM是可启动/已启动的虚拟机
  • *.box文件是vagrant可接受的基础模板文件
  • vagrant box指vagrant已安装好的基础模板

辨析关系:

  • *.iso文件 可经Virtualbox界面的手动安装得到可启动的VM
  • VM 可被vagrant package命令打包成为 *.box文件
  • *.box文件 可被vagrant box add命令安装为 vagrant box
  • vagrant box 可被vagrant在Vagrantfile中指定为VM运行的基础模板

Vagrantfile 怎么配

Vagrantfile是vagrant配置VM的起点,官方文档里零零散散的说明让我明白了“东西很简单,但找对不容易”这句话。

对Vagrantfile,有几个常问 HOWTO

  1. 指定要使用的vagrant box和设置VM名称
  2. 设置VM对宿主机和外部机器的网络连接
  3. 配置并启动VM后运行后续安装脚本

[HOWTO] 指定要使用的vagrant box和设置VM名称

一看便知。

Vagrant.configure("2") do |config|      # ‘2’的意思是我所用的vagrant-1.2.2属于内部v2版 
  config.vm.define :web do |web_config| # 设置此VM名称为web
    web_config.vm.box = "apache-centos" # 指定使用已安装的名为“apache-centos”的vagrant box
  end
end

参考

[HOWTO] 设置VM对宿主机和外部机器的网络连接

  1. 当VM只与宿主机通信时,可设置为私有网络,等效于设置virtualbox使用host-only模式网络适配器。
     config.vm.network :private_network, ip: "192.168.50.4"
    
  2. 当寄宿与同一宿主机上的多台VM之间也需相互通信时,设置各VM为私有网络,但将固定IP设为同一网段。
  3. 当VM需要与宿主机网络内的其他机器通信时,设置为公开网络,等效于设置virtualbox使用bridged模式网络适配器,默认DHCP获取地址。
     config.vm.network :public_network   # vagrant-1.2.2之后的版本可能改用 :bridged
    

参考

[HOWTO] 配置并启动VM后运行后续安装脚本

  1. 追求简单,那么下面两条配置其一就够用了
     config.vm.provision :shell, :inline => "ifconfig"  # inline script
    
     config.vm.provision :shell, :path => "initialize.sh"  # external script
    
  2. 不得不复杂时,Chef / Puppet / Ansible 都是可供你用的。细致配置见参考
  3. 自动化部署是好的,但如果是VM每次安装固定软件,那么就不必了。大可以将不变的软件安装配置完成后,将VM打包成为*.box文件静态化,以后以此box文件作为基础模板做进一步配置。步步为营的提升基础的实践,会加速VM搭建过程并减少配置脚本。

疑难杂症

VM上端口的可访问性

尤其对不连外网的VM,我们辛苦建了它却不能访问它的端口,那要它何用?防火墙是阻止端口访问的罪魁,索性关了它吧。

Centos/Redhat/Fedora 用iptables管理firewall,所以两个办法搞掉它

  1. 停掉iptables的服务, 参考
     $ sudo service iptables save
     $ sudo service iptables stop
     $ sudo iptables off
    
  2. 索性干掉iptables的所有规则, 参考
     $ sudo iptables -F
     $ sudo iptables -X
     $ sudo service iptables save
    

Ubuntu 用ufw管理firewall,关掉它就是了,参考

$ sudo ufw disable

修改默认ssh端口

场景

ssh端口默认22,那位说“为什么我要改它呢”,我例举一个场景:

假如你要开发一个包含SFTP server的应用。为了给使用者提供便利,你最好保留22端口给用户,使他能使用默认方式通过SFTP传文件。同时,你要将这个应用部署到VM上做测试,那么VM的ssh login就不能同时也用22端口了,你需要为它指定新端口,如 10022。

难点

难点在于下面的约束条件:

  • 原有VM的基础模板默认使用22端口,所以vagrant不能一开始就弃用22端口,否则VM无法访问。
  • VM上ssh端口的改变为新端口后,再重启VM前需要更改Vagrantfile以选用新端口。
  • vagrant ssh命令并不直接访问VM的ssh端口,而是通过访问宿主机的22XX端口来间接ssh login到VM上。
  • vagrant内置了从宿主机22XX端口向VM的22端口的映射,如果VM的新端口并没有被指定映射到宿主机的某个端口上,vagrant ssh命令仍会访问原来的宿主机22XX端口即VM的22端口。(vagrant选择22XX端口时的尝试路线是:2222 -> 2201 -> 2202 -> 2203 -> … ,以此保证多台VM启动时不会有端口冲突。)

坑是挺多的吧?Vagrantfile的ssh settings参考forwarded ports参考可没把这事儿说这么清楚。

行动大纲

解决问题须要分几步走:

  1. 预先在Vagrantfile中为VM的新端口做端口映射
  2. VM上修改ssh使用的端口到新端口
  3. 在Vagrantfile中指定ssh login时使用VM的新端口
  4. [非必做] 建立新基础模板以固化上述更改

按步骤走起

Step1: 在Vagrantfile中为VM的新端口做端口映射

config.vm.network :forwarded_port, guest: 10022, host: 2255
# config.ssh.port = 2255            # port of host  # commented in step1
# config.ssh.guest_port = 10022     # port of VM    # commented in step1

Step2: VM上修改ssh使用的端口到新端口

  • VM上将22端口换为10022端口:vi编辑sshd_config文件( Centos/Ubuntu: /etc/ssh/sshd_config ;Mac OS X: /etc/sshd_config
      :%s/#Port 22/Port 10022/g
      :wq
    
  • 重启sshd服务
      $ sudo service sshd restart
    

Step3: 在Vagrantfile中指定ssh login时使用VM的新端口

config.vm.network :forwarded_port, guest: 10022, host: 2255
config.ssh.port = 2255          # port of host  # uncommented in step3
config.ssh.guest_port = 10022   # port of VM    # uncommented in step3

Step4 [optional]: 建立新基础模板以固化上述更改

使用vagrant package命令将改过端口的VM保存为box文件。由这个新基础模板所产生的VM中,10022即为ssh访问端口,使用上述的Vagrantfile可直接通过vagrant ssh访问。

vagrant package <vm-name> --output <new-base.box>

生成新*.box文件前须清理网络设置上的障碍。详见下文。

将VM打包成*.box文件前清理网络设置上的障碍

将手动配置过的VM重新打包生成*.box文件作为新基础模板,在这件事上对linux-based的VM有个关于网络设置的障碍。

问题表现

例如设置了private network(等同于virtualbox设置host-only模式的网络适配器)的VM,若不做准备而直接使用vagrant package生成新box文件,那么安装此box文件到vagrant box后在启动VM时,会发现当前Vagrantfile指定的private network配置失败。

[default] Configuring and enabling network interfaces…

The following SSH command responded with a non-zero exit status.
Vagrant assumes that this means the command failed!

/sbin/ifup eth1 2> /dev/null

被启动的VM以让可以通过vagrant ssh命令去访问,但网络配置上却没有host-only模式的适配器。

分析解决

还记得配置private network时设置的固定ip地址么?是的,问题就在持久网络设备udev规则(persistent network device udev rules)是被原VM设置好的,再用box生成新VM时,这些rules需要被更新。而这和Vagrantfile里对新VM设置private network的指令发生冲突。

既然以后在Vagrantfile里显示地设置private network ip是免不了的,那么只要在生成box文件前干掉udev规则就是了。

sudo rm -f /etc/udev/rule.d/70-persistent-net.rules

题外话

有趣的是这篇参考细述了这个问题的因果与对策,反倒是O’Reilly出版的《Vagrant: Up and Running》一书中(第6章)对此含糊带过。

该书计划于2013年6月12日出版。试读版中尚仍有对过时命令的介绍(如“repackage”),希望正书出来了不会立即过时。

学习的话,官网文档还是应该对照的。

设置共享目录位置与读写权限

Virtualbox共享目录需要VM上装有Guest Additions。自己安装到VM再打包成box文件做基础模板,或者一开始就找好合适的box文件(前文提到过),随便你怎么整好。

vagrant 默认将宿主机上Vagrantfile所载目录共享至VM上的 /vagrant 目录。

我们常需要的是指定共享某个目录,为此vagrant 支持两种方式:

简单:vboxsf

vboxsf是VirtualboxSharedFolder(或VboxSharedFolder)的缩写。很多人知道可以指定vboxsf作类型来mount,却不知这个这个词全称,甚至误解为“虚拟机文件系统”而错写成vboxfs。

vagrant默认使用这种方式共享目录。优点方便,缺点是性能不好。配置时,只要在Vagrantfile里指明:

config.vm.synced_folder "path/on/host", "/absolute/path/on/vm"
  • 前一个参数须是宿主机上已存在的目录,若为相对目录,那是相对Vagrantfile所在目录。
  • 后一个参数须是VM上的绝对路径,若不存在,vagrant会在启动VM时建好,多层的目录也没关系。

正经:NFS

NFS是正途,不过它也挑剔。

vagrant 内置了宿主机和VM两端对NFS的支持与配置的协调。如果你用windows,那vagrant当作你的配置不存在,直接忽略(我也觉得你在瞎胡闹)。Vagrantfile里很容易,标上标记就行了:

config.vm.synced_folder "path/on/host", "/absolute/path/on/vm", :nfs => true
  • 两个目录可以一样,如都用 “/shared”,藉此建立多个机器节点的共享存储了。

NFS的共享目录这种方式的挑剔之处在于目录内的读写权限。

读写权限

以建立宿主机与VM的共享存储这个应用场景为例,目标是:

  • 两端对共享目录(/shared)的读写无限制
  • 没有root权限的麻烦

如果你在宿主机建/shared,然后直接配置关联,那对上述两个目标你都会失败。按我说的步骤来吧:

  1. 宿主机上将建立的共享目录改为可读写
     $ sudo chmod o+w /shared
    
  2. 设置为non-root用户所有
     $ sudo chown <user>:<group> /shared
    
  3. 配置了Vagrantfile后启动VM
     config.vm.synced_folder "/shared", "/shared", :nfs => true
    

这样得到的共享目录对场景设定的目标已大功告成了:

  • 在宿主机和VM两端都它都不是root用户所有
    • 宿主机上 /shared 属于例如twer用户。
    • VM上 /shared 所属的用户会是个数字,如1000。
  • 在宿主机和VM两端它都对读写无限制

多个VM的配置和启动

单Vagrantfile vs 多Vagrantfile

虽然vagrant支持在一个Vagrantfile中配置多个VM,但我个人喜欢为各VM写各自的Vagrantfile。

  • 一来,各个VM的配置和启动都相对独立,如vagrant ssh时可不指定VM名,用默认。
  • 二来,Vagrantfile也不至于常常要改。

不过真正的牛人没我这么小家子气。用统一的一个Vagrantfile来管理多个VM,从大局着眼确是有好处的:

  • 一个Vagrantfile收录了整个大环境中所有VM的基本配置,维持了虚拟网络的上下文完成。你一眼就知道环境里共有哪些VM,也不需要切换目录来检查各VM的状态,跟不会搞混了目录“丢掉”哪个倒霉的VM。
  • 更多地使用Chef/Puppet来配置各VM,比如把VM的ip配置从Vagrantfile后推到puppet进行,保持Vagrantfile的简洁。目的是在对本地环境的VM配置与E2E环境(甚至生产环境)的节点配置上,保持较高的一致性,有利于统一部署方式。

要自动化

自动化都求个极致,一条命令搞定的工作就不乐意让人敲几行。你要夹杂写手动配置再写个说明文档啥的,那你真不该好意跟人打招呼。自动化测试也期望有可执行来自动配置环境的脚本。

从简单做起吧,合并你能想到的某项任务的几步变为脚本一次执行,比如:

  • 推倒重建一个VM
  • 推倒重建一组VM,
  • 初始化一组的vagrant box
  • VM启动后执行post-install
  • ……

会越玩越有感觉的。

 
Comments Off on Vagrant 知识澄清与杂症诊治

Posted by in Uncategorized

 

Tags: ,

上线,怎么就纠结了?

现象

项目每个迭代结束都发布上线。最近上线模式变了,似乎所有人突然变得很纠结,都围绕着上线二字郁闷着:

@ Customer Care Center – 线上版本有个Bug,客户抱怨了,能不能尽快把修改后的功能上线啊。
@ IM – 似乎有些天没上线新功能了,尽快上线一次吧。
@ Business people – 不确定哪些新功能需要在接下来上线啊,反正可以随时上线嘛,让我再想想。
@ UX – 觉得UI还不够好,期望将自己的设计细节被完全实现了再上线,不完美宁愿不上线这个功能。
@ OPS – 一键部署已经完成搭建并随时待命了,终于不用再一个迭代上线一次了。团队可以随时在半小时内将最新代码上线,因此要求主干代码永远干净。
@ TechLead – 要保证主干上的代码随时能上线,同时要保证所有人的代码能持续集成,还要保证没有被Business的人认可的功能暂时不开放,只好选择使用feature toggle的方案了。虽然减少了代码分支的方案可能为DEV带来的集成上的苦恼,但DEV和QA在新增和测试feature toggle上工作量的增加是逃不掉了。
@ BA – 到底Business的人想要上线哪些功能啊,一会儿要这个一会不要那个?已经打包成了这么多版本的包,每个包里有哪些功能啊,又有哪些是已加上了toggle被隐藏了的啊?
@ QA – 哪能说上线就上线?要保证质量,要按流程在每个环境上测试;不仅测功能本身,还要测feature toggle开/关下的情况,以及层叠的toggle关系下的情况。每拿到一个包,都要把里面开放和关闭的功能历数一遍,好麻烦。
@ DEV – 现在提交代码要小心了,随时上线呢,万一把主干上的代码弄脏了,或者把人家还没决定好要上线的功能忘了加toggle就提交了,那就麻烦了。话说这story不就是改改UI么,偏偏为加个toggle写这么多代码。
@ PM – 协调所有人关于上线的意见真是费精力啊,怎么样才能让事情顺利起来呢?一定有些什么可以做来改变现状的。

梳理

整理了一些因果线索

1)Business people不确定什么功能需要在接下来上线
=> BA不知道功能的优先级,计划做不好
=> Kick off可能还不能上线的用户故事
=> DEV不得不加toggle以隐藏此功能
=> QA不得不花更多时间去测试toggle本身

2)OPS要求主干代码干净,保证随时能上线
=> 综合Business people对暂时隐藏部分功能的需求,以及代码持续集成的考虑,TechLead敲定使用feature toggle来处理未完成功能和暂不开放功能
=> QA测试工作量增加,同时要求未被sign off的功能必须及时toggle off
=> DEV代码工作量增加,而且在没有加feature toggle或功能未完成前不敢提交代码,代码集成次数减少
=> BA交流工作量增加,不得不每天整理可能上线的版本中所含功能的情况

3)回想从前两周迭代结束时冻结代码并上线的经历:
那时,所有人都清楚代码冻结的时间点,所以只为个别的未完成功能而加feature toggle
<=> 现在,大家对“随时都有可能取主干代码来上线”充满恐惧,因而被迫添加更多的feature toggle或在某些功能完成前不提交。

应对

我逐渐看到了本源,于是有三招出炉。

应对第一招:控制上线时间点,取回部署主动权。

好处是:
* 充分规划在接下来上线的版本中涵盖哪些功能
* 为开发过程拉开缓冲区,减少因未完成功能而加的feature toggle
* 放松DEV们绷着的弦,让他们正常提交,坚持持续集成

应对第二招:功能性问题完成后及时上线,小改进不阻大进度。

想做到频繁部署,一方面要有好的工具能及时部署指定版本,另一方面要对线上版本做好容错准备。一键部署工具确实带来很大的便利,让部署变得快速简单;而always beta的概念告诉我们苛求一时的完美是无意义的,要先容忍一些非核心问题滞留,同时容忍一些状况发生的可能性,或在之后的上线版本中持续改进。

应对第三招:搞清接下来要交付什么,不要盲目开始或盲目等待。

也许你会说,人家Business people没拿定注意要上线什么功能,我能怎么办?当然有我们能做的。
* 给他们压力让他们尽快去想去研究,争取在迭代开始就确定好要上线的是些什么,尽量避免开始一个不确定要不要的功能,以及之后可能出现的需求反覆。
* 保持急需的修改能及时地作为补丁上线。

之后总结

等着看…… 到时再写下来

 

影响力 – 从众心理

社会认同原理的根本,是人的社会存在感。周围人的目光就是人的一面镜子,人都希望镜子中的自己完美一点,不希望照出一副丑恶的相貌,所以人都会在意,即追求社会认同。人们或许会刻意表现,或许会遮遮掩掩;追求个性或抢占高枝儿的其实就想听一句称赞,埋在人群中随大流的其实只是不想被看做另类。

环境与从众心理

环境影响人。也许有少数能有所超脱,能与众不同,但大多数终归都融在了方方面面的圈子当中,与圈中的人群达成了统一。每个人在行为上都被圈中其他人的目光影响着,如果选择呆在圈中,就不得不跟其他人统一,否则他就不再属于这个圈子。从环境得到的社会证据,对人的顺从压力是十分巨大的,而且直接作用于你的潜意识,当你发现时你确实有权不顺从它,但常常你不会,更想不了那么多。

为了避免麻烦,照着别人做就变成了简便方法,久而久之,从众就成了人类的一种习惯。

来看心理学家做过的一个从众心理的实验的视频。实验安排在电梯里,利用狭小的空间创造出一个与外隔绝的环境。几个辅助实验人员跟随一个受试者走进电梯里,之后做出统一的动作,观察受试者的反应。辅助实验人员全部背对镜头,而可怜的小白鼠对一切都毫不知情。

只用“避免面对面的尴尬”的理由,怕是解释不了受试者的反应了吧!

相似性与维特效应

我们会观察周围所有的人,但当我们观察与自己情况相似的人的行为时,社会认同原理在我们身上能发挥出最大的影响力。我们的潜意识这样认为:于己相似性越高的人的选择越值得参考,源于他的社会证据越有说服力。

虽是做判断时的一念之差,但一切改变由此而生,因为人类有一项从做猿猴时就养成的本能——模仿。有时是有意识地学,有时却是无意识地盲从,总之都是从众心理地表现。

有一个句型像这样:“那谁谁的情况和你一样,后来人家如此如此做,结果就好/糟了。”广告上一个小伙子咳着嗓子,旁边大妈说:“你有这些症状吧,那是咽炎的表现,快吃X咽X宁吧,我儿子就和你一样,一吃就见效!”果然小伙儿一吃就表现出好了的样子……任谁在难受时看见了,都忍不住会拿自己类比一下吧?甚至模仿一下。这时是有意识去模仿。

另一种思路像这样:“那么多人都那样做,他们肯定比我多知道些什么,跟着他们做吧,应该没错。”下班时间拥挤的城市道路上,车辆排队挪动着,突然前面两辆车都打起转向灯,向相邻道上去;后车司机虽未见到前方有事发生,但也满腹狐疑地跟着这两辆车变了道;后面的车看到前面越来越多的车都在变道,于是对变道的疑虑更少了。结果大家都一窝蜂地想往隔壁道上去,造成交通事故和堵塞。仿照别人开车就像条件反射,自己常常意识不到。

维特效应是社会认同原理因相似性而发挥惊人影响力的著名例子,取名出自歌德的小说《少年维特之烦恼》。这本著名的小说曾经轰动一时,让歌德一夜成名;书中主人公维特自杀而告终,由此竟带动了欧洲的一阵自杀浪潮。当代的研究从数据中发现,对自杀的新闻报道常会带来当地自杀发生率的大幅提升,而对自杀事件的低调报道也成了媒体工作者必须知道地行规之一。不可否认的是,富士康系列事件里,第一个跳楼的人确实给追随他的人带了个坏头儿。

危害与避免

社会认同原理带来的危害有两方面,概括地讲就是蓄意谋利和无心之失。

蓄意地伪造社会证据,让别人因从众心理走入圈套之中,这是当“托儿”的人的基本目标。当别人用嘴说,或通过行动传达“其他人都那样做,你也应该跟着做”的信息给你时,你要闻一闻有没有人造因素在里面,敏感地察觉情况,不要轻易就相信了。还要明辨是非,尽量以事实证据做依据,不要完全依赖于观察别人身上的反馈。三人成虎的典故说的可不止是轻信人言的故事。

无心的失误常因情况不清而难以避免。也许和你处在类似情况的人们都在那么做,但家家有本经,考虑的理由未必相同;也许和你站在一起围观的人都没动静,也可能是别人看见其他人都没动静。这时最重要的是理解别人和你都可能有不确定的心理状态,都有盲从的冲动。不要总以为别人都比你掌握了更多的信息,因此才做出某种反应,那可能是从众心理,可能是多元无知效应。

 
Comments Off on 影响力 – 从众心理

Posted by in Uncategorized

 

影响力 – 多元无知效应

“不确定”

社会认同原理告诉我们:在判断何为正确时,如果自己不确定,人会根据别人的意见行事。

人在遇到某种情况时,如果自己不确定,会本能地观察周围人的反应,从他们身上搜集社会证据来修正自己的判断。

多元无知效应

类似于下面的情形,相信你一定遇见过。一件事在众人身边发生,大家都发现了,我只是不清楚到底怎么了,于是瞄一瞄其他人,发现其他人没什么反应,就不当回事儿了;其实情况很紧急,但看到身边的人都不怎么上心的样子,自己也就觉得没那么紧急,如果喊出来反而会被人觉得是大惊小怪了。

比如见到一个人坐倒在街边,前面来来往往的人都看一看走过了,你有多大的几率会停下来问他的情况呢?几乎没有吧?有人说,这是我们社会在变无情,人们在变冷漠。诚然,城市居民疏远的事实让我们承认:城市里,人与周围人的距离越来越远,尤其对陌生人,会以沉着的方式隐藏自己,忽略别人身上所发生的事。但我要为这些扣上“冷漠”的帽子的人们开脱开脱,也包括为我自己。

这种集体冷漠真的是因为在场的所有人都没有动念头、都各扫门前雪吗?不是,起码不全是。每个人都是独立的个体,每个人都被社会认同原理影响着,也就是说,当我发觉事情不正常时,其他人也发现了,所有人都不能确定情况;我在观察周围人的反应时,其他人也在观察;我在搞清楚之前会毫无举动,其他人也在保持冷静;我们所有人都看到其他人没什么反应,所以告诉自己,不需要担心不需要管,只要和别人保持一致就可以了;结果就出现了集体的冷漠。

这就是多元无知效应!每个人都得出判断:“既然没人在乎,那就应该没什么问题。”于是紧急的事在人眼中变得不紧急。

除非,事情紧急得达到了某一程度,人的判断才不再会参考其他人的反应,也就通常所说的“看不下去了,必须出手了”。这个紧急程度因人而异,与社会责任感有很大关系,比如新闻报道的“女老外跳入西湖救人,众中国爷们集体围观”的事。不作评论了,只是想说,多元无知效应发生在任何国度,但不同背景的人的素质有差别。

责任分散原理

与多元无知效应结合紧密的是责任分散原理:当分担所有责任的人越少时,每个个体身上的责任越明确,他的责任感越强,立即行动的可能性也越大;反之,当越多人分担全部责任时,每个个体身上的责任越模糊,他的责任感就不那么强,也未必会有行动。

面对发生在众人面前的事件,大家都会先观察周围人的反应,同时评估自己身上应承担的责任,以此来判断是否该做出某种行为。比如大家都有做出响应的责任,但我清楚大家都有这样的责任,而我不是直接责任人,何况“也许有人已经做了”,“只是我没看到、不了解”,“我不是非这么做不可”,“有这么多人,为什么非要我做”。众多心思,成就了一致的“冷漠”。即使最终悲剧了,我也会说“又不是我一个人的事”而不那么自责。相信每个人都体会过中国式课堂上,“一人提问众人无声”的尴尬吧?

如何避免?

清楚了多元无知效应与责任分散原理,你已经对那种情形下众人的心思有所了解了,接下来就是应对。我分为两方面来说,一是作为“旁观者”,另一是作为“求助者”。

作为旁观者,

  • 我们不要随便忽略自己对事件的第一感觉,不要随大流就算了,因为你已经明白社会认同原理是怎样操纵你的判断了,事实就是事实,别人不在乎不代表着你也应该不在乎。
  • 不要让多元无知效应轻易发生,我们应该敏感地意识到且勇敢地打破它。不要怕被认为是大惊小怪,告诉别人你注意到了什么,站出来引导众人面对现实,而不是躲在假装冷漠的面具之下。
  • 我们应当主动发挥责任感,即便是唐突地多此一举,也应核实下确实有人在承担这份责任了。

作为求助者,

  • 要让周围人明确地知道我需要立即帮助,让周围人从不确定中走出来,意识到事态紧急。
  • 要让责任集中于某人或某几个人身上,避免责任分散,让帮你的人意识到“应该帮他的确实是我”。
  • 告诉帮你的人如何做,消除他不清楚如何做的不安。

为求助者加上一个例子,比如你在街上意外倒下了,周围人看着你,也许他们眼神很关切,但在弄清楚“怎么了”之前他们不会帮你去医院;你痛苦地呻吟着,并且把手伸向四面,围观的人可能会像看要饭的一样看你了;如果你拉住一个人,不停地说“帮帮我,帮帮我”,他只会惊慌地想“该怎么办”,如果没有得到答案,他宁可推开你走掉。所以,从开始求助那一刻,你不要死等什么耐心的志愿者了,明确地说出自己突然病了,请“穿XX颜色衣服的先生”帮忙打个电话叫救护车。

如果你不懂这些,悲剧可能隔天见报;如果你明白了,那你肯定也懂了如何写高效的求助邮件。

 

 
Comments Off on 影响力 – 多元无知效应

Posted by in Uncategorized

 

影响力 – 知觉对比心理

人类社会发展到今天,人们都说文明进步了许多,我却觉得现在的人比前人更没有安全感。是因为犯罪依然在身边发生么?是因为战争的手段更加复杂么?是因为一不小心就“知道得太多了”么?不是。对老百姓而言,是自己敢放心去做的事越来越少了。

英国著名的哲学家阿尔弗雷德·诺斯·怀特海德曾说:“文明的进步,就是人们在不假思索中可以做的事情越来越多。”想想我们的生活中,怎么越来越多的事情都要仔细小心才敢做?不禁感慨,要考虑的时候太多了。更不幸的是,我们不得不考虑下去,因为我们要生存,要适应。我们不愿加入到那群在社会上把水搅浑的人中,我们想坚持正义与善良。理解影响力怎样作用于人们的心理,会让我们学会如何抵御牟利者的影响力花招,同时善意地帮助或影响身边的人。

回归正题。

什么是知觉对比心理?

知觉对比心理是人类在判断时会参考对比物找到依据的心理。因为对比,人们常扭曲了自己对事物原本的认识。期中考试100分但期末考试98分的学生竟然是退步的;本来5块一碗的面放在菜单上和海鲜一比,卖15也不觉的贵了;常常看美女模特照片的哥们,去相亲时一个个的长相都看不上了。这都是知觉对比心理带来的麻烦。

知觉对比心理如何被人利用?

仅以商品价值为例。这个时代的社会已经不渐渐尊重价值了,越来越多的人敢跳出来做推手,一是因为他们唯利是图,二是因为人们无法像古人一样很快地能鉴定物品的价值,第三是因为人们心中“一分价钱一分货”的善良心理尚未泯灭。有些人玩起了这样的手段:

同样的商品,凭借稍稍华丽的装饰,卖高出许多的价钱,客人无法立刻判断东西质量的好坏,只要价钱还可接受,本能地相信“买贵一点的应该没错”。尤其是那些买礼品的客人。

去买西服,导购小姐先带你看10000元的高档货,然后才带你看你要的3000元的档次,这时你会觉得3000的便宜多了,质量也只差一点点,更容易就接受了;接着导购小姐推荐你一件400元的毛背心搭配,你一试穿确实挺好看,买了。如果一上来你先看400的毛背心,也许就已经觉得不值了,再看3000的西服时,就更不能接受这价格了。

如何应对或使用?

如果你是被影响的一方,大多数时候我们都是,就不得不用理性的思考与自己的本能战斗。你应该及时意识到可能是知觉对比心理在作怪,这是关键,然后试着抛开对比去做判断。当你身处对比之中时,可试着去想“如果没有参考做比较,我觉得它怎么样”,这个方法很有效,尤其对有选择困难综合的人群。

如果你是手持影响力武器的一方,以不作假骗人为前提,你已经找了一条很好的说服手段,就是引入对比,让对方的知觉对比心理悄悄生效,让别人的思路导向你有利的方向。为了让你更有把握,还要结合其他影响力的手段,之后会提到。

 
Comments Off on 影响力 – 知觉对比心理

Posted by in Uncategorized

 

经历性能问题后的一点总结

Reporting项目是我在做的Rails项目,因为性能问题,我们经历曲折坎坷的调优过程,为能否按计划发布而担心。庆祝完发布,我得把一些总结写下来。

故事是这样

  • 项目开始于今年三月份,预计在十一月中旬有个大的发布。
  • 早在四月份,团队就开始为每个请求、每个查询加benchmark,目的是监视执行时间,但并没有验收条件。
  • 八月份,使用Apache Benchmark tool为所有请求在staging环境上做了性能测试,发现有5个图表性能低,甚至在选择地区数目很大(数百个)时,响应时间呈指数增长。之后做了两件事,一是在做功能开发的同时坚持做性能优化,目标就是这些过慢的请求;二是限制地区数目选择的上限到100,以控制最坏情况下的性能。
  • 九月份,优化之后对那些重点请求重新进行了并发级别为1的性能测试,结果是响应时间减少了70%~85%,Tom对此很高兴,我们以为性能问题不复存在了。十月二十日,我们开始重新做全面的压力测试,发现一些请求的并发访问性能确实成问题。我们立即告知了客户这个问题。我们没有利用起这期间的时间,发现问题时已经很晚了,离发布只剩1月。
  • 接着我们就分析原因,然后就发现数据库的并发查询性能是问题的核心,因为数据库执行时间占了请求响应时间的70%,在并发查询时,数据库反应时间增长地很快,直接导致请求的响应时间增长很快。我们需要DBA帮忙,但Paul的全部时间已经在另外一个项目上了,我们向客户争取来了Paul的部分时间,后来客户为我们安排了另一位DBA专门来帮忙。
  • 请DBA帮忙的方式是,我们告诉他某个查询的sql语句,以及目前的执行时间和我们期望的时间,他们来帮忙做优化。这样做的好处是他们立刻知道要干什么,不耽误时间。
  • 我们在staging环境上的测试越来越好,理论上产品数据库上的测试结果应更好才对,但是不是这样,惊喜了。在产品数据库上存在一个首次访问响应时间的问题,就是说在时隔若干时间之后的头次访问,响应时间非常慢,但是紧接着第二次访问页面就会很快。这个问题在staging上是没有的,而且我们也无法在产品数据库上重现,不知道这个间隔时间是多少,所以很难请DBA监视。
  • 如今,所有查询的优化已经结束了,在产品环境上所有请求在并发测试中的中位数响应时间是在要求之内的。虽然首次访问响应时间的问题还在,但是我们和DBA都没有找到办法能合理地重现它,客户同意的解决方案是:如果需要的话,向用户提示相关信息。
  • 昨天成功发布了。

我们学到了什么

如何处理问题?

  • 发现问题后,应该及时让客户和DM知道情况,因为这样的问题对项目发布有直接的影响。
  • 通过一些手段,比如profiler等工具,来检测应用,诊断出性能问题发生的部位和原因。
  • 性能调优需要有一个指标,应该在调优前就向客户、甚至客户的客户要这个指标。不仅要与客户的业务人员谈,还要和技术人员去谈,因为性能指标在这两方人眼中可能差异很大。
  • 自己去研究是对的,但应设定时间限制;不应该让讨论只发生在团队内部,应该去请教专家,效率会更高。
  • 同时应该让其他项目的同事也了解我们目前面临的问题,因为他们可能就有这方面的经验,也可能以后会遇到相似的情况。
  • 对于数据库的问题,我们需要客户的DBA帮忙,一方面要争取他们的时间不断催促他们做事,另一方面要做足准备,告诉DBA最直接的需要做的任务是什么,这样他们也会效率更高。比如告诉他们sql是什么,目前运行时间是多久,期望时间是多久。
  • 合理地与客户“谈判”,找到折中的解决方案。这个谈判不是推诿,而是坐在一起讨论,我们的提议要有足够的业务理由做支持。

如何避免问题?

  • 我们应该从一开始就把性能纳入考虑,在编写代码时注意到它,而不是专门做优化时被迫重写部分代码
  • 我们应该把性能测试和调优的着眼点放在产品环境上,这样可以降低最后得到惊喜的风险
  • 我们应该尽早地参考性能指标设计包括压力测试在内的性能测试策略
  • 对新版本的探索性测试时,应当对性能表现留心,更早地察觉并意识到问题,这应该叫做持续体验(continuous experience)

当前发布中正在做的事

  • 在技术选型时为性能做更多的考虑
  • 先做包括可能出现性能问题的故事在内的高风险故事
  • 在第一个页面可访问之后就设计性能测试策略
  • 在做更多的故事之前就为性能做统筹考虑
 
Comments Off on 经历性能问题后的一点总结

Posted by in Uncategorized

 

影响力

看完《盗梦空间》(《Inception》)那部电影时,头一次觉得让一个人跟着给他的一个念头走,竟是那么困难的一件事。

我们通常只是跟着自己的直觉去说服别人,或顺从别人。似乎有些人有一些经验总结,知道一个请求怎么提别人会答应的几率更大,知道有些心理学的玩意在作怪,然而我看到的只是树木,case by case地考虑,从没想过有森林这回事。

《影响力》(《Influence: The Psychology of Persuasion》)才将我引上了前往森林的路。原来影响一个人根本不需要植入一个念头这么复杂。我们人类的本能,我们的直觉,我们的社会存在感,结合在一起形成了人身上复杂的条件反射,它已经给了想影响我们的人足够的操作空间。

作为影响力的武器有三点特性,第一,它抓住人类具有的复杂的条件反射机制,满足条件以触发相应的某些行为;第二,这种触发条件反射而造成的影响力是压倒性的,若无防备极难抵挡,甚至始终不自觉;第三,有用心的人利用影响力武器可从中得利。

明白影响力在自己周围是如何发生的,识别之后应明白如何避免不利的损害,还应学为己用去无害地影响别人,这是我们读这本书的目的

为什么促销活动被提前终止,为了低价而来又感觉受骗的你仍在这里买了平常价钱的东西?

为什么看了餐馆的海鲜价格之后,觉得地摊上5块一碗的油泼面在这儿25块钱也不贵?

为什么对决定在明天说分手的男朋友,还要请他好吃好喝大为破费?

为什么情景戏剧里的观众假笑让人一想就觉得假,但人们还是不自觉地跟着傻笑?

为什么同样一件事实,德高望重的人说着听起来那么有道理?

为什么很多学生的学习动力起于压力而最终更止于压力?

为什么你对自己在世界杯上下赌注的球队莫名地增加了信心?

如果事先让你知道,你只要做一点儿事情就可以让成功说服别人的几率增加50%,你会不做吗?

如果事后你才明白,你只要做一点儿事情就可以避免明知被骗还无法脱身的窘境,你会不做吗?

一本书就能让你明白这么多事,那真是太值了。

 
Comments Off on 影响力

Posted by in Uncategorized

 

异步Database Replication的更新延迟问题

被最广泛使用的异步Database Replication有可能因更新延迟(lag)而出现问题:当查询请求被slave处理时,如果slave因更新延迟而包含尚未更新的陈腐数据,会导致查询结果不准确。

例如OLTP(On-Line Transaction Processing,联机事物处理)型的查询请求要求极高的实时性,如在博客中发表完一篇文章就应立即看到它出现在文章列表中,slave上的replication通常无法及时做完,这时如果查询请求由slave来处理,返回的就是错误的陈腐数据(stale data)。Replication的延迟虽然通常很小,但毕竟不是实时同步,在slave上查不到最新数据的情况会存在的,何况在master高负载时向slave更新的延迟会更大。

当某slave的Replication延迟过大时,应将此slave移出服务后强制同步数据。不过在延迟存在但还不算过大时,如何在保证查询准确性的前提下合适地使用slave来分担负载呢?下面讨论下Peter Zaitsev在他的文章中提到了三个方法,至于它们之间的混合使用就不在讨论之内了。

根据查询类型决定如何分派查询请求

根据查询对数据的实时性要求,将查询分为time critical和non time critical两种,前者受Replication延迟的影响很大,如前文提到的OLTP型的查询;后者对Replication的延迟不敏感,对最新数据没有迫切的要求,如多为报表使用的OLAP(On-Line Analytical Processing,联机分析处理)型查询。

在分派查询请求时,识别该查询请求的实时性要求,将non time critical的查询交给slave处理,而将time critical的查询交master处理。可见,只读性质的数据分析式查询越多,slave所分担的载荷就越多,这种方案就越有效。

根据session为访问者指派数据库副本

这种考虑是从两个事实出发的。

(1)刚刚做过更新操作的访问者需要实时获得更新后的数据

做完更新操作的访问者应在一定时间段内只从master读取数据,以保证他能读到可能由他自己写入的最新数据。这个时间段应长于所有slave上Replication的最长时间,以保证他写的数据已经replicate给了slave。

(2)刚刚查询过数据的访问者应当在再次做相同查询时看到基本相同的数据

如果一个访问者的两次只读查询请求是由两个slave分别处理的,那么第一次读到的数据有可能在第二次读时找不到,因为不同slave的Replication延迟是不同的,存在被查询的数据在一个slave中被更新了但尚未更新到另一个slave中的情况。所以,给访问者session,让他在这一段时间内持续访问同一个slave。

这种方法说起来容易做起来难。而且,在session的时间段内访问者无法摆脱所指派的slave,失去了在请求之间切换到其它slave上获取较新数据的机会。

根据访问对象指派数据库副本

根据所查询数据的最后更改时间(last updated time)决定将查询请求发给master或slave。数据的最后更改时间离当前时间越近,它出现在slave上的几率就越小,这种请求只能由master出马;反之,则可使用slave处理请求。

一个例子:博客上的文章有最后更新时间,查询某篇文章时,先查该文章的新旧,如果文章很新那向master请求数据,如果文章已经不那么新了,那就由slave处理查询请求。

这意味着数据查询请求被执行之前需要额外查询一次其最后更新时间?没错。幸运的是,我们可以使用memcached之类的对象缓存系统来代替直接向master做这个查询。

这中方法的思想很美,不过适用范围较窄。对于可追踪最后更新时间的对象,如博客文章、评论等,单个查询其数据时可采用此方法;如果查询这样的对象集合,那就要参考实时性要求去考虑了。在复杂性方面,缓存的维护以及与Replication时间之间的权衡为该方法增加了难度,任何没有更新到所有slave上的数据对象都需要维护在cache中,而已经更新至所有slave上的数据对象理论上都需要从cache中移除,以清理cache空间。

References

  • Peter Zaitsev的文章,http://www.mysqlperformanceblog.com/2007/02/14/getting-use-of-slave-in-mysql-replication/
 
Comments Off on 异步Database Replication的更新延迟问题

Posted by in Uncategorized

 

Database Replication的数据同步方式

为保证数据在各数据库副本上的一致性,Replication需要频繁同步数据,下文谈谈三种同步方式,以MySQL上的master-slave模型为例。

同步方式(Synchronous)

如果master接收更新请求后,在自身执行的同时将信息传播给所有slave,并要等收到所有slave获得更新信息的反馈之后才返回,那此同步过程会大大拖累性能。这个道理很容易理解,而MySQL Cluster号称拥有Synchronous Replication的特性,我确实还没搞清它怎样能做到。

异步方式(Asynchronous)

典型MySQL上的Replication是异步的,master处理完更新请求后返回,不等待slave获取到更新信息。借用51CTO.com的这张图来介绍下异步Replication的过程吧。

  1. master上有更新到来,先将更新存入binary-log中;
  2. master上的sql进程执行Database更新,同时master将有新更新的消息散播出去,让各slave随时来请求,这个散播互动的过程通常是基于publish-subscription的;
  3. 某slave向master发来IO请求,指定要binary-log上某偏移量之后的跟更新信息;
  4. master接受IO请求,并返回所请求的更新信息,以及binray-log上当前的偏移量;
  5. slave收到IO反馈,将收到的更新信息追加到relay-log末尾,并将binray-log偏移量记录到master-info文件中,然后向master返回Acknowledge消息;
  6. slave的sql进程监测到relay-log中有新内容后,会立即在database上执行更新。

根据binary-log的信息存储形式,Replication又可区分为如下三种级别,相应都在MySQL上有配置。

  • Row level – Binary Log 中会记录成每一行数据被修改的形式,然后在 Slave 端再对相同的数据进行修改,不用在乎执行的sql语句的上下文相关的信息。显然此方法log中数据量巨大。
  • Statement level – 每一条会修改数据的 Query 都会记录到 Master的 Binary Log 中。log中不存在大量数据了,但它不得不记录每条语句在执行的时候的一些相关信息,也就是上下文信息,以保证所有语句在slave端杯执行的时候能够得到和在master端执行时候相同的结果。这种结果常因为query语句无法完美Replicate而出现数据不一致。
  • Mixed level – 它是上两种方法的折中,会根据执行的每一条具体的 Query 语句来区分对待记录的日志形式,也就是在Statement和Row之间选择一种。

半同步方式(Semi-synchronous)

又是一个典型的折中。因为上面提到的异步方式下,master不管slave数据更新的进度,若slave出现明显的落后(Lag),数据不一致的问题和单点故障的风险都会被放大;而完全同步的方式对性能的损害又过大。

借用orczhou.com的图片如下来解释半同步方式。

在半同步的方式下,master等待至少一个slave收到更新,即等待其Acknowledge消息,以此保证至少有一个slave在master突然宕机的情况下能够不丢失数据,并迅速代替master机器。不过如果等待时间超过限制,半同步模式会自动转为异步模式,不再等待slave。

Reference

  • 半同步方式的更多解释,http://dev.mysql.com/doc/refman/5.5/en/replication-semisync.html
  • master-slave在MySQL上的配置,http://members.cox.net/midian/howto/mysqlReplication.htm
 
Comments Off on Database Replication的数据同步方式

Posted by in Uncategorized

 

Database Replication与应用模型介绍

Database Replication是一个在冗余数据库之间分享数据,以维护多个数据一致的数据库副本(Replica)的方法,目的是提高可靠性、容错性和可访问性。其目的和方式,直白地说,是以冗余数据的方式提高容错能力,以实时维护数据库副本的方式保证宕机时热切换,同时分散数据查询的载荷以提高性能,而所有的一切对外部用户是透明的。当然,不同的应用背景对数据库的期望是不同的,可能偏重于上述的某些个能力,并不是兼有。

例如分支团队希望在远程得到一部分数据库数据,而不是实时访问主数据库,那么可通过Replication为其建一个主数据库中某些表的副本,这个副本中的数据可隔一定时间同步一次。

Replication不是数据库备份技术,数据库备份的要旨在于将某一个时间节点上的数据库状态备份起来,供未来的数据恢复或参考用;而Replication的数据库副本对所做的更新都是无条件执行的,至于执行之后的数据状态是好是坏,它们不关心。不过Replication有助于数据库备份,后文介绍master-slave模式时会提及。

从数据一致性的维护上讲,应用Replication要首先安排所有数据库副本的责任角色,谁能接收更改请求并分享出来,谁仅读取其他副本的数据更新。称前者为master,称后者为slave,通常有master-slave和multi-master两种应用模型,下面首先介绍这两种模型。

master-slave

一个server上的DB做master,其他所有server上的DB副本都作为slave。任何时候都由master接收更新请求并首先执行,然后将更新的信息传递给slave,slave上再应用更新。slave仅用来接收查询请求,当master宕机时会按照切换策略将一个slave升级为master,而原master在修复之后则作为slave重新加入。

借用来自MySQL Reference Manual的下图说明master-slave模型的Replication的应用场景。

图中的应用场景是一个大量数据库查询的web应用,使用master-slave的首要目的是分担载荷。

  1. 用户的request先由Load Balancer分派到某一较轻负载的web应用实例上;
  2. 根据request中对数据的不同操作类型,web应用实例将数据实时性要求较宽松的只读请求发给slave处理,而将数据实时性要求高的读操作或写操作发给master处理;
  3. 写操作的信息在master数据库上执行的同时,被Replicate给各个slave。

另外,上文提到Replication并不属于数据库备份技术,但数据库备份操作确实可从中受益。master-slave模型中,可在某一slave更新数据后将它从slave阵列中切出,暂时不再接受任何request或replication,这时可对此slave数据库进行备份。备份过程可专心进行,相比直接对服务中的数据库做备份,难度降低许多。备份完毕的这台server可主动请求master的数据,更新完毕后可重新作为slave加入阵列继续提供服务。

multi-master

“能够接收更新请求并首先执行”是具有master角色的标准,该应用模型中所有的server上的DB副本都是master,可接收更新请求或数据查询请求,因为宕机时的切换成本比master-slave要小。这种应用模型的在副本数据更新的信息来源上也分两种方式。

1. Active Replication

任何更新请求都分别发给各个副本执行,这种主动行为的好处在于简化了副本间的数据同步,却让负载同时发生,失去了副本间并发响应查询请求的性能。

2. Passive Replication

任何更新请求只发给某一个副本,它接收到之后会立即执行,然后将自己的状态传播给其他副本,其他副本在此过程中只被动等待。这种副本间传递信息的方式比master-slave更要复杂,因为这张网上的任一节点都能当做其他节点的信息来源,而且两条对临界数据的修改可能随时出现,所以需要分布式并发控制。常见的方法有两个,一个基于锁机制,将修改所涉及到的资源的加锁,以同步不同master上收到的更改的执行顺序;另一个基于时间戳和事务回滚,各副本先应用事物所描述的更新,在其他副本的信息到来后发现冲突时,再依时间戳为据选择是否回滚前面的更新。

Reference

  • Replication的解释,http://en.wikipedia.org/wiki/Database_replication
  • 在负载均衡上的应用,http://dev.mysql.com/doc/refman/5.6/en/replication-solutions-scaleout.html
  • 在宕机时切换上的应用,http://dev.mysql.com/doc/refman/5.6/en/replication-solutions-switch.html
 
Comments Off on Database Replication与应用模型介绍

Posted by in Uncategorized