<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>Ruby China 社区 Linux 节点</title>
    <link>https://ruby-china.org/</link>
    <description>Ruby China 社区 Linux 节点最新发帖。</description>
    <item>
      <title>暂时隐藏暂时隐藏</title>
      <description>&lt;p&gt;国内教c#和java的教材写的真烂&lt;/p&gt;</description>
      <author>crella95</author>
      <pubDate>Mon, 16 Mar 2026 07:39:38 +0800</pubDate>
      <link>https://ruby-china.org/topics/44518</link>
      <guid>https://ruby-china.org/topics/44518</guid>
    </item>
    <item>
      <title>perl 编译快多了</title>
      <description>&lt;p&gt;perl5 编译快多了，上次编译看得眼花，这次大概十分钟就编译完了&lt;/p&gt;</description>
      <author>crella95</author>
      <pubDate>Tue, 03 Mar 2026 21:17:43 +0800</pubDate>
      <link>https://ruby-china.org/topics/44501</link>
      <guid>https://ruby-china.org/topics/44501</guid>
    </item>
    <item>
      <title>linux 技巧更新</title>
      <description>&lt;p&gt;第一，qemu 要用-drive file=DISK,cache=directsync，而且对于 windows，-vga vmware 启动快很多 -cpu core2duo&lt;/p&gt;

&lt;p&gt;labwc 说是一个类似 openbox 的 wayland 窗口管理器但是导致 vlc qemu-gtk 部分程序运行缓慢&lt;/p&gt;</description>
      <author>crella95</author>
      <pubDate>Sat, 10 Jan 2026 18:38:50 +0800</pubDate>
      <link>https://ruby-china.org/topics/44445</link>
      <guid>https://ruby-china.org/topics/44445</guid>
    </item>
    <item>
      <title>企业微信 5 还是没有自带 webview</title>
      <description>&lt;p&gt;我说的是安卓 5 和旧版本不是指 windows 安装在旧版本的系统的旧版本的 webview 就会卡住和启动失败，腾讯这公司到底在干嘛&lt;/p&gt;</description>
      <author>crella95</author>
      <pubDate>Sat, 10 Jan 2026 17:12:53 +0800</pubDate>
      <link>https://ruby-china.org/topics/44444</link>
      <guid>https://ruby-china.org/topics/44444</guid>
    </item>
    <item>
      <title>终端输入法</title>
      <description>&lt;p&gt;由于我的 linux 电脑 ibus 输入法经常消失&lt;/p&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nv"&gt;strict&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nv"&gt;warnings&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="c1"&gt;#gb2312 simplified chinese input;Terminal  PERL perl&lt;/span&gt;
&lt;span class="nb"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$ri&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;bgb2.csv&lt;/span&gt;&lt;span class="p"&gt;");&lt;/span&gt;
&lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;@mkey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;@mvar&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;$ri&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$ln&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="vg"&gt;$_&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nb"&gt;chomp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$ln&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;@lnx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;split&lt;/span&gt;&lt;span class="p"&gt;('&lt;/span&gt;&lt;span class="s1"&gt;,&lt;/span&gt;&lt;span class="p"&gt;',&lt;/span&gt;&lt;span class="nv"&gt;$ln&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$lnx&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;scalar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;@lnx&lt;/span&gt;&lt;span class="p"&gt;)&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="ow"&gt;eq&lt;/span&gt; &lt;span class="p"&gt;""){&lt;/span&gt; &lt;span class="nb"&gt;pop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;@lnx&lt;/span&gt;&lt;span class="p"&gt;);}&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;scalar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;@lnx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$hkey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$lnx&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="nb"&gt;shift&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;@lnx&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nb"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;@mkey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$hkey&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="nb"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;@mvar&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;\&lt;/span&gt;&lt;span class="nv"&gt;@lnx&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nb"&gt;close&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$ri&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;scalar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;@mkey&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;&lt;span class="nb"&gt;die&lt;/span&gt;&lt;span class="p"&gt;("&lt;/span&gt;&lt;span class="s2"&gt;too many keys&lt;/span&gt;&lt;span class="p"&gt;");}&lt;/span&gt; 
&lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ready&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="p"&gt;";&lt;/span&gt;

&lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$unum&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;"";&lt;/span&gt;
&lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;@ms&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$w&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$j&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;while&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="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$uip&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="bp"&gt;STDIN&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nb"&gt;chomp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$uip&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nv"&gt;$j&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$j&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nb"&gt;scalar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;@mkey&lt;/span&gt;&lt;span class="p"&gt;)){&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$uip&lt;/span&gt; &lt;span class="ow"&gt;eq&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;x&lt;/span&gt;&lt;span class="p"&gt;")&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
&lt;span class="nb"&gt;pop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;@ms&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="nb"&gt;join&lt;/span&gt;&lt;span class="p"&gt;("",&lt;/span&gt;&lt;span class="nv"&gt;@ms&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="se"&gt;\n&lt;/span&gt;&lt;span class="p"&gt;";&lt;/span&gt;&lt;span class="nv"&gt;$j&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;;}&lt;/span&gt;
        &lt;span class="k"&gt;elsif&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$mkey&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$j&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="ow"&gt;eq&lt;/span&gt; &lt;span class="nv"&gt;$uip&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt; 
            &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$cur&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$mvar&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$j&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
            &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;@curvar&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;@$cur&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$w&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="nv"&gt;$w&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="nb"&gt;scalar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;@curvar&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="nv"&gt;$w&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="k"&gt;print&lt;/span&gt; &lt;span class="nv"&gt;$w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;'&lt;/span&gt;&lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;$curvar&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$w&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="s2"&gt; &lt;/span&gt;&lt;span class="p"&gt;";&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="p"&gt;";&lt;/span&gt;
            &lt;span class="nv"&gt;$unum&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="bp"&gt;STDIN&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nb"&gt;chomp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$unum&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;#print "[".$unum."]\n";&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$unum&lt;/span&gt; &lt;span class="ow"&gt;eq&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;n&lt;/span&gt;&lt;span class="p"&gt;"){&lt;/span&gt;&lt;span class="nv"&gt;$j&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="k"&gt;elsif&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$unum&lt;/span&gt; &lt;span class="ow"&gt;eq&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;q&lt;/span&gt;&lt;span class="p"&gt;"){&lt;/span&gt;&lt;span class="nv"&gt;$j&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;;}&lt;/span&gt;                
            &lt;span class="k"&gt;elsif&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;index&lt;/span&gt;&lt;span class="p"&gt;("&lt;/span&gt;&lt;span class="s2"&gt;012345678910111213141516&lt;/span&gt;&lt;span class="p"&gt;",&lt;/span&gt; &lt;span class="nv"&gt;$unum&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&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="p"&gt;{&lt;/span&gt;         

                &lt;span class="nb"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;@ms&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$curvar&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$unum&lt;/span&gt;&lt;span class="p"&gt;)&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="k"&gt;print&lt;/span&gt; &lt;span class="nb"&gt;join&lt;/span&gt;&lt;span class="p"&gt;('',&lt;/span&gt; &lt;span class="nv"&gt;@ms&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="se"&gt;\n&lt;/span&gt;&lt;span class="p"&gt;";&lt;/span&gt; 
                &lt;span class="nv"&gt;$j&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;elsif&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$unum&lt;/span&gt; &lt;span class="ow"&gt;eq&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;r&lt;/span&gt;&lt;span class="p"&gt;")&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;$j&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="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nv"&gt;$j&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="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;bgb2.csv = &lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;aa,啊,阿,埃,挨,哎,唉,哀,皑,癌,蔼,矮,艾,碍,爱,隘
aa,鞍,氨,安,俺,按,暗,岸,胺,案,肮,昂,盎,凹,敖,熬,翱
aa,袄,傲,奥,懊,澳
ba,芭,捌,扒,叭,吧,笆,八,疤,巴,拔,跋
ba,靶,把,耙,坝,霸,罢,爸,白,柏,百,摆,佰,败,拜,稗,斑
ba,班,搬,扳,般,颁,板,版,扮,拌,伴,瓣,半,办,绊,邦,帮
ba,梆,榜,膀,绑,棒,磅,蚌,镑,傍,谤,苞,胞,包,褒,剥
ba,薄,雹,保,堡,饱,宝,抱,报,暴,豹,鲍,爆
be,杯,碑,悲,卑,北,辈,背,贝,钡,倍,狈,备,惫,焙
be,被,奔,苯,本,笨,崩,绷,甭,泵,蹦,迸
bi,逼,鼻,比,鄙,笔,彼,碧,蓖,蔽,毕
bi,毙,毖,币,庇,痹,闭,敝,弊,必,辟,壁,臂,避,陛,鞭,边
bi,编,贬,扁,便,变,卞,辨,辩,辫,遍,标,彪,膘,表,鳖,憋
bi,别,瘪,彬,斌,濒,滨,宾,摈,兵,冰,柄,丙,秉,饼,炳
bi,病,并
bo,玻,菠,播,拨,钵,波,博,勃,搏,铂,箔,伯,帛
bo,舶,脖,膊,渤,泊,驳
bu,捕,卜,哺,补,埠,不,布,步,簿,部,怖
ca,擦,猜,裁,材,才,财,睬,踩,采,彩,菜,蔡,餐,参,蚕
ca,残,惭,惨,灿,苍,舱,仓,沧,藏,操,糙,槽,曹,草,厕,策
ca,侧,册,测,层,蹭
cha,插,叉,茬,茶,查,碴,搽,察,岔,差,诧,拆,柴,豺
~~~~~~
&lt;/code&gt;&lt;/pre&gt;</description>
      <author>crella95</author>
      <pubDate>Sun, 07 Dec 2025 15:47:35 +0800</pubDate>
      <link>https://ruby-china.org/topics/44410</link>
      <guid>https://ruby-china.org/topics/44410</guid>
    </item>
    <item>
      <title>减少 linux 垄断软件</title>
      <description>&lt;p&gt;第一，删除 network manager 不一定适用于所有环境，前提是先卸载 network-manager-applet 和 NetworkManager 和 libnma，这两个搞不定的就不要看了&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

/usr/bin/wpa_supplicant -i wlp1s0（wlan设备） -c /etc/wpa_supplicant/wpa_supplicant.conf
/usr/bin/dhcpcd wlp1s0
编辑 /etc/resolv.conf"nameserver 114.114.114.114" 
因为我讨厌dhcp耗时长，所以设置静态ip
ip a add 192.168.1.157/24 dev wlp1s0
ip route add default via 192.168.1.1
&lt;/code&gt;&lt;/pre&gt;</description>
      <author>crella95</author>
      <pubDate>Thu, 27 Nov 2025 09:01:48 +0800</pubDate>
      <link>https://ruby-china.org/topics/44399</link>
      <guid>https://ruby-china.org/topics/44399</guid>
    </item>
    <item>
      <title>voidlinux 可以试用</title>
      <description>&lt;p&gt;放弃 debian，感觉有犹太人的审美，试用 voidlinux，用刻录 iso 方式安装的，感觉有 javascript 风格，安装新应用包还不太熟&lt;/p&gt;</description>
      <author>crella95</author>
      <pubDate>Thu, 06 Nov 2025 21:20:18 +0800</pubDate>
      <link>https://ruby-china.org/topics/44382</link>
      <guid>https://ruby-china.org/topics/44382</guid>
    </item>
    <item>
      <title>吐槽一下刚刚尝试 Ubuntu 遇到的抽象事...</title>
      <description>&lt;p&gt;先叠个甲，我基本没用过 Linux desktop。  &lt;/p&gt;

&lt;p&gt;最近终于有时间试一下 DHH 的 omakub。装完后配置搜狗输入法，把键盘输入系统换成了 fcitx，重启系统后键盘挂了，按啥都没反应。&lt;/p&gt;

&lt;p&gt;我想着肯定是我配的有问题，就想用屏幕键盘先进系统再说。
结果这个屏幕键盘的回车触发不了登录界面的确认，界面本身也没有一个独立的确认按钮。&lt;/p&gt;

&lt;p&gt;虽然最后命令模式进去改好了，但是这无障碍体验也太操蛋了，西八...&lt;/p&gt;</description>
      <author>RaySong</author>
      <pubDate>Sun, 17 Nov 2024 16:48:35 +0800</pubDate>
      <link>https://ruby-china.org/topics/43951</link>
      <guid>https://ruby-china.org/topics/43951</guid>
    </item>
    <item>
      <title>你们都用哪个 Linux 发行版？</title>
      <description>&lt;p&gt;从决定学习 ruby、Rails 那一刻开始，我就确定我要在 linux 上学习，这一点从未动摇。
然而，具体哪个发行版呢？&lt;/p&gt;

&lt;p&gt;我日常用的是 Manjaro，安装 ruby 时很方便，但在装 Rails 时各种错误。随后我干脆买了腾讯云的云服务器，尝试了 CentOS、uBuntu，都是类似的问题：Rails 很难安装成功。&lt;/p&gt;

&lt;p&gt;今天我突然试了试 Debian，居然大功告成。Debian 真好：）&lt;/p&gt;

&lt;p&gt;然而我日常使用 Manjaro 习惯了，不想把自己的电脑轻易换 OS. 郁闷&lt;/p&gt;</description>
      <author>macolex</author>
      <pubDate>Thu, 07 Mar 2024 19:20:33 +0800</pubDate>
      <link>https://ruby-china.org/topics/43616</link>
      <guid>https://ruby-china.org/topics/43616</guid>
    </item>
    <item>
      <title>浅谈 Linux 下 vim 的使用</title>
      <description>&lt;p&gt;Vim 是从 vi 发展出来的一个文本编辑器，其代码补全、编译及错误跳转等方便编程的功能特别丰富，在程序员中被广泛使用。&lt;/p&gt;

&lt;p&gt;Vi 是老式的字处理器，功能虽然已经很齐全了，但还有可以进步的地方。Vim 可以说是程序开发者的一项很好用的工具。对于大多数用户来说，Vim 刚开始学习的时候可能会进展缓慢，但是一旦掌握一些基本操作之后，就能大幅度提高编辑效率。今天我们就来简单介绍下 Vim 及其基本操作。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Vim 的三种模式&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;从 vi 派生出来的 Vim 具有多种模式，这种独特的设计容易使初学者产生混淆。几乎所有的编辑器都会有插入和执行命令两种模式，并且大多数的编辑器使用了与 Vim 截然不同的方式：命令目录（鼠标或者键盘驱动），组合键（通常通过 ctrl 键和 alt 键组成）或者鼠标输入。Vim 和 vi 一样，仅仅通过键盘来在这些模式之中切换。这就使得 Vim 可以不用进行菜单或者鼠标操作，并且最小化组合键的操作。对文字录入员或者程序员可以大大增强速度和效率。&lt;/p&gt;

&lt;p&gt;基本上，Vim 可以分为命令模式、插入模式和底线模式三种模式，各模块的功能区分如下：&lt;/p&gt;
&lt;h3 id="命令模式："&gt;&lt;strong&gt;命令模式：&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;使用 vim 编辑文件时，默认处于命令模式。在此模式下可以使用上、下、左、右键或者 k、j、h、l 键进行光标的移动，还可以对文件内容进行复制、粘贴、替换、删除等操作。&lt;/p&gt;
&lt;h3 id="插入模式："&gt;&lt;strong&gt;插入模式：&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;在该模式下可以对文件进行写的操作，类似于 windows 的文档操作。进入插入模式的方法是在命令模式下按 "i"或者"a"或者"o"，编写完成后按 Esc 即可回到命令模式。&lt;/p&gt;

&lt;p&gt;i：从光标目前所在位置插入所输入的字符&lt;/p&gt;

&lt;p&gt;a：从目前光标所在位置的下一个字符处插入所输入的字符&lt;/p&gt;

&lt;p&gt;o：插入新的一行从行首开始输入&lt;/p&gt;
&lt;h3 id="底线模式："&gt;&lt;strong&gt;底线模式：&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;如果要保存、查找或者替换一些内容等，就需要进入底线模式。底线模式的进入方法为：在命令模式下按":"键，Vim 窗口的左下方会出现一个":"符号，这时就可以输入相关的指令进行操作了。指令执行后会自动返回命令模式。&lt;/p&gt;
&lt;h2 id="Vim 的基本操作"&gt;&lt;strong&gt;Vim 的基本操作&lt;/strong&gt;&lt;/h2&gt;&lt;h3 id="一、打开文件或者新建文件"&gt;&lt;strong&gt;一、打开文件或者新建文件&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;统一命令：vim 文件名&lt;/p&gt;

&lt;p&gt;例子：vim 11.txt&lt;/p&gt;

&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/upyun/66cd0e02-1384-47b6-bf39-b466f4d3a61a.png!large" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;然后在页面的左下角可以看到文件的信息，行数和字符数，例如上图：3 行、426 个字符。&lt;/p&gt;
&lt;h3 id="二、光标的移动"&gt;&lt;strong&gt;二、光标的移动&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;以字符为单位移动，在命令模式中使用 h、j、k、l 这 4 个字符控制方向，分别表示向左、向下、向上、向左&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  按 G：移动到文件最后&lt;/li&gt;
&lt;li&gt;  按 gg: 移动到文件的开头&lt;/li&gt;
&lt;li&gt;  按 0 或者^: 光标移动到所在行的行首&lt;/li&gt;
&lt;li&gt;  按 $: 光标移动到所在行的行尾&lt;/li&gt;
&lt;li&gt;  按 ctrl+f 往下翻一页&lt;/li&gt;
&lt;li&gt;  按 ctrl+b 往上翻一页&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="三、插入模式"&gt;&lt;strong&gt;三、插入模式&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;当处于插入模式，左下角的状态如下图所示：&lt;/p&gt;

&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/upyun/d37a5ddd-58f1-43d3-bf1a-bab871f91a3a.png!large" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;当编辑完成，就可以按 Esc 退出插入模式，进入到命令模式。可以使用 Shift+zz 命令保存退出，其他保存和退出命令见下文。&lt;/p&gt;
&lt;h3 id="四、底线模式"&gt;&lt;strong&gt;四、底线模式&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;【保存和退出】&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;字母"w"：保存不退出；&lt;/p&gt;

&lt;p&gt;字母"q"：不保存退出；&lt;/p&gt;

&lt;p&gt;字符"!"：强制性操作；&lt;/p&gt;

&lt;p&gt;也可以 wq 这样直接保存退出&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;【显示行号】&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;显示行号：set nu&lt;/p&gt;

&lt;p&gt;不显示：set nonu&lt;/p&gt;

&lt;p&gt;直接到某行：在底线模式下直接输入数字就可以到想到的行，如果输入的数字比文档的行数多就会到最后一行。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;【搜索】&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;想要搜索某个词可以直接在底线模式输入：/要搜索的词，或者在命令模式里直接 /搜索的词也可以，&lt;/p&gt;

&lt;p&gt;可以按 n 到搜索的下一个词的地方，按 N 就是往上找。搜索到的词就会以高亮显示，如下图：&lt;/p&gt;

&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/upyun/ee64e511-351b-40db-8e16-e8a0ee0ee2eb.png!large" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;如果要忽略大小写，可以先在底线模式输入：set ic , 反之：set noic。&lt;/p&gt;

&lt;p&gt;这个高亮如果不取消显示会一直有，可以用这个命令取消，底线模式下输入：nohlsearch。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;【字符替换】&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;在底线模式下：输入 1,$s/string/replace/g 会将全文的 string 字符串替换为 replace 字符串。&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;1,$ 表示从第一行到最后一行&lt;br&gt;
s 表示替换&lt;br&gt;
g 表示每行全部替换
&lt;img src="https://l.ruby-china.com/photo/upyun/dcdc7c62-c8a4-4096-8f4e-a5f34974cbb0.png!large" title="" alt=""&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;此时 /w 已经搜索不到了。(此处没有忽略大小写)&lt;/p&gt;

&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/upyun/f4fc50a5-34ca-4768-a8a5-d9acdfbcec2d.png!large" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;替换某一行中的：5s/string/replace/g。&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;5 表示行数&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;【操作其它文件】&lt;/p&gt;

&lt;p&gt;写入到其它文件：可以直接 w 文件名，这样就会直接创建一个新的文件，并把当前文件的内容拷贝一份到里面。&lt;/p&gt;

&lt;p&gt;直接打开另外一个文件：edit 文件名，如果这个时候想看有没有切换成功，可以输入 file 就可以查看当前打开的文件。&lt;/p&gt;
&lt;h3 id="五、命令模式下的常用快捷键"&gt;&lt;strong&gt;五、命令模式下的常用快捷键&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;【删除】&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;x：根据光标的位置删除，一次只能删除一个，想要删除多个，可以先按下 想删除的数量 然后再按 x。&lt;/p&gt;

&lt;p&gt;例子：先按 300 后按 x，就是删除 300 个字符:300x。&lt;/p&gt;

&lt;p&gt;注：这里可以直接在键盘上按对应的数字，是没有显示的，按完数字再按 x 即可删除。&lt;/p&gt;

&lt;p&gt;dw : 删除光标所在处到词尾的内容。&lt;/p&gt;

&lt;p&gt;dd : 删除光标所在行，3dd 代表的意思就是删除光标所在位置向下的三行，包括光标所在的行 (同 x 批量删除一样)。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;【复制】&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;yy : 复制光标所在的行。&lt;/p&gt;

&lt;p&gt;yw : 复制光标所在处到词尾的内容。&lt;/p&gt;

&lt;p&gt;p : 黏贴，此命令是在命令模式下，按照上面的命令复制后，然后光标移动到想要复制的位置，然后按 p 黏贴。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;【取代替换】&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;r : 取代光标所在字符，按一下 r 再按 想要取代的字符。&lt;/p&gt;

&lt;p&gt;R : 连续取代字符直到按 Esc 为止，按一下 R 然后依次按后面取代的字符，最后按 Esc 结束。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;【撤销】&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;撤销键按：u。&lt;/p&gt;

&lt;p&gt;ctrl+r : 重做被撤销的操作，这个是如果你改好后不小心按了下 u，再用这个命令就可以重新回到撤销前的界面。&lt;/p&gt;

&lt;p&gt;本文只是简单介绍了下 vim 的常用命令，除了这些还有很多其它的命令，感兴趣的朋友可以更深入地去了解下。&lt;/p&gt;</description>
      <author>upyun</author>
      <pubDate>Thu, 24 Aug 2023 15:36:58 +0800</pubDate>
      <link>https://ruby-china.org/topics/43289</link>
      <guid>https://ruby-china.org/topics/43289</guid>
    </item>
    <item>
      <title>想在家里搭个局域网服务器，用来给电视共享电影资源，有没有好的机器推荐？</title>
      <description>&lt;p&gt;看起来树莓派不错，但是这两年涨价好多，两三年前买了一个 3B+ 玩耍才 200 多，现在同款都 700 多了。&lt;/p&gt;

&lt;p&gt;不知道有没有别的机子可以做到又省电、又能跑完整的 Linux。&lt;/p&gt;</description>
      <author>willx</author>
      <pubDate>Mon, 08 May 2023 14:58:09 +0800</pubDate>
      <link>https://ruby-china.org/topics/43060</link>
      <guid>https://ruby-china.org/topics/43060</guid>
    </item>
    <item>
      <title>又拍云邵海杨 - 25 年 Linux 老兵，聊聊运维的“术”与“道”</title>
      <description>&lt;h3 id="您好邵总，请您先做个自我介绍吧，聊聊您的履历和现状，让大家更好的认识您，了解您的背景也有助于读者理解后面的采访内容"&gt;您好邵总，请您先做个自我介绍吧，聊聊您的履历和现状，让大家更好的认识您，了解您的背景也有助于读者理解后面的采访内容&lt;/h3&gt;
&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/upyun/3213eb4d-0c6d-4a9c-9a97-9bfbe38c761a.png!large" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;我是来自又拍云的邵海杨，从 1998 年开始使用 Linux 至今快 25 年了，资深 (老鸟)Linux 系统运维/架构师，DevOps 八荣八耻倡导者，业余撰稿人；精通 (心虚) 系统优化及网络服务管理，Linux 系统定制，CDN 加速和安全防御; 擅长互联网高性能网络及架构设计、虚拟化 KVM 及 OpenStack 云平台，K8S 容器云和 Ceph 分布式存储等新技术；喜欢交流分享，活跃于社区，一直积极投身于开源活动的组织和传播。&lt;/p&gt;
&lt;h3 id="运维领域，每个公司都会制定自己的运维准则或者操作规范，能否分享一下贵司的经验，给我们一些参考？"&gt;运维领域，每个公司都会制定自己的运维准则或者操作规范，能否分享一下贵司的经验，给我们一些参考？&lt;/h3&gt;
&lt;p&gt;又拍云是一家提供云存储，云分发，云处理服务的公司，也是国内首创可编程 CDN 服务的专业云服务提供商，特点就是 7x24 全年不间断服务，所以云运维也有一些律条或原则，比如：&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;先保障稳定，然后再优化&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;过度设计或过早优化很可能会带来更多的故障停机时间，要先集中精力提高系统的可扩展性和高可用性。坚持“先完成，再完善，后完美”，项目也是“先能用，再好用，后用好”的实施策略。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;提供可靠的测试依据和时间验证&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;引入新技术到架构之前，要确保新技术的稳定性和足够时间久的考验，更要有运维工程化中开发出来的工具链的完整。一旦线上返工或变更造成的措手不及可能已经是故障的导火索。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;使用可控的自动化手段提升效率&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;自动部署、自动编排、自动巡检、自动升级等自动化手段越来越多应用于云运维。这是适应云计算时代的趋势，但能力越强，责任越大，要谨慎自动化的雪崩和惊群效应，做好灰度/蓝绿部署和各种测试。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;保持简单，监控一切&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;保持简单，别把事搞得太复杂。除了常见的异常问题报警外，面向业务指标，市场指标和销售数据，成本等都可以用来做趋势分析信息。定期的轮询查看各个趋势数据的峰值峰谷有助于见微知著。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;面向预算的运维&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;运维团队通常是最大的花费者，因为预算不足，没有钱的运维是很难兼顾到日益增长的公司业务规模，除非公司业务已经停滞或不再有爆炸式的增长，面对这样的挑战，运维要学会降本增益，开源节流，利用新技术实现能效比的提升。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;面向场景的智能运维&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;各种各样的负载场景，从高并发处理到视频转码，从高性能并行计算到海量的网络请求。这些不同的负载场景，对网络带宽，各种处理和 IO 的要求也各不相同。智能运维就是需要深入理解业务，合理配置资源和架构来满足不同业务场景的需求。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;持续集成和发布系统&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;持续发布包括灰度发布、测试发布、滚动发布、回滚发布等多种场景，并且确保每种场景都应该是可以可控的。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;确保任何人都可以被替换&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;铁打的营盘流水的兵，人挪活是常态，做好员工的共享文档管理和知识传递和分享，理论上所有人都可以被替换，任何人也不应该成为公司的天花板。&lt;/p&gt;
&lt;h3 id="虽说成长是自己的事情，但如果有合适的场域、合适的项目机会、合适的团队、合适的机制，会让工程师的成长更快，团队更有战斗力，您能否系统的谈一下是如何促成运维同学的成长的？"&gt;虽说成长是自己的事情，但如果有合适的场域、合适的项目机会、合适的团队、合适的机制，会让工程师的成长更快，团队更有战斗力，您能否系统的谈一下是如何促成运维同学的成长的？&lt;/h3&gt;
&lt;p&gt;公司一直是积极鼓励员工的技能自我提高和促进成长：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;每月开放日：公司内技术委员会会定期举办讲座，分享前沿研究中的一些收获，要求有主题，有重点，有应用场景，最好有实例。&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;每周分享会：鼓励所有开发者定期分享新的技术，谈论他们面对的问题，或者任何别的他们正思考的东西，分享的内容会形成文档和视频存档，并根据评分给予奖金和积分激励。&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;公司悬赏项目：无论是公司还是员工自身都可以发起项目，技术委员会评审通过后，自行组队完成，根据产出文档，数据对比，技术分享后获取相应的项目奖金。申请专利还有相应的专利奖金。&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;培养个人影响力：鼓励员工通过发表文章或演讲的形式，走出去做工程经验分享、工作心得的梳理，提高个人的影响力，并根据受众的反馈给予稿费和讲师费激励。&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;订阅报刊，杂志等纸质书籍，了解最新动态。以部门为单位，配置一定的购书津贴。&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;又拍云运维团队内的培养包括：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;化“天花板为托板”：把自己放在一个培养新人的管理角色，不让自己成公司瓶颈和员工的天花板，鼓励新人们去尝新和处理故障，增加自身的技能和实战经验；信任，互助，激励，他们会持续不断创造惊喜。&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;制作“自动化工具”：利用自己的经验抽象业务成程序模型，制作或培训自动化脚本的编写，提高团队的工作效率，让员工节省精力和时间去学习其它新知识；&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;承担“高精专”项目：提前准备最新知识的研究和可行性分析，整理成文档作公开培训，再交给团队去深入研究和实施，转化成生产力，积累一线经验再反馈完善文档，良性循环；&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;积极提倡“知识分享”：各种案例和“坑”都会整理成 wiki 文档，通过文档共享，定期分享讲座，鼓励员工撰写高质量的，可读性很强的文档，开口培训，增加感染力和自信心；&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;鼓励“参与开源交流”：公司鼓励员工走出去参与技术交流大会，闭门造车耗时耗力，不如专业的人点拨。也会有购书经费，团建活动经费，茶歇文化；&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="运维工程师其中一个典型的职业路径是做管理者，但管理者和资深运维要解决的问题截然不同，对于那些刚刚步入管理岗的资深运维，是否可以分享一些您的经验？"&gt;运维工程师其中一个典型的职业路径是做管理者，但管理者和资深运维要解决的问题截然不同，对于那些刚刚步入管理岗的资深运维，是否可以分享一些您的经验？&lt;/h3&gt;
&lt;p&gt;对于刚步入管理岗的运维来说，我的建议是及时梳理遗留的技术债和人才技能的盘点和培养，先打好基础，后面才能有更大的空间进步，具体可以参考我的《&lt;a href="https://mp.weixin.qq.com/s?__biz=MjM5ODc5ODgyMw==&amp;amp;mid=2653574974&amp;amp;idx=1&amp;amp;sn=1e831f88bf54fd36c706a73de7b70710&amp;amp;scene=21#wechat_redirect" rel="nofollow" target="_blank" title=""&gt;DevOps 的八荣八耻&lt;/a&gt;》的分享。&lt;/p&gt;

&lt;p&gt;一、以可配置为荣，以硬编码为耻&lt;/p&gt;

&lt;p&gt;二、以互备为荣，以单点为耻&lt;/p&gt;

&lt;p&gt;三、以随时重启为荣，以不能迁移为耻&lt;/p&gt;

&lt;p&gt;四、以整体交付为荣，以部分交付为耻&lt;/p&gt;

&lt;p&gt;五、以无状态为荣，以有状态为耻&lt;/p&gt;

&lt;p&gt;六、以标准化为荣，以特殊化为耻&lt;/p&gt;

&lt;p&gt;七、以自动化工具为荣，以手动和人肉为耻&lt;/p&gt;

&lt;p&gt;八、以无人值守为荣，以人工介入为耻人&lt;/p&gt;

&lt;p&gt;才上技能树的盘点，主要是配合人事做好人才九宫格的划分（如果是开发或运维，把左侧的绩效换成潜力，绩效针对销售而言），考查的是管理者对员工的全方面的辨析能力，知人善用。&lt;/p&gt;

&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/upyun/2d962785-7ca2-4f18-89db-741513bc75a7.jpg!large" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;再结合公司的 OKR 目标管理来激励员工，它的优点在于聚集目标的同时，还能：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;激励个人自驱力，鼓励员工创新和反思；&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;考查的是相对结果，鼓励有难度的挑战和突破；&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;考核的协同配合能力，鼓励员工去全方位的协调推进；&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="Kubernetes火了好一段时间了，很多公司也在大规模应用了，但显然，每个技术都不是银弹，无法解决所有场景的问题，这几年观察下来，您觉得哪些公司不适合上Kubernetes？能否给一个这类公司的画像，并说明理由？"&gt;Kubernetes 火了好一段时间了，很多公司也在大规模应用了，但显然，每个技术都不是银弹，无法解决所有场景的问题，这几年观察下来，您觉得哪些公司不适合上 Kubernetes？能否给一个这类公司的画像，并说明理由？&lt;/h3&gt;
&lt;p&gt;虽然 Kubernetes 代表着目前为止的 devops 的最佳工程应用实践 (真香)，但也不是所有场合都能应用，如又拍云的 CDN 边缘服务器，数据中心的日志分析平台，Ceph 分布式存储就以物理机为主。所以，我建议找一些合适的场景先试用起来，如：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;机器资源错峰空闲浪费严重的；&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;CPU，磁盘和网络 IO 都不密集的；&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;不需要持久化存储的或抢占资源的；&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;软件架构已经做了微服务改造的；&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;业务处理程序有周期性、可弹性扩容的；&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="运维和研发是最亲密的伙伴，贵司是如何做工作边界划分的？另外关于如何让这两个角色保持亲密合作，是否可以分享一些经验？"&gt;运维和研发是最亲密的伙伴，贵司是如何做工作边界划分的？另外关于如何让这两个角色保持亲密合作，是否可以分享一些经验？&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;运维工程师 = 冲锋陷阵的将军&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;软件工程师 = 坐阵帐中的军师&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;理论上，优秀的软件工程师是可以把部分 (甚至全部) 运维工程师的工作做掉，比如说业务软件性能的监控，如果程序员在程序中插入很多的钩子或探针，就可以统计出数据来，不需要运维劳心劳力的监控；比如说程序员在设计程序的时候，考虑到了分库分表，考虑到了大并发和分布式的设计，那运维就可以水平扩展机器就行；如果软件没有那么多 bug，还有很多如果......但是，现实是残酷的，这种高水平的程序员太少了，尤其在中国，大家都忙于实现业务功能，连个文档甚至注释都不愿意写，更别提能够考虑这么周全了；同理，运维接触的很多是开源很优秀很成熟的软件，从中是可以借鉴知晓优秀软件是怎么设计的，比如优秀的程序，日志信息会非常详尽，我们可以通过标准的 syslog 或者日志去监控它，所以，资深的运维会：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;积极参与事前的规划，配合开发做演练，自动化部署，协助架构改进&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;合理提需求，要资源，最好是有预算，做到防患于未燃&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;线上监控，故障复盘，反馈给整个团队，倒逼上下协调做改进&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;当然，要达到上述能力的运维管理，肯定需要潜心研究，承上启下，协调团队，任劳任怨的修行多年，到那个时候，运维就不再是对事情的结果负责，而是转变角色，主导和协调整个过程。当然，这里指的能力不仅仅是技能，还包括对业务的理解能力，站在公司管理层面对整个项目和资源的分配和把握。因此，运维工程师其实是现实中的软件工程师的互补，因为大家的能力侧重点不同，所以大家更要团结一体，要能够打胜仗，离开谁都是不行的，这是一个共同修炼进步的过程。&lt;/p&gt;

&lt;p&gt;最后，我的个人观点：架构师它可能不是一个人的角色，而是一个团队的统称，它可以：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;不必冲锋陷阵，就可以纵观全局，运筹帷幄，调度所有的资源（运维架构师的功能）&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;可以带领和团结团队，高屋筑瓴，因时制宜的实现解决方案（软件架构师的功能）&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;可以把握公司业务方向和深度，洽谈合作，控制成本（业务架构师的功能）&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="运维需要和其他多个部门沟通协作，鉴于各个团队目标关注点未必一致，合作起来可能未必有那么顺畅，针对这个问题您是用什么招来让这个过程更加顺畅的？"&gt;运维需要和其他多个部门沟通协作，鉴于各个团队目标关注点未必一致，合作起来可能未必有那么顺畅，针对这个问题您是用什么招来让这个过程更加顺畅的？&lt;/h3&gt;
&lt;p&gt;其实沟通不顺畅的原因大部分在于对后果的不可预见性，你说冗余他说预算，你说架构他说工期，各有立场又各有苦衷，但就是没人对结果负责。我在工作中发现，当故障发生时，各部门的配合是空前团结，战斗力也是最强的，所以，沟通协作的关键在于： &lt;strong&gt;既要团队协作，也要责任分明&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;事前部门沟通时，确定好项目预期，成本，影响要素，故障后果及责任方；&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;事后故障复盘时，根据故障原因，有理有据地“甩锅”，同时要引以为戒，亡羊补牢；&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;比如说提供在线 10W 并发的能力，需要冗余带宽冗余服务器数量 x2，因为预算不足减半所导致的后果及责任人；再比如软件设计不好，通过性能监控，发现指标异常的后果及责任人；当然，报警处理不及时，人为操作故障也会算到运维亦无可厚非；故障文化就是要关注问题和关注事情本身，对事不对人。大家都在故障中成长，在复盘中变强。&lt;/p&gt;
&lt;h3 id="您觉得运维工作最重要的几个目标是什么？您是怎么落地这些目标的？"&gt;您觉得运维工作最重要的几个目标是什么？您是怎么落地这些目标的？&lt;/h3&gt;
&lt;p&gt;运维自动化；&lt;/p&gt;

&lt;p&gt;监控常态化；&lt;/p&gt;

&lt;p&gt;日志可视化！&lt;/p&gt;

&lt;p&gt;这个篇幅太多了，不展开讲，可以参考《&lt;a href="https://mp.weixin.qq.com/s?__biz=MjM5ODc5ODgyMw==&amp;amp;mid=402610622&amp;amp;idx=1&amp;amp;sn=2bae92c0b14746bb815db55fecfb28db&amp;amp;scene=21#wechat_redirect" rel="nofollow" target="_blank" title=""&gt;云运维的启示和架构设计&lt;/a&gt;》&lt;/p&gt;
&lt;h3 id="工具选型这块，到底是自研，还是使用开源，还是使用商业产品，是如何抉择的？"&gt;工具选型这块，到底是自研，还是使用开源，还是使用商业产品，是如何抉择的？&lt;/h3&gt;
&lt;p&gt;又拍云通常不会重复造轮子，但一定会先用好轮子，或者把轮子改造得更加称手，选择自研往往具备了一定的开发能力，再加上某些必要原因，如：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;找不到符合要求的开源软件，如我们自研的云处理软件…&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;开源软件有 bug 或者 issue，社区短期内无法推进，但业务又急需，只能通过自研解决，如 ats 的内存泄露问题…&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;开源软件的功能特点跟公司的业务不相符合，不得不改造软件，如 nginx 的防盗链模块，需要与客户对接定制…&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;开源软件的设计目标过于高大上，通用性好但很臃肿，如果我们只要某个小功能点，就不需要牛刀了，如性能探针的埋点…&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;有数据保护要求，或者有隐私的场合…&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="越来越多的公司在迁往公有云，云原生架构下，SRE团队的核心职能是否有些变化？应该如何凸显团队的价值呢？"&gt;越来越多的公司在迁往公有云，云原生架构下，SRE 团队的核心职能是否有些变化？应该如何凸显团队的价值呢？&lt;/h3&gt;
&lt;p&gt;公有云作为 IaaS 基座，容器云作为 CaaS 中间层，云原生作为 SaaS 应用层，整个云生态日新月异，SRE 团队的核心职能会更加注重顶层系统性的容量规划，指标监控，高可用性和分布式的弹性设计，所以跨平台跨部门的职能互补、团队协作、持续精进、勇于承担包括：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;积极参与事前的规划，配合开发做演练，协助架构改进；&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;合理提可用性需求，冗余资源，最好是有预算，做到防患于未燃；&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;线上监控，故障分析，反馈给整个团队，倒逼上下协调做改进；&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;团队的价值就在于是否总是能够接受新事物，新的挑战，各施所长，不做井底之蛙，也不是温水煮青蛙，在创新或者颠覆来临的时候，也能保持不被时代脱钩。&lt;/p&gt;
&lt;h3 id="对于运维工程师个体，SRE的转型路径是？应该注意些什么？"&gt;对于运维工程师个体，SRE 的转型路径是？应该注意些什么？&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;技术领域&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;学会抽象业务模型，标准化组件，定制化脚本，自动化部署，提升整体效率；&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;学会收集日志和日志分析并可视化，提升运维监控和预警报警的效率；&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;掌握和熟悉一门或若干语言，能够帮助你成长，提升你的战斗力；&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;勤做笔记，温故而知新，学思结合，要学会沉淀，举一反三；&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;勇于面对新兴技术的挑战，打不过就学它；&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;非技术领域&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;学习能力，要知识面广；&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;沟通方面，了解客户的精确需求；&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;技术风险、人工、进度等成本，权衡取舍；&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;社区活动，积极分享，锻炼口才和交流能力；&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;提升自己的影响力，学会与人同行，可以交到更多的朋友；&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="面对当下快速发展的基础技术，您对给刚入行和入行已久的运维人员，分别有什么职业规划的建议吗？"&gt;面对当下快速发展的基础技术，您对给刚入行和入行已久的运维人员，分别有什么职业规划的建议吗？&lt;/h3&gt;
&lt;p&gt;首先不是工作选择人，而是人选择工作，一个人若对某方面有了兴趣，真正用心学习了近 10000 个小时，其实做什么都是可以的。比如说我毕业那个时候，都是强调复合型人才，根本没有运维这个职业，我们不光自己攒 (DIY) 机器，自学 Linux 操作系统，还学习编程，折腾网络，自己动手写论坛聊天室等程序；Linux 给我们带来的是每天都有创新的，好玩的，优秀的开源软件让我们保持激情去尽情的折腾和学习，当互联网兴起的机会来临时，做个运维总监其实也是顺理成章的事；其实，除此之外，我还转型做过售前，技术支持，跑过市场，经常做演讲培训，所以真正的高手是什么不会学什么，技多不压身，做个懂业务、会开发的运维工程师。&lt;/p&gt;
&lt;h3 id="您觉得运维人员最重要的素养是什么？对新入行的运维人员有哪些寄语？"&gt;您觉得运维人员最重要的素养是什么？对新入行的运维人员有哪些寄语？&lt;/h3&gt;
&lt;p&gt;我认为最重要的能力是表达沟通能力，但不排除运维本身所需的技术储备、实践动手能力、编程能力和学习能力。考虑到运维大部分还是一个成本支出的岗位，如何把深奥隐晦的性能及瓶颈指标，用直观的图表展示来获取上层持续的投入是需要技巧的；然后面对你的同事，你的兄弟部门，也需要你的影响力去协调推进工作，如果能够做到这些，说明你已经具备了领导的才能，这样以后做什么事都会站在更高的水平，用全局观的格局去统筹规划整个项目的目标，人员，工期和资源的合理分配和把握。&lt;/p&gt;</description>
      <author>upyun</author>
      <pubDate>Mon, 06 Mar 2023 10:49:21 +0800</pubDate>
      <link>https://ruby-china.org/topics/42923</link>
      <guid>https://ruby-china.org/topics/42923</guid>
    </item>
    <item>
      <title>记一次 inode 数量耗尽导致的生产事故</title>
      <description>&lt;p&gt;今天遇到一个挺有趣的场景，公司的线上服务器突然无法访问，当我尝试重新部署项目解决问题的时候却提示我说空间不足。这就很耐人寻味了，磁盘空间显示还剩几十个 G，一查发现原来是 inode 的问题，这篇文章简单记录一下。原文连接： &lt;a href="https://step-by-step.tech/posts/an-accident-of-inode-number-in-huiliu" rel="nofollow" target="_blank"&gt;https://step-by-step.tech/posts/an-accident-of-inode-number-in-huiliu&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="Linux系统的inode指标"&gt;Linux 系统的 inode 指标&lt;/h2&gt;
&lt;p&gt;Linux 系统里面有一个 inode 的概念，大概是这样一个意思&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;An inode is a data structure that keeps track of all the files and directories within a Linux or UNIX-based filesystem. So, every file and directory in a filesystem is allocated an inode, which is identified by an integer known as “inode number”. These unique identifiers store metadata about each file and directory.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;简单来说就是，在 Linux 或者类 Unix 的文件系统里面，所有的文件/目录都会被分配一个&lt;code&gt;inode number&lt;/code&gt;，这是一个唯一的编号，且数量是有限的。我们可以通过&lt;code&gt;ls -i&lt;/code&gt;来查看对应文件的&lt;code&gt;inode number&lt;/code&gt;。比如这样&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; apiclient_key.pem
6556243 apiclient_key.pem
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;表明&lt;code&gt;apiclient_key.pem&lt;/code&gt;这个文件的&lt;code&gt;inode number&lt;/code&gt;是&lt;code&gt;6556243&lt;/code&gt;。我们可以通过命令&lt;code&gt;df -i&lt;/code&gt;查看当前系统里 inode 总量&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;df&lt;/span&gt; &lt;span class="nt"&gt;-ih&lt;/span&gt;

Filesystem      Inodes   IUsed   IFree IUse% Mounted on
udev           1975880     418 1975462    1% /dev
tmpfs          1982935     626 1982309    1% /run
/dev/vda1      9830400 6873397 2957003   70% /
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="inode“超标”导致的“空间不足”"&gt;inode“超标”导致的“空间不足”&lt;/h2&gt;
&lt;p&gt;对阿里云服务器来说，一般硬盘的存储设备都是&lt;code&gt;/dev/vdax&lt;/code&gt;，我这台服务器刚好是&lt;code&gt;/dev/vda1&lt;/code&gt;。从上面的结果可知，该文件系统的 inodes 总容量是 9830400，已经使用了 6873397，还剩余 2957003。讲得再生动一点就是，这台服务器一共可以创建 9830400 个文件/目录，现在已经有 6873397 个了，接下来最多也只能创建 2957003 个文件/目录。如果数量超出之后，再尝试创建文件的时候系统会报错&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;No space left on device or running out of Inodes.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;第一次遇到这个错的时候，笔者也是吓懵了，毕竟这辈子从来没有见到过，而且当时线上的服务完全停滞，需要紧急修复。明明磁盘还有几十 G 的盈余，为何会&lt;strong&gt;No space left on device&lt;/strong&gt;。当时我的服务器大概都成这个鬼样了吧（这还是删除大量文件之后）&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;df&lt;/span&gt; &lt;span class="nt"&gt;-ih&lt;/span&gt;
Filesystem      Inodes   IUsed   IFree IUse% Mounted on
udev             1.9M   418  1.9M    1% /dev
tmpfs            1.9M   626  1.9M    1% /run
/dev/vda1        9.4M  9.3M  108K   99% /
....

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;系统运行有 2 年时间了，只是盯着磁盘空间看，没有留意到 inode 数量也会造成“空间不足”，也算是一点小经验了。幸好当时笔者距离家不远，急忙赶回家修复不至于耽误太长的时间。网上找到这个脚本，可以查找当前目录下文件数量最多的子目录，这是最后在 Rails 项目目录下的&lt;code&gt;tmp/&lt;/code&gt;目录里面运行的结果&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;sudo &lt;/span&gt;find shared &lt;span class="nt"&gt;-xdev&lt;/span&gt; &lt;span class="nt"&gt;-type&lt;/span&gt; f | &lt;span class="nb"&gt;cut&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s2"&gt;"/"&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; 2 | &lt;span class="nb"&gt;sort&lt;/span&gt; | &lt;span class="nb"&gt;uniq&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt; | &lt;span class="nb"&gt;sort&lt;/span&gt; &lt;span class="nt"&gt;-nr&lt;/span&gt;

9045071 cache
      8 videos
      2 pids
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可见&lt;code&gt;cache&lt;/code&gt;目录里面有太多的文件。估计是我使用模板系统的时候开启了缓存导致的。从文件落地的情况来看应该是使用了类似 Rails 的&lt;a href="https://guides.rubyonrails.org/caching_with_rails.html#fragment-caching" rel="nofollow" target="_blank" title=""&gt;Fragment Caching&lt;/a&gt;。模板以持久化的方式缓存了，且没有定时清理，运行时间太长，导致了&lt;code&gt;tmp/cache&lt;/code&gt;目录下的缓存模板越来越多。最终把操作系统的&lt;code&gt;inode number&lt;/code&gt;给撑爆了。&lt;/p&gt;

&lt;p&gt;解决方案其实挺简单的。可以手动删除一下&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; tmp/cache/&lt;span class="k"&gt;*&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;官方的做法则是通过脚本&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; Rails.cache.clear
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;作用是一样的，只是清理了&lt;code&gt;tmp/cache&lt;/code&gt;目录下的所有缓存文件。最大的问题是，缓存文件多的时候，这个过程会比较慢，占用系统资源导致服务器卡顿。建议定期清理，不用一次过清理干净，也可以只清理那些失效很长时间的缓存模板文件。&lt;/p&gt;
&lt;h2 id="总结"&gt;总结&lt;/h2&gt;
&lt;p&gt;第一次遇到这种场景的时候还是挺吓人的，似乎每 1 ～ 2 个月都会遇到点刺激的事故。这一两年下来算是习惯了，可能这也是后端/运维工作的常态吧。&lt;/p&gt;</description>
      <author>lanzhiheng</author>
      <pubDate>Sat, 10 Dec 2022 09:26:11 +0800</pubDate>
      <link>https://ruby-china.org/topics/42785</link>
      <guid>https://ruby-china.org/topics/42785</guid>
    </item>
    <item>
      <title>Rails 多节点日志合并查询</title>
      <description>&lt;h4 id="场景"&gt;场景&lt;/h4&gt;
&lt;p&gt;业务基于 &lt;code&gt;ruby on rails&lt;/code&gt; 用 &lt;code&gt;sidekiq&lt;/code&gt; 做异步队列，运行在 N 台服务器，N &amp;gt; 1，没有专门的日志服务器。&lt;/p&gt;

&lt;p&gt;业务定位问题，需要在 N 台机器的日志中搜索关键字，这样效率低。&lt;/p&gt;
&lt;h4 id="解决方案"&gt;解决方案&lt;/h4&gt;
&lt;p&gt;将 N 台机器日志，合并到一台目标机器，在目标机器上面查看最终日志搜索结果，这样效率高。&lt;/p&gt;

&lt;p&gt;假定有 3 台机器：A，B，C。&lt;/p&gt;

&lt;p&gt;目标是在 A 上执行脚本，一键将 B，C 机器日志拉取到 A 机器。&lt;/p&gt;
&lt;h4 id="方法"&gt;方法&lt;/h4&gt;&lt;h5 id="1. 将服务器A 公钥添加到B，C机器信任列表"&gt;1. 将服务器 A 公钥添加到 B，C 机器信任列表&lt;/h5&gt;
&lt;p&gt;在机器 A 上执行&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# 将下面的值拷贝&lt;/span&gt;
more ~/.ssh/id_rsa.pub
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在机器 B,C 上执行&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# 将拷贝的值追加到 authorized_keys&lt;/span&gt;
vim ~/.ssh/authorized_keys 
&lt;/code&gt;&lt;/pre&gt;&lt;h5 id="2. 添加远程执行的脚本"&gt;2. 添加远程执行的脚本&lt;/h5&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /tmp/&lt;span class="nv"&gt;$1&lt;/span&gt;
&lt;span class="k"&gt;for &lt;/span&gt;server &lt;span class="k"&gt;in &lt;/span&gt;B-INNER-IP  C-INNER-IP&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="c"&gt;# 注 B-INNER-IP 和 C-INNER-IP 是 B/C 服务器的内网IP地址&lt;/span&gt;
  &lt;span class="c"&gt;# deployer 是 B/C服务器的用户名 $1和$2 是执行脚本传入的第一，第二个参数， (date +%F) 是当天时间，比如： '2022-11-27'&lt;/span&gt;
  &lt;span class="c"&gt;# 以下语句： 远程ssh到B或C的指定目录， 在文件 $1中按关键字$2搜索今天的日志，追加到机器 A 的 /tmp/$1 目录&lt;/span&gt;
  ssh &lt;span class="nt"&gt;-t&lt;/span&gt; deployer@&lt;span class="nv"&gt;$server&lt;/span&gt; &lt;span class="s1"&gt;'cd /home/deployer/wai_mai/shared/log; more '&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s1"&gt;' |grep "$(date +%F)" | grep '&lt;/span&gt;&lt;span class="nv"&gt;$2&lt;/span&gt;&lt;span class="s1"&gt;''&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; /tmp/&lt;span class="nv"&gt;$1&lt;/span&gt;
  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"##### 节点 &lt;/span&gt;&lt;span class="nv"&gt;$server&lt;/span&gt;&lt;span class="s2"&gt; 传输完成#####"&lt;/span&gt;
&lt;span class="k"&gt;done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;注&lt;/strong&gt; 在 B，C 机器按关键字搜索后，再回传到机器 A，而不是将 B，C 机器整个日志传到 A，再在 A 上面进行搜索，这样可以大大降低网络传输。&lt;/p&gt;

&lt;p&gt;将脚本命名为： &lt;code&gt;merge_log.sh&lt;/code&gt;，添加可执行权限&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;chmod &lt;/span&gt;700 merge_log.sh
&lt;/code&gt;&lt;/pre&gt;&lt;h5 id="3. 执行脚本"&gt;3. 执行脚本&lt;/h5&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# 从机器 B，C上，找到今天在日志 `unicorn.stdout.log` 出现关键字 `588e6f3837b74dfdb827ba4d5e614645` 的所有日志，并存储到 A 机器的 /tmp/unicorn.stdout.log 文件中&lt;/span&gt;
./merge_log.sh  unicorn.stdout.log 588e6f3837b74dfdb827ba4d5e614645

&lt;span class="c"&gt;# 从机器 B，C上，找到今天在日志 `sidekiq.log` 出现关键字 `1100303332560786082` 的所有日志，并存储到 A 机器的 /tmp/sidekiq.log 文件中&lt;/span&gt;
./merge_log.sh sidekiq.log 1100303332560786082
&lt;/code&gt;&lt;/pre&gt;&lt;h4 id="备注"&gt;备注&lt;/h4&gt;
&lt;p&gt;目前的方式，对于机器都在一个内网中，整体执行效率较高。&lt;/p&gt;

&lt;p&gt;如果大家有更加优雅的日志合并和查询的方案，也请留言。&lt;/p&gt;</description>
      <author>luolinae86</author>
      <pubDate>Sun, 27 Nov 2022 17:17:43 +0800</pubDate>
      <link>https://ruby-china.org/topics/42766</link>
      <guid>https://ruby-china.org/topics/42766</guid>
    </item>
    <item>
      <title>corntab 表达式, 我百思不得其解, 求助各位 / \</title>
      <description>&lt;p&gt;cron 在线计算器：&lt;a href="https://tool.lu/crontab/" rel="nofollow" target="_blank"&gt;https://tool.lu/crontab/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;cron 表达式：0 0 */3 9 0&lt;/p&gt;

&lt;p&gt;注 : 上面的意思是从 9 月份开始，每隔 3 天执行一次，但是为什么 10 号和 11 号会连续执行，百思不得其解，我很苦恼 /  \&lt;/p&gt;

&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/cheng_sukai/b18ddea5-6902-4dcc-8ac1-e8817a4dffae.png!large" title="" alt=""&gt;&lt;/p&gt;</description>
      <author>cheng_sukai</author>
      <pubDate>Fri, 05 Aug 2022 12:39:40 +0800</pubDate>
      <link>https://ruby-china.org/topics/42575</link>
      <guid>https://ruby-china.org/topics/42575</guid>
    </item>
    <item>
      <title>Foreman 是干什么的？ 为什么不用 systemd ？</title>
      <description>&lt;p&gt;我在看一些项目的部署文档时，有些人提到了 Foreman，看样子它是用来守护进程的。比如 puma/sidekiq/racecar 之类的进程挂了，foreman 可以自动把它们启动。&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/zendesk/racecar#deploying-consumers" rel="nofollow" target="_blank"&gt;https://github.com/zendesk/racecar#deploying-consumers&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you're already deploying your Rails application using e.g. Capistrano, all you need to do to run your Racecar consumers in production is to have some process supervisor start the processes and manage them for you.&lt;/p&gt;

&lt;p&gt;Foreman is a very straightford tool for interfacing with several process supervisor systems. You define your process types in a Procfile, e.g.&lt;/p&gt;

&lt;p&gt;racecar-process-payments: bundle exec racecar ProcessPaymentsConsumer
racecar-resize-images: bundle exec racecar ResizeImagesConsumer&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="问题"&gt;问题&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;foreman 可以守护其他进程，如果 foreman 自己挂了，谁把它启动啊？&lt;/li&gt;
&lt;li&gt;为什么大家不直接用 systemd？&lt;/li&gt;
&lt;li&gt;foreman 出生时，systemd 还没诞生（或成熟）吗？&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;熟悉 Linux 的朋友，可以讲一讲历史岁月吗？&lt;/p&gt;</description>
      <author>xiaoronglv</author>
      <pubDate>Thu, 14 Oct 2021 10:11:14 +0800</pubDate>
      <link>https://ruby-china.org/topics/41770</link>
      <guid>https://ruby-china.org/topics/41770</guid>
    </item>
    <item>
      <title>利用 systemd 在 Ubuntu 執行 Sidekiq 6</title>
      <description>&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/kevinluo201/b9c06389-175f-455a-8f03-4e47845bb9b5.jpg!large" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;网志版：&lt;a href="https://dev.to/kevinluo201/systemd-ubuntu-sidekiq-6-d9c" rel="nofollow" target="_blank" title=""&gt;https://dev.to/kevinluo201/systemd-ubuntu-sidekiq-6-d9c&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;自从有了 Sidekiq 后，所有事情都变得容易了。
所有需要长时间执行的程式，我全往 sidekiq 扔，我再也不用怕 CloudFlare 的 524(请求超时) 了 (咦？)
在 production 的环境执行 sidekiq 虽不困难但对于 Linux 没那麽熟的人来说还满多细节要注意的，
Sidekiq 6 又好像跟之前变化颇大。
这次想分享一下将 Sidekiq 6 运行在 ubuntu 20.04 的经验 : )&lt;/p&gt;
&lt;h2 id="目标"&gt;目标&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;运行 Sidekiq (废话...)&lt;/li&gt;
&lt;li&gt;重开机或 sidekiq 挂了的话，sidekiq 会自动重启&lt;/li&gt;
&lt;li&gt;当我用 Capistrano 部署新的程式码时，sidekiq 会读新的程式码并重启&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="我们怎麽执行 Sidekiq?"&gt;我们怎麽执行 Sidekiq?&lt;/h2&gt;
&lt;p&gt;要知道在 production 环境怎麽运行 sidekiq, 首先要知道在 development 环境是怎麽跑的：&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bundle &lt;span class="nb"&gt;exec &lt;/span&gt;sidekiq
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;其实就那麽容易... 你可以再加一些参数像 &lt;code&gt;-C xxxx.yml&lt;/code&gt; 去指定要读取的设定档。不过我们先维持这样&lt;/p&gt;

&lt;p&gt;基本上你在 production 环境可以做一样的事，如果你想让它更像一个”真的服务”，也可以直接加个“&amp;amp;”在后面让它跑在背景：&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;RAILS_ENV&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;production bundle &lt;span class="nb"&gt;exec &lt;/span&gt;sidekiq &amp;amp;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果真的纯粹只是想要在 production 环境跑 sidekiq，其实这样就够了&lt;/p&gt;

&lt;p&gt;但光这样做好像没符合我们的目标：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;重开机或程式挂掉后 sidekiq 不会自动运行&lt;/li&gt;
&lt;li&gt;部署完后也不会自动运行&lt;/li&gt;
&lt;li&gt;最重要的是，这感觉好像不是很”Pro”。即使我们不是用 Sidekiq Pro , 应该也可以 Pro 一点&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;好，为了达到我们的目标，我们需要用 &lt;code&gt;systemd&lt;/code&gt;&lt;/p&gt;
&lt;h2 id="systemd是什麽?"&gt;systemd 是什麽？&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;systemd&lt;/code&gt; 是 Linux 系统专门来管理各式「服务程式」的程式，其实就是 daemon 所以才是 system*&lt;em&gt;d&lt;/em&gt;*。比如 mysql, apache, nginx, redis 这些都可以用它来管，事实上 &lt;code&gt;systemd&lt;/code&gt; 是多数 Linux 版本预设的 Service Manager。
有 &lt;code&gt;systemd&lt;/code&gt;,，我们可以：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;用 &lt;code&gt;systemctl start/stop/restart&lt;/code&gt; 任何服务&lt;/li&gt;
&lt;li&gt;可以启用 (&lt;strong&gt;enable&lt;/strong&gt;) 服务，启用的服务在系统重开时会自动开始运行&lt;/li&gt;
&lt;li&gt;你可以指定当程式挂掉后，该做什麽事，例如重启该服务&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;systemd&lt;/code&gt; 的内容还有一堆，不过目前知道这样就足够了，剩下的就自行 google 吧 xD
看起来 systemd 可以符合我们想做的事，就用 systemd 来操作 sidekiq 吧！&lt;/p&gt;
&lt;h2 id="将 Sidekiq 变成一个服务单元(service unit)"&gt;将 Sidekiq 变成一个服务单元 (service unit)&lt;/h2&gt;
&lt;p&gt;在 systemd 中，每个服务都被视为一个「单元」(Unit)
要新增一个 sidekiq 的服务单元，我们可以新增一个档案 &lt;code&gt;/lib/systemd/system/sidekiq.service&lt;/code&gt;
(另外，用来部署 rails 的使用者叫 &lt;code&gt;deployer&lt;/code&gt;)&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# /lib/systemd/system/sidekiq.service&lt;/span&gt;
&lt;span class="c"&gt;# 我们的 service 叫 sidekiq&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt;Unit]
&lt;span class="nv"&gt;Description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;sidekiq
&lt;span class="nv"&gt;After&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;syslog.target network.target

&lt;span class="c"&gt;# 这个 Type=simple 只是 systemd 要如何判断你的服务成功执行&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt;Service]
&lt;span class="nv"&gt;Type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;simple
&lt;span class="nv"&gt;WorkingDirectory&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/path/to/your/app

&lt;span class="c"&gt;# 如果是用 rbenv:&lt;/span&gt;
&lt;span class="c"&gt;# ExecStart=/bin/bash -lc 'exec /home/deploy/.rbenv/shims/bundle exec sidekiq -e production'&lt;/span&gt;
&lt;span class="c"&gt;# 如果直接用系统安装的 ruby:&lt;/span&gt;
&lt;span class="c"&gt;# ExecStart=/usr/local/bin/bundle exec sidekiq -e production&lt;/span&gt;
&lt;span class="c"&gt;# 如果是用 rvm ，用 ruby 2.6.5 也无特定 gemset&lt;/span&gt;
&lt;span class="c"&gt;# ExecStart=/home/deploy/.rvm/gems/ruby-2.6.5/wrappers/bundle exec sidekiq -e production&lt;/span&gt;
&lt;span class="c"&gt;# 如果是用 rvm ，用 ruby 2.6.5 且有特定 gemset&lt;/span&gt;
&lt;span class="c"&gt;# ExecStart=/home/deploy/.rvm/gems/ruby-2.6.5@gemset-name/wrappers/bundle exec sidekiq -e production&lt;/span&gt;
&lt;span class="c"&gt;# 如果是用 rvm ，用而且专案有 .ruby-version 指定版本&lt;/span&gt;
&lt;span class="nv"&gt;ExecStart&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/home/deploy/.rvm/bin/rvm &lt;span class="k"&gt;in&lt;/span&gt; /path/to/your/app/current &lt;span class="k"&gt;do &lt;/span&gt;bundle &lt;span class="nb"&gt;exec &lt;/span&gt;sidekiq &lt;span class="nt"&gt;-e&lt;/span&gt; production

&lt;span class="nv"&gt;User&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;deployer
&lt;span class="nv"&gt;Group&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;deployer
&lt;span class="nv"&gt;UMask&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0002

&lt;span class="c"&gt;# 这行可以大大降低 Ruby memory 用量&lt;/span&gt;
&lt;span class="c"&gt;# 我也是抄来放上&lt;/span&gt;
&lt;span class="c"&gt;# 不过有看 MALLOC_ARENA_MAX=2 的意思是限制 sidekiq 只能用2个 tread_pool &lt;/span&gt;
&lt;span class="c"&gt;# https://www.mikeperham.com/2018/04/25/taming-rails-memory-bloat/&lt;/span&gt;
&lt;span class="nv"&gt;Environment&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;MALLOC_ARENA_MAX&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;2

&lt;span class="c"&gt;# 如果挂掉就重启&lt;/span&gt;
&lt;span class="nv"&gt;RestartSec&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1
&lt;span class="nv"&gt;Restart&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;on-failure

&lt;span class="c"&gt;# log 会记在 /var/log/syslog&lt;/span&gt;
&lt;span class="nv"&gt;StandardOutput&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;syslog
&lt;span class="nv"&gt;StandardError&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;syslog

&lt;span class="c"&gt;# 这个服务的id 是 sidekiq&lt;/span&gt;
&lt;span class="nv"&gt;SyslogIdentifier&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;sidekiq

&lt;span class="o"&gt;[&lt;/span&gt;Install]
&lt;span class="nv"&gt;WantedBy&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;multi-user.target
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;systemd&lt;/code&gt; 会去找 &lt;code&gt;/lib/systemd/system/&lt;/code&gt;下所有的档案，所以 &lt;code&gt;sidekiq.service&lt;/code&gt; 已经可以被 &lt;code&gt;systemd&lt;/code&gt; 找到了。
我们接着可以执行下列指令&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# 重读所有服务&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl daemon-reload
&lt;span class="c"&gt;# enable sidekiq.service 所以它可以在开机后自动运行&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl &lt;span class="nb"&gt;enable &lt;/span&gt;sidekiq.service
&lt;span class="c"&gt;# 启动 sidekiq&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;service sidekiq start
&lt;span class="c"&gt;# 在 /var/log/syslog 看有没有 sidekiq 的 log&lt;/span&gt;
&lt;span class="nb"&gt;sudo cat&lt;/span&gt; /var/log/syslog
&lt;span class="c"&gt;# 可以用 ps 看 sidekiq 执行了或&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;ps aux | &lt;span class="nb"&gt;grep &lt;/span&gt;sidekiq
&lt;span class="c"&gt;# 或直接用 systemctl 来看目前运行中的服务&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl status
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="让 Capistrano 重启 Sidekiq"&gt;让 Capistrano 重启 Sidekiq&lt;/h2&gt;
&lt;p&gt;我用 Capistrano 来做自动部署以避免错误。
部署完当然希望 sidekiq 重启，这样它才读到最新的程式码。
要把重启 sidekiq 加到 Capistrano 的流程中，其实只要安装 gem &lt;code&gt;capistrano-sidekiq&lt;/code&gt; 就可以了。
在 Gemfile 加入：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Gemfile&lt;/span&gt;
&lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s1"&gt;'capistrano-sidekiq'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;group: :development&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;再到 Capfile 加入：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Capfile&lt;/span&gt;
&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'capistrano/sidekiq'&lt;/span&gt;
&lt;span class="c1"&gt;# 加入 sidekiq 的 rake tasks&lt;/span&gt;
&lt;span class="n"&gt;install_plugin&lt;/span&gt; &lt;span class="no"&gt;Capistrano&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Sidekiq&lt;/span&gt;
&lt;span class="c1"&gt;# 设定要用 systemd 去控制 sidekiq&lt;/span&gt;
&lt;span class="n"&gt;install_plugin&lt;/span&gt; &lt;span class="no"&gt;Capistrano&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Sidekiq&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Systemd&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这样设定好， &lt;code&gt;cap production deploy&lt;/code&gt; 时就会依序执行下列工作：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;停止从 redis 拿工作&lt;/li&gt;
&lt;li&gt;停止 Sidekiq 服务&lt;/li&gt;
&lt;li&gt;开启 Sidekiq 服务&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="做一个一般使用者的 sidekiq.service"&gt;做一个一般使用者的 sidekiq.service&lt;/h2&gt;
&lt;p&gt;上面其实我故意漏说了一件事。
上面新增的 service unit 其实是全系统范围的，也就是要用 &lt;code&gt;sudo&lt;/code&gt; 去执行 &lt;code&gt;systemctl&lt;/code&gt;的
如果我们希望一般的使用者也可以使用 systemd 的话，我们必须要做一个使用者自己的 sidekiq.service
而且 &lt;code&gt;capistrano/sidekiq&lt;/code&gt; 其实预设是要用一般使用者的权限去执行 systemctl 来重启 Sidekiq 的&lt;/p&gt;

&lt;p&gt;当然我们也可以去改 &lt;code&gt;capistrano/sidekiq&lt;/code&gt; 的设定，让它用 root 的权限去操作 systemctl，我只是想说明其实有多种选择，每种都可以。而且一开始我的 &lt;code&gt;sidekiq.service&lt;/code&gt; 怎麽都跑不起来就是因为我没注意到这件事....所以想特别提一下。&lt;/p&gt;

&lt;p&gt;If you have already enabled the system-wise &lt;code&gt;sidekiq.service&lt;/code&gt;, you need to disable it and delete the service-unit:
如果你刚刚已经安装好了全系统级别的 sidekiq.servive，你需要执行下面步骤去取消它：&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# 先停止 sidekiq&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl stop sidekiq
&lt;span class="c"&gt;# 不要启用 sidekiq.service&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl disable sidekiq.service
&lt;span class="c"&gt;# 删掉&lt;/span&gt;
&lt;span class="nb"&gt;sudo rm&lt;/span&gt; /lib/systemd/system/sidekiq.service
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;一般使用者级别的服务单元要放在 &lt;code&gt;~/.config/systemd/user/&lt;/code&gt; 下，systemd 会去检查下面的档案。我们再新增一次 &lt;code&gt;sidekiq.service&lt;/code&gt;，它稍有一些不同：&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;[&lt;/span&gt;Unit]
&lt;span class="nv"&gt;Description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;sidekiq
&lt;span class="nv"&gt;After&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;syslog.target network.target

&lt;span class="o"&gt;[&lt;/span&gt;Service]
&lt;span class="c"&gt;# 如果是用 Sidekiq 6.0.6 以后的版本，可以改成 notify 并配合 WatchdogSec&lt;/span&gt;
&lt;span class="c"&gt;# 否则沿用 simple&lt;/span&gt;
&lt;span class="nv"&gt;Type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;notify
&lt;span class="nv"&gt;WatchdogSec&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;10

&lt;span class="nv"&gt;WorkingDirectory&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/path/to/your/app/current

&lt;span class="c"&gt;# 如果是用 rbenv:&lt;/span&gt;
&lt;span class="c"&gt;# ExecStart=/bin/bash -lc 'exec /home/deploy/.rbenv/shims/bundle exec sidekiq -e production'&lt;/span&gt;
&lt;span class="c"&gt;# 如果直接用系统安装的 ruby:&lt;/span&gt;
&lt;span class="c"&gt;# ExecStart=/usr/local/bin/bundle exec sidekiq -e production&lt;/span&gt;
&lt;span class="c"&gt;# 如果是用 rvm ，用 ruby 2.6.5 也无特定 gemset&lt;/span&gt;
&lt;span class="c"&gt;# ExecStart=/home/deploy/.rvm/gems/ruby-2.6.5/wrappers/bundle exec sidekiq -e production&lt;/span&gt;
&lt;span class="c"&gt;# 如果是用 rvm ，用 ruby 2.6.5 且有特定 gemset&lt;/span&gt;
&lt;span class="c"&gt;# ExecStart=/home/deploy/.rvm/gems/ruby-2.6.5@gemset-name/wrappers/bundle exec sidekiq -e production&lt;/span&gt;
&lt;span class="c"&gt;# 如果是用 rvm ，用而且专案有 .ruby-version 指定版本&lt;/span&gt;
&lt;span class="nv"&gt;ExecStart&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/home/deploy/.rvm/bin/rvm &lt;span class="k"&gt;in&lt;/span&gt; /path/to/your/app/current &lt;span class="k"&gt;do &lt;/span&gt;bundle &lt;span class="nb"&gt;exec &lt;/span&gt;sidekiq &lt;span class="nt"&gt;-e&lt;/span&gt; production
&lt;span class="nv"&gt;ExecReload&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/usr/bin/kill &lt;span class="nt"&gt;-TSTP&lt;/span&gt; &lt;span class="nv"&gt;$MAINPID&lt;/span&gt;

&lt;span class="c"&gt;# 这行可以大大降低 Ruby memory 用量&lt;/span&gt;
&lt;span class="c"&gt;# 我也是抄来放上&lt;/span&gt;
&lt;span class="c"&gt;# 不过有看 MALLOC_ARENA_MAX=2 的意思是限制 sidekiq 只能用2个 tread_pool &lt;/span&gt;
&lt;span class="c"&gt;# https://www.mikeperham.com/2018/04/25/taming-rails-memory-bloat/&lt;/span&gt;
&lt;span class="nv"&gt;Environment&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;MALLOC_ARENA_MAX&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;2

&lt;span class="c"&gt;# 如果挂掉就重启&lt;/span&gt;
&lt;span class="nv"&gt;RestartSec&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1
&lt;span class="nv"&gt;Restart&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;on-failure

&lt;span class="c"&gt;# log 会记在 /var/log/syslog&lt;/span&gt;
&lt;span class="nv"&gt;StandardOutput&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;syslog
&lt;span class="nv"&gt;StandardError&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;syslog

&lt;span class="c"&gt;# 这个服务的id 是 sidekiq&lt;/span&gt;
&lt;span class="nv"&gt;SyslogIdentifier&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;sidekiq

&lt;span class="o"&gt;[&lt;/span&gt;Install]
&lt;span class="nv"&gt;WantedBy&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;default.target
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;我们再跑以下指令来启用/启动 &lt;code&gt;sidekiq.service&lt;/code&gt;:&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;systemctl &lt;span class="nt"&gt;--user&lt;/span&gt; daemon-reload 
systemctl &lt;span class="nt"&gt;--user&lt;/span&gt; &lt;span class="nb"&gt;enable &lt;/span&gt;sidekiq.service

&lt;span class="c"&gt;# 现在可以控制 sidekiq 啦&lt;/span&gt;
systemctl &lt;span class="nt"&gt;--user&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;start,stop,restart&lt;span class="o"&gt;}&lt;/span&gt; sidekiq
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;现在 &lt;code&gt;capistrano/sidekiq&lt;/code&gt; 应该可以正常运作了，用 capistrano 部署看看吧 : )&lt;/p&gt;
&lt;h2 id="其它问题"&gt;其它问题&lt;/h2&gt;&lt;h3 id="部署时跑 sidekiq:quiet 出现以下错误"&gt;部署时跑 sidekiq:quiet 出现以下错误&lt;/h3&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sidekiq:quiet
    01 systemctl --user reload sidekiq
    01 Failed to reload sidekiq.service: Job type reload is not applicable for unit sidekiq.service.
  ✘ 01 deployer@xxxxxxxx 0.067s
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;解法
    * 加  &lt;code&gt;ExecReload=/bin/kill -TSTP $MAINPID&lt;/code&gt; 进 sidekiq.service&lt;/p&gt;
&lt;h3 id="出现 target 找不到"&gt;出现 target 找不到&lt;/h3&gt;
&lt;p&gt;* target 其实是一组 service unit，执行 target 时全部服务会一起执行
    * 用 &lt;code&gt;systemctl list-units —type=target&lt;/code&gt; 去看能用的 target&lt;/p&gt;
&lt;h3 id="-L log/sidekiq.log 无效"&gt;-L log/sidekiq.log 无效&lt;/h3&gt;
&lt;p&gt;* Sidekiq 6 不再支援 log 的转向，请看 &lt;a href="https://github.com/mperham/sidekiq/wiki/Logging" rel="nofollow" target="_blank" title=""&gt;Logging · mperham/sidekiq Wiki · GitHub&lt;/a&gt;，一律看 /var/log/syslog
    * 可以用 &lt;code&gt;bundle exec sidekiq 2&amp;gt;&amp;amp;1 | logger -t sidekiq&lt;/code&gt; 为 log 加上 sidekiq 的 tag&lt;/p&gt;
&lt;h2 id="参考资料"&gt;参考资料&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;其实 &lt;code&gt;sidekiq.service&lt;/code&gt; 大部分我也是从 sidekiq repo 看来的啦：&lt;a href="https://github.com/mperham/sidekiq/blob/master/examples/systemd/sidekiq.service" rel="nofollow" target="_blank" title=""&gt;sidekiq/sidekiq.service at master · mperham/sidekiq · GitHub&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/seuros/capistrano-sidekiq" rel="nofollow" target="_blank" title=""&gt;GitHub - seuros/capistrano-sidekiq: Sidekiq integration for Capistrano&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <author>kevinluo201</author>
      <pubDate>Sat, 21 Aug 2021 01:06:16 +0800</pubDate>
      <link>https://ruby-china.org/topics/41600</link>
      <guid>https://ruby-china.org/topics/41600</guid>
    </item>
    <item>
      <title>How Linux finds physical address through virtual memory</title>
      <description>&lt;p&gt;原文链接 &lt;a href="https://github.com/yfractal/blog/blob/master/blog/2021-08-11-how-linux-finds-physical-address-through-virtual-address.md" rel="nofollow" target="_blank"&gt;https://github.com/yfractal/blog/blob/master/blog/2021-08-11-how-linux-finds-physical-address-through-virtual-address.md&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="Why"&gt;Why&lt;/h2&gt;
&lt;p&gt;Hardware can map virtual address to physical address or use physical address directly.&lt;/p&gt;

&lt;p&gt;The virtual address to physical address mapping is stored in memory.&lt;/p&gt;

&lt;p&gt;When virtual address is enabled, hardware will help us do the virtual address to physical address mapping.&lt;/p&gt;

&lt;p&gt;Sometimes, the kernel needs to do the same thing.&lt;/p&gt;

&lt;p&gt;For example when the kernel allocates new memory for a process kernel needs to walk through the page table and set up the mapping.&lt;/p&gt;

&lt;p&gt;So kernel needs to know how page table works.&lt;/p&gt;

&lt;p&gt;Now let's see how the hardware handles the virtual addresses.&lt;/p&gt;
&lt;h2 id="x86 4-level paging"&gt;x86 4-level paging&lt;/h2&gt;
&lt;p&gt;X86 supports different kinds of pages, they are similar. So let's consider 4 levels paging and 4KB page only.&lt;/p&gt;

&lt;p&gt;&lt;img src="https://user-images.githubusercontent.com/3775525/129035231-13bdac79-ebf8-4b1f-8e51-e988ddfa3eee.png" title="" alt="Screen Shot 2021-08-11 at 9 14 57 PM"&gt;&lt;/p&gt;

&lt;p&gt;As the image above, register &lt;code&gt;CR3&lt;/code&gt; is pointing to start address of global(L3) directory page, and virtual address' 47 ~ 39 bits will be used for global(L3) directory page(L3)'s offset.&lt;/p&gt;

&lt;p&gt;Then the content will point to the next level directory's start address, then we can use 38 ~ 30 bits of virtual address for the offset of the upper(L2) directory page.&lt;/p&gt;

&lt;p&gt;Then middle(L1) directory page and finally we arrive at page table(L0).&lt;/p&gt;
&lt;h3 id="Linux follow_page method"&gt;Linux &lt;code&gt;follow_page&lt;/code&gt; method&lt;/h3&gt;
&lt;p&gt;Linux &lt;code&gt;follow_page&lt;/code&gt; is used for doing the same thing.&lt;/p&gt;

&lt;p&gt;Main follow as before:&lt;/p&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// in mm/gup.c&lt;/span&gt;
&lt;span class="nf"&gt;follow_page&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;vma&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;flags&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;pgd&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;pgd_offset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mm&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nf"&gt;follow_p4d_mask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;vma&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pgd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;flags&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;p4d&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;p4d_offset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pgdp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// level 2&lt;/span&gt;
  &lt;span class="nf"&gt;follow_pud_mask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;vma&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;p4d&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;flags&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;pud&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;pud_offset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p4dp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;follow_pmd_mask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;vma&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pud&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;flags&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="n"&gt;pmd&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;pmd_offset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pudp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// level 1&lt;/span&gt;
      &lt;span class="nf"&gt;follow_page_pte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;vma&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pmd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;flags&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;pgmap&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;ptep&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;pte_offset_map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mm&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pmd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;ptl&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// level 0&lt;/span&gt;
        &lt;span class="n"&gt;pte&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt;&lt;span class="n"&gt;ptep&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;page&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;vm_normal_page&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;vma&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pte&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;pgd_offset&lt;/code&gt;'s defination is:&lt;/p&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt; &lt;span class="cp"&gt;#define PGDIR_SHIFT 39
&lt;/span&gt; &lt;span class="cp"&gt;#define PTRS_PER_PGD 512
&lt;/span&gt;
&lt;span class="cp"&gt;#define pgd_offset(mm, address) pgd_offset_pgd((mm)-&amp;gt;pgd, (address))
&lt;/span&gt;
 &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kr"&gt;inline&lt;/span&gt; &lt;span class="n"&gt;pgd_t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nf"&gt;pgd_offset_pgd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pgd_t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;pgd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
 &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pgd&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;pgd_index&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
 &lt;span class="p"&gt;};&lt;/span&gt;

 &lt;span class="cp"&gt;#define pgd_index(a)  (((a) &amp;gt;&amp;gt; PGDIR_SHIFT) &amp;amp; (PTRS_PER_PGD - 1))
&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;#define pgd_index(a)  (((a) &amp;gt;&amp;gt; PGDIR_SHIFT) &amp;amp; (PTRS_PER_PGD - 1))&lt;/code&gt; will shift right 39 bits then mark out 9 bits which will give us 47 ~ 39 bits of a virtual address.&lt;/p&gt;

&lt;p&gt;The result is the offset of the page global directory's offset.&lt;/p&gt;

&lt;p&gt;We add it to &lt;code&gt;pgd&lt;/code&gt; by &lt;code&gt;pgd + pgd_index(address)&lt;/code&gt; and the result is the next level directory's start address.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;p4d_offset&lt;/code&gt; is used for 5-level paging, code as below:&lt;/p&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kr"&gt;inline&lt;/span&gt; &lt;span class="n"&gt;p4d_t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nf"&gt;p4d_offset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pgd_t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;pgd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;pgtable_l5_enabled&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p4d_t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;pgd&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p4d_t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;pgd_page_vaddr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;pgd&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;p4d_index&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;pgtable_l5_enabled()&lt;/code&gt; will return &lt;code&gt;false&lt;/code&gt; we use level 4 paging, so &lt;code&gt;p4d_offset&lt;/code&gt; will just return &lt;code&gt;pgd&lt;/code&gt; back.&lt;/p&gt;

&lt;p&gt;Then &lt;code&gt;pud_offset&lt;/code&gt; for the upper directory, then &lt;code&gt;pmd_offset&lt;/code&gt; for the middle directory, and finally reached the last level by calling &lt;code&gt;pte_offset&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The calling is follow_page: pgd_offset -&amp;gt; p4d_offset -&amp;gt; pud_offset -&amp;gt; pmd_offset -&amp;gt; pte_offset.&lt;/p&gt;
&lt;h2 id="Paging"&gt;Paging&lt;/h2&gt;
&lt;p&gt;There are different kinds of paging in x84: 32-bit paging, PAE paging, 4-level paging, and 5-level paging.&lt;/p&gt;

&lt;p&gt;Basically, they are similar but use different bits for finding pages.&lt;/p&gt;

&lt;p&gt;More detail can be found in &lt;code&gt;Intel® 64 and IA-32 Architectures Software Developer’s Manual&lt;/code&gt; or &lt;code&gt;Understanding Linux Kernel&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;So I will not explain all of them.&lt;/p&gt;

&lt;p&gt;There are many interesting things about page table or addressing such as copy on write and &lt;code&gt;mmap&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;I will explain some of them in the following articles.&lt;/p&gt;</description>
      <author>yfractal</author>
      <pubDate>Wed, 11 Aug 2021 21:35:07 +0800</pubDate>
      <link>https://ruby-china.org/topics/41573</link>
      <guid>https://ruby-china.org/topics/41573</guid>
    </item>
    <item>
      <title>Ubuntu 应对卡死存档重启桌面技巧</title>
      <description>&lt;p&gt;理论上桌面 gnome shell 只是 Linux 上正在运行的一个程序，不存在真正意义上的桌面死机。因为系统本身并没有真正的挂掉。&lt;/p&gt;

&lt;p&gt;觉得系统卡顿，大多是内存+SWAP 分配到上限导致的。想要避免可以用一个办法，主动分配不低于 8G，最好 2 倍于内存的 SWAP 分区，可以有效的减少卡顿的现象。&lt;/p&gt;

&lt;p&gt;假设界面意外出现卡死，没必要像 Windows，Mac 一样去重启电脑。&lt;code&gt;Alt+F2&lt;/code&gt; 呼唤出类似于一个快捷命令窗口。&lt;/p&gt;

&lt;p&gt;然后输入 &lt;code&gt;r&lt;/code&gt; 回车。整个桌面会在记住当前浏览状态下，重启桌面。&lt;/p&gt;

&lt;p&gt;enjoy～&lt;/p&gt;
&lt;h2 id="参考"&gt;参考&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://wiki.archlinux.org/index.php/GNOME_(%E7%AE%80%E4%BD%93%E4%B8%AD%E6%96%87)#%E6%B5%8F%E8%A7%88" rel="nofollow" target="_blank" title=""&gt;GNOME_(简体中文)#浏览&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://wiki.gnome.org/Projects/GnomeShell/CheatSheet" rel="nofollow" target="_blank" title=""&gt;GnomeShell/CheatSheet&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <author>Mark24</author>
      <pubDate>Sat, 06 Feb 2021 20:17:59 +0800</pubDate>
      <link>https://ruby-china.org/topics/40897</link>
      <guid>https://ruby-china.org/topics/40897</guid>
    </item>
    <item>
      <title>2021 年给你的 MacbookPro 安装 Ubuntu</title>
      <description>&lt;h2 id="一、前面的话"&gt;一、前面的话&lt;/h2&gt;
&lt;p&gt;我的 MacBookPro2010(后面称呼为 mbp) 之前不能用了。usb 口接触不良，我以为就是永久了坏了。开机就非常卡，app 一个没开风扇就呼呼的，MacOS 也对他停止更新了。&lt;/p&gt;

&lt;p&gt;我以为这台设备就次废掉了。&lt;/p&gt;

&lt;p&gt;这里引入一个概念 &lt;a href="https://baike.baidu.com/item/%E8%AE%A1%E5%88%92%E6%8A%A5%E5%BA%9F/8582720?fr=aladdin" rel="nofollow" target="_blank" title=""&gt;计划性报废&lt;/a&gt; 就是为了企业的可持续发展，让你的老设备越来越慢，然后你会买新的 :D。&lt;/p&gt;

&lt;p&gt;好吧，这些都是铺垫。&lt;/p&gt;

&lt;p&gt;最重要是当你愿意折腾给他换个系统比如 Ubuntu，他的一切毛病都消失了。这就是计划性报废。&lt;/p&gt;

&lt;p&gt;这里记录以下 2021 年，首装 Ubuntu 踩下的坑。如果你恰巧也有一个同样的设备，在这里也能帮助到你。变“废”为宝。&lt;/p&gt;
&lt;h2 id="1. 看完这部分记录 你将会获得"&gt;1. 看完这部分记录 你将会获得&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;合理的分区：系统、数据分离，可以后期安装任意版本系统不影响数据&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;手动 SWAP：将会比你选择默认安装的方式快很多&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;稳定的 wifi 的新选择：探索新的方式解决 wifi 不稳定的问题&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;学会新的方式安装软件：除了 apt 还有更多选择&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;默认的多媒体将会工作：也许你一直奇怪为什么默认的视频无法工作。&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;开机莫名其妙的报错将会被修复：看不懂的报错也会被消灭。&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;一些 IDE 似乎不正常，帮你踩坑：帮助你恢复生产力&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="2. 设备参考"&gt;2. 设备参考&lt;/h2&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;参数表：
Intel® Core™ i5-2415M CPU @ 2.30GHz × 4 
3.8 GB 
Intel® HD Graphics 3000 (SNB GT2)
SSD:  Sandisk 240G
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;备注：我自己更换了一个 SSD, 机械硬盘在 swap 部分的提速效果会大大打折扣。&lt;/p&gt;
&lt;h2 id="3. 目标系统 Ubuntu20.10"&gt;3. 目标系统 Ubuntu20.10&lt;/h2&gt;
&lt;p&gt;我将会安装 &lt;a href="https://ubuntu.com/download/desktop" rel="nofollow" target="_blank" title=""&gt;Ubuntu 20.10&lt;/a&gt;。&lt;/p&gt;

&lt;p&gt;使用 Ubuntu 20.10 的原因是 他包含了 &lt;a href="https://discourse.ubuntu.com/t/groovy-gorilla-release-notes/15533" rel="nofollow" target="_blank" title=""&gt;相较于 Ubuntu20.04 诸多改进&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="二、安装"&gt;二、安装&lt;/h2&gt;&lt;h2 id="1. 制作启动盘"&gt;1. 制作启动盘&lt;/h2&gt;
&lt;p&gt;不多赘述 官方页面里面有不同系统下的 &lt;a href="https://ubuntu.com/download/desktop" rel="nofollow" target="_blank" title=""&gt;制作指导&lt;/a&gt;。&lt;/p&gt;
&lt;h2 id="2. 分区"&gt;2. 分区&lt;/h2&gt;
&lt;p&gt;Windows XP 的时代经常把硬盘分为若干个区，不过现在不论是 Windows10、MacOSX 都是一个分区了，原因就是现在的系统逐渐稳定了，并且他们也会存在一些云盘、NAS 等同步备份数据的外设。所以这部分逐渐不是问题了。&lt;/p&gt;

&lt;p&gt;系统和数据隔离还是有好处的，系统破坏了，不影响数据本身。&lt;/p&gt;
&lt;h3 id="2.1 优点："&gt;2.1 优点：&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;系统被破坏，数据不会被影响&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;可以任何时候安装新系统尝鲜，不会影响数据&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="2.2 缺点："&gt;2.2 缺点：&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;系统被局限在一个固定大小的分区里，太小会限制系统后期。&lt;/p&gt;

&lt;p&gt;不过这个无所谓，因为 Linux 的大小十分的有限。并且安装软件的方式可以灵活的选择 apt（这就是安装在系统分区）或者 snap、flatpak 他们都是在用户分区。所以这个缺点理论上不算个缺点。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;分区导致一部分内存浪费&lt;/p&gt;

&lt;p&gt;这个是事实。但是现在的硬盘也没那么窘迫。后面会建议给系统 50-64G 的空间。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="2.3 分区教程"&gt;2.3 分区教程&lt;/h3&gt;
&lt;p&gt;安装时候选择自定义分区。实际上我们只需要自定义三个分区，也就是删除硬盘空间，新建出三个。&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;/EFI &lt;/p&gt;

&lt;p&gt;新的电脑采用 UEFI 启动方式，必须设置一个 &lt;code&gt;/EFI&lt;/code&gt; 分区 建议分配大一点，256M 左右。&lt;/p&gt;

&lt;p&gt;Mac 采用的就是 UEFI 所以我们确保安装成功必须建立一个 &lt;code&gt;/EFI&lt;/code&gt; 分区。&lt;/p&gt;

&lt;p&gt;可以分配 256M 实际上可能占用就 33M 左右。多与的空间留给未来升级或者其他情况的缓冲。&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;参考&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;如果是 UEFI+GPT 分区表模式，那么给 ubuntu 分区的时候不用设置/boot 分区，设置 efi 系统分区；如果是 legacy+MBR 分区表那么就要设置/boot 分区。&lt;/p&gt;

&lt;p&gt;&lt;a href="https://blog.csdn.net/wangyuankl123/article/details/100532620" rel="nofollow" target="_blank" title=""&gt;Ubuntu 经验：设置 EFI 分区&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;会生成 &lt;code&gt;/dev/sda1&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="我们不会特别设置SWAP分区，虽然老的一些wiki里都会这里让你设置。没必要在这里设定死。"&gt;我们不会特别设置 SWAP 分区，虽然老的一些 wiki 里都会这里让你设置。没必要在这里设定死。&lt;/h4&gt;
&lt;p&gt;swap 分区可以没有，进入系统后，灵活的通过 swapfile 的方式加入 SWAP ,这里分配死不好变化了。&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;/ 根 分区，这里用来存放系统。&lt;/p&gt;

&lt;p&gt;目录建议 50～64G&lt;/p&gt;

&lt;p&gt;必须是 primary 分区类型。主分区（Primary）用来安装系统，并且个数有限制。&lt;/p&gt;

&lt;p&gt;精简系统安装在 9G 左右，全部安装大概在 17G，后期即使安装文件，也极其有限，64G 足够了。&lt;/p&gt;

&lt;p&gt;会生成 &lt;code&gt;/dev/sda2&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;/home 家目录，用户数据所在&lt;/p&gt;

&lt;p&gt;类型可以是 Primary 分区或者 Logic 分区，建议 Logic。&lt;/p&gt;

&lt;p&gt;剩余的内存全部分配给 &lt;code&gt;/home&lt;/code&gt; 分区&lt;/p&gt;

&lt;p&gt;会生成 &lt;code&gt;/dev/sda4&lt;/code&gt; (可能我编辑又删除了。应该是递增的。)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;booter 安装选择 /EFI 的分区 即 &lt;code&gt;/dev/sda1&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src="https://i.loli.net/2021/02/06/Dpu4L5IGNlH3gdt.jpg" title="" alt="IMG_20210204_175214.jpg"&gt;&lt;/p&gt;

&lt;p&gt;这样就可以正常安装了。&lt;/p&gt;
&lt;h2 id="3. 我想重装"&gt;3. 我想重装&lt;/h2&gt;
&lt;p&gt;按照 2 的分区方式。假设我因为更新内核系统崩溃了，或者想要换个发行版怎么办？&lt;/p&gt;

&lt;p&gt;没关系，最好保留一个 USB 的启动盘。插入电脑重新进入安装流程。在分区的环节，依然选择单独自己设置分区。&lt;/p&gt;

&lt;p&gt;你会看到电脑的分区表。和安装时候一样的分布。这里可以通过 &lt;code&gt;/dev/sda1&lt;/code&gt; 等标号对应起来，或者根据大小判断。&lt;/p&gt;

&lt;p&gt;需要做的就是把对应的分区设置，挂载。比如：单独对 &lt;code&gt;/EFI&lt;/code&gt;  &lt;code&gt;/&lt;/code&gt; 两个分区删除，并且 change 选择 format（其实就是格式化，会出现打钩）。&lt;/p&gt;
&lt;h3 id="注意"&gt;注意&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;/home&lt;/code&gt; 挂在上 &lt;code&gt;/home&lt;/code&gt; 分区，但是不要勾选 format，也就是不格式化。&lt;/p&gt;

&lt;p&gt;然后要注意的是，用户名 即 /home/  这里的 xxxx 要设置成一样的名字。&lt;/p&gt;

&lt;p&gt;重新安装完系统后，数据保持，系统更新了。&lt;/p&gt;
&lt;h2 id="三、配置"&gt;三、配置&lt;/h2&gt;&lt;h2 id="1. SWAP 分区"&gt;1. SWAP 分区&lt;/h2&gt;
&lt;p&gt;SWAP 分区是当年因为设备内存太小，分出一部分硬盘空间用来当内存以此来提高性能的技术。SSD 比机械硬盘快，所以这部分如果机器是 SSD，效果是更好一点。&lt;/p&gt;

&lt;p&gt;Ubuntu 安装系统默认的 Swap 分区是 2G，也就是内存的一半。&lt;/p&gt;

&lt;p&gt;网上总流传一个 swap 的配置：&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;如果内存很小 (&amp;lt;4GB)，设为内存大小

如果内存很大（&amp;gt;=4GB)，设置为内存的一半
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;实际上时过境迁了，现在随便浏览器开一个标签浏览一个视频网站，你的内存就快速增长。&lt;/p&gt;

&lt;p&gt;我这台设备是 4G 内存，日常使用的时候内存永远是满的状态，然后 SWAP 也会被塞满。这时候，我猜想 Linux 会花大量的时间在不断的 GC, 当你感觉到系统很卡，应该就是内存分配不过来了。&lt;/p&gt;

&lt;p&gt;而且 Linux 在内存分配产生边界的时候也会产生各种边界问题。&lt;/p&gt;

&lt;p&gt;这里建议&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;4G 内存，建议分配 8G SWAP

8G 内存，建议 8G SWAP

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;分配 SWAP 的方式参考 &lt;a href="https://linuxhint.com/change_swap_size_ubuntu/" rel="nofollow" target="_blank" title=""&gt;change_swap_size_ubuntu&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;简述步骤&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;step1 切换为 root 用户&lt;/p&gt;

&lt;p&gt;&lt;code&gt;sudo -s&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;step2 列出 可用的 SWAP&lt;/p&gt;

&lt;p&gt;&lt;code&gt;swapon -s&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src="https://linuxhint.com/wp-content/uploads/2018/11/2-39.png" title="" alt="展示可以用的SWAP"&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;step3 停用 SWAP&lt;/p&gt;

&lt;p&gt;&lt;code&gt;swapoff -a&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;step4 生成一个 8G 的文件 &lt;/p&gt;

&lt;p&gt;bs 就是一个单元，1M &lt;/p&gt;

&lt;p&gt;count 是 大小，实际大小是 &lt;code&gt;bs* count&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;所以我们需要 8G 是 &lt;code&gt;1M*1024 * 8 = 8192&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;所以应该输入命令&lt;/p&gt;

&lt;p&gt;&lt;code&gt;dd if=/dev/zero of=/swapfile bs=1M count=8192&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;step5 &lt;/p&gt;

&lt;p&gt;启用刚才的 swap&lt;/p&gt;

&lt;p&gt;&lt;code&gt;mkswap /swapfile&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;会生成一个随机 ID&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;step6 &lt;/p&gt;

&lt;p&gt;挂载 swap 分区&lt;/p&gt;

&lt;p&gt;&lt;code&gt;swapon /swapfile&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;step7 &lt;/p&gt;

&lt;p&gt;最好重启系统&lt;/p&gt;

&lt;p&gt;&lt;code&gt;sudo reboot&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;step8 &lt;/p&gt;

&lt;p&gt;重启系统可以查看&lt;/p&gt;

&lt;p&gt;&lt;code&gt;swapon -s&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;可以看到新的 8G Swap 已经在工作。&lt;/p&gt;

&lt;p&gt;或者通过图形软件：系统监视器&lt;/p&gt;

&lt;p&gt;里面可以看到 SWAP 交换区的工作状态&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="2. Xorg  VS  Wayland"&gt;2. Xorg  VS  Wayland&lt;/h2&gt;
&lt;p&gt;结论：&lt;/p&gt;

&lt;p&gt;1. Wayland 还有待成熟。&lt;/p&gt;

&lt;p&gt;2. 日常使用他们在表现上号无差别。虽然在原理上 wayland 应该更胜一筹，但是需要时间沉淀（已经快 10 年了）。&lt;/p&gt;

&lt;p&gt;3. Wayland 可以尝试，最后还需要 Xorg&lt;/p&gt;

&lt;p&gt;Wayland 的优点：&lt;/p&gt;

&lt;p&gt;1. 原理上，会比 Xorg 速度快，因为他简化了 X11 的模型&lt;/p&gt;

&lt;p&gt;2. 也会减少内存和 CPU&lt;/p&gt;

&lt;p&gt;Wayland 的缺点：&lt;/p&gt;

&lt;p&gt;兼容性：&lt;/p&gt;

&lt;p&gt;* 软件的兼容性不太好。而且在最重要的输入法会出现连击的 BUG，可以在系统设置--辅助里面，关闭掉连按按钮。但是不够好。&lt;/p&gt;

&lt;p&gt;* 录屏工具 obs-studio 在录制屏幕的时候，Wayland 下不工作，总是黑屏，因为 wayland 的 composite 缺乏一个输出图像的 api …… 总之吧，还缺失很多的细节。&lt;/p&gt;

&lt;p&gt;开发人员：&lt;/p&gt;

&lt;p&gt;* Wayland 的开发人员很少，obs-studio 这个 bug 上 Wayland 的解决也不够积极。这是 2018 年提出的问题，到现在也没解决。&lt;/p&gt;

&lt;p&gt;实际表现：&lt;/p&gt;

&lt;p&gt;* 看过游戏性/能，xorg 和 wayland 差不多。&lt;/p&gt;

&lt;p&gt;切换 Wayland 的方法&lt;/p&gt;

&lt;p&gt;. 注销系统，可以选择 wayland 登陆&lt;/p&gt;

&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/Mark24/2a9fcc19-b124-42bb-ab54-04d9e56c4541.jpg!large" title="" alt="change wayland"&gt;&lt;/p&gt;
&lt;h2 id="四、硬件与驱动"&gt;四、硬件与驱动&lt;/h2&gt;&lt;h2 id="1. Wifi"&gt;1. Wifi&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;关于主板自带 wifi Broadcom&lt;/p&gt;

&lt;p&gt;Broadcom 的无线网卡是很多主板上的选择，他虽然在 Ubuntu 上有闭源驱动，可是表现不尽人意。wifi 总是工作一段时间断掉，总让人有一种 Linux 很不稳定的感觉。我因为丢失 wifi 信号重启系统。&lt;/p&gt;

&lt;p&gt;尝试解决方案：&lt;/p&gt;

&lt;p&gt;1.把 wifi 芯片的节能模式设置为 off，永远不断开就可以工作。但是这需要芯片支持。结果不行。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;小米随身 wifi&lt;/p&gt;

&lt;p&gt;整理自己东西的时候，发现了 2016 年买的小米 wifi。长的就像一个小的无线鼠标接受器。随身 wifi 当年是台式机不支持 wifi，买一个这个插上去，PC 就可以支持 wifi 了。当年刚出来，驱动都需要额外安装。新东西往往 Linux 不支持。&lt;/p&gt;

&lt;p&gt;小米随身 wifi, 小度 wifi，360 随身 wifi，他们的方案都一样，都是基于 MTK7601U 这款芯片，对是联发科的。外国网友提交了补丁。现在 MTK7601U 这个驱动加入到内核里面了 —— 这玩意免驱的了。&lt;/p&gt;

&lt;p&gt;经过大概四五天的使用，不论是一天开机，隔夜开机，休眠，合盖子。wifi 工作都非常好，唤醒速度非常快，并且热插拔工作。当 wifi 的问题被解决后，系统的直观感受就是稳定多了，没那么多莫名其妙的信号突然丢失，网络突然减速。&lt;/p&gt;

&lt;p&gt;可以说远胜于自身主板的 wifi。信号都强 2 格。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;可以选择其他的随身 wifi&lt;/p&gt;

&lt;p&gt;淘宝上大概 20～30 不等，也有免驱动的兼容 linux 的，如果你手边有当年的随身 wifi 又可以使用了。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="2. 显卡"&gt;2. 显卡&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;这台机器没有独立显卡，这部分没有折腾记录 :D&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="五、软件使用"&gt;五、软件使用&lt;/h2&gt;&lt;h2 id="1. 安装软件的新选择"&gt;1. 安装软件的新选择&lt;/h2&gt;
&lt;p&gt;linux 的版本众多，ubuntu 这种 debian 系默认的使用是 apt 来安装软件，如果是 Redhat 系 比如 CentOS 需要用 yum 命令。并且两边的软件可能安装和工作的差距很大。&lt;/p&gt;

&lt;p&gt;于是出现了磨平兼容性的新的打包和安装方式。&lt;/p&gt;

&lt;p&gt;Ubuntu 阵营的 &lt;a href="https://snapcraft.io/" rel="nofollow" target="_blank" title=""&gt;snap&lt;/a&gt;，如果你安装&amp;gt;=20.04，已经自带了。或者是 RedHat 阵营的 &lt;a href="https://flathub.org" rel="nofollow" target="_blank" title=""&gt;flatpak&lt;/a&gt;。&lt;/p&gt;

&lt;p&gt;他们原理都差不多，类似 docker 这种，提供了虚拟环境，并且是分层构建的。&lt;/p&gt;

&lt;p&gt;Ubuntu 也可以安装&lt;a href="https://flatpak.org/setup/" rel="nofollow" target="_blank" title=""&gt;flatpak&lt;/a&gt;。&lt;/p&gt;
&lt;h3 id="1.1 Snap"&gt;1.1 Snap&lt;/h3&gt;
&lt;p&gt;一但用过 snap 估计就会喜欢上了它。网络好的时候速度非常快。感觉 snap 的基础设施起来了，flatpak 依然很慢。&lt;/p&gt;

&lt;p&gt;snap 会自动保持软件到最新。&lt;/p&gt;

&lt;p&gt;你只需要把 apt 替换成 snap 就好了。&lt;/p&gt;

&lt;p&gt;在 &lt;a href="https://snapcraft.io/" rel="nofollow" target="_blank" title=""&gt;https://snapcraft.io/&lt;/a&gt; 上浏览软件比自带的那个应用商店（做的的是垃圾）好多了。&lt;/p&gt;
&lt;h2 id="2. 默认播放器缺乏编码器"&gt;2. 默认播放器缺乏编码器&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;step1 勾选 multiverse 源&lt;/p&gt;

&lt;p&gt;打开“软件和更新（Software &amp;amp; Updates）”Ubuntu 软件的 tab 下，勾选“有版权和合法性问题的软件（multiverse）”&lt;/p&gt;

&lt;p&gt;然后关闭之后借助图形窗口更新源。或者取消自己去终端手动更新 &lt;code&gt;sudo apt update&lt;/code&gt; 。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;step2 安装额外包&lt;/p&gt;

&lt;p&gt;&lt;code&gt;sudo apt install ubuntu-restricted-extras&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;安装过程中需要输入 两个 Y 确认阅读了一些法律然后继续。&lt;/p&gt;

&lt;p&gt;安装完毕后即可正常使用默认播放器&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;参考&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=LW8F97qQzVE" rel="nofollow" target="_blank" title=""&gt;Fix Ubuntu Can't Play Video (MP4, MKV, Etc) Files&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Plan B&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;如果你觉得麻烦，可以直接使用  vlc 它自带了编码器。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="梯子"&gt;梯子&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://snapcraft.io/qv2ray" rel="nofollow" target="_blank" title=""&gt;qv2ray&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;sudo snap install qv2ray&lt;/code&gt;&lt;/p&gt;
&lt;h2 id="Vscode"&gt;Vscode&lt;/h2&gt;
&lt;p&gt;snap 安装的会出现 ibus 中文无法输入的情况。这是 Vscode 的 BUG 不过最近还没被修复。&lt;/p&gt;

&lt;p&gt;官网下在 deb 是解决方案。&lt;/p&gt;
&lt;h3 id="deb可能遇到的问题"&gt;deb 可能遇到的问题&lt;/h3&gt;
&lt;p&gt;deb 安装的报错&lt;/p&gt;

&lt;p&gt;解决方法见： &lt;a href="https://blog.csdn.net/u012057432/article/details/112849575" rel="nofollow" target="_blank" title=""&gt;N: 鉴于仓库...不支持‘armhf‘体系结构，跳过配置文件 ...的获取&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="Sublime Text"&gt;Sublime Text&lt;/h2&gt;
&lt;p&gt;在 18.04 的时候，sublime 无法中文输入。&lt;/p&gt;

&lt;p&gt;现在不论是 deb、snap、flatpak 都是可以工作的。&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;自带启动命令  subl&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;code&gt;subl .&lt;/code&gt; 打开目录类似于 vscode 的 &lt;code&gt;code .&lt;/code&gt;&lt;/p&gt;
&lt;h2 id="JetBrain  IDE"&gt;JetBrain  IDE&lt;/h2&gt;
&lt;p&gt;推荐 snap 安装，整个过程无痛，中文输入没有问题。&lt;/p&gt;
&lt;h2 id="六、其他情况"&gt;六、其他情况&lt;/h2&gt;&lt;h2 id="1. 开机出问题Failed to set MockListRT……报错"&gt;1. 开机出问题 Failed to set MockListRT……报错&lt;/h2&gt;
&lt;p&gt;解决方法&lt;/p&gt;

&lt;p&gt;你必须用 grubx64.efi  替换 shimx64.efi&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo su -
cd /boot/efi/EFI/ubuntu
cp grubx64.efi shimx64.efi
reboot

&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="七"&gt;七&lt;/h2&gt;
&lt;p&gt;踩坑还在继续……&lt;/p&gt;

&lt;p&gt;逐渐补充&lt;/p&gt;

&lt;p&gt;Ruby China 讨论 &lt;a href="https://ruby-china.org/topics/40896" rel="nofollow" target="_blank"&gt;https://ruby-china.org/topics/40896&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;V2EX 讨论 &lt;a href="https://www.v2ex.com/t/751846" rel="nofollow" target="_blank"&gt;https://www.v2ex.com/t/751846&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;我的博客  &lt;a href="https://mark24code.github.io/ubuntu/linux/%E6%95%99%E7%A8%8B/2021/02/06/2021%E5%B9%B4%E7%BB%99%E4%BD%A0%E7%9A%84MacbookPro%E5%AE%89%E8%A3%85Ubuntu%E8%B8%A9%E5%9D%91%E8%AE%B0%E5%BD%95.html" rel="nofollow" target="_blank"&gt;https://mark24code.github.io/ubuntu/linux/%E6%95%99%E7%A8%8B/2021/02/06/2021%E5%B9%B4%E7%BB%99%E4%BD%A0%E7%9A%84MacbookPro%E5%AE%89%E8%A3%85Ubuntu%E8%B8%A9%E5%9D%91%E8%AE%B0%E5%BD%95.html&lt;/a&gt;&lt;/p&gt;</description>
      <author>Mark24</author>
      <pubDate>Sat, 06 Feb 2021 15:49:29 +0800</pubDate>
      <link>https://ruby-china.org/topics/40896</link>
      <guid>https://ruby-china.org/topics/40896</guid>
    </item>
  </channel>
</rss>
