<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>涤生的博客</title>
    <link>https://andyyin.github.io/</link>
    <description>Recent content on 涤生的博客</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>zh</language>
    <lastBuildDate>Mon, 18 Nov 2019 00:00:00 +0000</lastBuildDate>
    
	<atom:link href="https://andyyin.github.io/index.xml" rel="self" type="application/rss+xml" />
    
    
    <item>
      <title>[译]用 RSocket 解决响应式服务之间的的通讯-Part 3：基于 RSocket 进行抽象</title>
      <link>https://andyyin.github.io/blog/%E8%AF%91%E7%94%A8-rsocket-%E8%A7%A3%E5%86%B3%E5%93%8D%E5%BA%94%E5%BC%8F%E6%9C%8D%E5%8A%A1%E4%B9%8B%E9%97%B4%E7%9A%84%E7%9A%84%E9%80%9A%E8%AE%AF-part-3%E5%9F%BA%E4%BA%8E-rsocket-%E8%BF%9B%E8%A1%8C%E6%8A%BD%E8%B1%A1/</link>
      <pubDate>Mon, 18 Nov 2019 00:00:00 +0000</pubDate>
      
      <guid>https://andyyin.github.io/blog/%E8%AF%91%E7%94%A8-rsocket-%E8%A7%A3%E5%86%B3%E5%93%8D%E5%BA%94%E5%BC%8F%E6%9C%8D%E5%8A%A1%E4%B9%8B%E9%97%B4%E7%9A%84%E7%9A%84%E9%80%9A%E8%AE%AF-part-3%E5%9F%BA%E4%BA%8E-rsocket-%E8%BF%9B%E8%A1%8C%E6%8A%BD%E8%B1%A1/</guid>
      <description>如果你看过本系列的前两篇文章，应该已经已经发现 RSocket 提供了一些底层的 API。可以直接使用交互模型中的方法进行操作，而且可以没有任何限制来回发送帧。这些基础的 API 为我们提供了许多自由和控制权，但是它可能会引入额外的问题，尤其是与微服务之间的契约相关的问题。
为了解决这些问题，我们可以使用 RSocket 作为通用抽象层。有两种可用的解决方案：RSocket RPC 或者与 Spring Framework集成。在以下各节中，我们将简要讨论它们。
基于 RSocket 的 RPC 保持微服务之间的契约干净清晰是分布式系统的关键问题之一。为了确保应用程序可以交换数据，我们可以利用 RPC（远程过程调用）。幸运的是，RSocket 具有专用的 RPC 模块，它使用 Protobuf 作为序列化工具，因此，我们可以从 RSocket 的性能中受益并且同时具有保持契约的能力。通过将生成的服务和对象与 RSocket 接受器结合在一起，我们可以启动完全可操作的 RPC 服务端，并使用 RPC 客户端轻松使用它。
首先，我们需要定义服务和对象。在下面的示例中，我们创建了具有四个方法的简单的CustomerService服务，它们每个表示交互模型相互不同的方法。
syntax = &amp;quot;proto3&amp;quot;; option java_multiple_files = true; option java_outer_classname = &amp;quot;ServiceProto&amp;quot;; package com.rsocket.rpc; import &amp;quot;google/protobuf/empty.proto&amp;quot;; message SingleCustomerRequest { string id = 1; } message MultipleCustomersRequest { repeated string ids = 1; } message CustomerResponse { string id = 1; string name = 2; } service CustomerService { rpc getCustomer(SingleCustomerRequest) returns (CustomerResponse) {} //request-response rpc getCustomers(MultipleCustomersRequest) returns (stream CustomerResponse) {} //request-stream rpc deleteCustomer(SingleCustomerRequest) returns (google.</description>
    </item>
    
    <item>
      <title>[译]Eclipse MAT — Incoming, Outgoing References 你真的了解吗？</title>
      <link>https://andyyin.github.io/blog/eclipse-mat-incoming-outgoing-references-%E4%BD%A0%E7%9C%9F%E7%9A%84%E4%BA%86%E8%A7%A3%E5%90%97/</link>
      <pubDate>Fri, 25 Oct 2019 00:00:00 +0000</pubDate>
      
      <guid>https://andyyin.github.io/blog/eclipse-mat-incoming-outgoing-references-%E4%BD%A0%E7%9C%9F%E7%9A%84%E4%BA%86%E8%A7%A3%E5%90%97/</guid>
      <description>了解 Eclipse MAT 中 incoming and outgoing 引用之间的区别。
 Eclipse MAT（内存分析器工具）是分析 JVM 堆 Dump 文件的强大工具。它具有几个非常有效分析内存问题的强大功能。 “Incoming references”和“Outgoing references”就是其中一种功能。在本文中，我们来探讨 Incoming references 和 Outgoing references 以及它们之间的区别。 在 Eclipse MAT 中，当右键单击任何对象时，将看到下拉菜单。如果选择“ListObjects”菜单项，则会注意到两个选项：
 with outgoing references with incoming references  通过示例理解知识会更容易，咱们来看看这样一个例子。让我们通过示例来了解有关 Incoming references 和 Outgoing references 的更多知识。例如，一个应用程序的源代码如下所示：
public class A { private C c1 = C.getInstance(); } public class B { private C c2 = C.getInstance(); } public class C { private static C myC = new C(); public static C getInstance() { return myC; } private D d1 = new D(); private E e1 = new E(); } public class D { } public class E { } public class SimpleExample { public static void main (String argsp[]) throws Exception { A a = new A(); B b = new B(); } }  现在，如果要为上述示例应用程序以图形方式绘制对象，则其外观将如下所示： 图 1：示例应用程序的对象引用图</description>
    </item>
    
    <item>
      <title>[译]Eclipse MAT: Shallow Heap Vs Retained Heap 你理解的对吗?</title>
      <link>https://andyyin.github.io/blog/eclipse-mat-shallow-heap-vs-retained-heap-%E4%BD%A0%E7%90%86%E8%A7%A3%E7%9A%84%E5%AF%B9%E5%90%97/</link>
      <pubDate>Wed, 23 Oct 2019 00:00:00 +0000</pubDate>
      
      <guid>https://andyyin.github.io/blog/eclipse-mat-shallow-heap-vs-retained-heap-%E4%BD%A0%E7%90%86%E8%A7%A3%E7%9A%84%E5%AF%B9%E5%90%97/</guid>
      <description>有没有想过 Shallow 和 Retained heap 之间的区别？
 Eclipse MAT（内存分析器工具）是分析 JVM 堆 Dump 文件的强大工具。当尝试分析内存相关的问题时，它非常方便。在 Eclipse MAT 中，报告了两种类型的对象大小：
 Shallow Heap Retained Heap  在本文中，我们主要讨论它们之间的区别，并探讨它们的计算方式。
通过示例理解知识会更容易，咱们来看看这样一个例子。例如，假设你的应用程序具有这样的对象模型，如图 1 所示：
图1：内存中的对象
 对象 A 持有对象 B 和 C 的引用。 对象 B 持有对象 D 和 E 的引用。 对象 C 持有对象 F 和 G 的引用。  另外，我们假设每个对象占用 10 个字节的内存。在这种场景下，我们来开始分析吧。
Shallow Heap 大小 请记住：对象的 Shallow heap 是其自身在内存中的大小。由于在我们的示例中，每个对象占用大约 10 个字节，因此每个对象的 Shallow heap 大小为 10 个字节。很简单。
B 的 Retained Heap 大小 从图 1 中，您可以注意到对象 B 持有对象 D 和 E 的引用。因此，如果对象 B 是从内存中被垃圾回收，则将不再有对对象 D 和 E 的引用。这意味着此时 D 和 E 也可以被垃圾收集。Retained heap 指的就是在垃圾回收特定对象时将释放的内存量。因此，B 的保留堆大小为： = B 的 shallow heap 大小 + D 的 shallow heap 大小 + E 的 shallow heap 大小 = 10 bytes + 10 bytes + 10 bytes = 30 bytes</description>
    </item>
    
    <item>
      <title>[译]用 RSocket 解决响应式服务之间的通讯-Part 2：负载均衡和可恢复性</title>
      <link>https://andyyin.github.io/blog/%E8%AF%91%E7%94%A8-rsocket-%E8%A7%A3%E5%86%B3%E5%93%8D%E5%BA%94%E5%BC%8F%E6%9C%8D%E5%8A%A1%E4%B9%8B%E9%97%B4%E7%9A%84%E9%80%9A%E8%AE%AF-part-2%E8%B4%9F%E8%BD%BD%E5%9D%87%E8%A1%A1%E5%92%8C%E5%8F%AF%E6%81%A2%E5%A4%8D%E6%80%A7/</link>
      <pubDate>Mon, 07 Oct 2019 00:00:00 +0000</pubDate>
      
      <guid>https://andyyin.github.io/blog/%E8%AF%91%E7%94%A8-rsocket-%E8%A7%A3%E5%86%B3%E5%93%8D%E5%BA%94%E5%BC%8F%E6%9C%8D%E5%8A%A1%E4%B9%8B%E9%97%B4%E7%9A%84%E9%80%9A%E8%AE%AF-part-2%E8%B4%9F%E8%BD%BD%E5%9D%87%E8%A1%A1%E5%92%8C%E5%8F%AF%E6%81%A2%E5%A4%8D%E6%80%A7/</guid>
      <description>本文是《用 RSocket 解决响应式服务之间的通讯》微型系列的第二篇文章，它将帮助你熟悉 RSocket——一种可能会彻底改变机器之间通讯的新二进制协议。在以下段落中，我们将讨论在云环境中的负载平衡问题以及介绍可恢复性能力，可恢复性能力有助于解决网络问题，尤其是在 IOT 系统中。
如果您不了解 RSocket 基础知识，请查看该系列之前的文章。 高可用性和负载平衡是企业级系统的重要能力 类似银行和保险等许多业务领域，可用性和可靠性是应用程序的核心能力。在这些要求苛刻的行业中，即使在高流量、网络问题导致延迟增加或自然灾害期间，服务也必须 24*7 全天候提供服务。为了确保该软件始终能够提供用户使用，通常会在多个可用区域中对其进行冗余部署。
在这种情况下，每个微服务的至少两个实例部署在至少两个可用性区域中。多个可用区内冗余部署让系统具有弹性且增加了容量（更多个实例能够处理更高的负载）。那么这样会带来什么问题呢？冗余部署引入了额外的复杂性。作为研发人员，我们必须确保进入的的流量分布在所有可用实例中（如果流量打到不可用的实例上，会导致请求失败）。
有两种主要的方法可解决这个问题：服务端负载平衡和客户端负载平衡。
第一种方法（服务端负载平衡）基于以下假设，请求者不知道响应者的 IP 地址。取而代之的是，请求者与负载均衡器进行通信，负载均衡器负责在后端的微服务之间分配进入的请求，类似产品有 Ngnix。这种设计在云时代很容易采用。 IaaS 提供商通常具有内置的可靠解决方案，例如 Amazon Web Services 中提供的 Elastic Load Balancer。此外，这种设计有助于开发比普通轮询式负载均衡更复杂的路由策略（例如，自适应负载平衡或链式故障转移）。该服务端负载平衡的主要缺点是必须配置和部署额外的资源，如果我们的系统包含数百个微服务，这可能会很痛苦。此外，它可能会影响延迟-每个请求在负载均衡器上会增加了网络一跳。
第二种方法（客户端负载平衡）与第一种方法有些相反。这里请求者知道给定微服务的每个实例的 IP 地址，而不是通过连接到响应者的中心点来进行负载均衡。有了这些微服务的实例 IP 地址，客户端就可以自己选择响应者实例，然后向其发送请求。该方法好处是不需要任何额外资源，但是必须确保请求者具有响应者所有实例的 IP 地址（请参阅如何使用服务发现模式来处理它）。客户端负载平衡模式的主要优点是其性能（可以减少一个额外的“网络跃点”），进而可以显着减少延迟。这也是 RSocket 实现客户端负载平衡模式的关键原因之一。
RSocket 中的客户端负载平衡 在代码实现方面，RSocket 中客户端负载平衡的实现非常简单。该机制依赖于LoadBalancedRSocketMono对象，根据该对象会从一组可用的 RSocket 实例中选择合适的 RSocket 实例。要访问 RSocket，我们必须订阅LoadBalancedRSocketMono，onNext该方法接收所有 RSocket 实例。而且，它为每个 RSocket 计算统计信息，以便能够估计每个实例的负载，并在特定时间点根据该负载选择性能最佳的实例。
该算法考虑了多个参数，例如延迟，保持的连接数以及未处理的请求数。每个 RSocket 的运行状况都由可用性参数反映出来，该参数的值从零到一，其中零表示给定实例无法处理任何请求，而一则表示分配的请求完全处理完成的 RSocket。下面的代码片段显示了 RSocket 负载平衡 的最基本示例，该示例连接到响应器的三个不同实例并执行 100 个请求。每次它从LoadBalancedRSocketMono对象获取 RSocket 。
@Slf4j public class LoadBalancedClient { static final int[] PORTS = new int[]{7000, 7001, 7002}; public static void main(String[] args) { List rsocketSuppliers = Arrays.</description>
    </item>
    
    <item>
      <title>[译]G1 GC：一个神奇的 JVM 参数，减少你的内存消耗</title>
      <link>https://andyyin.github.io/blog/g1-gc%E4%B8%80%E4%B8%AA%E7%A5%9E%E5%A5%87%E7%9A%84-jvm-%E5%8F%82%E6%95%B0%E5%87%8F%E5%B0%91%E4%BD%A0%E7%9A%84%E5%86%85%E5%AD%98%E6%B6%88%E8%80%97/</link>
      <pubDate>Sun, 06 Oct 2019 00:00:00 +0000</pubDate>
      
      <guid>https://andyyin.github.io/blog/g1-gc%E4%B8%80%E4%B8%AA%E7%A5%9E%E5%A5%87%E7%9A%84-jvm-%E5%8F%82%E6%95%B0%E5%87%8F%E5%B0%91%E4%BD%A0%E7%9A%84%E5%86%85%E5%AD%98%E6%B6%88%E8%80%97/</guid>
      <description>现代 Java 应用程序有大量的字符串操作，例如，Web 服务 API 调用（即 JSON、REST、SOAP 等）、外部数据源调用（SQL、从 DB 返回的数据等）以及文本解析和文本创建等。因此，字符串对象很容易就占据了约至少 30％ 的内存。然而，这些 String 对象中的大多数都是重复的，这些字符串的重复浪费了大量内存。因此，优化重复字符串对象浪费的内存是 Java 非常受欢迎的功能之一。在 G1 中，Java 就对此功能做了支持。
G1 做了什么？ G1 GC 算法运行时，它将从内存中删除垃圾对象。它还从内存中删除重复的字符串对象（字符串重复数据删除）。可以通过设置以下 JVM 参数来激活此功能：
-XX:+UseG1GC -XX:+UseStringDeduplication   注意1：为了使用此功能， 需要在 Java 8 update 20 或更高版本上运行。 注意2：为了使用-XX:+UseStringDeduplication，您需要使用 G1 GC 算法。
 让我们看一个例子吧 选择这个简单的示例就是为了研究 JVM 如何处理重复的字符串。让我们通过这个简单的程序来验证 Java 的这个功能。
 public class StringDeduplicationExample { public static List&amp;lt;String&amp;gt;myStrings = new ArrayList&amp;lt;&amp;gt;(); public static void main(String[] args) throws Exception { for (int counter = 0; counter &amp;lt; 200; ++counter) { for (int secondCounter = 0; secondCounter &amp;lt; 1000; ++secondCounter) { // Add it 1000 times.</description>
    </item>
    
    <item>
      <title>[译]用 RSocket 解决响应式服务之间的通讯-Part 1</title>
      <link>https://andyyin.github.io/blog/%E8%AF%91%E7%94%A8-rsocket-%E8%A7%A3%E5%86%B3%E5%93%8D%E5%BA%94%E5%BC%8F%E6%9C%8D%E5%8A%A1%E4%B9%8B%E9%97%B4%E7%9A%84%E9%80%9A%E8%AE%AF-part-1/</link>
      <pubDate>Fri, 04 Oct 2019 00:00:00 +0000</pubDate>
      
      <guid>https://andyyin.github.io/blog/%E8%AF%91%E7%94%A8-rsocket-%E8%A7%A3%E5%86%B3%E5%93%8D%E5%BA%94%E5%BC%8F%E6%9C%8D%E5%8A%A1%E4%B9%8B%E9%97%B4%E7%9A%84%E9%80%9A%E8%AE%AF-part-1/</guid>
      <description>本文是《用 RSocket 解决响应式服务之间的通讯》微型系列的第一篇文章，它将帮助你熟悉 RSocket——一种可能会彻底改变机器之间通讯的新二进制协议。在以下各段中，我们首先讨论当前分布式系统的问题，然后说明如何使用 RSocket 解决这些问题。本文聚焦于微服务之间的通信与 RSocket 交互模型。
分布式系统中的通讯问题 确实，微服务无处不在。从部署和维护非常麻烦的单体应用程序到完全分布式、微型、可扩展的微服务，我们经历了漫长的过程。微服务架构设计有很多好处。但是，它也有缺点。首先，为了向客户交付最终产品，服务之间必须交换大量数据。在单体应用程序中这不是问题，因为它整个通信都在单个 JVM 进程中进行。而在“微服务架构”中，部署在单独的容器中服务需要通过内部或外部网络进行通信。此时，“网络”是一等公民。如果在云上运行应用程序，事情将变得更加复杂。在这种情况下，网络问题和延迟增加将是不可避免的事情。与其尝试解决网络问题，不如设计具有弹性的体系结构，让其即使在网络抖动的情况下也能完全正常运行，这样岂不是更好。
我们来更深入地研究下微服务、数据、通信和云的概念。试想一下，对于一般的企业级系统，外部可以通过网站和移动 App 访问，或者通过小型外部设备（如家用加热控制器）与其进行交互。这些系统都是由多个微服务组成，这些微服务大多数是用 Java 编写的，其中一小部分是 Python 和 node.js 实现的组件，另外，为了确保整个系统高度可用，所有服务之间的传输数据都需要跨多个可用区进行复制备份。
IaaS 层是不可控的，为了改善开发人员体验，一般需要将应用程序运行在 PaaS 平台之上。对于 PaaS 平台，我们可以选择：Cloud Foundry，Kubernetes 或两者结合使用都是可行的。在服务之间的通信方面，设计比较简单，每个组件都暴露普通的 REST API，如下图所示。
乍一看，组件都被分散在云中运行，这样的体系结构看起来还不错。额，它可能出什么问题？主要有两个问题：它们都与通讯有关。
第一个问题是 HTTP 的请求/响应交互模型。尽管使用 HTTP 的案例有很多，但它并不是为机器之间的通信而设计的。微服务在不关心操作结果的情况下将某些数据发送到另一个组件是很常见的（即发即弃），或者在数据可用时自动流传输数据（数据流）。使用 HTTP 请求/响应交互模型难以用优雅、有效的方式实现这些交互模式。例如，在使用请求/响应交互模型时，执行简单的即发即弃操作也会产生副作用，会出现即使客户端对处理响应不感兴趣，服务器也必须将响应发送回客户端的问题。
第二个问题是性能。假设我们的系统被客户大量使用，流量增加了，并且我们注意到我们正在努力处理每秒数百个请求。借助容器和云，我们可以轻松扩展我们的服务；但是，如果我们关注下资源消耗的情况，则会发现一些问题。例如，当机器内存会出现不足时，可能 VM 的 CPU 还几乎处于空闲状态。这个问题主要来自于使用 HTTP 1.x 协议通常处理每个请求需要一个线程，致使每个请求都存在堆栈内存。在这种情况下，我们可以利用反应式编程模型和非阻塞 IO。它将在在不增加延迟的情况下大大减少内存使用量。 HTTP 1.x 是基于文本的协议，因此与二进制协议相比，需要传输的数据大小显著增大。
在机器之间的通信中，我们不应将自己局限于 HTTP（尤其是 1.x 版本，请求/响应交互模型以及性能低下）。在市场上还有许多更合适、更强大的解决方案。例如，基于 RabbitMQ、gRPC 或者 HTTP 2（支持多路复用和二进制化负载）进行信息传输在性能和效率方面会比纯 HTTP 1.x 更好。
在给定场景下，使用多种协议可以使我们最有效、最合适地连接微服务；但是，采用多种协议迫使我们一次又一次地重新发明轮子，另外，为了保证保证通讯的安全性，我们不得不用安全性相关的额外信息来丰富我们的数据；并且还需要创建多个适配器来处理协议之间的转换。在某些情况下，数据传输可能需要依赖外部资源（代理、服务等），这些服务必须高度可用。因此，尽管我们所需要的只是基于消息的简单“即发即弃”操作，但 HTTP 请求/响应交互模型由于其性能比较差，产生额外的资源会带来额外的成本。此外，多种不同的协议可能会引入与应用程序治理相关的严重问题，尤其是如果我们的系统包含数百个微服务时。
上面提到的两个核心问题是推出 RSocket 的原因，同时也是它可能彻底改变云通讯的原因。通过其反应式和内置的强大交互模型，RSocket可以应用于各种业务场景中，并可能最终统一我们在分布式系统中使用的通信模式。
RSocket 如何解决 RSocket 是一种新的、消息驱动的二进制协议，它规范了云中的通讯方式。它有助于以一致的方式解决常见的应用程序问题，并且它支持多种语言（例如 Java、JS、Python）和传输协议（TCP、WebSocket、Aeron）。在下面的部分中，我们将深入探讨协议内部实现并讨论交互模型。</description>
    </item>
    
    <item>
      <title>[译]如何减少长时间的 GC 停顿？</title>
      <link>https://andyyin.github.io/blog/%E5%A6%82%E4%BD%95%E5%87%8F%E5%B0%91%E9%95%BF%E6%97%B6%E9%97%B4%E7%9A%84-gc-%E5%81%9C%E9%A1%BF-/</link>
      <pubDate>Wed, 02 Oct 2019 00:00:00 +0000</pubDate>
      
      <guid>https://andyyin.github.io/blog/%E5%A6%82%E4%BD%95%E5%87%8F%E5%B0%91%E9%95%BF%E6%97%B6%E9%97%B4%E7%9A%84-gc-%E5%81%9C%E9%A1%BF-/</guid>
      <description>垃圾回收是非常必要的，但是如果处理不好，它会成为性能杀手。采取以下步骤以确保 GC 停顿时间最少且最短。
 长时间的 GC 停顿对应用程序是不利的，它会影响服务的 SLA，进而导致糟糕的用户体验，并对核心应用程序的服务造成严重损害。因此，在本文中，我列出了导致长时间 GC 停顿的关键原因以及解决这些问题的可能的解决方案。
1. 高速率创建对象 如果你的应用程序的对象创建率很高，那么为了跟上它，垃圾回收率也将会很高。高垃圾回收率也会增加 GC 停顿时间。因此，优化应用程序以创建更少的对象是减少长 GC 停顿的有效策略。这可能是一个耗时的工作，但百分百值得去做。为了优化应用程序中的对象创建速率，可以考虑先使用 Java 分析器来进行分析，例如 JProfiler，YourKit 或 JVisualVM，通过这些分析器可得出以下信息报告：
 创建了哪些对象？ 创建这些对象的速率是多少？ 它们在内存中占用多少空间？ 谁在创建了它们？  始终尝试去优化占用最大内存量的对象。
提示: 如何计算对象创建速率
将你的 GC 日志上传到通用 GC 日志分析器工具 GCeasy。该工具将报告对象创建率。在“对象统计信息”中将列出“平均创建率”。此项将报告对象创建率。力争使该值保持较低。请参见下图（摘自 GCeasy 生成的报告的目录），显示“平均创建速度”为 8.83 mb.sec。 2. 年轻代空间不足 当年轻代过小时，对象会过早地提升到老年代。从老年代收集垃圾比从年轻代收集垃圾要花费更多的时间。因此，增加年轻代的大小有可能减少长时间的 GC 停顿。可以通过设置两个 JVM 参数之一来增加年轻一代的大小 -Xmn ：指定年轻代的大小。 -XX:NewRatio ：指定年轻代相对于老年代的大小比例。例如，设置 -XX:NewRatio=2 表示年轻代与老年代之间的比率为 1:2。年轻代的大小将是整个堆的 1/3。因此，如果堆大小为 2 GB，则年轻代大小将为 2G / 3 = 667 MB。
3. 选择 GC 算法 GC 算法对 GC 停顿时间有很大的影响。如果你是 GC 专家或打算成为一个（或你的团队中的有人是 GC 专家），你可以调整 GC 参数配置以获得最佳 GC 停顿时间。如果你没有大量的 GC 的专业知识，那么我建议使用 G1 GC 算法，因为它有自动调节的能力。在 G1 中，可以使用系统属性 -xx：MaxGCPauseMillis来设置 GC 预期最大停顿时间。例如：</description>
    </item>
    
    <item>
      <title>服务刚启动就 Full GC，要闹哪样？</title>
      <link>https://andyyin.github.io/blog/%E6%9C%8D%E5%8A%A1%E5%88%9A%E5%90%AF%E5%8A%A8%E5%B0%B1-full-gc%E8%A6%81%E9%97%B9%E5%93%AA%E6%A0%B7/</link>
      <pubDate>Tue, 23 Jul 2019 00:00:00 +0000</pubDate>
      
      <guid>https://andyyin.github.io/blog/%E6%9C%8D%E5%8A%A1%E5%88%9A%E5%90%AF%E5%8A%A8%E5%B0%B1-full-gc%E8%A6%81%E9%97%B9%E5%93%AA%E6%A0%B7/</guid>
      <description>1.背景 最近有个同学说他的服务刚启动就收到两次 Full GC 告警， 按道理来说刚启动，对象应该不会太多，为啥会触发 Full GC 呢？
带着疑问，我们还是先看看日志吧，毕竟日志的信息更多。
2.日志 可以看到，其实是两次 CMS GC（监控对 Full GC 和 Old GC 不分）。但是你会发现一个奇怪的现象，咦，&amp;rdquo;CMS-initial-mark: 0K(3222528K)&amp;rdquo; 怎么 Old Gen 对象使用空间大小为 0，细想服务刚启动，Old Gen 为 0 也算正常，但是为什么会触发CMS GC 呢？ 第一次 CMS GC 日志：
2019-07-16T16:44:56.270+0800: 8.446: [GC (CMS Initial Mark) [1 CMS-initial-mark: 0K(3222528K)] 1477124K(5152832K), 0.0445445 secs] [Times: user=0.16 sys=0.00, real=0.05 secs] 2019-07-16T16:44:56.315+0800: 8.490: [CMS-concurrent-mark-start] 2019-07-16T16:44:56.337+0800: 8.513: [CMS-concurrent-mark: 0.022/0.022 secs] [Times: user=0.03 sys=0.00, real=0.02 secs] 2019-07-16T16:44:56.337+0800: 8.513: [CMS-concurrent-preclean-start] 2019-07-16T16:44:56.</description>
    </item>
    
    <item>
      <title>简单的 HTTP 调用，为什么时延这么大？</title>
      <link>https://andyyin.github.io/blog/%E7%AE%80%E5%8D%95%E7%9A%84-http-%E8%B0%83%E7%94%A8%E4%B8%BA%E4%BB%80%E4%B9%88%E6%97%B6%E5%BB%B6%E8%BF%99%E4%B9%88%E5%A4%A7/</link>
      <pubDate>Sun, 14 Jul 2019 00:00:00 +0000</pubDate>
      
      <guid>https://andyyin.github.io/blog/%E7%AE%80%E5%8D%95%E7%9A%84-http-%E8%B0%83%E7%94%A8%E4%B8%BA%E4%BB%80%E4%B9%88%E6%97%B6%E5%BB%B6%E8%BF%99%E4%B9%88%E5%A4%A7/</guid>
      <description>1. 背景 最近项目测试遇到个奇怪的现象，在测试环境通过 Apache HttpClient 调用后端的 HTTP 服务，平均耗时居然接近 39.2ms。可能你乍一看觉得这不是很正常吗，有什么好奇怪的？其实不然，我再来说下一些基本信息，该后端的 HTTP 服务并没有什么业务逻辑，只是将一段字符串转成大写然后返回，字符串长度也仅只有 100 字符，另外网络 ping 延时只有 1.9ms 左右。因此，理论上该调用耗时应该在 2-3ms 左右，但为什么平均耗时 39.2ms 呢？
由于工作原因，调用耗时的问题，对我来说，已经见怪不怪了，经常会帮业务解决内部 RPC 框架调用超时的相关问题，但是 HTTP 调用耗时第一次遇到。不过，排查问题的套路是一样的。主要方法论无外乎由外而内、至上而下等排查方法。我们先来看看外围的一些指标，看能否发现蛛丝马迹。
2. 外围指标 2.1 系统指标 主要看外围的一些系统指标（注意：调用与被调用的机器都要看）。例如负载、CPU。只需一个 top 命令就能一览无余。
因此，确认了下 CPU 和负载都很空闲。由于当时没有截图，这里就不放图了。
2.2 进程指标 Java 程序进程指标主要看 GC、线程堆栈情况（注意：调用与被调用的机器都要看）。
Young GC 都非常少，而且耗时也在 10ms 以内，因此没有长时间的 STW。
因为平均调用时间 39.2ms，比较大，如果耗时是代码导致，线程堆栈应该能发现点啥。看了之后一无所获，服务的相关线程堆栈主要表现是线程池的线程在等任务，这就意味着线程并不忙。
是不是感觉黔驴技穷了，接下来该怎么办呢？
3. 本地复现 如果本地（本地是 MAC 系统）能复现，对排查问题也是极好的。
因此在本地使用 Apache HttpClient 写了个简单 Test 程序，直接调用后端的 HTTP 服务，发现平均耗时在 55ms 左右。咦，怎么跟测试环境 39.2ms 的结果有点区别。主要是本地与测试环境的后端的 HTTP 服务机器跨地区了，ping 时延在 26ms 左右，所以延时增大了。不过本地确实也是存在问题的，因为ping 时延是 26ms，后端 HTTP 服务逻辑简单，几乎不耗时，因此本地调用平均耗时应该在 26ms 左右，为什么是 55ms？</description>
    </item>
    
    <item>
      <title>JVM 源码解读之 CMS 何时会进行 Full GC</title>
      <link>https://andyyin.github.io/blog/jvm-%E6%BA%90%E7%A0%81%E8%A7%A3%E8%AF%BB%E4%B9%8B-cms-%E4%BD%95%E6%97%B6%E4%BC%9A%E8%BF%9B%E8%A1%8C-full-gc/</link>
      <pubDate>Sat, 15 Jun 2019 00:00:00 +0000</pubDate>
      
      <guid>https://andyyin.github.io/blog/jvm-%E6%BA%90%E7%A0%81%E8%A7%A3%E8%AF%BB%E4%B9%8B-cms-%E4%BD%95%E6%97%B6%E4%BC%9A%E8%BF%9B%E8%A1%8C-full-gc/</guid>
      <description>前言 在文章 JVM 源码解读之 CMS GC 触发条件 中分析了 CMS GC 触发的五类情况，并且提到 CMS GC 分为 foreground collector 和 background collector。 不管是 foreground collector 还是 background collector 使用的都是 mark-sweep 算法，分阶段进行标记清理，优点很明显-低延时，但最大的缺点是存在碎片，内存空间利用率低。因此，CMS 为了解决这个问题，在每次进行 foreground collector 之前，判断是否需要进行一次压缩式 GC。
此压缩式 GC，CMS 使用的是跟 Serial Old GC 一样的 LISP2 算法，其使用 mark-compact 来做 Full GC，一般称之为 MSC（mark-sweep-compact），它收集的范围是 Java 堆的 Young Gen 和 Old Gen，以及 metaspace（元空间）。
本文不涉及具体的收集过程，只分析 CMS 在什么情况下会进行 compact 的 Full GC。
 本文内容是基于 JDK 8
什么情况下会进行一次压缩式 Full GC 呢？</description>
    </item>
    
    <item>
      <title>JVM 源码解读之 CMS GC 触发条件</title>
      <link>https://andyyin.github.io/blog/jvm-%E6%BA%90%E7%A0%81%E8%A7%A3%E8%AF%BB%E4%B9%8B-cms-gc-%E8%A7%A6%E5%8F%91%E6%9D%A1%E4%BB%B6/</link>
      <pubDate>Fri, 07 Jun 2019 00:00:00 +0000</pubDate>
      
      <guid>https://andyyin.github.io/blog/jvm-%E6%BA%90%E7%A0%81%E8%A7%A3%E8%AF%BB%E4%B9%8B-cms-gc-%E8%A7%A6%E5%8F%91%E6%9D%A1%E4%BB%B6/</guid>
      <description>前言 经常有同学会问，为啥我的应用 Old Gen 的使用占比没达到 CMSInitiatingOccupancyFraction 参数配置的阈值，就触发了 CMS GC，表示很莫名奇妙，不知道问题出在哪？
其实 CMS GC 的触发条件非常多，不只是 CMSInitiatingOccupancyFraction 阈值触发这么简单。本文通过源码全面梳理了触发 CMS GC 的条件，尽可能的帮你了解平时遇到的奇奇怪怪的 CMS GC 问题。
先抛出一些问题，来吸引你的注意力。
 为什么 Old Gen 使用占比仅 50% 就进行了一次 CMS GC？
Metaspace 的使用也会触发 CMS GC 吗？
为什么 Old Gen 使用占比非常小就进行了一次 CMS GC？
 触发条件 CMS GC 在实现上分成 foreground collector 和 background collector。foreground collector 相对比较简单，background collector 比较复杂，情况比较多。
下面我们从 foreground collector 和 background collector 分别来说明他们的触发条件：
 说明：本文内容是基于 JDK 8
说明：本文仅涉及 CMS GC 的触发条件，至于算法的具体过程，以及什么时候进行 MSC（mark sweep compact）不在本文范围</description>
    </item>
    
    <item>
      <title>Zookeeper 集群高可用部署详解</title>
      <link>https://andyyin.github.io/blog/zookeeper-%E9%9B%86%E7%BE%A4%E9%AB%98%E5%8F%AF%E7%94%A8%E9%83%A8%E7%BD%B2%E8%AF%A6%E8%A7%A3/</link>
      <pubDate>Sun, 19 May 2019 00:00:00 +0000</pubDate>
      
      <guid>https://andyyin.github.io/blog/zookeeper-%E9%9B%86%E7%BE%A4%E9%AB%98%E5%8F%AF%E7%94%A8%E9%83%A8%E7%BD%B2%E8%AF%A6%E8%A7%A3/</guid>
      <description>介绍 Zookeeper 我想大家都不陌生，在很多场合都听到它的名字。它是 Apache 的一个顶级项目，为分布式应用提供一致性高性能协调服务。可以用来做：配置维护、域名服务、分布式锁等。有很多开源组件，尤其是中间件领域，使用 Zookeeper 作为配置中心或者注册中心。例如，它是 Hadoop 和 HBase 的重要组件，是 Kafka 的管理和协调服务，是 Dubbo 等服务框架的注册中心等。
本文不探讨它的优缺点，仅着眼于如何对 Zookeeper 进行高可用部署。
原理 在介绍高可用部署前，我们先了解下 Zookeeper 的基本知识，这对充分理解它的高可用部署非常重要。
架构 下图是 Zookeeper 的架构图，ZooKeeper 集群中包含 Leader、Follower 以及 Observer 三个角色：
 Leader：负责进行投票的发起和决议，更新系统状态，Leader 是由选举产生; Follower： 用于接受客户端请求并向客户端返回结果，在选主过程中参与投票; Observer：可以接受客户端连接，接受读写请求，写请求转发给 Leader，但 Observer 不参加投票过程，只同步 Leader 的状态，Observer 的目的是为了扩展系统，提高读取速度。  Client 是 Zookeeper 的客户端，请求发起方。 高可用  Zookeeper 系统中只要集群中存在超过一半的节点（这里指的是投票节点即非 Observer 节点）能够正常工作，那么整个集群就能够正常对外服务
 基于此，如果想搭建一个能够允许 N 台机器 down 掉的集群，那么就要部署一个由 2*N+1 台服务器构成的 ZooKeeper 集群。 因此，如果部署了 3 个 Zookeeper 节点（非 Observer），则如果至少有 2个节点可用则整个集群就可用，意味着 1 个节点故障，不影响 Zookeeper 集群对外提供服务；如果部署了 5 个节点，意味着 2 个节点同时故障，Zookeeper 集群依然能够正常对外提供服务。</description>
    </item>
    
    <item>
      <title>[译]讨论在 Linux Control Groups 中运行 Java 应用程序的暂停问题</title>
      <link>https://andyyin.github.io/blog/%E8%AE%A8%E8%AE%BA%E5%9C%A8-linux-control-groups-%E4%B8%AD%E8%BF%90%E8%A1%8C-java-%E5%BA%94%E7%94%A8%E7%A8%8B%E5%BA%8F%E7%9A%84%E6%9A%82%E5%81%9C%E9%97%AE%E9%A2%98/</link>
      <pubDate>Thu, 09 May 2019 00:00:00 +0000</pubDate>
      
      <guid>https://andyyin.github.io/blog/%E8%AE%A8%E8%AE%BA%E5%9C%A8-linux-control-groups-%E4%B8%AD%E8%BF%90%E8%A1%8C-java-%E5%BA%94%E7%94%A8%E7%A8%8B%E5%BA%8F%E7%9A%84%E6%9A%82%E5%81%9C%E9%97%AE%E9%A2%98/</guid>
      <description>说明 本篇原文来自 LinkedIn 的 Zhenyun Zhuang，原文：Application Pauses When Running JVM Inside Linux Control Groups[1]，在容器化的进程中，或多或少会对现有应用程序带来一些问题，这篇文章讲的是 LinkedIn 在使用 cgroups 构建容器化产品过程中，发现资源限制策略对 Java 应用程序性能会产生一些影响，文章深入分析问题根本原因，并给出解决方案。笔者看过后，觉得非常赞，因此翻译后献给大家，希望对大家有帮助。
前言 基于 Linux cgroups[2]的解决方案（例如，Docker[3]，CoreOS[4]）越来越多地用于在同一主机上托管多个应用程序。我们一直在 LinkedIn 上使用 cgroups 来构建我们自己的容器化[5]产品 LPS[6]（LinkedIn 平台即服务），并研究资源限制策略对应用程序性能的影响。这篇文章介绍了我们关于 CPU 调度如何影响 cgroups 中 Java 应用程序性能的一些发现。我们发现，在将 CFS[7]（完全公平调度程序）与 CFS 带宽控制的配额结合使用时，Java 应用程序可能会有越来越长的暂停。在这些暂停期间，应用程序不能响应用户请求，因此，这是我们需要分析和解决这个严重性能问题。 这些增多的暂停是由 JVM 的 GC（垃圾收集）机制和 CFS 调度之间的交互引起的。在 CFS 中，为 cgroup 分配了一定的 CPU 配额（即 cfs_quota），这会被 JVM GC 的多线程活动快速耗尽，从而导致应用程序受到限制。例如，可能会发生以下情况：
 如果一个应用程序在一个调度期间积极地使用其 CPU 配额，那么该应用程序就会受到限制（不再使用 CPU），并在调度期间的剩余持续时间内停止响应。 多线程的 JVM GC 会使问题更加严重，因为应用程序的所有线程都计算了cfs_quota（配额）。因此，CPU 配额可能会更快地用完。JVM GC 有许多非 STW（stop the world）的并发阶段。但是，它们的运行也会导致更快的使用完 CPU 配额，因此，实际上将整个应用程序设置为 STW（stop the world）。  在本文中，我们将分享我们研究这个问题之后的发现，以及我们关于 CFS/JVM 调优以减轻负面影响的建议。具体而言：</description>
    </item>
    
    <item>
      <title>[译]高吞吐低延迟 Java 应用的 GC 优化</title>
      <link>https://andyyin.github.io/blog/%E9%AB%98%E5%90%9E%E5%90%90%E4%BD%8E%E5%BB%B6%E8%BF%9F-java-%E5%BA%94%E7%94%A8%E7%9A%84-gc-%E4%BC%98%E5%8C%96/</link>
      <pubDate>Sun, 21 Apr 2019 00:00:00 +0000</pubDate>
      
      <guid>https://andyyin.github.io/blog/%E9%AB%98%E5%90%9E%E5%90%90%E4%BD%8E%E5%BB%B6%E8%BF%9F-java-%E5%BA%94%E7%94%A8%E7%9A%84-gc-%E4%BC%98%E5%8C%96/</guid>
      <description>说明 本篇原文作者是 LinkedIn 的 Swapnil Ghike，这篇文章讲述了 LinkedIn 的 Feed 产品的 GC 优化过程，虽然文章写作于 April 8, 2014，但其中的很多内容和知识点非常有参考意义。因此，翻译后献给各位同学。 原文链接：Garbage Collection Optimization for High-Throughput and Low-Latency Java Applications。
背景 高性能应用构成了现代网络的支柱。LinkedIn 内部有许多高吞吐量服务来满足每秒成千上万的用户请求。为了获得最佳的用户体验，以低延迟响应这些请求是非常重要的。
例如，我们的用户经常使用的产品是 Feed —— 它是一个不断更新的专业活动和内容的列表。Feed 在 LinkedIn 的系统中随处可见，包括公司页面、学校页面以及最重要的主页资讯信息。基础 Feed 数据平台为我们的经济图谱（会员、公司、群组等）中各种实体的更新建立索引，它必须高吞吐低延迟地实现相关的更新。 为了将这些高吞吐量、低延迟类型的 Java 应用程序用于生产，开发人员必须确保在应用程序开发周期的每个阶段都保持一致的性能。确定最佳垃圾收集（Garbage Collection, GC）配置对于实现这些指标至关重要。
这篇博文将通过一系列步骤来明确需求并优化 GC，它的目标读者是对使用系统方法进行 GC 优化来实现应用的高吞吐低延迟目标感兴趣的开发人员。在 LinkedIn 构建下一代 Feed 数据平台的过程中，我们总结了该方法。这些方法包括但不限于以下几点：并发标记清除（Concurrent Mark Sweep，CMS） 和 G1 垃圾回收器的 CPU 和内存开销、避免长期存活对象导致的持续 GC、优化 GC 线程任务分配提升性能，以及可预测 GC 停顿时间所需的 OS 配置。
优化 GC 的正确时机？ GC 的行为可能会因代码优化以及工作负载的变化而变化。因此，在一个已实施性能优化的接近完成的代码库上进行 GC 优化非常重要。而且在端到端的基本原型上进行初步分析也很有必要，该原型系统使用存根代码并模拟了可代表生产环境的工作负载。这样可以获取该架构延迟和吞吐量的真实边界，进而决定是否进行纵向或横向扩展。</description>
    </item>
    
    <item>
      <title>技术人该有的六个意识</title>
      <link>https://andyyin.github.io/blog/%E6%8A%80%E6%9C%AF%E4%BA%BA%E8%AF%A5%E6%9C%89%E7%9A%84%E7%9A%84%E5%85%AD%E4%B8%AA%E6%84%8F%E8%AF%86/</link>
      <pubDate>Mon, 15 Apr 2019 00:00:00 +0000</pubDate>
      
      <guid>https://andyyin.github.io/blog/%E6%8A%80%E6%9C%AF%E4%BA%BA%E8%AF%A5%E6%9C%89%E7%9A%84%E7%9A%84%E5%85%AD%E4%B8%AA%E6%84%8F%E8%AF%86/</guid>
      <description>这篇文章讲的是百度在数年前要求每个入职的工程师必须被灌输的六个职场意识，这六个意识非常有价值，不管对技术 leader 还是职场小白都应该非常有指导意义。 这里分享给大家，与同在职场中奋斗的同学们共同参考。
内容摘要   质量意识 时间意识 沟通意识 团队意识 求实意识 进取意识   1. 质量意识 1.1 流程意识   world class procedure：用流程解决具有共性的、重复性问题，提高效率 既有的流程应严格遵守；没有流程的应创建流程   1.2 要对自己的工作质量负责，不要期待别人来发现自己的问题 1.3 “稳定”压倒一切，线上服务最重要   用户体验最重要 工作安排：二八原则 优先解决线上服务稳定性问题   1.4 不要“想当然”   不要默认“没问题”，而是缺省认为“有问题”；“肯定没问题”一定有问题 反复核实(double check)十分重要 “我以为他们已经开始做，但我也没有跟他们确认一下” —— 导致项目延期 “我以为这个接口是这样定义，但谁想到是那样的” —— 导致程序崩溃 “我以为发出邮件，他肯定就知道了” —— 实际上，他/她根本不在相应的邮件列表中   2. 时间意识 2.1 目标管理、结果导向   弹性工作制：上下班时间自由支配 关键是要按时保质完成工作   2.2 只争朝夕，争分夺秒   激烈的产业竞争环境 不要拖到最后才开始工作，因为总可能会有意外 能今天做完的绝不拖到明天   2.</description>
    </item>
    
    <item>
      <title>再次剖析 “一个 JVM 参数引发的频繁 CMS GC”</title>
      <link>https://andyyin.github.io/blog/%E5%86%8D%E6%AC%A1%E5%89%96%E6%9E%90-%E4%B8%80%E4%B8%AA-jvm-%E5%8F%82%E6%95%B0%E5%BC%95%E5%8F%91%E7%9A%84%E9%A2%91%E7%B9%81-cms-gc/</link>
      <pubDate>Wed, 10 Apr 2019 00:00:00 +0000</pubDate>
      
      <guid>https://andyyin.github.io/blog/%E5%86%8D%E6%AC%A1%E5%89%96%E6%9E%90-%E4%B8%80%E4%B8%AA-jvm-%E5%8F%82%E6%95%B0%E5%BC%95%E5%8F%91%E7%9A%84%E9%A2%91%E7%B9%81-cms-gc/</guid>
      <description>前言 前几天这篇《一个 JVM 参数引发的频繁 CMS GC》文章发出之后，反应比较激烈，因为这可能与同学们通常 GC 优化经验相悖，通常有很多业务都通过添加 -XX:+CMSScavengeBeforeRemark 参数，来降低 CMS-remark 的时间，进而提升业务的性能以及可用性。
背景 这里给出几位同学比较典型的的想法和建议： “同学1”：“-XX:+CMSScavengeBeforeRemark 参数引发的频繁 CMS GC 有失偏颇，其实根本原因是第一次 CMS GC 过程中的 Young GC 发生了 ‘promotion failed’ 导致了 to space 不为空”。
“同学2”：“我们线上也用了这个参数，没有出现频繁 CMS GC 的现象，我猜测你那种是特殊场景导致的，并不是用了那个参数就一定会导致频繁 CMS GC，大部分情况下加上这个参数是有好处的”。
“同学3”：“是不是可以降低 -XX:CMSInitiatingOccupancyFraction 参数的值来，比如70，让 Young GC成功”。
针对这几位同学提到的想法和建议，我又重新思考这个案例，来解答下这些的问题。因此，这篇文章是《一个 JVM 参数引发的频繁 CMS GC》的进阶版本。
主要内容 本文主要讲解：
  纠正《一个 JVM 参数引发的频繁 CMS GC》文章中的一个分析错误 -XX:+CMSScavengeBeforeRemark 参数到底是不是引起频繁 CMS GC 的原因 什么场景会出现这种问题 有哪些优化策略   内容 纠正《一个 JVM 参数引发的频繁 CMS GC》文章中的一个错误 这里纠正《一个 JVM 参数引发的频繁 CMS GC》文中提到的关于 “OldGen 的使用占比情况都没有达到 80%，什么原因导致的 CMS GC” 问题原因分析中的一个错误。</description>
    </item>
    
    <item>
      <title>一个 JVM 参数引发的频繁 CMS GC</title>
      <link>https://andyyin.github.io/blog/%E4%B8%80%E4%B8%AA-jvm-%E5%8F%82%E6%95%B0%E5%BC%95%E5%8F%91%E7%9A%84%E9%A2%91%E7%B9%81-cms-gc/</link>
      <pubDate>Wed, 03 Apr 2019 00:00:00 +0000</pubDate>
      
      <guid>https://andyyin.github.io/blog/%E4%B8%80%E4%B8%AA-jvm-%E5%8F%82%E6%95%B0%E5%BC%95%E5%8F%91%E7%9A%84%E9%A2%91%E7%B9%81-cms-gc/</guid>
      <description>前言 了解 CMS GC 的同学，一定知道 -XX:CMSScavengeBeforeRemark 参数，它是用来开启或关闭在 CMS-remark 阶段之前的清除（Young GC）尝试。
大家都知道CMS GC 只会回收 OldGen 的对象，那为什么需要这个参数？ 由于 YoungGen 存在引用 OldGen 对象的情况，因此 CMS-remark 阶段会将 YoungGen 作为 OldGen 的 “GC ROOTS” 进行扫描，防止回收了不该回收的对象。而配置 -XX:+CMSScavengeBeforeRemark 参数，在 CMS GC 的 CMS-remark 阶段开始前先进行一次 Young GC，有利于减少 Young Gen 对 Old Gen 的无效引用，降低 CMS-remark 阶段的时间开销。
这篇文章的内容是业务开发同学遇到的奇怪的频繁 CMS GC 问题，我们一起定位排查，最终发现跟 -XX:CMSScavengeBeforeRemark 参数相关。
问题 频繁 Full GC 业务开发同学通过监控发现线上一台机器频繁 CMS GC，下图是 CMS GC 监控图，大约从 20 点 5-15 分，每分钟 8-11 次的持续 CMS GC。  说明：公司监控对 Old GC 与 Full GC 是不区分的，案例中讲的其实是 CMS GC。</description>
    </item>
    
    <item>
      <title>一次 Young GC 的优化实践（FinalReference 相关）</title>
      <link>https://andyyin.github.io/blog/%E4%B8%80%E6%AC%A1-young-gc-%E7%9A%84%E4%BC%98%E5%8C%96%E5%AE%9E%E8%B7%B5finalreference-%E7%9B%B8%E5%85%B3/</link>
      <pubDate>Sat, 23 Feb 2019 00:00:00 +0000</pubDate>
      
      <guid>https://andyyin.github.io/blog/%E4%B8%80%E6%AC%A1-young-gc-%E7%9A%84%E4%BC%98%E5%8C%96%E5%AE%9E%E8%B7%B5finalreference-%E7%9B%B8%E5%85%B3/</guid>
      <description>前言 博客已经好久没有更新了，主要原因是 18 年下半年工作比较忙，另外也没有比较有意思的题材，所以迟迟没有更新。 此篇是 18 年底的微信上的某同学提供的一个 Young GC 问题案例，找我帮忙解决。这个 GC 案例比较有意思，虽然过去有一段时间了，但是想想觉得还是有必要写出来，应该对大家很有帮助。 排查问题有点像侦探断案，先分析各种可能性，再按照获得的一个个证据，去排除各种可能性、然后定位原因，最终解决问题。
问题 有个同学在微信上问我，有没有办法排查 YoungGC 效率低的问题？听到这话，我也是不知从何说起，就让他说下具体情况。 具体情况是： 有个服务在没有 RPC 调用时，YoungGC 时间大约在 4-5ms，但是有 RPC 调用时，YoungGC 的耗时在 40ms 以上，几乎没有什么对象晋升，频率 4-5 秒一次。GC 日志截图如下。 后来他为了排查问题，把服务只留一个 RPC 调用，结果 YoungGC 更严重，变成 100ms 以上，几乎没有什么对象晋升，另外 RPC 调用耗时在 4-5ms，压测的 QPS 也比较低，只有几个线程在压。GC 日志截图如下。 另外还有一个奇葩的现象，如果测试时，只留一个调用耗时更长的 RPC 进行测试，发现 Young GC 耗时会小一点。 这里也提供下提供了下 GC 参数如下：
//GC 参数 -Xmn700m -Xms3072m -Xmx3072m -XX:SurvivorRatio=8 -XX:MetaspaceSize=384m -XX:MaxMetaspaceSize=384m -XX:+UseConcMarkSweepGC -XX:+CMSScavengeBeforeRemark -XX:CMSInitiatingOccupancyFraction=80 -XX:+UseCMSInitiatingOccupancyOnly -XX:+PrintGC -XX:+PrintGCDateStamps -XX:+PrintGCDetails  可以看到，整个堆 3072M，Young Gen只有 700M，都不大。</description>
    </item>
    
    <item>
      <title>PhantomReference 导致 CMS GC 耗时严重</title>
      <link>https://andyyin.github.io/blog/phantomreference-%E5%AF%BC%E8%87%B4-cms-gc-%E8%80%97%E6%97%B6%E4%B8%A5%E9%87%8D/</link>
      <pubDate>Fri, 02 Feb 2018 00:00:00 +0000</pubDate>
      
      <guid>https://andyyin.github.io/blog/phantomreference-%E5%AF%BC%E8%87%B4-cms-gc-%E8%80%97%E6%97%B6%E4%B8%A5%E9%87%8D/</guid>
      <description>介绍 GC 优化关键是找到优化的点，如果明确 GC 过程中耗时的阶段在哪里，优化起来应该也就不难了。这篇文章主要讲述最近一次 CMS GC 优化过程，是一次分享，也是一次总结。闲话少说，我们开始吧。
现象 上图很明显（公司内部监控没有区分 Old GC 和 Full GC）Old GC 耗时严重，大致看了几天的监控，基本上每次都很耗时，时间约 1s 左右，这里统计的 1s 左右的耗时指的是 stop-the-world 的时间。
排查 那到底哪里耗时呢？我们得去看看 GC 日志，日志中有更多的信息
2018-01-13T19:21:36.254: [GC [1 CMS-initial-mark: 2097444K(4194304K)] 2143492K(6081792K), 0.2197240 secs] [Times: user=0.01 sys=0.17, real=0.22 secs] 2018-01-13T19:21:36.474: [CMS-concurrent-mark-start] 2018-01-13T19:21:36.654: [CMS-concurrent-mark: 0.180/0.180 secs] [Times: user=0.65 sys=0.07, real=0.18 secs] 2018-01-13T19:21:36.654: [CMS-concurrent-preclean-start] 2018-01-13T19:21:36.700: [CMS-concurrent-preclean: 0.045/0.045 secs] [Times: user=0.05 sys=0.01, real=0.04 secs] 2018-01-13T19:21:36.700: [CMS-concurrent-abortable-preclean-start] CMS: abort preclean due to time 2018-01-13T19:21:41.</description>
    </item>
    
    <item>
      <title>System.gc() 源码解读</title>
      <link>https://andyyin.github.io/blog/system.gc-%E6%BA%90%E7%A0%81%E8%A7%A3%E8%AF%BB/</link>
      <pubDate>Sun, 14 Jan 2018 00:00:00 +0000</pubDate>
      
      <guid>https://andyyin.github.io/blog/system.gc-%E6%BA%90%E7%A0%81%E8%A7%A3%E8%AF%BB/</guid>
      <description>介绍 System.gc()，大家应该也有所了解，是 JDK 提供的触发 Full GC 的一种方式，会触发 Full GC，其间会 stop the world，对业务影响较大，一般情况下不会直接使用。
 那它是如何实现的呢？ 另外有哪些参数可以进行优化呢？ 我们带着问题来对相关源码解读一下。
 实现 JDK实现 /** * Runs the garbage collector. * &amp;lt;p&amp;gt; * Calling the &amp;lt;code&amp;gt;gc&amp;lt;/code&amp;gt; method suggests that the Java Virtual * Machine expend effort toward recycling unused objects in order to * make the memory they currently occupy available for quick reuse. * When control returns from the method call, the Java Virtual * Machine has made a best effort to reclaim space from all discarded * objects.</description>
    </item>
    
    <item>
      <title>依赖包滥用 System.gc() 导致的 Full GC</title>
      <link>https://andyyin.github.io/blog/%E4%BE%9D%E8%B5%96%E5%8C%85%E6%BB%A5%E7%94%A8-system.gc-%E5%AF%BC%E8%87%B4%E7%9A%84-full-gc/</link>
      <pubDate>Wed, 11 Oct 2017 00:00:00 +0000</pubDate>
      
      <guid>https://andyyin.github.io/blog/%E4%BE%9D%E8%B5%96%E5%8C%85%E6%BB%A5%E7%94%A8-system.gc-%E5%AF%BC%E8%87%B4%E7%9A%84-full-gc/</guid>
      <description>介绍 业务部门的一个同事遇到个奇怪的 Full GC 问题，有个服务迁移到新的应用后，一直频繁 Full GC。新应用机器的配置是 4c 8g，老应用是 4c 4g，老应用 GC 都很正常，并且代码没有变更，所以比较奇怪。
现象 问题的现象是，从监控图上看一直有大量的 Full GC 排查 遇到这个问题，一般都是先看看各个区的内存占用情况： 从监控图上看 Old Gen、Young Gen、Perm Gen，没什么问题，不会触发 Full GC，当然这里看各个 Gen 是否会触发 Full GC 需要结合 JVM 参数配置来看。
顺便也看了下 GC 日志，一直狂暴 CMS GC 日志，而且可以看到老年代使用空间也不大，细心可以发现，大量的 CMS GC 中夹杂着 Young、Perm Gen 的回收，所以其实是 Full GC。GC 日志如下： 老应用的 JVM 参数配置 新应用的 JVM 参数配置 通过上面的观察，再根据一般触发 CMS GC 几个可能性：
 Old Gen 使用达到一定的比率，默认为 92%，这里看 CMSInitiatingOccupancyFraction=80%，而实际才使用 2%（看监控图表）不到，所以排除这种情况。 配置了 CMSClassUnloadingEnabled，且 Perm Gen 的使用达到一定的比率默认为 92%，这里看 CMSInitiatingPermOccupancyFraction=80%，而实际才使用 30％（看监控图表）不到，所以排除这种情况。 配置了 ExplictGCInvokesConcurrent 且未配置 DisableExplicitGC 的情况下显示调用了 System.</description>
    </item>
    
    <item>
      <title>长连接和心跳的那些事儿</title>
      <link>https://andyyin.github.io/blog/%E9%95%BF%E8%BF%9E%E6%8E%A5%E5%92%8C%E5%BF%83%E8%B7%B3%E7%9A%84%E9%82%A3%E4%BA%9B%E4%BA%8B%E5%84%BF/</link>
      <pubDate>Sun, 30 Jul 2017 00:00:00 +0000</pubDate>
      
      <guid>https://andyyin.github.io/blog/%E9%95%BF%E8%BF%9E%E6%8E%A5%E5%92%8C%E5%BF%83%E8%B7%B3%E7%9A%84%E9%82%A3%E4%BA%9B%E4%BA%8B%E5%84%BF/</guid>
      <description>介绍  长连接  首先这里所说的连接是指网络传输层的使用 TCP 协议经过三次握手建立的连接；长连接是指建立的连接长期保持，不管此时有无数据包的发送；有长连接自然也有短连接，短连接是指双方有数据发送时，就建立连接，发送几次请求后，就主动或者被动断开连接。
 心跳  心跳这个名字比较形象，就像人体心跳一样，是用来检测一个系统是否存活或者网络链路是否通畅的一种方式，其一般做法是定时向被检测系统发送心跳包，被检测系统收到心跳包进行回复，收到回复说明对方存活。
心跳和长连接在一起介绍的原因是，心跳能够给长连接提供保活功能，能够检测长连接是否正常（这里所说的保活不能简单的理解为保证活着，具体来说应该是一旦链路死了，不可用了，能够尽快知道，然后做些其他的高可用措施，来保证系统的正常运行）。
优势 长连接的优势
 减少连接建立过程的耗时  大家都知道 TCP 连接建立需要三次握手，三次握手也就说需要三次交互才能建立一个连接通道，同城的机器之间的大概是ms级别的延时，影响还不大，如果是北京和上海两地机房，走专线一来一回大概需要30ms，如果使用长连接，这个优化还是十分可观的。
 方便实现 push 数据  数据交互－推模式实现的前提是网络长连接，有了长连接，连接两端很方便的互相push数据，来进行交互。
疑问  TCP 连接到底是什么？  所谓的 TCP 连接不是物理的连接，是为了实现数据的可靠传输由通信双方进行三次握手交互而建立的逻辑上的连接，通信双方都需要维护这样的连接状态信息。比如 netstat 经常看到连接的状态为 ESTABLISHED，表示当前处于连接状态。（这里需要注意的是这个 ESTABLISHED 的连接状态只是操作系统认为当前还处在连接状态）
 是不是建立了长连接，就可以高枕无忧了呢？  建立好长连接，两端的操作系统都维护了连接已经建立的状态，是不是这时向对端发送数据一定能到达呢？ 答案是否定的。 可能此时链路已经不通，只是 TCP 层还没有感知到这一信息，操作系统层面显示的状态依然是连接状态，而且因为 TCP 层还认为连接是 ESTABLISHED，所以作为应用层自然也就无法感知当前的链路不通。 这种情况会导致什么问题？ 如果此时有数据想要传输，显然，数据是无法传送到对端，但是 TCP 协议为了保证可靠性，会重传请求，如果问题只是网线接头松了，导致网络不通，此时如果及时将网线接头接好，数据还是能正常到达对端，且 TCP 的连接依然是 ESTABLISHED，不会有任何变化。但不是任何时候都这么巧，有时就是某段链路瘫痪了，或者主机挂了，系统异常关闭了等。这时候如果应用系统不能感知到，是件很危险的事情。
 长连接怎么保活？  TCP 协议实现中，是有保活机制的，也就是 TCP的 KeepAlive 机制（此机制并不是 TCP 协议规范中的内容，由操作系统去实现），KeepAlive 机制开启后，在一定时间内（一般时间为 7200s，参数 tcp_keepalive_time）在链路上没有数据传送的情况下，TCP 层将发送相应的 KeepAlive 探针以确定连接可用性，探测失败后重试 10（参数 tcp_keepalive_probes）次，每次间隔时间 75s（参数 tcp_keepalive_intvl），所有探测失败后，才认为当前连接已经不可用。这些参数是机器级别，可以调整。</description>
    </item>
    
    <item>
      <title>Fancy App 1</title>
      <link>https://andyyin.github.io/itemized/item1/</link>
      <pubDate>Thu, 22 Jun 2017 00:00:00 +0000</pubDate>
      
      <guid>https://andyyin.github.io/itemized/item1/</guid>
      <description> App 1 </description>
    </item>
    
    <item>
      <title>Fancy App 2</title>
      <link>https://andyyin.github.io/itemized/item2/</link>
      <pubDate>Thu, 22 Jun 2017 00:00:00 +0000</pubDate>
      
      <guid>https://andyyin.github.io/itemized/item2/</guid>
      <description> App 2 </description>
    </item>
    
    <item>
      <title>Fancy App 3</title>
      <link>https://andyyin.github.io/itemized/item3/</link>
      <pubDate>Thu, 22 Jun 2017 00:00:00 +0000</pubDate>
      
      <guid>https://andyyin.github.io/itemized/item3/</guid>
      <description> App 3 </description>
    </item>
    
    <item>
      <title>Fancy App 4</title>
      <link>https://andyyin.github.io/itemized/item4/</link>
      <pubDate>Thu, 22 Jun 2017 00:00:00 +0000</pubDate>
      
      <guid>https://andyyin.github.io/itemized/item4/</guid>
      <description> App 4 </description>
    </item>
    
    <item>
      <title>Java 堆外内存回收原理</title>
      <link>https://andyyin.github.io/blog/java-%E5%A0%86%E5%A4%96%E5%86%85%E5%AD%98%E5%9B%9E%E6%94%B6%E5%8E%9F%E7%90%86/</link>
      <pubDate>Thu, 13 Apr 2017 00:00:00 +0000</pubDate>
      
      <guid>https://andyyin.github.io/blog/java-%E5%A0%86%E5%A4%96%E5%86%85%E5%AD%98%E5%9B%9E%E6%94%B6%E5%8E%9F%E7%90%86/</guid>
      <description>DirectByteBuffer 简介 DirectByteBuffer 这个类是 JDK 提供使用堆外内存的一种途径，当然常见的业务开发一般不会接触到，即使涉及到也可能是框架（如 Netty、RPC 等）使用的，对框架使用者来说也是透明的。
堆外内存的优势 堆外内存优势在 IO 操作上，对于网络 IO，使用 Socket 发送数据时，能够节省堆内存到堆外内存的数据拷贝，所以性能更高。看过 Netty 源码的同学应该了解，Netty 使用堆外内存池来实现零拷贝技术。对于磁盘 IO 时，也可以使用内存映射，来提升性能。 另外，更重要的几乎不用考虑堆内存烦人的 GC 问题。
堆外内存的创建 我们直接来看代码，首先向 Bits 类申请额度，Bits 类内部维护着当前已经使用的堆外内存值，会 check 当前申请的大小与已经使用的内存大小是否超过总的堆外内存大小（默认大小与堆内存差不多，其实是有细微区别的，拿 CMS GC 来举例，它的大小是新生代的最大值 - 一个 survivor 的大小 + 老生代的最大值），可以使用 -XX:MaxDirectMemorySize 参数指定堆外内存最大大小。
// DirectByteBuffer(int cap) { // package-private super(-1, 0, cap, cap); boolean pa = VM.isDirectMemoryPageAligned(); int ps = Bits.pageSize(); long size = Math.max(1L, (long)cap + (pa ? ps : 0)); Bits.</description>
    </item>
    
  </channel>
</rss>