-
- php的异步http请求类发表时间: 2011-11-10来源: IT牛人博客聚合网站
基于上次写的关于php的libevent扩展的应用,我实现了一个异步的http请求类。
代码在github上:https://github.com/volca/AsyncHttpClient
使用示例
如下,在request的时候能够定义请求完成之后的callback函数。
<?php require __DIR__ . '/../src/AsyncHttpClient.php'; $base = event_base_new(); $uri = "http://www.baidu.com/"; $config = array( 'eventbase' => $base ); for($i = 0; $i < 10; $i++) { $client = new AsyncHttpClient($uri, $config); $client->request(function($result) { echo "Result len:"; echo strlen($result['response']); echo "n"; }); } event_base_loop($base); echo "donen";目前的实现比较初级,只做了get方法的封装,如果需要http上传或者post,还需要另外实现。另外这个类也需要php的libevent扩展。
由 IT 牛人博客聚合网站(udpwork.com) 聚合 | 评论: 0
- Linux运维利器之ClusterShell发表时间: 2011-11-12来源: IT牛人博客聚合网站
如果你有若干台数据库服务器,突然你想知道它们当前的即时负载情况,你会怎么办?挨个登录上去uptime一下?感觉有点傻,写个shell?浪费时间,直接用ClusterShell吧!
ClusterShell的安装与配置
ClusterShell的安装很Easy,如果使用APT或YUM包管理方式的话,基本就是一条命令的事儿,我就不说了,这里说一下如何从源代码安装,需要在源代码目录执行如下命令:
shell> python setup.py install
为了使用的方便,还需要拷贝配置文件到指定目录:
shell> mkdir /etc/clustershell shell> cp conf/* /etc/clustershell
接着配置我们要管理的节点,假设我们配置了一个db组,包含db_[1-3]三个节点:
shell> cat /etc/clustershell/groups db: db_1 db_2 db_3
准备就绪,顺着文章开头的例子说:查询所有数据库服务器当前的负载情况:
shell> clush -g db "uptime"
注:前提是需要在被操作服务器上设置免密码登录,如果不清楚,请看下面的内容。
番外篇:如何配置服务器免密码登录?
如果没有事先生成ssh密匙的话,需要先生成:
shell> ssh-keygen
可选操作:为了方便,我们可以给需要登录的服务器起一个可读性更好的别名,如果你做了类似的操作,那么后面的<USER>@<SERVER>都可以换成对应的<HOST>:
shell> cat ~/.ssh/config Host db_1 Hostname <SERVER> User <USER> Port <PORT> Host db_2 Hostname <SERVER> User <USER> Port <PORT> Host db_3 Hostname <SERVER> User <USER> Port <PORT>
然后把生成的公钥添加到需要登录的服务器指定位置:
shell> cat ~/.ssh/id_rsa.pub | ssh <USER>@<SERVER> "cat - >> ~/.ssh/authorized_keys"
如果你和我一样总记不清如何正确拼写authorized_keys,可以接着学一下ssh-copy-id的用法,这个命令可以让操作更简单点:
shell> ssh-copy-id -i ~/.ssh/id_rsa.pub "<USER>@<SERVER>"
注:每配置好一台免密码登录的服务器,最好手动实际操作一下,因为第一次连接会要求手动确认是否保存信息到~/.ssh/known_hosts文件。
…
有的网友会说,监控服务器负载可以用Munin之类的工具。不错确实如此,不过Munin之类的工具无法给你一个及时数据,另外,ClusterShell并不局限在查询负载的功能上,跟上不同的命令,就可以查询不同的数据,而在Munin之类的工具里,如果你想监控某个数据,必须有对应的插件才行。ClusterShell是不可或缺的Linux运维利器!
由 IT 牛人博客聚合网站(udpwork.com) 聚合 | 评论: 0
- 前端优化之图片优化自动化发表时间: 2011-10-21来源: IT牛人博客聚合网站
前端图片优化介绍
随着前端页面越来越复杂,尤其是一些社区型的页面中,图片成了页面中不可或缺的资源,并且随着产品功能的叠加图片大小越来越多。以下是几个网站的图片所占的比重。
由于图片是二进制文件,并不能像js、css、html那些源代码文件一样可以通过gzip压缩大大减小文件的大小。所以图片优化主要是选择合适的图片格式,在不降低图片质量的情况下去掉图片里的元数据信息。
常用的一些优化方案
目前图片优化使用比较多的主要是下面几种方式:
- 选择合适的图片格式,如:png代替gif,尽量使用png8
- png使用pngout优化,jpg使用jpgtran
- 通过yahoo的smush进行
- 通过google的page speed插件进行

这些优化方案虽然结果都能将图片优化,但需要比较多的人工操作。如使用smush,先要上传文件,优化完了后还要下载文件。在项目时间限制或者改动很频繁的情况下很多时候就把图片优化这一非常重要的优化步骤给忽略了。
那如何尽量减少人工操作带来的麻烦和不确定因素呢?
如果在前端模块编译的时候,有图片自动优化的功能,上线前模块编译的时候得到就是优化后的图片,开发人员完全不用管图片优化了,但又不影响线上图片优化的结果。
如何结合一些工具做到图片优化完全自动化呢?先要考虑目前开发中经常用到的图片格式。
图片格式
开发中经常用到的图片格式主要有如下几种:
- 不透明的gif,全透明的gif,动画gif
- 不透明的png,全透明的png,半透明(alpha透明)的png
- jpg图片
对于全透明的png,ie6要通过下面的filter进行hack。

对于alpha透明的png,ie6下必须使用png24,目前还没有找到ie6下hack alpha透明png8的方式,如果有哪位大拿对这个有解决方案,麻烦告诉我。
经过筛选和优化原则要满足上面的图片格式的条件,选择的软件如下:
- 动画gif使用gifsicle
- png使用pngcrush
- jpeg使用jpegtran
软件安装
需要安装imagmagick, gifsicle, jpegtran, pngcrush,安装脚本如下:
#!/bin/sh #安装imagemagick wget ftp://ftp.kddlabs.co.jp/graphics/ImageMagick/ImageMagick-6.6.4-10.tar.gz tar zxvf ImageMagick-6.6.4-10.tar.gz cd ImageMagick-6.6.4-10 ./configure make make install cd ../ #安装gifsicle wget http://www.lcdf.org/gifsicle/gifsicle-1.60.tar.gz tar zxvf gifsicle-1.60.tar.gz cd gifsicle-1.60 make make install cd ../ #安装jpegtran wget http://jpegclub.org/droppatch.v8.tar.gz tar zxvf droppatch.v8.tar.gz sudo cp ./jpegtran /usr/local/bin #安装pngcrush wget http://sourceforge.net/projects/pmt/files/pngcrush/00-1.7.13/pngcrush-1.7.13.tar.gz/download tar zxvf pngcrush-1.7.13.tar.gz cd pngcrush-1.7.13 sudo make sudo cp ./pngcrush /usr/local/bin
将上面的代码拷贝到一个文件如:image.s,执行dos2unix image.sh,然后执行sh image.sh安装软件
图片优化
图片优化的代码如下:#/bin/bash OPTI_PATH=$1 cd $OPTI_PATH; CURRENT_PATH=$PWD; SH_LIST='jpegtran gifsicle pngcrush'; COMMOND_EXIST=1 #先检查相关的软件是否已经正确安装 for ITEM in $SH_LIST do SH_EXIST=`which $ITEM 2>/dev/null | wc -l`; if [[ $SH_EXIST == '0' ]]; then echo "$ITEM commond not exist"; COMMOND_EXIST=0; fi done if [[ "COMMOND_EXIST" == "0" ]]; then exit 1; fi #优化jpg JPG_FILES=`find . -type f -name "*.jpg" -or -name "*.jpeg"`; for FILE in $JPG_FILES do OUTPUT_FILE="$FILE.png" jpegtran -optimize -progressive -copy none -outfile $OUTPUT_FILE $FILE > /dev/null mv $OUTPUT_FILE $FILE done #优化gif GIF_FILES=`find . -type f -name "*.gif"`; for FILE in $GIF_FILES do DEPTH=`identify $FILE | wc -l`; if [[ "$DEPTH" == "1" ]]; then OUTPUT_FILE="$FILE.png"; OUTPUT_FILE_LEN=${#OUTPUT_FILE}-8; NEW_FILE_SUB=${OUTPUT_FILE:0:$OUTPUT_FILE_LEN}; NEW_FILE="$NEW_FILE_SUB.png" convert $FILE $NEW_FILE > /dev/null; else OUTPUT_FILE="$FILE.gif" gifsicle -o $OUTPUT_FILE $FILE > /dev/null mv $OUTPUT_FILE $FILE fi done #优化png PNG_FILES=`find . -type f -name "*.png"`; for FILE in $PNG_FILES do OUTPUT_FILE="$FILE.png" pngcrush -rem alla -brute -reduce $FILE $OUTPUT_FILE > /dev/null mv $OUTPUT_FILE $FILE done cd $CURRENT_PATH;将上面的代码保存如:image-optimation.sh,执行dosunix image-optizimation.sh,
然后执行sh image-optizimation.sh imgdir 就可以将imgdir目录下的图片进行优化,上线的时候只要拷贝优化后的图片就可以了。优化结果
以下是前端一个模块的优化前后的文件大小比较:
优化后,图片大小减小了66.6K,优化率达到35.2%。
从数据中可以发现,png图片优化还是非常多的,也是优化准则里尽量使用png图片的原因。
其他优化工具
除了上面用到的图片优化工具,还有其他很多可以优化图片的工具。但各种各样的小问题,最终并没有使用它们。
- pngrewrite
- optpng
- pngout
- pngquant
参考文档
- http://www.slideshare.net/stoyan/image-optimization-for-the-web-at-phpworks-presentation 图片优化方面的ppt
- http://www.smushit.com/ysmush.it/ smush
- https://github.com/thebeansgroup/smush.py smush的python实现
- http://code.google.com/speed/page-speed/docs/payload.html#CompressImages google关于图片优化的文档
- http://www.welefen.com/fcp-introduce.html FCP前端编译平台里包含了图片优化功能
由 IT 牛人博客聚合网站(udpwork.com) 聚合 | 评论: 0
- Web server调研分析发表时间: 2011-10-10来源: IT牛人博客聚合网站
摘要
简单可依赖的架构首先需要有一个简单可依赖的前端WebServer集群。本文通过深入调研当前主流的异步web服务器Lighttpd和Nginx,从业界使用情况、架构原理、扩展开发、功能对比、性能对比等多个方面进行分析。
调研分析
业界相关
从业界使用情况来看,最新Web Server使用情况的数据如下:Nginx的使用率是6.6%,Lighttpd的使用率是0.51%。

从文档来看,nginx中文相关文档越来越多。来自最新的百度搜索数据显示,nginx的网页数量是lighttpd的10倍。目前国内对于Nignx内核深入研究的人越来越多,有淘宝、sina、腾讯等许多大公司的技术人员参与研究,并进行相关的技术交流。对于Lighttpd的研究,目前主要是公司内部和一些学生。
从业界的点评来看,国内外基本上结论如下:
- 两者都是异步WebServer,都采用了状态机。本质上是相同的。
- Nginx稳定度高于Lighttpd。Lighttpd一直存在一定的内存泄漏。
- 性能上两者都非常优秀,Nginx有一定优势。
- Nginx在综合性能上更加优秀,更有可能成为未来的apache。
从社区活跃度来看,Nginx每月2到3个三位版本发布。Lighttpd3位版本更新较慢,目前1.5的版本基本上没有更新过。同时Nginx有丰富的第三方库类。
架构原理
代码层次
Nginx的代码量10W行,Lighttpd是5W左右。相对来说,Nginx的代码层次结构更加分明,具体代码结构如下:

Nginx和lighttpd都是采用C语言编写的,对于基础数据结构都有一定的处理。Nginx中关于数据结构的代码主要放在core文件夹里面。

Nginx主要的基础代码有:array、string、buf、file、hash、md5、内存池、队列、红黑树、time、共享锁等。这些数据结构对于扩展开发都非常有帮助。Lighttpd有一定的基础数据封装,但相对没有那么明显的设计。目前观察到的基础代码有:bitset、buffer等。
内存管理是所有C程序中非常值得关注的一点。Lighttpd在内存管理上没有做特殊的考虑,基本上都是采用系统内存管理函数,比如malloc/calloc等。在扩展开发中的内存也需要扩展模块自己考虑。Nginx在内存管理上提供了两种方式:1、原生malloc等的二次封装。2、内存池。在nginx内部大量的使用内存池。在扩展开发中也能直接调用内存池进行内存管理。此外,nginx还内置了对tcmalloc的支持。把内存优化做到极致。
架构层次
从总体架构来看,Nginx/Lighttpd都属于master+worker的工作模型。

但nginx相比lighttpd,在细节上处理的更加优化,具体可以从几个方面来谈
1、 配置文件热加载。Nginx从设计开始就支持配置文件热加载,甚至程序的热加载。Lighttpd本身不支持,目前业界有采用扩展方式,比如说lua,可以实现部分配置热加载。
2、 强大的master进程,实现worker进程和master进程的各司其职。Lighttpd的master进程在fork完worker进程后,就单独的等待worker进程的结束(或者在worker进程结束后再创建新的worker子进程)。Nginx的master进程负责对worker子进程的管理,并通过socket pair通信方式实现热配置文件升级、优雅重启、热应用程序升级等功能。
3、 线程锁。Lighttpd在进程之外还启动了线程进行相关方面的工作,这会对lighttpd的性能带来一定影响。Nginx内部虽然提供了对线程模式的支持,但在主推的进程模式中不会出现额外的线程。
4、 多核机器优化,cpu affinity。Nginx设计中考虑了对多核机器的优化方案,能降低进程在不同cpu之间的切换次数,从而提升性能。
超时处理
Lighttpd的超时处理原理非常简单:通过alarm信号量来实现的。每1s出发一个alarm信号,从而切换到超时处理函数。该函数也非常简单:循环简单当前所有连接的读和写,如果事件超时了,则直接close掉。这会有几个问题:
1、 连接非常多的时候。超时处理还是会非常耗事件的。随着连接数而递增。
2、 在不可重入的函数中出发alarm的时候,有可能出现意想不到的问题。
3、 需要轮询。
Nginx在超时处理上实现的巧妙的多:采用数据结构和巧妙的策略来实现。
1、 使用红黑树来存放定时器的相关数据。红黑树的重要特点是:插入删除都会在O(logN)完成,同时具有优秀的查找性能。所以很多C++的库(map)等都用到了它。
2、 通过红黑树计算出当前节点的超时时间差,使用这个时间差作为调用多路复用I/O操作的参数,当函数返回,只可能是I/O事件被触发,或者超时。
3、 处理完I/O事件之后,得到处理前后的时间差,根据这个时间差依次查看红黑树中哪些定时器可以被处理。
这也是在高压力下,Nginx更优于Lighttpd的一个重要原因。
Accept 处理
Lighttpd中对于Accept的处理有几个特点:1、不加锁。2、连接处理达到0.9的时候会禁止接收新的连接。3、1次性accpet 100个。这样有一个好处, 假如服务器监听fd是每次触发只接收一个新的连接, 那么效率是比较低的,不如每次被触发的时候”尽力”的去接收, 一直到接收了100个新的连接或者没有可接收的连接之后才返回。4、提供了fdwaitqueue。在fd不够用的时候备用。
Nginx:1、进程加锁,避免惊群,同时控制了获取accpet的概率,一定程度上控制各个子进程之间的请求数目。2、7/8阀值。连接数目达到最大连接数的7/8的时候,该进程将获取不到对应的accept锁。从而进入安全控制阶段。3、提供了multi_accept指令,在开启的情况下也和lighttpd一样尽可能的多accept。
状态机
Lighttpd和nginx都是状态机驱动模型,两者之间主要体现在细节的差异性上。
- Nginx对整个状态进行了分类,分成预处理、状态机、filter流程三个明显的阶段。
- Lighttpd的状态机相对简单固定。Nginx则相对灵活。
- Nginx的大部分处理状态都是可以扩展的并且可中断的。Lighttpd在部分状态中也可以扩展的。
- 耦合程度。nginx状态处理函数之间的耦合紧密,状态切换时的下一步处理由状态处理函数来决。而lighttpd将状态切换的动作放在状态机里,各个状态处理函数不关心下一步需要做什么,状态之间的耦合小。但同时会对扩展性带来一些问题,比如说subrequest的实现。
后端处理
Nginx针对不同的后端处理方式进行了封装,提供upstream来支持不同的协议(HTTP/FASTCGI/Memcache),提供扩展来支持不同的负载均衡算法。同样的Lighttpd在新版中也对不同的后端协议进行了封装,并提供了不同可供选择的负载均衡算法。
从原理层次来看,两者在后端处理上的思路是基本一致的。更多的对比需要从功能和性能上来对比。
扩展开发
Nginx和Lighttpd都支持扩展,Lighttpd是通过预留系统钩子来实现的,相对来说不够灵活,如果有一些特殊的修改则不得不修改源码。Nginx则通过预留系统钩子和控制反转结合,从而能够实现更多的功能。所以,nginx扩展的灵活性高于Lighttpd。
总结如下:
1、 nginx不支持动态扩展模块。
2、 扩展开发上,nginx更加灵活。提供了多种扩展切入方式。
3、 Nginx提供了丰富的类库,方便扩展开发。
功能对比
反向代理
对比分析如下:
1、 性能。
- 同等压力下,nginx的cpu消耗要低于lighttpd。但整体差别不大。
- 极限压力下,nginx处理能力高于lighttpd。原因未知。
2、 功能。
功能点 Lighttpd Nginx 备注 灵活的反向代理方式 支持 支持 都非常好 正则 支持 支持 自定义header头 部分支持 支持 目前gm有库支持IP的传递 负载均衡 支持 支持 超时处理 支持 支持连接、读写等 故障处理 支持 支持 Cache 不支持 支持 文件上传 未知 支持,可配置,有优化 Transmit不支持 输出过滤 不支持 支持 头部过滤和内容过滤。 结论:
1、功能上,nignx和lighttpd都具有完整的反向代理功能。但nginx在这方面明显优于lighttpd,更加完整的细节考虑和优化。主要体现在超时处理、文件上传、输入输出的过滤、cache等等。
2、性能上,Nginx稍优于lighttpd。
Fastcgi 支持
Nginx和lighttpd在Fastcgi方面功能上基本上相同,主要调研是从性能上对比。

10k 的php 请求
前端压力 Lighttpd Nginx 备注 1000QPS 96% 处理1000QPS 98% 2000QPS 91% 96% 4000QPS 81% 92% 8000QPS 65% 85% 20k 的PHP 请求
前端压力 Lighttpd Nginx 备注 1000QPS 95% 处理1000QPS 98% 2000QPS 90% 95% 4000QPS 80% 90% 8000QPS 63% 实际处理5588 QPS 86% 。实际处理5220QPS 从性能数据来看,2000QPS以内,两者性能差别不大,但高压力下,两者性能差别非常大。甚至有可能达到20%cpu差别。
页面Cache 和运维
Lighttpd目前暂无页面Cache的支持。Nginx从设计之初就考虑了更改Cache。甚至有单独的Cache管理进程。
从功能上来看,目前Nginx已经支持proxy cache和ssl filter,并且实现了对esi cache的支持。
从运维上来看,Nginx支持配置热加载,支持程序热加载。更适合完成24*365的全天候不间断服务。
总结
对比点汇总整理后如下
对比点 Nginx Lighttpd 备注 市场占有率 6.6% 0.5% 文档 百度文档10:1Google文档 1:1 国内研究人员nginx>lighttpd
业界点评 更加看好Nginx 代码量 10W 5W Nginx的代码结构层次较好。 基础数据结构 array、string、buf、file、hash、md5、内存池、队列、红黑树、time、共享锁 bitset、buffer 丰富的库类对扩展开发有很大帮助 内存管理 原生malloc、内存池、支持tcmalloc 原生malloc 配置文件热加载 支持 不支持 进程模型 Master负责管理,worker负责处理请求,各司其职。 Master简单。Worker复杂 进程额外线程 无 有 存在线程锁 多核机器优化 支持 不支持 连接管理 静态数组+单链表 动态数组,key交互 Nginx更加稳定高效。 超时处理 红黑树+巧妙的策略 Alarm+for循环 Accept处理 锁+7/8阀值,支持mult accept 0.9策略,一次性aceept100个。 状态机 - Nginx对整个状态进行了分类,分成预处理、状态机、filter流程三个明显的阶段。
- Lighttpd的状态机相对简单固定。Nginx则相对灵活。
- Nginx的每一个状态都是可以扩展的并且可中断的。Lighttpd在部分状态中也可以扩展的。
- 耦合程度。nginx状态处理函数之间的耦合紧密,状态切换时的下一步处理由状态处理函数来决定ligty将状态切换的动作放在状态机里,各个状态处理函数不关心下一步需要做什么,状态之间的耦合小。
后端处理 都支持多种协议,并且方便扩展,都支持负载均衡算法扩展。 扩展开发 1、 预定义钩子2、 控制反转 3、 丰富库类
预定义钩子 反向代理 1、功能上,nignx和lighttpd都具有完整的反向代理功能。但nginx在这方面明显优于lighttpd,更加完整的细节考虑和优化。主要体现在超时处理、文件上传、输入输出的过滤、cache等等。2、性能上,Nginx稍优于lighttpd。 fastcgi 功能上两者差别不大,主要体现在性能上。在性能上,2000QPS以内,两者性能差别不大,但高压力下,两者性能差别非常大。 页面Cache 支持proxy_cache。支持esi页面cache 不支持,需要额外开发。 运维相关 支持配置文件热加载支持应用程序热加载 支持有限的配置文件热加载 通过上述对比分析,可以得出如下结论:
“lighttpd和nginx一样具有非常好的架构,但在数据结构、内存管理都多个细节方面处理nginx考虑更加完善。如果说lighttpd是异步web server的先驱,那么nginx则是对lighttpd做了整体的优化的。而这些优化是全面的,根本性质的。无法简单的通过升级lighttpd来实现。因为nginx从一开始设计就希望做成一个完美的异步web server。nginx从event、跨平台、基础数据结构都很多细节方面进行了考虑和优化。应该来说,nginx必定是未来的apache,未来的主流。”
by xuliqiang
由 IT 牛人博客聚合网站(udpwork.com) 聚合 | 评论: 1
- Shell的知识点整理发表时间: 2011-10-15来源: IT牛人博客聚合网站
这几天抽了点时间看了一下《Advanced Bash-Scripting Guide》, 之前一直觉得shell这门脚本很有意思,虽然用得不多,但感觉shell这门脚本似乎有点粗糙,但看了abs-guide之后就觉得shell还是很强大的,很多高级特性之前都没曾接触过,平时也用得不算很多。浏览了一下abs-guide之后做了一些简单的笔记,方便以后查看,每个”echo ===”之间就是代码片段,在bash version 3.2.48下测试过,点解高亮区的”view source”可以直接复制所有代码。
#--------------- Begin #!/usr/bin/bash for arg in "Hello World What The Fuck" do echo $arg done echo "==================================" FILES="/usr/bin/accept /usr/sbin/pwck /usr/sbin/chroot /usr/badblocks /sbin/ypbind" for file in $FILES do if [ ! -e "$file" ] then echo "$file does not exist."; echo continue fi ls -l $file | awk '{ print $8 " file size: " $5 }' done echo "==================================" for file in * do echo $file done echo "==================================" NUMBERS="1 3 5 7 9 25.3" for num in `echo $NUMBERS` do echo -n "$num" done echo "==================================" PASSWD_FILE=/etc/passwd n=1 for name in $(awk 'BEGIN{FS=":"}{print $1}' < "$PASSWD_FILE") do echo "USER #$n = $name" let "n += 1" done echo "==================================" echo `seq 10` echo "==================================" for ((a=1, b=2; a <= 10; a++, b++)) do echo $((a-b)) echo $[$a-$b] done echo "==================================" ROOT_UID=0 E_NOTROOT=87 E_XCD=86 #can't change directory? #root check if [ "$UID" -ne "$ROOT_UID" ] then echo "Must be root to run this script." exit $E_NOTROOT fi cd /var/log || { echo "Cannot change to necessary directory." >&2 exit $E_XCD; } echo "==================================" let "t2 = ((a = 9, 15 / 3))" echo "==================================" # ` -> command substitution # pdftk is a useful tool for pdf files `pdftk f1.pdf,f2.pdf cat output combined.pdf` echo "==================================" # ${parameter-default}, ${parameter:-default}, return but not set var1=1 var2=2 #var3 is unset echo ${var1-$var2} # 1 echo ${var3-$var2} # 2 echo "${var3}=${var3}" # ${var3}= # ${parameter=default}, ${parameter:=default}, return and set var default echo ${var4=$var1} # 1 echo $var4 echo "${var4}=${var4}" # ${var4}=1 echo "==================================" args=$# # num of args lastarg=${!args} # or lastarg=${!#} echo "Last arg is ${lastarg}" echo "Listing args with "$*":" for arg in "$*" do echo "Arg #$index = $arg" # all in one line let "index+=1" done echo "Listing args with "$@":" for arg in "$@" do echo "Arg #$index = $arg" # seperate every arg in new line let "index+=1" done echo "==================================" # space should be quoted or escaped echo {file1,file2}* :{ A," B",' C'} # file1* : A file1* : B file1* : C file2* : A file2* : B file2* : C echo "==================================" echo {a..z} echo {0..3} echo "==================================" # both stdout & stderr `ls &> a.txt` # stdout -> stderr `ls >&2` echo "==================================" dt=$(date +%m-%d-%Y) echo $dt a=$(ls -l) echo $a # all in same line echo "$(ls -l)" # Quoting , don't suppress in one line echo "==================================" shift # shift 3, shift 3 positions echo $1 # value of $2 echo $2 # nothings echoes, move not copy echo "==================================" exit $? # $? reads the exit status of the last command executed echo "==================================" if [ 0 ] then echo "0 is true." else echo "0 is false." fi # 0 is true. if [ ] then echo "NULL is true." else echo "NULL is false." fi # NULL is false. echo "==================================" # page58, if test operators # if, elif, else if [ 0 ] then # command echo "if statement" elif [ 1 ] then # command echo "elif statement" else # default-command echo "else statement" fi echo "==================================" type test type '[' type '[[' echo "==================================" # test/[ considers its arguments as comparison expressions or file tests # and returns an exit status corresponding to the result of the comparison (0 for true, 1 for false) [ 0 ] echo $? # 0/true [ ] echo $? # 1/false echo "==================================" # The (( )) construct expands and evaluates an arithmetic expression. # If the expression evaluates as zero, it returns an exit status of 1, or "false". # A non-zero expression returns an exit status of 0, or "true". # This is in marked contrast to using the test and [ ] constructs previously discussed. ((0)) echo $? # 1/false (( 5 > 4)) echo $? # 0/true echo "==================================" # A number preceded by a 0 is octal (base 8). # A number preceded by 0x is hexadecimal (base 16). # A number with an embedded # evaluates as BASE#NUMBER a=021 # 8*2+1 b=0x21 # 16*2+1 c=4#21 # 4*2+1 echo "==================================" # Double-parentheses ((..)) construct is also a mechanism for # allowing C-style manipulation of variables in Bash, for example, (( var++ )). (( a = 23 )) (( a++ )) (( t = a<45?7:11 )) let --a echo "==================================" ROOTUSER_NAME=root username=`id -nu` if [ "$username" = "$ROOTUSER_NAME" ] then echo "Root!" else echo "Not Root!" fi echo "==================================" # $!, PID (process ID) of last job run in background # Forces completion of an ill-behaved program. # Useful, for example, in init scripts. # possibly_hanging_job & { eval 'kill -9 $!' &> /dev/null; } `wget http://www.facebook.com &` { eval 'kill -9 $!' &> /dev/null; echo "kill finished."; } echo "==================================" declare -i number=3 declare | grep HOME echo "==================================" echo $RANDOM num=2 echo $((RANDOM % num)) echo "==================================" # page 115 stringZ=abcABC123ABCabc echo ${#stringZ} # 15 echo `expr "$stringZ" : '.*'` echo "==================================" var1=unset previous=$var1 # Four conditions on "while", but only the last one (exit status) controls loop. while echo "previous-variable = $previous" echo previous=$var1 [ "$var1" != end ] do echo "Input variable #1 (end to exit) " read var1 echo "variable #1 = $var1" done echo "==================================" t=0 condition() { ((t++)) if [ $t -lt 5 ] then # like exit status return 0 else return 1 fi } # condition can be a function while condition do echo "Still going: t = $t" done echo "==================================" END_CONDITION=end # loop as long as the condition is false until [ "$var1" = "$END_CONDITION" ] do echo "Input variable #1 " echo "($END_CONDITION to exit)" read var1 echo "variable #1 = $var1" echo done echo "==================================" for outer in I II III IV V do echo "$outer " for inner in 1 2 3 4 5 do if [ $inner -eq 3 ] then # break can also optionally take a parameter continue 2 fi echo "$inner " done done # Output : I 1 2 II 1 2 III 1 2 IV 1 2 V 1 2 echo "==================================" # case statement while [ $# -gt 0 ]; do case "$1" in -d|--debug) DEBUG=1 echo "Debug On." ;; -c|--conf) CONFILE="$2" shift if [ ! -f $CONFILE]; then echo "Error: Supplied file doesn't exist!" exit $ERROR_OF_FILE_NOT_FOUND fi ;; esac shift done echo "==================================" # select statement, "select var [in list]" # select uses the $PS3 prompt by default # if [in list] omitted, use cmd line args or func args instead PS3="Choose your favorite vegetable:" echo choice_of() { select vegetable # [in list] omitted, so 'select' uses arguments passed to function. do echo echo "Your fav veggie is $vegetable." echo "Yuck!" echo break done } choice_of beans rice carrots radishes tomatoes spinach echo "==================================" # cmd substitution, will invoke a subshell file_listing=`ls -al` echo $file_listing file_listing2=$(ls -al) echo $file_listing2 for arg in `echo a b`; do echo $arg done # a b in 2 lines for arg in "`echo a b`"; do echo $arg done # ab in single line echo "==================================" declare -r PI=3.14159265358979 echo $PI printf "PI is %1.12fn" $PI read var1 var2 echo $var1 echo $var2 read echo "You just input : $REPLY" echo "==================================" echo "List of all users:" OIFS=$IFS; IFS=: while read name passwd uid gid fullname ignore do echo "$name ($fullname)" done < /etc/passwd echo "==================================" arr0=( 10 11 12 13 14 15) arr1=( 20 21 22 23 24 25) choose_array() { eval array_member=${arr${array_number}[element_number]} echo "Element $element_number of arr$array_number is $array_member." } array_number=0 element_number=3 choose_array echo "==================================" a='$b' b='$c' c=d # each invocation of eval forces a re-evaluation of its arguments echo $a # $b eval echo $a # $c eval eval echo $a # d echo "==================================" echo "Positional parameters before set 'uname -a' :" echo "Command-line argument #1 = $1" echo "Command-line argument #2 = $2" echo "Command-line argument #3 = $3" # set `Command` can reset the positional parameters that a script # sees as the result of a command set `uname -a` echo "Positional parameters after set `uname -a' : " echo "Field #1 of 'uname -a' = $1" echo "Field #2 of 'uname -a' = $2" echo "Field #3 of 'uname -a' = $3" echo "==================================" # using set with -- option explicitly assigns the contents of a variable # to the positional parameters. If no variable follows the --, # it unsets the positional parameters. var="one two three four five" set -- $var echo $1 echo $2 echo $3 echo "==================================" usage() { echo "Usage:..." exit 0 } flag=false list="" set -- $(getopt ahl: "$@") while [ $# -gt 0 ] do case "$1" in -h ) usage;; -a ) flag=true;; -l ) list="$2"; echo $list; shift;; -- ) shift; break;; -* ) echo "$0: unrecognized option $1" 1>&2; usage;; * ) break;; esac shift done echo "==================================" usage() { echo "Usage:..." exit 0 } flag=false list="" while getopts ":ahl:" Option do case $Option in a ) flag=true; echo "Option a : [OPTIND=${OPTIND}]";; h ) echo "Option h : [OPTIND=${OPTIND}]"; usage;; l ) echo "Option l : [OPTIND=${OPTIND}]"; list=$OPTARG; echo $list; break;; * ) echo "Unrecognized option. $Option";; esac done echo "$OPTIND" shift $(($OPTIND -1)) # $1 now references the first non-option item supplied on the command-line #+ if one exists. echo $1 echo "==================================" # same effect as the #include directive in a C program # var_in_file1=wtf in file1.sh source file1.sh echo $var_in_file1 echo "==================================" # Using the exec builtin, the shell does not fork, # and the command exec'ed replaces the shell. exec echo "Exiting "$0"." echo "This echo will never echo." exit 99 echo "==================================" # caller is useful in debugging function2() { caller 1 } function1() { function2 caller 0 } function1 echo "wtf" caller 0 echo "==================================" # true returns a successful(0) exit status # but does nothing else # false does the same, but return (1) true echo $? # 0 # endless loop, alias for ":" while true do echo "wtf" sleep 2 #cmd1 #cmd2 done echo "==================================" # page 204 jobs disown bg fg wait echo "==================================" # external cmd, page 210 `cat` `tac` `chattr` # ... echo "==================================" # here documents, simlilar to # interactive-program < command-file, # where command-file contains contents # between "this_is_a_mark_string" wall <<'this_is_a_mark_string' Do u know who i am? this_is_a_mark_string # - option can supress leading tabs(but not spcaes) # Quoting or escaping the "limit string" at the head of a here document # disables parameter substitution within its body var1=wth cat <<-MARK_OF_STR what the fuck? $var1 MARK_OF_STR echo "==================================" # file descriptor echo 1234567890 > file_name # write string to "file_name" exec 3<> file_name # open "file_name" and assign fd 3 to it read -n 4 < &3 # read only 4 chars # builtin echo do not support -n printf . >&3 # write a decimal point there exec 3>&- # close fd 3 cat file_name # 1234.67890 # n< &- close input fd n # 0<&-, <&- close stdin # n>&- close output fd n # 1>&-, >&- close stdout # child process inhreit open fd, close it if no need echo "==================================" # There is no method of 'declaring" the function like C func1 # error, func1 not defined declare -f func1 # not help func1 # still error echo "==================================" file=/etc/passwd pattern=hallo return_value="" file_excerpt() { echo "Pattern : $1" local i=0 while read line do echo $line ((i++)) if [ $i -eq 5 ];then # custom pre-defined return value return_value=(1 2 3) # max return value, positive int 255 return 0 fi done } < $file file_excerpt $pattern echo "Return value is : ${return_value[1]}" echo "==================================" # must set this option, else script will not expand aliases shopt -s expand_aliases alias llm='ls -al | more' llm echo unalias llm llm # error, unalias already echo "==================================" # bash permits array operations on variables # even if the variables are not explicitly declared as arrays. string=abcd1234 arr_str=("what" "the" "fuck") echo ${string[*]} # abcd1234 echo ${arr_str[*]} # what the fuck echo ${string[@]} # abcd1234 echo ${arr_str[@]} # what the fuck echo ${#string[@]} # 1, length echo ${#arr_str[@]} # 3 echo "==================================" # page 416 # many of the standard string operations work on arrays arrayZ=( one two three four five) echo ${arrayZ[@]:0} echo ${arrayZ[@]:1} echo ${arrayZ[@]:1:3} echo ${arrayZ[@]/ive/XYZ} # ... echo "==================================" # combine 2 array arr1=(one two three) arr2=(four five six) combined=(${arr1[@]} ${arr2[*]}) echo ${combined[*]} echo "==================================" arr1=( VAR1=value1 VAR2=value2 VAR3=value3 ) arr2=( v1="test" v2="VAR1=value1 VAR2=value2 VAR3=value3" v3=${arr1[*]} ) test_for_2d_array() { t="arr2[*]" local ${!t} echo "${!t}" # v1=test v2=VAR1=value1 VAR2=value2 VAR3=value3 v3=VAR1=value1 VAR2=value2 VAR3=value3 echo "${v1}" # test echo "${v2}" # VAR1=value1 echo "${VAR2}" # value2 echo "${VAR3}" # value3 echo "${v3}" # VAR1=value1 } test_for_2d_array echo "==================================" # indirect reference a=b b=hallo eval res=$$a echo "$res" # hallo echo "==================================" # trap specifies an action on receipt of a signal, # useful for debugging trap 'echo "omg"' EXIT while true do sleep 2 echo "hallo" done echo "==================================" # The DEBUG argument to trap causes a specified action to execute # "after" every command in a script, useful for tracing variables trap 'echo "TRACE> $variable = "$variable""' DEBUG variable=29 echo "Just init $variable to $variable." echo "==================================" # trap '' SIGNAL disables SIGNAL for the remainder of the script # This is useful to protect a critical portion of some uninterruptable actions trap '' 2 # Signal 2 is Control-C, now disabled sleep 2 cd ls sleep 2 # command... trap 2 # Reenables Control-C echo "==================================" #--------------- End由 IT 牛人博客聚合网站(udpwork.com) 聚合 | 评论: 0
- Subversion钩子发表时间: 2011-09-26来源: IT牛人博客聚合网站
Subversion本身有很好的扩展性,用户可以通过钩子实现一些自定义的功能。
所谓钩子实际上是一种事件机制,当系统执行到某个特殊事件时,会触发我们预定义的动作,这样的特殊事件在Subversion里有很多,默认有如下模板可供选择:
shell> ls /path/to/repository/hooks post-commit.tmpl post-lock.tmpl post-revprop-change.tmpl post-unlock.tmpl pre-commit.tmpl pre-lock.tmpl pre-revprop-change.tmpl pre-unlock.tmpl start-commit.tmpl
其中最常用的是pre-commit和post-commit,也就是提交前后的钩子,下面以pre-commit为例来说明一下如何自定义Subversion钩子。
假设有一个PHP项目使用Subversion做版本控制,使用中发现了一些问题,比如程序员不写日志,或者提交的文件有BOM,或者提交的文件有语法错误,或者提交的文件不符合编码规范等等,这些问题都可以利用pre-commit钩子来解决,实际上已经有人写了解决类似问题的工具php-svn-hook,不过我们这里选择自己实现:
shell> cat /path/to/repository/hooks/pre-commit #!/bin/bash REPOS="$1" TXN="$2" SVNLOOK="/usr/bin/svnlook" PHP="/usr/bin/php" LOG=$($SVNLOOK log -t "$TXN" "$REPOS") if [ "$LOG" = "" ]; then echo "Please input log" 1>&2 exit 1 fi FILES=$($SVNLOOK changed -t "$TXN" "$REPOS" | awk '/^[AU]/ {print $NF}') for FILE in $FILES; do CONTENT=$($SVNLOOK cat -t "$TXN" "$REPOS" "$FILE") if echo "$CONTENT" | grep -q $'xEFxBBxBF'; then echo "Please remove BOM from $FILE" 1>&2 exit 1 fi if [[ "$FILE" =~ .(php|html)$ ]]; then MESSAGE=$(echo "$CONTENT" | $PHP -l 2>&1) if [ $? -ne 0 ]; then echo "$MESSAGE" | sed "s/ -/ $FILE/g" 1>&2 exit 1 fi fi done /path/to/PHP_CodeSniffer/scripts/phpcs-svn-pre-commit "$REPOS" -t "$TXN" 1>&2 || exit 1 exit 0注:代码里使用PHP_CodeSniffer检查编码规范。
配置好脚本后,一定要记着给脚本加上可执行属性,不然脚本执行后会显示不知所云的错误信息:svn: Commit blocked by pre-commit hook (exit code 255) with no output。
本文以pre-commit为例说明了一下钩子的用法,实际上其他脚本也很有用,比如说如果你想在提交代码后发一条微博,就可以利用post-commit来解决,但是记住不要滥用,比如说非常流行的一种做法是利用post-commit来更新线上程序,但由于整个操作过程不能保证原子性,所以有可能出现问题,解决方法请参考Rasmus的描述,我就不多说了。
由 IT 牛人博客聚合网站(udpwork.com) 聚合 | 评论: 0
- 电子商务关键数字优化(线上部分,上)发表时间: 2011-09-25来源: 网站分析在中国
【每期一句】
没有数字和分析,没有电子商务。
【前言】
从事电子商务的工作一段时间,发现自己对于数据的想法有了很多变化。过去,我们拿着国外的理论,然后站在河边的岸上,对河中游泳的人们指指点点。今天,当你也跳入河中,就是全然不同的感受。一方面河水冰冷刺骨,另一方面,也开始理解为什么曾经河中的人们用各种“怪异的姿势”奋力搏击。这一篇文章,是我在杭州参加车品觉老师《智论商道,西湖秋学》活动的演讲整理,也记录了我的“河中感受”。
【正文】
这是一个很大很难但也是每一个电商人都会问的问题——我该如何优化我业务中的关键数字。
我也面临这个问题——这个有数百种,不数万种各不同相同答案的问题。优化关键业务数字,没有固定的策略,因此也就没有固定的答案,但却并非无迹可循,而是有章有法的。甚至,这些方法事实上并不需要你去从头摸索,前人早已准备了众多滋养,只需你有心跟随即可。
既如此,就让我们先看看前人给我们这些滋养是什么。
关键的第一步
优化电子商务关键数字的第一步是什么?
说来好笑,这个问题的答案是——什么电子商务的关键数字?不过这可是个很严肃的答案,当然,也是一个很严肃的问题。
分析不是为了分析而分析,没有明确目的的分析,是“无病呻吟”。分析是需要消耗资源的,而且消耗的全部是“沉没资源”——时间,你不能把分析投入到本来不需要分析的领域去。因此,电子商务关键数字优化的第一步恰恰是识别关键数字是什么。
对于电子商务关键数字的识别,是起始于“KBR”的。KBR是我在Adobe Omniture的时候被洗脑的一个词,意思是Key Business Requirement。当然,这不过是人头马酒瓶装二锅头罢了。KBR没什么新意,不过点明了你的分析要从组织的关键业务需求开始。
但这个思想很重要,本质上,这个思维方法就是我们熟悉的“金字塔思维方法”——事情有一个根本的基点,一切最终要回到这个基点。我们在分析的时候,很多时候是被兴趣所指引,发现了麻雀去追麻雀,发现了兔子又去撵兔子,这是分析工作最初吸引新来者的很重要的原因——看起来一切都是非常新奇有趣的。可是商业分析,你不能浪费你的“沉没成本”,我们不为兴趣所指引,我们所做的一切都需要不断反问自己,是否是围绕着KBR进行的。
KBR意味着组织的“当务之急”。对于电子商务,尤其是国内的电子商务,业务上的当务之急是清晰而明确的——增加销售,降低成本。不过这不能算KBR,因为它太过于粗放,而且不够具体。但沿着这个方向,我们会发现大部分电子商务公司在增加销售和降低成本方面都根本上将聚焦于下面两个事情——量和率。
量,当然,归根结底是销售量,不过销售量显然决定于流量、注册量,以及转化率和回头率。因此,我们的思维是,要提升销售,我们需要提升流量和注册,并且提升转化和回头的机会。这和做一个线下商店的关键数字指标是类似的——人流量多少,多少人进店买了东西,又有多少人还回来。
说一点题外话。我认为国内的电子商务公司,因为它们本身所具有的“股票公司”的特性,利润率什么的,反而不是真正他们关心的。区分什么样的电子商务公司更在乎利润率的一个有趣指标是——他们是否获得了外部投资。当这些公司没有外部投资,维持在一个较小规模的时候,利润率是非常重要的;但当投资进入,扩大规模、挤死竞争对手成为主线的时候,利润率是一个可以牺牲甚至是必须牺牲的指标了。这很有趣,对消费者而言,当一家电商公司刚刚获得投资的时候,促销一定是很给力的,这时的商品值得购买。

当然,电子商务是否还有什么其他的关键数字,取决于这个公司自身的经营特点和业务特性,这里不再赘述。强调一点,我们关注方法本身,电子商务关键数字优化的第一步是真正识别你的业务的关键数字。KBR不建议是最大的那个放之四海而皆准的目标(例如Revenue),而应该是这个大目标之下,跟你的大目标达成真正关联的那几个可以清晰定量的目标(例如电子商务中的量和率)。你值得花一些时间找到真正的KBR。
建立优化路径
现在,你通过自己的思考或是“老板的指示”知道了KBR是什么。现在你该怎么办呢?
我们都知道,任何复杂的问题都可以遵循一定的方法解决,若没有解决,是因为没有找到方法。例如哥德巴赫猜想,人们并非是在寻找答案,而是在寻找方法。同样,KBR不能优化,并非是它不能优化,而是我们可能没有找到正确的方法,或是没有去正确执行这些方法。
下面是我的方法,你当然也可以建立你自己的方法。有效果的方法就是好方法,这里没有标准答案。
上图是我总结的KBR的优化路径。这个路径看起来文字众多,步骤繁琐,实际上思想非常简单。你也可以看我下面的文字描述,可能更容易理解:
定义KBR——分解影响KBR绩效的驱动因素——确定这些驱动因素中哪些是基础驱动因素,哪些是非基础驱动因素——尝试分析基础驱动因素并着手改进——同样,尝试分析非基础驱动因素并着手改进——测试你的这些改进是否有效并固定有效的改进(优化)——优化不可能是针对所有人群和兴趣的,所以最后你要在优化的基础上进行动态处理(定制化)。
还是够复杂的,再简单点
,用白话!定义KBR——分解影响KBR的那些破事儿——哪些破事儿更具全局影响力?哪些是局部的?——想办法搞定这些破事儿——真的搞定了吗?测试看看——靠谱的办法固定下来——不能用一种办法搞定,多几个办法针对不同情况!
我觉得KBR就是被这么搞定的。只是每个破折号后面的每一步体现了水平。网站分析甚至不是一个技术活,毕竟我们没搞什么高深的数学模型,但确实需要缜密的心思,丰富的经验,敏感的嗅觉,和不断尝试的勇气。
当然,你可能还是觉得,上面的这个模型(姑且厚颜无耻点把它称为模型),毕竟是一个非常抽象的东西,您可能还是没有太理解,什么是驱动因素?为什么有基础和非基础?测试如何做?又如何动态化定制化?一连串的问题,待我慢慢道来。
基础驱动因素和非基础驱动因素
驱动因素真TMD是一个拗口的词。驱动因素是一个西方词,不是老祖宗汉语,但我们不得不用它是因为现代科学和管理学都是人家西方人树立的,咱们中国人也只有成了西方人(加入了别人国家),才似乎有点建树。不过我们国家盖楼修路放卫星办运动会火车比速度行,也不算一无是处。驱动因素是initiative的翻译,这个词是形容词,也可以作为名词。找不到更好的翻译,于是俺们国人就把它翻译成驱动因素了。
废话不多说,你理解它为影响因子也行(kao…,因子这个词也是人家,是factor的翻译,唉…),就是会影响KBR绩效的那些因素。例如,影响流量这个KBR的因素的驱动因素是资源多少(例如花钱多少)、营销活动的水准、SEO水平等等。这么说应该很好理解。
那么,什么是基础驱动因素和非基础驱动因素呢?这是我自己琢磨的,没理论根据,但我觉得好使。
所谓基础驱动因素,就是那些当你改变了它(优化了它)就会全局性长时间改变(优化)KBR的那些影响因子;
而非基础驱动因素,就是那些当你改变了它(优化了它)就会局部性一定时间内改变(优化)KBR的那些影响因子。
用咱们汉语说,基础驱动因素就是内功,非基础驱动因素则是招式。内功常在,招式则要过招时才发生。
现在可能你明白了一点我想说什么。不过,最好的方法是,我们举一个真正的KBR优化的例子,让我们看看上面的路径和驱动因素如何帮助我们优化KBR。
案例:如何优化KBR之转化率(1)——驱动因素的细分
转化率是我最喜欢谈的,因为对它的研究业界已经很多,但我们似乎总未破解它的迷局。
按照我们前面提到的KBR优化路径,我们要找到转化率这个KBR的驱动因素,并且要把基础驱动因素和非基础驱动因素区分开来。然后分别加以分析和优化。
我是这么分解的,如下图所示:
我影响转化率的基础驱动因素确定为:
- 关键转化过程
- 导航(分类)
- 搜索
- 信任
- ……
非基础驱动因素确定为:
- 产品页面
- 登陆页面
- 活动和流量匹配程度
- 外部流量本身质量
- ……
先来看看基础驱动因素的确定。关键转化过程,是老生常谈的了,就是在转换路径中各个关键环节。这些环节的某一个或多个做不好,对整体销售转化的影响都会非常大,也就是我们常说的木桶短板效应。导航和分类,本质上是对用户遍历或寻找商品逻辑的有效组织或再组织,不好的导航和分类,让用户没有在合适的位置找到合适的商品,扫兴而归,转化率受损。搜索,跟导航和分类是类似的,只是人们更容易对它产生更高期待,并更容易在期待落空后放弃。
这几个因素,都全局性的影响到转化率这一KBR。无论流量质量(人群价值)如何,无论你的活动页面有多么吸引人,这些因素做不好,转化率都会低下。因为这些因素是基础性的影响。而活动页面的吸引力则非基础性的,A活动的页面不好,那么在下一次B活动中加以改进,仍有机会,但关键转化路径中埋有惊人败笔,却不是活动设计本身能够挽救。
所以,我把它们作为基础性驱动因素。基础性驱动因素还有很多,限于篇幅不再冗举,朋友们不妨留言列举。
【闲来无事多读一点】
同转化率一样,回头率也有基础驱动因素和非基础驱动因素。在会场有朋友问起这个问题,引发了较长时间的讨论。
回头率的基础驱动因素往往是:
- 细分人群属性
- 细分人群消费行为
- 竞争商品
- 竞争价格
- 第一次消费体验
- 转化率(更高的转化率会促进回头率)
- ……
非基础驱动因素是:
- 市场及促销活动
- 精细化找回营销
- 外部市场环境(动态变化)
- ……
相对于转化率,回头率的衡量更具有难度,所受的影响因子也更多。优化它的基本方法必须经过人群的细分,按照消费行为、人群属性的细分,挖掘哪些属性、行为的人群的不同流失情况。以辨别流失倾向和人群的关系。另一种细分维度则是按商品品类细分的人群流失情况。哪类商品的购买者更容易发生流失。以辨别竞争商品和价格可能存在的问题。
转化率的非基础驱动因素则比较明显,它们都是局部性的,而且时限性相对较短。例如产品页面,产品页面的介绍对该产品的转化率影响很大,但并不影响其他产品,而且产品有明显的生命周期。登陆页面同样,它们会影响活动的转化效果,但只限于影响自己的活动。流量本身也是动态的,尽管流量永远存在,但却并不能保证每天的流量都能匹配landing page,或是保持持续的较高品质。
现在,你应该能够明白基础驱动因素和非基础驱动因素了。那么,我们这么划分的意义何在呢?
案例:如何优化KBR之转化率(2)——驱动因素细分意义何在
细分基础和非基础驱动因素的意义在于,你能够知道应该先从哪里下手。前文说过,分析是需要资源的,最重要的资源是时间,是沉没成本,你不太能够分析所有的因素,所以分析的艺术是抓住重点直切主题的艺术。

基础驱动和非基础驱动二者,在转化率这个电子商务的KBR上,体现出非常明显的没有抓住重点的趋势。原因无它,我们往往更重视非基础驱动因素而不愿直面基础驱动因素。招式易学,内功难练。
电子商务显现出非常明显的对活动的重视,对流量本身的重视,但却往往疏失关键的转化过程中是否存在明显短板,是否有更好的用户指引,并忽略建立初次和长时间的信任。这些都比不上修正下产品页面,给用户促销,以及产品页面的说服诱导见效快,所以理所应当的被放到次重要的位置上。
这是误区。内功练成,无招胜有招;招式搞定,却不过是空有花架子。基础驱动应该放到更高优先级上,至少它应该跟非基础驱动一并被关注和优化。
好了,这些都是浅显的道理,我就不多啰嗦了。限于时间的关系,我很难找到大段的时间跟大家分享。就先停笔到这里。未来也许某一天,我不会那么忙了,我停下来,能够跟朋友们更多分享。更多的内容,请期待这个文章的后半部分!
欢迎大家留言,想到什么就说什么!


- 推荐阅读:《北京的哥讲述的励志故事》发表时间: 2011-09-21来源: IT牛人博客聚合网站
经典励志片,可走《永不妥协Erin Brockovich》、《城市英雄 Falling Down》路线。哪位天使大哥大姐,赶紧找这个的哥买独家版权吧!
请点击知乎链接:http://www.zhihu.com/question/19855176/answer/13163625
讲述者:panbin,幸福科技CEO,前新周刊记者。
说一个个例,我曾调查一个医药案子(调查记者),在出租车上,跟后方编辑打电话交流看法。司机问我,你是医疗行业的?(因当时针对药监局内幕做了很多调查,弄得满嘴医学术语。)
我当然否定之,但司机追问,我只好说自己是记者,正在调查与医疗系统相关的事。对方很兴奋,说终于找到这样的人了。我问他什么情况,他说自己的岳父因为医疗事故,被同仁医院的外派医生弄瞎了眼睛,自己一直跟医院打官司呢。我听着有点料(职业本能判断),就给了他名片。
我在药监局的调查结束之后(就是这篇,《药审的秘密》blog.sina.com.cn/s/blog_4...),这名和气的出租车司机找到我单位,带了很多材料,向我说明案子情况。事实上,官司很简单,因为碍着医院和卫生局的关系,昌平法院一直不给判决,后来我去了一趟昌平法院,两个小时之后,判决书就下来了,还是胜诉。
我对这名出租车司机感兴趣,是因为他维权的方式。用知识武装自己,把自己的出租车厢当做“知乎”。他在长达两年的维权过程中,没有上访、闹事,而是专心学习法律、医学、信息、政治知识,而他的老师们,就是乘客。
比如案子中他发现,那位同仁医生的医师资格证书有问题,与另外一名医生号码重复,有可能造假,卫生局的答复是计算机数据库录入出错。他不信,就专门在中关 村科技园附近拉人,最终在上地遇到一位数据库专家,中国信息管理中心的工作人员,给他详细讲解了数据库原理,并告诉他,不可能是数据库录入出错。
又比如,他对眼睛致瞎的原因不清楚,就专门到医院附近拉活,后遇见一位北大人民医院的眼科主任,主任跟他详解眼病原因,并看了他随身带的病例和材料,并确 定地告诉他,医院和医生的责任在哪里。在讲解过程中,主任到家了,又在小区门口,多讲了半个多小时。
还比如,在医疗事故鉴定上,他得到非常不利的结果,他想推翻之,就专门找医疗鉴定专家。对法律知识不了解,就专门到法院附近拉人,在打官司过程中,很多法 官都给他出过主意,很多律师也提出帮助。他也想找记者,但遇到的都是文化娱乐记者,没见着法制或调查记者,我是第一个。
我后来去他家看过一次,电脑里有专门的文件夹,分门别类,写满了与官司有关的各种信息。还有厚厚的打印和手写材料。他自豪的说,现在,他是半个眼科医生和半个律师。二审的时候,他甚至没有花钱请律师,而是自己写诉状,自己充当辩护人。
他曾经求教过的人还有:中日友好医院的老教授(女)、空军总医院医师(女)、海淀法院立案庭法官、医院的法律顾问、海淀医院行政人员、司法鉴定中心工作人员、人大代表等等。
他用自己所学到的知识,数次将医院、鉴定中心、卫生局、法院逼到墙角,最终小胜。可惜的是,这个故事没有最终成稿,一是因为编辑觉得故事偏单薄,需要再找几个案例。二是我处在人生转型的关口,出来创业了。很遗憾,所以写在这里,想起什么,随时补充。作者:旁观者发表于 2011-09-21 20:58原文链接
最新新闻:
·慢公司的5000万美金(2011-09-23 18:01)
·我眼中的敏捷设计(2011-09-23 17:58)
·刘强东:我只是一个呼喊公平竞争的市场主义者(2011-09-23 17:58)
·微软中国CEO梁念坚 : Windows Phone有四大优点(2011-09-23 17:55)
·科学家将脑波转换为图像(2011-09-23 17:41)
编辑推荐:中国的土壤真的不适合软件生长!
网站导航:博客园首页 我的园子 新闻 闪存 小组 博问 知识库
由 IT 牛人博客聚合网站(udpwork.com) 聚合 | 评论: 0
- 女人,你要沉得住气发表时间: 2011-09-22来源: 左岸读书_blog
驴友荐文。
女人,请不要空等男人来给你幸福,给你金钱给你关爱。这样的等待像买彩票,太玄乎。你为什么不自己给自己幸福。在你有运气得到男人所给的幸福之前,请你先有能力自己给自己幸福。又或者,你不该这样的守株待兔,同样是社会,为什么男人拼的是真才实学,而女人却有另一条完全不同的成功小道?
文/菲瑜
整个社会对女人美貌的追求像对男人成功的追逐一样登峰造极,丑女永无出头之日,美女最快捷的成功方式就是靠美貌。
一百年后,如果中国的大地上还是忍受着高昂的物价,食品不安全、医疗无保障、出门怕被撞、孩子怕被拐,那么这将是我们这几代人的耻辱。
女人,请不要空等男人来给你幸福,给你金钱给你关爱。这样的等待像买彩票,太玄乎。你为什么不自己给自己幸福。在你有运气得到男人所给的幸福之前,请你先有能力自己给自己幸福。
女人,你不要自甘堕落,你不要不自重。你以为你骄傲炫耀、肤浅地在屏幕上袒胸露乳吸引了多少观众的眼光,其实,在大众眼里你是个跳梁小丑,没有人会尊敬敬重你。
年轻的时候,你该有沉得住气的远见和毅力。看见周围的人谈恋爱了,看见谁又去KTV了,看见谁又在宿舍呆了几天上网。于是,你就沉不住气了,你怀疑现在努力是为了什么,为什么别人每天安逸舒适,而我却要孤寂、不断奋斗。特别是,当你还是一个女生?
一个阿姨,一次跟我说,她二十多岁的时候,她周围所有的人都结婚了,只是她一个人还没有。看着昔日同事抱着一岁多了的孩子出现在她的面前,她只有回家一个人默默地吞眼泪。正好这时候,她碰到了我叔叔,各方面都还合适,她就把自己给嫁了。本来她报了一个大学的进修班,可是结婚后,哪还有时间看书,生了孩子就更加不可能了。可和她一起的另一个女人不同。她26岁了,26岁,在一个小地方,在上个世纪,基本上可以跟一辈子嫁不出去划等号。但是,她一直沉着气,在周围女人的街坊里短,流言蜚语里面坚定地学习。不用说,这个故事的结尾,阿姨语重心长地告诉我,现在的那个女人,已经到上海去了,言谈举止,眼界视野远不是她能比及的。而这一切的开始都是那个大学的进修班。
母亲说,女人最幸福的一生是人生层次不断上升的一生。那些我见过的活的最悲惨的女人是那些年轻的时候众人照顾捧在手心,没能嫁一个好丈夫,青春转眼逝去后,年龄往上,自己在最黄金的时候却没有努力。那以后的人生就将一路往下,失去了最大也是仅有的资本,却究其一生也无法再适应不在众人手心的境遇和人生。40多岁了,在菜市场卖菜,蓬松的头发和暗黄的皮肤,埋头于讨价还价,甚至都不曾注意到身边熟人路过。曾经青春美貌又怎么样?这种女人是我见过的活的最惨的一种女人。
二十岁出头的女生,无疑是最美好最美丽的年华。但这时候的女生大多对自己的人生毫不清晰。我们不知道自己要的是什么,追求的是什么,怎么样才能得到幸福。的确,最美丽的时候如果在恋爱中度过,每天安逸舒适,那将是最美好的回忆之一,可是美好之后呢?
在你身边那个二十多岁一无所有,稚气未脱的男生。如果他选择了奋斗,那么假以时日,你们的眼界层次慢慢就分开了,当爱情的炙热褪去,他对能干成熟的女同事屡屡示好,你不要骂他没有良心。享受了你最美好的年华后却不给你幸福的以后,毕竟一生不是用道德谴责和良心来维系的。
如果他选择了和你一起玩乐,那人到中年,当你回首人生,与周围不同层次的人比较时,你是该后悔自己拖累了你的爱人,还是在听到莎士比亚“真正的爱情使人向上”时怀疑你们之间的是不是真正的爱情?那么也请你不要在以后柴米油盐经济拮据的时候,指着丈夫的脑门大骂他无能。你知道,这样的现状你至少有一半的功劳。
女生,不论什么时候,都请有自己的目标和努力。
我看到过许多女生,恋爱之前都有着勃勃的目标和追求,言谈举止大方大气,各种能力不让须眉。恋爱后我却只看到一个男生背后亦步亦趋的小女生,三句话就是她男朋友,今后的整个人生都提前绕着他打转。也许你会说,女人应该示弱,太过强势,男生会敬而远之。我想反驳的是,示弱的前提是你本来强大,而不是在恋爱的温室中煮着青蛙一样的越来越依赖。你不是金丝笼里的小鸟,到要飞的时候发现自己已经不适应外面残酷的世界。而且,如果一个女生有目标有梦想就叫强势的话,那我想说,这样的男生太弱了,他要用女生的弱势来维系他虚弱的自尊心。
我从来都鄙视那些殉情的男人,在我也许偏激的观点里,男人是该干大事业的,而不是完全沉溺于儿女情长。殉情这种文艺的事,对一个女人负责了,对其余所有人包括他自己都不负责。傅雷在他的家书中语重心长地对他的儿子说,不要因为女人或者是感情而舒缓了自己的事业心。这里面的男权思想我们暂且不论,他的说法也不无道理,君不见多少英雄难过美人关?
每一个成功的男人背后都有一个得力的女人。也许你不得力,但至少你不要成为他努力向上道路中的下拉
- Beanstalkd 一个高性能分布式内存队列系统发表时间: 2011-09-13来源: IT牛人博客聚合网站
之前在微博上调查过大家正在使用的分布式内存队列系统,反馈有Memcacheq,Fqueue, RabbitMQ, Beanstalkd以及linkedin的kafka。RabbitMQ使用比较广泛,Beanstalkd是后起之秀。Beanstalkd之于RabbitMQ,就好比Nginx之于Apache,Varnish之于Squid。后面在项目中使用Beanstalkd的过程中,更发现其简单、轻量级、高性能、易使用等特点,以及优先级、多队列、持久化、分布式容错、超时控制等特性。下面就简单介绍一下Beanstalkd,不足之处请大家指正。
———————————————–正文分割线————————————————-
设计思想
高性能离不开异步,异步离不开队列,而其内部都是Producer-Comsumer模式的原理。
图1 Producer-Comsumer模式
应用
Beanstalkd,一个高性能、轻量级的分布式内存队列系统,最初设计的目的是想通过后台异步执行耗时的任务来降低高容量Web应用系统的页面访问延迟,支持过有9.5 million用户的Facebook Causes应用。后来开源,现在有PostRank大规模部署和使用,每天处理百万级任务。Beanstalkd是典型的类Memcached设计,协议和使用方式都是同样的风格,所以使用过memcached的用户会觉得Beanstalkd似曾相识。
核心概念
Beanstalkd设计里面的核心概念:
- job
一个需要异步处理的任务,是Beanstalkd中的基本单元,需要放在一个tube中。
- tube
一个有名的任务队列,用来存储统一类型的job,是producer和consumer操作的对象。
- producer
Job的生产者,通过put命令来将一个job放到一个tube中。
- consumer
Job的消费者,通过reserve/release/bury/delete命令来获取job或改变job的状态。
Beanstalkd中一个job的生命周期如图2所示。一个job有READY, RESERVED, DELAYED, BURIED四种状态。当producer直接put一个job时,job就处于READY状态,等待consumer来处理,如果选择延迟put,job就先到DELAYED状态,等待时间过后才迁移到READY状态。consumer获取了当前READY的job后,该job的状态就迁移到RESERVED,这样其他的consumer就不能再操作该job。当consumer完成该job后,可以选择delete, release或者bury操作;delete之后,job从系统消亡,之后不能再获取;release操作可以重新把该job状态迁移回READY(也可以延迟该状态迁移操作),使其他的consumer可以继续获取和执行该job;有意思的是bury操作,可以把该job休眠,等到需要的时候,再将休眠的job kick回READY状态,也可以delete BURIED状态的job。正是有这些有趣的操作和状态,才可以基于此做出很多意思的应用,比如要实现一个循环队列,就可以将RESERVED状态的job休眠掉,等没有READY状态的job时再将BURIED状态的job一次性kick回READY状态。
图2 Beanstalkd中job的生命周期
特性
Beanstalkd基于的源码安装和使用很简单,在此略过。这里重点介绍一下其几个很nice的特性。
- 优先级
支持0到2**32的优先级,值越小,优先级越高,默认优先级为1024。
- 持久化
可以通过binlog将job及其状态记录到文件里面,在Beanstalkd下次启动时可以通过读取binlog来恢复之前的job及状态。
- 分布式容错
分布式设计和Memcached类似,beanstalkd各个server之间并不知道彼此的存在,都是通过client来实现分布式以及根据tube名称去特定server获取job。
- 超时控制
为了防止某个consumer长时间占用任务但不能处理的情况,Beanstalkd为reserve操作设置了timeout时间,如果该consumer不能在指定时间内完成job,job将被迁移回READY状态,供其他consumer执行。
不足
在使用中发现一个Beanstalkd尚无提供删除一个tube的操作,只能将tube的job依次删除,并让Beanstalkd来自动删除空tube。还有就是Beanstalkd不支持客户端认证机制(开发者将应用场景定位在局域网)。
后续工作
- 介绍Beanstalkd的命令和使用
- 翻译Beanstalkd协议
- 分析Beanstalkd源码
参考文献
http://kr.github.com/beanstalkd/
http://adam.heroku.com/past/2010/4/24/beanstalk_a_simple_and_fast_queueing_backend/
http://nubyonrails.com/articles/about-this-blog-beanstalk-messaging-queue
http://www.igvita.com/2010/05/20/scalable-work-queues-with-beanstalk/
由 IT 牛人博客聚合网站(udpwork.com) 聚合 | 评论: 0
- 查看全部推荐内容>>
- php的异步http请求类






最近评论