<?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>开源小站 &#187; Litrin</title>
	<atom:link href="http://www.litrin.net/author/admin/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.litrin.net</link>
	<description>It is Cool to OpenSource</description>
	<lastBuildDate>Fri, 03 Feb 2012 04:33:02 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<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>0</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[开源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>
		<item>
		<title>用Nginx和Redis搭建琐碎文件下载站</title>
		<link>http://www.litrin.net/2011/11/22/%e7%94%a8nginx%e5%92%8credis%e6%90%ad%e5%bb%ba%e7%90%90%e7%a2%8e%e6%96%87%e4%bb%b6%e4%b8%8b%e8%bd%bd%e7%ab%99/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=%25e7%2594%25a8nginx%25e5%2592%258credis%25e6%2590%25ad%25e5%25bb%25ba%25e7%2590%2590%25e7%25a2%258e%25e6%2596%2587%25e4%25bb%25b6%25e4%25b8%258b%25e8%25bd%25bd%25e7%25ab%2599</link>
		<comments>http://www.litrin.net/2011/11/22/%e7%94%a8nginx%e5%92%8credis%e6%90%ad%e5%bb%ba%e7%90%90%e7%a2%8e%e6%96%87%e4%bb%b6%e4%b8%8b%e8%bd%bd%e7%ab%99/#comments</comments>
		<pubDate>Tue, 22 Nov 2011 09:46:48 +0000</pubDate>
		<dc:creator>Litrin</dc:creator>
				<category><![CDATA[www]]></category>
		<category><![CDATA[nosql]]></category>
		<category><![CDATA[Redis]]></category>

		<guid isPermaLink="false">http://www.litrin.net/?p=1596</guid>
		<description><![CDATA[对于网站来说，琐碎文件是一个很鸡肋的问题。太多过小文件的管理总有这样那样的问题，特别是当文件数量到达临界时，甚至作一条ls或者rm都无法正常反应。而且正常情况下琐碎文件都会主动缓存，花费太多资源去实现意义也不大。 之前曾经通过nginx的memcache扩展，配合TokyoTyrant Server（每次都觉得很别嘴）这个即支持memcache协议，又可以持久化的Key-Value实现过琐碎文件的管理，但限于Memcache无法逾越的1M鸿沟，只能保存些小文件。 这些天看到一个Nginx第三方插件 HttpRedis, 本身仅仅只是计划用它来做一些短域名跳转之类的应用，忽然觉得Redis没有内容主体的限制，而且性能优良，完全可以用作琐碎文件的下载。 首先下载nginx——不知不觉nginx已经有了正式的1.0以上的版本了！ wget http://www.nginx.org/download/nginx-1.0.10.tar.gz 下载 http_redis: wget http://people.freebsd.org/~osa/ngx_http_redis-0.3.5.tar.gz 开始编译，没什么复杂的： tar vzxf nginx-1.0.10.tar.gz tar vzxf  ngx_http_redis-0.3.5.tar.gz cd nginx-1.0.10 ./configure &#8211;user=www &#8211;group=www &#8211;prefix=/app/nginx  &#8211;add-module=../ngx_http_redis-0.3.5 make -j4 &#38;&#38; make install //部分CPU无法通过编译，还是乖乖的make  &#38;&#38; make install 修改nginx的配置文件： 在http{}之中加入： server { listen 80; server_name www.test.com; location / { set $redis_key CACHE_$request_uri; redis_pass localhost:6379; default_type text/html; } } &#160; 安装redis，还是老一套： apt-get [...]]]></description>
			<content:encoded><![CDATA[<p>对于网站来说，琐碎文件是一个很鸡肋的问题。太多过小文件的管理总有这样那样的问题，特别是当文件数量到达临界时，甚至作一条ls或者rm都无法正常反应。而且正常情况下琐碎文件都会主动缓存，花费太多资源去实现意义也不大。</p>
<p>之前曾经通过nginx的memcache扩展，配合TokyoTyrant Server（每次都觉得很别嘴）这个即支持memcache协议，又可以持久化的Key-Value实现过琐碎文件的管理，但限于Memcache无法逾越的1M鸿沟，只能保存些小文件。</p>
<p><span id="more-1596"></span></p>
<p>这些天看到一个Nginx第三方插件 <a rel="nofollow" target="_blank" href="http://wiki.nginx.org/HttpRedis">HttpRedis</a>, 本身仅仅只是计划用它来做一些短域名跳转之类的应用，忽然觉得Redis没有内容主体的限制，而且性能优良，完全可以用作琐碎文件的下载。</p>
<p>首先下载nginx——不知不觉nginx已经有了正式的1.0以上的版本了！</p>
<p>wget http://www.nginx.org/download/nginx-1.0.10.tar.gz</p>
<p>下载 http_redis:</p>
<p>wget http://people.freebsd.org/~osa/ngx_http_redis-0.3.5.tar.gz</p>
<p>开始编译，没什么复杂的：</p>
<p>tar vzxf nginx-1.0.10.tar.gz<br />
tar vzxf  ngx_http_redis-0.3.5.tar.gz</p>
<p>cd nginx-1.0.10<br />
./configure &#8211;user=www &#8211;group=www &#8211;prefix=/app/nginx  &#8211;add-module=../ngx_http_redis-0.3.5</p>
<p>make -j4 &amp;&amp; make install //部分CPU无法通过编译，还是乖乖的make  &amp;&amp; make install</p>
<p>修改nginx的配置文件：</p>
<p>在http{}之中加入：</p>
<pre>server {

    listen       80;
    server_name  www.test.com;

    location / {
      set $redis_key CACHE_$request_uri;
      redis_pass     localhost:6379;

      default_type   text/html;
    }
}</pre>
<p>&nbsp;</p>
<p>安装redis，还是老一套：</p>
<p>apt-get install redis-serve<br />
/etc/init.d/redis-server start</p>
<p>比如你现在需要通过http://www.test.com/a.html访问一个页面，则可以直接通过下面的方法在redis中塞入一个值，依次类推：</p>
<p>redis-cli<br />
redis &gt; set CACHE_a.html “Hello World!”<br />
OK</p>
<p>redis &gt; set CACHE_/b/a.html “Hello World!”<br />
OK</p>
<p>调试无误后就可以使用程序端直接向redis中写入数据了。</p>
<p>当然，也可以通过设置不同的“default_type”存放图片或者其他类型的文件。 由于此扩展支持redis连接池，而且redis本身也支持master-slaver数据同步，完全可以实现redis端的负载均衡（考虑到redis的性能，我觉得意义不大，除非为了热备份）。需要注意的是Redis是内存数据库，尽管它有定时将数据回写磁盘的机制，但如果不启用vm的话，内存是一个硬性的限制。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.litrin.net/2011/11/22/%e7%94%a8nginx%e5%92%8credis%e6%90%ad%e5%bb%ba%e7%90%90%e7%a2%8e%e6%96%87%e4%bb%b6%e4%b8%8b%e8%bd%bd%e7%ab%99/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>PHP的普青、文青和2B青</title>
		<link>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/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=php%25e7%259a%2584%25e6%2599%25ae%25e9%259d%2592%25e3%2580%2581%25e6%2596%2587%25e9%259d%2592%25e5%2592%258c2b%25e9%259d%2592</link>
		<comments>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/#comments</comments>
		<pubDate>Sat, 05 Nov 2011 14:17:21 +0000</pubDate>
		<dc:creator>Litrin</dc:creator>
				<category><![CDATA[站长的blog]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[业界话题]]></category>

		<guid isPermaLink="false">http://www.litrin.net/?p=1587</guid>
		<description><![CDATA[之前看过一篇东西，大致上说：之所以PHP这么流行，主要是因为PHP太“下贱”。门槛太低，什么样的写法都有。这些年接触下来，也颇有共鸣。正巧赶上最近网上很流行“普青、文青、2B青”的恶搞，抱着“回字到底有几种写法”的态度，对同样的问题进行各种风格的编码，为了更多的体现算法，我剔除了注释。只为搏大家一笑，希望大家也不要拓展开来了。 题目：1只羊第二年后开始繁殖，每年一胎，每胎一只，直到第5年死亡，列出前十年的羊的数量。 首先照例是普青： &#60;?php function foo($n, $echo = true) { $i = 1; $a = 1; while($i &#60; = $n) { $c = $b; $b += $a; $a = $c; if ($i &#62; 5) { $b -= (foo($i -5, false) -1) } if ($echo) echo "The " . $ i ."th year: " . $b [...]]]></description>
			<content:encoded><![CDATA[<p>之前看过一篇东西，大致上说：之所以PHP这么流行，主要是因为PHP太“下贱”。门槛太低，什么样的写法都有。这些年接触下来，也颇有共鸣。正巧赶上最近网上很流行“普青、文青、2B青”的恶搞，抱着“回字到底有几种写法”的态度，对同样的问题进行各种风格的编码，为了更多的体现算法，我剔除了注释。只为搏大家一笑，希望大家也不要拓展开来了。</p>
<p><strong>题目：1只羊第二年后开始繁殖，每年一胎，每胎一只，直到第5年死亡，列出前十年的羊的数量。</strong></p>
<p><span id="more-1587"></span></p>
<p>首先照例是普青：</p>
<pre name=code class=php>&lt;?php
function foo($n, $echo = true)
{
    $i = 1;
    $a = 1;

    while($i &lt; = $n)
    {
        $c = $b;
        $b += $a;
        $a = $c;

        if ($i &gt; 5)
        {
            $b -= (foo($i -5, false) -1)
        }
        if ($echo)
            echo "The " . $ i ."th year: " . $b ."\n";
        i ++;
    }
}
foo(10);
?&gt;</pre>
<p>资质一般，仅仅是做出了题目而已，没有考虑之后代码的维护，以及层层递归造成的性能浪费</p>
<p>接下来是文青：<span class="Apple-style-span" style="font-family: Consolas, Monaco, monospace; font-size: 12px; line-height: 18px; white-space: pre;"> </span></p>
<pre name=code class=php>&lt;?php

function getSheepNumber($finalYear)
{
    if ($finalYear &lt; 1 ) return 0;
    $thisYear = 1;
    $histoyRecord = array ('1' = 1);

    while($thisYear &lt; = $finalYear)
    {
        $lastYear = $thisYear - 1;
        $theYearBeforLastYear = $lastYear - 1;
        if ($theYearBeforLastYear &lt; 0 )
            $historyRecord[$thisYear] = $historyRecord[$lastYear];
        else
            $historyRecord[$thisYear] =
                $historyRecord[$lastYear] + $historyRecord[$theYearBeforLastYea];

        if ($thisYear &gt; 5)
        {
            $theYearBefor5Years = $lastYear - 5;
            $historyRecord[$thisYear] -= $historyRecord[$theYearBefor5Years];
        }
        $thisYear ++;
    }
    return $historyRecord[$thisYear]
}

for ($year = 1; $year&lt;=10; $year++)
{
    switch ($year)
    {
        case 1:
            echo "The 1st year: ";
            break;
        case 2:
            echo "The 2nd year: ";
            break;
        case 3:
            echo "The 3rd year: ";
            break;
        default:
            echo "The " . $year ."th year: ";
            break;
    }

    $sheepCount = getSheepNumber($year);
    echo $sheepCount . "\n";
}
?&gt;</pre>
<p>足够优雅，也有了不错的优化。可惜为了这优雅，循环调用，导致尽管优化了性能但依旧有潜力可挖，而且代码也罗嗦的可以了。谁让文青都不食人间烟火呢？</p>
<p>接下来2B青闪亮登场：</p>
<pre name=code class=php>&lt;?php
function foo($n)
{
    $year_2 = $year_1 = 1;
    $loop = 2;

    while( $n &gt; 0 )
    {
        $last_year = "year_" . $loop;
        $last_2_year = "year_" . ($loop - 1);
        $loop ++;

        $this_year = "year_" . $loop;

        $$this_year = $$last_2_year + $$last_year;

        if ($loop &gt; 5)
            $$this_year -= ${substr($this_year, 0 , -2) . ($loop - 5)};
?&gt;
            The &lt;?php =$loop ?&gt;th year &lt;?php =$$this_year ?&gt;
&lt;?php
    }
}
foo(10);
?&gt;</pre>
<p><span class="Apple-style-span" style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; font-size: 13px; line-height: 19px; white-space: normal;">好吧，我不得不承认PHP的特性真的很方便。为了特性而特性这就是2B。</span></p>
<p>NB青的,颇有爱尔兰(Erlang)风格：</p>
<pre name=code class=php>&lt;?php

function sheepBorn($n, &#038;$list)
{
    if ($list[$n]) return $list[$n];

    if $n < 1   return 0;
    if $n <= 2  return 1;

    $list[$n] = sheepBorn( $n - 1, $list ) + sheepBorn( $n - 2,  $list ) - sheepBorn( $n - 5,  $list );
    return $list[$n];
}

$list = array();
for ($year = 1; $year&lt;=10; $year++)
    echo "The " . $year ."th year: " . sheepBorn($year, $list) . "\n" ;
?&gt;</pre>
<p>够强！可这样的代码，除了表达一下自己的超强算法之外，给别人带来的困惑也会增加，要在注释上多下功夫了。</p>
<p>最终，真相帝降临：
</pre>
<pre name=code class=php>&lt;?php
for($i = 0; $i &lt;= 10; $i ++)
{
    if ($i &lt; 5)
        echo "The " . $i . "year is: 1 ";
    else
        echo "The " . $i . "year is: 0 ";
}</pre>
<p>只有一只羊的情况下确实不能繁殖。</p>
]]></content:encoded>
			<wfw:commentRss>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/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>非阻塞的Python web框架tornado</title>
		<link>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/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=%25e9%259d%259e%25e9%2598%25bb%25e5%25a1%259e%25e7%259a%2584python-web%25e6%25a1%2586%25e6%259e%25b6tornado</link>
		<comments>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/#comments</comments>
		<pubDate>Tue, 18 Oct 2011 08:10:12 +0000</pubDate>
		<dc:creator>Litrin</dc:creator>
				<category><![CDATA[www]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[服务器]]></category>

		<guid isPermaLink="false">http://www.litrin.net/?p=1581</guid>
		<description><![CDATA[公司项目中需要使用长链接方式的获取后端数据库——主要是Redis的实时数据。 由于项目本身是PHP的初次看到这个项目，首先想到的是Apache + mod_php的方式，配合php的ob_start()方式直接调用，就如同我之前的一篇东西所说的那样。可问题不这么简单： 系统是nginx + php-fpm方式，php-fpm“hold不住”过多的Http请求，而nginx需要调整响应时间。 用户数量很多，Apache的消耗很大。本身功能点很小，实现成本不合算。 说到并发，Apache采用的方式是大量的fork进程，通过“人多力量大”的方式应对多个请求，这样的基于进程（线程）模型的并发，一旦调用sleep，进程只是休眠而已，仍然占用着内存，仍然需要进程调度，资源始终得不到释放，资源自然无法得到控制。这些年nginx的流行大多都是因为nginx采用的epoll方式有效的解决这个问题——直接挂掉进程，然后再指定时间内重新启用。这就是传说中的“非阻塞”(asynchronous IO  AIO)。 多并发、轻量级应用，我首先想到的是Python，加上“非阻塞”关键字，得到的结果就是Tornado。 tornado原本是FriendFeed引擎的开源版本，本身就是为解决“C10K”问题而生的。 稍微研究了一下，coding也很简便： #!/usr/bin/env python #By Litrin J #http://www.litrin.net/ import tornado.httpserver import tornado.ioloop import tornado.options import tornado.web import time, redis, hashlib,random from tornado.options import define, options define("port", default=8888, help="run on the given port", type=int) class LongPolling(tornado.web.RequestHandler): minWaitTime = 15 maxWaitTime = 900 RedisHost = [...]]]></description>
			<content:encoded><![CDATA[<p>公司项目中需要使用长链接方式的获取后端数据库——主要是Redis的实时数据。</p>
<p>由于项目本身是PHP的初次看到这个项目，首先想到的是Apache + mod_php的方式，配合php的ob_start()方式直接调用，就如同我之前的<a title="重新认识下PHP的输出" href="http://www.litrin.net/2011/01/16/%e9%87%8d%e6%96%b0%e8%ae%a4%e8%af%86%e4%b8%8bphp%e7%9a%84%e8%be%93%e5%87%ba/">一篇东西</a>所说的那样。可问题不这么简单：</p>
<ol>
<li>系统是nginx + php-fpm方式，php-fpm“hold不住”过多的Http请求，而nginx需要调整响应时间。</li>
<li>用户数量很多，Apache的消耗很大。本身功能点很小，实现成本不合算。<span id="more-1581"></span></li>
</ol>
<p>说到并发，Apache采用的方式是大量的fork进程，通过“人多力量大”的方式应对多个请求，这样的基于进程（线程）模型的并发，一旦调用sleep，进程只是休眠而已，仍然占用着内存，仍然需要进程调度，资源始终得不到释放，资源自然无法得到控制。这些年nginx的流行大多都是因为nginx采用的epoll方式有效的解决这个问题——直接挂掉进程，然后再指定时间内重新启用。这就是传说中的“非阻塞”(asynchronous IO  AIO)。</p>
<p>多并发、轻量级应用，我首先想到的是Python，加上“非阻塞”关键字，得到的结果就是<a rel="nofollow" target="_blank" href="http://www.tornadoweb.org/">Tornado</a>。</p>
<p>tornado原本是FriendFeed引擎的开源版本，本身就是为解决“C10K”问题而生的。</p>
<p>稍微研究了一下，coding也很简便：</p>
<pre class="py" name=code>#!/usr/bin/env python
#By Litrin J
#http://www.litrin.net/
import tornado.httpserver
import tornado.ioloop
import tornado.options
import tornado.web
import time, redis, hashlib,random
from tornado.options import define, options

define("port", default=8888, help="run on the given port", type=int)

class LongPolling(tornado.web.RequestHandler):

    minWaitTime = 15
    maxWaitTime = 900

    RedisHost   = "172.18.194.98"
    RedisPrefix = "Q/MSG%s"

    SignSalt    = "salt"

    StopCode    = "{'stop':1}"

    @tornado.web.asynchronous
    def get(self):
        sUid        = self.get_argument("uid", None)
        sSign       = self.get_argument("sign", None)
        sJsonCall   = self.get_argument("jsonCallback", None)

        if (sUid is None or sSign is None
                or self.checkSign(sUid, sSign) == False):
            raise tornado.web.HTTPError(404)
            self.clear()

        else:
            self.doLongPolling(callback=self.onWaitting)

    def checkSign(self, sUid, sSign):
        return True

    def doLongPolling(self, callback):
        #Check if the client close the connection
        if self.request.connection.stream.closed():
            self.clear()

        sKey        =   self.RedisPrefix % self.uid
        res         =   redis.Redis(self.RedisHost)
        sMessage    =   res.rpop(sKey)
        del res #close the redis at 1st time

        callback(sMessage)

    def onWaitting(self, sMessage):
        if (sMessage is not None):
            self.onRespones(sMessage)
        else:
            iNextPollingTime = time.time() + self.minWaitTime
            if self.minWaitTime &lt; self.maxWaitTime:
                self.minWaitTime *= 2
                #Can't useing time.sleep for no-bloking mode
                tornado.ioloop.IOLoop.instance().add_timeout(
                iNextPollingTime ,
                lambda: self.doLongPolling(callback=self.onWaitting)
            )
            else:
                self.onRespones(self.StopCode)

    def onRespones(self, sMessage):
        sJsonCall   = self.get_argument("jsonCallback", None)
        if sJsonCall is not None:
            sMessage= sJsonCall + "( " + sMessage.decode('utf-8') + ")"

        self.write(sMessage)
        self.finish()

def main():
    tornado.options.parse_command_line()
    application = tornado.web.Application([
        (r"/", LongPolling),
    ])
    http_server = tornado.httpserver.HTTPServer(application)
    http_server.listen(options.port)
    tornado.ioloop.IOLoop.instance().start()

if __name__ == "__main__":
    main()</pre>
<p>一旦建立http连接，系统会每隔一段时间去轮询用户的队列中是否有数据，有数据时才向客户端发送请求，否则就是“长时间小菊花”状态。很简单，仅仅用了不到100行代码的样子。当然，为了安全因素和节省资源，代码里添加了很多限制性的操作，否则可能会更简洁高效。</p>
<p>需要注意的是，tornado的理念就是建立在“非阻塞”基础上的，你当然可以选择time.sleep(n)，但传统上的time.sleep(n)方式的休眠会导致IO阻塞，故只能采用tornado.ioloop.IOLoop.instance().add_timeout 的方法回调来回调去，将下次启动的时间转给系统。话说回来，这是我第一次在Java或JS以外使用回调函数……</p>
<p>初步测试了一下，借助Redis本身就很强的并发能力在台式机上可以每秒钟完成4K次请求以上，并可以保持同时4K以上的访问不掉线，此时的CPU load仍然保持在1以下，单是测试的结果就足以让Apache+Php组合汗颜。</p>
<p>部署的时候采用了单IP多端口方式，服务器有4个核心，决定开4个端口对应，分别是8885~8888，修改</p>
<pre>define("port", default=8888, help="run on the given port", type=int)</pre>
<p>即可</p>
<p>前端nginx用负责负载分发：</p>
<pre>upstream backend {
        server 127.0.0.1:8888;
        server 127.0.0.1:8887;
        server 127.0.0.1:8886;
        server 127.0.0.1:8885;
}
 server{
        listen  80;
        server_name message.test.com;
        keepalive_timeout 65;    #
        proxy_read_timeout 2000; #
        sendfile on;
        tcp_nopush on;
        tcp_nodelay on;

    location / {
        proxy_pass_header Server;
        proxy_set_header Host $http_host;
        proxy_redirect off;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Scheme $scheme;

        proxy_pass  http://backend;
        }
}</pre>
<p>需要注意的是，这样的httpSocket方式很可能被内核认为是SYN攻击，而且对于大量的keep alive而言，很可能超过核心限制，还要修改sysctl参数。</p>
<pre>#系统最大打开文件数
fs.file-max = 201510

#TCP连接的最长时间
net.ipv4.tcp_keepalive_time = 1800
#出现问题的尝试次数
net.ipv4.tcp_keepalive_probes = 15
#检查是否连接的等待时间
net.ipv4.tcp_keepalive_intvl = 60
#不进行SYN cookies防御
net.ipv4.tcp_syncookies = 0</pre>
<pre></pre>
]]></content:encoded>
			<wfw:commentRss>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/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Linux的CPU调速器</title>
		<link>http://www.litrin.net/2011/10/15/linux%e7%9a%84cpu%e8%b0%83%e9%80%9f%e5%99%a8/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=linux%25e7%259a%2584cpu%25e8%25b0%2583%25e9%2580%259f%25e5%2599%25a8</link>
		<comments>http://www.litrin.net/2011/10/15/linux%e7%9a%84cpu%e8%b0%83%e9%80%9f%e5%99%a8/#comments</comments>
		<pubDate>Sat, 15 Oct 2011 05:52:03 +0000</pubDate>
		<dc:creator>Litrin</dc:creator>
				<category><![CDATA[硬件相关]]></category>
		<category><![CDATA[Android]]></category>
		<category><![CDATA[Linux]]></category>

		<guid isPermaLink="false">http://www.litrin.net/?p=1576</guid>
		<description><![CDATA[都说Android手机的耗电和发热是与生俱来的，作为一个Android用户，我也深受其苦。于是刷了一个非官方的固件——Cyanogenmod。既然说是非官固件，总有特别的地方，在省电和性能的均衡方面，CM特地的设置了一个“调速器”的选项。Android本身就是一个Linux的内核，调速器的设置本身就是Linux内核中继承而来的。 在桌面版本的Linux中，一般默认已经安装了调速器的控制台，并可以通过类似gnome控制栏插件的方式简单的启用和调整。对于Server版本，由于定位不同，这样的设置意义不大，但可以手工安装。考虑到要做“绿色IT”，个人觉得在一定范围内适当的使用不但不会影响性能，而且还可以降低主机温度，达到延长主机寿命的功效。具体方法如下： sudo apt-get install cpufrequtils 手工调整CPU频率，需要CPU支持，虽然现如今大多数CPU都支持类似的技术（Speed Step之Intel和nCool之AMD），但恰巧我有一台ATOM芯片的机器就不支持。同样需要注意的是，不是超频，而是降频，指望这种方法为CPU超频的话我劝您还是直接去 BIOS里跳吧 cpufreq-selector -f  频率数，单位是kHz cpufreq-set -d 最高频率 cpufreq-set -u 最低频率 查看CPU状态，不需要太多解释了吧 cpufreq-info 设置CPU运行模式，这才是主要的。系统默认会为CPU设置几种模式方便直接切换 cpufreq-set -g 模式类型 模式类型 powersave，省电模式，简洁明了，就是最省电的状态，CPU始终工作在最低频率上。 userspace，用户定制，手工定制频率的方式。 ondemand，守护模式，自动根据系统负载调整模式，负载越高，频率越高。这是绝大多数系统选择的模式。 conservative，保守模式，有些类似于ondemand，但不同于ondemand一有负载就提高频率到最高，次模式尽量采用较低的模式，直至满载无法承受才提升频率。 performance，性能模式，系统始终工作在最高频率之上。 就拿我的Android手机为例，默认工作在ondemand模式，CPU主频是600mHz（不是新机器，让您见笑了）。下设245, 400, 480, 600共计4个档位。未调整前，大约有超过60％的时间系统工作在600mHz的档位上满负荷工作，而245的档位时间不足1％，耗电和温度自然降不下来。由于手机不同于台式机和服务器，待机时间相比性能而言更为重要——至少我的需求如此，而在大部分时间都应该处在相对空闲的状态下，满负荷大可不必。于是将调速器模式设置为conservative，一周后的统计，245的档位上占据了接近80％，而600的档位不足13％，发热也得到控制，待机时间至少增加了1/3。]]></description>
			<content:encoded><![CDATA[<p>都说Android手机的耗电和发热是与生俱来的，作为一个Android用户，我也深受其苦。于是刷了一个非官方的固件——<a rel="nofollow" target="_blank" href="http://www.cyanogenmod.com" target="_blank">Cyanogenmod</a>。既然说是非官固件，总有特别的地方，在省电和性能的均衡方面，CM特地的设置了一个“调速器”的选项。Android本身就是一个Linux的内核，调速器的设置本身就是Linux内核中继承而来的。</p>
<p><span id="more-1576"></span>在桌面版本的Linux中，一般默认已经安装了调速器的控制台，并可以通过类似gnome控制栏插件的方式简单的启用和调整。对于Server版本，由于定位不同，这样的设置意义不大，但可以手工安装。考虑到要做“绿色IT”，个人觉得在一定范围内适当的使用不但不会影响性能，而且还可以降低主机温度，达到延长主机寿命的功效。具体方法如下：</p>
<p>sudo apt-get install cpufrequtils</p>
<p><strong>手工调整CPU频率</strong>，需要CPU支持，虽然现如今大多数CPU都支持类似的技术（Speed Step之Intel和nCool之AMD），但恰巧我有一台ATOM芯片的机器就不支持。同样需要注意的是，不是超频，而是降频，指望这种方法为CPU超频的话我劝您还是直接去 BIOS里跳吧 <img src='http://www.litrin.net/wp-includes/images/smilies/icon_mrgreen.gif' alt=':mrgreen:' class='wp-smiley' /> </p>
<p>cpufreq-selector -f  频率数，单位是kHz<br />
cpufreq-set -d 最高频率<br />
cpufreq-set -u 最低频率</p>
<p><strong>查看CPU状态，</strong>不需要太多解释了吧</p>
<p>cpufreq-info</p>
<p><strong>设置CPU运行模式，这才是主要的。</strong>系统默认会为CPU设置几种模式方便直接切换</p>
<p>cpufreq-set -g 模式类型</p>
<p>模式类型</p>
<ul>
<li>powersave，省电模式，简洁明了，就是最省电的状态，CPU始终工作在最低频率上。</li>
<li>userspace，用户定制，手工定制频率的方式。</li>
<li>ondemand，守护模式，自动根据系统负载调整模式，负载越高，频率越高。这是绝大多数系统选择的模式。</li>
<li>conservative，保守模式，有些类似于ondemand，但不同于ondemand一有负载就提高频率到最高，次模式尽量采用较低的模式，直至满载无法承受才提升频率。</li>
<li>performance，性能模式，系统始终工作在最高频率之上。</li>
</ul>
<div>就拿我的Android手机为例，默认工作在ondemand模式，CPU主频是600mHz（不是新机器，让您见笑了）。下设245, 400, 480, 600共计4个档位。未调整前，大约有超过60％的时间系统工作在600mHz的档位上满负荷工作，而245的档位时间不足1％，耗电和温度自然降不下来。由于手机不同于台式机和服务器，待机时间相比性能而言更为重要——至少我的需求如此，而在大部分时间都应该处在相对空闲的状态下，满负荷大可不必。于是将调速器模式设置为conservative，一周后的统计，245的档位上占据了接近80％，而600的档位不足13％，发热也得到控制，待机时间至少增加了1/3。</div>
]]></content:encoded>
			<wfw:commentRss>http://www.litrin.net/2011/10/15/linux%e7%9a%84cpu%e8%b0%83%e9%80%9f%e5%99%a8/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>&#8216;xterm-256color&#8217;: unknown terminal type.</title>
		<link>http://www.litrin.net/2011/10/06/xterm-256color-unknown-terminal-type/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=xterm-256color-unknown-terminal-type</link>
		<comments>http://www.litrin.net/2011/10/06/xterm-256color-unknown-terminal-type/#comments</comments>
		<pubDate>Thu, 06 Oct 2011 07:53:22 +0000</pubDate>
		<dc:creator>Litrin</dc:creator>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[硬件相关]]></category>
		<category><![CDATA[Apple]]></category>
		<category><![CDATA[ubuntu]]></category>

		<guid isPermaLink="false">http://www.litrin.net/?p=1573</guid>
		<description><![CDATA[把我的Mac pro升级到Lion之后，照旧通过终端ssh连接到了Ubuntu Server。其他的命令操作均无异常，只是在习惯性的输入了top命令之后，系统没有正常启动top界面，反而出现如下的提示： root@www:~# top &#8216;xterm-256color&#8217;: unknown terminal type. 然而在Centos的主机下却不会出现问题。 说起终端的类型，尽管现在的终端大多都是一个PC而已，事实上在N多年前，终端类型可能仅仅只是体现了厂商的品牌而已，不同的终端类型多如牛毛。他们对于光标、控制字符以及颜色的定义相互都不兼容，历史遗留的问题了。包括之前也发觉很多主机商“backspace”键无效，必须使用ctrl+h进行退格的问题。 在Mac的终端下操作： LitrindeMacBook-Pro:~ litrin$ echo $TERM vt100 LitrindeMacBook-Pro:~ litrin$ infocmp vt100 # Reconstructed via infocmp from file: /usr/share/terminfo/76/vt100 vt100&#124;vt100-am&#124;dec vt100 (w/advanced video), am, mc5i, msgr, xenl, xon, cols#80, it#8, lines#24, vt#3, acsc=``aaffggjjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{&#124;&#124;}}~~, bel=^G, blink=\E[5m$&#60;2&#62;, bold=\E[1m$&#60;2&#62;, clear=\E[H\E[J$&#60;50&#62;, cr=^M, csr=\E[%i%p1%d;%p2%dr, cub=\E[%p1%dD, cub1=^H, cud=\E[%p1%dB, cud1=^J, cuf=\E[%p1%dC, cuf1=\E[C$&#60;2&#62;, cup=\E[%i%p1%d;%p2%dH$&#60;5&#62;, [...]]]></description>
			<content:encoded><![CDATA[<p>把我的Mac pro升级到Lion之后，照旧通过终端ssh连接到了Ubuntu Server。其他的命令操作均无异常，只是在习惯性的输入了top命令之后，系统没有正常启动top界面，反而出现如下的提示：<br />
root@www:~# top<br />
&#8216;xterm-256color&#8217;: unknown terminal type.<br />
然而在Centos的主机下却不会出现问题。</p>
<p><span id="more-1573"></span></p>
<p>说起终端的类型，尽管现在的终端大多都是一个PC而已，事实上在N多年前，终端类型可能仅仅只是体现了厂商的品牌而已，不同的终端类型多如牛毛。他们对于光标、控制字符以及颜色的定义相互都不兼容，历史遗留的问题了。包括之前也发觉很多主机商“backspace”键无效，必须使用ctrl+h进行退格的问题。</p>
<p>在Mac的终端下操作：</p>
<pre>LitrindeMacBook-Pro:~ litrin$ echo $TERM
vt100</pre>
<pre>LitrindeMacBook-Pro:~ litrin$ infocmp vt100
#	Reconstructed via infocmp from file: /usr/share/terminfo/76/vt100
vt100|vt100-am|dec vt100 (w/advanced video),
	am, mc5i, msgr, xenl, xon,
	cols#80, it#8, lines#24, vt#3,
	acsc=``aaffggjjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~,
	bel=^G, blink=\E[5m$&lt;2&gt;, bold=\E[1m$&lt;2&gt;,
	clear=\E[H\E[J$&lt;50&gt;, cr=^M, csr=\E[%i%p1%d;%p2%dr,
	cub=\E[%p1%dD, cub1=^H, cud=\E[%p1%dB, cud1=^J,
	cuf=\E[%p1%dC, cuf1=\E[C$&lt;2&gt;,
	cup=\E[%i%p1%d;%p2%dH$&lt;5&gt;, cuu=\E[%p1%dA,
	cuu1=\E[A$&lt;2&gt;, ed=\E[J$&lt;50&gt;, el=\E[K$&lt;3&gt;, el1=\E[1K$&lt;3&gt;,
	enacs=\E(B\E)0, home=\E[H, ht=^I, hts=\EH, ind=^J, ka1=\EOq,
	ka3=\EOs, kb2=\EOr, kbs=^H, kc1=\EOp, kc3=\EOn, kcub1=\EOD,
	kcud1=\EOB, kcuf1=\EOC, kcuu1=\EOA, kent=\EOM, kf0=\EOy,
	kf1=\EOP, kf10=\EOx, kf2=\EOQ, kf3=\EOR, kf4=\EOS, kf5=\EOt,
	kf6=\EOu, kf7=\EOv, kf8=\EOl, kf9=\EOw, lf1=pf1, lf2=pf2,
	lf3=pf3, lf4=pf4, mc0=\E[0i, mc4=\E[4i, mc5=\E[5i, rc=\E8,
	rev=\E[7m$&lt;2&gt;, ri=\EM$&lt;5&gt;, rmacs=^O, rmam=\E[?7l,
	rmkx=\E[?1l\E&gt;, rmso=\E[m$&lt;2&gt;, rmul=\E[m$&lt;2&gt;,
	rs2=\E&gt;\E[?3l\E[?4l\E[?5l\E[?7h\E[?8h, sc=\E7,
	sgr=\E[0%?%p1%p6%|%t;1%;%?%p2%t;4%;%?%p1%p3%|%t;7%;%?%p4%t;5%;m%?%p9%t\016%e\017%;$&lt;2&gt;,
	sgr0=\E[m\017$&lt;2&gt;, smacs=^N, smam=\E[?7h, smkx=\E[?1h\E=,
	smso=\E[7m$&lt;2&gt;, smul=\E[4m$&lt;2&gt;, tbc=\E[3g,</pre>
<p>说明了主机的默认终端类型正是导致出现问题的“xterm-256color”，对于每一种终端的定义，需要在terminfo文件中定义，Mac下这个文件保存在/usr/share/terminfo/目录下，而这个故障出现的最终原因是Ubuntu或者说Debian系的Linux默认没有xterm-256color终端的定义，而Lion操作系统升级之后，默认的终端类型从之前的vt100变成了xterm-color。</p>
<p>扯了这么多，解决方案有两种，都很简单：</p>
<ol>
<li>让server端支持xterm-256color：apt-get install ncurses-term，安装终端支持。</li>
<li>在Mac下终端的“偏好设置”，“设置”选项卡，“高级”选项，“声明终端为：”修改为“xterm-color”或者其他的类型，看个人喜好了。</li>
</ol>
<p>个人推荐还是采用方法2解决，此外，你也可以通过定义其他类型的终端，解决其他类似的问题。</p>
<p>&nbsp;</p>
<p><span style="font-family: Arial, Helvetica, sans-serif; color: #ffffff; background-color: #000000;">2011－10－05（<strong>PST</strong>）来自：<a rel="nofollow" target="_blank" style="color: #ffffff;" href="http://zh.wikipedia.org/wiki/史蒂夫·乔布斯">乔布斯</a>的MacBook Pro</span></p>
]]></content:encoded>
			<wfw:commentRss>http://www.litrin.net/2011/10/06/xterm-256color-unknown-terminal-type/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>使用linux的/dev/shm</title>
		<link>http://www.litrin.net/2011/09/30/%e4%bd%bf%e7%94%a8linux%e7%9a%84devshm/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=%25e4%25bd%25bf%25e7%2594%25a8linux%25e7%259a%2584devshm</link>
		<comments>http://www.litrin.net/2011/09/30/%e4%bd%bf%e7%94%a8linux%e7%9a%84devshm/#comments</comments>
		<pubDate>Fri, 30 Sep 2011 07:30:34 +0000</pubDate>
		<dc:creator>Litrin</dc:creator>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[硬件相关]]></category>

		<guid isPermaLink="false">http://www.litrin.net/?p=1570</guid>
		<description><![CDATA[挖掘一个很久之前的设想，06年的，之前的想法是用tmpfs，tmpfs是RAM和磁盘swap的混杂机制，大部分的情况是优先使用内存空间，尽管本质上是非持久存储，但性能上远不是磁盘甚至固态硬盘所能企及的。而且现在是内存空前便宜的时代，类似的方案例如memcache等，变得更有价值了。 默认的Linux发行版中的内核配置都会开启tmpfs，映射到了/dev/下的shm目录。可以通过df 命令查看结果如下： Filesystem Size Used Avail Use% Mounted on /dev/sda1 146G 14G 125G 10% / varrun 501M 84K 501M 1% /var/run varlock 501M 0 501M 0% /var/lock udev 501M 32K 501M 1% /dev devshm 501M 0 501M 0% /dev/shm 默认配置的shm分区正好是内存的一半。 可以重新调整大小： vi /etc/fstab tmpfs /dev/shm tmpfs defaults,size=4096M 0 0 umount /dev/shm; mount /dev/shm 不同于文件系统/dev/shm不是一个文件，是一个目录，完全可以通过文件链接的方式挂装到指定目录，还是推荐采用mount方式： [...]]]></description>
			<content:encoded><![CDATA[<p>挖掘一个<a title="关于使用tmpfs优化的设想" href="http://www.litrin.net/2006/06/21/%e5%85%b3%e4%ba%8e%e4%bd%bf%e7%94%a8tmpfs%e4%bc%98%e5%8c%96%e7%9a%84%e8%ae%be%e6%83%b3/">很久之前的设想</a>，06年的，之前的想法是用tmpfs，tmpfs是RAM和磁盘swap的混杂机制，大部分的情况是优先使用内存空间，尽管本质上是非持久存储，但性能上远不是磁盘甚至固态硬盘所能企及的。而且现在是内存空前便宜的时代，类似的方案例如memcache等，变得更有价值了。</p>
<p>默认的Linux发行版中的内核配置都会开启tmpfs，映射到了/dev/下的shm目录。可以通过df 命令查看结果如下：</p>
<pre>Filesystem            Size  Used Avail Use% Mounted on
/dev/sda1             146G   14G  125G  10% /
varrun                501M   84K  501M   1% /var/run
varlock               501M     0  501M   0% /var/lock
udev                  501M   32K  501M   1% /dev
devshm                501M     0  501M   0% /dev/shm</pre>
<p><span id="more-1570"></span></p>
<p>默认配置的shm分区正好是内存的一半。</p>
<p>可以重新调整大小：</p>
<p>vi /etc/fstab<br />
tmpfs /dev/shm tmpfs defaults,size=4096M 0 0</p>
<p>umount /dev/shm; mount /dev/shm</p>
<p>不同于文件系统/dev/shm不是一个文件，是一个目录，完全可以通过文件链接的方式挂装到指定目录，还是推荐采用mount方式：</p>
<p>mount &#8211;bind /dev/shm /data</p>
]]></content:encoded>
			<wfw:commentRss>http://www.litrin.net/2011/09/30/%e4%bd%bf%e7%94%a8linux%e7%9a%84devshm/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>从SQL到NoSQL</title>
		<link>http://www.litrin.net/2011/09/26/%e4%bb%8esql%e5%88%b0nosql/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=%25e4%25bb%258esql%25e5%2588%25b0nosql</link>
		<comments>http://www.litrin.net/2011/09/26/%e4%bb%8esql%e5%88%b0nosql/#comments</comments>
		<pubDate>Mon, 26 Sep 2011 05:13:28 +0000</pubDate>
		<dc:creator>Litrin</dc:creator>
				<category><![CDATA[数据库应用]]></category>
		<category><![CDATA[DataBase]]></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=1559</guid>
		<description><![CDATA[之前接触到的基于LAMP平台的网站，凡是稍微有一点量上去的，在数据结构的设计上总是离不开“拆库拆表”。同样，作为网站的数据结构设计，很少会出现类似ERP系统才会应用到的函数（function）、存储过程（procudce）、触发器（trigger）什么的——曾经看过有ERP系统的所有逻辑都是通过这3者保存在数据库端的。加上MySQL本身的一些因素，用之前一个朋友的话说：“Mysql在网站中的地位更多的是一个数据容器，而不是完整意义上的数据库。” 既然仅仅只是当作一个容器，从性能上考虑那为什么要用MySQL呢？ 最近在研究一些NoSQL的东西，memcache类这类的纯Key-value；redis这类key-list；以及更加接近于关系型的MongoDB。这类的数据容器相较MySQL这类SQL数据库而言，更多的都是在性能上做大幅提升。从搜索能力上讲，MySQL的搜索能力又远不及Sphinx或者Solr这类单纯的索引服务器。如果说关系型数据库的优势在于一致性。那事物操作本身也不是MySQL所擅长的，“拆库拆表”的设计理念更是打破了一致性的优势。MySQL剩下的优势恐怕只剩下了“便于维护”这一条了吧。 相比MySQL这些年做的改进，几乎都是在完善事物处理这类高级的SQL逻辑。之前人们选择MySQL的原因，其实很少是由于MySQL的事务处理，而是性能方面的优势。当MySQL不再将性能的提升作为首要任务时，加上近一段时间风声水起的SNS热潮，MySQL的王者地位已经逐渐被NoSQL数据库挑战——甚至出现了完全排除MySQL的SNS框架。 据说MySQL5.6中启用了对于Memcache的支持，看来连MySQL自己也顿悟了……]]></description>
			<content:encoded><![CDATA[<p>之前接触到的基于LAMP平台的网站，凡是稍微有一点量上去的，在数据结构的设计上总是离不开“拆库拆表”。同样，作为网站的数据结构设计，很少会出现类似ERP系统才会应用到的函数（function）、存储过程（procudce）、触发器（trigger）什么的——曾经看过有ERP系统的所有逻辑都是通过这3者保存在数据库端的。加上MySQL本身的一些因素，用之前一个朋友的话说：“Mysql在网站中的地位更多的是一个数据容器，而不是完整意义上的数据库。”</p>
<p><span id="more-1559"></span>既然仅仅只是当作一个容器，从性能上考虑那为什么要用MySQL呢？</p>
<p>最近在研究一些NoSQL的东西，memcache类这类的纯Key-value；redis这类key-list；以及更加接近于关系型的MongoDB。这类的数据容器相较MySQL这类SQL数据库而言，更多的都是在性能上做大幅提升。从搜索能力上讲，MySQL的搜索能力又远不及Sphinx或者Solr这类单纯的索引服务器。如果说关系型数据库的优势在于一致性。那事物操作本身也不是MySQL所擅长的，“拆库拆表”的设计理念更是打破了一致性的优势。MySQL剩下的优势恐怕只剩下了“便于维护”这一条了吧。</p>
<div id="attachment_1561" class="wp-caption aligncenter" style="width: 310px"><img class="size-medium wp-image-1561" title="mysql mongodb 写入对比" src="http://www.litrin.net/wp-content/uploads/2011/09/mysql-mongodb-write-300x179.png" alt="mysql mongodb 写入对比" width="300" height="179" /><p class="wp-caption-text">mysql mongodb 写入对比</p></div>
<div id="attachment_1562" class="wp-caption aligncenter" style="width: 310px"><img class="size-medium wp-image-1562" title="mysql mongodb 查询对比" src="http://www.litrin.net/wp-content/uploads/2011/09/mysql-mongodb-read-300x244.png" alt="mysql mongodb 查询对比" width="300" height="244" /><p class="wp-caption-text">mysql mongodb 查询对比</p></div>
<div id="attachment_1560" class="wp-caption aligncenter" style="width: 310px"><img class="size-medium wp-image-1560" title="mysql mongodb 资源对比" src="http://www.litrin.net/wp-content/uploads/2011/09/mysql-mongodb-300x202.png" alt="mysql mongodb 资源对比" width="300" height="202" /><p class="wp-caption-text">mysql mongodb 资源对比</p></div>
<p>相比MySQL这些年做的改进，几乎都是在完善事物处理这类高级的SQL逻辑。之前人们选择MySQL的原因，其实很少是由于MySQL的事务处理，而是性能方面的优势。当MySQL不再将性能的提升作为首要任务时，加上近一段时间风声水起的SNS热潮，MySQL的王者地位已经逐渐被NoSQL数据库挑战——甚至出现了完全排除MySQL的SNS框架。</p>
<p>据说MySQL5.6中启用了对于Memcache的支持，看来连MySQL自己也顿悟了……</p>
]]></content:encoded>
			<wfw:commentRss>http://www.litrin.net/2011/09/26/%e4%bb%8esql%e5%88%b0nosql/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>*nix全家福</title>
		<link>http://www.litrin.net/2011/09/10/nix%e5%85%a8%e5%ae%b6%e7%a6%8f/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=nix%25e5%2585%25a8%25e5%25ae%25b6%25e7%25a6%258f</link>
		<comments>http://www.litrin.net/2011/09/10/nix%e5%85%a8%e5%ae%b6%e7%a6%8f/#comments</comments>
		<pubDate>Sat, 10 Sep 2011 05:20:16 +0000</pubDate>
		<dc:creator>Litrin</dc:creator>
				<category><![CDATA[站长的blog]]></category>

		<guid isPermaLink="false">http://www.litrin.net/?p=1551</guid>
		<description><![CDATA[赶上中秋节小长假，本身就有团圆的一重含义在，于是在收拾房间的时候，将所有的操作系统安装介质找了出来，拍张全家福吧。 *nix成员名单： Solaris 10 授权包，for sparc and x86 Solaris 9 安装包，for sparc Ubuntu 606， for x86, x86_64, power mac Ubuntu 804，for x86, x86_64 Ubuntu 904，for x86 Suse Linux 10.2 Fedora 5 for x86_64 此外，趁着中秋假期前来串门的还有： Windows XP Home Windows XP Pro Juniper OS 直接看图！]]></description>
			<content:encoded><![CDATA[<p>赶上中秋节小长假，本身就有团圆的一重含义在，于是在收拾房间的时候，将所有的操作系统安装介质找了出来，拍张全家福吧。</p>
<p>*nix成员名单：</p>
<ul>
<li>Solaris 10 授权包，for sparc and x86</li>
<li>Solaris 9 安装包，for sparc</li>
<li>Ubuntu 606， for x86, x86_64, power mac</li>
<li>Ubuntu 804，for x86, x86_64</li>
<li>Ubuntu 904，for x86</li>
<li>Suse Linux 10.2</li>
<li>Fedora 5 for x86_64</li>
</ul>
<div>此外，趁着中秋假期前来串门的还有：</div>
<div>
<ul>
<li>Windows XP Home</li>
<li>Windows XP Pro</li>
<li>Juniper OS</li>
</ul>
<div><a title="操作系统全家福" href="http://www.litrin.net/wp-content/uploads/2011/09/DSCN0016.jpg" target="_blank">直接看图！</a></div>
</div>
<p><span id="more-1551"></span></p>
<p><img class="aligncenter size-full wp-image-1554" style="vertical-align: middle;" title="操作系统全家福" src="http://www.litrin.net/wp-content/uploads/2011/09/DSCN0016.jpg" alt="操作系统全家福" width="800" height="600" /></p>
]]></content:encoded>
			<wfw:commentRss>http://www.litrin.net/2011/09/10/nix%e5%85%a8%e5%ae%b6%e7%a6%8f/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>posix的特性——fork</title>
		<link>http://www.litrin.net/2011/08/31/posix%e7%9a%84%e7%89%b9%e6%80%a7%e2%80%94%e2%80%94fork/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=posix%25e7%259a%2584%25e7%2589%25b9%25e6%2580%25a7%25e2%2580%2594%25e2%2580%2594fork</link>
		<comments>http://www.litrin.net/2011/08/31/posix%e7%9a%84%e7%89%b9%e6%80%a7%e2%80%94%e2%80%94fork/#comments</comments>
		<pubDate>Wed, 31 Aug 2011 05:28:42 +0000</pubDate>
		<dc:creator>Litrin</dc:creator>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[Unix]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://www.litrin.net/?p=1541</guid>
		<description><![CDATA[记得之前曾经在一段Python中介绍过python的mulitprocess模块在windows的不兼容。其中提及了linux/Unix特有的fork方式，而windows无法实现导致的死循环。当时只是提到了一下，重点不同的关系，没有深究。 fork，顾名思义就是一把叉子，或者专业一点叫做复制叉。作为sys/type.h的一个函数，系统在每次调用fork()之后，将会以此为分叉，对进程本身进行复制，新的进程和旧进程有近乎完全一致的cpu时间和内存寄存器。 这本身并不重要，重要的是对于fork()函数的返回而言，父进程返回的是子进程的pid，而子进程返回的是0，当然还有一个-1的返回表示fork()的失败。对与C大致如此： #include &#60;unistd.h&#62;; #include &#60;sys/types.h&#62;; main () { pid_t pid; pid=fork(); if (pid &#60; 0) printf("error in fork!"); else { if (pid == 0) { printf("i am the child process, my process id is %d\n",getpid()); exit(); } else { printf("i am the parent process, my process id is %d\n",getpid()); exit(); } } } [...]]]></description>
			<content:encoded><![CDATA[<p>记得之前曾经在一段Python中介绍过<a title="python multiprocessing的问题" href="http://www.litrin.net/2010/06/23/python-multiprocessing%e7%9a%84%e9%97%ae%e9%a2%98/">python的mulitprocess模块在windows的不兼容</a>。其中提及了linux/Unix特有的fork方式，而windows无法实现导致的死循环。当时只是提到了一下，重点不同的关系，没有深究。</p>
<p>fork，顾名思义就是一把叉子，或者专业一点叫做复制叉。作为sys/type.h的一个函数，系统在每次调用fork()之后，将会以此为分叉，对进程本身进行复制，新的进程和旧进程有近乎完全一致的cpu时间和内存寄存器。</p>
<p><span id="more-1541"></span></p>
<p><img src="http://www.litrin.net/wp-content/uploads/2011/08/linux_fork.gif" alt="fork模型" title="fork模型" width="246" height="152" class="aligncenter size-full wp-image-1545" /></p>
<p>这本身并不重要，重要的是对于fork()函数的返回而言，父进程返回的是子进程的pid，而子进程返回的是0，当然还有一个-1的返回表示fork()的失败。对与C大致如此：</p>
<pre>#include &lt;unistd.h&gt;;
#include &lt;sys/types.h&gt;;

main ()
{
        pid_t pid;
        pid=fork();

        if (pid &lt; 0)
                printf("error in fork!");
        else
        {
			if (pid == 0)
                        {
                                 printf("i am the child process, my process id is %d\n",getpid());
		                 exit();
                        }
			else
                        {
                                printf("i am the parent process, my process id is %d\n",getpid());
				exit();
                         }
         }
}</pre>
<p>执行后，父进程和子进程分别将自己的Pid打印出来。</p>
<p>既然如此，对于我常用的php来说，可以同样做到后端执刑一些耗时的操作，从而达到异步的效果：</p>
<pre name=code class="php">function mulitProcess()/*{{{*/
{
        if (function_exists(pcntl_fork))
        {
            $pid = pcntl_fork();

		    if ( $pid === -1 )
		    {
		    	return false;
		    }
		    elseif ( $pid )
		    {
                        usleep(10);
                        exit();
                    }
                    else
                    {
                         doBackground();
                    }
        }
        // windows system or php not support PCNTL libs
        else
        {
			doBackground();
        }
}</pre>
<p>对于很多守护进程来说，脱离shell（即“脱壳”）正是利用了这种方式进行进程复制。对与PHP来说需要进行2次fork之后配合一个死循环即可,当然为了防止死循环真的“死掉”需要sleep()函数来进行休眠：</p>
<pre name=code class="php">function daemonize() /*{{{*/
{
    $pid    =   pcntl_fork();

    if (-1 == $pid)
    {
        return false;
    }
    elseif ($pid)  //parent process
    {
        usleep(500);
        exit();
    }
    $sid    =   posix_setsid();

    if (!$sid)
    {
        return false;
    }

    $pid    =   pcntl_fork();

    if ( -1 == $pid )
    {
        return false;
    }
    elseif ($pid)
    {
        usleep(500);
        exit(0);
    }

    // deny process display and io
    if (defined('STDIN'))
            fclose(STDIN);

    if (defined('STDOUT'))
            fclose(STDOUT);

    if (defined('STDERR'))
            fclose(STDERR);
    while(true)
            doSomeThing();

}/*}}}*/</pre>
<p>需要注意的是，windows没有fork()，php直接屏蔽了PCNL函数库，而python相对没有一棒子打死。Python采用的方式等于在命令行重新调用一次脚本，如果直接将没有考虑到这个问题的python脚本直接移植windows的话进程数量将会爆炸式增长，很快就会导致资源耗尽。由于我在windows上大多只是进行测试而已，多进程带来的性能优势不重要，习惯上我的方法就是使用threading模块替换掉mulitprocessing模块。写个示例：</p>
<pre name=code class="python">
try: #if os.name == 'posix':
    from multiprocessing import Process, Queue
except: #else:
    from threading import Thread as Process
    from Queue import Queue
</pre>
<p><img src="http://www.litrin.net/wp-content/uploads/2011/08/windows_fork_sim-300x125.gif" alt="windows模拟fork模型" title="悲催的windows模拟fork模型" width="300" height="125" class="aligncenter size-medium wp-image-1546" /></p>
]]></content:encoded>
			<wfw:commentRss>http://www.litrin.net/2011/08/31/posix%e7%9a%84%e7%89%b9%e6%80%a7%e2%80%94%e2%80%94fork/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Hadoop的单机部署</title>
		<link>http://www.litrin.net/2011/08/19/hadoop%e7%9a%84%e5%8d%95%e6%9c%ba%e9%83%a8%e7%bd%b2/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=hadoop%25e7%259a%2584%25e5%258d%2595%25e6%259c%25ba%25e9%2583%25a8%25e7%25bd%25b2</link>
		<comments>http://www.litrin.net/2011/08/19/hadoop%e7%9a%84%e5%8d%95%e6%9c%ba%e9%83%a8%e7%bd%b2/#comments</comments>
		<pubDate>Fri, 19 Aug 2011 13:23:08 +0000</pubDate>
		<dc:creator>Litrin</dc:creator>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[数据库应用]]></category>
		<category><![CDATA[DataBase]]></category>
		<category><![CDATA[Hadoop]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[ubuntu]]></category>
		<category><![CDATA[服务器]]></category>

		<guid isPermaLink="false">http://www.litrin.net/?p=1528</guid>
		<description><![CDATA[&#160; 要说最近最热的云计算，不得不提Hadoop。这个项目就是为集群运算而生的。依赖于它的项目n多，个人感觉hadoop已经逐渐成为一个“基于Java的分布式运算中间件”。 这里安装的hadoop为ver 0.21.0版本，包含了HDFS分布式文件系统。平台为老一套的Ubuntu 1104 server for amd64。 既然是Java Base的，首先要准备jdk环境。默认1104已经把java从apt中剔除了——跟oracle收购sun不无关系，尽管openjdk还在，我还是建议安装sun-jdk。具体实现如下： echo “deb http://archive.canonical.com/ natty partner” &#62;&#62; /etc/apt/sources.list #添加源 apt-get update apt-get install sun-java-jdk 文件多而大，耐心等待。 基础环境 默认apt方式安装的jdk目录为/usr/lib/jvm/java-6-sun ，等待jdk完成之后， echo "/usr/lib/jvm/java-6-sun"  &#62; /etc/jvm 官方建议关闭ipv6，尽管我不清楚有什么影响 echo "blacklist ipv6" &#62;&#62; /etc/modprobe.d/blacklist 建立用户/组，没什么要解释的 addgroup hadoop adduser --ingroup hadoop hadoop 修改环境变量，vi /etc/bash.bashrc，在末尾添加： export JAVA_HOME=/usr/lib/jvm/java-6-sun export JDK_HOME=$JAVA_HOME export PATH=$PATH:$JAVA_HOME/bin 切换用户到hadoop, su &#8211; hadoop 调通ssh，具体参见这里之前的东西。 mkdir [...]]]></description>
			<content:encoded><![CDATA[<p>&nbsp;</p>
<p>要说最近最热的云计算，不得不提<a rel="nofollow" target="_blank" href="http://hadoop.apache.org" target="_blank">Hadoop</a>。这个项目就是为集群运算而生的。依赖于它的项目n多，个人感觉hadoop已经逐渐成为一个“基于Java的分布式运算中间件”。</p>
<p>这里安装的hadoop为ver 0.21.0版本，包含了HDFS分布式文件系统。平台为老一套的Ubuntu 1104 server for amd64。</p>
<p>既然是Java Base的，首先要准备jdk环境。默认1104已经把java从apt中剔除了——跟oracle收购sun不无关系，尽管openjdk还在，我还是建议安装sun-jdk。具体实现如下：</p>
<p><span id="more-1528"></span><br />
echo “deb http://archive.canonical.com/ natty partner” &gt;&gt; /etc/apt/sources.list #添加源<br />
apt-get update<br />
apt-get install sun-java-jdk</p>
<p>文件多而大，耐心等待。</p>
<p><strong>基础环境</strong></p>
<p><strong></strong>默认apt方式安装的jdk目录为/usr/lib/jvm/java-6-sun ，等待jdk完成之后，</p>
<pre>echo "/usr/lib/jvm/java-6-sun"  &gt; /etc/jvm</pre>
<p>官方建议关闭ipv6，尽管我不清楚有什么影响</p>
<pre>echo "blacklist ipv6" &gt;&gt; /etc/modprobe.d/blacklist</pre>
<p>建立用户/组，没什么要解释的</p>
<pre>addgroup hadoop
adduser --ingroup hadoop hadoop</pre>
<p>修改环境变量，vi /etc/bash.bashrc，在末尾添加：</p>
<pre>export JAVA_HOME=/usr/lib/jvm/java-6-sun
export JDK_HOME=$JAVA_HOME
export PATH=$PATH:$JAVA_HOME/bin</pre>
<p>切换用户到hadoop, su &#8211; hadoop</p>
<p>调通ssh，具体参见<a title="用publickey验证登录SSH服务器" href="http://www.litrin.net/2006/04/10/%e7%94%a8publickey%e9%aa%8c%e8%af%81%e7%99%bb%e5%bd%95ssh%e6%9c%8d%e5%8a%a1%e5%99%a8/" target="_blank">这里</a>之前的东西。</p>
<pre>mkdir .ssh
cd .ssh
ssh-keygen -t rsa
cat id_rsa.pub &gt;&gt; authorized_keys
ssh localhost</pre>
<p><strong>配置Hadoop</strong></p>
<p>我默认已经使用hadoop用户进行操作，root权限可以不用了。</p>
<p>将下载后的hadoop保存在适当的目录下，我选择了/opt/hadoop目录。</p>
<p>修改/opt/hadoop/conf/hadoop-env.sh文件中，添加 export JAVA_HOME=/usr/lib/jvm/java-6-sun</p>
<p>cd /opt/hadoop/conf 一堆的配置文件要改。</p>
<p>conf/core-site.xml:</p>
<pre>&lt;configuration&gt;
     &lt;property&gt;
         &lt;name&gt;fs.default.name&lt;/name&gt;&lt;!--文件系统名称--&gt;
        &lt;!--&lt;value&gt;hdfs://localhost:9000&lt;/value&gt;单机，不使用集群文件系统 --&gt;&lt;value&gt;/date/hadoop&lt;/value&gt;
     &lt;/property&gt;
&lt;/configuration&gt;</pre>
<p>conf/hdfs-site.xml:</p>
<pre>&lt;configuration&gt;
     &lt;property&gt;
         &lt;name&gt;dfs.replication&lt;/name&gt;
         &lt;value&gt;1&lt;/value&gt;
     &lt;/property&gt;
&lt;/configuration&gt;</pre>
<p>conf/mapred-site.xml:</p>
<pre>&lt;configuration&gt;
     &lt;property&gt;
         &lt;name&gt;mapred.job.tracker&lt;/name&gt;
         &lt;value&gt;localhost:9001&lt;/value&gt;
     &lt;/property&gt;
&lt;/configuration&gt;</pre>
<p>需要注意的是，不同的版本号之间，配置方式有细微的不同。</p>
<p>配置OK!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.litrin.net/2011/08/19/hadoop%e7%9a%84%e5%8d%95%e6%9c%ba%e9%83%a8%e7%bd%b2/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Linux 3</title>
		<link>http://www.litrin.net/2011/08/17/linux-3/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=linux-3</link>
		<comments>http://www.litrin.net/2011/08/17/linux-3/#comments</comments>
		<pubDate>Wed, 17 Aug 2011 09:15:24 +0000</pubDate>
		<dc:creator>Litrin</dc:creator>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[ubuntu]]></category>

		<guid isPermaLink="false">http://www.litrin.net/?p=1523</guid>
		<description><![CDATA[最近Linux更新到了3.x的版本，彻底抛弃了2.x。赶着这波热乎劲，把系统内核升级到了3.0.2。贴个uname -a炫耀下： Linux www 3.0.13.0.1 #2 SMP Wed Aug 17 16:05:25 CST 2011 x86_64 x86_64 x86_64 GNU/Linux 作为debian系的Ubuntu，相对制作kernel包还是比较容易的。 wget http://www.kernel.org/pub/linux/kernel/v3.0/linux-3.0.2.tar.bz2 apt-get install build-essential kernel-package tar vzxf  linux-3.0.2.tar.bz2 cd linux-3.0.2 make menuconfig make-kpkg &#8211;initrd  kernel_image kernel-headers 漫长的编译之后上层目录会出现 linux-headers-* 和linux-image-*连个包，直接dpkg -i 就OK了，很方便。 话说回来，这次2-&#62;3的升级有点不知所云，没有什么较大的新特性的引入，仅仅是Linus大神认为的2.6.39的版本号太大了。也不知道今后linux是否还延续“单数不稳定的传统”。相比2.2-&#62;2.4, 2.4-&#62;2.6的跨越，反而成了讽刺。]]></description>
			<content:encoded><![CDATA[<p>最近Linux更新到了3.x的版本，彻底抛弃了2.x。赶着这波热乎劲，把系统内核升级到了3.0.2。贴个uname -a炫耀下：</p>
<pre>Linux www 3.0.13.0.1 #2 SMP Wed Aug 17 16:05:25 CST 2011 x86_64 x86_64 x86_64 GNU/Linux</pre>
<p><span id="more-1523"></span>作为debian系的Ubuntu，相对制作kernel包还是比较容易的。</p>
<p>wget http://www.kernel.org/pub/linux/kernel/v3.0/linux-3.0.2.tar.bz2</p>
<p>apt-get install build-essential kernel-package</p>
<p>tar vzxf  linux-3.0.2.tar.bz2</p>
<p>cd linux-3.0.2</p>
<p>make menuconfig</p>
<p>make-kpkg &#8211;initrd  kernel_image kernel-headers</p>
<p>漫长的编译之后上层目录会出现 linux-headers-* 和linux-image-*连个包，直接dpkg -i 就OK了，很方便。</p>
<p>话说回来，这次2-&gt;3的升级有点不知所云，没有什么较大的新特性的引入，仅仅是Linus大神认为的2.6.39的版本号太大了。也不知道今后linux是否还延续“单数不稳定的传统”。相比2.2-&gt;2.4, 2.4-&gt;2.6的跨越，反而成了讽刺。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.litrin.net/2011/08/17/linux-3/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>开源小站的基础结构</title>
		<link>http://www.litrin.net/2011/08/12/%e5%bc%80%e6%ba%90%e5%b0%8f%e7%ab%99%e7%9a%84%e5%9f%ba%e7%a1%80%e7%bb%93%e6%9e%84/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=%25e5%25bc%2580%25e6%25ba%2590%25e5%25b0%258f%25e7%25ab%2599%25e7%259a%2584%25e5%259f%25ba%25e7%25a1%2580%25e7%25bb%2593%25e6%259e%2584</link>
		<comments>http://www.litrin.net/2011/08/12/%e5%bc%80%e6%ba%90%e5%b0%8f%e7%ab%99%e7%9a%84%e5%9f%ba%e7%a1%80%e7%bb%93%e6%9e%84/#comments</comments>
		<pubDate>Fri, 12 Aug 2011 05:06:03 +0000</pubDate>
		<dc:creator>Litrin</dc:creator>
				<category><![CDATA[www]]></category>
		<category><![CDATA[站长的blog]]></category>
		<category><![CDATA[硬件相关]]></category>
		<category><![CDATA[网络和安全]]></category>

		<guid isPermaLink="false">http://www.litrin.net/?p=1516</guid>
		<description><![CDATA[之前有朋友问过开源小站的架构是怎样的，我回答道：“标准的wordpress，稍微做了一些调整。”时隔一段时期，几经搬迁，这次重新整理了一下开源小站的结构，就当分享罢了。 “开源小站”最初是基于drupal构建，基础数据库是postgresql。后来由于drupal的性能问题以及框死了的postgresql，只能整体迁移到了wordpress+mysql。当然迁移好之后，考虑到drupal和wordpress的链接地址的不同，修改了wordpress的部分代码，让之前的外链不至于失效。后来索性就通过apache的mod_rewrite模块添加了301跳转，wordpress的版本也可以随着“持续演进”了。 由于wordpress或者这一类的CMS系统本身不是一个性能优化的产品，后来一段时间搬迁过一次，平台是vps的虚拟机。性能问题很突出，首页打开竟然需要2.7秒以上，加上传输耗时，超出了3秒的范围，严重影响用户体验。于是不得不在wordpress的代码上进行修改。页面全部缓存到了memcache。响应时间减少到1.5秒以下，基本可以满足大部分需求。但这样就无法跟随wordpress持续演进了。wp的版本只能定死在了某个版本号上。考虑到安全因素，我只能说，这是3.1之前的“某个版本”。 关于硬件环境，最初的drupal版本是一台相对很“牛”的机器，双核志强*2 + 4G RAM+ RAID5。所以当初提供了很多开源系统镜像下载。系统的瓶颈出现在网络带宽上，可谓“衣食无忧”。 之后的变故，加上域名备案的因素，使得网站一度只能跑在一台win2003的virtual server上，内存只有64M，从一个极端到了另一个极端。之后很长一段时间，开源小站始终运行在虚拟机或者vps之上。当然，由此带来的流量下滑不是一点点，但访客停留时间大大增加。也算抹平了。 后来，设法弄到了一点资源，与别人合用了一台主机，4核Xeon+4GRAM + RAID1，磁盘总是不够用，甚至为此都不保存访问日志。 后来，曾经狂热的支持了一把atom，于是自己用atom的平台搭建了一台服务器，1u高度标准机箱，atom-230,1.6G +2GRAM+160G的笔记本硬盘，操作系统选择了Ubuntu的804 Server，竟然跑得很流畅，这就是现在开源小站的主机。当然，也感谢某位朋友，免费提供了他们所代理的某款网络安全产品，用以作为我们小站的前端防火墙。在前端防火墙之后，通过端口映射的方式完成了网站80端口的指向。负担一部分iptable的任务，同时也作为SSH和远程重起主机的跳板。 之后，加入了xml-rpc服务，同时将文章推送到几个免费博客和litrinjiang.appspot.com，尽管格式全乱，但至少也算是备份吧。 &#160;]]></description>
			<content:encoded><![CDATA[<p>之前有朋友问过开源小站的架构是怎样的，我回答道：“标准的wordpress，稍微做了一些调整。”时隔一段时期，几经搬迁，这次重新整理了一下开源小站的结构，就当分享罢了。</p>
<p>“开源小站”最初是基于drupal构建，基础数据库是postgresql。后来由于drupal的性能问题以及框死了的postgresql，只能<a title="WordPress的家" href="http://www.litrin.net/2009/03/17/wordpress%e7%9a%84%e5%ae%b6/">整体迁移到了wordpress+mysql</a>。当然迁移好之后，考虑到drupal和wordpress的链接地址的不同，修改了wordpress的部分代码，让之前的外链不至于失效。后来索性就通过apache的mod_rewrite模块添加了301跳转，wordpress的版本也可以随着“持续演进”了。</p>
<p><span id="more-1516"></span>由于wordpress或者这一类的CMS系统本身不是一个性能优化的产品，后来一段时间搬迁过一次，平台是vps的虚拟机。性能问题很突出，首页打开竟然需要2.7秒以上，加上传输耗时，超出了3秒的范围，严重影响用户体验。于是不得不在wordpress的代码上进行修改。页面全部缓存到了memcache。响应时间减少到1.5秒以下，基本可以满足大部分需求。但这样就无法跟随wordpress持续演进了。wp的版本只能定死在了某个版本号上。考虑到安全因素，我只能说，这是3.1之前的“某个版本”。</p>
<p>关于硬件环境，最初的drupal版本是一台相对很“牛”的机器，双核志强*2 + 4G RAM+ RAID5。所以当初提供了很多开源系统镜像下载。系统的瓶颈出现在网络带宽上，可谓“衣食无忧”。</p>
<p>之后的变故，加上域名备案的因素，使得网站一度只能跑在一台win2003的virtual server上，内存只有64M，从一个极端到了另一个极端。之后很长一段时间，开源小站始终运行在虚拟机或者vps之上。当然，由此带来的流量下滑不是一点点，但访客停留时间大大增加。也算抹平了。</p>
<p>后来，设法弄到了一点资源，与别人合用了一台主机，4核Xeon+4GRAM + RAID1，磁盘总是不够用，甚至为此都不保存访问日志。</p>
<p><img class="aligncenter size-medium wp-image-1519" title="" src="http://www.litrin.net/wp-content/uploads/2011/08/20110301125-225x300.jpg" alt="" width="225" height="300" /></p>
<p>后来，曾经<a title="完工的ATOM" href="http://www.litrin.net/2009/07/16/%e5%ae%8c%e5%b7%a5%e7%9a%84atom/">狂热的支持了一把atom</a>，于是自己用atom的平台搭建了一台服务器，1u高度标准机箱，atom-230,1.6G +2GRAM+160G的笔记本硬盘，操作系统选择了Ubuntu的804 Server，竟然跑得很流畅，这就是现在开源小站的主机。当然，也感谢某位朋友，免费提供了他们所代理的某款网络安全产品，用以作为我们小站的前端防火墙。在前端防火墙之后，通过端口映射的方式完成了网站80端口的指向。负担一部分iptable的任务，同时也作为SSH和远程重起主机的跳板。</p>
<p><img class="aligncenter size-medium wp-image-1518" title="20110226121" src="http://www.litrin.net/wp-content/uploads/2011/08/20110226121-300x225.jpg" alt="" width="300" height="225" /></p>
<p>之后，加入了xml-rpc服务，同时将文章推送到几个免费博客和litrinjiang.appspot.com，尽管格式全乱，但至少也算是备份吧。</p>
<p>&nbsp;</p>
]]></content:encoded>
			<wfw:commentRss>http://www.litrin.net/2011/08/12/%e5%bc%80%e6%ba%90%e5%b0%8f%e7%ab%99%e7%9a%84%e5%9f%ba%e7%a1%80%e7%bb%93%e6%9e%84/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

