跳转到内容


冰力

注册日期: 2010-07-03
离线 最后上线: 昨天, 00:45
-----

我发起的主题

三种东西永远不要放到数据库里

2012/05/21 01:33:30

我已经在很多演讲里说过,改进你的系统的最好的方法是先避免做“蠢事”。我并不是说你或你开发的东西“蠢”,只是有些决定很容易被人们忽略掉其暗含 的牵连,认识不到这样做对系统维护尤其是系统升级带来多大的麻烦。作为一个顾问,像这样的事情我到处都能见到,我还从来没有见过做出这样的决定的人有过好 的结果的。
图片,文件,二进制数据

既然数据库支持BLOB类型的数据,把文件塞进BLOB字段里一定没有错了!?错,不是这样的!别的先不提,在很多数据库语言里,处理大字段都不是很容易。
把文件存放在数据库里有很多问题:
  • 对数据库的读/写的速度永远都赶不上文件系统处理的速度
  • 数据库备份变的巨大,越来越耗时间
  • 对文件的访问需要穿越你的应用层和数据库层
这后两个是真正的杀手。把图片缩略图存到数据库里?很好,那你就不能使用nginx或其它类型的轻量级服务器来处理它们了。
给自己行个方便吧,在数据库里只简单的存放一个磁盘上你的文件的相对路径,或者使用S3或CDN之类的服务。
短生命期数据

使用情况统计数据,测量数据,GPS定位数据,session数据,任何只是短时间内对你有用,或经常变化的数据。如果你发现自己正在使用定时任务从某个表里删除有效期只有一小时,一天或数周的数据,那说明你没有找对正确的做事情的方法。使用redisstatsd/graphiteRiak,它们都是干这种事情更合适的工具。这建议也适用于对于收集那些短生命期的数据。
当然,用挖土机在后花园里种土豆也是可行的,但相比起从储物间里拿出一把铲子,你预约一台挖土机、等它赶到你的园子里挖坑,这显然更慢。你要选择合适的工具来处理手头上的事。
日志文件

把日志数据存放到数据库里,表面上看起来似乎不错,而且“将来也许我需要对这些数据进行复杂的查询”,这样的话很得人心。这样做并不是一个特别差的做法,但如果你把日志数据和你的产品数据存放到一个数据库里就非常不好了。
也许你的日志记录做的很保守,每次web请求只产生一条日志。对于整个网站的每个事件来说,这仍然会产生大量的数据库插入操作,争夺你用户需要的数据库资源。如果你的日志级别设置为verbose或debug,那等着看你的数据库着火吧。
你应该使用一些比如Splunk Loggly或纯文本文件来存放你的日志数据。这样去查看它们也许会不方便,但这样的时候不多,甚至有时候你需要写出一些代码来分析出你想要的答案,但总的来说是值得的。
可是稍等一下,你是那片不一样的雪花,你遇到的问题会如此的不同,所以,如果你把上面提到的三种东西中的某一种放到了数据库里也不会有问题。不,你错了,不,你不特殊。相信我。

老程序员都到哪里去了?

2012/05/20 00:30:48

老程序员都到哪儿去了? –寻找40岁之后软件开发者的象冢

人们都认为软件开发是年轻人的游戏。当年轻自信的程序员获得优厚的待遇并向管理层晋升的时候,老程序员们甚至找工作都困难。真的如此吗?
在最近的一篇文章中,加州大学戴维斯分校的计算机科学教授Norman Matloff认为“软件工程是职业生涯的死胡同”。他写到:“很多程序员发现,大约从35岁起他们的就业能力就开始走下坡路了。”
如果这要是在广播上的话,我会选择跳过这段录音。35岁?我还以为我们要讨论年纪更大些的程序员呢。从什么时候起35岁就算是“老人”了?

附加文件  Old Programmers Newver Die They Just Gosub Without Return.jpg   25.58K   0 下载次数

Matloff继续说:“统计表明,大多数软件开发者40岁之前会离开编程领域。”看到这儿我的眉毛开始挑起来了。大多数程序员?还他们中的绝大多数?离开?(Matloff拒绝说明他从哪里看到的统计数字。)
如果这是真的,那些老程序员都去哪儿了?是否真有这样的地方,让我们把疲倦衰弱的、不适合再做程序员的人送去,使他们远离年轻程序员的视线,优雅的死去?或者说他们拿到了不动产执照? 还是去开剪贴簿商店了?我有点怀疑。

天真的塌下来了?

现在,我并不是走极端说软件开发中不存在年龄歧视。这种现象可能在技术领域比其他行业更普遍。但我不得不说,当我读到Matloff令人震惊的言论时,我的直觉反应是我不买账。
首先,可以举一些经验证据:我认识相当多的人,我的社交圈里基本每个人都超过或者马上就到40岁了,里面有很多是软件开发者。这怎么解释?难道我的每个程序员朋友都碰巧是统计的离群值吗?
除了统计之外,像Matloff的这种恐慌性文章还通过选择性地援引一些技术明星的话来作为支持。Matloff引用Intel前CEO Craig Barrett的话说,“软件工程师或硬件工程师的半衰期只有几年”。此外,他说,Mark Zuckerberg……,唉,我们就别替他操心了。
即使Gordon Moore的一些随便的评论已经变成“定律”,我不会因为他们都曾是Intel的CEO而给Craig Barrett相同的优待。简洁的引用并不会使研究变困难。所有的程序员到底去哪里了呢,我在想这儿吗?我有些想法。

蹲下身子

首先,很多人并未离去。他们在某个领域、行业、工具或者公司变得非常专业化,他们开拓商机并坚持做到最好。有的程序员在大的技术公司成为杰出工程师。他们也是Matloff统计数据的离群值吧,所以让我们忘了他们吧。
其他程序员自然而然地晋升到管理岗位。我想,你在翻白眼吧,也许你会说“软件开发经验并不能使你成为一个好的管理者”。你知道吗?其实管理培训课程也未必能。
重点在于,晋升会带来新的头衔。告诉别人你的新头衔是宣告你进入了一个更高位置的最好方式。当下一次有调查让你填工作角色时,你可能选择“项目经理”而非“软件开发者”,即使你仍然直接参与软件设计、规范、开发、测试和部署过程的每一步。
晋升是留住雇员的一种方式。但不管相信与否,进入软件开发团队的管理位置并不意味着你已经放弃了程序员的工作。然而,看起来统计也是没有包括这部分人的。

低调神秘,开启职业新篇章

尽管其他开发者不再从事原来的工作,但并未离开这个领域。他们继续创业,角色可能转变成为负责人或CTO。一般职业调查是不包括企业家的,再一次,这些人没在统计之中。
职业调查可能也漏掉了独立承包人。对于软件开发者而言,咨询也是个商机,能够给成熟的程序员大量的行业经验。
显然,如果你并不打算找一个全职工作,他们就无法估算你找一个全职工作要花多长时间。你是否注意到国家失业统计数字并不包括那些不找工作的人?承包人同样影响职业统计。
沿着这些思路,我们来检查下Matloff引用的统计信息。他说,研究表明,“超过40岁的工作人员失业之后再找工作要多花23.4%的时间”。真有意思,但是研究没有分析为什么——可能他们将时间花在了咨询上呢。
还有一点是,老程序员们已经为错误交过学费了。他们可能曾经犯过错误,干过不好的工作,并习惯于某种生活标准。他们并不会感到很大压力非要在第一份 工作来的时候就抓住,特别是当他们过去几年过着六位数收入的舒适生活时。有经验的程序员找新工作花的时间更长,可能因为他们要求的标准更高呢?

综合信息

但是谁真正关心Matloff说的那些话呢,是吧?统计,所有这一切,都是谎言,可恶的谎言。不管这些灾难预言者怎么说,老的技术人员很可能对自己 在职业生涯中的位置有一个公正的认识。我真正担心的是,Matloff的文章传达给年轻一代(特别是那些马上进入这个工作领域的人)的信息。
一方面,高科技看来仍然是美国为数不多的真正繁荣的行业之一。公司说他们找不到足够多的合格人选。政治家和教育家们绞尽脑汁要燃起年轻人对计算技术的兴趣。并且,一年年的,软件开发一直栖身于最好的工作之列。
另一方面,我们却有像Matloff写的这样的文章,认为编程工作是个死胡同,当其他领域的人员正处于职业生涯巅峰时,程序员只能寄望于被送到制胶厂。这样的说法,往好了说是愚蠢、标题党;往坏了说,是彻头彻尾的不负责任。

Old Programmers Never Die They Just Go sub Without Return ..

rsync 的核心算法

2012/05/18 16:21:28

rsync是 unix/linux下同步文件的一个高效算法,它能同步更新两处计算机的文件与目录,并适当利用查找文件中的不同块以减少数据传输。rsync中一项与 其他大部分类似程序或协定中所未见的重要特性是镜像是只对有变更的部分进行传送。rsync可拷贝/显示目录属性,以及拷贝文件,并可选择性的压缩以及递 归拷贝。rsync利用由Andrew Tridgell发明的算法。这里不介绍其使用方法,只介绍其核心算法。我们可以看到,Unix下的东西,一个命令,一个工具都有很多很精妙的东西,怎么学也学不完,这就是Unix的文化啊。
本来不想写这篇文章的,因为原先发现有很多中文blog都说了这个算法,但是看了一下,发现这些中文blog要么翻译国外文章翻译地非常烂,要么就 是介绍这个算法介绍得很乱让人看不懂,还有错误,误人不浅,所以让我觉得有必要写篇rsync算法介绍的文章。(当然,我成文比较仓促,可能会有一些错 误,请指正)
问题

首先, 我们先来想一下rsync要解决的问题,如果我们要同步的文件只想传不同的部分,我们就需要对两边的文件做diff,但是这两个问题在两台不同的机器上, 无法做diff。如果我们做diff,就要把一个文件传到另一台机器上做diff,但这样一来,我们就传了整个文件,这与我们只想传输不同部的初衷相背。
于是我们就要想一个办法,让这两边的文件见不到面,但还能知道它们间有什么不同。这就出现了rsync的算法。
算法

rsync的算法如下:(假设我们同步源文件名为fileSrc,同步目的文件叫fileDst
1)分块Checksum算法。首先,我们会把fileDst的文件平均切分成若干个小块,比如每块512个字节(最后一块会小于这个数),然后对每块计算两个checksum,
  • 一个叫rolling checksum,是弱checksum,32位的checksum,其使用的是Mark Adler发明的adler-32算法,
  • 另一个是强checksum,128位的,以前用md4,现在用md5 hash算法。
为什么要这样?因为若干年前的硬件上跑md4的算法太慢了,所以,我们需要一个快算法来鉴别文件块的不同,但是弱的adler32算法碰撞概率太高了,所以我们还要引入强的checksum算法以保证两文件块是相同的。也就是说,弱的checksum是用来区别不同,而强的是用来确认相同。(checksum的具体公式可以参看这篇文章
2)传输算法。同步目标端会把fileDst的一个checksum列表传给同步源,这个列表里包括了三个东西,rolling checksum(32bits)md5 checksume(128bits)文件块编号
我估计你猜到了同步源机器拿到了这个列表后,会对fileSrc做同样的checksum,然后和fileDst的checksum做对比,这样就知道哪些文件块改变了。
但是,聪明的你一定会有以下两个疑问:
  • 如果我fileSrc这边在文件中间加了一个字符,这样后面的文件块都会位移一个字符,这样就完全和fileDst这边的不一样了,但理论上来说,我应该只需要传一个字符就好了。这个怎么解决?
  • 如果这个checksum列表特别长,而我的两边的相同的文件块可能并不是一样的顺序,那就需要查找,线性的查找起来应该特别慢吧。这个怎么解决?
很好,让我们来看一下同步源端的算法。
3)checksum查找算法。同步源端拿到fileDst的checksum数组后,会把这个数据存到一个 hash table中,用rolling checksum做hash,以便获得O(1)时间复杂度的查找性能。这个hash table是16bits的,所以,hash table的尺寸是2的16次方,对rolling checksum的hash会被散列到0 到 2^16 – 1中的某个整数值。(对于hash table,如果你不清楚,建议回去看大学时的数据结构教科书)
顺便说一下,我在网上看到很多文章说,“要对rolling checksum做排序”,这两篇文章都引用并翻译了原作者的这篇文章,但是他们都理解错了,不是排序,就只是把fileDst的checksum数据,按rolling checksum做存到2^16的hash table中,当然会发生碰撞,把碰撞的做成一个链表就好了。这就是原文中所说的第二步——搜索有碰撞的情况。
4)比对算法。这是最关键的算法,细节如下:
4.1)取fileSrc的第一个文件块(我们假设的是512个长度),也就是从fileSrc的第1个字节到第512个字节,取出来后做rolling checksum计算。计算好的值到hash表中查。
4.2)如果查到了,说明发现在fileDst中有潜在相同的文件块,于是就再比较 md5的checksum,因为rolling checksume太弱了,可能发生碰撞。于是还要算md5的128bits的checksum,这样一来,我们就有 2^-(32+128) = 2^-160的概率发生碰撞,这太小了可以忽略。如果rolling checksum和md5 checksum都相同,这说明在fileDst中有相同的块,我们需要记下这一块在fileDst下的文件编号
4.3)如果fileSrc的rolling checksum 没有在hash table中找到,那就不用算md5 checksum了。表示这一块中有不同的信息。总之,只要rolling checksum 或 md5 checksum 其中有一个在fileDst的checksum hash表中找不到匹配项,那么就会触发算法对fileSrc的rolling动作。于是,算法会住后step 1个字节,取fileSrc中字节2-513的文件块要做checksum,go to (4.1) - 现在你明白什么叫rolling checksum了吧。
4.4)这样,我们就可以找出fileSrc相邻两次匹配中的那些文本字符,这些就是我们要往同步目标端传的文件内容了。
图示

怎么,你没看懂? 好吧,我送佛送上西,画个示意图给你看看(对图中的东西我就不再解释了)。

附加文件  rsync-algorithm.jpg   67.58K   0 下载次数

这样,最终,在同步源这端,我们的rsync算法可能会得到下面这个样子的一个数据数组,图中,红色块表示在目标端已匹配上,不用传输(注:我专门 在其中显示了两块chunk #5,相信你会懂的),而白色的地方就是需要传输的内容(注意:这些白色的块是不定长的),这样,同步源这端把这个数组(白色的就是实际内容,红色的就放 一个标号)压缩传到目的端,在目的端的rsync会根据这个表重新生成文件,这样,同步完成。

附加文件  rsync-algorithm-result.jpg   10.23K   0 下载次数

最后想说一下,对于某些压缩文件使用rsync传输可能会传得更多,因为被压缩后的文件可能会非常的不同。对此,对于gzip和bzip2这样的命令,记得开启 “rsyncalbe” 模式。

Setting up Apache 2.2, MySQL 5.5 + Sphinx 2.0, PHP 5.3, a Scripted Guide

2012/05/18 00:42:08

Similar to the previous scripted guide, this script will download the source for Apache, MySQL (and optionally with Sphinx, steps denoted in red font), and PHP and compile it under CentOS 5 and 6 on a x86-64 platform.
I’ve had this type of script for a few years now due to the amount of times I’ve had to provision a VPS from scratch. I simply copy/paste the script onto a clean VPS and away it goes setting up a LAMP server from source. This script should not require any existing requisites and should work out-of-the-box on a clean installation of CentOS 6.

#
# We need a few packages in order to compile apache, mysql and PHP from rpmforge.
# Import the key and install the repo.

cd
wget http://packages.sw.be/rpmforge-release/rpmforge-release-0.5.2-2.el6.rf.x86_64.rpm
rpm --import http://apt.sw.be/RPM-GPG-KEY.dag.txt
rpm -K rpmforge-release-0.5.2-2.el6.rf.*.rpm
rpm -i rpmforge-release-0.5.2-2.el6.rf.*.rpm
# Install all prerequisites.
yum -y install make autoconf g++ gcc-c++ libtermcap-devel libgcc-c++ libtool gcc libpng-devel libjpeg-devel libxml1-devel libxml2-devel curl curl-devel libmcrypt libmcrypt-devel libtool-ltdl-devel libxml2.x86_64 libxml2-devel.x86_64 curl-devel.x86_64 openssl-devel
# Download the source files. Sphinx is optional.
mkdir src
cd ~/src
wget http://host.steamr.com/supportfiles/httpd-2.2.21.tar.gz
wget http://host.steamr.com/supportfiles/mysql-5.5.16.tar.gz
wget http://host.steamr.com/supportfiles/php-5.3.8.tar.gz
wget http://host.steamr.com/supportfiles/sphinx-2.0.1-beta.tar.gz
# Extract all archives
for f in `ls *.tar.gz` ; do tar -xzf $f ; done

#
# Setting up apache into /opt/apache
#

cd /root/src/http*/
./configure --prefix=/opt/apache --enable-so --enable-rewrite --enable-ssl --enable-setenvif
make
make install
#
# Setting up MySQL into /opt/mysql.
# Note: MySQL 5.5 and above will require cmake.
#

yum -y install cmake
cd /root/src/mysql*/

# If you wish to compile MySQL with Sphinx, run the following:
cp -R ../sphinx-*/mysqlse/ storage/sphinx
sh BUILD/autorun.sh
./configure --prefix=/opt/mysql --with-plugins=sphinx --with-unix-socket-path=/opt/mysql/mysql.sock --without-man --enable-shared --without-debug --enable-assembler --with-ssl CFLAGS=-O3 'CXXFLAGS=-O3 -fno-exceptions -felide-constructors -fno-rtti' CXX=gcc


# Otherwise, to compile MySQL without Sphinx run:
./configure --prefix=/opt/mysql --with-unix-socket-path=/opt/mysql/mysql.sock --without-man --enable-shared --without-debug --enable-assembler --with-ssl CFLAGS=-O3 'CXXFLAGS=-O3 -fno-exceptions -felide-constructors -fno-rtti' CXX=gcc

make
make install
# Setup the init scripts
/bin/cp support-files/mysql.server /etc/init.d/mysql
chmod 755 /etc/init.d/mysql
ln -s /etc/init.d/mysql /etc/rc3.d/S40mysql
# Copy the default configuration
/bin/cp support-files/my-medium.cnf /etc/my.cnf
# Setup the mysql system account
/usr/sbin/useradd -r mysql
# Update the MySQL permissions
cd /opt/mysql
chown -R mysql .
chgrp -R mysql .
# When setting up the initial database on MySQL 5.4 or earlier, run:
# /opt/mysql/bin/mysql_install_db --user=mysql
# On MySql 5.5 or later, run:

/opt/mysql/scripts/mysql_install_db --user=mysql --basedir=/opt/mysql
# Ensure the new database files created from the previous step is owned by mysql
chown -R mysql /opt/mysql
# Start MySQL manually:
/opt/mysql/bin/mysqld_safe --user=mysql &

#
# MySQL should now be running. You can verify this by running:
# ps -A|grep mysql
#

#
# Set the lib paths of mysql so the libmysqlclient.so or w/e can be found
#

echo "/opt/mysql/lib/mysql" > /etc/ld.so.conf.d/mysql.conf
/sbin/ldconfig

#
# Setting up Sphinx
# NOTE: You must have sphinx compiled with mysql from the previous step.
# You may skip this step if you do not wish to have Sphinx and continue to PHP.
#

cd /root/src/sphinx*
./configure --prefix=/opt/sphinx --with-mysql
make
make install
# The init script used by Sphinx requires sudo.
yum -y install sudo
# Setup the default config
/bin/cp /root/sphinx.conf /opt/sphinx/etc/sphinx.conf
# Setup the init scripts
cp contrib/scripts/searchd /etc/init.d/
chmod 777 /etc/init.d/searchd
ln -s /etc/init.d/searchd /etc/init.d/S55searchd
# Create the sphinx system account and ensure everything under /opt/sphinx/var is owned by sphinx.
useradd -r searchd
cd /opt/sphinx
chown -R searchd:searchd var
#
# Setup PHP as a module for apache:
#

cd /root/src/php*/
./configure --prefix=/opt/php5 --with-apxs2=/opt/apache/bin/apxs --with-config-file-path=/etc/ --with-gd --enable-shmop --enable-track-vars --enable-ftp --enable-sockets --enable-exif --enable-zip --enable-sysvsem --with-zlib --enable-sysvshm --enable-magic-quotes --with-jpeg-dir --with-png-dir --enable-mbstring --enable-embedded-mysqli=shared --with-curl --with-mcrypt --with-mysql=/opt/mysql --with-mysqli=/opt/mysql/bin/mysql_config
# If you want imap support: use options --with-imap --with-imap-ssl=/usr/include/openssl --with-kerberos
make
make install

MySQL 控制台修改帐号密码

2012/05/16 21:31:11

登录到 MYSQL 的控制台,使用下面的命令来修改用户密码,如果用户不存在会创建一个这样的用户:

GRANT USAGE ON *.* TO root@127.0.0.1 IDENTIFIED BY '123456';

为了使修改生效执行下面的命令来刷新 MYSQL 管理权限:

FLUSH PRIVILEGES;