<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>wudixiaotie (肖铁)</title>
    <link>https://ruby-china.org/wudixiaotie</link>
    <description>sb</description>
    <language>en-us</language>
    <item>
      <title>一个稳定高效的连接池</title>
      <description>&lt;p&gt;连接池很好写，基本架构就是一个 manager，在 manager 启动的时候负责创建链接并把连接存储到一个地方，然后每次请求过来都给出一个有效的连接。
为了保证效率，我采用了 ets 表，而没有用进程字典和 queue 作为存储连接的地方，为什么呢？因为 ets 表可以并发读和并发写，进程字典和 queue 速度是比 ets 快，但是只能有 manager 去访问，这样无形当中就形成了性能瓶颈，ets 则可以 N 多个进程同时去读，没有瓶颈，在并发的情况下比进程字典和 queue 快了不是 1 倍 2 倍。
在 erlang 中大部分数据库 driver 的连接都是一个进程，我们拿到的都是这个进程的 PID，拿 postgresql 的 driver 举例子。他的单个连接可以支持并发访问，所以连接池不需要加锁。
当我们给其他进程连接的时候，由于未知错误导致这个数据库连接进程挂掉了怎么办？所以我们需要一个 supervisor 进程来监督这些连接。每当有个连接死掉的话，就通知 supervisor 让他去重启，所以我们的重启策略就是永久的也就是 permanent，然后由于所有的链接都是一样的所以监控策略就是 simple_one_for_one，每 5 秒中重启 10 次就 dawn 掉整个 supervisor。
当我们一个连接挂掉，我们要求重启的时候也能通知 manager，告诉他替换新的连接，所以我们还需要在每次重启前执行一段代码，这样就需要个 worker，由他负责启动连接替换旧的连接，然后把新链接注册到 supervisor 上。
当 supervisor 挂掉后怎么确保 manager 也重启呢？我的做法是把 manager 注册到最顶层的 supervisor 上，然后 supervisor link 到 manager 上，这样保证了 manager 和 supervisor 任何一个挂掉，整个连接池都会重启。
真个架构最终形态应该是：
&lt;a href="http://dl2.iteye.com/upload/attachment/0111/7439/3b310bb5-b2dc-39d8-9e63-14d33fc6ee1e.png" rel="nofollow" target="_blank" title=""&gt;架构图片&lt;/a&gt;
具体的代码在这里：&lt;a href="https://github.com/wudixiaotie/simple_im/tree/master/src/pool" rel="nofollow" target="_blank" title=""&gt;postgresql pool&lt;/a&gt;&lt;/p&gt;</description>
      <author>wudixiaotie</author>
      <pubDate>Wed, 16 Sep 2015 10:37:29 +0800</pubDate>
      <link>https://ruby-china.org/topics/27353</link>
      <guid>https://ruby-china.org/topics/27353</guid>
    </item>
    <item>
      <title>自己写的 IM，来这边推广一下。</title>
      <description>&lt;p&gt;IM Server 链接：&lt;a href="https://github.com/wudixiaotie/simple_im" rel="nofollow" target="_blank" title=""&gt;simple_im&lt;/a&gt;
IM Client 链接：&lt;a href="https://github.com/wudixiaotie/simple_im_client" rel="nofollow" target="_blank" title=""&gt;simple_client&lt;/a&gt;
基本功能：
1.没有是否在线，对朋友就能发消息，如果不在线则存离线，离线保存 7 天。
2.群聊
基本架构参考了 ejabberd，跟它不同的是：
1.协议不用 xml stream 改用 toml，这样节约流量，而且很多没用的协议部分也都删除了，例如出席等，基本都是我重新定义的协议，跟 xmpp 没啥关系，随着需要添加。
2.session 不用 mnesia 而用 ets，说实话 ejabberd 用 dirty_wirte 和 ets 跨节点发消息没啥区别，反而 ets 效率更高。
3.添加了 ack。
4.把 hook 拿掉了，感觉那东西完全就是一个多此一举的东西，效率低不说，代码完全无法阅读，只能在线调试才知道走到哪！！
5.关系数据库用的 pg，驱动是&lt;a href="https://github.com/epgsql/epgsql" rel="nofollow" target="_blank" title=""&gt;epgsql/epgsql&lt;/a&gt;，链接池是我自己写的，简单高效，为什么不用 poolboy，因为这个 driver 的查询支持同一数据库连接的并发查询。&lt;/p&gt;

&lt;p&gt;现在的进度：
能实现 1v1 聊天和群聊，不过登录功能是假的，群成员列表也是假数据，因为今天才定下来要采用 postgresql 做关系数据库。现在有了 db migrate 文件，还没写 users 和 groups 的业务逻辑。欢迎大家提意见讨论。&lt;/p&gt;
&lt;h2 id="补充一下：本项目天然支持分布式啊，多节点我测试没啥问题，但节点撑个100W的客户端链接完全没压力啊（前提你要用好机器），多节点每个节点都要指定father node，用来从他那里同步session数据和联通节点。1000W的session数据同步我测试了大概几秒钟就完成了。"&gt;补充一下：本项目天然支持分布式啊，多节点我测试没啥问题，但节点撑个 100W 的客户端链接完全没压力啊（前提你要用好机器），多节点每个节点都要指定 father node，用来从他那里同步 session 数据和联通节点。1000W 的 session 数据同步我测试了大概几秒钟就完成了。&lt;/h2&gt;</description>
      <author>wudixiaotie</author>
      <pubDate>Sat, 12 Sep 2015 19:57:13 +0800</pubDate>
      <link>https://ruby-china.org/topics/27301</link>
      <guid>https://ruby-china.org/topics/27301</guid>
    </item>
    <item>
      <title>Heroku 的日志系统大牛们是怎么解决遇到的问题的。</title>
      <description>&lt;p&gt;相信用过 rails 的人，都写过一个自己的 rails 的项目，大多数人因该都部署在 heroku 上吧，因为免费的平台太少了。
那么 heroku 上部署了那么多的系统，他们的日志都是怎么记录的呢？原来他们有个用 erlang 写的日志服务叫做 Logplex，这个服务是可扩展的，他的作用是接收来自 http 和 tcp 的日志推送请求（这些请求可以来自你部署在 heroku 的 web 项目，heroku 的路由栈，heroku 平台本身，还有你项目增加的配件服务），其他的系统只要调用 http 接口，或者保持 tcp 链接并不断的推送，然后把收到的日志发送排水管道中（tcp 或 http），而我们通过 heroku logs --tail 或者 heroku 上的日志配件服务 (flydata，papertrail) 就是这个排水管道的接收方。Logplex 起到了一个日志路由的功能，：）。
&lt;a href="https://blog.heroku.com/archives/2013/11/7/logplex-down-the-rabbit-hole" rel="nofollow" target="_blank"&gt;https://blog.heroku.com/archives/2013/11/7/logplex-down-the-rabbit-hole&lt;/a&gt;
这个文章就是 Logplex 的开发人员在完成这个系统后，面对海量的 log 时，遇到的问题和怎么解决的过程。
顺便还能锻炼英语为以后出国做好准备，多好的事啊。
这个文章不是我找到的，而是看褚霸的 blog 里推荐的，被我剽窃过来了，啦啦啦。&lt;/p&gt;</description>
      <author>wudixiaotie</author>
      <pubDate>Mon, 31 Aug 2015 11:54:54 +0800</pubDate>
      <link>https://ruby-china.org/topics/27126</link>
      <guid>https://ruby-china.org/topics/27126</guid>
    </item>
    <item>
      <title>“你们都用 erlang 做什么？” 和 “随便聊聊用这两个语言在工作中的事”</title>
      <description>&lt;p&gt;好想问，为什么 ruby 的社区要建 erlang 的节点？在这里待着的人，有真正从事 erlang 工作的呢，还是工作做 ruby，只是喜欢 erlang，想学学这个 coolcool 的东西？
    我最开始是个 ruby 程序员，后来自学的 erlang，现在找到了个 erlang 的工作在做（IM 方面）。
    我很奇怪国内连个 erlang 的根据地都没有，大家交流也是在几个 erlang 大牛的博客中留言而已，以前也有 erlang 的社区网站不过不知道为什么早早就不维护了。
    说起来国内的 erlang 大牛肯定是有很多啊，不过愿意出来写博客分享的有两个：淘宝的褚霸还有网名叫坚强 2002 的一个哥们。
    基本上他们会分享出自己工作中遇到过的一些问题和解决办法，还有 erlang 的细节和虚拟机内部机制。尤其是后两点，对于了解 erlang 太重要了，因为如果这些东西不知道的话，你很难写出高并发的程序，你会发现，怎么我的代码这么好的服务器就几十万的并发就 cpu90% 了？内存也快满了。。erlang 也没比 java 牛逼多少啊！！！
    唉，真真让我怎么说这些同学呢，其实根源是有些东西不是随便写写就 OK 的。
    做 erlang 和以前做 ruby 最大的不同在于，做 ruby 的时候我写代码，写完做测试开个 irb 或者 rails c 验证一下代码确实能运行并得到我想要的结果，这意味着我这次的工作完成了，git add commit merge push。over。
    做 erlang 的时候呢？每个功能我做之前就要想好多方案，这些方案都能实现这个功能，然后我要做测试，测试有 2 种，1 种要保证这个方案确实能得出我要的结果，第 2 种就是做性能测试，确保哪个方案是性能最优的。然后才实际编写功能，最后大家一起审查我的代码，没问题了才上传，还要在测试服务器上做压力测试等等，才会上线。
    例如我们做消息回执的时候，给客户端发消息，消息会存缓存，等收到客户端的回执的时候，删除缓存，一定时间没收到回执，则存离线。
    有 3 种方式存缓存，1.mnesia write。2.mnesia dirty_write. 3.ets.
    最终我们选择了 ets。因为首先 mnesia write 的时候是走事物的，他要保证所有节点之间数据同步之后才算执行完成，无形当中产生了瓶颈。mnesia dirty_write 效率很高，但是由于这个回执不需要跨节点，所以也没采用，最后我们用了 ets，读写速度非常快。基本能满足我们的需求。
    看到这有些同学可能要说，3 个方案能差多少呢，有时候单进程差距很小，结果在大并发下差距会非常大，当时做测试的数据我忘了，不过在十几万的并发下 mnesia write 的消息全部堆积在了接收其他节点的同步回执上。效率慢的根本无法忍受。
    在整个系统过百万的并发下，多小的性能差异都会放大到很难想想的地步。就拿最简单的消息分发来说，我做过测试，一个进程负责接收消息，然后公平的分派给其他的 worker 进程，逻辑不复杂，但是如果这个分发进程用 gen_server 在 10 万的并发下会出现消息堆积的情况，也就是说超出了他的处理能力，只会越来越慢。如果直接 receive 则撑 10W 的并发不成问题。所以很多地方需要放 gen_server 就放弃吧。连 mnesia 的接收同步请求的进程也是直接 receive 的（mnesia_tm）。
    扯着扯着就扯远了。希望 erlang 能有大牛带着大家成立个社区，像 ruby 社区这样活跃。
    这是我在某个下午干完工作，产生的无聊的思绪，不知道为什么就写到这了。：）&lt;/p&gt;</description>
      <author>wudixiaotie</author>
      <pubDate>Wed, 26 Aug 2015 16:30:01 +0800</pubDate>
      <link>https://ruby-china.org/topics/27091</link>
      <guid>https://ruby-china.org/topics/27091</guid>
    </item>
    <item>
      <title>为什么这个是错的</title>
      <description>&lt;pre class="highlight erlang"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;binary&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这种写法为什么报错？&lt;/p&gt;</description>
      <author>wudixiaotie</author>
      <pubDate>Wed, 03 Dec 2014 19:29:38 +0800</pubDate>
      <link>https://ruby-china.org/topics/23007</link>
      <guid>https://ruby-china.org/topics/23007</guid>
    </item>
    <item>
      <title>leetcode 上的一道题，有没有更简单的解法？</title>
      <description>&lt;p&gt;Trapping Rain Water
Given n non-negative integers representing an elevation map where the width of each bar is 1, compute how much water it is able to trap after raining.&lt;/p&gt;

&lt;p&gt;For example, 
Given [0,1,0,2,1,0,1,3,2,1,2,1], return 6.
&lt;img src="https://l.ruby-china.com/photo/2014/3eed3dd7bb4c0d3550f8d1331348dc5e.png" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;The above elevation map is represented by array [0,1,0,2,1,0,1,3,2,1,2,1]. In this case, 6 units of rain water (blue section) are being trapped. Thanks Marcos for contributing this image!&lt;/p&gt;

&lt;p&gt;===============================下面是我的解法=======================================
大概思路是遍历每个节点，找到左边最高边界，找到右边最高边界，然后取这两个边界中最小的和当前高度做差，就是当前的点的蓄水量。每个点蓄水量之和就是总的蓄水量。&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="c1"&gt;# https://oj.leetcode.com/problems/trapping-rain-water/&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;trap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data_arr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;total_trap&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;

  &lt;span class="n"&gt;data_arr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;each_with_index&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="n"&gt;left_edge&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;right_edge&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;
    &lt;span class="c1"&gt;# find left bigest edge&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;reverse_each&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;left_index&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
      &lt;span class="n"&gt;left_item&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;data_arr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;left_index&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;left_item&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;left_edge&lt;/span&gt;
        &lt;span class="n"&gt;left_edge&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;left_item&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="c1"&gt;# find right bigest edge&lt;/span&gt;
    &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data_arr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;length&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;each&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;right_index&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
      &lt;span class="n"&gt;right_item&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;data_arr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;right_index&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;right_item&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;right_edge&lt;/span&gt;
        &lt;span class="n"&gt;right_edge&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;right_item&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="c1"&gt;# this point traped water&lt;/span&gt;
    &lt;span class="n"&gt;increment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;left_edge&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;right_edge&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="n"&gt;right_edge&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;left_edge&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;

    &lt;span class="c1"&gt;# puts "index:#{index} left_edge:#{left_edge} right_edge:#{right_edge} increment:#{increment}"&lt;/span&gt;
    &lt;span class="n"&gt;total_trap&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;increment&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="n"&gt;total_trap&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="nb"&gt;p&lt;/span&gt; &lt;span class="nb"&gt;trap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt; &lt;span class="c1"&gt;# =》 true&lt;/span&gt;
&lt;span class="nb"&gt;p&lt;/span&gt; &lt;span class="nb"&gt;trap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="c1"&gt;# =》 true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;==============================================================================================
或者有什么办法把代码简化？&lt;/p&gt;</description>
      <author>wudixiaotie</author>
      <pubDate>Thu, 13 Nov 2014 16:13:14 +0800</pubDate>
      <link>https://ruby-china.org/topics/22651</link>
      <guid>https://ruby-china.org/topics/22651</guid>
    </item>
    <item>
      <title>关于网页抓取的学习历程</title>
      <description>&lt;p&gt;做网页抓取信息，其实非常非常麻烦，但是不难，最开始我也想自己弄个 gem，用 machanize，可是发现这东西真的不是特别方便，js 过多的网页要想抓取就要分析 js 文件，尤其是编译过的 js，解压后找到 ajax 请求的地址，说实话，人家主站小改以下整个程序就有可能跑不通了。&lt;/p&gt;

&lt;p&gt;已京东的手机搜索为例子做个小程序爬了一下，分析才发现，一个页面 60 个商品，前 30 个是跟着页面过来的，后 30 个是去另外的地址通过 ajax 拿到的，而且每个商品的价格也是从另外的地方 ajax 得到的，不能说这么设计页面不好，能想到当初设计师的设计思路大概是，为了加快页面加载速度只加载一半的商品，等用户浏览到底部的时候再载入剩下的商品，价格从 ajax 请求得到，可以随时做活动打折而不用修改当前展示页面的代码。可是这可苦了作爬虫的人了。&lt;/p&gt;

&lt;p&gt;最后发现了一个东西 casperjs，这个东西是基于 phantomjs 的，作用是用 js 代码不通过浏览器而模拟用户行为，主要用于前端自动化脚本测试（初始目的？）。用了这个其实就用不上 ruby 了。不过有了这东西就不会出现上述的情况了，拿来一个网站，不用分析 js，分析页面加载顺序。直接操作就行了，然后把操作的动作翻译成 js。希望多一些人研究这个东西，说实话，现在我有问题了都不知道问谁，大家一起进步把。。。。&lt;/p&gt;

&lt;p&gt;正如 &lt;a href="#reply13" class="at_floor" data-floor="13"&gt;#13 楼&lt;/a&gt; &lt;a href="/lanyatou" class="user-mention" title="@lanyatou"&gt;&lt;i&gt;@&lt;/i&gt;lanyatou&lt;/a&gt; 所说的，这就是我后来不用 mechanize 的原因，如我最开始所说，要爬的网站一变，就要重新分析网页，重写代码。。。。实在是个噩梦，尤其是要同时爬很多网站的这种情况，永远在改以前的代码。另外关于 js 速度没有 mechanize 速度快的问题，我们可以有很多办法解决这个问题，但是程序员的时间才是最宝贵的而不是机器的时间。。。&lt;/p&gt;

&lt;p&gt;结果我发现我错了，还是 mechanize 好。。。。。。。。。。。。&lt;/p&gt;</description>
      <author>wudixiaotie</author>
      <pubDate>Thu, 21 Aug 2014 14:45:15 +0800</pubDate>
      <link>https://ruby-china.org/topics/21157</link>
      <guid>https://ruby-china.org/topics/21157</guid>
    </item>
    <item>
      <title> Can't verify CSRF token authenticity</title>
      <description>&lt;p&gt;明明在 ajax 请求中加入了 form_authenticity_token，结果有的账户在请求时候还是验证不通过，但是只是偶尔的情况，请问各位大神，有知道的么？还有怎么解决接口的安全性。&lt;/p&gt;</description>
      <author>wudixiaotie</author>
      <pubDate>Sat, 09 Aug 2014 15:18:24 +0800</pubDate>
      <link>https://ruby-china.org/topics/20929</link>
      <guid>https://ruby-china.org/topics/20929</guid>
    </item>
    <item>
      <title>sidekiq 自动关闭的问题</title>
      <description>&lt;p&gt;在项目中的测试机上 &lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;nohup &lt;/span&gt;bundle &lt;span class="nb"&gt;exec &lt;/span&gt;sidekiq &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; production &lt;span class="nt"&gt;-l&lt;/span&gt; log/sidekiq.log &amp;amp;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;总会隔一天自动关闭，日志里也没有错误，能不能是机器内存过低导致的，因为 resque 起到第三个 worker 时，这台机器会报这个错 cann't allocate memory。但是 sidekiq 能启动起来运行几个小时没问题阿。。。哪个大神遇到过类似的问题，或者有什么解决办法。&lt;/p&gt;</description>
      <author>wudixiaotie</author>
      <pubDate>Wed, 06 Aug 2014 14:11:50 +0800</pubDate>
      <link>https://ruby-china.org/topics/20869</link>
      <guid>https://ruby-china.org/topics/20869</guid>
    </item>
    <item>
      <title>mechanize 做爬虫 gethtml 的时候，有节点载入不完全的情况</title>
      <description>&lt;p&gt;一个页面在网上 get 的时候搜索某个节点会搜索不到，但是把页面下载后再 get 本地的同一个网页就会获取到这个节点，不知道有没有遇到过类似的情况。&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;agent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Mechanize&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;
&lt;span class="n"&gt;keyword&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"手机"&lt;/span&gt;
&lt;span class="n"&gt;page_num&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="n"&gt;list_page_p1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;agent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"http://search.jd.com/Search?keyword=&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;keyword&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;amp;enc=utf-8&amp;amp;page=&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;page_num&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:price&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;div&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"div[@class='p-price']"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/\t.*\t/&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
&lt;span class="c1"&gt;#这时会搜索不到item[:price]这个节点，但是把这个网页保存到本地就能搜索到&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;哪个大神帮我解决一下，get 图片的时候保存也会遇到这个问题，但是那个好解决只要判断保存的图片大小为 0 就重新 get 就是了，但是这个怎么办呢？？？还是我写的有问题？？？？&lt;/p&gt;</description>
      <author>wudixiaotie</author>
      <pubDate>Sun, 27 Jul 2014 21:24:50 +0800</pubDate>
      <link>https://ruby-china.org/topics/20707</link>
      <guid>https://ruby-china.org/topics/20707</guid>
    </item>
    <item>
      <title>不能发帖问题反馈</title>
      <description>&lt;p&gt;我用 opera12、ie9、chrome 分别测试了发帖功能，只有 chrome 可以正常发帖子，其他的浏览器都不能发帖子，希望站主能尽快修改！&lt;/p&gt;</description>
      <author>wudixiaotie</author>
      <pubDate>Fri, 14 Dec 2012 15:35:52 +0800</pubDate>
      <link>https://ruby-china.org/topics/7570</link>
      <guid>https://ruby-china.org/topics/7570</guid>
    </item>
  </channel>
</rss>
