17 十月, 2008 01:52
文/Brad Sugars
任何公司面临的最大挑战之一就是定价。
这规律不仅适用于创业企业,也适用于成熟企业,尤其在那些利润率低、竞争激烈的行业。多数定价问题的共同核心是风险:价格设定太高的风险——可能会失去潜在的客户;价格设定太低的风险——利润减少了。
这种“定价矛盾”驱使多数企业家采取折扣策略。然而,多数情况下的风险可以通过获取更多的信息来消除。通常,你了解得越多,可能承受的风险就越少。从这个角度上说,定价的实质就是尽可能多地获得信息:你所在的市场、客户以及决定利润的企业内部数据。
生意上没有秘密,只有你还不知道的信息。说到定价问题,以下是在创业阶段避免犯错的7种方法。如果你能避免这些错误,就不仅能在竞争中领先,还能超越多数其他企业。
1.价格太低,总在减价:对有些公司来说,这并不是错误,这完全是战略,但并不是非常好的战略。价格总是走低可能会获得较高的营业收入,但也可能会损失你的利润底线,这关系到企业的生存问题。你需要平衡利润和价格的关系。
2.所有产品保持同样的毛利率:没有规则说所有的产品都需要同样的毛利率。事实上,周转慢的项目需要更高的毛利率。如果销量很大那么还可以用低些的毛利率。即使是这样,你还是应该寻找既能增加销量又能提高毛利率的方式。
3.不理解毛利与加价率的差别:毛利率总是基于销售价格。而加价率总是基于进货成本。我曾有一个客户不理解其中的差别,以100%的加价率报出了一系列产品的价格,然后又减掉50%达成销售。最终的结果?实际上这家商店基本上是以成本价销售。别犯同样的错误。
4.总是遗漏某些成本因素:为了正确地定价,需要识别每一项成本。即使是微不足道的项目,像信用卡处理费,通常也会增加每笔交易1%~2%的成本。其它的项目,像送货或运输成本,也能在不知不觉中增加成本。出售商品的成本对你的生存底线有着重大影响。
5.与竞争者采取类似策略:不要跟风竞争,多做点功课,发现你真正能为顾客提供的价值。然后根据这种价值给商品定价。这样做你就处于非常有利的位置,能抵御竞争保持价格。只要你有了自己的充足“理由”,你的报价就值这个价。
6.基于销售价格及利润百分比设定销售佣金:对于使用基于佣金制度的销售队伍的公司来说,这和毛利率/加价率之间的区别是类似的。采用何种基数来计算佣金将直接影响公司的利润。利润是惟一重要的数字。从营业收入中支付佣金意味着你将公司的部分利益让给了销售人员。
7.打折没有增加价值,只是减少了利润价值:打折10%,通常可能需要多销售50%的产品才能保持利润底线。在打折的游戏中成本也会增加,所以这样做的 公司差不多是将自己驱逐出商场。不要在交易中削减要价,你应该问自己是否有增加产品或服务价值的方法。这种“附加值”意味着你能“放弃”一些不能产生利润 的东西。正确实施后,它也能改善客户体验。好体验是获得回头客的关键,利润也会随之增加。
熟练处理所谓的“定价矛盾”,你就会对所在的领域得心应手。一旦你处理得好,你就会对自己产品和服务的价值有信心,而竞争对手则往往会急于放弃价格底线。 (译/梁晓平)
09 十月, 2008 16:24
【2】可以做技术,切不可沉湎于技术。千万不可一门心思钻研技术!给自己很大压力,如果你的心思全部放在这上面,那么注定你将成为孔乙己一类的人物!适可而止为之,因为技术只不过是你今后前途的支柱之一,而且还不是最大的支柱,除非你只愿意到老还是个工程师!
【3】 不要去做技术高手,只去做综合素质高手!在企业里混,我们时常瞧不起某人,说他“什么都不懂,凭啥拿那么多钱,凭啥升官!”这是普遍的典型的工程师的迂腐 之言。8051很牛吗?人家能上去必然有他的本事,而且是你没有的本事。你想想,老板搞经营那么多年,难道见识不如你这个新兵?人家或许善于管理,善于领 会老板意图,善于部门协调等等。因此务必培养自己多方面的能力,包括管理,亲和力,察言观色能力,攻关能力等,要成为综合素质的高手,则前途无量,否则只 能躲在角落看示波器!技术以外的技能才是更重要的本事!!从古到今,美国日本,一律如此!
【4】多交社会三教九流的朋友!不要只和工程师 交往,认为有共同语言,其实更重要的是和其他类人物交往,如果你希望有朝一日当老板或高层管理,那么你整日面对的就是这些人。了解他们的经历,思维习惯, 爱好,学习他们处理问题的模式,了解社会各个角落的现象和问题,这是以后发展的巨大的本钱,没有这些以后就会笨手笨脚,跌跌撞撞,遇到重重困难,交不少学 费,成功的概率大大降低!
【5】知识涉猎不一定专,但一定要广!多看看其他方面的书,金融,财会,进出口,税务,法律等等,为以后做一些积累,以后的用处会更大!会少交许多学费!!
【6】 抓住时机向技术管理或市场销售方面的转变!要想有前途就不能一直搞开发,适当时候要转变为管理或销售,前途会更大,以前搞技术也没有白搞,以后还用得着。 搞管理可以培养自己的领导能力,搞销售可以培养自己的市场概念和思维,同时为自己以后发展积累庞大的人 脉!应该说这才是前途的真正支柱。。?
【7】 逐渐克服自己的心里弱点和性格缺陷!多疑,敏感,天真(贬义,并不可爱),犹豫不决,胆怯,多虑,脸皮太薄,心不够黑,教条式思维。。。这些工程师普遍存 在的性格弱点必须改变!很难吗?只在床上想一想当然不可能,去帮朋友守一个月地摊,包准有效果,去实践,而不要只想!不克服这些缺点,一切不可能,甚至连 项目经理都当不好--尽管你可能技术不错!
【8】工作的同时要为以后做准备!建立自己的工作环境!及早为自己配置一个工作环境,装备电 脑,示波器(可以买个二手的),仿真器,编程器等,业余可以接点活,一方面接触市场,培养市场感觉,同时也积累资金,更重要的是准备自己的产品,咱搞技术 的没有钱,只有技术,技术的代表不是学历和证书,而是产品,拿出象样的产品,就可技术转让或与人合作搞企业!先把东西准备好,等待机会,否则,有了机会也 抓不住!
【9】要学会善于推销自己!不仅要能干,还要能说,能写,善于利用一切机会推销自己,树立自己的品牌形象,很必要!要创造条件让 别人了解自己,不然老板怎么知道你能干?外面的投资人怎么相信你?提早把自己推销出去,机会自然会来找你!搞个个人主页是个好注意!!特别是培养自己在行 业的名气,有了名气,高薪机会自不在话下,更重要的是有合作的机会...
29 九月, 2008 17:00
今天学到一点docbook经验:
(1)一个比较全面的docbook样式指引: DocBook XSL: The Complete Guide http://www.sagehill.net/docbookxsl/index.html
(2)如果图片过大,超出PDF右边界,有时候可以简单地设置图片居中让图片显示全:
<imagedata fileref="images/status/cs_status.png" align="center" />
或者更好的办法:
<imagedata fileref="images/api_jbpm.png" align="center" width="100%" scalefit="1" />
(3)自定义表格宽度: colwidth="1*"表示此column为标准长度1倍,colwidth="4*"表示此column为标准列长度的4倍:
- <title>状态变化表</title>
- <table>
- <tgroup cols="3">
- <colspec colnum="1" colname="col1" colwidth="4*" />
- <colspec colnum="2" colname="col2" colwidth="6*" />
- <colspec colnum="3" colname="col3" colwidth="1*" />
- <thead>
- <row>
29 九月, 2008 16:14
*DocBook DTD
*DocBook XSL 样式单
*XSLT处理程序
*XSL-FO处理程序
下面详细介绍各个工具的安装。
1.安装DocBook DTD
Docbook DTD可以到OASIS的网站上下载(http://www.oasis-open.org/docbook/xml/),在这里你可以找到zip格式的压缩包。目前的最新版本是4.2。
事实上可以不下载Docbook DTD。如果你的文档DTD声明这样写:
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
根 据这样的定义,大部分XML处理器能够从网络上获取DTD。这样做的好处是编辑的Docbook文档移植性好,可以在没有安装Docbook DTD的机器上使用。不过由于Docbook DTD比较庞大,通过网络获取DTD会影响处理速度,在低速网络或者网络比较糟糕的情况下,影响尤为显著。
如果选择使用本地DTD,文档的DTD引用应该这样写:
Linux:
<!DOCTYPE book SYSTEM "/usr/share/docbook-4.2/docbookx.dtd">
Windows:
<!DOCTYPE book SYSTEM "file:///C:/xml/docbook42/docbookx.dtd">
Docbook提供了一种方式,让用户可以使用相同的DTD声明,但可以在使用网络获取DTD和使用本地DTD之间切换,同时拥有两者的优势。这就是catalog文件的作用。典型的catalog的声明如下:
<catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog">
<group id="DocbookDTD" prefer="public">
<system
systemId="http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"
uri="file:///usr/share/xml/docbook42/docbookx.dtd"/>
</group>
</catalog>
这个声明把网络DTD映射到本地DTD。如果使用支持Catalog的XSLT Processor,它首先会查找本地文件,如果本地文件不存在,再查找网络。
2.安装Docbook XSL样式单
在http://docbook.sourceforge.net上可以下载到Docbook XSL样式单,目前最新的版本是1.67.2。
解压之后,有几个比较主要的目录:
*common - 包含的是公用的模块,诸如语言之类的文件都在这里。
*extensions - 针对特定的XSLT Processor编写的扩展代码。
*fo - 生成XSL-FO文件所需的XSL样式单。
*html - 生成HTML文件所需的XSL样式单。
*images - 生成文档时所需要的图片。
*doc - 有关XSL样式单的文档,同样是Docbook文档。
其他还有像htmlhelp之类的目录,但不是生成HTML或XSL-FO所必须的。
3.安装XSLT Processor
目前有许多免费的XSLT Processor,最常用的是
*Saxon - 使用Java实现,http://saxon.sourceforge.net/。
*Xalan - 有Java和C++版本,http://xml.apache.org/xalan-j/index.html。
*xsltproc - 使用C实现,是最快的处理程序,http://xmlsoft.org/XSLT/
因为Saxon和Xalan都有Java版本,所以按照一般的Java程序的安装方式安装即可。下面介绍xsltproc的安装,因为它速度快,是我比较喜欢的处理程序。
如果你使用windows平台,那么你有两个方法可选:
*第一,直接下载为windows平台预编译的版本,可以在
ftp://ftp.zlatkovic.com/libxml/
上找到。你需要下载libxml, libxslt, 和iconv,它们都是zip格式,解压之后,在环境变量PATH中添加xsltproc.exe和.dll文件的路径。
如果你不想编辑环境变量,一个简单的办法是把下面这些文件复制到C:WindowsSystem32:
libxslt.dll
libxml2.dll
libexslt.dll
iconv.dll
xsltproc.exe
这样在命令行就可以直接找到这些文件了。完成之后,运行
xsltproc -version
打印出版本号则表明完成安装。
*第二,在Cygwin下安装,这是我选择使用的方式。Cygwin是一个在Windows下模拟Linux Shell的应用程序。如果你喜欢以Linux命令的方式来使用xsltproc,可以到
http://www.cygwin.com/
下载Cygwin安装程序。Cygwin的是通过网络安装的,首先你从它提供的包列表中选择libxslt,然后安装程序会根据依赖关系自动选择libxml2,确定之后,安装程序下载并安装xsltproc。完成安装之后,你就可以运行
xsltproc -version
来检查是否安装成功。
*第三,如果使用Linux,很有可能系统已经安装了xsltproc。运行
xsltproc -version
检查一下是否已经安装。如果运行命令失败,或者版本太老,那么访问下面两个URL获取最新的RPM包:
http://rpmfind.net/linux/rpm2html/search.php?query=libxml2
http://rpmfind.net/linux/rpm2html/search.php?query=libxslt
然后切换到root权限,安装新的包:
rpm -Uv libxml2-2.6.17-2.i386.rpm
rpm -Uv libxslt-1.1.12-4.i386.rpm
完成之后,就可以运行
xsltproc -version
检查安装是否完成。
安装之后,就可以使用xsltproc来生成HTML或者XSL-FO文件。
譬如,下面是根据Docbook文档生成HTML的例子:
xsltproc --output myfile.html docbook-xsl/html/docbook.xsl myfile.xml
或者根据docbook文档生成XSL-FO文档的例子:
xsltproc --output myfile.fo docbook-xsl/fo/docbook.xsl myfile.xml
在http://xmlsoft.org/XSLT/xsltproc2.html上列出了所有xsltproc的命令行参数,或者直接运行
xsltproc也会打印出参数列表。
如果你只要发布HTML文档,那么到此为止。如果你还想发布PDF或是PS文档,那么需要安装XSL-FO处理程序。
4. 安装XSL-FO处理程序
XSL-FO处理程序根据XSLT处理程序生成的XSL-FO文件生成PDF或者PS文件。目前可供选择的XSL-FO处理程序远不如XSLT处理程序那么多,这是因为:
a. XSL-FO标准比XSLT标准的制订晚两年;
b.XSL-FO标准及其庞大而复杂,该标准的作者也发现其实现上的难度,从而将该标准分为基本、扩展和完整三个级别。
现在可用的免费的XSL-FO处理程序有:
*FOP - 来自Apache XML项目(http://xml.apache.org/fop/)。目前最新的版本是0.20.5,还在开发当中,还有很多特性不支持,不过已经可以满足一般的使用。
*PassiveTeX - 来自Sebastian Rahtz (http://www.tei-c.org.uk/Software/passivetex/)一款基于TeX的XSL-FO处理程序。同样也在开发中,较FOP要复杂的多。
另外有一些商业产品可供选择,可能生成的文档质量要比开源代码好,譬如:
*XEP(http://www.renderx.com)
*XSL Formatter(http://www.antennahouse.com)
下面介绍如何安装FOP。
4.1.首先需要安装JDK,这个不必多说。
4.2. 到http://www.apache.org/dyn/closer.cgi/xml/fop/下载FOP,可以选择tar或者zip压缩包。下载之后解压到本地。
4.3. 下载图形代码库。FOP自己不支持PNG之类的图片,如果在你的文档里会涉及到图片,那么需要下载额外的代码库。可以选择JAI(http://java.sun.com/products/java-media/jai/current.html),或者Jimi(http://java.sun.com/products/jimi/)。0.20.5之前的版本只能使用Jimi。下载之后,将jai_core.jar和jai_codec.jar(JAI),或者JimiProClasses.jar(Jimi)复制到FOP安装目录的lib目录下,然后在fop.bat(Windows平台)中添加
set LOCALCLASSPATH=%LOCALCLASSPATH%;%LIBDIR%jai_core.jar
set LOCALCLASSPATH=%LOCALCLASSPATH%;%LIBDIR%jai_codec.jar
或是
set LOCALCLASSPATH=%LOCALCLASSPATH%;%LIBDIR%JimiProClasses.zip
如果使用fop.sh(Linux平台),会自动搜索。
4.4. 添加扩展代码。如果Docbook XSL样式单有针对FOP的扩展代码(目前没有),像上面一样把它们添加到FOP安装目录下lib目录。
现在就可以使用FOP来生成PDF文档了。FOP提供两个脚本fop.bat(Windows平台)和fop.sh(Unix和Linux平台)以方便使用。生成PDF的命令行如下:
Linux或Unix:
fop.sh -xsl /docbook-xsl/fo/docbook.xsl -xml myfile.xml -pdf myfile.pdf
Windows:
fop.bat -xsl /docbook-xsl/fo/docbook.xsl -xml myfile.xml -pdf myfile.pdf
在处理过程中,可能会提示某些属性不支持或尚未实现,不用理会这些提示,因为FOP仍处于开发中,这并不影响生成PDF文档。
到此,一个Docbook发布系统配置完成,并可以用来发布文档了。你完全可以在Linux上编写任务,通过该系统自动发布技术文档。
19 九月, 2008 03:00
2 quilt
我们自己的项目可以用cvs或svn管理全部代码。但有时我们要使用其他开发者维护的项目。我们需要修改一些文件, 但又不能直接向版本管理工具提交代码。自己用版本管理工具重建整个项目是不合适的,因为大多数代码都是别人维护的,例如Linux内核。我们只是想管理好 自己的补丁。这时可以使用quilt。
2.1 基本概念
quilt是一个帮助我们管理补丁的程序。quilt的命令格式类似于cvs:
quilt 子命令 [参数]
0.46版的quilt有29个子命令。
掌握quilt的关键是了解使用quilt的流程。使用quilt时,我们会在一个完整的源代码树里工作。只要我们 在源代码树里使用了quilt命令,quilt就会在源代码树的根目录建立两个特殊目录:patches和.pc。quilt在patches目录保存它 管理的所有补丁。quilt用.pc目录保存自己的内部工作状态,用户不需要了解这个目录。
patches/series文件记录了quilt当前管理的补丁。补丁按照加入的顺序排列,早加入的补丁在前。quilt用堆栈的概念管理补丁的应用。

我们在应用补丁A前,必须先应用所有早于补丁A的补丁。所以,patches/series中的补丁总是从上向下应 用。例如:上图中,补丁1到补丁5是已经应用的补丁。我们可以将已应用的补丁想象成一个向下生长的堆栈,栈顶就是已应用的最新补丁。应用补丁就是将补丁入 栈,撤销补丁就是将补丁出栈。
我们在源代码树中作任何修改前,必须用"quilt add"命令将要修改的文件与一个补丁联系起来。在完成修改后,用"quilt refresh"命令将修改保存到已联系的补丁。下面我们通过一篇流程攻略来认识一下quilt的命令。
2.2 导入补丁
我们把 old-prj.tar.bz2 想象成Linux内核,我们把它解压后,进入代码树的根目录:
$ mkdir qtest; cd qtest; tar xvjf ../old-prj.tar.bz2; mv old-prj prj; cd prj
在修改代码前,我们通常要先打上官方补丁。在quilt中,可以用import命令导入补丁:
$ quilt import ../../prj.diff
Importing patch ../../prj.diff (stored as prj.diff)
执行improt命令后, prj 目录会多出一个叫 patches 的子目录:
$ find patches/ -type f
patches/prj.diff
patches/series
quilt在这个目录存放所有补丁和前面介绍的series文件。quilt的大多数命令都可以在代码树的任意子目录运行,不一定要从根目录运行。我们可以用applied命令查询当前已应用的补丁。
$ quilt applied
No patches applied
目前还没有应用任何补丁。unapplied命令查询当前还没有应用的补丁,top命令查询栈顶补丁,即已应用的最新补丁:
$ quilt unapplied
prj.diff
$ quilt top
No patches applied
我们可以使用push命令应用补丁,例如:
$ quilt push -a
Applying patch prj.diff
patching file src/drv/drv1.h
patching file src/sys/sys1.c
patching file src/sys/sys1.h
patching file src/usr/usr1.c
patching file src/usr/usr1.h
Now at patch prj.diff
push的"-a"参数表示应用所有补丁。在使用push命令后,prj 目录会多了一个叫.pc的隐含子目录。quilt用这个目录保存内部状态,用户不需要了解这个目录。应用补丁后,我们再使用applied、unapplied和top命令查看:
$ quilt applied
prj.diff
$ quilt unapplied
File series fully applied, ends at patch prj.diff
$ quilt top
prj.diff
2.3 修改文件
我们必须将对源代码树所作的任何改动都和一个补丁联系起来。add命令将文件的当前状态与补丁联系起来。add命令的格式为:
quilt add [-P 补丁名] 文件名
如果未指定补丁名,文件就与栈顶补丁联系起来。目前,我们的栈顶补丁是官方补丁。我们不想修改这个补丁,可以用new命令新建一个补丁:
$ quilt new drv_p1.diff
Patch drv_p1.diff is now on top
$ quilt top
drv_p1.diff
$ quilt applied
prj.diff
drv_p1.diff
$ quilt unapplied
File series fully applied, ends at patch drv_p1.diff
然后用add命令向栈顶补丁添加一个准备修改的文件:
$ cd src/drv; quilt add drv2.h
File src/drv/drv2.h added to patch drv_p1.diff
add命令为指定补丁保存了指定文件的当前快照,当我们执行refresh命令时,quilt就会检查文件 的变化,将差异保存到指定补丁中。使用"quilt diff -z [-P 补丁名] [文件名]"可以查看指定补丁指定文件的当前改动。省略-P参数表示查看当前补丁的改动,省略文件名表示查看所有改动。我们修改drv2.h后,执行 diff命令:
$ quilt diff -z
Index: prj/src/drv/drv2.h
===================================================================
--- prj.orig/src/drv/drv2.h 2008-03-02 13:37:34.000000000 +0800
+++ prj/src/drv/drv2.h 2008-03-02 13:38:53.000000000 +0800
@@ -1,7 +1,7 @@
-#ifndef APP1_H
-#define APP1_H
+#ifndef DRV2_H
+#define DRV2_H
-#include "def1.h"+#include "def2.h" #endif
只要文件已经与我们希望保存改动的补丁联系过了,我们就可以多次修改文件。使用"quilt files [补丁名]"命令可以查看与指定补丁关联的文件。使用"quilt files -val"可以查看所有补丁联系的所有文件。"-v"参数表示更友好的显示,"-a"参数表示显示所有补丁,"-l"参数显示补丁名。例如:
$ quilt files
src/drv/drv2.h
$ quilt files -val
[prj.diff] src/drv/drv1.h
[prj.diff] src/sys/sys1.c
[prj.diff] src/sys/sys1.h
[prj.diff] src/usr/usr1.c
[prj.diff] src/usr/usr1.h
[drv_p1.diff] src/drv/drv2.h
"quilt refresh [补丁名]"刷新补丁,即将指定补丁的文件变化保存到补丁。省略文件名表示刷新栈顶补丁。我们refresh后,查看补丁文件:
$ quilt refresh
Refreshed patch drv_p1.diff
$ cat ../../patches/drv_p1.diff
Index: prj/src/drv/drv2.h
===================================================================
--- prj.orig/src/drv/drv2.h 2008-03-02 12:42:21.000000000 +0800
+++ prj/src/drv/drv2.h 2008-03-02 12:46:25.000000000 +0800
@@ -1,7 +1,7 @@
-#ifndef APP1_H
-#define APP1_H
+#ifndef DRV2_H
+#define DRV2_H
-#include "def1.h"
+#include "def2.h"
#endif
"quilt diff -z"命令不会显示已经保存的差异。"quilt diff"显示所有的差异,不管是否保存过。
2.4 再做几个补丁
在增加文件前,我们要先将准备增加的文件与补丁联系起来。我们新建一个补丁,然后新增两个文件src/applet/applet1.h和src/applet/applet1.c。
$ cd ..; quilt new more_p1.diff
Patch more_p1.diff is now on top
$ quilt add applet/applet.c
File src/applet/applet.c added to patch more_p1.diff
$ quilt add applet/applet.1
File src/applet/applet.1 added to patch more_p1.diff
看看我们增加的文件:
$ quilt files
src/applet/applet.1
src/applet/applet.c
哎呀,文件名写错了。我们可以用"remove"命令从补丁中删除关联文件:
$ quilt remove applet/applet.1
rm: remove write-protected regular empty file `.pc/more_p1.diff/src/applet/applet.1'? y
File src/applet/applet.1 removed from patch more_p1.diff
$ quilt remove applet/applet.c
rm: remove write-protected regular empty file `.pc/more_p1.diff/src/applet/applet.c'? y
File src/applet/applet.c removed from patch more_p1.diff
$ quilt files
$ quilt add applet/applet1.h
File src/applet/applet1.h added to patch more_p1.diff
$ quilt add applet/applet1.c
File src/applet/applet1.c added to patch more_p1.diff
$ quilt files
src/applet/applet1.c
src/applet/applet1.h
好了,现在可以创建新文件:
$ mkdir applet
$ echo -e "#ifndef APPLET1_Hn#define APPLET1_Hn#include "def1.h"n#endif">applet/applet1.h
$ echo -e "#include "applet1.h"">applet/applet1.c
$ quilt refresh more_p1.diff
Refreshed patch more_p1.diff
刷新补丁后,我们再修改文件drv2.h。修改前一定要先将文件与准备保存改动的补丁联系起来:
$ quilt add drv/drv2.h
File src/drv/drv2.h added to patch more_p1.diff
$ vi drv/drv2.h
$ quilt diff -z drv/drv2.h
Index: prj/src/drv/drv2.h
===================================================================
--- prj.orig/src/drv/drv2.h 2008-03-02 14:19:35.000000000 +0800
+++ prj/src/drv/drv2.h 2008-03-02 14:31:28.000000000 +0800
@@ -1,7 +1,7 @@
#ifndef DRV2_H
#define DRV2_H
-#include "def2.h"
+#include "def1.h"
#endif
我们再新建一个补丁,然后删除两个文件。删除文件前也要先为文件建立关联:
$ quilt new more_p2.diff
Patch more_p2.diff is now on top
$ quilt add app/*
File src/app/app1.c added to patch more_p2.diff
File src/app/app1.h added to patch more_p2.diff
File src/app/app2.c added to patch more_p2.diff
File src/app/app2.h added to patch more_p2.diff
$ rm -rf app
$ quilt refresh
Refreshed patch more_p2.diff
我们再修改applet/applet1.h:
$ quilt edit applet/applet1.h
File src/applet/applet1.h added to patch more_p2.diff
$ quilt refresh
Refreshed patch more_p2.diff
"quilt edit"在调用"quilt add"后自动启动编辑器。用refresh命令刷新补丁。
对了,前面为more_p1.diff修改drv2.h后还没有刷新呢。我们查看修改并刷新:
$ quilt diff -z -P more_p1.diff
Index: prj/src/drv/drv2.h
===================================================================
--- prj.orig/src/drv/drv2.h 2008-03-02 14:19:35.000000000 +0800
+++ prj/src/drv/drv2.h 2008-03-02 14:31:28.000000000 +0800
@@ -1,7 +1,7 @@
#ifndef DRV2_H
#define DRV2_H
-#include "def2.h"
+#include "def1.h"
#endif
Warning: more recent patches modify files in patch more_p1.diff
$ quilt refresh more_p1.diff
More recent patches modify files in patch more_p1.diff. Enforce refresh with -f.
$ quilt refresh -f more_p1.diff
Refreshed patch more_p1.diff
quilt会抱怨更新的补丁修改了补丁more_p1.diff的文件。这是在说more_p2.diff修改了applet1.h。我们知道这和我们要刷新的drv2.h没关系,所以可以用-f参数强制刷新。
2.5 管理补丁
series命令可以查看series文件中的补丁:
$ quilt series
prj.diff
drv_p1.diff
more_p1.diff
more_p2.diff
"quilt patches 文件名"显示修改了指定文件的所有补丁,例如:
$ quilt patches drv/drv2.h
drv_p1.diff
more_p1.diff
"quilt annotate 文件名"显示指定文件的修改情况,它会指出哪个补丁修改了哪一行。例如:
$ quilt annotate drv/drv2.h
1 #ifndef DRV2_H
1 #define DRV2_H
2 #include "def1.h"
#endif
1 drv_p1.diff
2 more_p1.diff
我们可以使用push和pop命令应用补丁或撤销补丁,例如:
$ quilt pop -a
Removing patch more_p2.diff
Restoring src/app/app1.c
Restoring src/app/app2.c
Restoring src/app/app2.h
Restoring src/app/app1.h
Restoring src/applet/applet1.h
Removing patch more_p1.diff
Restoring src/drv/drv2.h
Removing src/applet/applet1.h
Removing src/applet/applet1.c
Removing patch drv_p1.diff
Restoring src/drv/drv2.h
Removing patch prj.diff
Restoring src/sys/sys1.c
Restoring src/sys/sys1.h
Restoring src/drv/drv1.h
Removing src/usr/usr1.c
Removing src/usr/usr1.h
No patches applied
$ quilt top
No patches applied
$ quilt next
prj.diff
$ quilt previous
No patches applied
"quilt pop -a"撤销所有补丁。top命令显示栈顶命令,即当前应用的最新的补丁。next命令显示下一个可以应用的补丁。previous显示上一条应用过的补丁。"push 补丁A"将从上到下依次应用所有早于补丁A的补丁,最后应用补丁A。例如:
$ quilt push more_p1.diff
Applying patch prj.diff
patching file src/drv/drv1.h
patching file src/sys/sys1.c
patching file src/sys/sys1.h
patching file src/usr/usr1.c
patching file src/usr/usr1.h
Applying patch drv_p1.diff
patching file src/drv/drv2.h
Applying patch more_p1.diff
patching file src/applet/applet1.c
patching file src/applet/applet1.h
patching file src/drv/drv2.h
Now at patch more_p1.diff
$ quilt top
more_p1.diff
$ quilt next
more_p2.diff
$ quilt previous
drv_p1.diff
"quilt push -a"应用所有补丁:
$ quilt push -a
Applying patch more_p2.diff
patching file src/app/app1.c
patching file src/app/app1.h
patching file src/app/app2.c
patching file src/app/app2.h
patching file src/applet/applet1.h
Now at patch more_p2.diff
"quilt graph -all"可以为栈顶补丁的依赖关系生成dot文件。Graphviz的dot可以根据dot文件产生图片,例如:
$ quilt graph --all > ../../more_p2.dot
$ cd ../..; dot -Tpng more_p2.dot -o more_p2.png

2.6 发布补丁
只要将patches目录打包发布就可以了。例如:
$ cd prj; tar cvjf prj-0.1-patches.tar.bz2 patches; mv prj-0.1-patches.tar.bz2 ../..
用户先下载、解压补丁包对应的源代码树:
$ cd ../..; mkdir user; cd user; tar xvjf ../old-prj.tar.bz2; mv old-prj/ prj
然后下载、解压补丁:
$ cd ../..; tar xvjf prj-0.1-patches.tar.bz2; cd user/prj
最后把补丁目录链接到源代码树的patches目录,然后应用所有补丁:
$ ln -sfn ../../patches/ patches
$ quilt push -a
Applying patch prj.diff
patching file src/drv/drv1.h
patching file src/sys/sys1.c
patching file src/sys/sys1.h
patching file src/usr/usr1.c
patching file src/usr/usr1.h Applying patch drv_p1.diff
patching file src/drv/drv2.h
Applying patch more_p1.diff
patching file src/applet/applet1.c
patching file src/applet/applet1.h
patching file src/drv/drv2.h
Applying patch more_p2.diff
patching file src/app/app1.c
patching file src/app/app1.h
patching file src/app/app2.c
patching file src/app/app2.h
patching file src/applet/applet1.h
Now at patch more_p2.diff
3 结束语
在上面的流程攻略中,我们演示了19个quilt命令:add, annotate, applied, diff, edit, files, graph, import, new, next, patches, pop, previous, push, refresh, remove, series, top, unapplied。
本次Linux之旅到此结束,欢迎您再次参加Linux之旅,一起探索浩瀚的Linux世界。
19 九月, 2008 02:56
diff和patch是在Linux环境为源代码制作和应用补丁的标准工具。diff可以比较文件或目录的差异,并 将差异记录到补丁文件。patch可以将补丁文件应用到源代码上。quilt也是一个制作和应用补丁的工具,它适合于管理较多补丁。quilt有自己的特 有的工作方式。本文通过简单的例子介绍这三个常用的工具。
0 示例工程
我们先准备一个用来做实验的工程,它包含若干子目录和文件。可以用find命令列出文件清单:
$ find old-prj/ -type f
old-prj/inc/def1.h
old-prj/inc/def2.h
old-prj/src/sys/sys1.c
old-prj/src/sys/sys1.h
old-prj/src/app/app1.c
old-prj/src/app/app2.c
old-prj/src/app/app2.h
old-prj/src/app/app1.h
old-prj/src/drv/drv1.h
old-prj/src/drv/drv2.c
old-prj/src/drv/drv1.c
old-prj/src/drv/drv2.h
old-prj/build/Makefile
find命令的"-type f"参数选择普通文件,可以省略掉目录。希望自己操作的读者可以下载这个示例工程。
1 diff和patch
1.1 比较一个文件
将old-prj.tar.bz2放到我们的工作目录,然后建立一个子目录,进入后解压示例工程:
$ mkdir test1; cd test1; tar xvjf ../old-prj.tar.bz2
用分号分隔多个命令可以节省篇幅。将old-prj复制到new-prj:
$ cp -a old-prj/ new-prj
让我们编辑一个文件。src/drv/drv1.h的内容本来是:
$ cat -n old-prj/src/drv/drv1.h
1 #ifndef DRV1_H
2 #define DRV1_H
3
4 #include "def1.h"
5
6 typedef struct {
7 int p1;
8 int p2;
9 int p3;
10 } App1;
11
12 void do_app1(void);
13
14 #endif
cat命令的"-n"参数可以增加行号。我们用vi将它修改成:
$ cat -n new-prj/src/drv/drv1.h
1 #ifndef DRV1_H
2 #define DRV1_H
3
4 #include "def1.h"
5
6 typedef struct {
7 int a;
8 int b;
9 } App1;
10
11 void do_app1(void);
12
13 #endif
现在可以用diff命令比较文件了:
$ diff -u old-prj/src/drv/drv1.h new-prj/src/drv/drv1.h
--- old-prj/src/drv/drv1.h 2008-03-01 12:59:46.000000000 +0800
+++ new-prj/src/drv/drv1.h 2008-03-01 13:07:14.000000000 +0800
@@ -4,9 +4,8 @@
#include "def1.h"
typedef struct {
- int p1;
- int p2;
- int p3;
+ int a;
+ int b;
} App1;
void do_app1(void);
diff程序按行比较文本文件。比较文件的diff命令格式是:
$ diff -u 旧文件 新文件
"-u"参数指定diff命令使用 unified 格式,这是一种最常用的格式,我们来看看它的含义。
1.2 diff的 unified 格式
以"---"开头的行是旧文件信息,以"+++"开头的行是新文件信息:
--- old-prj/src/drv/drv1.h 2008-03-01 12:59:46.000000000 +0800
+++ new-prj/src/drv/drv1.h 2008-03-01 13:07:14.000000000 +0800
unified 格式默认在变化部分的前后各显示三行上下文。在上例中,旧文件的7、8、9行被替换成新文件的7、8行。旧文件的变化部分是7-9行,前后多显示3行,因 此显示4-12行。新文件的变化部分是7-8行,前后多显示3行,因此显示4-11行。以"@@"包围的行指示补丁的范围:
@@ -4,9 +4,8 @@
'-4,9'中,'-'表示旧文件,'4,9'表示从第4行开始,显示9行,即显示4-12行。'+4,8' 中,'+'表示新文件,'4,8'表示从第4行开始,显示8行,即显示4-11行。"@@"行之后是上下文和变化的文本,其中'-'开头的行是旧文件特有 的,'+'开头的行是新文件特有的,其它行是两个文件都有的,即补丁的上下文。例如:
#include "def1.h"
typedef struct {
- int p1;
- int p2;
- int p3;
+ int a;
+ int b;
} App1;
void do_app1(void);
1.3 制作和应用补丁
所谓制作补丁就是diff的输出重定向到一个文件,这个文件就是补丁文件。例如:
$ diff -u old-prj/src/drv/drv1.h new-prj/src/drv/drv1.h>../drv1.diff
我们将old-prj解压到另一个目录,准备应用这个补丁:
$ cd ..; mkdir test2; cd test2; tar xvjf ../old-prj.tar.bz2; mv old-prj myprj; cd myprj
在真实场景中,test2目录通常是在用户2的电脑上。用户2可能不使用 old-prj 作为第一级目录的名字。例如:用户1的第一级目录名是 linux-2.6.23.14, 用户2的第一级目录名是linux。所以我们将 old-prj 改为 myprj 以模拟这种情况。
我们在 myprj 目录使用patch命令应用补丁:
$ patch -p1 < ../../drv1.diff
patching file src/drv/drv1.h
patch命令行中为什么没有出现要打补丁的文件?这是因为patch命令可以使用补丁文件中的文件信息:
--- old-prj/src/drv/drv1.h 2008-03-01 12:59:46.000000000 +0800
"-pn"参数(上例中n=1)中的n表示要从补丁文件的文件路径中去掉几层目录,可以理解为去掉几个'/'。例 如:p1表示去掉一层目录,"old-prj/src/drv/drv1.h"去掉一层就成为"src/drv/drv1.h"。patch命令在 myprj 目录找到"src/drv/drv1.h"后应用补丁。
我们通常都在代码树的上一层目录制作补丁,在代码树的根目录应用补丁。因此,最常用的patch命令格式是:
$ patch -p1 < 补丁文件
1.4 比较目录
我们回到test1目录,再对 new_prj 做一些改动。这次我们删除掉src/sys目录及其中的文件。再建立src/usr目录,并在该目录增加两个文件usr1.h和usr1.c。
$ cd ../../test1; rm -rf new-prj/src/sys; mkdir new-prj/src/usr
$ echo -e "#ifndef USR1_Hn#define USR1_Hn#include "def1.h"n#endif">new-prj/src/usr/usr1.h
$ echo -e "#include "usr1.h"">new-prj/src/usr/usr1.c
echo命令的"-e"参数打开对转义符的支持,bash默认是不支持转义符的。
现在我们比较目录并制作补丁:
$ diff -Nur old-prj/ new-prj/ > ../prj.diff
读者可以cat这个补丁文件的内容。根据前面的介绍,读者应该能看懂补丁文件了吧。
比较目录的常用命令是:
$ diff -Nur 旧目录 新目录 > 补丁文件
或
$ diff -Naur 旧目录 新目录 > 补丁文件
"-u"参数前面已经介绍过了。"-N"参数将不存在的文件当作空文件。如果没有这个参数,补丁就不会包含孤儿文件(即另一方没有的文件)。"-r"参数表示比较子目录。"-a"参数表示将所有文件当作文本文件。
我们再准备一个目录来应用补丁:
$ cd ..; mkdir test3; cd test3; tar xvjf ../old-prj.tar.bz2; mv old-prj myprj; cd myprj
在源代码树的根目录应用补丁:
$ patch -p1 < ../../prj.diff
patching file src/drv/drv1.h
patching file src/sys/sys1.c
patching file src/sys/sys1.h
patching file src/usr/usr1.c
patching file src/usr/usr1.h
好了,读者可以用"diff -Nur"比较一下"test1/new_prj"和"test3/myprj",没有输出就表示完全相同。
$ cd ../..; diff -Nur test1/new-prj test3/myprj
1.5 很多的补丁...
一个大项目可能有不同开发者提供很多补丁。这些补丁可能还存在依赖关系,例如补丁B必须打在补丁A上。我们当然可以凭着程序员的“心细如发”去管理好这些补丁,不过有一个叫quilt的工具可以使我们轻松一些。当然,即使有工具的帮助,细心和认真也是必需的。
附录
为了简单起见,前面只介绍了一个"diff -Nur 老目录 新目录"的用法。有时候,新目录里只放了修改过的文件。这时可以不使用-N参数以忽略孤儿文件,即"diff -ur 老目录 新目录"。diff会输出孤儿文件的提示,我们可以删除或保留这些提示,它们对patch没有影响。
使用diff时可以用--exclude排除文件和目录,例如:
diff -ur -exclude=.* --exclude=CVS prj_old prj_new 上例排除了源代码树中以'.'开头的文件和所有CVS目录。其实对于CVS项目,可以直接在源代码树根目录中执行:
cvs diff -u3 > 补丁文件名u3表示输出3行上下文的unified 格式。打补丁时在源代码树根目录中执行:
patch -p0 < 补丁文件名 "cvs diff"会自动忽略CVS项目外的文件。通过CVS的tag和补丁文件,我们可以方便地保存工作快照。
16 九月, 2008 18:58
防止webshell运行cmd命令
这里讲述一个简单的方法,那就是把默认的CMD名称改成其他任何复杂名称。自己需要使用的时候可以更改回来。这个是最简单的,当然也存 在安全隐患,当恶意用户上传一个CMD到任意目录下,就可以执行了,这里可以找到很安全的设置方法,比如设置CMD 运行的权限,把所有权限都删除掉,当使用的时候在把权限加上去,wscript.shell 相信大家都比较了解它,Wscript.Shell可以调用系统内核运行DOS基本命令,这里可以通过修改注册表,将此组件改名或删除(建议改名),方法 如下:
HKEY_CLASSES_ROOTWscript.Shell
HKEY_CLASSES_ROOTWscript.Shell.1
这个样子几个简单的步骤就可以达到webshell无法运行cmd命令的效果。
修改系统默认文件夹漏洞
也就是最常见的 C:Documents and SettingsAll Users,虽然大部分人都知道这里可以进程上传,但管理员一般很少注意到这个目录的权限问题,从而产生安全隐患。在这里我们吧此文件夹的阅读权限设置只 允许管理员用户和system用户完全控制,其他的屏蔽掉即可。
Serv-U提权
Serv-U 作为一款精典的FTP服务器软件,一直被大部分管理员所使用,它简单的安装和配置以及强大的管理功能的人性化也一直被管理员们称颂。但是随着使用者越来越 多,该软件的安全问题也逐渐显露出来。Serv-U 提升权限 ASP版 6.2 ,我们怎么能够防止它进行提权呢?那么只需更改默认端口和默认FTP软件的 账户和密码,默认管理员:LocalAdministrator,默认密码:#l@$ak#.lk;0@P,其修改方法如下:
首先利用Ultraedit修改文件ServUDaemon.exe和ServUAdmin.exe两个程序,将默认密码修改成同等长 度的其它字符,然后用Ultraedit打开ServUAdmin.exe查找最后一个B6AB(43958的16进制),替换成自定义的端口比如 3930(12345)即可。
当然也希望各各管理员能够及时更新自己的Serv-U 因为这个漏洞只有一些Serv-U的老版本存在的漏洞!最新的Serv-U已经不存在此漏洞和加入了 管理员密码的功能!让我们使用起来更加安全!
安全设置IIS用户
重新建立一个用户然后把用户所在组删除,让其独立,然后在IIS中指派给其网站,然后在网站跟目录指派其用户读取、运行,即可,此时即使WEBSHELL上传成功也只能在网站文件夹内活动,涉及不到其他文件夹。
总结:以上介绍主要是一些常规的防范方式,不同的环境有着不同的设置,如果计算机中安装了其他软件,那就需要相对应的设置了。
01 九月, 2008 20:52
31 八月, 2008 19:10
在开始编写插件之前,应该先熟悉lighttpd中两个基本数据结构以及他们所在文件:
* buffer (buffer.c)
* array (array.c)
* global structures (base.h)
接下来需要阅读:
* http://www.lighttpd.net/documentation/state.html (在lighttpd的'doc/'目录下可以找到,名字为state.txt)
* http://www.lighttpd.net/documentation/plugins.html (在lighttod的'doc/'目录下可以找到,名字为plugins.txt)
框架
确保你的系统中安装
* automake 1.8.x or higher
* autoconf 2.57 or higher
* libtool 1.5.x or higher
当要编写自己的插件,可以从修改mod_skeleton.c开始,mod_skeleton.c包括一个插件的基本架构,它是mod_access模块的一个拷贝,mod_access模块非常简单,以至于把mod_access模块作为演示插件如何工作的基本向导。
如何把mod_skeleton变成一个自己的插件,你需要用编辑器打开这个文件,把文件里面的 'skeleton'替换成你自己的插件名‘counter’。
$ cd src/
$ cp mod_skeleton.c mod_counter.c
$ vi mod_counter.c
:%s/skeleton/counter/g
把下面代码添加到src/Makefile.am,告诉编译器我们需要创建新的插件:
lib_LTLIBRARIES += mod_counter.la
mod_counter_la_SOURCES = mod_counter.c
mod_counter_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
mod_counter_la_LIBADD = $(common_libadd)
默认情况下,生成系统将假定你是一个普通用户,只是想编译现有代码。所以更改makefile.am文件后不会产生新的makefiles 。你需要手工执行以下命令:
$ ./configure --enable-maintainer-mode ...
无论何时更新Makefile.am,比如增加新的依赖库,执行上面命令都会自动重建完整的Makefile文件.
开发过程中,如果你希望通过前缀安装所有的文件来避免真实安装,可以:
$ ./configure --enable-maintainer-mode --prefix=${HOME}/testbed/lighttpd-1.4.x/ ...
这样可以消除你每次以root身份安装的负担,并且不需要root权限就可以运行lighttpd。启动lighttpd之前,最好把lighttpd配置文件中的port修改为大于1024的端口。
如果开发的插件不能正常工作,您可能需要使用autoconf重新创建生成系统,如下命令
$autoreconf -fi
$./configure --enable-maintainer-mode ...
如果一切正确, 生成目录中将会创建mod_counter.la 和 mod_counter.lo两个文件 .
调整代码
查看mod_counter插件. 你会发现:
* 配置结构体: plugin_config和plugin_data。
* 结构体初始化代码。
* set_defaults函数分析配置结构。
* the patch-function which applies the conditionals
* the real work code and finally
* plugin_init函数在插件注册服务时被调用一次。
plugin_config
每个插件在全局配置文件中可以选择是否设置配置信息,并且可以通过plugin_config结构体记录这些不同的设置信息。这个结构体被用在结构体plugin_data结构中,用于保存插件的配置信息。
plugin_data
每个插件都有属于插件自身的本地数据(像配置信息和临时缓存),通过plugin_data结构体保存这些数据。
handler_ctx
如果插件需要存储此次连接(connection)的特定信息,需要用handler_ctx结构来存储每个连接的信息。更深入的了解可以参考mod_rewrite插件。
所需函数
* _init
* _free
* _set_defaults
* _plugin_init
_plugin_init
每个插件需要编写 ..._plugin_init函数,这个函数会在插件加载时被调用。需要设置p->name指向插件名字(用户定义的插件名,本例中为 counter)缓存地址,设置相关的钩子(hooks)函数(init,set_defaults,cleanup),最后返回0即可。
_init
..._init函数在插件自身初始化时被调用,这个函数返回plugin_data结构体指针。
_free
..._free 函数在插件生命期要结束时被调用,这个函数用来释放插件申请的内存,记住不要让程序结束时为你清理内存,请自己手动释放插件中申请的内存。考虑使用valgrind或者其他工具分析验证你写的插件是否存在问题。
_set_defaults
一旦配置文件被解析,每个插件都有机会从配置文件中获取它的配置值,并验证正确性,在插件中使用config_values_t结构体保存配置文件中相应的关键字和类型信息。需要注意的是Config_values_t结构体的最后一项必须用NULL标示结束。
如果你不关心插件配置, set_defaults功能是相当简单的:
* set the destinations of the config_values_t
* 调用config_insert_values_global()
conditionals
如果编写的插件需要配置信息,在调用config_insert_values_global()函数之前还需要多做一些工作(就是对配置文件内容的解析处理),具体参考mod_access.c模块中的实现。
使用config_storage存储所有的条件和一个patch函数(比如mod_counter_patch_connection函数)。
patch function sets the basic defaults and applies the necessary modifications for the currently valid conditionals.
Don't forget to check if the patched config makes sense when you use it.
The patch functions have to be called as soon as one of the work-handlers is called (like _uri_handler and friends).
mod_counter_patch_connection(srv, con, p);
插件返回值
在大多数情况下,只需要使用HANDLER_GO_ON, HANDLER_FINISHED and HANDLER_ERROR作为插件的返回值。
HANDLER_GO_ON:当你需要其他插件处理此次请求时,在多数情况下返回HANDLER_GO_ON。有时如果你知道不需要处理这个请求,可以直接返回HANDLER_GO_ON。
HANDLER_ERROR:当发生致命错误时,当连接终止时,当调用hanlers相关函数(产生错误时)或者终止lighttpd时,当调用_set_defaults函数时(主要指配置文件出错时)返回HANDLER_ERROR。
HANDLER_FINISHED: 终止返回值状态,在以下两种情况下返回:
* 设置非200的状态码;
* 生成完用户所需的内容;
HANDLER_WAIT_FOR_EVENT 和 HANDLER_WAIT_FOR_FD:当插件没有处理完成并等待fd-event或者执行FDs时,需要返回 HANDLER_WAIT_FOR_EVENT或者HANDLER_WAIT_FOR_FD(这两种状态码用在异步事件处理的插件中,比如 mod_proxy,mod_fastcgi等插件中,以后还会提到)
HANDLER_COMEBACK:当需要重新检查请求结构(request-structur)时,需要返回HANDLER_COMEBACK状态码。在mod_rewrite插件中用于重写URI.
翻译原文:
http://trac.lighttpd.net/trac/wiki/HowToWriteALighttpdPlugin
说明:在这片文章的原文中作者没有严格区分plugin(插件)和module(模块)的概念,这里为了和原文一致,在出现plugin的地方翻译为插件,出现module的地方翻译为模块,两者表示相同的意思。对于patch-function部分,实在不好翻译,所以没有翻译,好在这部分内容容易理解。
初次翻译,有不合适的地方,欢迎大家批评指正。也希望和大家对lighttpd相关内容进行探讨。
本文版权归原文所有,转载请注明出处!
28 八月, 2008 06:23
thread_concurrency
数量设置为CPU核心数量的两倍.
thread_cache_size
按照内存大小来设置, 1G=8, 2G=16, 3G=32, >3G=64
wait_timeout
超时时间,如果连接数比较大,可以减少此参数的值,我使用的是10
max_connections
最大连接数,mysql实际允许连接数的值是max_connections+1,按照系统库不同而有不同性能.一般是500~1000,MySQL AB提供的linux静态库可以达到4000.
query_cache_size
查询缓冲,默认是0,所以必须打开以提高mysql性能,其本身需要40K来保存结构数据.所以不能设置的太小,初期可以设置成32M,然后根据实际运行情况另行调整
query_cache_type
指定查询缓冲的类型,0是关闭,1是缓冲除了使用SELECT SQL_NO_CACHE语句指明了不需要缓冲的数据意外的所有查询,2是只缓冲SELECT SQL_CACHE指定的查询.一般设置为1.
query_cache_limit
允许进入查询缓冲区的最小数据大小,默认值是1MB,可以修改的小一点以满足更多查询的需求.但是如果设置的过于小,则会导致很多新的小查询的结果将原有的查询结果交换出去.增加系统的颠簸.
相关命令
查询mysql服务器相关状态数据
>SHOW STATUS;
查询mysql服务器相关配置选项
>SHOW VARIABLES;
整理查询缓冲区里的碎片
>flush query cache;
删除查询缓冲区里的所有内容
>reset query cache;
设置mysql参数
>SET GLOBAL;
查询mysql当前执行的sql语句
>show processlist;
变量 含义
Qcache_queries_in_cache
在缓存中已注册的查询数目
Qcache_inserts
被加入到缓存中的查询数目
Qcache_hits
缓存采样数数目
Qcache_lowmem_prunes
因为缺少内存而被从缓存中删除的查询数目
Qcache_not_cached
没有被缓存的查询数目 (不能被缓存的,或由于 QUERY_CACHE_TYPE)
Qcache_free_memory
查询缓存的空闲内存总数
Qcache_free_blocks
查询缓存中的空闲内存块的数目
Qcache_total_blocks
查询缓存中的块的总数目
MySQL查询优化
>SHOW STATUS LIKE ‘Qcache%’;
查询出Cache状态
如果Qcache_lowmem_prunes非常大,说明因为内存不足而被交换出cache的数据很多.如果增加内存.可以保证较小的交换次数以及较高的命中率
例如现在我们查询的结果如下
| Qcache_free_memory | 25957504 |
| Qcache_hits | 55771119 |
| Qcache_inserts | 7441153 |
| Qcache_lowmem_prunes | 28332 |
| Qcache_not_cached | 1233788 |
| Qcache_queries_in_cache | 4810 |
| Qcache_total_blocks | 11038 |
设置为64M cache内存后
>set global query_cache_size=67108864;
| Qcache_free_memory | 66623616 |
| Qcache_hits | 55788258 |
| Qcache_inserts | 7445445 |
| Qcache_lowmem_prunes | 28332 |
| Qcache_not_cached | 1234057 |
| Qcache_queries_in_cache | 183 |
| Qcache_total_blocks | 392 |
自由内存块看起来变小了
是因为现在自由内存块.是一个整块.而以前的内存块都是分散的小块
而因为重建了cache区
Qcache_queries_in_cache变量变小了.因为此操作重新建立了cache内存区.所有数据重新缓存
在运行一两天后我们再看此数据.如果变大了.说明增大cache内存区域是有效的.如果和以前数据差不多
说明增加的内存并没有实际起到多大的作用.
有人会觉得如果我将cache内存设置的非常大
然后将cache_limit设置成0
那么所有查询都会被缓存了
理论上是这样.但是一台数据库服务器的查询非常多.
如果连查询单条数据都要缓存.
那么内存再大也会不够的.到时候老的内容就会被交换出去
当cache内存使用满的时候,就会不停的有新查询进来将老查询替换出去.
这样导致两个结果.一个是内存颠簸.效率反而下降.
第二个是cache内存的小碎块增多,内存利用率降低
如果是只有内容很少的小库,并且查询率不高.是可以使用这种方法提高响应速度
但是如果是实际生产环境,数据量会比较大.还是需要按照最佳比例来配置.
而不同的应用不同的数据量会有不同的搭配,这点大家不要看网上的优化配置随便的填写
还是要时时的查看mysql的状态进行调整.即便是这个月调整好的优化参数
到了下个月业务不同,数据量增加,也会需要调整的.
28 八月, 2008 06:11
一、实际需求
在应用各种监控软件(比如:cacti、nagios、sitescope等)的时候,我一般都会用到它的email阀值报警功能。如果这时候再加上一个 msn在线监控机器人为你把关,第一时间给你发出msn报警信息,是不是能让你更快的处理问题呢。以下我为大家介绍一个msn command line 的小程序来实现这个功能。
软件下载地址:sendMsg
二、运行环境
一个支持php的系统环境就可以啦,当然要能上网,不然怎么发消息呢。
我的做法是和cacti监控服务器放一起,不需要额外的设备和资源投入。
注册一个msn的帐号用于监控机器人。比如:test@test.com 密码:123456
需要收到消息的msn帐号必须加监控帐号test@test.com为好友,不然收不到消息。
三、sendMsg用法
sendMsg.zip包中所有文件如下:
-rw-r--r-- 1 root root 1213 Jul 29 2007 index.php //测试页面,web中打开开始测试;很容易做。
-rw-r--r-- 1 root root 3894 Jul 29 2007 msnpauth-1.1.3.php
-rw-r--r-- 1 root root 3372 Jul 29 2007 msnpauth.php
-rw-r--r-- 1 root root 4586 Jul 29 2007 sendMsg.php
-rw-r--r-- 1 root root 223 Jul 29 2007 simple.php
-rw-r--r-- 1 root root 1424 Jul 29 2007 template.tpl
该程序也是通过登录msn服务器、建立IM会话,发送消息;
基本PHP语法如下:
$sendMsg->login('test@test.com', '123456');
//刚才建立的用于举例的msn监控机器人帐号
$sendMsg->createSession('recipient@hotmail.com');
//接受信息人的msn帐号
$sendMsg->sendMessage('message', 'Times New Roman', 'FF0000');
//第一个是具体信息内容,后面可以设定字体和颜色;
$sendMsg->sendMessage(iconv("GBK", "UTF-8", 测试), 'Times New Roman', '008000');
//也利用iconv转换gbk到utf8来发送中文信息;
四、实际应用
这里是我自己写的一个应用发送msn信息的php脚本:仅供参考,如果大家有更好请和我交流。
<?
if ($argc != 3) {
die("Usage: send_cndmonitor.php <msn-address> <messages>n");
}
array_shift($argv);
$msnaddr = $argv[0];
$messages = $argv[1];
include('sendMsg.php');
$sendMsg = new sendMsg();
$sendMsg->login('test@test.com', '123456');
$sendMsg->createSession($msnaddr);
$sendMsg->sendMessage($messages, 'Times New Roman', '008000');
?>
主要是为了能被其他脚本调用,用于发送一个报警信息。缺点是不能判定错误,所以实际运用中存在故障,需要网络流畅的环境下使用。
我们的生产环境已经存在大量的监控系统,所以针对错误信息已经整理到数据库中,因此我只需要从数据库导出目前存在error信息的文本文件,然后根据节点位置发送给相关维护负责人即可。
为了能判定和确保发送正确,我利用sendMsg中的index.php的页面和shell脚本相结合来循环发送,实在抱歉本人PHP程度有限;
脚本如下:(这是我实例中使用的一个工作脚本,仅供大家借鉴)
wget --user=monitor --password=123456 http://127.0.0.1/monitor/msn.txt -O /var/www/html/sendMsg/msn.txt.1 >/dev/null 2>&1
#下载msn要发送的信息,因为页面都是认证的所以用了wget的user和password;
now=`date +%Y-%m-%d-%H:%M`
[ -f /var/www/html/sendMsg/msn.txt ] && oldmd5=`md5sum var/www/html/sendMsg/msn.txt |awk '{print $1}' |tee /var/log/cdn_status_old.md5` || exit 0
[ -f /var/www/html/sendMsg/msn.txt.1 ] && newmd5=`md5sum var/www/html/sendMsg/msn.txt.1 |awk '{print $1}' |tee /var/log/cdn_status_new.md5` || exit 0
SA=(admin1 admin2 admin3 admin4)
# 相关负责人列表和下载的msn信息的中的名字对应;
msnaddr=(admin1@msn.com admin2@msn.com admin3@msn.com admin4@msn.com)
# 相关负责人的msn帐号和SA变量中的的名字顺序一一对应;
sendMsg()
{
num=0
while [ $num -lt 1 ];
do
wget --post-data "sender=test@test.com&password=123456&recipient=${1}&message=${2}" http://127.0.0.1/sendMsg/index.php -O /var/www/html/sendMsg/index.php.1 >/dev/null 2>&1
# 使用wget post-data发送post参数给index.php页面,用以发送msn信息。
if [ -f /var/www/html/sendMsg/index.php.1 ]; then
if cat /var/www/html/sendMsg/index.php.1 |grep -i successfully >/dev/null 2>&1;then
num=1 #判断信息发送成功
elif cat
