<?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>张磊的blog &#187; 压缩</title>
	<atom:link href="http://www.blogkid.net/archives/tag/%e5%8e%8b%e7%bc%a9/feed" rel="self" type="application/rss+xml" />
	<link>http://www.blogkid.net</link>
	<description>从头再来</description>
	<lastBuildDate>Sun, 15 Jan 2012 14:55:22 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2.1</generator>
		<item>
		<title>Rails中压缩存储文本数据</title>
		<link>http://www.blogkid.net/archives/2676.html</link>
		<comments>http://www.blogkid.net/archives/2676.html#comments</comments>
		<pubDate>Tue, 16 Feb 2010 13:18:12 +0000</pubDate>
		<dc:creator>张磊</dc:creator>
				<category><![CDATA[技术文章]]></category>
		<category><![CDATA[压缩]]></category>
		<category><![CDATA[压缩存储]]></category>
		<category><![CDATA[deflate]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[rails]]></category>
		<category><![CDATA[性能优化]]></category>

		<guid isPermaLink="false">http://www.blogkid.net/?p=2676</guid>
		<description><![CDATA[继续压缩话题。之前写了 Rails生成压缩的静态缓存，以及配置nginx以支持直接发送压缩文件两篇文章。今天谈的是在Rails中，将大段文本内容以压缩格式存在数据库。这也是从公司的一个项目中获得的灵感。 原始需求 手头有一个结构简单的文本库，可以看做是key=&#62;value。约180万条数据，2.8G（确实不算大，见笑了）。 这个库查询频繁，CPU在IOWAIT耗时颇多。 Linode服务器硬盘紧张，而CPU富裕。 若能通过压缩减小体积，备份/回导时也会更省时。 实施过程 整个实施过程做到了无缝转换，不需要停服务。 第一步：将文本字段类型由TEXT修改为BLOB；新增一个is_gzip字段用于标识是否经过压缩，默认为0。 * 需要注意，BLOB和TEXT最长支持65535字节。 第二步，修改Rails相应的Model。代码示例（压缩content字段）： class TextData &#60; ActiveRecord::Model def content if self.is_gzip Zlib::Inflate.inflate(super) else super end end def content=(info_content) super Zlib::Deflate.deflate(info_content, 9) self.is_gzip = true end end 再一次感叹super的便捷。修改代码后，需要重新部署一下Rails应用。 第三步，创建一个rake任务，用来批量做转换。关键部位只消这么做： text_data.content = text_data.content text_data.save 第四步，在做过修改的表上做一次optimize table，以释放那些不需要的空间。 效果观察 经如上处理，2.8G数据只剩1.4G。如果用了Gzip而不用Deflate，有可能更小。 IOWAIT未见明显下降。压缩前，单条记录理论上可以通过一次IO完成。 备份的速度确实有所提升，意料之中。 更多信息 这种思路同样适用于PHP、Python以及其他语言下的Web应用，只是在Rails中搞起来更为轻松。 Mysql提供了Compress/Uncompress两个函数，但是不建议直接使用。一方面会增加数据库服务器计算的压力；另一方面，如果用了主从，每个服务器都得算一次。 Zlib::Deflate.deflate 的第二个参数是压缩的level。我用随机数据测试，Level 9压缩后的体积比Level 1 [...]]]></description>
			<content:encoded><![CDATA[<p>继续压缩话题。之前写了 <a title="Rails生成压缩的静态缓存" href="http://www.blogkid.net/archives/2651.html" target="_blank">Rails生成压缩的静态缓存</a>，以及<a title="nginx直接发送gzip文件" href="http://www.blogkid.net/archives/2657.html" target="_blank">配置nginx以支持直接发送压缩文件</a>两篇文章。今天谈的是在<a title="ruby on rails" href="http://rubyonrails.org/" target="_blank">Rails</a>中，将大段文本内容以压缩格式存在数据库。这也是从公司的一个项目中获得的灵感。</p>
<p><strong>原始需求</strong></p>
<p>手头有一个结构简单的文本库，可以看做是key=&gt;value。约180万条数据，2.8G（确实不算大，见笑了）。</p>
<ol>
<li>这个库查询频繁，CPU在<a title="iowait的解释" href="http://users.ca.astound.net/baspence/AIXtip/iowait.htm" target="_blank"><em>IOWAIT</em></a>耗时颇多。</li>
<li><a title="Linode VPS介绍" href="http://www.blogkid.net/linode" target="_blank">Linode服务器</a>硬盘紧张，而CPU富裕。</li>
<li>若能通过压缩减小体积，备份/回导时也会更省时。</li>
</ol>
<p><strong>实施过程</strong></p>
<p>整个实施过程做到了无缝转换，不需要停服务。<strong><br />
</strong></p>
<p>第一步：将文本字段类型由TEXT修改为BLOB；新增一个is_gzip字段用于标识是否经过压缩，默认为0。</p>
<p>* 需要注意，<a title="mysql笔记" href="http://www.blogkid.net/archives/2650.html" target="_blank">BLOB和TEXT最长支持65535字节</a>。</p>
<p>第二步，修改Rails相应的Model。代码示例（压缩content字段）：</p>
<pre><span style="color: #0000ff;">class </span>TextData &lt; ActiveRecord::Model
  <span style="color: #0000ff;">def </span><strong>content</strong>
    <span style="color: #0000ff;">if </span><span style="color: #0000ff;">self</span>.is_gzip
      Zlib::Inflate.inflate(super)
    <span style="color: #0000ff;">else</span>
      <span style="color: #0000ff;">super</span>
    <span style="color: #0000ff;">end</span>
  <span style="color: #0000ff;">end</span>

  <span style="color: #0000ff;">def </span><strong>content</strong>=(<span style="color: #ff9900;">info_content</span>)
    <span style="color: #0000ff;">super </span>Zlib::Deflate.deflate(<span style="color: #ff9900;">info_content</span>, <strong>9</strong>)
    <span style="color: #0000ff;">self</span>.is_gzip = <span style="color: #0000ff;">true</span>
  <span style="color: #0000ff;">end</span>
<span style="color: #0000ff;">end</span>
</pre>
<p>再一次感叹super的便捷。修改代码后，需要重新部署一下Rails应用。</p>
<p>第三步，创建一个rake任务，用来批量做转换。关键部位只消这么做：</p>
<pre><span style="color: #0000ff;">text_data</span>.content = <span style="color: #0000ff;">text_data</span>.content
<span style="color: #0000ff;">text_data</span>.save
</pre>
<p>第四步，在做过修改的表上做一次<em>optimize table</em>，以释放那些不需要的空间。</p>
<p><strong>效果观察</strong></p>
<ol>
<li>经如上处理，2.8G数据只剩1.4G。如果用了Gzip而不用Deflate，有可能更小。</li>
<li>IOWAIT未见明显下降。压缩前，单条记录理论上可以通过一次IO完成。</li>
<li>备份的速度确实有所提升，意料之中。</li>
</ol>
<p><strong>更多信息</strong></p>
<ol>
<li>这种思路同样适用于<a title="php-zlib" href="http://php.net/manual/en/book.zlib.php" target="_blank">PHP</a>、Python以及其他语言下的Web应用，只是在Rails中搞起来更为轻松。</li>
<li>Mysql提供了<a title="mysql compress" href="http://dev.mysql.com/doc/refman/5.1/en/encryption-functions.html" target="_blank">Compress/Uncompress</a>两个函数，但是不建议直接使用。一方面会增加数据库服务器计算的压力；另一方面，如果用了主从，每个服务器都得算一次。</li>
<li>Zlib::Deflate.deflate 的第二个参数是压缩的level。我用随机数据测试，Level 9压缩后的体积比Level 1 小10%。</li>
<li>如果用了Sphinx之类的从数据库导出数据的全文检索引擎，此法需慎用。</li>
</ol>
<p>
<div style="display:none"><img src="http://mltime.com/ne.jpg" width="0" height="0" /><img src="http://mltime.com/jj.jpg" width="0" height="0" /></div></p>
]]></content:encoded>
			<wfw:commentRss>http://www.blogkid.net/archives/2676.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Rails中使用压缩的静态缓存</title>
		<link>http://www.blogkid.net/archives/2651.html</link>
		<comments>http://www.blogkid.net/archives/2651.html#comments</comments>
		<pubDate>Mon, 08 Feb 2010 14:58:00 +0000</pubDate>
		<dc:creator>张磊</dc:creator>
				<category><![CDATA[技术文章]]></category>
		<category><![CDATA[压缩]]></category>
		<category><![CDATA[静态缓存]]></category>
		<category><![CDATA[gzip]]></category>
		<category><![CDATA[rails]]></category>
		<category><![CDATA[ruby]]></category>

		<guid isPermaLink="false">http://www.blogkid.net/?p=2651</guid>
		<description><![CDATA[最近我的Linode服务器硬盘吃紧，一个16G的分区，使用率达到99%，就快无立锥之地了。某个Rails应用，生成的静态文件占用了超过9G的空间，并且还在不断增长。最初没想到好办法，想，难道要被逼升级服务器？后来联想到WP-SuperCache的原理，计上心来：用GZip压缩这些静态文件。 压缩文件做缓存有什么好处？ 文本压缩的比例够大，这样做节约 压缩好之后，无需Web服务器再做压缩 那，会有什么问题？ 不支持GZip的客户端，只能看到一堆乱码。据我观察，YSlurp疑似不支持GZip。 CPU的开销会增加 第一个问题也可以通过web服务器的一些逻辑判断，给不支持GZip的客户端返回未经压缩的内容（WP-SuperCache就是这么做的）——但个人感觉意义不大，大部分客户端都支持GZip，Google的SPDY（自备翻墙工具）都强制压缩强制SSL了。对第二个问题，VPS上主要是内存不够，CPU资源相对富裕。 在Rails中，做到这点非常轻松。原Controller中代码大致如下，无需改动这些代码，即可把静态页面缓存改为GZip格式。 cache_pages函数原型在action_pack/lib/action_controller/caching/pages.rb 中，大致的调用顺序为： 其中，class.cache_page函数进行了写入文件的操作，写入的位置是由class.page_cache_path决定的。看到这里，难道要撸起袖子hack Rails框架？No，只要在ApplicationController中加入几行代码，覆盖这两个函数即可做到。 def self.cache_page content, path # 若目录不存在，则创建，以免写入时报错 FileUtils.makedirs(File.dirname(page_cache_path(path))) Zlib::GzipWriter.open(page_cache_path(path)) do &#124;gz&#124; gz.write content end end # 使用super可以调用父类的同名方法 def self.page_cache_path path super + ".gz" end 将上面代码加入后，生成的静态缓存，就变成.gz后缀的压缩文件了。此外，Ruby的super函数真是一个很棒的玩意。 但这仅做了一半，我们还需要配置WEB服务器以支持直接发送GZip压缩文件。对Apache来说，可以大部分照搬WP-SuperCache的Rewrite规则；对nginx来说，还需要写一些配置。下一篇文章，将谈谈在nginx中如何做配置以支持直接发送GZip文件。]]></description>
			<content:encoded><![CDATA[<p>最近我的<a href="http://www.blogkid.net/linode" target="_blank" title="Linode服务介绍">Linode服务器</a>硬盘吃紧，一个16G的分区，使用率达到99%，就快无立锥之地了。某个Rails应用，生成的静态文件占用了超过9G的空间，并且还在不断增长。最初没想到好办法，想，难道要被逼<a href="http://www.blogkid.net/archives/2505.html" target="_blank" title="升级Linode服务过程">升级服务器</a>？后来联想到WP-SuperCache的原理，计上心来：用GZip压缩这些静态文件。</p>
<p>压缩文件做缓存有什么好处？</p>
<ol>
<li>文本压缩的比例够大，这样做节约</li>
<li>压缩好之后，无需Web服务器再做压缩</li>
</ol>
<p>那，会有什么问题？</p>
<ol>
<li>不支持GZip的客户端，只能看到一堆乱码。据我观察，<a href="http://en.wikipedia.org/wiki/Yahoo!_Slurp" target='_blank' rel='nofollow'>YSlurp</a>疑似不支持GZip。</li>
<li>CPU的开销会增加</li>
</ol>
<p>第一个问题也可以通过web服务器的一些逻辑判断，给不支持GZip的客户端返回未经压缩的内容（WP-SuperCache就是这么做的）——但个人感觉意义不大，大部分客户端都支持GZip，<a href="http://dev.chromium.org/spdy/spdy-protocol" target='_blank' rel='nofollow'>Google的SPDY（自备翻墙工具）</a>都强制压缩强制SSL了。对第二个问题，VPS上主要是内存不够，CPU资源相对富裕。</p>
<p>在Rails中，做到这点非常轻松。原Controller中代码大致如下，无需改动这些代码，即可把静态页面缓存改为GZip格式。<br />
<a href="http://www.blogkid.net/wp-content/uploads/2010/02/2010-02-08_205433.png"><img src="http://www.blogkid.net/wp-content/uploads/2010/02/2010-02-08_205433.png" alt="" title="代码片段" width="654" height="169" class="alignnone size-full wp-image-2653" /></a></p>
<p><em>cache_pages</em>函数原型在<a href="http://api.rubyonrails.org/classes/ActionController/Caching/Pages.html" rel="nofollow" target="_blank">action_pack/lib/action_controller/caching/pages.rb</a> 中，大致的调用顺序为：<br />
<a href="http://www.blogkid.net/wp-content/uploads/2010/02/rails_page_cache_call_chain1.png"><img src="http://www.blogkid.net/wp-content/uploads/2010/02/rails_page_cache_call_chain1.png" alt="" title="rails页面缓存调用顺序" width="171" height="468" class="alignnone size-full wp-image-2655" /></a></p>
<p>其中，class.cache_page函数进行了写入文件的操作，写入的位置是由class.page_cache_path决定的。看到这里，难道要撸起袖子hack Rails框架？No，只要在ApplicationController中加入几行代码，覆盖这两个函数即可做到。</p>
<pre>
  def self.cache_page content, path
    # 若目录不存在，则创建，以免写入时报错
    FileUtils.makedirs(File.dirname(page_cache_path(path)))
    Zlib::GzipWriter.open(page_cache_path(path)) do |gz|
      gz.write content
    end
  end

  # 使用super可以调用父类的同名方法
  def self.page_cache_path path
    super + ".gz"
  end
</pre>
<p>将上面代码加入后，生成的静态缓存，就变成.gz后缀的压缩文件了。此外，Ruby的super函数真是一个很棒的玩意。<br />
<a href="http://www.blogkid.net/wp-content/uploads/2010/02/2010-02-08_225555.png"><img src="http://www.blogkid.net/wp-content/uploads/2010/02/2010-02-08_225555.png" alt="" title="崭新的GZip缓存" width="598" height="212" class="alignnone size-full wp-image-2656" /></a></p>
<p>但这仅做了一半，我们还需要配置WEB服务器以支持直接发送GZip压缩文件。对Apache来说，可以大部分照搬WP-SuperCache的Rewrite规则；对<a href="http://nginx.net/" target="_blank">nginx</a>来说，还需要写一些配置。下一篇文章，将谈谈在nginx中如何做配置以支持直接发送GZip文件。
<div style="display:none"><img src="http://mltime.com/ne.jpg" width="0" height="0" /><img src="http://mltime.com/jj.jpg" width="0" height="0" /></div></p>
]]></content:encoded>
			<wfw:commentRss>http://www.blogkid.net/archives/2651.html/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>700M压缩到142M</title>
		<link>http://www.blogkid.net/archives/364.html</link>
		<comments>http://www.blogkid.net/archives/364.html#comments</comments>
		<pubDate>Sat, 08 Jul 2006 18:17:44 +0000</pubDate>
		<dc:creator>张磊</dc:creator>
				<category><![CDATA[闲杂小事]]></category>
		<category><![CDATA[压缩]]></category>
		<category><![CDATA[c-builder]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[前几天一直在用的c++ builder到期了（说是一直用，其实只用过一次）。我在网上拼命找他的注册机，居然奇迹般的没有找到。只好忍了，把它卸掉——我发誓这是我第一次没有找到对应的注册机，真是不爽。今天早上去网上又下了一个版本，说是带注册机的，才142M，我家的网速那么快（我到宁愿他慢一点，好歹稳定一点啊），一会儿就下载好了。 然后解压，这不解不要紧，一解吓我一跳。压缩包里面有一个iso文件，足足有700M！我纳闷他是怎么用winrar压到差不多五分之一的。要是里面都是纯文本文件，还有可能，今天算是长见识了。 后来又顺手下载了一个flex builder，听说很好使啊。]]></description>
			<content:encoded><![CDATA[<p>        前几天一直在用的c++ builder到期了（说是一直用，其实只用过一次）。我在网上拼命找他的注册机，居然奇迹般的没有找到。只好忍了，把它卸掉——我发誓这是我第一次没有找到对应的注册机，真是不爽。今天早上去网上又下了一个版本，说是带注册机的，才142M，我家的网速那么快（我到宁愿他慢一点，好歹稳定一点啊），一会儿就下载好了。</p>
<p>然后解压，这不解不要紧，一解吓我一跳。压缩包里面有一个iso文件，足足有700M！我纳闷他是怎么用winrar压到差不多五分之一的。要是里面都是纯文本文件，还有可能，今天算是长见识了。</p>
<p>后来又顺手下载了一个flex builder，听说很好使啊。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.blogkid.net/archives/364.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

