<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.9.0">Jekyll</generator><link href="https://qtsang.github.io/feed.xml" rel="self" type="application/atom+xml" /><link href="https://qtsang.github.io/" rel="alternate" type="text/html" /><updated>2021-01-13T13:15:05+00:00</updated><id>https://qtsang.github.io/feed.xml</id><title type="html">九尾</title><subtitle>九尾行个人博客</subtitle><author><name>qtsang</name></author><entry><title type="html">Nginx安全漏洞处理</title><link href="https://qtsang.github.io/2020/10/19/Nginx%E5%AE%89%E5%85%A8%E6%BC%8F%E6%B4%9E%E5%A4%84%E7%90%86/" rel="alternate" type="text/html" title="Nginx安全漏洞处理" /><published>2020-10-19T00:00:00+00:00</published><updated>2020-10-19T00:00:00+00:00</updated><id>https://qtsang.github.io/2020/10/19/Nginx%E5%AE%89%E5%85%A8%E6%BC%8F%E6%B4%9E%E5%A4%84%E7%90%86</id><content type="html" xml:base="https://qtsang.github.io/2020/10/19/Nginx%E5%AE%89%E5%85%A8%E6%BC%8F%E6%B4%9E%E5%A4%84%E7%90%86/">&lt;blockquote&gt;
  &lt;p&gt;不管是互联网企业还是传统企业，大多数喜欢使用NGINX作为反向代理，然后不合理的使用会存在一些安全隐患，下面介绍一些常用隐患处理方法。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h6 id=&quot;隐藏应用服务器名称&quot;&gt;隐藏应用服务器名称&lt;/h6&gt;

&lt;p&gt;修改NGINX源将，将SERVER名称换成X-WEB(此处自定义)&lt;/p&gt;

&lt;p&gt;vim src/http/ngx_http_header_filter_module.c  #&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;static char ngx_http_server_string[] = &quot;Server: X-Web&quot; CRLF;
static char ngx_http_server_full_string[] = &quot;Server:X-Web&quot; NGINX_VER CRLF;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;vim src/http/ngx_http_special_response.c  #将源代码的nginx更换成X-Web&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;static u_char ngx_http_error_tail[] =
&quot;&amp;lt;hr&amp;gt;&amp;lt;center&amp;gt;X-Web&amp;lt;/center&amp;gt;&quot; CRLF
&quot;&amp;lt;/body&amp;gt;&quot; CRLF
&quot;&amp;lt;/html&amp;gt;&quot; CRLF
;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h6 id=&quot;隐藏nginx版本号&quot;&gt;隐藏NGINX版本号&lt;/h6&gt;

&lt;p&gt;vim conf/nginx.conf&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;server_tokens                  off;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h6 id=&quot;限制可用方法&quot;&gt;限制可用方法&lt;/h6&gt;

&lt;p&gt;限定请求方法，只支持GET和POST&lt;/p&gt;

&lt;p&gt;vim conf/nginx.conf&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; location / {
        if ($request_method !~* GET|POST) {
            return  403;
        }
         proxy_pass        http://XXXXX;
  }
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;</content><author><name>qtsang</name></author><category term="系统运维" /><summary type="html">不管是互联网企业还是传统企业，大多数喜欢使用NGINX作为反向代理，然后不合理的使用会存在一些安全隐患，下面介绍一些常用隐患处理方法。</summary></entry><entry><title type="html">软件架构模式</title><link href="https://qtsang.github.io/2020/10/16/%E8%BD%AF%E4%BB%B6%E6%9E%B6%E6%9E%84%E6%A8%A1%E5%BC%8F%E4%BB%8B%E7%BB%8D/" rel="alternate" type="text/html" title="软件架构模式" /><published>2020-10-16T00:00:00+00:00</published><updated>2020-10-16T00:00:00+00:00</updated><id>https://qtsang.github.io/2020/10/16/%E8%BD%AF%E4%BB%B6%E6%9E%B6%E6%9E%84%E6%A8%A1%E5%BC%8F%E4%BB%8B%E7%BB%8D</id><content type="html" xml:base="https://qtsang.github.io/2020/10/16/%E8%BD%AF%E4%BB%B6%E6%9E%B6%E6%9E%84%E6%A8%A1%E5%BC%8F%E4%BB%8B%E7%BB%8D/">&lt;p&gt;系统架构（System Architecture），软件架构（Soft Architecture）是 IT 领域常见的名词，架构设计是软件系统构建过程中极其关键的一部分。&lt;/p&gt;

&lt;blockquote&gt;
  &lt;h2 id=&quot;系统架构为什么重要&quot;&gt;&lt;strong&gt;系统架构为什么重要&lt;/strong&gt;&lt;/h2&gt;
&lt;/blockquote&gt;

&lt;p&gt;我们知道摩尔定律——计算机硬件的能力大致每两年提高一倍的速度发展。然而软件开发的流程却没有这样的提速过程，开发成本也没有下降，系统架构的设计方法论和设计模式不断变化，而这个重要的流程依旧没有一个完全可靠和一劳永逸的解决方案。为什么？软件开发过程有什么特别的难题？有下面几点：&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;复杂性（Complexity）&lt;/p&gt;

    &lt;p&gt;软件可以说是人类创造的最复杂的系统类型。软件的各个模块之间有各种显性或隐性的依赖关系，随着系统的成长和模块的增多，这些关系的数量往往以几何级数的速度增长。而理解运用这些复杂性的人并没有太多的变化。&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;不可见性（Invisibility）&lt;/p&gt;

    &lt;p&gt;软件工程师能直接看见源代码，但是源代码不是软件本身。并且静态的源代码和运行的系统也不一样，软件运行环境的复杂性也增加了软件系统的不可预测性。软件系统不能以简单的方式描述出来，设计文档，描述说明，流程图，架构图这些也不过是让复杂的软件系统以更易于理解和易于交流的方式展示，却依旧不能完全描述系统的全貌。&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;易变性（Changeability）&lt;/p&gt;

    &lt;p&gt;修改软件看似很容易，修改软件比修改硬件容易多了，修改软件系统也比修改一座巍立建筑物容易的多。所以人们自然地期待软件系统能够适应未来的变化。但变化却是复杂的，环境也是复杂的，这些复杂的情况往往让一个易于修改的事情却变成一件越来越困难的事情。&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;服从性（Conformity）&lt;/p&gt;

    &lt;p&gt;软件系统不能独立存在，它总是运行在硬件上面，也总是要服从系统中其他组成部分的要求，也要服从用户的要求、行业的要求。&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;软件系统的以上特性使得系统架构的设计显得尤其重要。系统架构设计通过以下方式来解决上面的软件难题：&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;抽象&lt;/p&gt;

    &lt;p&gt;抽象是系统架构设计的重要一步。抽象是将复杂的概念简单化。在最高层次上，将软件系统抽象为&lt;strong&gt;对象&lt;/strong&gt;和&lt;strong&gt;过程&lt;/strong&gt;两个高层次概念。对象可以是系统、组件、接口、类、方法等等不同层次的概念，过程是系统运行的方式和流程。抽象使具象的事物概念化，从而确定边界，易于理解，易于交流。&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;分解&lt;/p&gt;

    &lt;p&gt;分解与组合相互作用。分解就是将高层次的抽象概念分解成低层次的抽象概念，就是将实体分成小的部件或组成部分，&lt;strong&gt;在应对复杂度的诸多方式中，”分而治之“是一项基本策略，它把大问题持续分解成小问题，直到每一个小问题都能够解决为止。&lt;/strong&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;语言&lt;/p&gt;

    &lt;p&gt;语言的边界就是世界的边界。领域语言、设计语言确定系统的&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;what&lt;/code&gt;、&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;how&lt;/code&gt;和&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;why&lt;/code&gt;。语言使系统显见于文档，设计图等等易于理解的层次，也使得系统的易变性被规范在可预见和可控制的范围之中。&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
  &lt;h2 id=&quot;几种架构模式&quot;&gt;&lt;strong&gt;几种架构模式&lt;/strong&gt;&lt;/h2&gt;
&lt;/blockquote&gt;

&lt;p&gt;一起来看下常见的架构模式：&lt;strong&gt;Client-Server、Peer to Peer、MVC、Layered、Distribute-Cluster、Micro-Service、Even-Source、Hexagonal&lt;/strong&gt;&lt;/p&gt;

&lt;h3 id=&quot;client-server&quot;&gt;Client-Server&lt;/h3&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/2021-1/640.png&quot; alt=&quot;640&quot; /&gt;&lt;/p&gt;

&lt;p&gt;client-server 模式以请求-响应方式工作，客户端发送请求信息，服务端接受请求，作出相应处理，然后发回响应信息&lt;/p&gt;

&lt;h3 id=&quot;peer-to-peer&quot;&gt;Peer to Peer&lt;/h3&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/2021-1/651.png&quot; alt=&quot;651&quot; /&gt;&lt;/p&gt;

&lt;p&gt;端对端服务模式（Peer to Peer，简称 P2P），亦称为“点对点模式”，是指通过互联网将个人与个人连接起来，绕开中心平台而直接提供服务、完成交易的模式。&lt;/p&gt;

&lt;h3 id=&quot;mvc&quot;&gt;MVC&lt;/h3&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/2021-1/652.png&quot; alt=&quot;img&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Model-View-Controller，MVC 架构是面向对象编程的一大进步。服务将逻辑划分为三个不同的组建：Model——模型，即数据，通常存储在数据库中，在内存中进行逻辑操作。View——用户可见的组建，用于用户交互和数据展示，如 Web GUI。Controller——逻辑操作，连接 Model 和 View 的组件，操作 Model 逻辑和 View 交互展示逻辑&lt;/p&gt;

&lt;h3 id=&quot;layered&quot;&gt;Layered&lt;/h3&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/2021-1/653.png&quot; alt=&quot;img&quot; /&gt;&lt;/p&gt;

&lt;p&gt;三层架构的经典和流行，以及大量 Web 后台框架对三层架构的靠近，使得 Web 后台开发简单到一个刚刚入门的开发人员就可以进行 web 开发。也正因为此，使得大部分 web 开发人员的思维受限于此，从而成为人人调侃的 CRUD-Boy。随着 MIS 系统时代的渐远，三层架构也开始在一些领域无法成为“银弹“。&lt;/p&gt;

&lt;p&gt;除去经典的三层架构。在领域驱动设计中，Eric Evans 设计了一种经典的四层架构，其在用户界面层与业务逻辑层之间引入了新的一层，即应用层（Application Layer）。其余几层也相应的有所调整。&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/2021-1/654.png&quot; alt=&quot;img&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;distribute-cluster&quot;&gt;Distribute-Cluster&lt;/h3&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/2021-1/655.png&quot; alt=&quot;img&quot; /&gt;&lt;/p&gt;

&lt;p&gt;应用的迭代速度也不断变快。单体应用的模式已经不适合互联网的快速发展。这样，后台分布式集群架构越来越流行。&lt;/p&gt;

&lt;h3 id=&quot;micro-service&quot;&gt;Micro-Service&lt;/h3&gt;

&lt;p&gt;微服务架构是一种架构模式，它提倡将单一应用程序划分成一组小的服务，服务之间相互协调、相互配合，为用户提供最终价值。每个服务运行在其独立的进程中，服务与服务间采用轻量级的通信机制互相沟通（通常基于 HTTP 的 RESTful API）。每个服务都围绕着具体业务进行构建，并且能够被独立地部署到生产环境。&lt;/p&gt;

&lt;p&gt;随着微服务的流行，微服务的很多问题也被越来越多的框架和服务解决掉了。我们以 Spring Cloud 技术栈为例：&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;SpringBoot：单体服务，快速创建项目，快速集成各种框架，易于测试，易于部署。&lt;/li&gt;
  &lt;li&gt;Feign：微服务独立部署，通过相关协议通信。Feign 就是一个简单的申明式通信框架，基于 HTTP restful。&lt;/li&gt;
  &lt;li&gt;Eureka：独立服务越来越多，服务实例也越来越多。服务治理便是必须的，Eureka 提供高可用的服务注册和服务发现功能。&lt;/li&gt;
  &lt;li&gt;Ribbon：Feign 只负责通信，Ribbon 提供客户端负载均衡，是系统优化的部分。&lt;/li&gt;
  &lt;li&gt;Hystrix：微服务将带来服务间复杂的依赖关系，分布式和集群的复杂度也将带来许多难以预料的问题。为防止复杂网络和复杂系统某一点的问题导致整个系统的雪崩状态，便有了 Hystrix，Hystrix 是 Spring Cloud 体系中优秀的断路器，可以在系统发生问题时进行服务降级，防止整体系统崩溃。&lt;/li&gt;
  &lt;li&gt;Zuul：统一网关，统一网关是以 Facade 模式，对外提供友好的接口，微服务化之后，服务将越来越多，越来越复杂，为了降低外部系统调用的复杂度，统一网关就是常用解决方案。&lt;/li&gt;
  &lt;li&gt;Config：服务划分越多，配置将越多，Spring cloud config 提供统一的配置管理。&lt;/li&gt;
  &lt;li&gt;Sleuth：服务监控和治理。监控是复杂系统必需的基础设施。系统感知、问题发现、性能定位都需要监控的加持。&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/2021-1/656.png&quot; alt=&quot;img&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;even-source&quot;&gt;Even-Source&lt;/h3&gt;

&lt;p&gt;事件溯源是最新流行一种应用程序体系结构模式。事件源将应用程序进行的状态更改建模为事件的不可变序列或“日志”。事件源不是在现场修改应用程序的状态，而是将触发状态更改的事件存储在不可变的日志中，并将状态更改建模为对日志中事件的响应。&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/2021-1/657.png&quot; alt=&quot;img&quot; /&gt;event-source&lt;/p&gt;

&lt;p&gt;CQRS 模式通常基事件溯源模式。在传统的体系结构中，使用同一数据模型查询和更新数据库。这十分简单，非常适用于基本的 CRUD 操作。但是，在更复杂的应用程序中，此方法会变得难以操作。例如，在读取方面，应用程序可能执行大量不同的查询，返回具有不同形状的数据传输对象 (DTO)。对象映射可能会变得复杂。在写入方面，模型可能实施复杂验证和业务逻辑。结果，模型执行太多操作，过度复杂。&lt;/p&gt;

&lt;p&gt;CQRS（命令查询的责任分离 Command Query Responsibility Segregation ）将读取和写入操作分成不同的模型，使用 &lt;strong&gt;命令&lt;/strong&gt; 更新数据，并使用 &lt;strong&gt;查询&lt;/strong&gt; 来读取数据。&lt;/p&gt;

&lt;h3 id=&quot;hexagonal&quot;&gt;Hexagonal&lt;/h3&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/2021-1/658.png&quot; alt=&quot;img&quot; /&gt;&lt;/p&gt;

&lt;p&gt;六边形架构又称“端口和适配器模式”，是 Alistair Cockburn 提出的一种具有对称性特征的架构风格。在这种架构中，系统通过适配器的方式与外部交互，将应用服务与领域服务封装在系统内部。&lt;/p&gt;

&lt;p&gt;六边形架构由以下三个组件组成：&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Ports：又可以分为输入端和输出端，是系统与其他系统交互的接口。&lt;/li&gt;
  &lt;li&gt;Adapters：与其他系统的适配层，一方面防止核心系统和领域被外部影响，即防腐;另一方面方便 api 使用。&lt;/li&gt;
  &lt;li&gt;Domain：应用和模型是程序的核心。&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;六边形架构的核心理念是：应用通过”端口”跟外部进行交互。在传统的分层架构中很容易跨越层间的边界，把业务逻辑渗透到其它层中去。六边形架构重要的就是“边界”和“领域”。六边形架构的初衷是为了解决技术与业务系统的解耦合问题，以及技术与技术间的解耦合问题，这一架构从设计模式中来，从业务的实体服务出发，将面向接口的设计具体化的端口协议和适配器实现，服务自身实现独立性和完备性&lt;/p&gt;</content><author><name>qtsang</name></author><category term="软件架构" /><summary type="html">系统架构（System Architecture），软件架构（Soft Architecture）是 IT 领域常见的名词，架构设计是软件系统构建过程中极其关键的一部分。</summary></entry><entry><title type="html">MYSQL分库分表</title><link href="https://qtsang.github.io/2020/10/13/Mysql%E5%88%86%E5%BA%93%E5%88%86%E8%A1%A8/" rel="alternate" type="text/html" title="MYSQL分库分表" /><published>2020-10-13T00:00:00+00:00</published><updated>2020-10-13T00:00:00+00:00</updated><id>https://qtsang.github.io/2020/10/13/Mysql%E5%88%86%E5%BA%93%E5%88%86%E8%A1%A8</id><content type="html" xml:base="https://qtsang.github.io/2020/10/13/Mysql%E5%88%86%E5%BA%93%E5%88%86%E8%A1%A8/">&lt;blockquote&gt;
  &lt;h2 id=&quot;什么是分库分表&quot;&gt;什么是分库分表&lt;/h2&gt;
&lt;/blockquote&gt;

&lt;p&gt;其实 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;分库&lt;/code&gt; 和 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;分表&lt;/code&gt; 是两个概念，只不过通常分库与分表的操作会同时进行，以至于我们习惯性的将它们合在一起叫做分库分表。&lt;/p&gt;

&lt;p&gt;分库分表是为了解决由于库、表数据量过大，而导致数据库性能持续下降的问题。按照一定的规则，将原本数据量大的数据库拆分成多个单独的数据库，将原本数据量大的表拆分成若干个数据表，使得单一的库、表性能达到最优的效果（响应速度快），以此提升整体数据库性能。&lt;/p&gt;

&lt;blockquote&gt;
  &lt;h2 id=&quot;如何分库分表&quot;&gt;如何分库分表&lt;/h2&gt;
&lt;/blockquote&gt;

&lt;p&gt;分库分表的核心理念就是对数据进行切分（&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Sharding&lt;/code&gt;），以及切分后如何对数据的快速定位与查询结果整合。而分库与分表都可以从：&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;垂直&lt;/code&gt;（纵向）和 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;水平&lt;/code&gt;（横向）两种纬度进行切分。&lt;/p&gt;

&lt;h3 id=&quot;垂直切分&quot;&gt;垂直切分&lt;/h3&gt;

&lt;p&gt;垂直切分有 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;垂直&lt;/code&gt; 分库 和 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;垂直&lt;/code&gt;分表。&lt;/p&gt;

&lt;h3 id=&quot;1垂直分库&quot;&gt;1、垂直分库&lt;/h3&gt;

&lt;p&gt;垂直分库相对来说是比较好理解的，核心理念就四个字：&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;专库专用&lt;/code&gt;。&lt;/p&gt;

&lt;p&gt;按业务类型对表进行分类，像订单、支付、优惠券、积分等相应的表放在对应的数据库中。开发者不可以跨库直连别的业务数据库，想要其他业务数据，对应业务方可以提供 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;API&lt;/code&gt; 接口，这就是微服务的初始形态。&lt;/p&gt;

&lt;p&gt;垂直分库很大程度上取决于业务的划分，但有时候业务间的划分并不是那么清晰，比如：订单数据的拆分要考虑到与其他业务间的关联关系，并不是说直接把订单相关的表放在一个库里这么简单。&lt;/p&gt;

&lt;p&gt;在一定程度上，垂直分库似乎提升了一些数据库性能，可实际上并没有解决由于单表数据量过大导致的性能问题，所以就需要配合水平切分方式来解决。&lt;/p&gt;

&lt;h3 id=&quot;2垂直分表&quot;&gt;2、垂直分表&lt;/h3&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;垂直分表&lt;/code&gt;是基于数据表的列（字段）为依据切分的，是一种大表拆小表的模式。&lt;/p&gt;

&lt;p&gt;例如：一张 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;order&lt;/code&gt; 订单表，将订单金额、订单编号等访问频繁的字段，单独拆成一张表，把 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;blob&lt;/code&gt; 类型这样的大字段或访问不频繁的字段，拆分出来创建一个单独的扩展表 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;work_extend&lt;/code&gt; ，这样每张表只存储原表的一部分字段，再将拆分出来的表分散到不同的库中。&lt;/p&gt;

&lt;p&gt;垂直分表&lt;/p&gt;

&lt;p&gt;我们知道数据库是以行为单位将数据加载到内存中，这样拆分以后核心表大多是访问频率较高的字段，而且字段长度也都较短，因而可以加载更多数据到内存中，来增加查询的命中率，减少磁盘IO，以此来提升数据库性能。&lt;/p&gt;

&lt;p&gt;库：将库按照不同业务进行拆分。比如说订单、商品、库存分成一个库，用户分成一个库&lt;/p&gt;

&lt;p&gt;表：将表按照访问频繁度进行拆分。比如说订单表有一个blob字段，可以把常用访问字段拆分开。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;垂直切分的优点&lt;/strong&gt;：&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;业务间数据解耦，不同业务的数据进行独立的维护、监控、扩展。&lt;/li&gt;
  &lt;li&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;/li&gt;
  &lt;li&gt;分布式事务管理难度增加。&lt;/li&gt;
  &lt;li&gt;数据库还是存在单表数据量过大的问题，并未根本上解决，需要配合水平切分&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;水平切分&quot;&gt;水平切分&lt;/h3&gt;

&lt;p&gt;前边说了垂直切分还是会存在单库、表数据量过大的问题，当我们的应用已经无法在细粒度的垂直切分时， 依旧存在单库读写、存储性能瓶颈，这时就要配合水平切分一起了，水平切分能大幅提升数据库性能。&lt;/p&gt;

&lt;h3 id=&quot;1水平分库&quot;&gt;1、水平分库&lt;/h3&gt;

&lt;p&gt;水平分库是把同一个表按一定规则拆分到不同的数据库中，每个库可以位于不同的服务器上，以此实现水平扩展，是一种常见的提升数据库性能的方式。&lt;/p&gt;

&lt;p&gt;这种方案往往能解决单库存储量及性能瓶颈问题，但由于同一个表被分配在不同的数据库中，数据的访问需要额外的路由工作，因此系统的复杂度也被提升了。&lt;/p&gt;

&lt;p&gt;例如下图，&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;订单DB_1&lt;/code&gt;、&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;订单DB_1&lt;/code&gt;、&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;订单DB_3&lt;/code&gt; 三个数据库内有完全相同的表 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;order&lt;/code&gt;，我们在访问某一笔订单时可以通过对订单的订单编号取模的方式 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;订单编号 mod 3 （数据库实例数）&lt;/code&gt; ，指定该订单应该在哪个数据库中操作。&lt;/p&gt;

&lt;h3 id=&quot;2水平分表&quot;&gt;2、水平分表&lt;/h3&gt;

&lt;p&gt;水平分表是在&lt;strong&gt;同一个数据库内&lt;/strong&gt;，把一张大数据量的表按一定规则，切分成多个结构完全相同表，而每个表只存原表的一部分数据。&lt;/p&gt;

&lt;p&gt;例如：一张 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;order&lt;/code&gt; 订单表有 900万数据，经过水平拆分出来三个表，&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;order_1&lt;/code&gt;、&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;order_2&lt;/code&gt;、&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;order_3&lt;/code&gt;，每张表存有数据 300万，以此类推。&lt;/p&gt;

&lt;p&gt;水平分表&lt;/p&gt;

&lt;p&gt;水平分表尽管拆分了表，但子表都还是在同一个数据库实例中，只是解决了单一表数据量过大的问题，并没有将拆分后的表分散到不同的机器上，还在竞争同一个物理机的CPU、内存、网络IO等。要想进一步提升性能，就需要将拆分后的表分散到不同的数据库中，达到分布式的效果。&lt;/p&gt;

&lt;p&gt;分库分表&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;水平切分的优点：&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;解决高并发时单库数据量过大的问题，提升系统稳定性和负载能力。&lt;/li&gt;
  &lt;li&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;/li&gt;
  &lt;li&gt;跨库的join关联查询性能较差。&lt;/li&gt;
  &lt;li&gt;扩容的难度和维护量较大，（拆分成几千张子表想想都恐怖）。&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
  &lt;h2 id=&quot;一定规则是什么&quot;&gt;一定规则是什么&lt;/h2&gt;
&lt;/blockquote&gt;

&lt;p&gt;我们上边提到过很多次 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;一定规则&lt;/code&gt; ，这个规则其实是一种路由算法，就是决定一条数据具体应该存在哪个数据库的哪张表里。&lt;/p&gt;

&lt;p&gt;常见的有 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;取模算法&lt;/code&gt; 和 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;范围限定算法&lt;/code&gt;&lt;/p&gt;

&lt;h3 id=&quot;1取模算法&quot;&gt;1、取模算法&lt;/h3&gt;

&lt;p&gt;按字段取模（对hash结果取余数 (hash() mod N)，N为数据库实例数或子表数量）是最为常见的一种切分方式。&lt;/p&gt;

&lt;p&gt;还拿 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;order&lt;/code&gt; 订单表举例，先对数据库从 0 到 N-1进行编号，对 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;order&lt;/code&gt; 订单表中 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;work_no&lt;/code&gt; 订单编号字段进行取模，得到余数 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;i&lt;/code&gt;，&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;i=0&lt;/code&gt;存第一个库，&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;i=1&lt;/code&gt;存第二个库，&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;i=2&lt;/code&gt;存第三个库….以此类推。&lt;/p&gt;

&lt;p&gt;这样同一笔订单的数据都会存在同一个库、表里，查询时用相同的规则，用 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;work_no&lt;/code&gt; 订单编号作为查询条件，就能快速的定位到数据。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;优点：&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&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;这种算法存在一些问题，当某一台机器宕机，本应该落在该数据库的请求就无法得到正确的处理，这时宕掉的实例会被踢出集群，此时算法变成hash(userId) mod N-1，用户信息可能就不再在同一个库中了。&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;2范围限定算法&quot;&gt;2、范围限定算法&lt;/h3&gt;

&lt;p&gt;按照 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;时间区间&lt;/code&gt; 或 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ID区间&lt;/code&gt; 来切分，比如：我们切分的是用户表，可以定义每个库的 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;User&lt;/code&gt; 表里只存10000条数据，第一个库只存 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;userId&lt;/code&gt; 从1 ~ 9999的数据，第二个库存 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;userId&lt;/code&gt; 为10000 ~ 20000，第三个库存 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;userId&lt;/code&gt; 为 20001~ 30000……以此类推，按时间范围也是同理。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;优点：&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;单表数据量是可控的&lt;/li&gt;
  &lt;li&gt;水平扩展简单只需增加节点即可，无需对其他分片的数据进行迁移&lt;/li&gt;
  &lt;li&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;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
  &lt;h2 id=&quot;分库分表的难点&quot;&gt;分库分表的难点&lt;/h2&gt;
&lt;/blockquote&gt;

&lt;h3 id=&quot;1分布式事务&quot;&gt;1、分布式事务&lt;/h3&gt;

&lt;p&gt;由于表分布在不同库中，不可避免会带来跨库事务问题。一般可使用 “&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;三阶段提交&lt;/code&gt; “和 “&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;两阶段提交&lt;/code&gt;” 处理，但是这种方式性能较差，代码开发量也比较大。通常做法是做到最终一致性的方案，如果不苛求系统的实时一致性，只要在允许的时间段内达到最终一致性即可，采用事务补偿的方式。&lt;/p&gt;

&lt;p&gt;这里我应用阿里的分布式事务框架&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Seata&lt;/code&gt; 来做分布式事务的管理，后边会结合实际案例。&lt;/p&gt;

&lt;h3 id=&quot;2分页排序跨库联合查询&quot;&gt;2、分页、排序、跨库联合查询&lt;/h3&gt;

&lt;p&gt;分页、排序、联合查询是开发中使用频率非常高的功能，但在分库分表后，这些看似普通的操作却是让人非常头疼的问题。将分散在不同库中表的数据查询出来，再将所有结果进行汇总整理后提供给用户。&lt;/p&gt;

&lt;h3 id=&quot;3分布式主键&quot;&gt;3、分布式主键&lt;/h3&gt;

&lt;p&gt;分库分表后数据库的自增主键意义就不大了，因为我们不能依靠单个数据库实例上的自增主键来实现不同数据库之间的全局唯一主键，此时一个能够生成全局唯一ID的系统是非常必要的，那么这个全局唯一ID就叫 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;分布式ID&lt;/code&gt;。&lt;/p&gt;

&lt;h3 id=&quot;4读写分离&quot;&gt;4、读写分离&lt;/h3&gt;

&lt;p&gt;不难发现大部分主流的关系型数据库都提供了主从架构的高可用方案，而我们需要实现 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;读写分离&lt;/code&gt; + &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;分库分表&lt;/code&gt;，读库与写库都要做分库分表处理，后边会有具体实战案例。&lt;/p&gt;

&lt;h3 id=&quot;5数据脱敏&quot;&gt;5、数据脱敏&lt;/h3&gt;

&lt;p&gt;数据脱敏，是指对某些敏感信息通过脱敏规则进行数据转换，从而实现敏感隐私数据的可靠保护，如身份证号、手机号、卡号、账号密码等个人信息，一般这些都需要进行做脱敏处理。&lt;/p&gt;

&lt;h2 id=&quot;分库分表工具&quot;&gt;分库分表工具&lt;/h2&gt;

&lt;p&gt;我还是那句话，尽量不要自己造轮子，因为自己造的轮子可能不那么圆，业界已经有了很多比较成熟的分库分表中间件，我们根据自身的业务需求挑选，将更多的精力放在业务实现上。&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sharding-jdbc&lt;/code&gt;（当当）&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TSharding&lt;/code&gt;（蘑菇街）&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Atlas&lt;/code&gt;（奇虎360）&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Cobar&lt;/code&gt;（阿里巴巴）&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MyCAT&lt;/code&gt;（基于Cobar）&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Oceanus&lt;/code&gt;（58同城）&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Vitess&lt;/code&gt;（谷歌）&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;为什么选-sharding-jdbc&quot;&gt;为什么选 sharding-jdbc&lt;/h2&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sharding-jdbc&lt;/code&gt; 是一款轻量级 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Java&lt;/code&gt; 框架，以 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;jar&lt;/code&gt; 包形式提供服务，是属于客户端产品不需要额外部署，它相当于是个增强版的 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;JDBC&lt;/code&gt; 驱动；相比之下像 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Mycat&lt;/code&gt; 这类需要单独的部署服务的服务端产品，就稍显复杂了。况且我想把更多精力放在实现业务，不想做额外的运维工作。&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sharding-jdbc&lt;/code&gt;的兼容性也非常强大，适用于任何基于 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;JDBC&lt;/code&gt; 的 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ORM&lt;/code&gt; 框架，如：&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;JPA&lt;/code&gt;， &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Hibernate&lt;/code&gt;，&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Mybatis&lt;/code&gt;，&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Spring JDBC Template&lt;/code&gt; 或直接使用的 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;JDBC&lt;/code&gt;。&lt;/li&gt;
  &lt;li&gt;完美兼容任何第三方的数据库连接池，如：&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DBCP&lt;/code&gt;， &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;C3P0&lt;/code&gt;， &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BoneCP&lt;/code&gt;，&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Druid&lt;/code&gt;， &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HikariCP&lt;/code&gt; 等，几乎对所有关系型数据库都支持。&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;不难发现确实是比较强大的一款工具，而且它对项目的侵入性很小，几乎不用做任何代码层的修改，也无需修改 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SQL&lt;/code&gt; 语句，只需配置待分库分表的数据表即可。&lt;/p&gt;

&lt;blockquote&gt;
  &lt;h2 id=&quot;总结&quot;&gt;总结&lt;/h2&gt;
&lt;/blockquote&gt;

&lt;p&gt;简单的回顾一下分库分表的基础知识，接下来的文章会配合实战项目介绍 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sharding-jdbc&lt;/code&gt; 在分库分表中的各个功能点。&lt;/p&gt;</content><author><name>qtsang</name></author><category term="数据库" /><summary type="html">什么是分库分表</summary></entry><entry><title type="html">JVM监控命令监控应用运行情况</title><link href="https://qtsang.github.io/2020/05/08/%E9%80%9A%E8%BF%87JVM%E7%9B%91%E6%8E%A7%E5%91%BD%E4%BB%A4%E7%9B%91%E6%8E%A7%E5%BA%94%E7%94%A8%E8%BF%90%E8%A1%8C%E6%83%85%E5%86%B5/" rel="alternate" type="text/html" title="JVM监控命令监控应用运行情况" /><published>2020-05-08T00:00:00+00:00</published><updated>2020-05-08T00:00:00+00:00</updated><id>https://qtsang.github.io/2020/05/08/%E9%80%9A%E8%BF%87JVM%E7%9B%91%E6%8E%A7%E5%91%BD%E4%BB%A4%E7%9B%91%E6%8E%A7%E5%BA%94%E7%94%A8%E8%BF%90%E8%A1%8C%E6%83%85%E5%86%B5</id><content type="html" xml:base="https://qtsang.github.io/2020/05/08/%E9%80%9A%E8%BF%87JVM%E7%9B%91%E6%8E%A7%E5%91%BD%E4%BB%A4%E7%9B%91%E6%8E%A7%E5%BA%94%E7%94%A8%E8%BF%90%E8%A1%8C%E6%83%85%E5%86%B5/">&lt;blockquote&gt;
  &lt;p&gt;本文记录常用的JVM监控命令，监控项目运行情况&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h6 id=&quot;查看进程占用内存情况&quot;&gt;查看进程占用内存情况&lt;/h6&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;ps aux | sort -k4,4nr | head -n 10   #查看内存占用前10名的程序

top -p 进程号      # 查看进程cpu和内存使用情况
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h6 id=&quot;查看进程堆使用情况&quot;&gt;查看进程堆使用情况&lt;/h6&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;jmap -heap 进程号
参考 https://www.cnblogs.com/shoufeng/p/9739525.html
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h6 id=&quot;jvm调优示例&quot;&gt;JVM调优示例&lt;/h6&gt;

&lt;p&gt;16G内存 JDK8 生产服务器配置未验证，先丢完整配置&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
JAVA_OPTS=&quot;-server -Xmx4g -Xms4g -Xmn256m -Xss256k -XX:+DisableExplicitGC  -XX:+UseConcMarkSweepGC -XX:+CMSParallelRemarkEnabled -XX:LargePageSizeInBytes=128m -XX:+UseFastAccessorMethods -XX:+UseCMSInitiatingOccupancyOnly -XX:CMSInitiatingOccupancyFraction=70 -Duser.timezone=GMT+8&quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;**打开文件句柄数过多(too many open files) **&lt;/p&gt;

&lt;p&gt;一般报too many open files是因为文件打开数超过了系统设置的最大的打开文件数，出现这类问题，首先可以调整操作系统的最大文件数，如果还不能解决问题，则需要看一下代码是否存在打开没有关闭的情况。&lt;/p&gt;

&lt;p&gt;从系统级别处理&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;ulimit -u 查看open files设置 默认好像是1024 linux
ulimit -a 查看所有设置
ulimit -u 65535(新的open files 值)修改设置
ulimit -n 65536 设置用户可以同时打开的最大文件数（max open files） 默认是2048
如果本参数设置过小，对于并发访问量大的网站，可能会出现too many open files的错误 
使用lsof -p pid [httpd进程的 pid、java的pid]来查看系统中apache进程和java运行时进程当前打开的文件资源，发现两者之和已
经接近1024，大于了默认的设置

1、修改配置：（我看机器上好像都有）
修改/etc/security/limits.conf，在文件末加上
* soft nofile 65536
* hard nofile 65536

2、检查 /etc/bashrc文件
看是否有  ulimit -n 2048 ，有的话注释掉
3、修改 /etc/profile 文件
添加
ulimit -u 65535
ulimit -SHn 65535
4、 /etc/pam.d/su /etc/pam.d/sshd /etc/pam.d/login 文件中添加
      session    required     pam_limits.so
这个也看到过 ，加不加不知道有没有效果
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;通过lsof分析&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;lsof -p 进程号         # 查看单个进程所有打开的文件详情
lsof -p 进程号 | wc -l   # 统计进程打开了多少文件
lsof -p 进程号 |grep 'sock' -c  #查看对应进程看的sock名称的数量
lsof -p 进程号 &amp;gt; lsof.log  将执行结果内容输出到日志文件中查看(当文件太多的情况),可以将日志下载到本地
cat lsof.log | awk '{print $8}' | sort | uniq -c | sort -rn | head -n 10 #筛选出占用句柄前十的信息
netstat -tnpoa|grep 进程号
strace -p 进程
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;</content><author><name>qtsang</name></author><category term="基础知识" /><summary type="html">本文记录常用的JVM监控命令，监控项目运行情况</summary></entry><entry><title type="html">NGINX代理OAUTH认证问题</title><link href="https://qtsang.github.io/2020/02/15/NGINX%E4%BB%A3%E7%90%86OAUTH%E8%AE%A4%E8%AF%81%E9%97%AE%E9%A2%98/" rel="alternate" type="text/html" title="NGINX代理OAUTH认证问题" /><published>2020-02-15T00:00:00+00:00</published><updated>2020-02-15T00:00:00+00:00</updated><id>https://qtsang.github.io/2020/02/15/NGINX%E4%BB%A3%E7%90%86OAUTH%E8%AE%A4%E8%AF%81%E9%97%AE%E9%A2%98</id><content type="html" xml:base="https://qtsang.github.io/2020/02/15/NGINX%E4%BB%A3%E7%90%86OAUTH%E8%AE%A4%E8%AF%81%E9%97%AE%E9%A2%98/">&lt;blockquote&gt;
  &lt;p&gt;在SpringBoot项目中使用Oauth2做认证的时候，使用Nginx代理应用服务造成JWT不可用，本文记录其解决过程。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;1、OAuth2 客户端应用采用的是HTTPS部署，而OAUTH2服务端使用HTTP部署，通过前置NGINX做了一层返向代理转发至服务端。&lt;/p&gt;

&lt;p&gt;NGINX&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;   &lt;span class=&quot;n&quot;&gt;proxy_set_header&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;HOST&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;$host&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
   &lt;span class=&quot;n&quot;&gt;proxy_set_header&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;X&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Real&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;IP&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;$remote_addr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
   &lt;span class=&quot;n&quot;&gt;proxy_set_header&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;X&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Forwarded&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;For&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;$proxy_add_x_forwarded_for&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
   &lt;span class=&quot;n&quot;&gt;proxy_set_header&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;X&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Forwarded&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Proto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;https&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Tomcat&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Engine&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Valve&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;className&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;org.apache.catalina.valves.RemoteIpValve&quot;&lt;/span&gt;  
    &lt;span class=&quot;n&quot;&gt;remoteIpHeader&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;X-Forwarded-For&quot;&lt;/span&gt;  
    &lt;span class=&quot;n&quot;&gt;protocolHeader&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;X-Forwarded-Proto&quot;&lt;/span&gt;  
    &lt;span class=&quot;n&quot;&gt;protocolHeaderHttpsValue&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;https&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&amp;gt;&lt;/span&gt; 
&lt;span class=&quot;o&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Engine&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;2.使用下划线的KEY存放JWT，导致使用NGINX转发后无法获取。&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;headers&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;access_token&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;jwt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;在设置HEADER时，KEY使用了下划线，需要开启NGINX支持下划线&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;underscores_in_headers on&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;3、Nginx负载问题&lt;/p&gt;

&lt;p&gt;为了解决session共享问题，会使用ip_hash作为负载均衡算法。我们的客户端请求，首先是请求到一个网关服务，由网关服务再转发到Nginx，此时Nginx拿到的ip都是网关服务的，这样的话IP就会转发到一个节点，负责不均衡。可以通过自定义Hash策略来实现。&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;#获取用户真实IP，并赋值给变量$clientRealIP
map $http_x_forwarded_for $clientRealIp {
“” $remote_addr;
~^(?P&amp;lt;firstAddr&amp;gt;[0-9\.]+),?.*$ $firstAddr;
}
#通过自定义策略到相应的节点
upstream h5 {
hash $clientRealIp;
server 192.168.100.104:9080;
server 192.168.100.105:9080;
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;</content><author><name>qtsang</name></author><category term="系统运维" /><summary type="html">在SpringBoot项目中使用Oauth2做认证的时候，使用Nginx代理应用服务造成JWT不可用，本文记录其解决过程。</summary></entry></feed>