Robert的博客
https://robberphex.com/icon.png
2024-03-17T08:36:27.000Z
https://robberphex.com/
Robert Lu
Hexo
谈谈Java Volatile的设计
https://robberphex.com/about-java-volatile/
2024-03-17T08:36:27.000Z
2024-03-17T08:36:27.000Z
<h2 id="java-volatile为什么要这么设计?"><a href="#java-volatile为什么要这么设计?" class="headerlink" title="java volatile为什么要这么设计?"></a>java volatile为什么要这么设计?</h2><p>最近在知乎上看见一个有意思的问题:</p>
<blockquote>
<p><strong><a href="https://www.zhihu.com/question/648886114">java volatile为什么要这么设计?</a></strong><br>如图所示,这种指令重排规则背后设计的是出于什么原因考虑?我想知道why? 而不是What/How<br><img src="/./about-java-volatile/java-volatile.png"></p>
</blockquote>
<p>这个问题看似简单,但是后面其实隐藏着计算机架构的演变:</p>
<h2 id="CPU的多核心时代"><a href="#CPU的多核心时代" class="headerlink" title="CPU的多核心时代"></a>CPU的多核心时代</h2><p>说到这儿,就要开始聊一下多线程/多处理器的发展史了。初期计算机性能的提升,主要靠的是主频的提升,后来主频提升遇到了困难,然后就开始了多核处理器的时代。</p>
<p>这里面有一个问题,一个程序可不是天然就能同时跑在多个CPU核心上的,如何让程序员利用多核心处理器提升效率,是一个难题。</p>
<p>这个问题乍一看很简单,我们已经有了线程模型了,直接套用到多核架构上不就可以了么?</p>
<p>但是不行,在原来的单核心架构中,我们的内存模型是 <a href="https://www.cnblogs.com/jiayy/p/3246157.html">顺序一致性(Sequential consistency)</a>:</p>
<ol>
<li>每个线程内部的指令都是按照程序规定的顺序(program order)执行的(单个线程的视角)</li>
<li>线程执行的交错顺序可以是任意的,但是所有线程所看见的整个程序的总体执行顺序都是一样的(整个程序的视角)</li>
</ol>
听说你没法在JRE中使用arthas?不,你可以
https://robberphex.com/attach-arthas-on-jre/
2022-12-06T15:39:19.000Z
2022-12-06T15:39:19.000Z
<p><em>本文是《容器中的Java》系列文章之 5/n ,欢迎关注后续连载 :) 。</em></p>
<ul>
<li><a href="/java-and-docker-memory-and-cpu-limits/" title="JVM如何获取当前容器的资源限制">JVM如何获取当前容器的资源限制?——容器中的Java 1</a></li>
<li><a href="/java-agent-issue-of-append-to-system-class-loader-search/" title="Java Agent踩坑之appendToSystemClassLoaderSearch问题">Java Agent踩坑之appendToSystemClassLoaderSearch问题——容器中的Java 2</a></li>
<li><a href="/java-agent-is-getting-better-at-dragonwell/" title="让 Java Agent 在 Dragonwell 上更好用">让 Java Agent 在 Dragonwell 上更好用——容器中的Java 3</a></li>
<li><a href="/attach-jvm-in-container-at-arthas/" title="为什么在容器挂不上arthas?">为什么在容器中1号进程挂不上arthas?——容器中的Java 4</a></li>
</ul>
<p>之前经常遇到的问题是,排查问题需要挂arthas,但客户用的是JRE,没法挂载arthas。就只能让客户更换成JDK,再重新部署、排查问题。</p>
<p>很多有用的现场,在这个过程中也会丢失,最终导致问题排查效率降低。于是就探索了下如何在JRE环境中,使用artahs。</p>
<h2 id="复现问题"><a href="#复现问题" class="headerlink" title="复现问题"></a>复现问题</h2><p><em>如果一个Bug 没法复现,研发大概率是无法修复的。 —— by 网友</em></p>
<p>我们写一个Java例子和Dockerfile:</p>
<figure class="highlight java"><figcaption><span>./src/main/java/Main.java</span></figcaption><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Main</span> {</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> Exception {</span><br><span class="line"> <span class="keyword">while</span> (<span class="literal">true</span>) {</span><br><span class="line"> System.out.println(<span class="string">"hello!"</span>);</span><br><span class="line"> Thread.sleep(<span class="number">30</span> * <span class="number">1000</span>);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<figure class="highlight dockerfile"><figcaption><span>./Dockerfile</span></figcaption><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">FROM</span> openjdk:<span class="number">8</span>-jdk-alpine as builder</span><br><span class="line"><span class="keyword">COPY</span><span class="language-bash"> ./ /app</span></span><br><span class="line"><span class="keyword">WORKDIR</span><span class="language-bash"> /app/src/main/java/</span></span><br><span class="line"><span class="comment"># 编译java文件</span></span><br><span class="line"><span class="keyword">RUN</span><span class="language-bash"> javac Main.java</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 运行时容器使用JRE</span></span><br><span class="line"><span class="keyword">FROM</span> openjdk:<span class="number">8</span>-jre-alpine</span><br><span class="line"><span class="keyword">RUN</span><span class="language-bash"> apk add bash curl busybox-extras</span></span><br><span class="line"><span class="keyword">WORKDIR</span><span class="language-bash"> /app/src/main/java/</span></span><br><span class="line"><span class="comment"># 将arthas copy 到容器中</span></span><br><span class="line"><span class="keyword">COPY</span><span class="language-bash"> --from=hengyunabc/arthas:latest /opt/arthas /opt/arthas</span></span><br><span class="line"><span class="keyword">COPY</span><span class="language-bash"> --from=builder /app/src/main/java/ /app/src/main/java/</span></span><br><span class="line"><span class="keyword">CMD</span><span class="language-bash"> [<span class="string">"java"</span>, <span class="string">"Main"</span>]</span></span><br></pre></td></tr></table></figure>
<p>构建并正常启动应用,并尝试用arthas attach,此处为了便于了解原理,我们使用as.sh来执行:</p>
为什么在容器中1号进程挂不上arthas?
https://robberphex.com/attach-jvm-in-container-at-arthas/
2022-12-03T15:55:55.000Z
2022-12-03T15:55:55.000Z
<p><em>本文是《容器中的Java》系列文章之 4/n ,欢迎关注后续连载 :) 。</em></p>
<ul>
<li><a href="/java-and-docker-memory-and-cpu-limits/" title="JVM如何获取当前容器的资源限制">JVM如何获取当前容器的资源限制?——容器中的Java 1</a></li>
<li><a href="/java-agent-issue-of-append-to-system-class-loader-search/" title="Java Agent踩坑之appendToSystemClassLoaderSearch问题">Java Agent踩坑之appendToSystemClassLoaderSearch问题——容器中的Java 2</a></li>
<li><a href="/java-agent-is-getting-better-at-dragonwell/" title="让 Java Agent 在 Dragonwell 上更好用">让 Java Agent 在 Dragonwell 上更好用——容器中的Java 3</a></li>
</ul>
<p>最近在容器环境中,发现在Java进程是1号进程的情况下,无法使用arthas,提示<code>AttachNotSupportedException: Unable to get pid of LinuxThreads manager thread</code>。具体操作和报错如下:</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta prompt_"># </span><span class="language-bash">java -jar arthas-boot.jar</span></span><br><span class="line">[INFO] arthas-boot version: 3.5.6</span><br><span class="line">[INFO] Found existing java process, please choose one and input the serial number of the process, eg : 1. Then hit ENTER.</span><br><span class="line">* [1]: 1 com.alibabacloud.mse.demo.ZuulApplication</span><br><span class="line">1</span><br><span class="line">[INFO] arthas home: /home/admin/.opt/ArmsAgent/arthas</span><br><span class="line">[INFO] Try to attach process 1</span><br><span class="line">[ERROR] Start arthas failed, exception stack trace:</span><br><span class="line">com.sun.tools.attach.AttachNotSupportedException: Unable to get pid of LinuxThreads manager thread</span><br><span class="line"> at sun.tools.attach.LinuxVirtualMachine.<init>(LinuxVirtualMachine.java:86)</span><br><span class="line"> at sun.tools.attach.LinuxAttachProvider.attachVirtualMachine(LinuxAttachProvider.java:78)</span><br><span class="line"> at com.sun.tools.attach.VirtualMachine.attach(VirtualMachine.java:250)</span><br><span class="line"> at com.taobao.arthas.core.Arthas.attachAgent(Arthas.java:117)</span><br><span class="line"> at com.taobao.arthas.core.Arthas.<init>(Arthas.java:27)</span><br><span class="line"> at com.taobao.arthas.core.Arthas.main(Arthas.java:166)</span><br><span class="line">[INFO] Attach process 1 success.</span><br></pre></td></tr></table></figure>
<p>之前也遇到过,总是调整了下镜像,让Java进程不是1号进程就可以了。但这个不是长久之计,还是要抽时间看下这个问题。</p>
<h2 id="复现问题"><a href="#复现问题" class="headerlink" title="复现问题"></a>复现问题</h2><p>我们创建如下项目,来复现这个问题:</p>
<figure class="highlight java"><figcaption><span>./src/main/java/Main.java</span></figcaption><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Main</span> {</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> Exception {</span><br><span class="line"> <span class="keyword">while</span> (<span class="literal">true</span>) {</span><br><span class="line"> System.out.println(<span class="string">"hello!"</span>);</span><br><span class="line"> Thread.sleep(<span class="number">30</span> * <span class="number">1000</span>);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<figure class="highlight dockerfile"><figcaption><span>./Dockerfile</span></figcaption><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">FROM</span> openjdk:<span class="number">8</span>u212-jdk-alpine</span><br><span class="line"><span class="keyword">COPY</span><span class="language-bash"> ./ /app</span></span><br><span class="line"><span class="keyword">WORKDIR</span><span class="language-bash"> /app/src/main/java/</span></span><br><span class="line"><span class="keyword">RUN</span><span class="language-bash"> javac Main.java</span></span><br><span class="line"><span class="keyword">CMD</span><span class="language-bash"> [<span class="string">"java"</span>, <span class="string">"Main"</span>]</span></span><br></pre></td></tr></table></figure>
<p>然后正常启动应用,并尝试用arthas,或者jstack:</p>
Z-Library挂了?怎么办?
https://robberphex.com/z-library-alternatives/
2022-11-05T17:35:32.000Z
2022-11-05T17:35:32.000Z
<h2 id="Z-Library"><a href="#Z-Library" class="headerlink" title="Z-Library"></a>Z-Library</h2><p>Z-Library 是一个免费下载电子书的网站。不过最近由于Z-Library的域名被查封,所以现在没法访问了。</p>
<p>Z-Library 刚开始的时候是 LibGen 的镜像站点,正因如此,Z-Library 上的大部分图书,都能在 LibGen找到;但有一些书是用户自己上传到 Z-Library 的,所以就没法在 LibGen 找到了。</p>
<p>这种情况,一般可以在维基百科上找下官方信息,就能发现 Z-Library 还提供了一个 onion 域名可以访问。</p>
<p>所以,我们可以下载一个 Tor 浏览器,或者 Brave 浏览器,然后访问 <a href="http://zlibrary24tuxziyiyfr7zd46ytefdqbqd2axkmxm4o5374ptpc52fad.onion/">http://zlibrary24tuxziyiyfr7zd46ytefdqbqd2axkmxm4o5374ptpc52fad.onion</a> 来继续访问了:</p>
<p><img src="/./z-library-alternatives/zlibrary-onion.jpeg"></p>
<p><em>当然, Tor 网络虽然链路是分布式的,但是其中的 server 却是集中式的,个人觉得不算是“分布式Web”</em></p>
<ul>
<li>网上也会有一些 Z-Library 镜像,也可以搜索下使用,比如 <a href="https://zlib.wiki/">zlib.wiki</a>、<a href="https://zlib.quest/">zlib.quest</a>等。</li>
</ul>
<h3 id="Z-Library-存档"><a href="#Z-Library-存档" class="headerlink" title="Z-Library 存档"></a>Z-Library 存档</h3><p>当然,这种网站一般也会有人收集离线存档,可以在 <a href="http://pilimi.org/">pilimi.org</a> 找到 Z-Library 存档。</p>
如何使用rust写内核模块
https://robberphex.com/write-kernel-module-with-rust/
2022-11-02T16:17:19.000Z
2022-11-02T16:17:19.000Z
<p><em>近年来,Rust语言以内存安全、高可靠性、零抽象等能力获得大量开发者关注,而这些特性恰好是内核编程中所需要的,所以我们来尝试下如何用rust来写Linux内核模块。</em></p>
<h2 id="Rust与内核模块"><a href="#Rust与内核模块" class="headerlink" title="Rust与内核模块"></a>Rust与内核模块</h2><p>虽然Rust支持已经在Linux Kernel 6.1版本合并到主线了,所以理论上来说,开发者可以使用Rust来为Linux 6.1写内核模块。<br>但实际开发工作中,内核版本不是最新的,比如Debian 11的内核就是5.10版本的,那么在这种情况下,该如何用Rust写内核模块呢?</p>
<h2 id="原理"><a href="#原理" class="headerlink" title="原理"></a>原理</h2><ol>
<li>Rust如何向内核注册回调、如何调用内核代码。Rust和C的互操作性</li>
<li>Rust如何编译到目标平台上。Rust的target配置</li>
<li>Rust如何申明内核模块入口、并添加特殊section。Rust内核模块的二进制约定</li>
</ol>
<h3 id="Rust和C的互操作性"><a href="#Rust和C的互操作性" class="headerlink" title="Rust和C的互操作性"></a>Rust和C的互操作性</h3><p>第一个问题基本上就是C和Rust的互操作性了。<br>得益于Rust的抽象层次,C语言和Rust的互相调用都是比较容易的。rust官方也提供了bindgen这样,根据.h文件生成.rs文件的库。<br>这样一来,貌似直接使用bindgen将内核头文件翻译成.rs就可以了?<br>但还有一个问题,如何获取内核头文件路径呢?<br>可以使用一个dummy内核模块,在编译过程中把编译参数导出来,其中包含了头文件路径,编译参数等,用于bindgen生成代码。</p>
<h3 id="Rust的target配置"><a href="#Rust的target配置" class="headerlink" title="Rust的target配置"></a>Rust的target配置</h3><p>内核模块和普通的程序相比,主要的不同在于:</p>
<ol>
<li>内核模块是freestanding的,没有libc、内存分配也比较原始</li>
<li>内核模块对于异常处理等有特殊约定</li>
</ol>
如果java虚拟线程稳定了,是不是有一大批框架和工具要重写?
https://robberphex.com/will-virtual-thread-make-us-rewrite-java-code/
2022-11-02T15:16:40.000Z
2022-11-02T15:16:40.000Z
<p><em>知乎上有一个提问,“如果java虚拟线程稳定了,是不是有一大批框架和工具要重写?”,我整理了下我的知乎回答:</em></p>
<p>首先,抛开虚拟线程、协程,我们看看现在的架构。</p>
<p>在顶层,开辟出很多调度单位(线程、协程);在底层,有很多的IO原语(accept、read、write);在中间,有很多的组织逻辑。</p>
<p>协程主要做的就是,在底层执行IO原语的时候,暂时保存上下文,等执行结束后,再恢复上下文继续执行。</p>
<p>那么在现有的协程实现方案上,就出现了两种模式:</p>
<p><strong>有栈协程</strong>,就是协程上下文包括了callstack,当IO完成、恢复上下的时候,连带着callstack恢复。那么对于callstack中的各个caller(调用者)和callee(被调用者),都感知不到整个协程的调用过程,自然代码就不用修改了。</p>
<p>有栈协程的优点就是不需要现有的代码改动太多,只需要调度单位创建+调度器+IO操作方面改动即可。但开发者的把控就比较弱,不能干涉调度过程。</p>
<p>Go和Java的Loom,都是有栈协程。</p>
<p><strong>无栈协程</strong>,就是协程上下问不包含callstack,恢复上下文的时候,也只是通知上下文完成了。接下来干什么事情,还是得重新构建callstack。</p>
<p>比如 A -> B -> C -> IO函数,当出现IO调用,需要保留上下文,那么就需要C->B->A逐个返回上下文,恢复的时候也是 A -> B ->C去恢复执行。</p>
让 Java Agent 在 Dragonwell 上更好用
https://robberphex.com/java-agent-is-getting-better-at-dragonwell/
2022-09-26T01:45:36.000Z
2022-09-26T01:45:36.000Z
<p><em>本文是《容器中的Java》系列文章之 3/n ,欢迎关注后续连载 :) 。</em></p>
<h1 id="背景"><a href="#背景" class="headerlink" title="背景"></a>背景</h1><p>Java Agent 技术能够动态修改 Java 应用程序行为,而不用重新修改代码。</p>
<p>正是因为这些特点,很多中间件团队、云厂商团队、开源产品,开始使用 Java Agent 技术来提供一些基础能力,比如 Apache Skywalking、OpenTelemetry 都提供了 Java Agent。</p>
<p>在早前,中间件团队通过SDK提供能力(比如可观测、微服务治理能力等);但中间件团队每次新增特性、修复缺陷,都需要各个业务方更新SDK版本、重新发布。</p>
<p>随着公司架构越来越复杂,随着云厂商开始提供中间件能力,这种逐个推动SDK使用方更新的方式越来越麻烦。</p>
<p>而用了 Java Agent 之后,业务同学只需要写业务代码;中间件能力通过设置环境变量来动态注入Java Agent来实现。Java Agent的更新,也只需要重启应用即可。</p>
<h1 id="问题"><a href="#问题" class="headerlink" title="问题"></a>问题</h1><p>我们以一个<a href="https://github.com/aliyun/alibabacloud-microservice-demo/tree/master/mse-simple-demo/helm/mse-simple-demo">微服务demo</a>为例。先在一个Kubernetes集群中部署demo,然后通过<code>JAVA_TOOL_OPTIONS</code>使用用Java Agent:</p>
<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">$ <span class="built_in">echo</span> <span class="variable">$JAVA_TOOL_OPTIONS</span></span><br><span class="line">-javaagent:/home/admin/.opt/ArmsAgent/arms-bootstrap-1.7.0-SNAPSHOT.jar ...</span><br></pre></td></tr></table></figure>
LeetCode 周赛 311
https://robberphex.com/leetcode-weekly-contest-311/
2022-09-18T14:18:14.000Z
2022-09-18T14:18:14.000Z
<h2 id="第一题-2413-Smallest-Even-Multiple"><a href="#第一题-2413-Smallest-Even-Multiple" class="headerlink" title="第一题 2413. Smallest Even Multiple"></a>第一题 2413. Smallest Even Multiple</h2><blockquote>
<p>给你一个正整数 n ,返回 2 和 n 的最小公倍数(正整数)。 </p>
</blockquote>
<p>显而易见的:</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">smallestEvenMultiple</span><span class="params">(n <span class="type">int</span>)</span></span> <span class="type">int</span> {</span><br><span class="line"> <span class="keyword">if</span> n%<span class="number">2</span>==<span class="number">1</span>{</span><br><span class="line"> <span class="keyword">return</span> n*<span class="number">2</span></span><br><span class="line"> }<span class="keyword">else</span>{</span><br><span class="line"> <span class="keyword">return</span> n</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h2 id="第二题-2414-Length-of-the-Longest-Alphabetical-Continuous-Substring"><a href="#第二题-2414-Length-of-the-Longest-Alphabetical-Continuous-Substring" class="headerlink" title="第二题 2414. Length of the Longest Alphabetical Continuous Substring"></a>第二题 2414. Length of the Longest Alphabetical Continuous Substring</h2><p><img src="/./leetcode-weekly-contest-311/leetcode-6181-description.png"></p>
<p>最近恰好做过dp的题目,所以立马dp:</p>
<ul>
<li>状态定义为 下标i -> 以i结尾的string中,字母序连续的字符串最大长度</li>
<li>状态转移 s[i]和s[i-1]连续,那么在前面基础上+1,如果不连续,则置为1</li>
</ul>
<p>最后,遍历i,拿最大长度即可。</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">longestContinuousSubstring</span><span class="params">(s <span class="type">string</span>)</span></span> <span class="type">int</span> {</span><br><span class="line"> dp := <span class="built_in">make</span>([]<span class="type">int</span>, <span class="built_in">len</span>(s))</span><br><span class="line"> dp[<span class="number">0</span>] = <span class="number">1</span></span><br><span class="line"> <span class="keyword">for</span> i := <span class="number">1</span>; i < <span class="built_in">len</span>(s); i++ {</span><br><span class="line"> <span class="keyword">if</span> s[i] == s[i<span class="number">-1</span>]+<span class="number">1</span> {</span><br><span class="line"> dp[i] = dp[i<span class="number">-1</span>] + <span class="number">1</span></span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> dp[i] = <span class="number">1</span></span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> res := <span class="number">1</span></span><br><span class="line"> <span class="keyword">for</span> i := <span class="number">0</span>; i < <span class="built_in">len</span>(dp); i++ {</span><br><span class="line"> <span class="keyword">if</span> res < dp[i] {</span><br><span class="line"> res = dp[i]</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> res</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
Java Agent踩坑之appendToSystemClassLoaderSearch问题
https://robberphex.com/java-agent-issue-of-append-to-system-class-loader-search/
2022-06-20T06:31:23.000Z
2022-06-20T06:31:23.000Z
<p><em>本文是《容器中的Java》系列文章之 2/n ,欢迎关注后续连载 :) 。</em></p>
<p><em>从Java Agent报错开始,到JVM原理,到glibc线程安全,再到pthread tls,逐步探究Java Agent诡异报错。</em></p>
<h1 id="背景"><a href="#背景" class="headerlink" title="背景"></a>背景</h1><p>由于阿里云多个产品都提供了Java Agent给用户使用,在多个Java Agent一起使用的场景下,造成了总体Java Agent耗时增加,各个Agent各自存储,导致内存占用、资源消耗增加。</p>
<p>所以我们发起了one-java-agent项目,能够协同各个Java Agent;同时也支持更加高效、方便的字节码注入。</p>
<p>其中,各个Java Agent作为one-java-agent的plugin,在premain阶段是通过多线程启动的方式来加载,从而将启动速度由O(n)降低到O(1),降低了整体Java Agent整体的加载时间。</p>
<h1 id="问题"><a href="#问题" class="headerlink" title="问题"></a>问题</h1><p>但最近在新版Agent验证过程中,one-java-agent的premain阶段,发现有如下报错:</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line">2022-06-16 09:51:09 [oneagent plugin a-java-agent start] ERROR c.a.o.plugin.PluginManagerImpl -start plugin error, name: a-java-agent</span><br><span class="line">com.alibaba.oneagent.plugin.PluginException: start error, agent jar::/path/to/one-java-agent/plugins/a-java-agent/a-java-agent-1.7.0-SNAPSHOT.jar</span><br><span class="line"> at com.alibaba.oneagent.plugin.TraditionalPlugin.start(TraditionalPlugin.java:113)</span><br><span class="line"> at com.alibaba.oneagent.plugin.PluginManagerImpl.startOnePlugin(PluginManagerImpl.java:294)</span><br><span class="line"> at com.alibaba.oneagent.plugin.PluginManagerImpl.access$200(PluginManagerImpl.java:22)</span><br><span class="line"> at com.alibaba.oneagent.plugin.PluginManagerImpl$2.run(PluginManagerImpl.java:325)</span><br><span class="line"> at java.lang.Thread.run(Thread.java:750)</span><br><span class="line">Caused by: java.lang.InternalError: null</span><br><span class="line"> at sun.instrument.InstrumentationImpl.appendToClassLoaderSearch0(Native Method)</span><br><span class="line"> at sun.instrument.InstrumentationImpl.appendToSystemClassLoaderSearch(InstrumentationImpl.java:200)</span><br><span class="line"> at com.alibaba.oneagent.plugin.TraditionalPlugin.start(TraditionalPlugin.java:100)</span><br><span class="line"> ... 4 common frames omitted</span><br><span class="line">2022-06-16 09:51:09 [oneagent plugin b-java-agent start] ERROR c.a.o.plugin.PluginManagerImpl -start plugin error, name: b-java-agent</span><br><span class="line">com.alibaba.oneagent.plugin.PluginException: start error, agent jar::/path/to/one-java-agent/plugins/b-java-agent/b-java-agent.jar</span><br><span class="line"> at com.alibaba.oneagent.plugin.TraditionalPlugin.start(TraditionalPlugin.java:113)</span><br><span class="line"> at com.alibaba.oneagent.plugin.PluginManagerImpl.startOnePlugin(PluginManagerImpl.java:294)</span><br><span class="line"> at com.alibaba.oneagent.plugin.PluginManagerImpl.access$200(PluginManagerImpl.java:22)</span><br><span class="line"> at com.alibaba.oneagent.plugin.PluginManagerImpl$2.run(PluginManagerImpl.java:325)</span><br><span class="line"> at java.lang.Thread.run(Thread.java:855)</span><br><span class="line">Caused by: java.lang.IllegalArgumentException: null</span><br><span class="line"> at sun.instrument.InstrumentationImpl.appendToClassLoaderSearch0(Native Method)</span><br><span class="line"> at sun.instrument.InstrumentationImpl.appendToSystemClassLoaderSearch(InstrumentationImpl.java:200)</span><br><span class="line"> at com.alibaba.oneagent.plugin.TraditionalPlugin.start(TraditionalPlugin.java:100)</span><br><span class="line"> ... 4 common frames omitted</span><br></pre></td></tr></table></figure>
<p>熟悉Java Agent的同学可能能注意到,这是调用<code>Instrumentation.appendToSystemClassLoaderSearch</code>报错了。</p>
kill-port 清理占用端口的进程
https://robberphex.com/kill-port/
2022-05-06T11:58:27.000Z
2022-05-06T11:58:27.000Z
<h2 id="背景"><a href="#背景" class="headerlink" title="背景"></a>背景</h2><p>在日常开发中,经常出现端口莫名被占用的情况。比如要启动一个java服务,报错8080端口被占用,这时候就想着快速清理掉占用该端口的进程。</p>
<p>在Linux下,我们可以用熟悉的<code>ss</code>命令来找出进程并删除,但是macOS下,netstat我用的比较少,而且速度也很慢。</p>
<p>最近正好在学习Rust,所以就用Rust来写一个kill-port小工具,也算是入门系统编程了吧。</p>
<h2 id="安装"><a href="#安装" class="headerlink" title="安装"></a>安装</h2><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">$ git <span class="built_in">clone</span> https://github.com/robberphex/kill-port.git</span><br><span class="line">$ cargo build --release</span><br><span class="line"><span class="comment"># 将 ./target/release/kill-port 添加到PATH路径中。</span></span><br></pre></td></tr></table></figure>
<h2 id="使用方法"><a href="#使用方法" class="headerlink" title="使用方法"></a>使用方法</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">kill-port 0.1.0</span><br><span class="line"></span><br><span class="line">USAGE:</span><br><span class="line"> kill-port [PORT]...</span><br><span class="line"></span><br><span class="line">ARGS:</span><br><span class="line"> <PORT>... ports to find</span><br></pre></td></tr></table></figure>
<p>例子:</p>
<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># kill掉占用8080端口的进程</span></span><br><span class="line">$ kill-port 8080</span><br></pre></td></tr></table></figure>
用 Pygments 在 Word 中实现代码高亮
https://robberphex.com/copy-from-pygments-paste-to-word/
2021-12-13T05:05:31.000Z
2022-05-03T12:57:39.000Z
<p>虽然日常都是在写代码,但有的时候,还是需要写一些Word文档。这时候在Word文档中贴代码的时候,就希望能够做到代码高亮。</p>
<p>可以看一下rtf formatter的说明<code>pygmentize -H formatter rtf</code>:</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">Format tokens as RTF markup. This formatter automatically outputs full RTF</span><br><span class="line">documents with color information and other useful stuff. Perfect for Copy and</span><br><span class="line">Paste into Microsoft(R) Word(R) documents.</span><br><span class="line"></span><br><span class="line">Please note that ``encoding`` and ``outencoding`` options are ignored.</span><br><span class="line">The RTF format is ASCII natively, but handles unicode characters correctly</span><br><span class="line">thanks to escape sequences.</span><br></pre></td></tr></table></figure>
<p>可以看到,复制出来的是RTF格式的,能够复制、粘贴到Word文档中,并带上语法高亮等特性。</p>
<p>使用时只需要执行如下命令,</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">pygmentize ~/tmp/a-pod.yaml -f rtf | pbcopy</span><br></pre></td></tr></table></figure>
<p>然后在Word等支持RTF格式的软件中粘贴即可。</p>
Spring Native 0.11发布,带来新的AOT引擎和性能优化
https://robberphex.com/new-aot-engine-brings-spring-native-to-the-next-level/
2021-12-12T11:21:17.000Z
2021-12-12T11:21:17.000Z
<p><a href="https://github.com/spring-projects-experimental/spring-native/releases/tag/0.11.0">Spring Native 0.11</a>已于2021年12月9日发布。</p>
<p>这个宏大的版本是Spring团队五个月辛勤工作的结果,他们一直在研究一个全新的架构,将让Spring使用GraalVM创建原生可执行文件的方式提升到一个新的水平。你目前已经可以已经在<a href="https://start.spring.io/#!dependencies=native">start.spring.io</a>上试用了!</p>
<p>想了解有关Spring Native 0.11的更多信息,可以查看来自Spring布道师的<a href="https://www.youtube.com/watch?v=DVo5vmk5Cuw&feature=emb_imp_woyt">新一期的Spring Tips视频</a>(在YouTube上)。</p>
<h2 id="新的AOT引擎"><a href="#新的AOT引擎" class="headerlink" title="新的AOT引擎"></a>新的AOT引擎</h2><p>这个版本最大的变化无疑是引入了新的AOT引擎,该引擎在构建时对Spring程序进行深入的转化和分析,并生成所需的GraalVM Native配置。这些转换由Maven和Gradle Spring AOT插件执行。</p>
<p><img src="/./new-aot-engine-brings-spring-native-to-the-next-level/spring-boot-native.png" alt="spring boot native"></p>
<p>更深入地说,AOT引擎在构建时评估构建环境,以便生成专门为您的应用程序优化后的 application context 和 Spring factories(Spring Boot背后的插件系统)。在实践中,这意味着:</p>
<ul>
<li>在运行时执行的 Spring 基础结构更少</li>
<li>在运行时要判断的条件更少</li>
<li>减少反射,因为使用的是<a href="https://spring.io/blog/2017/03/01/spring-tips-programmatic-bean-registration-in-spring-framework-5">编程式bean注册</a></li>
</ul>
<p>AOT 引擎根据标记为活动的 Bean、Spring 编程模型的知识以及与 Spring Native 捆绑在一起或由应用程序本身提供的native hint,来推断出将应用程序编译为本机可执行文件所需的native configuration。</p>
<p><img src="/./new-aot-engine-brings-spring-native-to-the-next-level/aot-architecture.png" alt="aot architecture"></p>
MySQL解决ONLY_FULL_GROUP_BY的几个方法
https://robberphex.com/mysql-fix-only-full-group-by/
2021-12-11T05:28:05.000Z
2021-12-11T05:28:05.000Z
<h1 id="问题"><a href="#问题" class="headerlink" title="问题"></a>问题</h1><p>以 <a href="https://github.com/datacharmer/test_db/blob/e5f310ac7786a2a181a7fc124973725d7aa4ce7c/employees.sql#L41-L49">employee 示例数据库</a>为例,测试环境用了一条语句:</p>
<p><code>SELECT * FROM employees GROUP BY gender;</code></p>
<p>在测试环境运行正常,但是在线上就会有问题,报错如下:</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Expression #1 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'mse.msc_k8s_cluster.id' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by</span><br><span class="line"> at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)</span><br><span class="line"> at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)</span><br><span class="line"> at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)</span><br><span class="line"> at java.lang.reflect.Constructor.newInstance(Constructor.java:423)</span><br><span class="line"> at com.mysql.jdbc.Util.handleNewInstance(Util.java:425)</span><br></pre></td></tr></table></figure>
<h1 id="原因"><a href="#原因" class="headerlink" title="原因"></a>原因</h1><p>MySQL 在<code>ONLY_FULL_GROUP_BY</code>模式下,有如下约束:</p>
<blockquote>
<p>执行了带 GROUP BY 和 ORDER BY的SELECT语句,就需要保证你 SELECT 的列都在 GROUP BY 和 ORDER BY 中。</p>
</blockquote>
<p>打个比方,如果有数据如下:</p>
<table>
<thead>
<tr>
<th align="left">emp_no</th>
<th align="left">gender</th>
</tr>
</thead>
<tbody><tr>
<td align="left">1</td>
<td align="left">M</td>
</tr>
<tr>
<td align="left">2</td>
<td align="left">M</td>
</tr>
</tbody></table>
在Java的类型系统中,数组有什么缺陷吗?
https://robberphex.com/array-on-java-type-system/
2021-12-05T18:58:50.000Z
2021-12-05T18:58:50.000Z
<p>2020年2月,<a href="http://www.yinwang.org/blog-cn/2020/02/13/java-type-system">王垠吐槽了下Java的类型系统</a>,说:</p>
<blockquote>
<p>关于程序员对 Java 类型系统的理解,比较高级的一个面试问题是这样:</p>
</blockquote>
<figure class="highlight java"><figcaption><span>王垠原版的代码</span></figcaption><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">f</span><span class="params">()</span> {</span><br><span class="line"> String[] a = <span class="keyword">new</span> <span class="title class_">String</span>[<span class="number">2</span>];</span><br><span class="line"> Object[] b = a;</span><br><span class="line"> a[<span class="number">0</span>] = <span class="string">"hi"</span>;</span><br><span class="line"> b[<span class="number">1</span>] = Integer.valueOf(<span class="number">42</span>);</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<blockquote>
<p>这段代码里面到底哪一行错了?为什么?如果某个 Java 版本能顺利运行这段代码,那么如何让这个错误暴露得更致命一些?<br>注意这里所谓的「错了」是本质上,原理上的。</p>
</blockquote>
<p>那么这儿的“错误”是指什么呢?</p>
<h1 id="TL-DR"><a href="#TL-DR" class="headerlink" title="TL;DR"></a>TL;DR</h1><p>如果只能用一句话回答这个问题的话,那么就是:</p>
<p><strong>Java数组不支持泛型,破坏了Java的类型安全性</strong></p>
<h1 id="类型系统的一些前提"><a href="#类型系统的一些前提" class="headerlink" title="类型系统的一些前提"></a>类型系统的一些前提</h1><p>一个好的类型系统,<strong>能够尽可能早的检测出错误</strong>,比如你将一个String赋值给int变量的时候,编译器就会报错,而不是等程序跑起来再报错。</p>
尝鲜Go 1.18中范型版本的map和slice
https://robberphex.com/go-generics-maps-slices/
2021-12-05T18:05:02.000Z
2021-12-05T18:05:02.000Z
<p>大家最近都关注到了Go 1.18会支持范型的消息了吧。</p>
<p>作为Golang的内置类型,大家都期待map和slice支持范型后,可以简化很多的判断逻辑,比如Equal逻辑等等。</p>
<p>几天前,Go范型的标准库已经提交了,且可以试用了:</p>
<p><img src="/./go-generics-maps-slices/go-generic-exp-module.png"></p>
<p>大家也可以读一下对应的代码:<a href="https://cs.opensource.google/go/x/exp/+/master:maps/maps.go">https://cs.opensource.google/go/x/exp/+/master:maps/maps.go</a></p>
<p>废话不多说,我们看下如何尝试范型版本的map和slice吧!</p>
<h1 id="如何使用Go-1-18?"><a href="#如何使用Go-1-18?" class="headerlink" title="如何使用Go 1.18?"></a>如何使用Go 1.18?</h1><p>Golang 官网链接只有1.17版本的下载,那么我们如何才能使用1.18版本的Golang呢?</p>
<p>网上翻了翻,有人提供了Golang 1.18版本的Docker镜像 <code>seongwoohong/golang-nightly:1.18</code>,而且保证维护到1.18版本正式发布:</p>
<p><img src="/./go-generics-maps-slices/golang-nightly-image.png"></p>
如何通过Kubernetes事件来报告错误
https://robberphex.com/error-reporting-with-kubernetes-events/
2021-12-04T17:45:20.000Z
2021-12-04T17:45:20.000Z
<p>组内有维护一个Kubernetes Webhook,可以拦截pod的创建请求,并做一些修改(比如添加环境变量、添加init-container等)。</p>
<p>业务逻辑本身很简单,但是如果过程中产生错误,就很难处理。要不直接阻止pod创建,那么就有可能导致应用无法启动。要么忽略业务逻辑,那么就会导致静默失败,谁也不知道这儿出现了一个错误。</p>
<p>于是,朴素的想法就是接入告警系统,但这会导致当前组件和具体的告警系统耦合起来。</p>
<p>在Kubernetes中,有Event机制,可以做到把一些事件,比如警告、错误等信息记录下来,就比较适合这个场景。</p>
<h1 id="什么是Kubernetes中的事件-Event?"><a href="#什么是Kubernetes中的事件-Event?" class="headerlink" title="什么是Kubernetes中的事件/Event?"></a>什么是Kubernetes中的事件/Event?</h1><p>事件(Event)是 Kubernetes 中众多资源对象中的一员,通常用来记录集群内发生的状态变更,大到集群节点异常,小到 Pod 启动、调度成功等等。</p>
<p>比如我们Describe一个pod,就能看到这个pod对应的事件:</p>
<p><code>kubectl describe pod sc-b-68867c5dcb-sf9hn</code></p>
<p><img src="/./error-reporting-with-kubernetes-events/pod-events.png"></p>
<p>可以看到,从调度、到启动、再到这个pod最终拉取镜像失败,都会通过event的方式记录下来。</p>
Go并不需要Java风格的GC
https://robberphex.com/go-does-not-need-a-java-style-gc/
2021-11-30T05:51:48.000Z
2021-11-30T05:51:48.000Z
<p>像Go、Julia和Rust这样的现代语言不需要像Java c#所使用的那样复杂的垃圾收集器。但这是为什么呢?</p>
基于内存通信的gRPC调用
https://robberphex.com/grpc-in-memory/
2021-11-19T14:49:54.000Z
2021-11-19T14:49:54.000Z
<p>Apache Dubbo 有injvm方式的通信,能够避免网络带来的延迟,同时也不占用本地端口,对测试、本地验证而言,是一种比较方便的RPC通信方式。</p>
<p>最近看到 containerd 的代码,发现它也有类似的需求。<br>但使用ip端口通信,有可能会有端口冲突;使用unix socket,可能会有路径冲突。<br>考察了下gRPC有没有和injvm类似的,基于内存的通信方式。后来发现pipe非常好用,所以记录了下。</p>
<h1 id="Golang-gRPC对网络的抽象"><a href="#Golang-gRPC对网络的抽象" class="headerlink" title="Golang/gRPC对网络的抽象"></a>Golang/gRPC对网络的抽象</h1><p>首先,我们先看一下gRPC一次调用的架构图。当然,这个架构图目前只关注了网络抽象分布。</p>
<p><img src="/./grpc-in-memory/grpc-architecture.png"></p>
<p>我们重点关注网络部分。</p>
<h2 id="操作系统系统抽象"><a href="#操作系统系统抽象" class="headerlink" title="操作系统系统抽象"></a>操作系统系统抽象</h2><p>首先,在网络包之上,系统抽象出来了<a href="https://linux.die.net/man/2/socket">socket</a>,代表一条虚拟连接,对于UDP,这个虚拟连接是不可靠的,对于TCP,这个链接是尽力可靠的。</p>
<p>对于网络编程而言,仅仅有连接是不够的,还需要告诉开发者如何创建、关闭连接。<br><strong>对于服务端</strong>,系统提供了<a href="https://linux.die.net/man/2/accept"><code>accept</code>方法</a>,用来接收连接。<br><strong>对于客户端</strong>,系统提供了<a href="https://linux.die.net/man/2/connect"><code>connect</code>方法</a>,用于和服务端建立连接。</p>
<h2 id="Golang抽象"><a href="#Golang抽象" class="headerlink" title="Golang抽象"></a>Golang抽象</h2>
如何通过抓包来查看Kubernetes API流量
https://robberphex.com/how-to-inspect-kubernetes-api/
2021-11-18T05:29:31.000Z
2021-11-18T05:29:31.000Z
<p>当我们通过kubectl来查看、修改Kubernetes资源时,有没有想过后面的接口到底是怎样的?有没有办法探查这些交互数据呢?</p>
<p>Kuberenetes客户端和服务端交互的接口,是基于http协议的。所以只需要能够捕捉并解析https流量,我们就能看到kubernetes的API流量。</p>
<p>但是由于kubenetes使用了客户端私钥来实现对客户端的认证,所以抓包配置要复杂一点。具体是如下的结构:</p>
<p><img src="/./how-to-inspect-kubernetes-api/capture-architecture.png"></p>
<p><em>如果想了解更多Kubernetes证书的知识,可以看下<a href="https://qingwave.github.io/k8s-tls/">这篇Kubernetes证书解析的文章</a></em></p>
<h1 id="从kubeconfig中提取出客户端证书和私钥"><a href="#从kubeconfig中提取出客户端证书和私钥" class="headerlink" title="从kubeconfig中提取出客户端证书和私钥"></a>从kubeconfig中提取出客户端证书和私钥</h1><p>kubeconfig中包含了客户端的证书和私钥,我们首先要把它们提取出来:</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 提取出客户端证书</span></span><br><span class="line">grep client-certificate-data ~/.kube/config | \</span><br><span class="line"> awk <span class="string">'{ print $2 }'</span> | \</span><br><span class="line"> <span class="built_in">base64</span> --decode > client-cert.pem</span><br><span class="line"><span class="comment"># 提取出客户端私钥</span></span><br><span class="line">grep client-key-data ~/.kube/config | \</span><br><span class="line"> awk <span class="string">'{ print $2 }'</span> | \</span><br><span class="line"> <span class="built_in">base64</span> --decode > client-key.pem</span><br><span class="line"><span class="comment"># 提取出服务端CA证书</span></span><br><span class="line">grep certificate-authority-data ~/.kube/config | \</span><br><span class="line"> awk <span class="string">'{ print $2 }'</span> | \</span><br><span class="line"> <span class="built_in">base64</span> --decode > cluster-ca-cert.pem</span><br></pre></td></tr></table></figure>
<p><em>参考自<a href="https://www.reddit.com/r/kubernetes/comments/h7wfnc/how_do_i_derive_certificate_pem_data_from/">Reddit</a></em></p>
<h1 id="配置Charles代理软件"><a href="#配置Charles代理软件" class="headerlink" title="配置Charles代理软件"></a>配置Charles代理软件</h1>
Dockershim即将被删除,你准备好了吗?
https://robberphex.com/are-you-ready-for-dockershim-removal/
2021-11-15T16:05:31.000Z
2021-11-15T16:05:31.000Z
<p><strong>重点</strong>:1.24版本的k8s将不会自带dockershim,即默认不支持docker作为容器运行时了。现在可以给Kubernetes反馈相关信息了:<a href="https://forms.gle/svCJmhvTv78jGdSx8%E3%80%82">https://forms.gle/svCJmhvTv78jGdSx8。</a></p>
<p>Mirantis单独维护了dockershim组件,仍然可以使用:<a href="https://github.com/Mirantis/cri-dockerd">https://github.com/Mirantis/cri-dockerd</a></p>
<hr>
<p>正文:</p>
<p>去年我们宣布Dockershim已被弃用:<a href="https://kubernetes.io/blog/2020/12/02/dockershim-faq/">Dockershim弃用FAQ</a>。我们目前的计划是尽快将dockershim从Kubernetes代码库中移除。我们正在寻求您的反馈,您是否已经准备好移除dockershim,并确保您已经准备好了。<strong>请填写这个调查问卷:<a href="https://forms.gle/svCJmhvTv78jGdSx8">https://forms.gle/svCJmhvTv78jGdSx8</a></strong>。</p>
<p>Docker作为Kubernetes容器运行时的dockershim组件已被弃用,取而代之的是直接使用容器运行时接口(CRI)的运行时。许多Kubernetes用户已经顺利地迁移到其他容器运行时。然而,我们看到dockershim仍然很受欢迎。您可能会在<a href="https://www.datadoghq.com/container-report/#8">DataDog最近的容器报告</a>中看到一些公开统计数据。一些Kubernetes供应商最近才启用了其他运行时支持(特别是Windows节点)。我们知道许多第三方工具供应商还没有准备好:<a href="https://kubernetes.io/zh/docs/tasks/administer-cluster/migrating-from-dockershim/migrating-telemetry-and-security-agents/#telemetry-and-security-agent-vendors">迁移遥测和安全代理</a>。</p>
<p>在这一点上,我们相信Docker和其他运行时之间的特性是等价的。许多终端用户已经使用了我们的迁移指南,并且正在使用这些不同的运行时运行生产工作负载。现在的计划是,dockershim将在明年4月发布的1.24版本中被移除。对于那些Kubernetes开发者或运行alpha和beta版本的人,dockershim将在12月开始的1.24发布周期被移除。</p>
<p>只有一个月的时间给我们反馈。我们想让你告诉我们你准备好了多少。</p>
<p>为了更好地了解dockershim移除的准备工作,<a href="https://forms.gle/svCJmhvTv78jGdSx8"><strong>我们的调查问卷</strong></a>会询问您当前使用的Kubernetes版本,以及您认为采用Kubernetes 1.24的估计时间。所有关于dockershim移除的汇总信息最终将被公开。一些评论将由SIG Node来审查过滤。如果您想讨论从dockershim迁移的任何细节、报告bug或阻碍点,您可以在在任何时候联系SIG Node:<a href="https://github.com/kubernetes/community/tree/master/sig-node#contact">https://github.com/kubernetes/community/tree/master/sig-node#contact</a></p>
<p>Kubernetes是一个成熟的项目。dockershim的移除是为了摆脱“永久的beta特性”并提供更强的稳定性和兼容性保证。通过dockershim的迁移,你将获得更多的灵活性和容器运行时的选项,减少了对特定底层技术的依赖。请花时间查看<a href="https://kubernetes.io/zh/docs/tasks/administer-cluster/migrating-from-dockershim/">dockershim迁移文档</a>,并咨询Kubernetes供应商有哪些容器运行时选项可供您选择。阅读<a href="https://kubernetes.io/zh/docs/setup/production-environment/container-runtimes/#%E5%AE%B9%E5%99%A8%E8%BF%90%E8%A1%8C%E6%97%B6">有关如何使用容器和CRI-O的容器运行时文档</a>,以帮助您在升级到1.24时做好准备。</p>