<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>开源小站</title>
	<atom:link href="http://www.litrin.net/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.litrin.net</link>
	<description>It is Cool to OpenSource</description>
	<lastBuildDate>Thu, 17 May 2012 02:02:32 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Linux KVM中FreeBSD9的安装</title>
		<link>http://www.litrin.net/2012/05/17/linux-kvm%e4%b8%adfreebsd9%e7%9a%84%e5%ae%89%e8%a3%85/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=linux-kvm%25e4%25b8%25adfreebsd9%25e7%259a%2584%25e5%25ae%2589%25e8%25a3%2585</link>
		<comments>http://www.litrin.net/2012/05/17/linux-kvm%e4%b8%adfreebsd9%e7%9a%84%e5%ae%89%e8%a3%85/#comments</comments>
		<pubDate>Thu, 17 May 2012 02:02:32 +0000</pubDate>
		<dc:creator>Litrin</dc:creator>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[Unix]]></category>
		<category><![CDATA[硬件相关]]></category>
		<category><![CDATA[FreeBSD]]></category>
		<category><![CDATA[ubuntu]]></category>
		<category><![CDATA[www]]></category>
		<category><![CDATA[服务器]]></category>

		<guid isPermaLink="false">http://www.litrin.net/?p=1789</guid>
		<description><![CDATA[种种原因，站长已经很久没有关注过FreeBSD了，记得最后一次关注，FreeBSD还是8.0。现在已经到了9.0，安装界面上有了“质一级的飞跃”！由于真实主机上的安装没什么难度，这次就直接在KVM中安装。印象中FreeBSD属于比较保守的操作系统，对新的硬件和技术的支持相对比较慢。安装中也确实出现过问题，这里顺便也做个记录。 KVM主机是之前一直在说的Ubuntu1204的libvirt，没有桌面系统，也就意味着不能简单的通过virt-manger工具配置。主机在外网，且防火墙限制了它不能直接通过VNC连接。 首先是准备ssh 通道，windows下，我一直用putty &#160; 连接成功后，本地将会出现5900端口的监听，直接用VNC的客户端连接localhost的5900事实上就连接到了远程主机的5900。当然，虚拟机还没有启动，两个5900都不存在。 准备配置文件，其实我是直接用模版修改出来的：  &#60;domain type='kvm'&#62;   &#60;name&#62;medkaoyan&#60;/name&#62;   &#60;uuid&#62;f5936116-24c7-163f-13ac-7f50604faa5c&#60;/uuid&#62;   &#60;memory&#62;524288&#60;/memory&#62;   &#60;currentMemory&#62;524288&#60;/currentMemory&#62;   &#60;vcpu&#62;2&#60;/vcpu&#62;   &#60;os&#62;     &#60;type arch='x86_64' machine='pc-1.0'&#62;hvm&#60;/type&#62;     &#60;boot dev='cdrom'/&#62; &#60;!-- 首次用光驱启动 --&#62;   &#60;/os&#62;   &#60;features&#62;     &#60;acpi/&#62;   &#60;/features&#62;   &#60;clock offset='utc'/&#62;   &#60;on_poweroff&#62;destroy&#60;/on_poweroff&#62;   &#60;on_reboot&#62;restart&#60;/on_reboot&#62;   &#60;on_crash&#62;destroy&#60;/on_crash&#62;   &#60;devices&#62;     &#60;emulator&#62;/usr/bin/kvm&#60;/emulator&#62;     &#60;disk type='file' [...]]]></description>
			<content:encoded><![CDATA[<p>种种原因，站长已经很久没有关注过FreeBSD了，记得最后一次关注，FreeBSD还是8.0。现在已经到了9.0，安装界面上有了“质一级的飞跃”！由于真实主机上的安装没什么难度，这次就直接在KVM中安装。印象中FreeBSD属于比较保守的操作系统，对新的硬件和技术的支持相对比较慢。安装中也确实出现过问题，这里顺便也做个记录。</p>
<p>KVM主机是之前一直在说的Ubuntu1204的libvirt，没有桌面系统，也就意味着不能简单的通过virt-manger工具配置。主机在外网，且防火墙限制了它不能直接通过VNC连接。</p>
<p><span id="more-1789"></span></p>
<p>首先是准备ssh 通道，windows下，我一直用putty</p>
<p><a href="http://www.litrin.net/wp-content/uploads/2012/05/KVM_vnc.png"><img class="aligncenter size-medium wp-image-1790" title="KVM_vnc" src="http://www.litrin.net/wp-content/uploads/2012/05/KVM_vnc-300x286.png" alt="" width="300" height="286" /></a></p>
<p>&nbsp;</p>
<p>连接成功后，本地将会出现5900端口的监听，直接用VNC的客户端连接localhost的5900事实上就连接到了远程主机的5900。当然，虚拟机还没有启动，两个5900都不存在。</p>
<p>准备配置文件，其实我是直接用模版修改出来的：</p>
<pre> &lt;domain type='kvm'&gt;
  &lt;name&gt;medkaoyan&lt;/name&gt;
  &lt;uuid&gt;f5936116-24c7-163f-13ac-7f50604faa5c&lt;/uuid&gt;
  &lt;memory&gt;524288&lt;/memory&gt;
  &lt;currentMemory&gt;524288&lt;/currentMemory&gt;
  &lt;vcpu&gt;2&lt;/vcpu&gt;
  &lt;os&gt;
    &lt;type arch='x86_64' machine='pc-1.0'&gt;hvm&lt;/type&gt;
    &lt;boot dev='cdrom'/&gt; &lt;!-- 首次用光驱启动 --&gt;
  &lt;/os&gt;
  &lt;features&gt;
    &lt;acpi/&gt;
  &lt;/features&gt;
  &lt;clock offset='utc'/&gt;
  &lt;on_poweroff&gt;destroy&lt;/on_poweroff&gt;
  &lt;on_reboot&gt;restart&lt;/on_reboot&gt;
  &lt;on_crash&gt;destroy&lt;/on_crash&gt;
  &lt;devices&gt;
    &lt;emulator&gt;/usr/bin/kvm&lt;/emulator&gt;
    &lt;disk type='file' device='disk'&gt;
      &lt;driver name='qemu' type='qcow2'/&gt;
      &lt;source file='/data/VM/medkaoyan/freebsd.qcow2'/&gt; &lt;!-- 磁盘文件 --&gt;
      &lt;target dev='hda' bus='ide'/&gt;
      &lt;address type='drive' controller='0' bus='0' unit='0'/&gt;
    &lt;/disk&gt;
&lt;!--
    &lt;disk type='file' device='disk'&gt;
      &lt;driver name='qemu' type='qcow2'/&gt;
      &lt;source file='/data/VM/medkaoyan/data.qcow2'/&gt;
      &lt;target dev='hda' bus='ide'/&gt;
      &lt;address type='drive' controller='0' bus='0' unit='1'/&gt;
    &lt;/disk&gt;
--&gt;
    &lt;disk type='file' device='cdrom'&gt;
      &lt;driver name='qemu' type='raw'/&gt;
      &lt;source file='/root/FreeBSD-9.0-RELEASE-i386-disc1.iso'/&gt; &lt;!-- 安装介质 --&gt;
      &lt;target dev='hdc' bus='ide'/&gt;
      &lt;readonly/&gt;
      &lt;address type='drive' controller='0' bus='1' unit='0'/&gt;
    &lt;/disk&gt;
    &lt;controller type='ide' index='0'&gt;
      &lt;address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/&gt;
    &lt;/controller&gt;
    &lt;interface type='bridge'&gt;
      &lt;mac address='52:54:00:ef:8c:06'/&gt;
      &lt;source bridge='br0'/&gt;
      &lt;model type='ne2k_pci'/&gt; &lt;!-- 网络 --&gt;
      &lt;address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/&gt;
    &lt;/interface&gt;
    &lt;!-- &lt;input type='mouse' bus='ps2'/&gt; --&gt;
    &lt;graphics type='vnc' port='-1' autoport='yes'/&gt;
    &lt;video&gt;
      &lt;model type='cirrus' vram='9216' heads='1'/&gt;
      &lt;address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/&gt;
    &lt;/video&gt;
    &lt;memballoon model='virtio'&gt;
      &lt;address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/&gt;
    &lt;/memballoon&gt;
  &lt;/devices&gt;
&lt;/domain&gt;</pre>
<p>典型的xml，很好通读，里面的问题稍后再说。</p>
<p>制作虚拟磁盘文件，配置文件中，此文件名为 /data/VM/medkaoyan/freebsd.qcow2</p>
<p>kvm-image create -f qcow2 /data/VM/medkaoyan/freebsd.qcow2 20G   , 创建一个20G的虚拟磁盘。</p>
<p>多说一句，KVM支持多种虚拟磁盘格式，除了诸如vmdk等其他几个虚拟主机格式的文件之外，raw和qcow2我用的比较多。raw事实上是硬模拟了一个裸设备，这样做的优势是相对来说数据是平滑的，也就是一旦虚拟机崩溃，用这个文件可以硬恢复数据的。但磁盘空间是预分配的，而且不支持snap，从某种程度上说是增加了崩溃几率。qcow2的空间分配是按照使用率来的，效率比较高，而且支持数据压缩、数据缓存等高级功能，但问题是一旦崩溃，数据恢复比较复杂。大家各取所需吧。</p>
<p>下载安装镜像，没什么难度：</p>
<p>wget http://mirrors.163.com/FreeBSD/releases/ISO-IMAGES/9.0/FreeBSD-9.0-RELEASE-i386-disc1.iso</p>
<p>对于网络，系统原本推荐的是virtio，但FreeBSD不支持virtio，第一次安装的时候我在全部完成之后进入系统，手工配置内核后才OK，其间没有网络cvsup都是问题，费时费力。为了方便，索性这次直接修改默认配置到ne2k_pci，很方便！</p>
<p>确认无误后启动virsh，create你的xml配置文件，start 虚拟主机。此时5900开始监听，VNC上！</p>
<p><a href="http://www.litrin.net/wp-content/uploads/2012/05/KVM_freebsd.png"><img class="aligncenter size-medium wp-image-1791" title="KVM_freebsd" src="http://www.litrin.net/wp-content/uploads/2012/05/KVM_freebsd-300x175.png" alt="" width="300" height="175" /></a>安装过程是图形化的，直接跳过。</p>
<p>完成后destroy 主机， 将启动介质从cdrom切换为hd。</p>
<p>首次进入系统后，准备之前说的virtio模块，优化性能（需要安装src源并保持更新）。</p>
<pre>cd /usr/src/sys/dev
svn co http://svn.freebsd.org/base/projects/virtio/sys/dev/virtio
cd /usr/src/sys/modules
svn co http://svn.freebsd.org/base/projects/virtio/sys/modules/virtio
cd /usr/src/sys/modules/virtio

make install</pre>
<p>漫长的编译过程。。。。完成后编辑 /boot/loader.conf，增加：</p>
<pre>virtio_load="YES"
virtio_pci_load="YES"
virtio_blk_load="YES"
if_vtnet_load="YES"
virtio_balloon_load="YES"</pre>
<p>重起之后确认模块是否挂装：</p>
<pre># dmesg | grep -i  virtio
vtnet0:  on virtio_pci0
virtio_pci1:  port 0xc060-0xc07f irq 11 at device 4.0 on pci0
vtballoon0:  on virtio_pci1
virtio_pci2:  port 0xc080-0xc0bf mem 0xf2040000-0xf2040fff irq 10 at device 5.0 on pci0
vtblk0:  on virtio_pci2</pre>
<p>写在最后的是通过virt-install的安装方法，有没有觉得之前看这么多是上当了？ <img src='http://www.litrin.net/wp-includes/images/smilies/icon_mrgreen.gif' alt=':mrgreen:' class='wp-smiley' />   请先apt-get install virtinst</p>
<pre>
sudo virt-install \
--name medkaoyan\
--ram 512 --vcpus=2 \
--os-type unix --hvm --vnc \
--cdrom=/root/FreeBSD-9.0-RELEASE-i386-disc1.iso \
--network=bridge:br0,model=ne2k_pci \
--disk path=/data/VM/medkaoyan/freebsd.qcow2,size=20</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.litrin.net/2012/05/17/linux-kvm%e4%b8%adfreebsd9%e7%9a%84%e5%ae%89%e8%a3%85/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>mod_php迁移到php-fpm的注意事项</title>
		<link>http://www.litrin.net/2012/05/07/mod_php%e8%bf%81%e7%a7%bb%e5%88%b0php-fpm%e7%9a%84%e6%b3%a8%e6%84%8f%e4%ba%8b%e9%a1%b9/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=mod_php%25e8%25bf%2581%25e7%25a7%25bb%25e5%2588%25b0php-fpm%25e7%259a%2584%25e6%25b3%25a8%25e6%2584%258f%25e4%25ba%258b%25e9%25a1%25b9</link>
		<comments>http://www.litrin.net/2012/05/07/mod_php%e8%bf%81%e7%a7%bb%e5%88%b0php-fpm%e7%9a%84%e6%b3%a8%e6%84%8f%e4%ba%8b%e9%a1%b9/#comments</comments>
		<pubDate>Mon, 07 May 2012 07:23:46 +0000</pubDate>
		<dc:creator>Litrin</dc:creator>
				<category><![CDATA[Coding]]></category>
		<category><![CDATA[www]]></category>
		<category><![CDATA[php]]></category>

		<guid isPermaLink="false">http://www.litrin.net/?p=1785</guid>
		<description><![CDATA[Php-fpm由于其特有的优势已经逐渐成为这一阶段大负载网站的首选。近期受朋友之托，将一个稍显老旧的网站从apache+mod_php迁移到了nginx+php-fpm之上。其间碰到不少问题，除却php版本升级带来的兼容性问题之外，很多兼容性问题其实来自于php-fpm的特性。这里就简单的罗列一下所碰到的问题，以供大家参考，少走弯路为妙。 首当其冲的是$_SERVER["HTTP_REFERER"] 环境变量，这个问题经常出现在需要跳转的页面上，表现为跳转到白板。 很多代码习惯上用$_SERVER["HTTP_REFERER"] 获取上次访问的页面URL，这对于mod_php来说，由于采用直接嵌入http服务器的方法，PHP可以很容易的获得HTTP_REFERER变量。但对于CGI方式的php-fpm来说，此环境变量无法获取，我个人的解决方法是通过不断刷新一个cookie获取。显得很笨拙，但代码改动的量很少。你也许会说这样做容易被篡改，但事实上即便mod_php获取的环境变量也是很容易被篡改的。 接下来是$_SERVER["HTTPS"]，这个问题经常出现在跳转上，如果发现所有的跳转url出现异常多半是这个问题。 mod_php中$_SERVER["HTTPS"]变量只有在启用了https之后才会出现，否则empty($_SERVER["HTTPS"]) === true，而作为php-fpm这个值是始终存在的，只是在http时$_SERVER["HTTPS"] === null而已。尽管$_SERVER["HTTPS"] == null 等价于empty($_SERVER["HTTPS"]) == true，但在“三等”条件下并不成立。 对应的$_SERVER变量问题还有x-forward*之类，这里不再累述。 然后是rewrite规则，这个规则事实上是apache和nginx之间的兼容问题，跟php无关。 个人觉得很apache和nginx的跳转规则基本上是通用的甚至于只要用记事本做个全文替换就好。例如： RewriteRule ^(.*\.(css&#124;js))$ min/index.php?f=$1 [L] 转换为nginx rewrite "^(.*\.(css&#124;js))$"              /min/index.php?f=$1     last; 当然，nginx是不支持.htaccess的，需要写入配置文件中去。 执行时间问题，对应的大多为502报错。这个问题说实话我没有很好的方法解决，只能提前规划。 不同于mod_php的方式，在执行一个较长时间的脚本时，一旦超出阀值（默认10秒）php-fpm会自动关闭执行，向前端返回502。个人觉得这相对于mod_php来说是一个保护性的设置，是优势所在，不应该关闭。 进程控制类函数，相对用的应该不多。 php-fpm用的是非阻塞性质的线程池，不应该有这类函数出现，应当慎用。 一个窍门：$_ENV变量 相比mod_php来说，$_ENV变量是一个优势，对于企业开发，特别是开发和运维分开的企业，这很容易开发出环境无关的代码——运维修改$_ENV变量，开发读取此变量，相互直接不需要太多交流。对应5.3 fpm配置文件中 env[TEMP] = /tmp 或者5.2 &#60;value name=”environment”&#62;  &#60;value name=”TMP”&#62;/tmp&#60;/value&#62;标签。 &#160;]]></description>
			<content:encoded><![CDATA[<p>Php-fpm由于其特有的优势已经逐渐成为这一阶段大负载网站的首选。近期受朋友之托，将一个稍显老旧的网站从apache+mod_php迁移到了nginx+php-fpm之上。其间碰到不少问题，除却php版本升级带来的兼容性问题之外，很多兼容性问题其实来自于php-fpm的特性。这里就简单的罗列一下所碰到的问题，以供大家参考，少走弯路为妙。</p>
<p><span id="more-1785"></span></p>
<p>首当其冲的是$_SERVER["HTTP_REFERER"] 环境变量，这个问题经常出现在需要跳转的页面上，表现为跳转到白板。<br />
很多代码习惯上用$_SERVER["HTTP_REFERER"] 获取上次访问的页面URL，这对于mod_php来说，由于采用直接嵌入http服务器的方法，PHP可以很容易的获得HTTP_REFERER变量。但对于CGI方式的php-fpm来说，此环境变量无法获取，我个人的解决方法是通过不断刷新一个cookie获取。显得很笨拙，但代码改动的量很少。你也许会说这样做容易被篡改，但事实上即便mod_php获取的环境变量也是很容易被篡改的。</p>
<p>接下来是$_SERVER["HTTPS"]，这个问题经常出现在跳转上，如果发现所有的跳转url出现异常多半是这个问题。<br />
mod_php中$_SERVER["HTTPS"]变量只有在启用了https之后才会出现，否则empty($_SERVER["HTTPS"]) === true，而作为php-fpm这个值是始终存在的，只是在http时$_SERVER["HTTPS"] === null而已。尽管$_SERVER["HTTPS"] == null 等价于empty($_SERVER["HTTPS"]) == true，但在“三等”条件下并不成立。</p>
<p>对应的$_SERVER变量问题还有x-forward*之类，这里不再累述。</p>
<p>然后是rewrite规则，这个规则事实上是apache和nginx之间的兼容问题，跟php无关。<br />
个人觉得很apache和nginx的跳转规则基本上是通用的甚至于只要用记事本做个全文替换就好。例如：</p>
<pre>RewriteRule ^(.*\.(css|js))$ min/index.php?f=$1 [L]</pre>
<p>转换为nginx</p>
<pre>rewrite "^(.*\.(css|js))$"              /min/index.php?f=$1     last;</pre>
<p>当然，nginx是不支持.htaccess的，需要写入配置文件中去。</p>
<p>执行时间问题，对应的大多为502报错。这个问题说实话我没有很好的方法解决，只能提前规划。<br />
不同于mod_php的方式，在执行一个较长时间的脚本时，一旦超出阀值（默认10秒）php-fpm会自动关闭执行，向前端返回502。个人觉得这相对于mod_php来说是一个保护性的设置，是优势所在，不应该关闭。</p>
<p>进程控制类函数，相对用的应该不多。<br />
php-fpm用的是非阻塞性质的线程池，不应该有这类函数出现，应当慎用。</p>
<p>一个窍门：$_ENV变量<br />
相比mod_php来说，$_ENV变量是一个优势，对于企业开发，特别是开发和运维分开的企业，这很容易开发出环境无关的代码——运维修改$_ENV变量，开发读取此变量，相互直接不需要太多交流。对应5.3 fpm配置文件中 env[TEMP] = /tmp 或者5.2 &lt;value name=”environment”&gt;  &lt;value name=”TMP”&gt;/tmp&lt;/value&gt;标签。</p>
<p>&nbsp;</p>
]]></content:encoded>
			<wfw:commentRss>http://www.litrin.net/2012/05/07/mod_php%e8%bf%81%e7%a7%bb%e5%88%b0php-fpm%e7%9a%84%e6%b3%a8%e6%84%8f%e4%ba%8b%e9%a1%b9/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Ubuntu 1204的全套壁纸</title>
		<link>http://www.litrin.net/2012/04/28/ubuntu-1204%e7%9a%84%e5%a3%81%e7%ba%b8/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=ubuntu-1204%25e7%259a%2584%25e5%25a3%2581%25e7%25ba%25b8</link>
		<comments>http://www.litrin.net/2012/04/28/ubuntu-1204%e7%9a%84%e5%a3%81%e7%ba%b8/#comments</comments>
		<pubDate>Sat, 28 Apr 2012 03:10:07 +0000</pubDate>
		<dc:creator>Litrin</dc:creator>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[ubuntu]]></category>

		<guid isPermaLink="false">http://www.litrin.net/?p=1763</guid>
		<description><![CDATA[猛击这里下载 1204 新特性： The Head-Up Display (HUD) 顶部部显示空间 The Video Lens 新的视频展现方式 Ubuntu Software Centre 新的软件中心 全文http://www.ubuntu.com/ubuntu/whats-new &#160;]]></description>
			<content:encoded><![CDATA[<p style="text-align: center;"><a title="Ubuntu 1204的全套壁纸" href="http://www.litrin.net/2012/04/28/ubuntu-1204%e7%9a%84%e5%a3%81%e7%ba%b8/">猛击这里下载</a></p>
<p><span id="more-1763"></span></p>

<a href='http://www.litrin.net/2012/04/28/ubuntu-1204%e7%9a%84%e5%a3%81%e7%ba%b8/delicate_petals_by_lefthandgergo/' title='Delicate_Petals_by_lefthandgergo'><img width="150" height="150" src="http://www.litrin.net/wp-content/uploads/2012/04/Delicate_Petals_by_lefthandgergo-150x150.jpg" class="attachment-thumbnail" alt="Delicate_Petals_by_lefthandgergo" title="Delicate_Petals_by_lefthandgergo" /></a>
<a href='http://www.litrin.net/2012/04/28/ubuntu-1204%e7%9a%84%e5%a3%81%e7%ba%b8/early_blossom_by_dh0r/' title='Early_Blossom_by_Dh0r'><img width="150" height="150" src="http://www.litrin.net/wp-content/uploads/2012/04/Early_Blossom_by_Dh0r-150x150.jpg" class="attachment-thumbnail" alt="Early_Blossom_by_Dh0r" title="Early_Blossom_by_Dh0r" /></a>
<a href='http://www.litrin.net/2012/04/28/ubuntu-1204%e7%9a%84%e5%a3%81%e7%ba%b8/flocking_by_noombox/' title='Flocking_by_noombox'><img width="150" height="150" src="http://www.litrin.net/wp-content/uploads/2012/04/Flocking_by_noombox-150x150.jpg" class="attachment-thumbnail" alt="Flocking_by_noombox" title="Flocking_by_noombox" /></a>
<a href='http://www.litrin.net/2012/04/28/ubuntu-1204%e7%9a%84%e5%a3%81%e7%ba%b8/floorboards_by_dawid_huczynski/' title='Floorboards_by_Dawid_Huczyński'><img width="150" height="150" src="http://www.litrin.net/wp-content/uploads/2012/04/Floorboards_by_Dawid_Huczyński-150x150.jpg" class="attachment-thumbnail" alt="Floorboards_by_Dawid_Huczyński" title="Floorboards_by_Dawid_Huczyński" /></a>
<a href='http://www.litrin.net/2012/04/28/ubuntu-1204%e7%9a%84%e5%a3%81%e7%ba%b8/golden_bloom_by_twinmama/' title='Golden_Bloom_by_Twinmama'><img width="150" height="150" src="http://www.litrin.net/wp-content/uploads/2012/04/Golden_Bloom_by_Twinmama-150x150.jpg" class="attachment-thumbnail" alt="Golden_Bloom_by_Twinmama" title="Golden_Bloom_by_Twinmama" /></a>
<a href='http://www.litrin.net/2012/04/28/ubuntu-1204%e7%9a%84%e5%a3%81%e7%ba%b8/london_eye_from_beneath_by_fernando_garcia/' title='London_Eye_From_Beneath_by_Fernando_García'><img width="150" height="150" src="http://www.litrin.net/wp-content/uploads/2012/04/London_Eye_From_Beneath_by_Fernando_García-150x150.jpg" class="attachment-thumbnail" alt="London_Eye_From_Beneath_by_Fernando_García" title="London_Eye_From_Beneath_by_Fernando_García" /></a>
<a href='http://www.litrin.net/2012/04/28/ubuntu-1204%e7%9a%84%e5%a3%81%e7%ba%b8/morning_dew_by_lars_clausen/' title='Morning_Dew_by_Lars_Clausen'><img width="150" height="150" src="http://www.litrin.net/wp-content/uploads/2012/04/Morning_Dew_by_Lars_Clausen-150x150.jpg" class="attachment-thumbnail" alt="Morning_Dew_by_Lars_Clausen" title="Morning_Dew_by_Lars_Clausen" /></a>
<a href='http://www.litrin.net/2012/04/28/ubuntu-1204%e7%9a%84%e5%a3%81%e7%ba%b8/murales_by_jan_bencini/' title='Murales_by_Jan_Bencini'><img width="150" height="150" src="http://www.litrin.net/wp-content/uploads/2012/04/Murales_by_Jan_Bencini-150x150.jpg" class="attachment-thumbnail" alt="Murales_by_Jan_Bencini" title="Murales_by_Jan_Bencini" /></a>
<a href='http://www.litrin.net/2012/04/28/ubuntu-1204%e7%9a%84%e5%a3%81%e7%ba%b8/precise_pangolin_by_vlad_gerasimov/' title='Precise_Pangolin_by_Vlad_Gerasimov'><img width="150" height="150" src="http://www.litrin.net/wp-content/uploads/2012/04/Precise_Pangolin_by_Vlad_Gerasimov-150x150.jpg" class="attachment-thumbnail" alt="Precise_Pangolin_by_Vlad_Gerasimov" title="Precise_Pangolin_by_Vlad_Gerasimov" /></a>
<a href='http://www.litrin.net/2012/04/28/ubuntu-1204%e7%9a%84%e5%a3%81%e7%ba%b8/speaker_weave_by_phil_jackson/' title='Speaker_Weave_by_Phil_Jackson'><img width="150" height="150" src="http://www.litrin.net/wp-content/uploads/2012/04/Speaker_Weave_by_Phil_Jackson-150x150.jpg" class="attachment-thumbnail" alt="Speaker_Weave_by_Phil_Jackson" title="Speaker_Weave_by_Phil_Jackson" /></a>
<a href='http://www.litrin.net/2012/04/28/ubuntu-1204%e7%9a%84%e5%a3%81%e7%ba%b8/the_forbidden_city_by_daniel_mathis/' title='The_Forbidden_City_by_Daniel_Mathis'><img width="150" height="150" src="http://www.litrin.net/wp-content/uploads/2012/04/The_Forbidden_City_by_Daniel_Mathis-150x150.jpg" class="attachment-thumbnail" alt="The_Forbidden_City_by_Daniel_Mathis" title="The_Forbidden_City_by_Daniel_Mathis" /></a>
<a href='http://www.litrin.net/2012/04/28/ubuntu-1204%e7%9a%84%e5%a3%81%e7%ba%b8/tie_my_boat_by_ray_garcia/' title='Tie_My_Boat_by_Ray_García'><img width="150" height="150" src="http://www.litrin.net/wp-content/uploads/2012/04/Tie_My_Boat_by_Ray_García-150x150.jpg" class="attachment-thumbnail" alt="Tie_My_Boat_by_Ray_García" title="Tie_My_Boat_by_Ray_García" /></a>
<a href='http://www.litrin.net/2012/04/28/ubuntu-1204%e7%9a%84%e5%a3%81%e7%ba%b8/twilight_frost_by_phil_jackson/' title='Twilight_Frost_by_Phil_Jackson'><img width="150" height="150" src="http://www.litrin.net/wp-content/uploads/2012/04/Twilight_Frost_by_Phil_Jackson-150x150.jpg" class="attachment-thumbnail" alt="Twilight_Frost_by_Phil_Jackson" title="Twilight_Frost_by_Phil_Jackson" /></a>
<a href='http://www.litrin.net/2012/04/28/ubuntu-1204%e7%9a%84%e5%a3%81%e7%ba%b8/warty-final-ubuntu/' title='warty-final-ubuntu'><img width="150" height="150" src="http://www.litrin.net/wp-content/uploads/2012/04/warty-final-ubuntu-150x150.jpg" class="attachment-thumbnail" alt="warty-final-ubuntu" title="warty-final-ubuntu" /></a>
<a href='http://www.litrin.net/2012/04/28/ubuntu-1204%e7%9a%84%e5%a3%81%e7%ba%b8/winter_morning_by_shannon_lucas/' title='Winter_Morning_by_Shannon_Lucas'><img width="150" height="150" src="http://www.litrin.net/wp-content/uploads/2012/04/Winter_Morning_by_Shannon_Lucas-150x150.jpg" class="attachment-thumbnail" alt="Winter_Morning_by_Shannon_Lucas" title="Winter_Morning_by_Shannon_Lucas" /></a>

<p><object width="480" height="400" classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0"><param name="src" value="http://player.youku.com/player.php/sid/XMzgwNDQ2NTM2/v.swf" /><param name="quality" value="high" /><param name="allowscriptaccess" value="sameDomain" /><param name="allowfullscreen" value="true" /><embed width="480" height="400" type="application/x-shockwave-flash" src="http://player.youku.com/player.php/sid/XMzgwNDQ2NTM2/v.swf" quality="high" allowscriptaccess="sameDomain" allowfullscreen="true" /></object></p>
<p>1204 新特性：</p>
<ul>
<li>The Head-Up Display (HUD) 顶部部显示空间</li>
<li>The Video Lens 新的视频展现方式</li>
<li>Ubuntu Software Centre 新的软件中心</li>
</ul>
<p>全文<a rel="nofollow" target="_blank" href="http://www.ubuntu.com/ubuntu/whats-new">http://www.ubuntu.com/ubuntu/whats-new</a></p>
<p>&nbsp;</p>
]]></content:encoded>
			<wfw:commentRss>http://www.litrin.net/2012/04/28/ubuntu-1204%e7%9a%84%e5%a3%81%e7%ba%b8/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Unix的Socket协议</title>
		<link>http://www.litrin.net/2012/04/19/unix%e7%9a%84socket%e5%8d%8f%e8%ae%ae/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=unix%25e7%259a%2584socket%25e5%258d%258f%25e8%25ae%25ae</link>
		<comments>http://www.litrin.net/2012/04/19/unix%e7%9a%84socket%e5%8d%8f%e8%ae%ae/#comments</comments>
		<pubDate>Thu, 19 Apr 2012 01:52:29 +0000</pubDate>
		<dc:creator>Litrin</dc:creator>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[Unix]]></category>
		<category><![CDATA[网络和安全]]></category>

		<guid isPermaLink="false">http://www.litrin.net/?p=1756</guid>
		<description><![CDATA[PHP的官方文档中，对于mysql_connect函数的介绍中有这么一条信息： Note: 只要将 server 指定为 “localhost” 或 “localhost:port”，MySQL 客户端库会越过此值并尝试连接到本地套接字（Windows 中的名字管道）。如果想用 TCP/IP，应该用 “127.0.0.1&#8243; 代替 “localhost”。如果 MySQL 客户端库试图连接到一个错误的本地套接字，则应该在 PHP 配置中设定的正确路径并把 server 留空。 看到这里，就捎带着说说Unix的Socket协议吧。 Socket接口或者叫博克利套接字接口，最初在Unix系统中实现的目的是为了进行进程间的通讯，习惯上被define成AF_UNIX或者PF_UNIX。目前大部分的socket套接的通讯方式已经完全兼容TCP/IP，对于本地的访问进程可以通过raw socket的方式访问socket文件就可以方便的进行通讯。相对于TCP/IP这种IP地址+端口号的方式Unix socket的描述符更像是一个文件路径。 例如在php中 mysql_connect(&#8216;localhost&#8217;, &#8216;mysql_user&#8217;, &#8216;mysql_password&#8217;); 可以替换为 mysql_connect(&#8216;UNIX:/var/run/mysqld/mysqld.sock&#8217;, &#8216;mysql_user&#8217;, &#8216;mysql_password&#8217;); (Ubuntu的默认MysqlSocket的保存路径和Redhat的是不同的，需要注意！) 由于socket的通讯方式相比TCP/IP来说不需要占用带宽，所以在某些情况下可以达到提升性能的目的。而且由于上文所说大部分Socket有意设计的跟TCP/IP协议兼容，故很多情况下可以善用它。 举个例子吧，就说php5.3-fpm + nginx的修改。 默认情况下，php-fpm绑定了本地的9000端口，nginx将请求转发到本地9000号从而实现对php的解析。 我们修改php-fpm.ini文件，如果是apt安装，可以直接修改/etc/php5/fpm/pool.d/www.conf listen = 127.0.0.1:9000 改为 listen = /var/lib/php5/php-fpm.sock php5.3以前的php-fpm是一个xml， &#60;value name=”listen_address”&#62;127.0.0.1:9000&#60;/value&#62; 改为 &#60;value name=”listen_address”&#62;/tmp/php-fpm.sock&#60;/value&#62; 重起php-fpm之后，netstat -an应该没有了对于9000端口的监听，取而代之的是多了这么一行 unix [...]]]></description>
			<content:encoded><![CDATA[<p>PHP的官方文档中，对于mysql_connect函数的介绍中有这么一条信息：<br />
<strong>Note</strong>:<br />
只要将 server 指定为 “localhost” 或 “localhost:port”，MySQL 客户端库会越过此值并尝试连接到本地套接字（Windows 中的名字管道）。如果想用 TCP/IP，应该用 “127.0.0.1&#8243; 代替 “localhost”。如果 MySQL 客户端库试图连接到一个错误的本地套接字，则应该在 PHP 配置中设定的正确路径并把 server 留空。</p>
<p>看到这里，就捎带着说说Unix的Socket协议吧。</p>
<p><span id="more-1756"></span></p>
<p>Socket接口或者叫博克利套接字接口，最初在Unix系统中实现的目的是为了进行进程间的通讯，习惯上被define成AF_UNIX或者PF_UNIX。目前大部分的socket套接的通讯方式已经完全兼容TCP/IP，对于本地的访问进程可以通过raw socket的方式访问socket文件就可以方便的进行通讯。相对于TCP/IP这种IP地址+端口号的方式Unix socket的描述符更像是一个文件路径。</p>
<p>例如在php中 mysql_connect(&#8216;localhost&#8217;, &#8216;mysql_user&#8217;, &#8216;mysql_password&#8217;); 可以替换为 mysql_connect(&#8216;UNIX:/var/run/mysqld/mysqld.sock&#8217;, &#8216;mysql_user&#8217;, &#8216;mysql_password&#8217;); (Ubuntu的默认MysqlSocket的保存路径和Redhat的是不同的，需要注意！)</p>
<p>由于socket的通讯方式相比TCP/IP来说不需要占用带宽，所以在某些情况下可以达到提升性能的目的。而且由于上文所说大部分Socket有意设计的跟TCP/IP协议兼容，故很多情况下可以善用它。</p>
<p>举个例子吧，就说php5.3-fpm + nginx的修改。</p>
<p>默认情况下，php-fpm绑定了本地的9000端口，nginx将请求转发到本地9000号从而实现对php的解析。</p>
<p>我们修改php-fpm.ini文件，如果是apt安装，可以直接修改/etc/php5/fpm/pool.d/www.conf</p>
<p>listen = 127.0.0.1:9000 改为 listen = /var/lib/php5/php-fpm.sock</p>
<p>php5.3以前的php-fpm是一个xml，</p>
<p>&lt;value name=”listen_address”&gt;127.0.0.1:9000&lt;/value&gt; 改为 &lt;value name=”listen_address”&gt;/tmp/php-fpm.sock&lt;/value&gt;</p>
<p>重起php-fpm之后，netstat -an应该没有了对于9000端口的监听，取而代之的是多了这么一行</p>
<p>unix 2 [ ACC ] STREAM LISTENING 124099 /var/lib/php5/php-fpm.sock</p>
<p>修改nginx配置：</p>
<p>location ~ \.php$ {<br />
    #fastcgi_pass 127.0.0.1:9000;<br />
    fastcgi_pass unix:/var/lib/php5/php-fpm.sock;<br />
    fastcgi_index index.php;<br />
    include fastcgi_params;<br />
}</p>
<p>重起Nginx，成功！</p>
]]></content:encoded>
			<wfw:commentRss>http://www.litrin.net/2012/04/19/unix%e7%9a%84socket%e5%8d%8f%e8%ae%ae/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>几种Python C重构的性能差异</title>
		<link>http://www.litrin.net/2012/04/10/%e5%87%a0%e7%a7%8dpython-c%e9%87%8d%e6%9e%84%e7%9a%84%e6%80%a7%e8%83%bd%e5%b7%ae%e5%bc%82/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=%25e5%2587%25a0%25e7%25a7%258dpython-c%25e9%2587%258d%25e6%259e%2584%25e7%259a%2584%25e6%2580%25a7%25e8%2583%25bd%25e5%25b7%25ae%25e5%25bc%2582</link>
		<comments>http://www.litrin.net/2012/04/10/%e5%87%a0%e7%a7%8dpython-c%e9%87%8d%e6%9e%84%e7%9a%84%e6%80%a7%e8%83%bd%e5%b7%ae%e5%bc%82/#comments</comments>
		<pubDate>Tue, 10 Apr 2012 06:46:40 +0000</pubDate>
		<dc:creator>Litrin</dc:creator>
				<category><![CDATA[Coding]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://www.litrin.net/?p=1753</guid>
		<description><![CDATA[C重构，C重构，看的已经有点郁闷了！这次打算收尾了，将几种方法的性能做个横向比较吧，近期不再研究。 相关文章： Cython快速实现Python的C重构 Cython快速实现Python的C重构 &#160; 老一套的python源码： def sheepBorn(i):     if i &#60; 1:         return 0     elif i &#60; 2:         return 1     return sheepBorn(i-1) + sheepBorn(i-2) - sheepBorn(i-5) 和计时测试借口： import time from sheepBorn import sheepBorn startTime = time.time() print sheepBorn(32) print time.time() - startTime 直接Python的测试结果耗时15.7993621826秒。 在不修改任何代码的情况下把它通过Cython编译为.so文件再测试一遍， 9.83871483803，有差距了！ 修改为面向Cython优化过的pyx文件 def sheepBorn(int i): cdef [...]]]></description>
			<content:encoded><![CDATA[<p>C重构，C重构，看的已经有点郁闷了！这次打算收尾了，将几种方法的性能做个横向比较吧，近期不再研究。</p>
<p>相关文章：</p>
<ul>
<li><a rel="nofollow" target="_blank" title="Permanent Link: Cython快速实现Python的C重构" href="../2012/04/04/cython%e5%bf%ab%e9%80%9f%e5%ae%9e%e7%8e%b0python%e7%9a%84c%e9%87%8d%e6%9e%84/" rel="bookmark">Cython快速实现Python的C重构</a></li>
<li><a rel="nofollow" target="_blank" title="Permanent Link: Cython快速实现Python的C重构" href="../2012/04/04/cython%e5%bf%ab%e9%80%9f%e5%ae%9e%e7%8e%b0python%e7%9a%84c%e9%87%8d%e6%9e%84/" rel="bookmark">Cython快速实现Python的C重构</a></li>
</ul>
<p>&nbsp;</p>
<p><span id="more-1753"></span></p>
<p>老一套的python源码：</p>
<pre>def sheepBorn(i):
    if i &lt; 1:
        return 0
    elif i &lt; 2:
        return 1
    return sheepBorn(i-1) + sheepBorn(i-2) - sheepBorn(i-5)</pre>
<p>和计时测试借口：</p>
<pre>import time
from sheepBorn import sheepBorn

startTime = time.time()
print sheepBorn(32)
print time.time() - startTime</pre>
<p>直接Python的测试结果耗时15.7993621826秒。</p>
<p>在不修改任何代码的情况下把它通过Cython编译为.so文件再测试一遍，</p>
<p>9.83871483803，有差距了！</p>
<p>修改为面向Cython优化过的pyx文件</p>
<pre>def sheepBorn(int i):
    cdef int a
    if i &lt; 1:
        a = 0
    elif i &lt; 2:
        a = 1
    else:
        a = sheepBorn(i-1) + sheepBorn(i-2) - sheepBorn(i-5)

    return a</pre>
<p>说实话，由于算法已经足够精简了，代码上几乎没有变化。<br />
测试结果是7.72257995605，也就是一行的变动，导致了不错的提升！</p>
<p>Continue!</p>
<p>察看转换过程中的C中间文件，找到了 static PyObject *__pyx_pf_9sheepBorn_sheepBorn(PyObject *__pyx_self, PyObject *__pyx_arg_i)函数，很臃肿，简单的优化了一下：</p>
<pre>static int py_sheepBorn(int i)
{
     if (i &amp;lt 1) return 0;
     if (i &amp;lt 2) return 1;
     return py_sheepBorn(i -1) + py_sheepBorn(i-2) - py_sheepBorn(i-5);
}
//修改部分略过</pre>
<p>重新编译为python 的 so扩展<br />
gcc -pthread -fno-strict-aliasing -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes -fPIC -I/usr/include/python2.7 -c sheepBorn.c -o build/temp.linux-x86_64-2.7/sheepBorn.o<br />
gcc -pthread -shared -Wl,-O1 -Wl,-Bsymbolic-functions -Wl,-Bsymbolic-functions build/temp.linux-x86_64-2.7/sheepBorn.o -o /root/ctype/cython/sheepBorn.so<br />
测试结果0.174817800522，这是极限吗？</p>
]]></content:encoded>
			<wfw:commentRss>http://www.litrin.net/2012/04/10/%e5%87%a0%e7%a7%8dpython-c%e9%87%8d%e6%9e%84%e7%9a%84%e6%80%a7%e8%83%bd%e5%b7%ae%e5%bc%82/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>我职业发展中的纠结</title>
		<link>http://www.litrin.net/2012/04/08/%e6%88%91%e8%81%8c%e4%b8%9a%e5%8f%91%e5%b1%95%e4%b8%ad%e7%ba%a0%e7%bb%93/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=%25e6%2588%2591%25e8%2581%258c%25e4%25b8%259a%25e5%258f%2591%25e5%25b1%2595%25e4%25b8%25ad%25e7%25ba%25a0%25e7%25bb%2593</link>
		<comments>http://www.litrin.net/2012/04/08/%e6%88%91%e8%81%8c%e4%b8%9a%e5%8f%91%e5%b1%95%e4%b8%ad%e7%ba%a0%e7%bb%93/#comments</comments>
		<pubDate>Sun, 08 Apr 2012 14:13:33 +0000</pubDate>
		<dc:creator>Litrin</dc:creator>
				<category><![CDATA[站长的blog]]></category>
		<category><![CDATA[业界话题]]></category>

		<guid isPermaLink="false">http://www.litrin.net/?p=1734</guid>
		<description><![CDATA[算起来在这过去的2年，可能是我职业生涯中工作变化最频繁的一段时间，频繁到了我甚至都会产生所谓的惯性，习惯性的打探xx公司在忙些什么，缺不缺人之类的话题，甚至说差点仅仅为了薪资而去跳槽，自己都觉得这样不是什么好现象。 工作的频繁变动不排除一方面有公司的因素或者说项目的因素存在，但另一方面，我还是觉得目前个人的职业发展出现了瓶颈，很难找到一个突破口，翻来覆去都是一些重复，重复，再重复。当收入水平上可以满足一定的生活现状的条件下，时间一长在惰性的干预下，就会到达到所谓职业的稳定期。加上由于年龄和家庭的影响，我很害怕今后将难有大的突破。由于IT行业本身的特性，“稳定”事实上是“后退”“下滑”之类词语的婉转用法。“Keep huger, Keep thinking! (－Steven Jobs)” ，这两者之间的关系确实是紧密的。 总之，我深怕自己陷入由来已久的“工程师30岁现象”中去。 之前相对来说公司都是以创业型或者发展型企业为主，对于我们这样的技术人员来说，这样的公司能够提供一个成长中的平台。随着公司的发展，只要你愿意接触，很容易在各个方面上有所提升，进步也是很明显的。但缺点在于，如果一个技术人员始终处于这种状态下，久而久之技术上是够全面的了，由于平台的容量所限，往往在一段时间内，很难在某一方面有所精通，达到所谓的专家级别。所谓“小公司出全才，大公司出专才。”是有道理的。 举个例子，就拿做网站架构来说，在创业型公司里，由于一切都是新的，加之有前车之鉴，而且在可预见的时间内得到“摩尔定律”的眷顾没有什么技术上的难题，团队合作上也没有什么顾及，可以肆无忌惮的用一些很花哨的东西，甚至可以肆无忌惮的修改需求以适应这些东西。一旦成品出现，这些花哨的东西，足够成为你取笑老牌网站的资本。但当一个创业型企业实现蜕变，成为一个成熟型企业时，网站的访问量达到了一定规模，团队规模也足够庞大，这个时候，起作用的更多的是“物种起源”而不是“摩尔定律”。不管是技术架构还是管理架构都会出现不适应的问题，那些花哨的东西成为华而不实的鸡肋，既不能拿掉，也无法推翻重来。况且这个时候团队内部的配合、团队间的配合也远远不是当初时那么的顺畅和简单。说1＋1&#60;2尚且是乐观主义者，事实上1＋1&#60;1的情况也不在少数。后来的人不明就里，处于各种目的，无一例外的痛斥前人留下的烂摊子，如果整个公司的所有部门都是如此面貌的话，不客气的说，这样的公司无法实现蜕变，要么几十年如一日始终处于创业期（貌似没有这样的公司），要么干脆关门大吉。 我这里说的“发展型公司”和“成熟的公司”并非指的是公司大小和规模，而是指一个公司从职位设置到规章制度都有章可循。对于一个相对成熟的公司来说，各方面的资源相对完善，各个岗位都是专注于某一特定内容。关注一个问题更多并不是“如何实现”，而是“如何控制”。在“可控”的前提下，他们更多的愿意以专业的人去处理专业的事情，“顶岗”是绝对失控的表现，不会被轻易的允许。这也就意味着在其中的人特别是技术出身的人的工作范围被压缩到了一个狭长的位置，只能定向去发展，最终的目标是“悟净”，而不是“悟空”——相对大师兄的呼风唤雨，却又状况百出，沙师弟只要把那么几句经典台词说好就可以了。沙僧易找，悟空难寻，这么做本身就是为了防止失控。但由于过度的追求“可控”，“悟空”被加上了过多的紧箍咒，畏首畏脚，很难发挥，久而久之也将成为“悟净”！ 对于身处其中的技术人员来说，在经过了创业型公司不断发展的洗礼之后，兴许已经积累的足够的资本，而且工作方式上也形成了足够强烈的惯性。或许已经很难再去适应一个成熟企业的方方面面。如果没有足够的准备，他也很难再去适应一个企业的蜕变。从另一方面来说，对于成熟公司的员工一旦成了习惯，如果不是创业公司的核心团队，他将很难适应创业初期的失控局面，同样也要需要不断的适应。我有幸的是能将自己的爱好、性格和职业做到了比较好的统一，对于这种适应已经逐步的感到了力不从心，对于很多没有如此幸运的人来说，这个适应本身就更加成为了一种累赘。 目前的国内互联网公司的创业很容易，门槛足够低，但这些也导致了成功转型的不够多，大多数的互联网公司最终都没能够成功。即便所谓成功的互联网企业，说句老实话，大多都是成为某些国外巨头或者国内更大型企业的模仿抄袭或／和附庸而已。很难说是开创了新思路、新市场、新平台什么的。这对于一个30岁左右，已经有了足够职业沉淀的技术人员来说， 年少轻狂时代的冲劲已经荡然无存 ，单从项目上很难说有吸引力，或者从工作内容上讲他已经有所厌倦；接近10年的工作经验可能已经让他们看透了这个行业的起起落落，某些“奶酪”已经被动过了，失去了原先的激励效果；来自生活的压力要求他更多的想要更稳定的收入或者是更多的收入，而这个时候的等待他们可能并非是单纯技术层面的转变，甚至来自职业上的转型都迫在眉睫。兴许这就是前面说到的 “工程师30岁现象”的由来。 &#160; 我一直尽可能的想要避免这个问题，然而它却不可避免的悄悄来临了⋯⋯]]></description>
			<content:encoded><![CDATA[<p>算起来在这过去的2年，可能是我职业生涯中工作变化最频繁的一段时间，频繁到了我甚至都会产生所谓的惯性，习惯性的打探xx公司在忙些什么，缺不缺人之类的话题，甚至说差点仅仅为了薪资而去跳槽，自己都觉得这样不是什么好现象。</p>
<p>工作的频繁变动不排除一方面有公司的因素或者说项目的因素存在，但另一方面，我还是觉得目前个人的职业发展出现了瓶颈，很难找到一个突破口，翻来覆去都是一些重复，重复，再重复。当收入水平上可以满足一定的生活现状的条件下，时间一长在惰性的干预下，就会到达到所谓职业的稳定期。加上由于年龄和家庭的影响，我很害怕今后将难有大的突破。由于IT行业本身的特性，“稳定”事实上是“后退”“下滑”之类词语的婉转用法。“<em>Keep huger, Keep thinking!</em> (－<em>Steven Jobs</em>)” ，这两者之间的关系确实是紧密的。</p>
<p>总之，我深怕自己陷入由来已久的“工程师30岁现象”中去。</p>
<p><span id="more-1734"></span></p>
<p>之前相对来说公司都是以创业型或者发展型企业为主，对于我们这样的技术人员来说，这样的公司能够提供一个成长中的平台。随着公司的发展，只要你愿意接触，很容易在各个方面上有所提升，进步也是很明显的。但缺点在于，如果一个技术人员始终处于这种状态下，久而久之技术上是够全面的了，由于平台的容量所限，往往在一段时间内，很难在某一方面有所精通，达到所谓的专家级别。所谓“小公司出全才，大公司出专才。”是有道理的。</p>
<p>举个例子，就拿做网站架构来说，在创业型公司里，由于一切都是新的，加之有前车之鉴，而且在可预见的时间内得到“摩尔定律”的眷顾没有什么技术上的难题，团队合作上也没有什么顾及，可以肆无忌惮的用一些很花哨的东西，甚至可以肆无忌惮的修改需求以适应这些东西。一旦成品出现，这些花哨的东西，足够成为你取笑老牌网站的资本。但当一个创业型企业实现蜕变，成为一个成熟型企业时，网站的访问量达到了一定规模，团队规模也足够庞大，这个时候，起作用的更多的是“物种起源”而不是“摩尔定律”。不管是技术架构还是管理架构都会出现不适应的问题，那些花哨的东西成为华而不实的鸡肋，既不能拿掉，也无法推翻重来。况且这个时候团队内部的配合、团队间的配合也远远不是当初时那么的顺畅和简单。说1＋1&lt;2尚且是乐观主义者，事实上1＋1&lt;1的情况也不在少数。后来的人不明就里，处于各种目的，无一例外的痛斥前人留下的烂摊子，如果整个公司的所有部门都是如此面貌的话，不客气的说，这样的公司无法实现蜕变，要么几十年如一日始终处于创业期（貌似没有这样的公司），要么干脆关门大吉。</p>
<p>我这里说的“发展型公司”和“成熟的公司”并非指的是公司大小和规模，而是指一个公司从职位设置到规章制度都有章可循。对于一个相对成熟的公司来说，各方面的资源相对完善，各个岗位都是专注于某一特定内容。关注一个问题更多并不是“如何实现”，而是“如何控制”。在“可控”的前提下，他们更多的愿意以专业的人去处理专业的事情，“顶岗”是绝对失控的表现，不会被轻易的允许。这也就意味着在其中的人特别是技术出身的人的工作范围被压缩到了一个狭长的位置，只能定向去发展，最终的目标是“悟净”，而不是“悟空”——相对大师兄的呼风唤雨，却又状况百出，沙师弟只要把那么几句经典台词说好就可以了。沙僧易找，悟空难寻，这么做本身就是为了防止失控。但由于过度的追求“可控”，“悟空”被加上了过多的紧箍咒，畏首畏脚，很难发挥，久而久之也将成为“悟净”！</p>
<p>对于身处其中的技术人员来说，在经过了创业型公司不断发展的洗礼之后，兴许已经积累的足够的资本，而且工作方式上也形成了足够强烈的惯性。或许已经很难再去适应一个成熟企业的方方面面。如果没有足够的准备，他也很难再去适应一个企业的蜕变。从另一方面来说，对于成熟公司的员工一旦成了习惯，如果不是创业公司的核心团队，他将很难适应创业初期的失控局面，同样也要需要不断的适应。我有幸的是能将自己的爱好、性格和职业做到了比较好的统一，对于这种适应已经逐步的感到了力不从心，对于很多没有如此幸运的人来说，这个适应本身就更加成为了一种累赘。</p>
<p>目前的国内互联网公司的创业很容易，门槛足够低，但这些也导致了成功转型的不够多，大多数的互联网公司最终都没能够成功。即便所谓成功的互联网企业，说句老实话，大多都是成为某些国外巨头或者国内更大型企业的模仿抄袭或／和附庸而已。很难说是开创了新思路、新市场、新平台什么的。这对于一个30岁左右，已经有了足够职业沉淀的技术人员来说， 年少轻狂时代的冲劲已经荡然无存 ，单从项目上很难说有吸引力，或者从工作内容上讲他已经有所厌倦；接近10年的工作经验可能已经让他们看透了这个行业的起起落落，某些“奶酪”已经被动过了，失去了原先的激励效果；来自生活的压力要求他更多的想要更稳定的收入或者是更多的收入，而这个时候的等待他们可能并非是单纯技术层面的转变，甚至来自职业上的转型都迫在眉睫。兴许这就是前面说到的 “工程师30岁现象”的由来。</p>
<p>&nbsp;</p>
<p>我一直尽可能的想要避免这个问题，然而它却不可避免的悄悄来临了⋯⋯</p>
]]></content:encoded>
			<wfw:commentRss>http://www.litrin.net/2012/04/08/%e6%88%91%e8%81%8c%e4%b8%9a%e5%8f%91%e5%b1%95%e4%b8%ad%e7%ba%a0%e7%bb%93/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Cython快速实现Python的C重构</title>
		<link>http://www.litrin.net/2012/04/04/cython%e5%bf%ab%e9%80%9f%e5%ae%9e%e7%8e%b0python%e7%9a%84c%e9%87%8d%e6%9e%84/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=cython%25e5%25bf%25ab%25e9%2580%259f%25e5%25ae%259e%25e7%258e%25b0python%25e7%259a%2584c%25e9%2587%258d%25e6%259e%2584</link>
		<comments>http://www.litrin.net/2012/04/04/cython%e5%bf%ab%e9%80%9f%e5%ae%9e%e7%8e%b0python%e7%9a%84c%e9%87%8d%e6%9e%84/#comments</comments>
		<pubDate>Wed, 04 Apr 2012 06:59:32 +0000</pubDate>
		<dc:creator>Litrin</dc:creator>
				<category><![CDATA[Coding]]></category>
		<category><![CDATA[网络和安全]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://www.litrin.net/?p=1724</guid>
		<description><![CDATA[忘掉这篇愚人节玩笑吧，这次我们要动真格的了！ 说起Python，首先想到的他是一种“胶水语言”。作为一种合格的胶水语言，比起开发的难易程度或者开发效率来讲，语言的适应性和可扩充性同样很重要。python的一大特色是有许多方便灵活的扩展模块。 对于上次我们曾经说过ctypes的方式可能对于已经存在的lib库，这对于已经存在的C libs或者有C程序员参与的情况下是很方便的，但对于很多团队来说，合格的C程序员始终是个缺口。这次我们就说说针对单独的一个模块通过Python的一个扩展Cython进行C重构，从而达到尽可能减少工作量，从而达到最便捷的C重构。 在此之前，安装cython和python-dev（需要Python.h文件参与） apt-get install python python-dev python原文件，这次选择的是“费波拉契数列”的计算： fib.py def fib(i): a = 0 b = 1 while i &#62; 0: i -= 1 a, b = b, a+b return True startTest.py import time from fib import fib startTime = time.time() for i in xrange(1,10): fib(10**6) print time.time() - startTime 执行 python startTest.py得到的运行时间是130.857528925，两分多钟。 [...]]]></description>
			<content:encoded><![CDATA[<p>忘掉<a href="http://www.litrin.net/2012/04/01/%e6%97%a0%e9%a1%bbcoding%e5%bf%ab%e9%80%9f%e5%ae%9e%e7%8e%b0python%e7%9a%84c%e9%87%8d%e6%9e%84/" title="无须coding快速实现Python的C重构">这篇愚人节玩笑</a>吧，这次我们要动真格的了！</p>
<p>说起Python，首先想到的他是一种“胶水语言”。作为一种合格的胶水语言，比起开发的难易程度或者开发效率来讲，语言的适应性和可扩充性同样很重要。python的一大特色是有许多方便灵活的扩展模块。</p>
<p>对于上次我们曾经说过ctypes的方式可能对于已经存在的lib库，这对于已经存在的C libs或者有C程序员参与的情况下是很方便的，但对于很多团队来说，合格的C程序员始终是个缺口。这次我们就说说针对单独的一个模块通过Python的一个扩展Cython进行C重构，从而达到尽可能减少工作量，从而达到最便捷的C重构。</p>
<p><span id="more-1724"></span></p>
<p>在此之前，安装cython和python-dev（需要Python.h文件参与）</p>
<p>apt-get install python python-dev</p>
<p>python原文件，这次选择的是“费波拉契数列”的计算：</p>
<p>fib.py</p>
<pre class="py" name=code>
def fib(i):
    a = 0
    b = 1
    while i &gt; 0:
        i -= 1
        a, b = b, a+b

    return True</pre>
<p>startTest.py</p>
<pre class="py" name=code>
import time
from fib import fib

startTime = time.time()
for i in xrange(1,10):
    fib(10**6)

print time.time() - startTime
</pre>
<p>执行 python startTest.py得到的运行时间是130.857528925，两分多钟。</p>
<p>准备编译脚本，虽然违背了没有coding，但请相信,代码真的很少</p>
<p>&nbsp;</p>
<p>build.py</p>
<pre class="py" name=code>

from distutils.core import setup
from distutils.extension import Extension
from Cython.Distutils import build_ext

setup(

cmdclass = {'build_ext': build_ext},

ext_modules = [Extension("fib", ["fib.py"])]

)
</pre>
<p>开始编译：</p>
<pre>
root@Vhost2:~/testCython# python build.py build_ext --inplace

running build_ext

cythoning fib.py to fib.c

building 'fib' extension

creating build

creating build/temp.linux-x86_64-2.7

gcc -pthread -fno-strict-aliasing -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes -fPIC -I/usr/include/python2.7 -c fib.c -o build/temp.linux-x86_64-2.7/fib.o

gcc -pthread -shared -Wl,-O1 -Wl,-Bsymbolic-functions -Wl,-Bsymbolic-functions build/temp.linux-x86_64-2.7/fib.o -o /root/testCython/fib.so
</pre>
<p>当前目录下应该多出来一个fib.c和fib.so，不要怀疑，.c的那个就是C的源码，而.so则是基于c 的python 扩展。如果你有实力可以在.c文件上进行人肉优化，我想效率也远高于从0开始。其中比较好的一点是，C源码中，python的源码会作为注释添加其中，看起来也很方便。</p>
<p>本文主要介绍的是cython，对于生成出来C代码的优劣不在讨论中，有兴趣欢迎私下交流。</p>
<p>开始新的测试：</p>
<p>删除原来的py库，mv fib.py fib.py.bak &amp;&amp; rm -f *.pyc</p>
<p>python startTest.py</p>
<p>得出结果105.579359305，汗！没有想象中的那么突飞猛进。通过cProfile的导出，没有看出什么名堂。<br />
<a href="http://www.litrin.net/wp-content/uploads/2012/04/python.png"><img src="http://www.litrin.net/wp-content/uploads/2012/04/python-146x300.png" alt="" title="python" width="146" height="300" class="aligncenter size-medium wp-image-1732" /></a></p>
<p><a href="http://www.litrin.net/wp-content/uploads/2012/04/C.png"><img src="http://www.litrin.net/wp-content/uploads/2012/04/C-123x300.png" alt="" title="C" width="123" height="300" class="aligncenter size-medium wp-image-1731" /></a></p>
<p>事实上查看了C源码，发觉事实上大量的代码实现的仍旧是Python的逻辑，而Python的效率跟C绝对不是一个等级。这当然存在更加有优势的优化方式，但已经脱离了“快速实现”的本质，本文不再介绍。</p>
<p>考虑到“费波拉契数列”是python实现的经典例子，我重新改动了代码。（方便测试，连函数名都没动，容易误导）</p>
<p>fib.py</p>
<pre class="py" name=code>
def fib(i):
    a = 0

    while i &gt; 0:
        a += i
        i -= 1

return a
</pre>
<p>6.1317088604 : 4.3963329792算是比较显著了吧。</p>
<p>对于编译后的脚本来说，个人觉得性能的提升只是一方面的优势。特别是一些对安全性有要求的应用中，编译后的代码隐蔽性较好，在生产环境中即便别人获得了你的服务器权限，也很难反拆你的算法，避免了很多麻烦。</p>
<p>需要注意的是，对于yield方式实现的迭代器，cython无法完成编译，只能重新修改代码，但对于大多数的代码来说，cython几乎是平滑的。而且你甚至可以写一个全自动的部署脚本，上线后自动完成编译。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.litrin.net/2012/04/04/cython%e5%bf%ab%e9%80%9f%e5%ae%9e%e7%8e%b0python%e7%9a%84c%e9%87%8d%e6%9e%84/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>无须coding快速实现Python的C重构</title>
		<link>http://www.litrin.net/2012/04/01/%e6%97%a0%e9%a1%bbcoding%e5%bf%ab%e9%80%9f%e5%ae%9e%e7%8e%b0python%e7%9a%84c%e9%87%8d%e6%9e%84/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=%25e6%2597%25a0%25e9%25a1%25bbcoding%25e5%25bf%25ab%25e9%2580%259f%25e5%25ae%259e%25e7%258e%25b0python%25e7%259a%2584c%25e9%2587%258d%25e6%259e%2584</link>
		<comments>http://www.litrin.net/2012/04/01/%e6%97%a0%e9%a1%bbcoding%e5%bf%ab%e9%80%9f%e5%ae%9e%e7%8e%b0python%e7%9a%84c%e9%87%8d%e6%9e%84/#comments</comments>
		<pubDate>Sun, 01 Apr 2012 07:00:01 +0000</pubDate>
		<dc:creator>Litrin</dc:creator>
				<category><![CDATA[站长的blog]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[服务器]]></category>
		<category><![CDATA[桌面应用]]></category>
		<category><![CDATA[硬件相关]]></category>

		<guid isPermaLink="false">http://www.litrin.net/?p=1719</guid>
		<description><![CDATA[正如之前说的，很多情况下我们需要对代码中的部分甚至于全部进行基于C语言的重构以大幅提升性能。对于很多团队来说，由于C语言过于复杂，很难像Python，PHP或者其他高级语言那样快速上手。本文就着重介绍如何通过现有的资源，快速的将python转成C而尽可能的减少工作量。同样的，这种方式稍加修改就可以适用于PHP以及其他的解释型高级语言。同样适用于桌面系统的代码调优。 照旧，先放上例子： def test(i): x = 0 while i &#62; 0: i -= 1 x += i return x 想必各位都能看懂段代码吧，不懂得话，请直接跳过。 由于C对于类型的判断强于Python，为了方便起见，建议整理一篇文档，以保证出入参数时不会报错。大致如下： 方法名：test 方法简介：计算从0到i的总数 入参：int  i 返回：int x 为了更清晰，我习惯上画一个流程图： &#160; 把上面的文档整理一下，找一个会C的朋友。一般来说，可以遵循以下流程： 需要注意的是。为了保证成本最低，一定要从-1元开始出价，这样在流程第二步加价1元之后，你仍然不需要出钱，当然你也可以从-10000开始。考虑到程序要适应大多数情况，而不是个别情况，个人强力推荐从-1开始！ 之后需要一定转换时间，视具体需求而定，如果你的项目像我的一样简单，这个过程应该不会太久。 转换出来的代码大致如下： int test(int i) { int x = 0; while(i &#60; 0) x += --i; return x; } 完全可以部署的代码！ 祝大家节日愉快！ PS：如果您来访问的日期不是某年的4月1日的话，请去这里查看。]]></description>
			<content:encoded><![CDATA[<p>正如之前说的，很多情况下我们需要对代码中的部分甚至于全部进行基于C语言的重构以大幅提升性能。对于很多团队来说，由于C语言过于复杂，很难像Python，PHP或者其他高级语言那样快速上手。本文就着重介绍如何通过现有的资源，快速的将python转成C而尽可能的减少工作量。同样的，这种方式稍加修改就可以适用于PHP以及其他的解释型高级语言。同样适用于桌面系统的代码调优。</p>
<p>照旧，先放上例子：</p>
<pre class="py" name=code>
def test(i):
    x = 0
    while i &gt; 0:
        i -= 1
        x += i
    return x</pre>
<p>想必各位都能看懂段代码吧，不懂得话，请直接跳过。<br />
<span id="more-1719"></span><br />
由于C对于类型的判断强于Python，为了方便起见，建议整理一篇文档，以保证出入参数时不会报错。大致如下：</p>
<ul>
<li>方法名：test</li>
<li>方法简介：计算从0到i的总数</li>
<li>入参：int  i</li>
<li>返回：int x</li>
</ul>
<p>为了更清晰，我习惯上画一个流程图：</p>
<p><a href="http://www.litrin.net/wp-content/uploads/2012/04/python_c_41.png"><img class="aligncenter size-medium wp-image-1720" title="python_c_41" src="http://www.litrin.net/wp-content/uploads/2012/04/python_c_41-235x300.png" alt="" width="235" height="300" /></a></p>
<p>&nbsp;</p>
<p>把上面的文档整理一下，找一个会C的朋友。一般来说，可以遵循以下流程：</p>
<p><a href="http://www.litrin.net/wp-content/uploads/2012/04/python_c_42.png"><img class="aligncenter size-medium wp-image-1721" title="python_c_42" src="http://www.litrin.net/wp-content/uploads/2012/04/python_c_42-300x271.png" alt="" width="300" height="271" /></a></p>
<p>需要注意的是。为了保证成本最低，一定要从-1元开始出价，这样在流程第二步加价1元之后，你仍然不需要出钱，当然你也可以从-10000开始。考虑到程序要适应大多数情况，而不是个别情况，个人强力推荐从-1开始！</p>
<p>之后需要一定转换时间，视具体需求而定，如果你的项目像我的一样简单，这个过程应该不会太久。</p>
<p>转换出来的代码大致如下：</p>
<pre class="cpp" name=code>
int test(int i)
{
    int x = 0;
    while(i &lt; 0) x += --i;
    return x;
}</pre>
<p>完全可以部署的代码！</p>
<p>祝大家节日愉快！</p>
<p>PS：如果您来访问的日期不是某年的4月1日的话，请去<a rel="nofollow" target="_blank" href=http://www.litrin.net/2012/04/04/cython快速实现python的c重构/>这里查看。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.litrin.net/2012/04/01/%e6%97%a0%e9%a1%bbcoding%e5%bf%ab%e9%80%9f%e5%ae%9e%e7%8e%b0python%e7%9a%84c%e9%87%8d%e6%9e%84/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Ubuntu上KVM的快速部署</title>
		<link>http://www.litrin.net/2012/03/19/ubuntu%e4%b8%8akvm%e7%9a%84%e5%bf%ab%e9%80%9f%e9%83%a8%e7%bd%b2/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=ubuntu%25e4%25b8%258akvm%25e7%259a%2584%25e5%25bf%25ab%25e9%2580%259f%25e9%2583%25a8%25e7%25bd%25b2</link>
		<comments>http://www.litrin.net/2012/03/19/ubuntu%e4%b8%8akvm%e7%9a%84%e5%bf%ab%e9%80%9f%e9%83%a8%e7%bd%b2/#comments</comments>
		<pubDate>Mon, 19 Mar 2012 07:01:21 +0000</pubDate>
		<dc:creator>Litrin</dc:creator>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[硬件相关]]></category>
		<category><![CDATA[ubuntu]]></category>
		<category><![CDATA[服务器]]></category>

		<guid isPermaLink="false">http://www.litrin.net/?p=1706</guid>
		<description><![CDATA[之前写过一篇东西：Ubuntu上Xen的快速部署，以及近期的一篇Ubuntu上KVM虚拟化的部署。前一篇东西写的比较早了，Xen已经被KVM所取代，后一篇主要是通过图形化界面来操作，通用性虽强，但效率较低，无法实现批量化。 这次就通过ubuntu自带的一个工具，实现快速的批量化定制基于KVM的Ubuntu的虚拟机。 首先，安装定制包apt-get install ubuntu-vm-builder cd /data/virtual;  ubuntu-vm-builder kvm lucid --debug \ --addpkg=openssh-server --hostname=Webserver --bridge=br0 \ -m 512 --ip=192.168.1.55 --gw=192.168.1.254 --dns=8.8.8.8 -a i386 --user=litrin --password=litrin\ --libvirt qemu:///system 整个系统会自己下载安装镜像，自己静默安装整个系统，剩下的就是慢慢等它结束了，真的很方便！看到中文的资料真的很少，大部分的文档都是贴的，这里我就先讲解几个重要参数吧。 所有的参数除了开头的”Kvm lucid”之外其实都可以省略而采用系统默认值 kvm lucid 安装的版本类型，有个常理：客户版本不能超过宿主版本。即lucid (1004)不可以装natty(1104)，但natty上可以装lucid &#8211;hostname=Webserver 虚拟主机名称，唯一标示 &#8211;debug 输出调试，第一次还是开启吧，至少知道在哪边出错 &#8211;bridge=br0 参见，绑定的网卡名称 -a i386 &#124; &#8211;arch=i386 平台的类型，默认与宿主平台一致 &#8211;cpus=2 虚拟机cpu个数，默认是1 -m512 &#124; &#8211;mem=512 分配的内存大小，默认是128,单位统统是M &#8211;ip=192.168.1.55 &#8211;gw=192.168.1.254 配置虚拟机的IP和网关，默认是DHCP的，对应的&#8211;mac （mac地址）&#8211;mask（掩码）&#8211;net（网络） &#8211;bcast（广播）&#8211;dns（自己猜！） &#8211;user=litrin [...]]]></description>
			<content:encoded><![CDATA[<p>之前写过一篇东西：<a title="Ubuntu上Xen的快速部署" href="http://www.litrin.net/2010/10/08/ubuntu%e4%b8%8axen%e7%9a%84%e5%bf%ab%e9%80%9f%e9%83%a8%e7%bd%b2/">Ubuntu上Xen的快速部署</a>，以及近期的一篇<a title="Ubuntu上KVM虚拟化的部署" href="http://www.litrin.net/2012/01/20/ubuntu%e4%b8%8akvm%e8%99%9a%e6%8b%9f%e5%8c%96%e7%9a%84%e9%83%a8%e7%bd%b2/">Ubuntu上KVM虚拟化的部署</a>。前一篇东西写的比较早了，Xen已经被KVM所取代，后一篇主要是通过图形化界面来操作，通用性虽强，但效率较低，无法实现批量化。</p>
<p>这次就通过ubuntu自带的一个工具，实现快速的批量化定制基于KVM的Ubuntu的虚拟机。</p>
<p><span id="more-1706"></span></p>
<p>首先，安装定制包apt-get install ubuntu-vm-builder</p>
<pre>cd /data/virtual; 
ubuntu-vm-builder kvm lucid --debug \</pre>
<pre>    --addpkg=openssh-server --hostname=Webserver --bridge=br0 \</pre>
<pre>    -m 512 --ip=192.168.1.55 --gw=192.168.1.254 --dns=8.8.8.8</pre>
<pre>    -a i386 --user=litrin --password=litrin\</pre>
<pre>    --libvirt qemu:///system</pre>
<p>整个系统会自己下载安装镜像，自己静默安装整个系统，剩下的就是慢慢等它结束了，真的很方便！看到中文的资料真的很少，大部分的文档都是贴的，这里我就先讲解几个重要参数吧。</p>
<p>所有的参数除了开头的”Kvm lucid”之外其实都可以省略而采用系统默认值<br />
<strong>kvm lucid </strong>安装的版本类型，有个常理：客户版本不能超过宿主版本。即lucid (1004)不可以装natty(1104)，但natty上可以装lucid</p>
<p><strong>&#8211;hostname=Webserver </strong>虚拟主机名称，唯一标示</p>
<p><strong></strong><strong>&#8211;debug</strong> 输出调试，第一次还是开启吧，至少知道在哪边出错</p>
<p><strong>&#8211;bridge=br0</strong> <a href="http://www.litrin.net/2012/01/20/ubuntu%E4%B8%8Akvm%E8%99%9A%E6%8B%9F%E5%8C%96%E7%9A%84%E9%83%A8%E7%BD%B2/">参见</a>，绑定的网卡名称</p>
<p><strong>-a i386 | &#8211;arch=i386</strong> 平台的类型，默认与宿主平台一致</p>
<p><strong>&#8211;cpus=2 </strong>虚拟机cpu个数，默认是1</p>
<p><strong>-m512 | &#8211;mem=512</strong> 分配的内存大小，默认是128,单位统统是M</p>
<p><strong>&#8211;ip=192.168.1.55 &#8211;gw=192.168.1.254 </strong>配置虚拟机的IP和网关，默认是DHCP的，对应的&#8211;mac （mac地址）&#8211;mask（掩码）&#8211;net（网络） &#8211;bcast（广播）&#8211;dns（自己猜！）</p>
<p><strong>&#8211;user=litrin | &#8211;password=litrin </strong> 默认添加的帐户和密码，说到这里，我第一次没有使用这两个参数，而是用默认值，等到都安装好了才发觉根本进不了系统，抱着试试看的心理用ubuntu用户和ubuntu作为密码竟然通过了，看来我的运气好到家了，一下子猜到了默认配置。如果是直接放公网上，为了防止有人跟我一样好运，还是安装的时候就设置好吧。还有一个类似的&#8211;rootpass，不推荐。</p>
<p><strong>&#8211;ssh-key=~/.ssh/authorized_keys </strong>自动添加一个root的ssh的验证公钥。</p>
<p><strong>&#8211;libvirt qemu:///system </strong>把虚拟机直接加到本地的virt-manager中，需要注意的是本机不是Localhost，而是system，有点有悖常理。支持ssh方式远程主机。<br />
<a href="http://www.litrin.net/2012/03/19/ubuntu%e4%b8%8akvm%e7%9a%84%e5%bf%ab%e9%80%9f%e9%83%a8%e7%bd%b2/virt-manager-localurl/" rel="attachment wp-att-1707"><img class="aligncenter size-medium wp-image-1707" title="virt-manager-localurl" src="http://www.litrin.net/wp-content/uploads/2012/03/virt-manager-localurl-300x209.png" alt="" width="300" height="209" /></a><br />
<strong>&#8211;addpkg=openssh-server </strong>安装软件包，可以配置多个。对应的逆向操作：&#8211;removepkg=openssh-server</p>
<p><strong>&#8211;install-mirror </strong>选用Ubuntu的镜像站，如<a rel="nofollow" target="_blank" href="http://mirrors.163.com/ubuntu-releases">http://mirrors.163.com/ubuntu-releases</a></p>
<p><strong>&#8211;iso=~/ubuntu.iso</strong> 直接使用本地的ISO安装，以现在的网络带宽下强力推荐</p>
<p><strong>&#8211;lang=zh_CN.utf-8 </strong>默认字符，默认为en_US.UTF-8</p>
<p><strong> &#8211;timezone=CST </strong>默认时区，默认UTC</p>
<p><strong>&#8211;firstboot=PATH</strong> 首次启动时的脚本，由于通过上面的&#8211;addpkg=openssh-server 方式只会增加ssh的服务端而不会设置为启动项，可以通过这种方式设定。类似的&#8211;firstlogin=PATH，第一次登录脚本。</p>
<p><strong> &#8211;rootsize=SIZE |&#8211;optsize=SIZE |&#8211;swapsize=SIZE</strong> 分别是/ , /opt 和swap的分区大小，默认只有一个3.8G的swap和1G的SWAP需要更详细的配置，则通过&#8211;part=配置文件来操作，配置文件的格式：</p>
<pre>root 2000
 /boot 512
 swap 1000
 ---
 /var 8000
 /var/log 2000</pre>
<p>用&#8212;表示使用新的虚拟磁盘</p>
<p><strong>&#8211;raw=PATH </strong>使用一个裸设备来作为第一个虚拟磁盘，我没有测试过，有兴趣可以试一下。</p>
<p>默认加入virt-manager之后需要手工启动，并默认绑定了本地的5900端口监听vnc服务器，远程主机可以通过<a title="用SSH Tunnel穿越防火墙" href="http://www.litrin.net/2010/02/09/%e7%94%a8ssh-tunnel%e7%a9%bf%e8%b6%8a%e9%98%b2%e7%81%ab%e5%a2%99/">ssh通道</a>，映射成本地5900再连接。不过像我这样用MAC自带的VNC工具就比较悲剧了，它不支持连接本地5900，只能找台中转机了。</p>
<p>PS：</p>
<p>本文由于Wordpress的显示问题，所有的 双线（- -）都被替换成了单线（-），在这里，包括本站所有的文档请遵循Linux的一贯原则：单线后面是单字母配置，空格后面配置参数；双线后面是全配置，单词间用单线，后面用=跟配置。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.litrin.net/2012/03/19/ubuntu%e4%b8%8akvm%e7%9a%84%e5%bf%ab%e9%80%9f%e9%83%a8%e7%bd%b2/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>CoreSeek Python数据源的基类</title>
		<link>http://www.litrin.net/2012/03/14/coreseek-python%e6%95%b0%e6%8d%ae%e6%ba%90%e7%9a%84%e5%9f%ba%e7%b1%bb/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=coreseek-python%25e6%2595%25b0%25e6%258d%25ae%25e6%25ba%2590%25e7%259a%2584%25e5%259f%25ba%25e7%25b1%25bb</link>
		<comments>http://www.litrin.net/2012/03/14/coreseek-python%e6%95%b0%e6%8d%ae%e6%ba%90%e7%9a%84%e5%9f%ba%e7%b1%bb/#comments</comments>
		<pubDate>Wed, 14 Mar 2012 07:30:36 +0000</pubDate>
		<dc:creator>Litrin</dc:creator>
				<category><![CDATA[Coding]]></category>
		<category><![CDATA[数据库应用]]></category>
		<category><![CDATA[DataBase]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://www.litrin.net/?p=1699</guid>
		<description><![CDATA[上次提到过Coreseek的安装一文，我个人建议Coreseek最好采用Python作为数据源，相对灵活性很大。这次我就分享一下我写的一个CoreSeek的Python数据源基类。 这个基类的优势在于特别是对于“分库分表”的MySQL来说，支持直接多进程并发读库，性能超强。而且对于Python2.6以下不具有多进程特性的用户来说，这个基类支持通过线程来模拟进程，完全透明！ 该库已经在生产环境中使用。 需要MySQLdb类包 #!/usr/bin/env python # -*- coding:utf-8 -*- # abs class for CoreSeek indexer data source # #   By Litrin J. 2011-07 # from DBConfig import DBConfig import MySQLdb import datetime, time, types try:     from multiprocessing import Process, Queue except:     from threading import Thread as Process     from Queue import Queue [...]]]></description>
			<content:encoded><![CDATA[<p>上次提到过<a title="Ubuntu上Coreseek+php的安装" href="http://www.litrin.net/2011/06/16/ubuntu%e4%b8%8acoreseekphp%e7%9a%84%e5%ae%89%e8%a3%85/">Coreseek</a>的安装一文，我个人建议Coreseek最好采用Python作为数据源，相对灵活性很大。这次我就分享一下我写的一个CoreSeek的Python数据源基类。</p>
<p>这个基类的优势在于特别是对于“分库分表”的MySQL来说，支持直接多进程并发读库，性能超强。而且对于Python2.6以下不具有多进程特性的用户来说，这个基类支持通过线程来模拟进程，完全透明！</p>
<p>该库已经在生产环境中使用。</p>
<p><span id="more-1699"></span></p>
<p>需要MySQLdb类包</p>
<pre class="py" name=code>
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# abs class for CoreSeek indexer data source
#
#   By Litrin J. 2011-07
#

from DBConfig import DBConfig
import MySQLdb
import datetime, time, types
try:
    from multiprocessing import Process, Queue
except:
    from threading import Thread as Process
    from Queue import Queue

class CoreSeek(object):
    '''
    Abs class for CoreSeek data source.
    '''

    DBName = ""
    #field list, you can use "as" method, just like 'id as uid' to rename the `id` field to uid
    Field = []
    WhereCause = "TRUE"
    #the uniq id in the row for 1 table
    UniqId = None
    Scheme = []
    FieldOrder = []

    SQLGroupBy = ""
    #if the table to long, use it!
    SQLLimit = 0
    #Debug switch
    Debug = False

    MaxProcess = 2

    #private var
    __data = []
    __curItem = []
    __uniqNumber = 0
    __tableList = []
    
    __processPool = []   

    def __init__(self, conf):
        if self.__class__ == CoreSeek:
            raise NotImplementedError, "Cannot create object of class CoreSeek!"

        self.conf = conf
    
    def __del__(self):
        pass

    def __getattr__(self, key):
        if self.UniqId is None and 'id' == key:
            return self.__uniqNumber
        else:
            return self.__curItem[key]
    
    def __iter__(self):
        while self.NextDocument() :
            yield self.__curItem   
 
    def __str__(self):
        return str(self.__curItem)

    def GetScheme(self):  
        return self.Scheme

    def GetFieldOrder(self):
        return self.FieldOrder

    def Connected(self):
        tableList = DBConfig().getDBTableConfig(self.DBName)
        self.__tableList = Queue(len(tableList))
        for dConfig in tableList:
            self.__tableList.put(dConfig)

        self.__data = Queue()
        if (len(tableList) &lt; self.MaxProcess):
            self.MaxProcess = len(tableList)

        for i in range (0, self.MaxProcess):
            process = Process(target=self.getTableData).run()
            self.__processPool.append(process)

    def NextDocument(self, err=None):
        if (  self.__data.empty() == False ):
            self.__curItem = self.__data.get()
            self.__uniqNumber += 1

            if (self.Debug):
                print self
            return True

        iProcessRuning = 0
        for process in self.__processPool:
            if process is not None and process.is_alive():
                iProcessRuning += 1 

        if (iProcessRuning &gt; 0):
            return self.NextDocument()

        else:
            del self.__tableList
            del self.__data
            time.sleep(0.01)
            return False
    
    def getTableData(self):
        if (self.__tableList.empty() ):
            return False

        dConfig = self.__tableList.get()
        
        sSQL = self.getSQL(dConfig["tableName"])
        iCountPreLoad = self.SQLLimit
        iRecordLoaded = 0

        if (iCountPreLoad == 0):
            iRecordLoaded = self.doLoadData(dConfig, sSQL)

        else:
            iStep         = 0
            iRecordCount  = iCountPreLoad
               
            while (iCountPreLoad == iRecordCount):
                sLimit = " LIMIT " + str(iStep * iCountPreLoad ) + ", " + str(iCountPreLoad)
                sLimitSQL = sSQL + sLimit
                
                iRecordCount = self.doLoadData(dConfig, sLimitSQL)

                if (iRecordCount &lt; iCountPreLoad):
                    break
                iRecordLoaded += iRecordCount
                
                iStep += 1

        self.getTableData()

        return True
   
    def doLoadData(self, dConfig, sSQL):

        tableNumber = int(dConfig["tableName"][-2:], 16)

        mysqlHandle = MySQLdb.connect(host=dConfig["host"], user=dConfig["user"],passwd=dConfig["passwd"], db=dConfig["dbName"], charset="UTF8")
        mysqlCursor = mysqlHandle.cursor()

        if (self.Debug):
            print "SQL: " + sSQL

        try:
            mysqlCursor.execute(sSQL)

            lResultList = mysqlCursor.fetchall()
            iRecordCount = len(lResultList)
        
        except:
            return 0
    
        for lRow in lResultList:
            dRow = self.getNamedDict(lRow)
            if self.UniqId is not None:
                dRow["tablerecord"] = [tableNumber, dRow[self.UniqId.lower()]]
                dRow["id"] = int (dRow[self.UniqId.lower()]) * 1000 + tableNumber

            dRow = self.buildIndex(dRow)

            self.__data.put(dRow)                   

        mysqlHandle.close()
        
        return iRecordCount
    
    def getSQL(self, sTableName):
        SQL = "SELECT %s FROM %s WHERE %s " % (", ".join(self.Field), sTableName, self.WhereCause)

        if(self.SQLGroupBy != ""):
            SQL += "GROUP BY %s " % self.SQLGroupBy
        return SQL

    def getNamedDict(self, lRow):
        i = 0
        result = {}
        for sFieldName in self.Field:
            sDictKey = sFieldName.lower()
            if (sDictKey.find(" as ") &gt; 0):
                sDictKey = sDictKey[sDictKey.find(' as ')+4: ]

            if (isinstance(lRow[i], types.StringTypes)):
                result[sDictKey] = lRow[i].encode("utf-8")
            elif (type(lRow[i]) == type(datetime.datetime.today())):
                result[sDictKey] = int(time.mktime(lRow[i].timetuple()))
            else:
                result[sDictKey] = lRow[i]
            i+=1
        
        return result

    def buildIndex(self, *dRow):
        if(self.Debug):
            print dRow

        return dRow

class CoreSeekUtility:

    @staticmethod
    def literallyCut(string, sChar=" ", CharSet="utf-8"):

        uString = string.decode(CharSet)
        iLength = len(uString)
        if (iLength &lt;= 1):
            return string

        lString = [uString[i:i+1] for i in range(0, iLength)]
        sCut = sChar.join(lString)

        return sCut.encode(CharSet)

    @staticmethod
    def dictIndex(dRecord):
        result = ""
        for key in dRecord:
            key = key.upper()
            value = dRecord[key]

            result += key + "=" + str(value) + " "

        return result
</pre>
<p>数据源示例：</p>
<pre class="py" name=code>
from CoreSeek import CoreSeek, CoreSeekUtility
import time

class Topic(CoreSeek):
    Scheme = [
              ('id' , {'docid' : True ,} ),
              ('index', { 'type' : 'text',} ),
              ('index_uid', { 'type' : 'text',} ),

              ('topicid', { 'type' : 'integer'} ),
              ('type', { 'type' : 'integer'} ),
              ('privacy', { 'type' : 'integer'} ),
              ('body', { 'type' : 'string'} ),
              ('title', { 'type' : 'string'} ),
              ('uid', { 'type' : 'string'} ),
              ('description', { 'type' : 'string'} )
          ]

    FieldOrder = [('index', 'index_uid')]
    Field = ["topicId", "uid", "title", 'body', 'privacy', 'description', 'type']

    DBName = "Topic"

    def buildIndex(self, dRow):
        dRow['index_uid'] = dRow['uid']
        dRow['index'] = "%s %s" % (dRow['title'], dRow['description'])

        return dRow

class TopicDelta(Topic):
    WhereCause = "createTime > %s " % (time.time() - 3600)

if __name__ == "__main__":
    conf = {}
    source = Topic(conf)
    source.Connected()

    while source.NextDocument():
        print source
</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.litrin.net/2012/03/14/coreseek-python%e6%95%b0%e6%8d%ae%e6%ba%90%e7%9a%84%e5%9f%ba%e7%b1%bb/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>从“深蓝”到“华生”</title>
		<link>http://www.litrin.net/2012/02/28/%e4%bb%8e%e6%b7%b1%e8%93%9d%e5%88%b0%e5%8d%8e%e7%94%9f/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=%25e4%25bb%258e%25e6%25b7%25b1%25e8%2593%259d%25e5%2588%25b0%25e5%258d%258e%25e7%2594%259f</link>
		<comments>http://www.litrin.net/2012/02/28/%e4%bb%8e%e6%b7%b1%e8%93%9d%e5%88%b0%e5%8d%8e%e7%94%9f/#comments</comments>
		<pubDate>Tue, 28 Feb 2012 04:58:08 +0000</pubDate>
		<dc:creator>Litrin</dc:creator>
				<category><![CDATA[硬件相关]]></category>
		<category><![CDATA[站长的blog]]></category>
		<category><![CDATA[IBM]]></category>
		<category><![CDATA[业界话题]]></category>

		<guid isPermaLink="false">http://www.litrin.net/?p=1691</guid>
		<description><![CDATA[貌似是一年前的旧东西了，当时人正忙，没来的急及时发布。时隔一年，重新整理了一下。可能由于原文的写作时间关系，可能会有时序错乱的情况，希望大家容忍。 这些日子，IT界最为盛大的公关秀莫过于IBM的新一代超级计算机“华生（Watson）”对阵2位智力问答高手，最终计算机胜出。这不免让我想到了“深蓝”对阵卡斯帕罗的象棋赛。两场比赛有着诸多相似：同样的人机对战；同样是号称当时代最强的计算机；同样的“险胜”。当然也不排除IBM方面可能会让对决更加精彩或者更加戏剧化让人印象深刻有意进行了台下交易之类的黑幕。 我个人一直比较推崇IBM，IBM更接近于一个技术研发者，而Google也好Apple也好，更接近一个技术或者产品的推广者。IBM的研发动向可以说是行业的风向标。 15年前的那场象棋赛，尽管至今IBM也没有公布源代码，但根据当初官方宣称的说法是基于“穷举概率”。可以这样理解：“深蓝”在下第一步棋之前就会把棋盘上的所有可能都进行了一次例遍，统计出每一步棋导致最终的胜出概率，然后选择概率最高的那一步。如果这是真的，可以预见的是这绝对是海量的运算。按照当时的标准，台式机刚刚跨入100MHz，这种计算是不可想象的。 直到今天，如果换了我去考虑实现的话（尽管我根本一窍不通），我第一反应将会是分布式计算框架和Map Reduce，而且我相信如果今天有人需要重新实现这一课题时，首选的就是是分布式Map Reduce。选择这个框架的原因主要是考虑到并发的问题，IBM在15年前已经关注了这个方向的问题，尽管Map Reduce的概念是近几年才由Google提出的。可见IBM的先知先觉。 正如15年前一样，今天IBM到底要向我们展示什么技术上的革新呢？我的理解是“语义分析”，“自然语句合成”，“海量数据检索”这3个方面。如何让计算机“听懂”自然语音是这一个阶段有待突破的问题（注：当初还没有ip4s和Siri）。之前还看到过报道，亚马逊为了节约成本，将呼叫中心部署在菲律宾，通过当地廉价的劳动成本为欧美国家服务。从这个侧面可以反应出大型服务企业在应对人工语音服务的一种无奈。不去说远的，抛开识别语音不谈，哪怕是对自然语句的理，也是目前计算机行业的难题之一。解假设目前有这么一种机器人程序能够实现大部分淘宝店家的“阿里旺旺”的职守功能，只要出得起这个价钱的话，相信很快就会成为网店必备。此外还有对于同声传译的突破……种种的难题解答的可能性都能在这次智力问答中得到展示。 之前的比赛更多的是展现了IBM强悍的机能，今天的比赛展示更多的则是在此强悍机能之上强大的软件能力。与其说是2场比赛，不如说是一场比赛，只是中场休息了太长时间，在此期间，我们经历了M到G级别的硬件更新，经历了互联网的崛起，经历了Window3到windows7……但终究还是面临了这样一个问题：“我们有了如此强悍的硬件之后，到底该如何驾驭？难道只是为了测评软件的得分去买硬件吗？”IBM已经用下半场的比赛回答了我们：“No！还有更多的难题需要我们去升级硬件。” 我很期待下一个15年的比赛！]]></description>
			<content:encoded><![CDATA[<p>貌似是一年前的旧东西了，当时人正忙，没来的急及时发布。时隔一年，重新整理了一下。可能由于原文的写作时间关系，可能会有时序错乱的情况，希望大家容忍。</p>
<p>这些日子，IT界最为盛大的公关秀莫过于IBM的新一代超级计算机“华生（Watson）”对阵2位智力问答高手，最终计算机胜出。这不免让我想到了“深蓝”对阵卡斯帕罗的象棋赛。两场比赛有着诸多相似：同样的人机对战；同样是号称当时代最强的计算机；同样的“险胜”。当然也不排除IBM方面可能会让对决更加精彩或者更加戏剧化让人印象深刻有意进行了台下交易之类的黑幕。</p>
<p><span id="more-1691"></span></p>
<p>我个人一直比较推崇IBM，IBM更接近于一个技术研发者，而Google也好Apple也好，更接近一个技术或者产品的推广者。IBM的研发动向可以说是行业的风向标。</p>
<p>15年前的那场象棋赛，尽管至今IBM也没有公布源代码，但根据当初官方宣称的说法是基于“穷举概率”。可以这样理解：“深蓝”在下第一步棋之前就会把棋盘上的所有可能都进行了一次例遍，统计出每一步棋导致最终的胜出概率，然后选择概率最高的那一步。如果这是真的，可以预见的是这绝对是海量的运算。按照当时的标准，台式机刚刚跨入100MHz，这种计算是不可想象的。<br />
直到今天，如果换了我去考虑实现的话（尽管我根本一窍不通），我第一反应将会是分布式计算框架和Map Reduce，而且我相信如果今天有人需要重新实现这一课题时，首选的就是是分布式Map Reduce。选择这个框架的原因主要是考虑到并发的问题，IBM在15年前已经关注了这个方向的问题，尽管Map Reduce的概念是近几年才由Google提出的。可见IBM的先知先觉。</p>
<p>正如15年前一样，今天IBM到底要向我们展示什么技术上的革新呢？我的理解是“语义分析”，“自然语句合成”，“海量数据检索”这3个方面。如何让计算机“听懂”自然语音是这一个阶段有待突破的问题（注：当初还没有ip4s和Siri）。之前还看到过报道，亚马逊为了节约成本，将呼叫中心部署在菲律宾，通过当地廉价的劳动成本为欧美国家服务。从这个侧面可以反应出大型服务企业在应对人工语音服务的一种无奈。不去说远的，抛开识别语音不谈，哪怕是对自然语句的理，也是目前计算机行业的难题之一。解假设目前有这么一种机器人程序能够实现大部分淘宝店家的“阿里旺旺”的职守功能，只要出得起这个价钱的话，相信很快就会成为网店必备。此外还有对于同声传译的突破……种种的难题解答的可能性都能在这次智力问答中得到展示。</p>
<p>之前的比赛更多的是展现了IBM强悍的机能，今天的比赛展示更多的则是在此强悍机能之上强大的软件能力。与其说是2场比赛，不如说是一场比赛，只是中场休息了太长时间，在此期间，我们经历了M到G级别的硬件更新，经历了互联网的崛起，经历了Window3到windows7……但终究还是面临了这样一个问题：“我们有了如此强悍的硬件之后，到底该如何驾驭？难道只是为了测评软件的得分去买硬件吗？”IBM已经用下半场的比赛回答了我们：“No！还有更多的难题需要我们去升级硬件。”</p>
<p>我很期待下一个15年的比赛！</p>
]]></content:encoded>
			<wfw:commentRss>http://www.litrin.net/2012/02/28/%e4%bb%8e%e6%b7%b1%e8%93%9d%e5%88%b0%e5%8d%8e%e7%94%9f/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Key-Value式数据结构设计</title>
		<link>http://www.litrin.net/2012/02/21/key-value%e5%bc%8f%e6%95%b0%e6%8d%ae%e7%bb%93%e6%9e%84%e8%ae%be%e8%ae%a1/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=key-value%25e5%25bc%258f%25e6%2595%25b0%25e6%258d%25ae%25e7%25bb%2593%25e6%259e%2584%25e8%25ae%25be%25e8%25ae%25a1</link>
		<comments>http://www.litrin.net/2012/02/21/key-value%e5%bc%8f%e6%95%b0%e6%8d%ae%e7%bb%93%e6%9e%84%e8%ae%be%e8%ae%a1/#comments</comments>
		<pubDate>Tue, 21 Feb 2012 02:28:49 +0000</pubDate>
		<dc:creator>Litrin</dc:creator>
				<category><![CDATA[www]]></category>
		<category><![CDATA[数据库应用]]></category>
		<category><![CDATA[站长的blog]]></category>
		<category><![CDATA[MongoDB]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[nosql]]></category>
		<category><![CDATA[Redis]]></category>

		<guid isPermaLink="false">http://www.litrin.net/?p=1685</guid>
		<description><![CDATA[近一年来始终专注于No-SQL技术和大并发下的数据结构。整理一下思路。 之前从事的行业以企业管理和电子商务系统为主，这样的系统比较注重于对于数据的描述和事物化的流程管理。这样的模式自然是SQL的强项，特别是企业信息化管理系统和电子商务中的帐务结算子系统，这类系统对于数据的原子性和一致性的要求近乎苛刻，根据CAP原则，只能放弃性能作为代价。后来辗转到互联网行业，特别是SNS的开发和运维中，很多思维模式必须要打破。SNS，特别是Feed部分的数据结构，绝对是SQL模式的噩梦——Feed分发、个性化增删改加上分库分表的物理结构让传统上的SQLDB疲于应付，即便实现成功，也始终无法摆脱“硬撑”的嫌疑。 之前使用过Memcache，并曾经很长一段时间把Key-Value和Memcache等价起来，认为K-V数据库就是一个缓存工具而已。只不过是把DB中的热数据临时保存的解决方案。当出现了更为强大的Redis之后，No-SQL也从Key-value，演化到了Key-list, Key-Hash，Key-set，并支持数据的持久化，其实直道现在我仍然认为它还是中规中矩的Key-Value，只不过对应了json数据结构中的三种括号而已。 在以前用DB的时候，经常会出现很多慢查询，到头来只是因为没有及时更新索引而已。对于很多企业而言，开发和运维是两个团队，尽管Facebook提出了DevOps这种“快速运维”的管理模式，但真正实施上，往往由于侧重点的不同，加上“快速迭代”的产品策略，运维团队，特别是DBA很难第一时间跟进开发团队的步伐调整索引或者数据结构；开发团队也很难在开发中发觉DB瓶颈，从而进行设计变动。这样势必需要在DB操作上进行限制，这样一方面有利于性能上进行优化，同时也会减低数据结构的复杂性。 我的想法是通过底层封装，限制数据库的直接访问，通过类似Key-value的访问数据获取模式进行数据操作，直接忽略底层的数据结构。开发人员无须关注数据的物理存贮位置和存储结构，这样整个系统将成为K-V主导。配合Json化的数据结构可以直接实现很多DB Like的操作。 对于文本匹配的问题，由于MySQL之类的DB本身也支持的很弱，直接通过CoreSeek之类的全文搜索引擎实现。目的是“合适的工具做合适的事情”。让DB去做更加擅长的事物关系处理。 通过这样的改造，整个系统将成为一个No-SQL的数据结构，这样带来的性能提升绝对不是一点点，或者说这样的数据规划本身就是“并发优化”的。 带来的问题最主要的就是一致性问题，但仅过实际经验来说，只要处置得当，一致性问题绝对是“可接受的”。当然，中间可以用Mongo这类的骑墙产品过渡，但我个人的观点是：Mongo的存在是为了替代简单逻辑中MySQL的地位，而不是仅仅用来作为适应性过渡，因为这玩艺是No-SQL的，对大多数人来说用起来却比SQL还复杂。 &#160;]]></description>
			<content:encoded><![CDATA[<p>近一年来始终专注于No-SQL技术和大并发下的数据结构。整理一下思路。</p>
<p>之前从事的行业以企业管理和电子商务系统为主，这样的系统比较注重于对于数据的描述和事物化的流程管理。这样的模式自然是SQL的强项，特别是企业信息化管理系统和电子商务中的帐务结算子系统，这类系统对于数据的原子性和一致性的要求近乎苛刻，根据CAP原则，只能放弃性能作为代价。后来辗转到互联网行业，特别是SNS的开发和运维中，很多思维模式必须要打破。SNS，特别是Feed部分的数据结构，绝对是SQL模式的噩梦——Feed分发、个性化增删改加上分库分表的物理结构让传统上的SQLDB疲于应付，即便实现成功，也始终无法摆脱“硬撑”的嫌疑。</p>
<p><span id="more-1685"></span></p>
<p>之前使用过Memcache，并曾经很长一段时间把Key-Value和Memcache等价起来，认为K-V数据库就是一个缓存工具而已。只不过是把DB中的热数据临时保存的解决方案。当出现了更为强大的Redis之后，No-SQL也从Key-value，演化到了Key-list, Key-Hash，Key-set，并支持数据的持久化，其实直道现在我仍然认为它还是中规中矩的Key-Value，只不过对应了json数据结构中的三种括号而已。</p>
<p>在以前用DB的时候，经常会出现很多慢查询，到头来只是因为没有及时更新索引而已。对于很多企业而言，开发和运维是两个团队，尽管Facebook提出了DevOps这种“快速运维”的管理模式，但真正实施上，往往由于侧重点的不同，加上“快速迭代”的产品策略，运维团队，特别是DBA很难第一时间跟进开发团队的步伐调整索引或者数据结构；开发团队也很难在开发中发觉DB瓶颈，从而进行设计变动。这样势必需要在DB操作上进行限制，这样一方面有利于性能上进行优化，同时也会减低数据结构的复杂性。</p>
<p>我的想法是通过底层封装，限制数据库的直接访问，通过类似Key-value的访问数据获取模式进行数据操作，直接忽略底层的数据结构。开发人员无须关注数据的物理存贮位置和存储结构，这样整个系统将成为K-V主导。配合Json化的数据结构可以直接实现很多DB Like的操作。</p>
<p>对于文本匹配的问题，由于MySQL之类的DB本身也支持的很弱，直接通过CoreSeek之类的全文搜索引擎实现。目的是“合适的工具做合适的事情”。让DB去做更加擅长的事物关系处理。</p>
<p>通过这样的改造，整个系统将成为一个No-SQL的数据结构，这样带来的性能提升绝对不是一点点，或者说这样的数据规划本身就是“并发优化”的。 带来的问题最主要的就是一致性问题，但仅过实际经验来说，只要处置得当，一致性问题绝对是“可接受的”。当然，中间可以用Mongo这类的骑墙产品过渡，但我个人的观点是：Mongo的存在是为了替代简单逻辑中MySQL的地位，而不是仅仅用来作为适应性过渡，因为这玩艺是No-SQL的，对大多数人来说用起来却比SQL还复杂。</p>
<p>&nbsp;</p>
]]></content:encoded>
			<wfw:commentRss>http://www.litrin.net/2012/02/21/key-value%e5%bc%8f%e6%95%b0%e6%8d%ae%e7%bb%93%e6%9e%84%e8%ae%be%e8%ae%a1/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Tornado的进程级别缓存用法</title>
		<link>http://www.litrin.net/2012/02/03/tornado%e7%9a%84%e8%bf%9b%e7%a8%8b%e7%ba%a7%e5%88%ab%e7%bc%93%e5%ad%98%e7%94%a8%e6%b3%95/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=tornado%25e7%259a%2584%25e8%25bf%259b%25e7%25a8%258b%25e7%25ba%25a7%25e5%2588%25ab%25e7%25bc%2593%25e5%25ad%2598%25e7%2594%25a8%25e6%25b3%2595</link>
		<comments>http://www.litrin.net/2012/02/03/tornado%e7%9a%84%e8%bf%9b%e7%a8%8b%e7%ba%a7%e5%88%ab%e7%bc%93%e5%ad%98%e7%94%a8%e6%b3%95/#comments</comments>
		<pubDate>Fri, 03 Feb 2012 03:20:48 +0000</pubDate>
		<dc:creator>Litrin</dc:creator>
				<category><![CDATA[www]]></category>
		<category><![CDATA[nosql]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://www.litrin.net/?p=1665</guid>
		<description><![CDATA[之前一直在跟朋友调试一个基于tornado框架的长连接HTTP服务，并不断的优化尽量以最少的资源换取最大的连接数。我的想法是通过定期轮询一个Redis键，当键值发生改变后推送信息给客户端，并同时回写改变数据到redis以便下次比对。这种方法中规中矩，但显然每次变动都会牵扯两次Redis读写，网络开销的代价很大。即便采用了Redis pipline连接池，受通讯时间的影响，性能只能说“可以接受”而已。瓶颈在数据存储的级别。 记得在PHP开发过程中，经常会用到实例级别或者线程级别的变量缓存，带来的性能提升是巨大的。但对于tornado来说，由于每次访问都会实例化tornado.web.RequestHandler，不能满足要求，只能考虑在主线程上进行变量缓存。一旦成功将有可能直接抛弃redis。 种种原因，不公开最终实现的代码，这里只用一个页面计数器来模拟。通过一个页面http://localhost/get获得主页http://localhost/的Page View。 import tornado.httpserver import tornado.ioloop import tornado.options import tornado.httpclient import tornado.web import sys, os from tornado.options import define, options ##### class PageCounter(object): count = 0 #### #PageCounter = 0 这种采用全局变量的方法被证实无法实现。 class MainPage(tornado.web.RequestHandler): def get(self): PageCounter.count += 1 self.finish('Hello World!') class GetPageView(tornado.web.RequestHandler): def get(self): sPageView = str(PageCounter.count) self.write(sPageView) def main(port): if os.fork() [...]]]></description>
			<content:encoded><![CDATA[<p>之前一直在跟朋友调试一个<a href="http://www.litrin.net/2011/10/18/%E9%9D%9E%E9%98%BB%E5%A1%9E%E7%9A%84python-web%E6%A1%86%E6%9E%B6tornado/" target="_blank">基于tornado框架的长连接HTTP服务</a>，并不断的优化尽量以最少的资源换取最大的连接数。我的想法是通过定期轮询一个Redis键，当键值发生改变后推送信息给客户端，并同时回写改变数据到redis以便下次比对。这种方法中规中矩，但显然每次变动都会牵扯两次Redis读写，网络开销的代价很大。即便采用了Redis pipline连接池，受通讯时间的影响，性能只能说“可以接受”而已。瓶颈在数据存储的级别。</p>
<p>记得在PHP开发过程中，经常会用到实例级别或者线程级别的变量缓存，带来的性能提升是巨大的。但对于tornado来说，由于每次访问都会实例化tornado.web.RequestHandler，不能满足要求，只能考虑在主线程上进行变量缓存。一旦成功将有可能直接抛弃redis。</p>
<p><span id="more-1665"></span></p>
<p>种种原因，不公开最终实现的代码，这里只用一个页面计数器来模拟。通过一个页面http://localhost/get获得主页http://localhost/的Page View。</p>
<pre class="py" name=code>
import tornado.httpserver
import tornado.ioloop
import tornado.options
import tornado.httpclient
import tornado.web
import sys, os
from tornado.options import define, options

#####
class PageCounter(object):
    count = 0
####

#PageCounter = 0 这种采用全局变量的方法被证实无法实现。

class MainPage(tornado.web.RequestHandler):

    def get(self):
        PageCounter.count += 1
        self.finish('Hello World!')

class GetPageView(tornado.web.RequestHandler):
    def get(self):
        sPageView = str(PageCounter.count)
        self.write(sPageView)

def main(port):
    if os.fork() != 0:
        exit()
    define("port", default=port, help="run on the given port", type=int)
    application = tornado.web.Application([
        ("/", MainPage),
        ("/get", GetPageView),
    ])
    http_server = tornado.httpserver.HTTPServer(application)
    http_server.listen(options.port)
    tornado.ioloop.IOLoop.instance().start()

if __name__ == "__main__":

    if len (sys.argv) &gt; 1:
        port = sys.argv[1]
    else:
        port = 80
    main(port)</pre>
<p>这里要说的是object基类的PageCounter方法，可以定义一种数据结构以及对应的操作方法。当然这段代码只是Demo，写得不规范。由于PageCount是全局的，跟随进程实例化，所以可以很灵活在各个实例之间传递数据。</p>
<p><a href="http://www.litrin.net/2012/02/03/tornado%e7%9a%84%e8%bf%9b%e7%a8%8b%e7%ba%a7%e5%88%ab%e7%bc%93%e5%ad%98%e7%94%a8%e6%b3%95/homepage/" rel="attachment wp-att-1668"><img class="aligncenter size-medium wp-image-1668" title="homepage" src="http://www.litrin.net/wp-content/uploads/2012/02/homepage-300x218.png" alt="" width="300" height="218" /></a></p>
<p><a href="http://www.litrin.net/2012/02/03/tornado%e7%9a%84%e8%bf%9b%e7%a8%8b%e7%ba%a7%e5%88%ab%e7%bc%93%e5%ad%98%e7%94%a8%e6%b3%95/pageview/" rel="attachment wp-att-1669"><img class="aligncenter size-medium wp-image-1669" title="pageView" src="http://www.litrin.net/wp-content/uploads/2012/02/pageView-300x218.png" alt="" width="300" height="218" /></a></p>
<p>&nbsp;</p>
<p>类似这种方法，我们的项目性能提升了至少5倍。但这样实现的结果也非常明显，首先不能持久化，一旦进程终止，数据就被清空；其次是进程隔离，这种方法共享数据只能工作在tornado的一个进程中，对于习惯于多进程并行的Tornado部署会有问题，我们最终的做法是做唯一哈希；最后要注意的是内存释放的问题，数据保存在内存中，如果是大量的数据通过dict/list做映射的话需要进行定期清理，当然通过这种方法可以变态的做一个基于HTTP协议的Key-value数据库。</p>
<p># ab -n10000 -c1000 http://localhost/<br />
This is ApacheBench, Version 2.3 < $Revision: 655654 $><br />
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/<br />
Licensed to The Apache Software Foundation, http://www.apache.org/</p>
<p>Benchmarking localhost (be patient)<br />
Completed 1000 requests<br />
Completed 2000 requests<br />
Completed 3000 requests<br />
Completed 4000 requests<br />
Completed 5000 requests<br />
Completed 6000 requests<br />
Completed 7000 requests<br />
Completed 8000 requests<br />
Completed 9000 requests<br />
Completed 10000 requests<br />
Finished 10000 requests</p>
<p>Server Software:        TornadoServer/2.1.1<br />
Server Hostname:        localhost<br />
Server Port:            80</p>
<p>Document Path:          /<br />
Document Length:        12 bytes</p>
<p>Concurrency Level:      1000<br />
Time taken for tests:   8.921 seconds<br />
Complete requests:      10000<br />
Failed requests:        0<br />
Write errors:           0<br />
Total transferred:      1700000 bytes<br />
HTML transferred:       120000 bytes<br />
Requests per second:    1120.89 [#/sec] (mean)<br />
Time per request:       892.148 [ms] (mean)<br />
Time per request:       0.892 [ms] (mean, across all concurrent requests)<br />
Transfer rate:          186.09 [Kbytes/sec] received</p>
<p>Connection Times (ms)<br />
              min  mean[+/-sd] median   max<br />
Connect:        0  230 792.8      0    3012<br />
Processing:    14  134  73.9    114    1878<br />
Waiting:       14  134  73.9    114    1878<br />
Total:         86  364 815.1    114    3818</p>
<p>Percentage of the requests served within a certain time (ms)<br />
  50%    114<br />
  66%    115<br />
  75%    121<br />
  80%    141<br />
  90%    378<br />
  95%   3135<br />
  98%   3176<br />
  99%   3223<br />
 100%   3818 (longest request)</p>
]]></content:encoded>
			<wfw:commentRss>http://www.litrin.net/2012/02/03/tornado%e7%9a%84%e8%bf%9b%e7%a8%8b%e7%ba%a7%e5%88%ab%e7%bc%93%e5%ad%98%e7%94%a8%e6%b3%95/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>微博</title>
		<link>http://www.litrin.net/2012/01/31/%e5%be%ae%e5%8d%9a/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=%25e5%25be%25ae%25e5%258d%259a</link>
		<comments>http://www.litrin.net/2012/01/31/%e5%be%ae%e5%8d%9a/#comments</comments>
		<pubDate>Tue, 31 Jan 2012 02:05:30 +0000</pubDate>
		<dc:creator>Litrin</dc:creator>
				<category><![CDATA[站长的blog]]></category>

		<guid isPermaLink="false">http://www.litrin.net/?p=1661</guid>
		<description><![CDATA[最近看了一下自己之前写的帖子——甚至直接回溯到了2005年。本想学习韩寒那样删掉一部分内容，这部分的内容无非几种情况：内容明显脱节的，诸如早期版本的安装配置等；有一些错误或者言语上容易让读者产生误解的；还有就是早期为了填充内容直接黏贴的。后来觉得既然已经在小站上出现的东西，不论什么情况，这已经成为网站的一部分，何况还有RSS以及其他方式订阅的读者，“说出的话，泼出的水”没有回收删除的必要了。 从小站一开始就在思索如何与用户互动，评论自然是一个好的方式。但访问本站的朋友大多数是在处理问题时通过搜索引擎进来的，看一眼就走人，可谓是“来也匆匆，去也匆匆”自然不会有评论。即便是文章中的错误，除了背后骂娘之外也不会有其他的动作。当然也有很多的评论，几乎占了90%以上，无非还停留在某某论坛的抢积分逻辑上。“顶”，“路过”等等没什么营养的回复我会直接归结为垃圾评论。 作为ITer，我本身非常热衷于新事物，微博这类的新媒体我也用了一段时间。当然09年前以Twitter为主，众所周知的原因，不能成为主流。后来用了Google buzz，最大的优点在于可以直接与Google Reader中的feed订阅同步。可惜google自己终止了它。最终只能回归到GFW内的本地克隆。抵制腾讯的我选择了新浪微博。 @开源微站 敬请关注！]]></description>
			<content:encoded><![CDATA[<p>最近看了一下自己之前写的帖子——甚至直接回溯到了2005年。本想学习韩寒那样删掉一部分内容，这部分的内容无非几种情况：内容明显脱节的，诸如早期版本的安装配置等；有一些错误或者言语上容易让读者产生误解的；还有就是早期为了填充内容直接黏贴的。后来觉得既然已经在小站上出现的东西，不论什么情况，这已经成为网站的一部分，何况还有RSS以及其他方式订阅的读者，“说出的话，泼出的水”没有回收删除的必要了。</p>
<p>从小站一开始就在思索如何与用户互动，评论自然是一个好的方式。但访问本站的朋友大多数是在处理问题时通过搜索引擎进来的，看一眼就走人，可谓是“来也匆匆，去也匆匆”自然不会有评论。即便是文章中的错误，除了背后骂娘之外也不会有其他的动作。当然也有很多的评论，几乎占了90%以上，无非还停留在某某论坛的抢积分逻辑上。“顶”，“路过”等等没什么营养的回复我会直接归结为垃圾评论。</p>
<p>作为ITer，我本身非常热衷于新事物，微博这类的新媒体我也用了一段时间。当然09年前以Twitter为主，众所周知的原因，不能成为主流。后来用了Google buzz，最大的优点在于可以直接与Google Reader中的feed订阅同步。可惜google自己终止了它。最终只能回归到GFW内的本地克隆。抵制腾讯的我选择了新浪微博。</p>
<h2 style="text-align: center;"><a rel="nofollow" target="_blank" title="开源微站" href="http://weibo.com/1429950522/profile?leftnav=1&amp;wvr=4">@开源微站</a> 敬请关注！</h2>
]]></content:encoded>
			<wfw:commentRss>http://www.litrin.net/2012/01/31/%e5%be%ae%e5%8d%9a/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Ubuntu上KVM虚拟化的部署</title>
		<link>http://www.litrin.net/2012/01/20/ubuntu%e4%b8%8akvm%e8%99%9a%e6%8b%9f%e5%8c%96%e7%9a%84%e9%83%a8%e7%bd%b2/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=ubuntu%25e4%25b8%258akvm%25e8%2599%259a%25e6%258b%259f%25e5%258c%2596%25e7%259a%2584%25e9%2583%25a8%25e7%25bd%25b2</link>
		<comments>http://www.litrin.net/2012/01/20/ubuntu%e4%b8%8akvm%e8%99%9a%e6%8b%9f%e5%8c%96%e7%9a%84%e9%83%a8%e7%bd%b2/#comments</comments>
		<pubDate>Fri, 20 Jan 2012 08:38:44 +0000</pubDate>
		<dc:creator>Litrin</dc:creator>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[服务器]]></category>
		<category><![CDATA[硬件相关]]></category>

		<guid isPermaLink="false">http://www.litrin.net/?p=1649</guid>
		<description><![CDATA[这个KVM跟控制台切换器之类的东西一点关系没有，KVM全称Kernel-based Virtual Machine，是基于Linux核心的虚拟机。之前曾经写过基于XEN的虚拟化，最终linux世界还是没有选择XEN。KVM被正式导入Linux是在2007年的2.6.20核心上，以替代XEN，不过相对XEN来说，KVM要求CPU硬件上支持虚拟化技术，即Intel-vt或者AMD-v的支持。这对于2008年之后的机器来说几乎是标配的。对于这一个时期的CPU都一个劲的堆核心，内存也空前的便宜，硬盘也逐步到了320G起板的水平，可以大胆的玩虚拟机了！ 再此之前，还是先确认系统的CPU是否支持虚拟化： #egrep &#8216;(vmx&#124;svm)&#8217; /proc/cpuinfo 应该有返回，如果没有返回，且确认您的CPU支持虚拟化的话，建议去看看BIOS设置，大多数的主板都支持关闭此技术的。 还是以最常用的Ubuntu Server 做例子，desktop的可以直接apt-get install ubuntu-server之后，用server的核心启动。如果你全程参考本文，个人建议还是通过后一种方式来做，因为本文的过程需要X环境。 首先，设置好桥接，由于我使用的机器在远程，操作全部通过ssh，桥接的过程断开过网络。让机房重起数次之后，找到了最稳妥的方法，虽然也要断网，但好在会自己恢复。 #sudo apt-get install bridge-utils uml-utilities #vi /etc/network/intefaces auto lo iface lo inet loopback auto tap0 iface tap0 inet manual up ifconfig $IFACE 0.0.0.0 up down ifconfig $IFACE down tunctl_user root auto br0 iface br0 inet static bridge_ports eth0 tap0 address 192.168.1.3 [...]]]></description>
			<content:encoded><![CDATA[<p>这个KVM跟控制台切换器之类的东西一点关系没有，KVM全称Kernel-based Virtual Machine，是基于Linux核心的虚拟机。之前曾经写过<a title="Ubuntu上Xen的快速部署" href="http://www.litrin.net/2010/10/08/ubuntu%e4%b8%8axen%e7%9a%84%e5%bf%ab%e9%80%9f%e9%83%a8%e7%bd%b2/">基于XEN的虚拟化</a>，最终linux世界还是没有选择XEN。KVM被正式导入Linux是在2007年的2.6.20核心上，以替代XEN，不过相对XEN来说，KVM要求CPU硬件上支持虚拟化技术，即Intel-vt或者AMD-v的支持。这对于2008年之后的机器来说几乎是标配的。对于这一个时期的CPU都一个劲的堆核心，内存也空前的便宜，硬盘也逐步到了320G起板的水平，可以大胆的玩虚拟机了！</p>
<p>再此之前，还是先确认系统的CPU是否支持虚拟化：<br />
#egrep &#8216;(vmx|svm)&#8217; /proc/cpuinfo</p>
<p>应该有返回，如果没有返回，且确认您的CPU支持虚拟化的话，建议去看看BIOS设置，大多数的主板都支持关闭此技术的。</p>
<p><span id="more-1649"></span></p>
<p>还是以最常用的Ubuntu Server 做例子，desktop的可以直接apt-get install ubuntu-server之后，用server的核心启动。如果你全程参考本文，个人建议还是通过后一种方式来做，因为本文的过程需要X环境。</p>
<p>首先，设置好桥接，由于我使用的机器在远程，操作全部通过ssh，桥接的过程断开过网络。让机房重起数次之后，找到了最稳妥的方法，虽然也要断网，但好在会自己恢复。</p>
<p>#sudo apt-get install bridge-utils uml-utilities</p>
<p>#vi /etc/network/intefaces</p>
<p>auto lo<br />
iface lo inet loopback</p>
<p>auto tap0<br />
iface tap0 inet manual<br />
up ifconfig $IFACE 0.0.0.0 up<br />
down ifconfig $IFACE down<br />
tunctl_user root</p>
<p>auto br0<br />
iface br0 inet static<br />
bridge_ports eth0 tap0<br />
address 192.168.1.3<br />
netmask 255.255.255.0<br />
network 192.168.1.0<br />
broadcast 192.168.1.255<br />
gateway 192.168.1.254</p>
<p>注意这个br0，我通过前端防火墙做的DMZ通道，所以设置了内网地址。主机通过这个ip访问。所有的虚拟主机也直接设置到192.168.1.0/24网段。</p>
<p>#/etc/init.d/network restart</p>
<p>断网了，等待几分钟后网络恢复，直接ifconfig</p>
<p>br0       Link encap:Ethernet  HWaddr 02:0b:b1:f7:79:01<br />
inet addr:192.168.1.3  Bcast:192.168.1.255  Mask:255.255.255.0<br />
inet6 addr: fe80::b:b1ff:fef7:7901/64 Scope:Link<br />
UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1<br />
RX packets:506941 errors:0 dropped:0 overruns:0 frame:0<br />
TX packets:733910 errors:0 dropped:0 overruns:0 carrier:0<br />
collisions:0 txqueuelen:0<br />
RX bytes:45469237 (45.4 MB)  TX bytes:654152049 (654.1 MB)</p>
<p>eth0      Link encap:Ethernet  HWaddr e4:1f:13:95:82:cf<br />
inet6 addr: fe80::e61f:13ff:fe95:82cf/64 Scope:Link<br />
UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1<br />
RX packets:1367878 errors:0 dropped:0 overruns:0 frame:0<br />
TX packets:1541493 errors:0 dropped:0 overruns:0 carrier:0<br />
collisions:0 txqueuelen:100<br />
RX bytes:689206805 (689.2 MB)  TX bytes:1062795975 (1.0 GB)<br />
Memory:81a80000-81aa0000</p>
<p>eth0:0    Link encap:Ethernet  HWaddr e4:1f:13:95:82:cf<br />
inet addr:192.168.1.2  Bcast:0.0.0.0  Mask:0.0.0.0<br />
UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1<br />
Memory:81a80000-81aa0000</p>
<p>桥接成功！</p>
<p>相对来说，我还是比较喜欢图形化的管理工具，命令行实在太痛苦</p>
<p>#apt-get install virt-manager libvirtd kvm libvirt-bin</p>
<p>看看是否安装成功</p>
<p># ls /dev | grep kvm</p>
<p>直接用ssh通道执行gnome-session就可以连到远程桌面，执行系统工具里的“虚拟系统管理器”。添加连接中选择本地，QEMU/KVM。</p>
<p><a href="http://www.litrin.net/2012/01/20/ubuntu%e4%b8%8akvm%e8%99%9a%e6%8b%9f%e5%8c%96%e7%9a%84%e9%83%a8%e7%bd%b2/kvm-conn/" rel="attachment wp-att-1650"><img class="aligncenter size-medium wp-image-1650" title="kvm-conn" src="http://www.litrin.net/wp-content/uploads/2012/01/kvm-conn-229x300.png" alt="" width="229" height="300" /></a><a href="http://www.litrin.net/2012/01/20/ubuntu%e4%b8%8akvm%e8%99%9a%e6%8b%9f%e5%8c%96%e7%9a%84%e9%83%a8%e7%bd%b2/virt-manager/" rel="attachment wp-att-1651"><img class="aligncenter size-medium wp-image-1651" title="virt-manager" src="http://www.litrin.net/wp-content/uploads/2012/01/virt-manager-292x300.png" alt="" width="292" height="300" /></a>然后建立新的虚拟主机，个人觉得这块跟用VM之类的工具没有什么区别了，直接跳过了。不过在第五步的时候，请将网卡设置为桥接设备，除非仅仅用于NAT方式联网。<a href="http://www.litrin.net/2012/01/20/ubuntu%e4%b8%8akvm%e8%99%9a%e6%8b%9f%e5%8c%96%e7%9a%84%e9%83%a8%e7%bd%b2/kvm-net/" rel="attachment wp-att-1652"><img class="aligncenter size-medium wp-image-1652" title="kvm-net" src="http://www.litrin.net/wp-content/uploads/2012/01/kvm-net-199x300.png" alt="" width="199" height="300" /></a></p>
<p>需要注意的是，如果你跟我一样通过远程连接，直接打开主机的控制台的时候，键盘会不听使唤。这不是切换键盘设置可以搞定的问题，我尝试过不同的X客户端和操作系统，涵盖了windows mac linux，全都如此。只能认为是一个bug。我的最终解决方法是通过ssh通道，将远程主机的5900 VNC端口转接回本地，然后再通过vnc客户端连接本地才得以通过，键盘的问题得以解决。很傻，如果你有更好的方式，敬请赐教了！</p>
<p>照旧建立一个虚拟主机，我还是选择了Ubuntu Server 1110 64bit，也没有什么好说的。安装好之后，配置好了ssh。从此就可以直接抛弃vnc和宿主主机的X访问了。</p>
<p>在虚拟主机上安装定制的内核:</p>
<p>#apt-get install kernel-virtual</p>
<p>重起的速度那是嗖嗖的！直接lsmod发觉真的是定制内核，和标准的server内核比起来一点多余的没有：</p>
<p>root@www:~# lsmod<br />
Module                  Size  Used by<br />
psmouse                73882  0<br />
serio_raw              13166  0<br />
lp                     17799  0<br />
parport                46562  1 lp<br />
8139too                32177  0<br />
8139cp                 27412  0</p>
<p>对比一下性能吧，还是<a title="Ctypes实现“C重构”" href="http://www.litrin.net/2012/01/04/ctypes%e5%ae%9e%e7%8e%b0c%e9%87%8d%e6%9e%84/">那道题目</a>的python原版，稍作优化：</p>
<p>虚拟机：</p>
<p>root@www:/home/litrin# python TimeCost.py<br />
10240<br />
Cost: 0.508388996124<br />
root@www:/home/litrin# python TimeCost.py<br />
10240<br />
Cost: 0.507208108902<br />
root@www:/home/litrin#</p>
<p>宿主机：</p>
<p>root@vserver:~# python TimeCost.py<br />
10240<br />
Cost: 4.35039806366<br />
root@vserver:~# python TimeCost.py<br />
10240<br />
Cost: 4.35194683075</p>
<p>我开始真的不知道该如何解释。虚拟机的性能竟然强于宿主机。后来检查了python的版本才明白，宿主是py2.6而客户机是2.7，版本不同，性能有差距，但可以肯定的是，从这一点上来说虚拟化的性能损失不大。</p>
<p>最后一步，去掉虚拟机上不需要的东西，精简主义者！</p>
<p>这次就直接用宿主的命令行操作吧：</p>
<p>#virsh</p>
<p>virsh # list<br />
Id Name                 State<br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-<br />
30 www.litrin.net       running //我的虚拟主机名为www.litrin.net，请注意！</p>
<p>virsh # edit www.litrin.net</p>
<p>删掉vnc, pty, mouse, graphic</p>
<p>virsh # destroy www.litrin.net</p>
<p>virsh # start www.litrin.net</p>
<p>这里有一个问题也凸现，就是无法使用宿主机的reboot和halt命令，只能强行的destroy。</p>
<p>你同时还可以配合DHCP和主机克隆，大规模快速甚至自动化的架设多个虚拟机，本文不再探讨。</p>
<p>尽管现在“云”已经被用滥了，搞个虚拟机就敢号称云托管的大有人在。个人觉得其实对于少数几台主机的虚拟化来说，更多的是节约机房的托管费用和主机成本，这对于稍微大一点的项目并没有什么太多的优势。如果配合上open stack之类的故障平滑迁移技术才是虚拟化方案的终极利器。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.litrin.net/2012/01/20/ubuntu%e4%b8%8akvm%e8%99%9a%e6%8b%9f%e5%8c%96%e7%9a%84%e9%83%a8%e7%bd%b2/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>MongoDB的分发模式和部署</title>
		<link>http://www.litrin.net/2012/01/11/mongodb%e7%9a%84%e5%88%86%e5%8f%91%e6%a8%a1%e5%bc%8f%e5%92%8c%e9%83%a8%e7%bd%b2/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=mongodb%25e7%259a%2584%25e5%2588%2586%25e5%258f%2591%25e6%25a8%25a1%25e5%25bc%258f%25e5%2592%258c%25e9%2583%25a8%25e7%25bd%25b2</link>
		<comments>http://www.litrin.net/2012/01/11/mongodb%e7%9a%84%e5%88%86%e5%8f%91%e6%a8%a1%e5%bc%8f%e5%92%8c%e9%83%a8%e7%bd%b2/#comments</comments>
		<pubDate>Wed, 11 Jan 2012 03:58:07 +0000</pubDate>
		<dc:creator>Litrin</dc:creator>
				<category><![CDATA[数据库应用]]></category>
		<category><![CDATA[DataBase]]></category>
		<category><![CDATA[MongoDB]]></category>
		<category><![CDATA[nosql]]></category>

		<guid isPermaLink="false">http://www.litrin.net/?p=1634</guid>
		<description><![CDATA[MongoDB是近期一直在研究的No-SQL，作为No-SQL来说，Mongo做的反而更像传统的关系型数据库，可以利用弱关系进行查询。作为网站应用来说，毫不客气地说，如果你的查询复杂程度到了MongoDB无法支持的程度，只能说明你的数据结构设计的有问题。 作为No-sql的强项，MongoDB的数据分发/同步机制相对比MySQL灵活的多，支持传统上的主从同步和趋向于高性能的ShareSet，而且对于程序端来说改动相对较小，代价几乎可以不计。现在就从这两种分发机制方式说起。 Master-slaver机制 不同于MySQL的主从同步，MongoDB的主备同步有3种角色，primary（相当于Master）, secondary（相当于Slave），Arbite（选举机）。正常情况下primary与secondary的配置要相当，因为很有可能主备切换，Arbite则没有被升格的可能（只有选举权，没有被选举权），正常情况下只是相当于一个心跳监控机而已。一旦p出现故障或者整个拓扑结构发生变化，导致P不能联系上大多数M之后，如果存在多台S需要升格成P的时候就需要A来进行选举。 Master-Slaver的部署 假设3台主机,主机名分别是 P S A,请注意Shell提示符 P# mongod &#8211;rest &#8211;replSet testSet P# mongo &#62;cfg = {member:{host: “P:27017&#8243;}} &#62;  rs.initiate(cfg) S# mongod &#8211;rest &#8211;replSet testSet p#mongo &#62;rs.add(“S”) { “ok” : 1 } A# mongod &#8211;rest &#8211;replSet testSet &#8211;oplogSize 8 p# mongo &#62;rs.add( { host:”A”, arbiterOnly:true } ) { “ok” : 1 } 宣告成功！就这么简单！ 如果之前一直按照此步骤的话，你就可以直接通过访问http://P:28017/来查看整个系统的状态。 理论上MongoDB可以支持互为主备，但个人觉得没有意义，反而会出现较多的一致性问题，没有在这里测试。 Sharding机制 不知道你会怎么理解”Sharding”这个单词，我的第一反应是罐头装的沙丁鱼。从拓扑结构上看，真的很像！ [...]]]></description>
			<content:encoded><![CDATA[<p>MongoDB是近期一直在研究的No-SQL，作为No-SQL来说，Mongo做的反而更像传统的关系型数据库，可以利用弱关系进行查询。作为网站应用来说，毫不客气地说，如果你的查询复杂程度到了MongoDB无法支持的程度，只能说明你的数据结构设计的有问题。</p>
<p>作为No-sql的强项，MongoDB的数据分发/同步机制相对比MySQL灵活的多，支持传统上的主从同步和趋向于高性能的ShareSet，而且对于程序端来说改动相对较小，代价几乎可以不计。现在就从这两种分发机制方式说起。</p>
<p><span id="more-1634"></span></p>
<p><strong>Master-slaver机制</strong></p>
<p><img class="aligncenter" src="http://www.mongodb.org/download/attachments/9830402/replset.png?version=1&amp;modificationDate=1321024229272" alt="" width="405" height="310" /></p>
<p>不同于MySQL的主从同步，MongoDB的主备同步有3种角色，primary（相当于Master）, secondary（相当于Slave），Arbite（选举机）。正常情况下primary与secondary的配置要相当，因为很有可能主备切换，Arbite则没有被升格的可能（只有选举权，没有被选举权），正常情况下只是相当于一个心跳监控机而已。一旦p出现故障或者整个拓扑结构发生变化，导致P不能联系上大多数M之后，如果存在多台S需要升格成P的时候就需要A来进行选举。</p>
<p><strong>Master-Slaver的部署</strong></p>
<p>假设3台主机,主机名分别是 P S A,请注意Shell提示符</p>
<p>P# mongod &#8211;rest &#8211;replSet testSet</p>
<p>P# mongo</p>
<p>&gt;cfg = {member:{host: “P:27017&#8243;}}<br />
&gt;  rs.initiate(cfg)</p>
<p>S# mongod &#8211;rest &#8211;replSet testSet<br />
p#mongo</p>
<p>&gt;rs.add(“S”)</p>
<p>{ “ok” : 1 }</p>
<p>A# mongod &#8211;rest &#8211;replSet testSet &#8211;oplogSize 8</p>
<p>p# mongo</p>
<p>&gt;rs.add( { host:”A”, arbiterOnly:true } )</p>
<p>{ “ok” : 1 }</p>
<p>宣告成功！就这么简单！</p>
<p>如果之前一直按照此步骤的话，你就可以直接通过访问http://P:28017/来查看整个系统的状态。</p>
<p>理论上MongoDB可以支持互为主备，但个人觉得没有意义，反而会出现较多的一致性问题，没有在这里测试。</p>
<p><strong>Sharding机制</strong></p>
<p><img class="aligncenter" src="http://www.mongodb.org/download/attachments/2097393/sharding.PNG?version=2&amp;modificationDate=1267724627656" alt="" width="572" height="333" /></p>
<p>不知道你会怎么理解”Sharding”这个单词，我的第一反应是罐头装的沙丁鱼。从拓扑结构上看，真的很像！</p>
<p>沙丁鱼有3种角色，shard，参与存储和运算的节点，要求数量多；config ，控制节点，保存有各个数据的哈希映射，及负载信息,相对来说是整个环节中的关键应用；mongos，路由节点，负责前端分发和数据汇总，相对来说是整个环节中的中央应用。客户端向任意一个Mongos发起请求，mongs首先从config上获取哈希映射，再通过哈希映射获取所有的数据后汇总给客户端。config不断的维系全局的数据分片，又有点类似心跳监视的意思。更加夸张的是，这种沙丁鱼结构支持嵌套，同样也支持嵌套上面的主从结构。</p>
<p><strong>sharding的部署</strong></p>
<p>这次还是3台机器，S1 S2 MS，S1 S2在做shard服务器的同时也兼作config，shard是27018口，config是27019口，都是默认的端口。</p>
<p>s1# mongod &#8211;shardsvr &#8211;replSet s1</p>
<p>s1# mongo</p>
<p>&gt; cfg = { _id : “s1&#8243;, members : [ {_id : 0, host : "S1:27018"}, ] }</p>
<p>&gt; rs.initiate(cfg)</p>
<p>s2# mongod &#8211;shardsvr &#8211;replSet s2</p>
<p>s2# mongo</p>
<p>&gt; cfg = { _id : “s1&#8243;, members : [ {_id : 0, host : "S2:27018"}, ] }<br />
&gt; rs.initiate(cfg)</p>
<p>s1# mongod &#8211;configsvr</p>
<p>s2# mongod &#8211;configsvr</p>
<p>MS# mongos &#8211;configdb s1:27019,s2:27019</p>
<p>MS#mongo</p>
<p>&gt; db.adminCommand( { addShard : “s1/s1:27018&#8243; } )</p>
<p>&gt; db.adminCommand( { addShard : “s2/s2:27018&#8243; } )</p>
<p>恭喜完成了这么复杂的系统!需要注意的是整个系统中尽量使用主机名,通过hosts指向还是通过DNS无所谓，这是因为系统一旦启动就很难修改主机信息，IP地址远没有主机名灵活。</p>
<p><strong>客户端的配置</strong></p>
<p>算了,照贴PHP官档！</p>
<div>
<div>
<p><code>&lt;?php</code></p>
<p>// 连接池方式，主机名之间用逗号隔开，然后添加array(“replicaSet” =&gt; true)<br />
$m1 = new Mongo(“mongodb://sf2.example.com,ny1.example.com”, array(“replicaSet” =&gt; true));</p>
<p>// 可以只写一个连接，然后添加array(“replicaSet” =&gt; true)表示这是一个集群，系统将会获取完整的服务器列表<br />
$m2 = new Mongo(“mongodb://ny1.example.com”, array(“replicaSet” =&gt; true));</p>
<p>?&gt;</p>
</div>
</div>
]]></content:encoded>
			<wfw:commentRss>http://www.litrin.net/2012/01/11/mongodb%e7%9a%84%e5%88%86%e5%8f%91%e6%a8%a1%e5%bc%8f%e5%92%8c%e9%83%a8%e7%bd%b2/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Ctypes实现“C重构”</title>
		<link>http://www.litrin.net/2012/01/04/ctypes%e5%ae%9e%e7%8e%b0c%e9%87%8d%e6%9e%84/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=ctypes%25e5%25ae%259e%25e7%258e%25b0c%25e9%2587%258d%25e6%259e%2584</link>
		<comments>http://www.litrin.net/2012/01/04/ctypes%e5%ae%9e%e7%8e%b0c%e9%87%8d%e6%9e%84/#comments</comments>
		<pubDate>Wed, 04 Jan 2012 08:59:46 +0000</pubDate>
		<dc:creator>Litrin</dc:creator>
				<category><![CDATA[Coding]]></category>
		<category><![CDATA[开源7788]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://www.litrin.net/?p=1618</guid>
		<description><![CDATA[现阶段很多网站都是基于非编译的语言，例如Php，Python语言完成。这样做的效果是开发效率很高，同时开发人员也很容易就位。当网站访问量达到一个数量级之后，就会遇到传说中的C10K问题，借助解释型语言的性能劣势，整个网站会到达一种“无处修改，无处优化，无处升级”的怪圈。这时候往往就会需要采用更加底层的C去重构部分或整个项目，“C重构”由此而来。当然，技术的进化也很迅速，FaceBook开源了hiphop这个PHP2C的工具，可以部分自动化的实现“C重构”。 一直把Python当成胶水语言来用，这次就接着这个话题，说个Python C重构的例子： 首先是python原码：(很眼熟吗？) #!/usr/bin/env python import time lGoal = {} def main(i): # if lGoal.has_key(i): # return lGoal[i] if i &#60; 1: return long (0) elif i &#60; 2: return long(1) return main(i-1) + main(i-2) - main(i-5) def getList(iMax): for i in range(1, iMax+1): iGoal = main(i) lGoal[i] = iGoal return lGoal #i = [...]]]></description>
			<content:encoded><![CDATA[<p>现阶段很多网站都是基于非编译的语言，例如Php，Python语言完成。这样做的效果是开发效率很高，同时开发人员也很容易就位。当网站访问量达到一个数量级之后，就会遇到传说中的C10K问题，借助解释型语言的性能劣势，整个网站会到达一种“无处修改，无处优化，无处升级”的怪圈。这时候往往就会需要采用更加底层的C去重构部分或整个项目，“C重构”由此而来。当然，技术的进化也很迅速，FaceBook开源了hiphop这个PHP2C的工具，可以部分自动化的实现“C重构”。</p>
<p>一直把Python当成胶水语言来用，这次就接着这个话题，说个Python C重构的例子：</p>
<p><span id="more-1618"></span></p>
<p>首先是python原码：(<a title="PHP的普青、文青和2B青" href="http://www.litrin.net/2011/11/05/php%e7%9a%84%e6%99%ae%e9%9d%92%e3%80%81%e6%96%87%e9%9d%92%e5%92%8c2b%e9%9d%92/" target="_blank">很眼熟吗？</a>)</p>
<pre name=code class=python>#!/usr/bin/env python

import time

lGoal = {}

def main(i):
#    if lGoal.has_key(i):
#        return lGoal[i]

    if i &lt; 1:
        return long (0)
    elif i &lt; 2:
        return long(1)
    return main(i-1) + main(i-2) - main(i-5)

def getList(iMax):
    for i in range(1, iMax+1):
        iGoal = main(i)
        lGoal[i] = iGoal

    return lGoal

#i = int(raw_input())
i = 30
timeStart = time.time()
getList(i)

print "Cost: %s" % (time.time() - timeStart)</pre>
<p>看看它的耗时：<br />
Cost: 21.9739699364</p>
<p>首先对于这种多重循环和调用，绝对是C的强项，理论上Python 2 C 之后会有很大的提升空间。重构的思路是用Python的ctypes模块调用基于C的lib库，这样可以在保留大部分Python代码的基础上完成重构，而且重构之后的程序仍然还是Python的。<br />
开始C重构vi LoadTest.c：</p>
<pre name=code class=cpp>#include &lt;stdio.h&gt;
/*
int main()
{
    int i, goal;
    for (i=1; i &lt;= 30; i++)
    {
        goal = C_Time_Cost(i);
        printf ("%d, %d \n", i, goal);

    }

   return 0;
}
*/
int C_Time_Cost(int a)
{
    if (a &lt; 1)
    {
        return 0;
    }
    if (a &lt; 2 )
    {
        return 1;
    }

    return C_Time_Cost( a - 1 ) + C_Time_Cost( a - 2 ) - C_Time_Cost( a - 5 ) ;
}</pre>
<p>编译到.o文件：<br />
gcc -c LoadTest.c -fPIC</p>
<p>编译成为Lib<br />
gcc &#8211;shared -o libLoadTest.so LoadTest.o<br />
cp libLoadTest.so /lib64 &amp;&amp; ldconfig //这一点很重要，否则会报找不到lib文件。</p>
<p>修改python:</p>
<pre name=code class=python>#!/usr/bin/env python

import time
from ctypes import *
lGoal = {}

def main(i):
    cdll.LoadLibrary("libLoadTest.so")
    libc = CDLL("libLoadTest.so")
    goal = libc.C_Time_Cost(c_int(i))
    return goal

def getList(iMax):
    for i in range(1, iMax+1):
        iGoal = main(i)
        lGoal[i] = iGoal

    return lGoal

#i = int(raw_input())
i = 30
timeStart = time.time()
getList(i)

print "Cost: %s" % (time.time() - timeStart)</pre>
<p>执行时间：<br />
Cost: 0.280420064926</p>
<p>对比之前的21.9739699364 性能提升78倍！不过需要注意，ctypes模块的加载本身很耗资源，使用不当会起到反效果，例如将i=30改为i=10的情况下，python: 0.000591039657593，而Ctypes则需要0.00165605545044，反而落后3倍的时间。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.litrin.net/2012/01/04/ctypes%e5%ae%9e%e7%8e%b0c%e9%87%8d%e6%9e%84/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>从Redis的数据丢失说起</title>
		<link>http://www.litrin.net/2011/12/22/%e4%bb%8eredis%e7%9a%84%e6%95%b0%e6%8d%ae%e4%b8%a2%e5%a4%b1%e8%af%b4%e8%b5%b7/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=%25e4%25bb%258eredis%25e7%259a%2584%25e6%2595%25b0%25e6%258d%25ae%25e4%25b8%25a2%25e5%25a4%25b1%25e8%25af%25b4%25e8%25b5%25b7</link>
		<comments>http://www.litrin.net/2011/12/22/%e4%bb%8eredis%e7%9a%84%e6%95%b0%e6%8d%ae%e4%b8%a2%e5%a4%b1%e8%af%b4%e8%b5%b7/#comments</comments>
		<pubDate>Thu, 22 Dec 2011 02:35:21 +0000</pubDate>
		<dc:creator>Litrin</dc:creator>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[数据库应用]]></category>
		<category><![CDATA[nosql]]></category>
		<category><![CDATA[Redis]]></category>

		<guid isPermaLink="false">http://www.litrin.net/?p=1611</guid>
		<description><![CDATA[碰到一个悲催的事情：一台Redis服务器，4核，16G内存且没有任何硬件上的问题。持续高压运行了大约3个月，保存了大约14G的数据，设置了比较完备的Save参数。而就是这台主机，在一次重起之后，丢失了大量的数据，14G的数据最终只恢复了几百兆而已。 正常情况下，像Redis这样定期回写磁盘的内存数据库，丢失几个数据也是在情理之中，可超过80%数据丢失率实在太离谱。排除了误操作的可能性之后，开始寻找原因。 &#160; 重启动时的日志： [26641] 21 Dec 09:46:34 * Slave ask for synchronization [26641] 21 Dec 09:46:34 * Starting BGSAVE for SYNC [26641] 21 Dec 09:46:34 # Can&#8217;t save in background: fork: Cannot allocate memory [26641] 21 Dec 09:46:34 * Replication failed, can&#8217;t BGSAVE [26641] 21 Dec 09:46:34 # Received SIGTERM, scheduling shutdown&#8230; [26641] 21 [...]]]></description>
			<content:encoded><![CDATA[<p>碰到一个悲催的事情：一台Redis服务器，4核，16G内存且没有任何硬件上的问题。持续高压运行了大约3个月，保存了大约14G的数据，设置了比较完备的Save参数。而就是这台主机，在一次重起之后，丢失了大量的数据，14G的数据最终只恢复了几百兆而已。</p>
<p>正常情况下，像Redis这样定期回写磁盘的内存数据库，丢失几个数据也是在情理之中，可超过80%数据丢失率实在太离谱。排除了误操作的可能性之后，开始寻找原因。</p>
<p><span id="more-1611"></span></p>
<p>&nbsp;</p>
<p>重启动时的日志：</p>
<p><strong>[26641] 21 Dec 09:46:34 * Slave ask for synchronization</strong></p>
<p><strong>[26641] 21 Dec 09:46:34 * Starting BGSAVE for SYNC</strong></p>
<p><strong>[26641] 21 Dec 09:46:34 # <span style="color: #ff0000;">Can&#8217;t save in background: fork: Cannot allocate memory</span></strong></p>
<p><strong>[26641] 21 Dec 09:46:34 * Replication failed, can&#8217;t BGSAVE</strong></p>
<p><strong>[26641] 21 Dec 09:46:34 # Received SIGTERM, scheduling shutdown&#8230;</strong></p>
<p><strong>[26641] 21 Dec 09:46:34 # User requested shutdown&#8230;</strong></p>
<p>很明显的一个问题，系统不能在后台保存，fork进程失败。</p>
<p>翻查了几个月的日志，发觉系统在频繁报错：</p>
<p><strong>[26641] 18 Dec 04:02:14 * 1 changes in 900 seconds. Saving&#8230;</strong></p>
<p><strong>[26641] 18 Dec 04:02:14 #<span style="color: #ff0000;"> Can&#8217;t save in background: fork: Cannot allocate memory</span></strong></p>
<p>系统不能在后台保存，fork进程时无法指定内存。</p>
<p>对源码进行跟踪，在src/rdb.c中定位了这个报错：</p>
<pre class="cpp">int rdbSaveBackground(char *filename) {
    pid_t childpid;
    long long start;

    if (server.bgsavechildpid != -1) return REDIS_ERR;
    if (server.vm_enabled) waitEmptyIOJobsQueue();
    server.dirty_before_bgsave = server.dirty;
    start = ustime();
    if ((childpid = fork()) == 0) {
        /* Child */
        if (server.vm_enabled) vmReopenSwapFile();
        if (server.ipfd &gt; 0) close(server.ipfd);
        if (server.sofd &gt; 0) close(server.sofd);
        if (rdbSave(filename) == REDIS_OK) {
            _exit(0);
        } else {
            _exit(1);
        }
    } else {
        /* Parent */
        server.stat_fork_time = ustime()-start;
        if (childpid == -1) {
            redisLog(REDIS_WARNING,"Can't save in background: fork: %s",
                strerror(errno));
            return REDIS_ERR;
        }
        redisLog(REDIS_NOTICE,"Background saving started by pid %d",childpid);
        server.bgsavechildpid = childpid;
        updateDictResizePolicy();
        return REDIS_OK;
    }
    return REDIS_OK; /* unreached */
}</pre>
<p>数据丢失的问题总算搞清楚了！</p>
<p>Redis的数据回写机制分同步和异步两种，</p>
<ol>
<li>同步回写即SAVE命令，主进程直接向磁盘回写数据。在数据大的情况下会导致系统假死很长时间，所以一般不是推荐的。</li>
<li>异步回写即BGSAVE命令，主进程fork后，复制自身并通过这个新的进程回写磁盘，回写结束后新进程自行关闭。由于这样做不需要主进程阻塞，系统不会假死，一般默认会采用这个方法。</li>
</ol>
<p>个人感觉方法２采用fork主进程的方式很拙劣，但似乎是唯一的方法。内存中的热数据随时可能修改，要在磁盘上保存某个时间的内存镜像必须要冻结。冻结就会导致假死。fork一个新的进程之后等于复制了当时的一个内存镜像，这样主进程上就不需要冻结，只要子进程上操作就可以了。</p>
<p>在小内存的进程上做一个fork,不需要太多资源，但当这个进程的内存空间以Ｇ为单位时，fork就成为一件很恐怖的操作。何况在16G内存的主机上fork 14G内存的进程呢？肯定会报内存无法分配的。更可气的是，越是改动频繁的主机上fork也越频繁，fork操作本身的代价恐怕也不会比假死好多少。</p>
<p>找到原因之后，直接修改内核参数vm.overcommit_memory = 1</p>
<p>Linux内核会根据参数vm.overcommit_memory参数的设置决定是否放行。</p>
<ol>
<li> 如果 vm.overcommit_memory = 1，直接放行</li>
<li>vm.overcommit_memory = 0：则比较 此次请求分配的虚拟内存大小和系统当前空闲的物理内存加上swap，决定是否放行。</li>
<li>vm.overcommit_memory = 2：则会比较 进程所有已分配的虚拟内存加上此次请求分配的虚拟内存和系统当前的空闲物理内存加上swap，决定是否放行。</li>
</ol>
]]></content:encoded>
			<wfw:commentRss>http://www.litrin.net/2011/12/22/%e4%bb%8eredis%e7%9a%84%e6%95%b0%e6%8d%ae%e4%b8%a2%e5%a4%b1%e8%af%b4%e8%b5%b7/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Redis的主从复制</title>
		<link>http://www.litrin.net/2011/12/20/redis%e7%9a%84%e4%b8%bb%e4%bb%8e%e5%a4%8d%e5%88%b6/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=redis%25e7%259a%2584%25e4%25b8%25bb%25e4%25bb%258e%25e5%25a4%258d%25e5%2588%25b6</link>
		<comments>http://www.litrin.net/2011/12/20/redis%e7%9a%84%e4%b8%bb%e4%bb%8e%e5%a4%8d%e5%88%b6/#comments</comments>
		<pubDate>Tue, 20 Dec 2011 05:43:46 +0000</pubDate>
		<dc:creator>Litrin</dc:creator>
				<category><![CDATA[数据库应用]]></category>
		<category><![CDATA[nosql]]></category>
		<category><![CDATA[Redis]]></category>

		<guid isPermaLink="false">http://www.litrin.net/?p=1605</guid>
		<description><![CDATA[作为MySQL对于Web应用的优化之一，主从复制（Master-slaver）是普遍被接受的，Redis作为当下一个no-sql的解决方案，很自然的将这个特性引入。同时将“操作便捷”作为一大目标，Redis的主从复制更为简单，甚至不需要额外的操作，完全可以在两台热机之间进行。 首先，准备2套Redis主机，本例192.168.0.1为主，192.168.0.2为从。为了保障不会出现稀奇古怪的毛病，要求2台主机配置文件中 databases ，dbs数量，决定了select命令的最大数（分块数量） maxmemory，最大内存使用，决定了整个系统的容量 两个参数的配置要一致，系统版本尽量保证一致（我测试过不一致的版本也可以同步，但不保证所有的情况下都可以同步）其余的数据不强制要求一致。 用客户端连接slaver主机的redis并操作 redis-cli -h 192.168.0.2 redis 192.168.0.2:6379&#62; slaveof 192.168.0.1 6379 OK 就这么方便！ 这时，可以在输入info命令，查看master_host的配置： redis 192.168.0.2:6379&#62;info &#8230; master_host:192.168.0.1 &#8230; 为保证主机每次启动都保持slave的状态，则可以在redis.conf中增加一行slaveof 192.168.0.1 6379 即可，也非常简单。 作为redis这类nosql来说，并发的压力并不像MySQL那样迫切，何况数据没有关联，一旦出现并发的瓶颈，可以很方便的将数据拆分成多个主机。那对于标准的web应用，主从的意义是什么？ 个人理解： 解决Redis内存回写磁盘一瞬间的阻塞问题。 Redis 是内存数据库，数据都在内存中，仅在改变时才会回写。但在磁盘回写的时候，由于需要拷贝内存镜像，整个处于阻塞状态，服务器不会做任何相应，在数据少的情况下阻塞时间也很少，可以忽略。但数据达到G这个级别之后的阻塞绝对是致命的。而且这个阻塞由Redis特性决定，无法彻底解决。 通过主从这种方式对任务进行分工，主机负责写入，通过配置文件中的save选项，减少回写甚至直接取消数据回写，将数据持久化的任务交由slaver主机进行。一旦宕机，由slaver主机上的数据恢复出master。 数据热迁移。 这个很好理解了，数据迁移示意图 &#160;]]></description>
			<content:encoded><![CDATA[<p>作为MySQL对于Web应用的优化之一，主从复制（Master-slaver）是普遍被接受的，Redis作为当下一个no-sql的解决方案，很自然的将这个特性引入。同时将“操作便捷”作为一大目标，Redis的主从复制更为简单，甚至不需要额外的操作，完全可以在两台热机之间进行。</p>
<p><span id="more-1605"></span></p>
<p>首先，准备2套Redis主机，本例192.168.0.1为主，192.168.0.2为从。为了保障不会出现稀奇古怪的毛病，要求2台主机配置文件中</p>
<ul>
<li>databases ，dbs数量，决定了select命令的最大数（分块数量）</li>
<li>maxmemory，最大内存使用，决定了整个系统的容量</li>
</ul>
<p>两个参数的配置要一致，系统版本尽量保证一致（我测试过不一致的版本也可以同步，但不保证所有的情况下都可以同步）其余的数据不强制要求一致。</p>
<p>用客户端连接slaver主机的redis并操作</p>
<p>redis-cli -h 192.168.0.2</p>
<p>redis 192.168.0.2:6379&gt; slaveof 192.168.0.1 6379<br />
OK</p>
<p>就这么方便！</p>
<p>这时，可以在输入info命令，查看master_host的配置：</p>
<p>redis 192.168.0.2:6379&gt;info<br />
&#8230;<br />
master_host:192.168.0.1<br />
&#8230;</p>
<p>为保证主机每次启动都保持slave的状态，则可以在redis.conf中增加一行slaveof 192.168.0.1 6379 即可，也非常简单。</p>
<p>作为redis这类nosql来说，并发的压力并不像MySQL那样迫切，何况数据没有关联，一旦出现并发的瓶颈，可以很方便的将数据拆分成多个主机。那对于标准的web应用，主从的意义是什么？</p>
<p>个人理解：</p>
<ol>
<li>解决Redis内存回写磁盘一瞬间的阻塞问题。<br />
Redis 是内存数据库，数据都在内存中，仅在改变时才会回写。但在磁盘回写的时候，由于需要拷贝内存镜像，整个处于阻塞状态，服务器不会做任何相应，在数据少的情况下阻塞时间也很少，可以忽略。但数据达到G这个级别之后的阻塞绝对是致命的。而且这个阻塞由Redis特性决定，无法彻底解决。<br />
通过主从这种方式对任务进行分工，主机负责写入，通过配置文件中的save选项，减少回写甚至直接取消数据回写，将数据持久化的任务交由slaver主机进行。一旦宕机，由slaver主机上的数据恢复出master。</li>
<li>数据热迁移。<br />
这个很好理解了，<a href="http://www.litrin.net/2011/12/20/redis%e7%9a%84%e4%b8%bb%e4%bb%8e%e5%a4%8d%e5%88%b6/redis_data/" rel="attachment wp-att-1606">数据迁移示意图</a></li>
</ol>
<p>&nbsp;</p>
]]></content:encoded>
			<wfw:commentRss>http://www.litrin.net/2011/12/20/redis%e7%9a%84%e4%b8%bb%e4%bb%8e%e5%a4%8d%e5%88%b6/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Mysql Innodb的两种表空间方式</title>
		<link>http://www.litrin.net/2011/12/06/mysql-innodb%e7%9a%84%e4%b8%a4%e7%a7%8d%e8%a1%a8%e7%a9%ba%e9%97%b4%e6%96%b9%e5%bc%8f/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=mysql-innodb%25e7%259a%2584%25e4%25b8%25a4%25e7%25a7%258d%25e8%25a1%25a8%25e7%25a9%25ba%25e9%2597%25b4%25e6%2596%25b9%25e5%25bc%258f</link>
		<comments>http://www.litrin.net/2011/12/06/mysql-innodb%e7%9a%84%e4%b8%a4%e7%a7%8d%e8%a1%a8%e7%a9%ba%e9%97%b4%e6%96%b9%e5%bc%8f/#comments</comments>
		<pubDate>Tue, 06 Dec 2011 05:17:36 +0000</pubDate>
		<dc:creator>Litrin</dc:creator>
				<category><![CDATA[数据库应用]]></category>
		<category><![CDATA[mysql]]></category>

		<guid isPermaLink="false">http://www.litrin.net/?p=1599</guid>
		<description><![CDATA[要说表空间，Mysql的表空间管理远远说不上完善。换句话说，事实上Mysql根本没有真正意义上的表空间管理。Mysql的Innodb包含两种表空间文件模式，默认的共享表空间和每个表分离的独立表空间。只要在my.cnf里面增加innodb_file_per_table=1就可以从共享表空间切换到独立表空间。当然对于已经存在的表，则需要执行alter table MY_TABLE engine=innodb命令迁移数据。 共享表空间方式 由于是默认的方式，就暂且理解为Mysql官方推荐的方式。相对而言所有的数据都在一个（或几个）文件中，比较利于管理，而且在操作的时候只需要open这一个（或几个）文件即可，相对来说代价很低。 但问题是在数据达到以G为单位来计算的时候优劣逆转。一个大小惊人的文件很不利于管理，而且对于一个如此巨大的文件来说，读写它需要耗费的资源一样巨大。更加令人费解的是，MySQL竟然将索引和数据保存于同一个文件中，索引和数据之间尚存在资源争用，不利于性能的提升。你当然可以通过innodb_data_file_path的配置规划多个表空间文件，但MySQL的逻辑是“用满后增加”，仅仅是一个文件的拆分而已，不能从根本上分离数据和索引。 之前曾经遭遇到700G以上的表空间文件，而且更加让人郁闷的是对于如此大的文件还在以每天数G的数量增加。由于无法停机，即便是拷贝一下也要花费差不多一夜，只能眼睁睁看着它继续增大而毫无保守可行的办法。 独立表空间方式 相对而言对立表空间每个表都有独立的多个数据文件，而且做到了索引和数据的分离。多个小文件之间很方便的完成跨数据库甚至跨硬件的数据拷贝和迁移。相对来说灵活性很好。 这样做同样带来另一个方面的问题。当数据库中的表数量达到一定级别时，每次操作所涉及的文件过多，如果按照默认Centos的ulimit -n = 1024的话，仅仅只能保证同时打开256个表以内，这在习惯上“拆库拆表”的MySQL数据结构上很难达到要求。尚且这种数据文件的利用率不算很高，当大量“不高”的文件集中起来，浪费的空间也很惊人，更何况最后可能出现的状况不是“一堆K级别的小文件”而是“一堆G级别的大文件”，有点适得其反的意思。你自然可以联想到分区表，又是一个“仅仅做文件拆分而已”，多个分区文件缺一不可。 之前同样遇到过这个问题，MySQL连接大的状况下大量的timeout，但主机负载还算可以，查了一圈才知道是open files限制的问题，限制一修改，负载变得惊人，但连接数却又提升的不多。 总之，两种方法各有所长，部分互补，但都不是解决问题的终极方案。期待MySQL能够出现真正意义上表空间的概念，更加自由的规划数据文件。]]></description>
			<content:encoded><![CDATA[<p>要说表空间，Mysql的表空间管理远远说不上完善。换句话说，事实上Mysql根本没有真正意义上的表空间管理。Mysql的Innodb包含两种表空间文件模式，默认的共享表空间和每个表分离的独立表空间。只要在my.cnf里面增加innodb_file_per_table=1就可以从共享表空间切换到独立表空间。当然对于已经存在的表，则需要执行alter table MY_TABLE engine=innodb命令迁移数据。</p>
<p><span id="more-1599"></span><strong>共享表空间方式</strong></p>
<p>由于是默认的方式，就暂且理解为Mysql官方推荐的方式。相对而言所有的数据都在一个（或几个）文件中，比较利于管理，而且在操作的时候只需要open这一个（或几个）文件即可，相对来说代价很低。</p>
<p>但问题是在数据达到以G为单位来计算的时候优劣逆转。一个大小惊人的文件很不利于管理，而且对于一个如此巨大的文件来说，读写它需要耗费的资源一样巨大。更加令人费解的是，MySQL竟然将索引和数据保存于同一个文件中，索引和数据之间尚存在资源争用，不利于性能的提升。你当然可以通过innodb_data_file_path的配置规划多个表空间文件，但MySQL的逻辑是“用满后增加”，仅仅是一个文件的拆分而已，不能从根本上分离数据和索引。</p>
<p>之前曾经遭遇到700G以上的表空间文件，而且更加让人郁闷的是对于如此大的文件还在以每天数G的数量增加。由于无法停机，即便是拷贝一下也要花费差不多一夜，只能眼睁睁看着它继续增大而毫无保守可行的办法。</p>
<p><strong>独立表空间方式</strong></p>
<p>相对而言对立表空间每个表都有独立的多个数据文件，而且做到了索引和数据的分离。多个小文件之间很方便的完成跨数据库甚至跨硬件的数据拷贝和迁移。相对来说灵活性很好。</p>
<p>这样做同样带来另一个方面的问题。当数据库中的表数量达到一定级别时，每次操作所涉及的文件过多，如果按照默认Centos的ulimit -n = 1024的话，仅仅只能保证同时打开256个表以内，这在习惯上“拆库拆表”的MySQL数据结构上很难达到要求。尚且这种数据文件的利用率不算很高，当大量“不高”的文件集中起来，浪费的空间也很惊人，更何况最后可能出现的状况不是“一堆K级别的小文件”而是“一堆G级别的大文件”，有点适得其反的意思。你自然可以联想到分区表，又是一个“仅仅做文件拆分而已”，多个分区文件缺一不可。</p>
<p>之前同样遇到过这个问题，MySQL连接大的状况下大量的timeout，但主机负载还算可以，查了一圈才知道是open files限制的问题，限制一修改，负载变得惊人，但连接数却又提升的不多。</p>
<p>总之，两种方法各有所长，部分互补，但都不是解决问题的终极方案。期待MySQL能够出现真正意义上表空间的概念，更加自由的规划数据文件。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.litrin.net/2011/12/06/mysql-innodb%e7%9a%84%e4%b8%a4%e7%a7%8d%e8%a1%a8%e7%a9%ba%e9%97%b4%e6%96%b9%e5%bc%8f/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

