文章列表

【阿里云】Linux系统初始化后重新挂载数据盘

作者:じ☆ve宝贝

问题:如果服务器需要初始化系统,数据盘数据不需要改变,初始化服务器后需要对数据盘重新挂载。 1、输入mount命令可以看到并没有挂载数据盘,输入fdisk -l 命令,看到已经分区的数据盘 /dev/xvdb1 (设备编号以实际情况为准)。 ![阿里云重新挂载数据盘](/upload/c69359fa997c40cabf868a45dd7895d1.jpg "阿里云重新挂载数据盘") 2、输入命令mount /dev/xvdb1 /目录,下面的例子是挂载到了/alidata1 目录上,这个目录需要按照各自实际需要挂载的目录进行填写,这里只是举例。 ![阿里云重新挂载数据盘](/upload/3850787c55a2427c96edb7e596ef299a.jpg "阿里云重新挂载数据盘") 挂载后再输入mount命令可以看到数据盘已经挂载,并且格式是ext4 3、修改/etc/fstab自动挂载文件,增加数据盘挂载条目,分区类型是ext3还是ext4要注意与刚才执行mount命令看到类型相对应。 ![阿里云重新挂载数据库](/upload/45406f3cbc564cc98122db5b8b4405ed.jpg "阿里云重新挂载数据盘") 4、最后可以使用umount命令卸除磁盘挂载,再重新使用mount -a 命令查看是否可以自动挂载上。 ![阿里云重新挂载数据盘](/upload/e6c85626ba604ce785dbd267275f829a.jpg "阿里云重新挂载数据盘")

Eclipse 安装SVN插件老是弹出subversive connector discovery的解决方案

作者:じ☆ve宝贝

wokrspace下面有个.metadata的目录,该目录主要是保存eclipse在该worksapce的运行时信息,比如项目结构,透视图等的组织信息 进入该目录,删除相关文件夹,重新启动,不断重试,最终定位到: ``` .metadata\.plugins\org.eclipse.core.runtime\.settings\org.eclipse.ui.workbench.prefs ``` 该文件,通过文件对比工具,比较出现该故障前和故障后的该文件,发现 正常情况: ``` org.eclipse.team.svn.ui.decorator.SVNLightweightDecorator\:false ``` 异常情况: ``` org.eclipse.team.svn.ui.decorator.SVNLightweightDecorator\:true ``` 处理: 在org.eclipse.ui.workbench.prefs文件中搜索"**SVNLightweightDecorator**"将后面的true值该为**false**即可

深入探索 Java 热部署

作者:微信小助手

<section class="output_wrapper" style="font-size: 16px;color: rgb(62, 62, 62);line-height: 1.6;letter-spacing: 0px;background-image: linear-gradient(90deg, rgba(50, 0, 0, 0.05) 3%, rgba(0, 0, 0, 0) 3%), linear-gradient(360deg, rgba(50, 0, 0, 0.05) 3%, rgba(0, 0, 0, 0) 3%);background-size: 20px 20px;background-position: center center;" data-mpa-powered-by="yiban.io"> <blockquote style="line-height: inherit;padding: 15px 15px 15px 1rem;font-size: 0.9em;margin-top: 1em;margin-bottom: 1em;color: rgb(129, 145, 152);border-left-width: 6px;border-left-color: rgb(220, 230, 240);background: rgb(242, 247, 251);overflow: auto;overflow-wrap: normal;"> <p style="font-size: inherit;color: inherit;line-height: inherit;">来源:https://www.ibm.com/developerworks/cn/java/j-lo-hotdeploy/<br>作者:丁志君</p> </blockquote> <h1 style="color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;font-weight: bold;font-size: 1.6em;"><span style="font-size: inherit;color: inherit;line-height: inherit;">简介</span></h1> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">在 Java 开发领域,热部署一直是一个难以解决的问题,目前的 Java 虚拟机只能实现方法体的修改热部署,对于整个类的结构修改,仍然需要重启虚拟机,对类重新加载才能完成更新操作。对于某些大型的应用来说,每次的重启都需要花费大量的时间成本。虽然 osgi 架构的出现,让模块重启成为可能,但是如果模块之间有调用关系的话,这样的操作依然会让应用出现短暂的功能性休克。本文将探索如何在不破坏 Java 虚拟机现有行为的前提下,实现某个单一类的热部署,让系统无需重启就完成某个类的更新。</p> <h1 style="color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;font-weight: bold;font-size: 1.6em;"><span style="font-size: inherit;color: inherit;line-height: inherit;">类加载的探索</span></h1> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">首先谈一下何为热部署(hotswap),热部署是在不重启 Java 虚拟机的前提下,能自动侦测到 class 文件的变化,更新运行时 class 的行为。Java 类是通过 Java 虚拟机加载的,某个类的 class 文件在被 classloader 加载后,会生成对应的 Class 对象,之后就可以创建该类的实例。默认的虚拟机行为只会在启动时加载类,如果后期有一个类需要更新的话,单纯替换编译的 class 文件,Java 虚拟机是不会更新正在运行的 class。如果要实现热部署,最根本的方式是修改虚拟机的源代码,改变 classloader 的加载行为,使虚拟机能监听 class 文件的更新,重新加载 class 文件,这样的行为破坏性很大,为后续的 JVM 升级埋下了一个大坑。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">另一种友好的方法是创建自己的 classloader 来加载需要监听的 class,这样就能控制类加载的时机,从而实现热部署。本文将具体探索如何实现这个方案。首先需要了解一下 Java 虚拟机现有的加载机制。目前的加载机制,称为双亲委派,系统在使用一个 classloader 来加载类时,会先询问当前 classloader 的父类是否有能力加载,如果父类无法实现加载操作,才会将任务下放到该 classloader 来加载。这种自上而下的加载方式的好处是,让每个 classloader 执行自己的加载任务,不会重复加载类。但是这种方式却使加载顺序非常难改变,让自定义 classloader 抢先加载需要监听改变的类成为了一个难题。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">不过我们可以换一个思路,虽然无法抢先加载该类,但是仍然可以用自定义 classloader 创建一个功能相同的类,让每次实例化的对象都指向这个新的类。当这个类的 class 文件发生改变的时候,再次创建一个更新的类,之后如果系统再次发出实例化请求,创建的对象讲指向这个全新的类。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">下面来简单列举一下需要做的工作。</p> <ul style="" class=" list-paddingleft-2"> <li><p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">创建自定义的 classloader,加载需要监听改变的类,在 class 文件发生改变的时候,重新加载该类。</p></li> <li><p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">改变创建对象的行为,使他们在创建时使用自定义 classloader 加载的 class。</p></li> </ul> <h1 style="color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;font-weight: bold;font-size: 1.6em;"><span style="font-size: inherit;color: inherit;line-height: inherit;">自定义加载器的实现</span></h1> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">自定义加载器仍然需要执行类加载的功能。这里却存在一个问题,同一个类加载器无法同时加载两个相同名称的类,由于不论类的结构如何发生变化,生成的类名不会变,而 classloader 只能在虚拟机停止前销毁已经加载的类,这样 classloader 就无法加载更新后的类了。这里有一个小技巧,让每次加载的类都保存成一个带有版本信息的 class,比如加载 Test.class 时,保存在内存中的类是 Test_v1.class,当类发生改变时,重新加载的类名是 Test_v2.class。但是真正执行加载 class 文件创建 class 的 defineClass 方法是一个 native 的方法,修改起来又变得很困难。所以面前还剩一条路,那就是直接修改编译生成的 class 文件。</p> <h1 style="color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;font-weight: bold;font-size: 1.6em;"><span style="font-size: inherit;color: inherit;line-height: inherit;">利用 ASM 修改 class 文件</span></h1> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">可以修改字节码的框架有很多,比如 ASM,CGLIB。本文使用的是 ASM。先来介绍一下 class 文件的结构,class 文件包含了以下几类信息,一个是类的基本信息,包含了访问权限信息,类名信息,父类信息,接口信息。第二个是类的变量信息。第三个是方法的信息。ASM 会先加载一个 class 文件,然后严格顺序读取类的各项信息,用户可以按照自己的意愿定义增强组件修改这些信息,最后输出成一个新的 class。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">首先看一下如何利用 ASM 修改类信息。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">清单 1. 利用 ASM 修改字节码</p> <pre style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 0px;margin-bottom: 0px;padding: 0px;"><code class="hljs javascript" style="margin-right: 2px;margin-left: 2px;line-height: 18px;font-size: 14px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;color: rgb(169, 183, 198);background: rgb(40, 43, 46);padding: 0.5em;display: block !important;overflow-wrap: normal !important;overflow: auto !important;">ClassWriter&nbsp;cw&nbsp;=&nbsp;<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">new</span>&nbsp;ClassWriter(ClassWriter.COMPUTE_MAXS);&nbsp;<br><br>ClassReader&nbsp;cr&nbsp;=&nbsp;<span class="hljs-literal" style="font-size: inherit;line-height: inherit;color: rgb(174, 135, 250);overflow-wrap: inherit !important;word-break: inherit !important;">null</span>;&nbsp;&nbsp;&nbsp;&nbsp;<br><br><span class="hljs-built_in" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">String</span>&nbsp;enhancedClassName&nbsp;=&nbsp;classSource.getEnhancedName();<br><br><span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">try</span>&nbsp;{<br><br>&nbsp;&nbsp;&nbsp;&nbsp;cr&nbsp;=&nbsp;<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">new</span>&nbsp;ClassReader(<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">new</span>&nbsp;FileInputStream(<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;classSource.getFile()));<br><br>}&nbsp;<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">catch</span>&nbsp;(IOException&nbsp;e)&nbsp;{<br><br>&nbsp;&nbsp;&nbsp;&nbsp;e.printStackTrace();<br><br>&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">return</span>&nbsp;<span class="hljs-literal" style="font-size: inherit;line-height: inherit;color: rgb(174, 135, 250);overflow-wrap: inherit !important;word-break: inherit !important;">null</span>;<br><br>}<br><br>ClassVisitor&nbsp;cv&nbsp;=&nbsp;<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">new</span>&nbsp;EnhancedModifier(cw,<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;className.replace(<span class="hljs-string" style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);overflow-wrap: inherit !important;word-break: inherit !important;">"."</span>,&nbsp;<span class="hljs-string" style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);overflow-wrap: inherit !important;word-break: inherit !important;">"/"</span>),<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;enhancedClassName.replace(<span class="hljs-string" style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);overflow-wrap: inherit !important;word-break: inherit !important;">"."</span>,&nbsp;<span class="hljs-string" style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);overflow-wrap: inherit !important;word-break: inherit !important;">"/"</span>));<br><br>cr.accept(cv,&nbsp;<span class="hljs-number" style="font-size: inherit;line-height: inherit;color: rgb(174, 135, 250);overflow-wrap: inherit !important;word-break: inherit !important;">0</span>);<br></code></pre> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">ASM 修改字节码文件的流程是一个责任链模式,首先使用一个 ClassReader 读入字节码,然后利用 ClassVisitor 做个性化的修改,最后利用 ClassWriter 输出修改后的字节码。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">之前提过,需要将读取的 class 文件的类名做一些修改,加载成一个全新名字的派生类。这里将之分为了 2 个步骤。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">第一步,先将原来的类变成接口。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">清单 2. 重定义的原始类</p> <pre style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 0px;margin-bottom: 0px;padding: 0px;"><code class="hljs cs" style="margin-right: 2px;margin-left: 2px;line-height: 18px;font-size: 14px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;color: rgb(169, 183, 198);background: rgb(40, 43, 46);padding: 0.5em;display: block !important;overflow-wrap: normal !important;overflow: auto !important;">&nbsp;&nbsp;&nbsp;<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">public</span>&nbsp;Class&lt;?&gt;&nbsp;redefineClass(String&nbsp;className){<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ClassWriter&nbsp;cw&nbsp;=&nbsp;<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">new</span>&nbsp;ClassWriter(ClassWriter.COMPUTE_MAXS);<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ClassReader&nbsp;cr&nbsp;=&nbsp;<span class="hljs-literal" style="font-size: inherit;line-height: inherit;color: rgb(174, 135, 250);overflow-wrap: inherit !important;word-break: inherit !important;">null</span>;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ClassSource&nbsp;cs&nbsp;=&nbsp;classFiles.<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">get</span>(className);<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">if</span>(cs==<span class="hljs-literal" style="font-size: inherit;line-height: inherit;color: rgb(174, 135, 250);overflow-wrap: inherit !important;word-break: inherit !important;">null</span>){<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">return</span>&nbsp;<span class="hljs-literal" style="font-size: inherit;line-height: inherit;color: rgb(174, 135, 250);overflow-wrap: inherit !important;word-break: inherit !important;">null</span>;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">try</span>&nbsp;{<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cr&nbsp;=&nbsp;<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">new</span>&nbsp;ClassReader(<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">new</span>&nbsp;FileInputStream(cs.getFile()));<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">catch</span>&nbsp;(IOException&nbsp;e)&nbsp;{<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e.printStackTrace();<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">return</span>&nbsp;<span class="hljs-literal" style="font-size: inherit;line-height: inherit;color: rgb(174, 135, 250);overflow-wrap: inherit !important;word-break: inherit !important;">null</span>;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ClassModifier&nbsp;cm&nbsp;=&nbsp;<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">new</span>&nbsp;ClassModifier(cw);<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cr.accept(cm,&nbsp;<span class="hljs-number" style="font-size: inherit;line-height: inherit;color: rgb(174, 135, 250);overflow-wrap: inherit !important;word-break: inherit !important;">0</span>);<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">byte</span>[]&nbsp;code&nbsp;=&nbsp;cw.toByteArray();<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">return</span>&nbsp;defineClass(className,&nbsp;code,&nbsp;<span class="hljs-number" style="font-size: inherit;line-height: inherit;color: rgb(174, 135, 250);overflow-wrap: inherit !important;word-break: inherit !important;">0</span>,&nbsp;code.length);<br><br>}<br></code></pre> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">首先 load 原始类的 class 文件,此处定义了一个增强组件 ClassModifier,作用是修改原始类的类型,将它转换成接口。原始类的所有方法逻辑都会被去掉。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">第二步,生成的派生类都实现这个接口,即原始类,并且复制原始类中的所有方法逻辑。之后如果该类需要更新,会生成一个新的派生类,也会实现这个接口。这样做的目的是不论如何修改,同一个 class 的派生类都有一个共同的接口,他们之间的转换变得对外不透明。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">清单 3. 定义一个派生类</p> <pre style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 0px;margin-bottom: 0px;padding: 0px;"><code class="hljs cs" style="margin-right: 2px;margin-left: 2px;line-height: 18px;font-size: 14px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;color: rgb(169, 183, 198);background: rgb(40, 43, 46);padding: 0.5em;display: block !important;overflow-wrap: normal !important;overflow: auto !important;">&nbsp;&nbsp;&nbsp;<span class="hljs-comment" style="font-size: inherit;line-height: inherit;color: rgb(128, 128, 128);overflow-wrap: inherit !important;word-break: inherit !important;">//&nbsp;在&nbsp;class&nbsp;文件发生改变时重新定义这个类</span><br><br>&nbsp;&nbsp;&nbsp;<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">private</span>&nbsp;Class&lt;?&gt;&nbsp;redefineClass(String&nbsp;className,&nbsp;ClassSource&nbsp;classSource){<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ClassWriter&nbsp;cw&nbsp;=&nbsp;<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">new</span>&nbsp;ClassWriter(ClassWriter.COMPUTE_MAXS);<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ClassReader&nbsp;cr&nbsp;=&nbsp;<span class="hljs-literal" style="font-size: inherit;line-height: inherit;color: rgb(174, 135, 250);overflow-wrap: inherit !important;word-break: inherit !important;">null</span>;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;classSource.update();<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;enhancedClassName&nbsp;=&nbsp;classSource.getEnhancedName();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">try</span>&nbsp;{<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cr&nbsp;=&nbsp;<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">new</span>&nbsp;ClassReader(<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">new</span>&nbsp;FileInputStream(classSource.getFile()));<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">catch</span>&nbsp;(IOException&nbsp;e)&nbsp;{<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e.printStackTrace();<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">return</span>&nbsp;<span class="hljs-literal" style="font-size: inherit;line-height: inherit;color: rgb(174, 135, 250);overflow-wrap: inherit !important;word-break: inherit !important;">null</span>;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;EnhancedModifier&nbsp;em&nbsp;=&nbsp;<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">new</span>&nbsp;EnhancedModifier(cw,&nbsp;className.replace(<span class="hljs-string" style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);overflow-wrap: inherit !important;word-break: inherit !important;">"."</span>,&nbsp;<span class="hljs-string" style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);overflow-wrap: inherit !important;word-break: inherit !important;">"/"</span>),<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;enhancedClassName.replace(<span class="hljs-string" style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);overflow-wrap: inherit !important;word-break: inherit !important;">"."</span>,&nbsp;<span class="hljs-string" style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);overflow-wrap: inherit !important;word-break: inherit !important;">"/"</span>));<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ExtendModifier&nbsp;exm&nbsp;=&nbsp;<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">new</span>&nbsp;ExtendModifier(em,&nbsp;className.replace(<span class="hljs-string" style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);overflow-wrap: inherit !important;word-break: inherit !important;">"."</span>,&nbsp;<span class="hljs-string" style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);overflow-wrap: inherit !important;word-break: inherit !important;">"/"</span>),<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;enhancedClassName.replace(<span class="hljs-string" style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);overflow-wrap: inherit !important;word-break: inherit !important;">"."</span>,&nbsp;<span class="hljs-string" style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);overflow-wrap: inherit !important;word-break: inherit !important;">"/"</span>));<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cr.accept(exm,&nbsp;<span class="hljs-number" style="font-size: inherit;line-height: inherit;color: rgb(174, 135, 250);overflow-wrap: inherit !important;word-break: inherit !important;">0</span>);<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">byte</span>[]&nbsp;code&nbsp;=&nbsp;cw.toByteArray();<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;classSource.setByteCopy(code);<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Class&lt;?&gt;&nbsp;clazz&nbsp;=&nbsp;defineClass(enhancedClassName,&nbsp;code,&nbsp;<span class="hljs-number" style="font-size: inherit;line-height: inherit;color: rgb(174, 135, 250);overflow-wrap: inherit !important;word-break: inherit !important;">0</span>,&nbsp;code.length);<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;classSource.setClassCopy(clazz);<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">return</span>&nbsp;clazz;<br><br>}<br></code></pre> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">再次 load 原始类的 class 文件,此处定义了两个增强组件,一个是 EnhancedModifier,这个增强组件的作用是改变原有的类名。第二个增强组件是 ExtendModifier,这个增强组件的作用是改变原有类的父类,让这个修改后的派生类能够实现同一个原始类(此时原始类已经转成接口了)。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">自定义 classloader 还有一个作用是监听会发生改变的 class 文件,classloader 会管理一个定时器,定时依次扫描这些 class 文件是否改变。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">改变创建对象的行为<br>Java 虚拟机常见的创建对象的方法有两种,一种是静态创建,直接 new 一个对象,一种是动态创建,通过反射的方法,创建对象。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">由于已经在自定义加载器中更改了原有类的类型,把它从类改成了接口,所以这两种创建方法都无法成立。我们要做的是将实例化原始类的行为变成实例化派生类。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">对于第一种方法,需要做的是将静态创建,变为通过 classloader 获取 class,然后动态创建该对象。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">清单 4. 替换后的指令集所对应的逻辑</p> <pre style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 0px;margin-bottom: 0px;padding: 0px;"><code class="hljs cpp" style="margin-right: 2px;margin-left: 2px;line-height: 18px;font-size: 14px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;color: rgb(169, 183, 198);background: rgb(40, 43, 46);padding: 0.5em;display: block !important;overflow-wrap: normal !important;overflow: auto !important;"><span class="hljs-comment" style="font-size: inherit;line-height: inherit;color: rgb(128, 128, 128);overflow-wrap: inherit !important;word-break: inherit !important;">//&nbsp;原始逻辑&nbsp;&nbsp;</span><br><br>&nbsp;&nbsp;Greeter&nbsp;p&nbsp;=&nbsp;<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">new</span>&nbsp;Greeter();<br><br><span class="hljs-comment" style="font-size: inherit;line-height: inherit;color: rgb(128, 128, 128);overflow-wrap: inherit !important;word-break: inherit !important;">//&nbsp;改变后的逻辑</span><br><br>&nbsp;&nbsp;IGreeter&nbsp;p&nbsp;=&nbsp;(IGreeter)MyClassLoader.getInstance().<br><br>&nbsp;&nbsp;findClass(<span class="hljs-string" style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);overflow-wrap: inherit !important;word-break: inherit !important;">"com.example.Greeter"</span>).newInstance();<br></code></pre> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">这里又需要用到 ASM 来修改 class 文件了。查找到所有 new 对象的语句,替换成通过 classloader 的形式来获取对象的形式。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">清单 5. 利用 ASM 修改方法体</p> <pre style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 0px;margin-bottom: 0px;padding: 0px;"><code class="hljs dart" style="margin-right: 2px;margin-left: 2px;line-height: 18px;font-size: 14px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;color: rgb(169, 183, 198);background: rgb(40, 43, 46);padding: 0.5em;display: block !important;overflow-wrap: normal !important;overflow: auto !important;"><span class="hljs-meta" style="font-size: inherit;line-height: inherit;color: rgb(91, 218, 237);overflow-wrap: inherit !important;word-break: inherit !important;">@Override</span><br><br>public&nbsp;<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">void</span>&nbsp;visitTypeInsn(<span class="hljs-built_in" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">int</span>&nbsp;opcode,&nbsp;<span class="hljs-built_in" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">String</span>&nbsp;type)&nbsp;{<br><br>&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">if</span>(opcode==Opcodes.NEW&nbsp;&amp;&amp;&nbsp;type.equals(className)){<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-built_in" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">List</span>&lt;LocalVariableNode&gt;&nbsp;variables&nbsp;=&nbsp;node.localVariables;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-built_in" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">String</span>&nbsp;compileType&nbsp;=&nbsp;<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">null</span>;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">for</span>(<span class="hljs-built_in" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">int</span>&nbsp;i=<span class="hljs-number" style="font-size: inherit;line-height: inherit;color: rgb(174, 135, 250);overflow-wrap: inherit !important;word-break: inherit !important;">0</span>;i&lt;variables.size();i++){<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;LocalVariableNode&nbsp;localVariable&nbsp;=&nbsp;variables.<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">get</span>(i);<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;compileType&nbsp;=&nbsp;formType(localVariable.desc);<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">if</span>(matchType(compileType)&amp;&amp;!valiableIndexUsed[i]){<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;valiableIndexUsed[i]&nbsp;=&nbsp;<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">true</span>;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">break</span>;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;mv.visitMethodInsn(Opcodes.INVOKESTATIC,&nbsp;CLASSLOAD_TYPE,<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-string" style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);overflow-wrap: inherit !important;word-break: inherit !important;">"getInstance"</span>,&nbsp;<span class="hljs-string" style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);overflow-wrap: inherit !important;word-break: inherit !important;">"()L"</span>+CLASSLOAD_TYPE+<span class="hljs-string" style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);overflow-wrap: inherit !important;word-break: inherit !important;">";"</span>);<br><br>&nbsp;&nbsp;&nbsp;&nbsp;mv.visitLdcInsn(type.replace(<span class="hljs-string" style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);overflow-wrap: inherit !important;word-break: inherit !important;">"/"</span>,&nbsp;<span class="hljs-string" style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);overflow-wrap: inherit !important;word-break: inherit !important;">"."</span>));<br><br>&nbsp;&nbsp;&nbsp;&nbsp;mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL,&nbsp;CLASSLOAD_TYPE,<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-string" style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);overflow-wrap: inherit !important;word-break: inherit !important;">"findClass"</span>,&nbsp;<span class="hljs-string" style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);overflow-wrap: inherit !important;word-break: inherit !important;">"(Ljava/lang/String;)Ljava/lang/Class;"</span>);<br><br>&nbsp;&nbsp;&nbsp;&nbsp;mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL,&nbsp;<span class="hljs-string" style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);overflow-wrap: inherit !important;word-break: inherit !important;">"java/lang/Class"</span>,<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-string" style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);overflow-wrap: inherit !important;word-break: inherit !important;">"newInstance"</span>,&nbsp;<span class="hljs-string" style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);overflow-wrap: inherit !important;word-break: inherit !important;">"()Ljava/lang/Object;"</span>);<br><br>&nbsp;&nbsp;&nbsp;&nbsp;mv.visitTypeInsn(Opcodes.CHECKCAST,&nbsp;compileType);<br><br>&nbsp;&nbsp;&nbsp;&nbsp;flag&nbsp;=&nbsp;<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">true</span>;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">else</span>&nbsp;{<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mv.visitTypeInsn(opcode,&nbsp;type);<br><br>&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;}<br></code></pre> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">对于第二种创建方法,需要通过修改 Class.forName()和 ClassLoader.findClass()的行为,使他们通过自定义加载器加载类。</p> <h1 style="color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;font-weight: bold;font-size: 1.6em;"><span style="font-size: inherit;color: inherit;line-height: inherit;">使用 JavaAgent 拦截默认加载器的行为</span></h1> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">之前实现的类加载器已经解决了热部署所需要的功能,可是 JVM 启动时,并不会用自定义的加载器加载 classpath 下的所有 class 文件,取而代之的是通过应用加载器去加载。如果在其之后用自定义加载器重新加载已经加载的 class,有可能会出现 LinkageError 的 exception。所以必须在应用启动之前,重新替换已经加载的 class。如果在 jdk1.4 之前,能使用的方法只有一种,改变 jdk 中 classloader 的加载行为,使它指向自定义加载器的加载行为。好在 jdk5.0 之后,我们有了另一种侵略性更小的办法,这就是 JavaAgent 方法,JavaAgent 可以在 JVM 启动之后,应用启动之前的短暂间隙,提供空间给用户做一些特殊行为。比较常见的应用,是利用 JavaAgent 做面向方面的编程,在方法间加入监控日志等。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">JavaAgent 的实现很容易,只要在一个类里面,定义一个 premain 的方法。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">清单 6. 一个简单的 JavaAgent</p> <pre style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 0px;margin-bottom: 0px;padding: 0px;"><code class="hljs cpp" style="margin-right: 2px;margin-left: 2px;line-height: 18px;font-size: 14px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;color: rgb(169, 183, 198);background: rgb(40, 43, 46);padding: 0.5em;display: block !important;overflow-wrap: normal !important;overflow: auto !important;"><span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">public</span>&nbsp;<span class="hljs-class" style="font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;"><span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">class</span>&nbsp;<span class="hljs-title" style="font-size: inherit;line-height: inherit;color: rgb(165, 218, 45);overflow-wrap: inherit !important;word-break: inherit !important;">ReloadAgent</span>&nbsp;{</span><br><br>&nbsp;&nbsp;&nbsp;<span class="hljs-function" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;"><span class="hljs-keyword" style="font-size: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">public</span>&nbsp;<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">static</span>&nbsp;<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">void</span>&nbsp;<span class="hljs-title" style="font-size: inherit;line-height: inherit;color: rgb(165, 218, 45);overflow-wrap: inherit !important;word-break: inherit !important;">premain</span><span class="hljs-params" style="font-size: inherit;line-height: inherit;color: rgb(255, 152, 35);overflow-wrap: inherit !important;word-break: inherit !important;">(String&nbsp;agentArgs,&nbsp;Instrumentation&nbsp;inst)</span></span>{<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;GeneralTransformer&nbsp;trans&nbsp;=&nbsp;<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">new</span>&nbsp;GeneralTransformer();<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;inst.addTransformer(trans);<br><br>&nbsp;&nbsp;&nbsp;}<br><br>}<br></code></pre> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">然后编写一个 manifest 文件,将 Premain-Class属性设置成定义一个拥有 premain方法的类名即可。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">生成一个包含这个 manifest 文件的 jar 包。</p> <pre style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 0px;margin-bottom: 0px;padding: 0px;"><code class="hljs css" style="margin-right: 2px;margin-left: 2px;line-height: 18px;font-size: 14px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;color: rgb(169, 183, 198);background: rgb(40, 43, 46);padding: 0.5em;display: block !important;overflow-wrap: normal !important;overflow: auto !important;"><span class="hljs-selector-tag" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">manifest-Version</span>:&nbsp;1<span class="hljs-selector-class" style="font-size: inherit;line-height: inherit;color: rgb(165, 218, 45);overflow-wrap: inherit !important;word-break: inherit !important;">.0</span><br><br><span class="hljs-selector-tag" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">Premain-Class</span>:&nbsp;<span class="hljs-selector-tag" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">com</span><span class="hljs-selector-class" style="font-size: inherit;line-height: inherit;color: rgb(165, 218, 45);overflow-wrap: inherit !important;word-break: inherit !important;">.example</span><span class="hljs-selector-class" style="font-size: inherit;line-height: inherit;color: rgb(165, 218, 45);overflow-wrap: inherit !important;word-break: inherit !important;">.ReloadAgent</span>&nbsp;<br><br><span class="hljs-selector-tag" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">Can-Redefine-Classes</span>:&nbsp;<span class="hljs-selector-tag" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">true</span><br></code></pre> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">最后需要在执行应用的参数中增加 -javaagent参数 , 加入这个 jar。同时可以为 Javaagent增加参数,下图中的参数是测试代码中 test project 的绝对路径。这样在执行应用的之前,会优先执行 premain方法中的逻辑,并且预解析需要加载的 class。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">图 1. 增加执行参数</p> <p style="text-align: center;"><img class="" data-copyright="0" data-ratio="0.458041958041958" data-s="300,640" data-type="png" data-w="572" src="/upload/82bcc695695ef409df5999c4f01f8ade.null" style=""></p> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">这里利用 JavaAgent替换原始字节码,阻止原始字节码被 Java 虚拟机加载。只需要实现 一个 ClassFileTransformer的接口,利用这个实现类完成 class 替换的功能。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">清单 7. 替换 class</p> <pre style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 0px;margin-bottom: 0px;padding: 0px;"><code class="hljs cs" style="margin-right: 2px;margin-left: 2px;line-height: 18px;font-size: 14px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;color: rgb(169, 183, 198);background: rgb(40, 43, 46);padding: 0.5em;display: block !important;overflow-wrap: normal !important;overflow: auto !important;">@Override<br><br><span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">public</span>&nbsp;<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">byte</span>&nbsp;[]&nbsp;transform(ClassLoader&nbsp;paramClassLoader,&nbsp;String&nbsp;paramString,<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Class&lt;?&gt;&nbsp;paramClass,&nbsp;ProtectionDomain&nbsp;paramProtectionDomain,<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">byte</span>&nbsp;[]&nbsp;paramArrayOfByte)&nbsp;throws&nbsp;IllegalClassFormatException&nbsp;{<br><br>&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;className&nbsp;=&nbsp;paramString.replace(<span class="hljs-string" style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);overflow-wrap: inherit !important;word-break: inherit !important;">"/"</span>,&nbsp;<span class="hljs-string" style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);overflow-wrap: inherit !important;word-break: inherit !important;">"."</span>);<br><br>&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">if</span>(className.<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">equals</span>(<span class="hljs-string" style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);overflow-wrap: inherit !important;word-break: inherit !important;">"com.example.Test"</span>)){<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MyClassLoader&nbsp;cl&nbsp;=&nbsp;MyClassLoader.getInstance();<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cl.defineReference(className,&nbsp;<span class="hljs-string" style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);overflow-wrap: inherit !important;word-break: inherit !important;">"com.example.Greeter"</span>);<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">return</span>&nbsp;cl.getByteCode(className);<br><br>&nbsp;&nbsp;&nbsp;&nbsp;}<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">else</span>&nbsp;<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">if</span>(className.<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">equals</span>(<span class="hljs-string" style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);overflow-wrap: inherit !important;word-break: inherit !important;">"com.example.Greeter"</span>)){<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MyClassLoader&nbsp;cl&nbsp;=&nbsp;MyClassLoader.getInstance();<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cl.redefineClass(className);<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">return</span>&nbsp;cl.getByteCode(className);<br><br>&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">return</span>&nbsp;<span class="hljs-literal" style="font-size: inherit;line-height: inherit;color: rgb(174, 135, 250);overflow-wrap: inherit !important;word-break: inherit !important;">null</span>;<br><br>&nbsp;}<br></code></pre> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">至此,所有的工作大功告成,欣赏一下 hotswap 的结果吧。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">图 2. Test 执行结果</p> <p style="text-align: center;"><img class="" data-copyright="0" data-cropselx1="0" data-cropselx2="558" data-cropsely1="0" data-cropsely2="256" data-ratio="0.21853146853146854" data-s="300,640" data-type="png" data-w="572" src="/upload/fee2052c78fb16fc19d58acc7c8ac5bf.null" style="width: 558px;height: 122px;"></p> <h1 style="color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;font-weight: bold;font-size: 1.6em;"><span style="font-size: inherit;color: inherit;line-height: inherit;">结束语</span></h1> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">解决 hotswap 是个困难的课题,本文解决的仅仅是让新实例化的对象使用新的逻辑,并不能改变已经实例化对象的行为,如果 JVM 能够重新设计 class 的生命周期,支持运行时重新更新一个 class,hotswap 就会成为 Java 的一个闪亮新特性。官方的 JVM 一直没有解决热部署这个问题,可能也是由于无法完全克服其中的诸多难点,希望未来的 Jdk 能解决这个问题,让 Java 应用对于更新更友好,避免不断重启应用浪费的时间。</p> </section>

Java设计模式(转)——1.工厂方法模式

作者:じ☆ve宝贝

## 1.工厂方法模式(Factory Method) 工厂方法模式分为三种: ## 普通工厂模式 普通工厂模式,就是建立一个工厂类,对实现了同一接口的一些类进行实例的创建。首先看下关系图: ![工厂设计模式](/upload/content8.png "工厂设计模式") 举例如下:(我们举一个发送邮件和短信的例子) 首先,创建二者的共同接口: ``` public interface Sender { public void Send(); } ``` 其次,创建实现类: ``` public class MailSender implements Sender { @Override public void Send() { System.out.println("this is mailsender!"); } } ``` ``` public class SmsSender implements Sender { @Override public void Send() { System.out.println("this is smssender!"); } } ``` 最后,建工厂类: ``` public class SendFactory { public Sender produce(String type) { if ("mail".equals(type)) { return new MailSender(); } else if ("sms".equals(type)) { return new SmsSender(); } else { System.out.println("请输入正确的类型!"); return null; } } } ``` 我们来测试下: ``` public class FactoryTest { public static void main(String[] args) { SendFactory factory = new SendFactory(); Sender sender = factory.produce("sms"); sender.Send(); } } ``` 输出:this is smssender! ## 多个工厂方法模式 多个工厂方法模式,是对普通工厂方法模式的改进,在普通工厂方法模式中,如果传递的字符串出错,则不能正确创建对象,而多个工厂方法模式是提供多个工厂方法,分别创建对象。关系图: ![工厂设计模式](/upload/content9.png "工厂设计模式") 将上面的代码做下修改,改动下SendFactory类就行,如下: ``` public class SendFactory { public Sender produceMail(){ return new MailSender(); } public Sender produceSms(){ return new SmsSender(); } } ``` 测试类如下: ``` public class FactoryTest { public static void main(String[] args) { SendFactory factory = new SendFactory(); Sender sender = factory.produceMail(); sender.Send(); } } ``` 输出:this is mailsender! ## 静态工厂方法模式 静态工厂方法模式,将上面的多个工厂方法模式里的方法置为静态的,不需要创建实例,直接调用即可。 ``` public class SendFactory { public static Sender produceMail(){ return new MailSender(); } public static Sender produceSms(){ return new SmsSender(); } } ``` ``` public class FactoryTest { public static void main(String[] args) { Sender sender = SendFactory.produceMail(); sender.Send(); } } ``` 输出:this is mailsender! 总体来说,工厂模式适合:凡是出现了大量的产品需要创建,并且具有共同的接口时,可以通过工厂方法模式进行创建。在以上的三种模式中,第一种如果传入的字符串有误,不能正确创建对象,第三种相对于第二种,不需要实例化工厂类,所以,大多数情况下,我们会选用第三种——静态工厂方法模式。

如何画好架构图

作者:微信小助手

<p style="text-align: center;margin-bottom: 15px;"><strong style="max-width: 100%;letter-spacing: 0.544px;font-size: 16px;color: rgb(74, 74, 74);font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;text-align: right;white-space: pre-line;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: 14px;color: rgb(136, 136, 136);box-sizing: border-box !important;overflow-wrap: break-word !important;">点击蓝色“</span></strong><span style="max-width: 100%;letter-spacing: 0.544px;font-size: 16px;font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;text-align: right;white-space: pre-line;background-color: rgb(255, 255, 255);color: rgb(0, 128, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"><strong style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: 14px;box-sizing: border-box !important;overflow-wrap: break-word !important;">程序猿DD</span></strong></span><strong style="max-width: 100%;letter-spacing: 0.544px;font-size: 16px;color: rgb(74, 74, 74);font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;text-align: right;white-space: pre-line;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: 14px;color: rgb(136, 136, 136);box-sizing: border-box !important;overflow-wrap: break-word !important;">”关注我哟</span></strong></p> <p style="text-align: center;"><img class="" data-copyright="0" data-ratio="0.61484375" data-s="300,640" src="/upload/e076fb927f87bc04b155e6bea4a5869f.jpg" data-type="jpeg" data-w="1280" style=""></p> <p style="text-align: right;margin-bottom: 15px;"><span style="color: rgb(136, 136, 136);font-family: -apple-system, system-ui, &quot;Segoe UI&quot;, Roboto, &quot;Helvetica Neue&quot;, Helvetica, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, SimSun, sans-serif;font-size: 14px;letter-spacing: 0.16px;text-align: right;background-color: rgb(255, 255, 255);">来源:阿里巴巴中间件</span></p> <blockquote style="max-width: 100%;font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;text-size-adjust: auto;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <p style="max-width: 100%;min-height: 1em;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;background-color: rgb(255, 255, 255);color: rgb(74, 74, 74);font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;font-size: 15px;letter-spacing: 0.544px;white-space: pre-line;box-sizing: border-box !important;overflow-wrap: break-word !important;">技术传播的价值,不仅仅体现在通过商业化产品和开源项目来缩短我们构建应用的路径,加速业务的上线速率,</span><span style="max-width: 100%;background-color: rgb(255, 255, 255);font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;font-size: 15px;letter-spacing: 0.544px;white-space: pre-line;color: rgb(0, 122, 170);box-sizing: border-box !important;overflow-wrap: break-word !important;">也体现在优秀工程师在工作效率提升、产品性能优化和用户体验改善等经验方面的分享,以提高我们的专业能力。</span><br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></p> </blockquote> <p style="max-width: 100%;min-height: 1em;font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;text-size-adjust: auto;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br></p> <p style="max-width: 100%;min-height: 1em;font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;text-size-adjust: auto;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;font-size: 15px;letter-spacing: 0.544px;white-space: pre-line;background-color: rgb(255, 255, 255);color: rgb(136, 136, 136);box-sizing: border-box !important;overflow-wrap: break-word !important;">本文作者阿里巴巴技术专家三画,分享了自己和团队在画好架构图方面的理念和经验,首发于阿里内部技术分享平台,阿里巴巴中间件授权转载,梓敬、鹏升和余乐对此文亦有贡献。</span></p> <p style="max-width: 100%;min-height: 1em;font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;text-size-adjust: auto;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></p> <p style="max-width: 100%;min-height: 1em;font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;text-size-adjust: auto;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(74, 74, 74);font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;font-size: 15px;letter-spacing: 0.544px;white-space: pre-line;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;">当我们想用一张或几张图来描述我们的系统时,是不是经常遇到以下情况:</span></p> <p style="max-width: 100%;min-height: 1em;font-family: -apple-system-font, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;text-size-adjust: auto;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br></p> <ul class=" list-paddingleft-2" style=""> <li><p style="max-width: 100%;min-height: 1em;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(74, 74, 74);font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;font-size: 15px;letter-spacing: 0.544px;white-space: pre-line;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;">对着画布无从下手、删了又来?</span></p></li> <li><p style="max-width: 100%;min-height: 1em;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;background-color: rgb(255, 255, 255);color: rgb(74,

REST API安全设计指南

作者:じ☆ve宝贝

###### REST的全称是REpresentational State Transfer,它利用传统Web特点,提出一个既适于客户端应用又适于服务端的应用的、统一架构,极大程度上统一及简化了网站架构设计。 目前在三种主流的Web服务实现方案中,REST模式服务相比复杂的SOAP和XML-RPC对比来讲,更加简洁,越来越多的web服务开始使用REST设计并实现。但其缺少安全特性,《REST API 安全设计指南》就是一个REST API安全设计的指南,权当抛砖引玉,推荐网站后台设计及网站架构师们阅读。 ### 1、REST API 简介 REST的全称是REpresentational State Transfer,表示表述性无状态传输,无需session,所以每次请求都得带上身份认证信息。rest是基于http协议的,也是无状态的。只是一种架构方式,所以它的安全特性都需我们自己实现,没有现成的。建议所有的请求都通过https协议发送。RESTful web services概念的核心就是“资源”。资源可以用URI来表示。客户端使用HTTP协议定义的方法来发送请求到这些URIs,当然可能会导致这些被访问的”资源“状态的改变。HTTP请求对应关系如下: ``` ========== ===================== ======================== HTTP 方法 行为 示例 ========== ===================== ======================== GET 获取资源的信息 http://xx.com/api/orders GET 获取某个特定资源的信息 http://xx.com/api/orders/123 POST 创建新资源 http://xx.com/api/orders PUT 更新资源 http://xx.com/api/orders/123 DELETE 删除资源 http://xx.com/api/orders/123 ========== ====================== ====================== ``` 对于请求的数据一般用json或者xml形式来表示,推荐使用json。 ### 2、身份认证 身份认证包含很多种,有HTTP Basic、HTTP Digest、API KEY、Oauth、JWK等方式,下面简单讲解下: #### 2.1 HTTP Basic REST由于是无状态的传输,所以每一次请求都得带上身份认证信息,身份认证的方式,身份认证的方式有很多种,第一种便是http basic,这种方式在客户端要求简单,在服务端实现也非常简单,只需简单配置apache等web服务器即可实现,所以对于简单的服务来说还是挺方便的。但是这种方式安全性较低,就是简单的将用户名和密码base64编码放到header中。 ``` base64编码前:Basic admin:admin base64编码后:Basic YWRtaW46YWRtaW4= 放到Header中:Authorization: Basic YWRtaW46YWRtaW4= ``` 正是因为是简单的base64编码存储,切记切记在这种方式下一定得注意使用ssl,不然就是裸奔了。在某些产品中也是基于这种类似方式,只是没有使用apache的basic机制,而是自己写了认证框架,原理还是一样的,在一次请求中base64解码Authorization字段,再和认证信息做校验。很显然这种方式有问题,认证信息相当于明文传输,另外也没有防暴力破解功能。 #### 2.2 API KEY API Key就是经过用户身份认证之后服务端给客户端分配一个API Key,类似:http://example.com/api?key=dfkaj134,一般的处理流程如下: 一个简单的设计示例如下。 client端: ![rest接口](/upload/14453211382412.jpg "rest接口") server端: ![rest接口](/upload/144532116555321.jpg "rest接口") client端向服务端注册,服务端给客户端发送响应的api_key以及security_key,注意保存不要泄露,然后客户端根据api_key,secrity_key,timestrap,rest_uri采用hmacsha256算法得到一个hash值sign,构造途中的url发送给服务端。服务端收到该请求后,首先验证api_key,是否存在,存在则获取该api_key的security_key,接着验证timestrap是否超过时间限制,可依据系统成而定,这样就防止了部分重放攻击,途中的rest_api是从url获取的为/rest/v1/interface/eth0,最后计算sign值,完之后和url中的sign值做校验。这样的设计就防止了数据被篡改。通过这种API Key的设计方式加了时间戳防止了部分重放,加了校验,防止了数据被篡改,同时避免了传输用户名和密码,当然了也会有一定的开销。 #### 2.3 auth1.0a或者Oauth2 OAuth协议适用于为外部应用授权访问本站资源的情况。其中的加密机制与HTTP Digest身份认证相比,安全性更高。使用和配置都比较复杂,这里就不涉及了。 ####2.4 JWT JWT是JSON Web Token,用于发送可通过数字签名和认证的东西,它包含一个紧凑的、URL安全的JSON对象,服务端可通过解析该值来验证是否有操作权限,是否过期等安全性检查。由于其紧凑的特点,可放在url中或者HTTP Authorization头中,具体的算法就如下图: ![rest接口](/upload/14453212109244.jpg "rest接口") ###3、授权 身份认证之后就是授权,根据不同的身份,授予不同的访问权限。比如admin用户、普通用户、auditor用户都是不同的身份。简单的示例: ![rest接口](/upload/14453216104042.jpg "rest接口") 上述是垂直权限的处理,如果遇到了平行权限的问题,如用户A获取用户B的身份信息或者更改其他用户信息,对于这些敏感数据接口都需要加上对用户的判断,这一步一般都在具体的逻辑实现中实现。 ### 4、URL过滤 在进入逻辑处理之前,加入对URL的参数过滤,如: ``` /site/{num}/policy ``` 限定num位置为整数等,如果不是参数则直接返回非法参数,设定一个url清单,不在不在url清单中的请求直接拒绝,这样能防止开发中的api泄露。rest api接口一般会用到GET、POST、PUT、DELETE,未实现的方法则直接返回方法不允许,对于POST,PUT方法的数据采用json格式,并且在进入逻辑前验证是否json,不合法返回json格式错误。 ### 5、重要功能加密传输 第一步推荐SSL加密传输,同时对于系统中重要的功能做加密传输,如证书、一些数据、配置的备份功能,同时还得确保具备相应的权限,这一步会在授权中涉及。 ### 6、速率限制 请求速率限制,根据api_key或者用户来判断某段时间的请求次数,将该数据更新到内存数据库(redis,memcached),达到最大数即不接受该用户的请求,同时这样还可以利用到内存数据库key在特定时间自动过期的特性。在php中可以使用APC,Alternative PHP Cache (APC)是一个开放自由的PHP opcode缓存。它的目标是提供一个自由、开放,和健全的框架用于缓存和优化PHP的中间代码。在返回时设置X-Rate-Limit-Reset:当前时间段剩余秒数,APC的示例代码如下: ![rest接口](/upload/14453217216777.jpg "rest接口") ###7、错误处理 对于非法的,导致系统出错的等请求都进行记录,一些重要的操作,如登录、注册等都通过日志接口输出展示。有一个统一的出错接口,对于400系列和500系列的错误都有相应的错误码和相关消息提示,如401:未授权;403:已经鉴权,但是没有相应权限。如不识别的url: ``` {"result":"Invalid URL!"} ``` · 错误的请求参数 ``` {"result":"json format error"} ``` · 不允许的方法: ``` {"result":"Method Not Allowed"} ``` · 非法参数等。上面所说的都是单状态码,同时还有多状态码,表示部分成功,部分字符非法等。示例如下: ### 8、重要ID不透明处理 在系统一些敏感功能上,比如/user/1123可获取id=1123用户的信息,为了防止字典遍历攻击,可对id进行url62或者uuid处理,这样处理的id是唯一的,并且还是字符安全的。 9、其他注意事项 (1)请求数据,对于POST,DELETE方法中的数据都采用json格式,当然不是说rest架构不支持xml,由于xml太不好解析,对于大部分的应用json已经足够,近一些的趋势也是json越来越流行,并且json格式也不会有xml的一些安全问题,如xxe。使用json格式目前能防止扫描器自动扫描。 (2)返回数据统一编码格式,统一返回类型,如Content-Type: application/json; charset=”UTF-8″ (3)在逻辑实现中,json解码之后进行参数验证或者转义操作,第一步json格式验证,第二步具体参数验证基本上能防止大部分的注入问题了。 (4)在传输过程中,采用SSL保证传输安全。 (5)存储安全,重要信息加密存储,如认证信息hash保存。 总之,尽量使用SSL。

MySQL MySQL 5.7.9新的密码规则

作者:じ☆ve宝贝

安装的时候会生成随机密码,如果忘记可以修改MySQL的配置文件(linux默认为/etc/my.cnf,windows默认为my.ini),在[mysqld]下添加一行**skip-grant-tables **(跳过输入密码过程) 进入mysql后 ``` mysql> update mysql.user set authentication_string=password('root') where user='root' and Host = 'localhost'; mysql> flush privileges; mysql> quit; ``` 或者 ``` SET PASSWORD = PASSWORD(‘newpasswd‘); 设置新密码 ```

[MySQL错误]Table './web/t_tmp_book' is marked as crashed and should be repaired

作者:じ☆ve宝贝

Table './web/t_tmp_book' is marked as crashed and should be repaired 频繁查询和更新dede_archives表造成的索引错误 ` myisamchk -c -r ../data/mysql/shujukumingcheng/biaoming.MYI ` 然后myisamchk 工具会帮助你恢复数据表的索引。重新启动mysql,问题解决。

让Elasticsearch飞起来!百亿级实时查询优化实战

作者:微信小助手

<section style="box-sizing: border-box;font-size: 16px;"> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <section style="margin-top: 10px;margin-bottom: 10px;box-sizing: border-box;"> <section style="padding-top: 10px;padding-right: 10px;padding-left: 10px;box-sizing: border-box;background-color: rgb(239, 239, 239);"> <span style="display: inline-block;width: 5%;line-height: 0.8;font-weight: bolder;font-size: 48px;box-sizing: border-box;"> <section style="box-sizing: border-box;"> “ </section></span> <section style="display: inline-block;vertical-align: top;float: right;width: 90%;line-height: 1.5;font-size: 15px;color: rgb(89, 89, 89);box-sizing: border-box;"> <p style="box-sizing: border-box;"><span style="letter-spacing: 1px;">最近的一个项目是风控过程数据实时统计分析和聚合的一个 OLAP 分析监控平台,日流量峰值在 10 到 12 亿上下,每年数据约 4000 亿条,占用空间大概 200T。</span></p> </section> <section style="clear: both;box-sizing: border-box;"></section> </section> </section> </section> </section> <p style="line-height: 1.75em;"><br></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;margin-bottom: 5px;"><img class="rich_pages" data-copyright="0" data-ratio="0.42825848849945236" data-s="300,640" src="/upload/6e55af3ebca20c4349ede186153a5886.png" data-type="png" data-w="913" style=""></p> <p style="margin-right: 8px;margin-left: 8px;white-space: normal;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">面对这样一个数据量级的需求,我们的数据如何存储和实现实时查询将是一个严峻的挑战。</span></p> <p style="white-space: normal;line-height: normal;"><br></p> <p style="margin-right: 8px;margin-left: 8px;white-space: normal;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(71, 193, 168);">经过对 Elasticsearch 多方调研和超过几百亿条数据的插入和聚合查询的验证之后,我们总结出以下几种能够有效提升性能和解决这一问题的方案:</span></p> <ul class=" list-paddingleft-2"> <li><p style="margin-right: 8px;margin-left: 8px;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">集群规划</span></strong></p></li> <li><p style="margin-right: 8px;margin-left: 8px;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">存储策略</span></strong></p></li> <li><p style="margin-right: 8px;margin-left: 8px;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">索引拆分</span></strong></p></li> <li><p style="margin-right: 8px;margin-left: 8px;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">压缩</span></strong></p></li> <li><p style="margin-right: 8px;margin-left: 8px;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">冷热分区等</span></strong></p></li> </ul> <p style="white-space: normal;line-height: normal;"><br></p> <p style="margin-right: 8px;margin-bottom: 5px;margin-left: 8px;white-space: normal;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">本文所使用的 Elasticsearch 版本为 5.3.3。</span></p> <p style="margin-right: 8px;margin-bottom: 5px;margin-left: 8px;line-height: 27.2px;white-space: normal;text-align: center;"><img class="" data-copyright="0" data-ratio="0.4926719278466742" data-s="300,640" src="/upload/d769be36cf372ca0b7bdead40b334678.png" data-type="png" data-w="1774"></p> <p style="margin-right: 8px;margin-left: 8px;white-space: normal;line-height: 1.75em;"><span style="color: rgb(71, 193, 168);"><span style="font-size: 15px;letter-spacing: 1px;">什么是时序索引?</span><span style="font-size: 15px;letter-spacing: 1px;line-height: 1.75em;">其主要特点体现在如下两个方面:</span></span></p> <ul class=" list-paddingleft-2"> <li><p style="margin-right: 8px;margin-left: 8px;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">存,</span></strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">以时间为轴,数据只有增加,没有变更,并且必须包含 timestamp(日期时间,名称随意)字段。</span></p><p style="margin-right: 8px;margin-left: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">其作用和意义要大于数据的 id 字段,常见的数据比如我们通常要记录的操作日志、用户行为日志、或股市行情数据、服务器 CPU、内存、网络的使用率等。</span></p></li> <li><p style="margin-right: 8px;margin-left: 8px;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">取,</span></strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">一定是以时间范围为第一过滤条件,然后是其他查询条件,比如近一天、一周、本月等等,然后在这个范围内进行二次过滤。</span></p><p style="margin-right: 8px;margin-left: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">比如性别或地域等,查询结果中比较关注的是每条数据和 timestamp 字段具体发生的时间点,而非 id。</span></p></li> </ul> <p style="white-space: normal;line-height: normal;"><br></p> <p style="margin-right: 8px;margin-left: 8px;white-space: normal;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">此类数据一般用于 OLAP、监控分析等场景。</span></p> <p style="white-space: normal;line-height: normal;"><br></p> <section style="white-space: normal;box-sizing: border-box;font-size: 16px;"> <section powered-by="xiumi.us" style="box-sizing: border-box;"> <section style="margin-top: 0.5em;margin-bottom: 0.5em;border-bottom-width: 1px;border-bottom-style: solid;border-bottom-color: black;line-height: 1.2;box-sizing: border-box;"> <section style="margin-bottom: -1px;display: inline-block;border-bottom-width: 6px;border-bottom-style: solid;border-color: rgb(89, 89, 89);font-size: 20px;color: rgb(89, 89, 89);box-sizing: border-box;"> <p style="box-sizing: border-box;">集群部署规划</p> </section> </section> </section> </section> <p style="white-space: normal;line-height: normal;"><br></p> <p style="margin-right: 8px;margin-bottom: 5px;margin-left: 8px;white-space: normal;text-align: center;line-height: 1.75em;"><img class="" data-copyright="0" data-ratio="0.6142857142857143" data-s="300,640" src="/upload/7083479511f4d22cf53f41bb1a7eba88.png" data-type="png" data-w="1260"></p> <p style="margin-right: 8px;margin-left: 8px;white-space: normal;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">我们都知道在 Elasticsearch(下称 ES)集群中有两个主要角色:Master Node 和 Data Node,其他如 Tribe Node 等节点可根据业务需要另行设立。</span></p> <p style="white-space: normal;line-height: normal;"><br></p> <p style="margin-right: 8px;margin-left: 8px;white-space: normal;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">为了让集群有更好的性能表现,我们应该对这两个角色有一个更好的规划,在 Nodes 之间做读取分离,保证集群的稳定性和快速响应,在大规模的数据存储和查询的压力之下能够坦然面对,各自愉快的协作。</span></p> <p style="white-space: normal;line-height: normal;"><br></p> <section style="white-space: normal;box-sizing: border-box;font-size: 16px;"> <section powered-by="xiumi.us" style="box-sizing: border-box;"> <section style="margin-top: 10px;margin-bottom: 10px;box-sizing: border-box;"> <section style="width: 0.6em;display: inline-block;vertical-align: middle;box-sizing: border-box;"> <span style="width: 0.6em;height: 0.6em;display: block;opacity: 0.2;box-sizing: border-box;background-color: rgb(89, 89, 89);"></span> <strong><span style="margin-top: 2px;margin-bottom: 2px;width: 0.6em;height: 0.6em;display: block;opacity: 0.6;box-sizing: border-box;background-color: rgb(89, 89, 89);"></span><span style="width: 0.6em;height: 0.6em;display: block;opacity: 1;box-sizing: border-box;background-color: rgb(89, 89, 89);"></span></strong> </section> <section style="padding-left: 5px;display: inline-block;vertical-align: middle;font-size: 18px;color: rgb(89, 89, 89);box-sizing: border-box;"> <p style="box-sizing: border-box;"><strong>Master Nodes</strong></p> </section> </section> </section> </section> <p style="white-space: normal;line-height: normal;"><br></p> <p style="margin-right: 8px;margin-left: 8px;white-space: normal;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">Master Node,整个集群的管理者,负有对 index 的管理、shards 的分配,以及整个集群拓扑信息的管理等功能。</span></p> <p style="white-space: normal;line-height: normal;"><br></p> <p style="margin-right: 8px;margin-left: 8px;white-space: normal;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">众所周知,Master Node 可以通过 Data Node 兼任,但是,如果对群集规模和稳定要求很高的话,就要职责分离,Master Node 推荐独立,它的状态关乎整个集群的存活。</span></p> <p style="white-space: normal;line-height: normal;"><br></p> <p style="margin-right: 8px;margin-bottom: 5px;margin-left: 8px;white-space: normal;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(71, 193, 168);">Master 的配置:</span></p> <section class="output_wrapper" style="letter-spacing: 0px;white-space: normal;font-size: 16px;color: rgb(62, 62, 62);line-height: 1.6;font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', Arial, sans-serif;"> <pre style="font-size: inherit;color: inherit;line-height: inherit;"><code class="hljs kotlin" style="margin-right: 2px;margin-left: 2px;padding: 0.5em;line-height: 18px;font-size: 14px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;color: rgb(169, 183, 198);display: block !important;word-wrap: normal !important;word-break: normal !important;overflow: auto !important;background: rgb(40, 43, 46);">node.master:&nbsp;<span class="hljs-literal" style="font-size: inherit;line-height: inherit;color: rgb(174, 135, 250);word-wrap: inherit !important;word-break: inherit !important;">true</span>&nbsp;<br>node.<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">data</span>:&nbsp;<span class="hljs-literal" style="font-size: inherit;line-height: inherit;color: rgb(174, 135, 250);word-wrap: inherit !important;word-break: inherit !important;">false</span>&nbsp;<br>node.ingest:&nbsp;<span class="hljs-literal" style="font-size: inherit;line-height: inherit;color: rgb(174, 135, 250);word-wrap: inherit !important;word-break: inherit !important;">false</span><br></code></pre> </section> <p style="white-space: normal;line-height: normal;"><br></p> <p style="margin-right: 8px;margin-left: 8px;white-space: normal;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">这样 Master 不参与 I、O,从数据的搜索和索引操作中解脱出来,专门负责集群的管理工作,因此 Master Node 的节点配置可以相对低一些。</span></p> <p style="white-space: normal;line-height: normal;"><br></p> <p style="margin-right: 8px;margin-left: 8px;white-space: normal;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">另外防止 ES 集群&nbsp;split brain(脑裂),合理配置 discovery.zen.minimum_master_nodes 参数,官方推荐 master-eligible nodes / 2 + 1 向下取整的个数。</span></p> <p style="white-space: normal;line-height: normal;"><br></p> <p style="margin-right: 8px;margin-left: 8px;white-space: normal;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">这个参数决定选举 Master 的 Node 个数,太小容易发生“脑裂”,可能会出现多个 Master,太大 Master 将无法选举。</span></p> <p style="white-space: normal;line-height: normal;"><br></p> <p style="margin-right: 8px;margin-bottom: 5px;margin-left: 8px;white-space: normal;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(71, 193, 168);">更多 Master 选举相关内容请参考:</span></p> <section class="output_wrapper" style="letter-spacing: 0px;white-space: normal;font-size: 16px;color: rgb(62, 62, 62);line-height: 1.6;font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', Arial, sans-serif;"> <pre style="font-size: inherit;color: inherit;line-height: inherit;"><code class="hljs ruby" style="margin-right: 2px;margin-left: 2px;padding: 0.5em;line-height: 18px;font-size: 14px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;color: rgb(169, 183, 198);display: block !important;word-wrap: normal !important;word-break: normal !important;overflow: auto !important;background: rgb(40, 43, 46);"><span class="hljs-symbol" style="font-size: inherit;line-height: inherit;color: rgb(174, 135, 250);word-wrap: inherit !important;word-break: inherit !important;">https:</span>/<span class="hljs-regexp" style="font-size: inherit;color: inherit;line-height: inherit;word-wrap: inherit !important;word-break: inherit !important;">/www.elastic.co/guide</span><span class="hljs-regexp" style="font-size: inherit;color: inherit;line-height: inherit;word-wrap: inherit !important;word-break: inherit !important;">/en/elasticsearch</span><span class="hljs-regexp" style="font-size: inherit;color: inherit;line-height: inherit;word-wrap: inherit !important;word-break: inherit !important;">/reference/</span><span class="hljs-number" style="font-size: inherit;line-height: inherit;color: rgb(174, 135, 250);word-wrap: inherit !important;word-break: inherit !important;">5.3</span>/modules-discovery-zen.html<span class="hljs-comment" style="font-size: inherit;line-height: inherit;color: rgb(128, 128, 128);word-wrap: inherit !important;word-break: inherit !important;">#master-election</span><br></code></pre> </section> <p style="white-space: normal;line-height: normal;"><br></p> <section style="white-space: normal;box-sizing: border-box;font-size: 16px;"> <section powered-by="xiumi.us" style="box-sizing: border-box;"> <section style="margin-top: 10px;margin-bottom: 10px;box-sizing: border-box;"> <section style="width: 0.6em;display: inline-block;vertical-align: middle;box-sizing: border-box;"> <span style="width: 0.6em;height: 0.6em;display: block;opacity: 0.2;box-sizing: border-box;background-color: rgb(89, 89, 89);"></span> <strong><span style="margin-top: 2px;margin-bottom: 2px;width: 0.6em;height: 0.6em;display: block;opacity: 0.6;box-sizing: border-box;background-color: rgb(89, 89, 89);"></span><span style="width: 0.6em;height: 0.6em;display: block;opacity: 1;box-sizing: border-box;background-color: rgb(89, 89, 89);"></span></strong> </section> <section style="padding-left: 5px;display: inline-block;vertical-align: middle;font-size: 18px;color: rgb(89, 89, 89);box-sizing: border-box;"> <p style="box-sizing: border-box;"><strong>Data Nodes</strong></p> </section> </section> </section> </section> <p style="white-space: normal;line-height: normal;"><br></p> <p style="margin-right: 8px;margin-left: 8px;white-space: normal;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">Data Node 是数据的承载者,对索引的数据存储、查询、聚合等操作提供支持。</span></p> <p style="white-space: normal;line-height: normal;"><br></p> <p style="margin-right: 8px;margin-left: 8px;white-space: normal;line-height: 1.75em;"><span style="color: rgb(89, 89, 89);font-size: 15px;letter-spacing: 1px;line-height: 1.75em;">这些操作严重消耗系统的 CPU、内存、IO 等资源,因此,应该把最好的资源分配给 Data Node,因为它们是真正干累活的角色,同样 Data Node 也不兼任 Master 的功能。</span></p> <p style="white-space: normal;line-height: normal;"><br></p> <p style="margin-right: 8px;margin-bottom: 5px;margin-left: 8px;white-space: normal;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;line-height: 1.75em;color: rgb(71, 193, 168);">Data&nbsp;的配置:</span></p> <section class="output_wrapper" style="letter-spacing: 0px;white-space: normal;font-size: 16px;color: rgb(62, 62, 62);line-height: 1.6;font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', Arial, sans-serif;"> <pre style="font-size: inherit;color: inherit;line-height: inherit;"><code class="hljs kotlin" style="margin-right: 2px;margin-left: 2px;padding: 0.5em;line-height: 18px;font-size: 14px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;color: rgb(169, 183, 198);display: block !important;word-wrap: normal !important;word-break: normal !important;overflow: auto !important;background: rgb(40, 43, 46);">node.master:&nbsp;<span class="hljs-literal" style="font-size: inherit;line-height: inherit;color: rgb(174, 135, 250);word-wrap: inherit !important;word-break: inherit !important;">false</span>&nbsp;<br>node.<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">data</span>:&nbsp;<span class="hljs-literal" style="font-size: inherit;line-height: inherit;color: rgb(174, 135, 250);word-wrap: inherit !important;word-break: inherit !important;">true</span>&nbsp;<br>node.ingest:&nbsp;<span class="hljs-literal" style="font-size: inherit;line-height: inherit;color: rgb(174, 135, 250);word-wrap: inherit !important;word-break: inherit !important;">false</span><br></code></pre> </section> <p style="white-space: normal;line-height: normal;"><br></p> <section style="white-space: normal;box-sizing: border-box;font-size: 16px;"> <section powered-by="xiumi.us" style="box-sizing: border-box;"> <section style="margin-top: 10px;margin-bottom: 10px;box-sizing: border-box;"> <section style="width: 0.6em;display: inline-block;vertical-align: middle;box-sizing: border-box;"> <span style="width: 0.6em;height: 0.6em;display: block;opacity: 0.2;box-sizing: border-box;background-color: rgb(89, 89, 89);"></span> <span style="margin-top: 2px;margin-bottom: 2px;width: 0.6em;height: 0.6em;display: block;opacity: 0.6;box-sizing: border-box;background-color: rgb(89, 89, 89);"></span> <strong><span style="width: 0.6em;height: 0.6em;display: block;opacity: 1;box-sizing: border-box;background-color: rgb(89, 89, 89);"></span></strong> </section> <section style="padding-left: 5px;display: inline-block;vertical-align: middle;font-size: 18px;color: rgb(89, 89, 89);box-sizing: border-box;"> <p style="box-sizing: border-box;"><strong>Coordinating Only Nodes</strong></p> </section> </section> </section> </section> <p style="white-space: normal;line-height: normal;">&nbsp;</p> <p style="margin-right: 8px;margin-bottom: 5px;margin-left: 8px;white-space: normal;text-align: center;line-height: 1.75em;"><img class="" data-copyright="0" data-ratio="0.7379032258064516" data-s="300,640" src="/upload/5c4b878d95bfe9f73c91ce99fbaf45f0.png" data-type="png" data-w="992"></p> <p style="margin-right: 8px;margin-left: 8px;white-space: normal;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">ES 本身是一个分布式的计算集群,每个 Node 都可以响应用户的请求,包括 Master Node、Data Node,它们都有完整的 Cluster State 信息。</span></p> <p style="white-space: normal;line-height: normal;"><br></p> <p style="margin-right: 8px;margin-left: 8px;white-space: normal;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">正如我们知道的一样,在某个 Node 收到用户请求的时候,会将请求转发到集群中所有索引相关的 Node 上,之后将每个 Node 的计算结果合并后返回给请求方。</span></p> <p style="white-space: normal;line-height: normal;"><br></p> <p style="margin-right: 8px;margin-left: 8px;white-space: normal;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">我们暂且将这个 Node 称为查询节点,整个过程跟分布式数据库原理类似。</span><span style="color: rgb(89, 89, 89);font-size: 15px;letter-spacing: 1px;line-height: 1.75em;">那问题来了,这个查询节点如果在并发和数据量比较大的情况下,由于数据的聚合可能会让内存和网络出现瓶颈。</span></p> <p style="white-space: normal;line-height: normal;"><br></p> <p style="margin-right: 8px;margin-left: 8px;white-space: normal;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">因此,在职责分离指导思想的前提下,这些操作我们也应该从这些角色中剥离出来,官方称它是&nbsp;Coordinating Nodes,只负责路由用户的请求,包括读、写等操作,对内存、网络和 CPU 要求比较高。</span></p> <p style="white-space: normal;line-height: normal;"><br></p> <p style="margin-right: 8px;margin-bottom: 5px;margin-left: 8px;white-space: normal;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">本质上,Coordinating Only Nodes 可以笼统的理解为是一个负载均衡器,或者反向代理,只负责读,本身不写数据,</span><span style="font-size: 15px;letter-spacing: 1px;color: rgb(71, 193, 168);">它的配置是:</span></p> <section class="output_wrapper" style="letter-spacing: 0px;white-space: normal;font-size: 16px;color: rgb(62, 62, 62);line-height: 1.6;font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', Arial, sans-serif;"> <pre style="font-size: inherit;color: inherit;line-height: inherit;"><code class="hljs css" style="margin-right: 2px;margin-left: 2px;padding: 0.5em;line-height: 18px;font-size: 14px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;color: rgb(169, 183, 198);display: block !important;word-wrap: normal !important;word-break: normal !important;overflow: auto !important;background: rgb(40, 43, 46);"><span class="hljs-selector-tag" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">node</span><span class="hljs-selector-class" style="font-size: inherit;line-height: inherit;color: rgb(165, 218, 45);word-wrap: inherit !important;word-break: inherit !important;">.master</span>:&nbsp;<span class="hljs-selector-tag" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">false</span>&nbsp;<br><span class="hljs-selector-tag" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">node</span><span class="hljs-selector-class" style="font-size: inherit;line-height: inherit;color: rgb(165, 218, 45);word-wrap: inherit !important;word-break: inherit !important;">.data</span>:&nbsp;<span class="hljs-selector-tag" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">false</span>&nbsp;<br><span class="hljs-selector-tag" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">node</span><span class="hljs-selector-class" style="font-size: inherit;line-height: inherit;color: rgb(165, 218, 45);word-wrap: inherit !important;word-break: inherit !important;">.ingest</span>:&nbsp;<span class="hljs-selector-tag" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">false</span>&nbsp;<br><span class="hljs-selector-tag" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">search</span><span class="hljs-selector-class" style="font-size: inherit;line-height: inherit;color: rgb(165, 218, 45);word-wrap: inherit !important;word-break: inherit !important;">.remote.connect</span>:&nbsp;<span class="hljs-selector-tag" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">false</span><br></code></pre> </section> <p style="white-space: normal;line-height: normal;"><br></p> <p style="margin-right: 8px;margin-left: 8px;white-space: normal;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">增加 Coordinating Nodes 的数量可以提高 API 请求响应的性能,我们也可以针对不同量级的 Index 分配独立的 Coordinating Nodes 来满足请求性能。</span></p> <p style="white-space: normal;line-height: normal;"><br></p> <p style="margin-right: 8px;margin-left: 8px;white-space: normal;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">那是不是越多越好呢?在一定范围内是肯定的,但凡事有个度,过了负作用就会突显,太多的话会给集群增加负担。</span></p> <p style="white-space: normal;line-height: normal;"><br></p> <p style="margin-right: 8px;margin-left: 8px;white-space: normal;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">在做 Master 选举的时候会先确保所有 Node 的 Cluster State 是一致的,同步的时候会等待每个 Node 的 Acknowledgement 确认,所以适量分配可以让集群畅快的工作。</span></p> <p style="white-space: normal;line-height: normal;"><br></p> <p style="margin-right: 8px;margin-bottom: 5px;margin-left: 8px;white-space: normal;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">search.remote.connect 是禁用跨集群查询,防止在进行集群之间查询时发生二次路由:</span></p> <section class="output_wrapper" style="letter-spacing: 0px;white-space: normal;font-size: 16px;color: rgb(62, 62, 62);line-height: 1.6;font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', Arial, sans-serif;"> <pre style="font-size: inherit;color: inherit;line-height: inherit;"><code class="hljs cpp" style="margin-right: 2px;margin-left: 2px;padding: 0.5em;line-height: 18px;font-size: 14px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;color: rgb(169, 183, 198);display: block !important;word-wrap: normal !important;word-break: normal !important;overflow: auto !important;background: rgb(40, 43, 46);">https:<span class="hljs-comment" style="font-size: inherit;line-height: inherit;color: rgb(128, 128, 128);word-wrap: inherit !important;word-break: inherit !important;">//www.elastic.co/guide/en/elasticsearch/reference/current/modules-cross-cluster-search.html</span><br></code></pre> </section> <p style="white-space: normal;line-height: normal;"><br></p> <section style="white-space: normal;box-sizing: border-box;font-size: 16px;"> <section powered-by="xiumi.us" style="box-sizing: border-box;"> <section style="margin-top: 0.5em;margin-bottom: 0.5em;border-bottom-width: 1px;border-bottom-style: solid;border-bottom-color: black;line-height: 1.2;box-sizing: border-box;"> <section style="margin-bottom: -1px;display: inline-block;border-bottom-width: 6px;border-bottom-style: solid;border-color: rgb(89, 89, 89);font-size: 20px;color: rgb(89, 89, 89);box-sizing: border-box;"> <p style="box-sizing: border-box;">Routing</p> </section> </section> </section> </section> <p style="white-space: normal;line-height: normal;"><br></p> <p style="margin-right: 8px;margin-bottom: 5px;margin-left: 8px;white-space: normal;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">类似于分布式数据库中的分片原则,将符合规则的数据存储到同一分片。ES 通过哈希算法来决定数据存储于哪个 Shard:</span></p> <section class="output_wrapper" style="letter-spacing: 0px;white-space: normal;font-size: 16px;color: rgb(62, 62, 62);line-height: 1.6;font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', Arial, sans-serif;"> <pre style="font-size: inherit;color: inherit;line-height: inherit;"><code class="hljs ini" style="margin-right: 2px;margin-left: 2px;padding: 0.5em;line-height: 18px;font-size: 14px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;color: rgb(169, 183, 198);display: block !important;word-wrap: normal !important;word-break: normal !important;overflow: auto !important;background: rgb(40, 43, 46);"><span class="hljs-attr" style="font-size: inherit;line-height: inherit;color: rgb(165, 218, 45);word-wrap: inherit !important;word-break: inherit !important;">shard_num</span>&nbsp;=&nbsp;hash(_routing)&nbsp;%&nbsp;num_primary_shards<br></code></pre> </section> <p style="white-space: normal;line-height: normal;"><br></p> <p style="margin-right: 8px;margin-left: 8px;white-space: normal;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">其中 hash(_routing) 得出一个数字,然后除以主 Shards 的数量得到一个余数,余数的范围是 0 到 number_of_primary_shards - 1,这个数字就是文档所在的 Shard。</span></p> <p style="white-space: normal;line-height: normal;"><br></p> <p style="margin-right: 8px;margin-left: 8px;white-space: normal;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">Routing 默认是 id 值,当然可以自定义,合理指定 Routing 能够大幅提升查询效率,Routing 支持 GET、Delete、Update、Post、Put 等操作。</span></p> <p style="white-space: normal;line-height: normal;"><br></p> <p style="margin-right: 8px;margin-bottom: 5px;margin-left: 8px;white-space: normal;line-height: 1.75em;"><span style="color: rgb(89, 89, 89);font-size: 15px;letter-spacing: 1px;line-height: 1.75em;">如:</span></p> <section class="output_wrapper" style="letter-spacing: 0px;white-space: normal;font-size: 16px;color: rgb(62, 62, 62);line-height: 1.6;font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', Arial, sans-serif;"> <pre style="font-size: inherit;color: inherit;line-height: inherit;"><code class="hljs vbscript" style="margin-right: 2px;margin-left: 2px;padding: 0.5em;line-height: 18px;font-size: 14px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;color: rgb(169, 183, 198);display: block !important;word-wrap: normal !important;word-break: normal !important;overflow: auto !important;background: rgb(40, 43, 46);">PUT&nbsp;my_index/my_type/<span class="hljs-number" style="font-size: inherit;line-height: inherit;color: rgb(174, 135, 250);word-wrap: inherit !important;word-break: inherit !important;">1</span>?routing=user1<br>{<br>&nbsp;&nbsp;<span class="hljs-string" style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);word-wrap: inherit !important;word-break: inherit !important;">"title"</span>:&nbsp;<span class="hljs-string" style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);word-wrap: inherit !important;word-break: inherit !important;">"This&nbsp;is&nbsp;a&nbsp;document"</span><br>}<br><br><span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">GET</span>&nbsp;my_index/my_type/<span class="hljs-number" style="font-size: inherit;line-height: inherit;color: rgb(174, 135, 250);word-wrap: inherit !important;word-break: inherit !important;">1</span>?routing=user1<br></code></pre> </section> <p style="white-space: normal;line-height: normal;"><br></p> <p style="margin-right: 8px;margin-bottom: 5px;margin-left: 8px;white-space: normal;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(71, 193, 168);">不指定 Routing 的查询过程:</span></p> <p style="margin-right: 8px;margin-bottom: 5px;margin-left: 8px;white-space: normal;text-align: center;line-height: 1.75em;"><img class="" data-copyright="0" data-ratio="0.7399813606710158" data-s="300,640" src="/upload/27ac3042d3436ebd679df1a7561bb0d.png" data-type="png" data-w="1073"></p> <p style="margin-right: 8px;margin-left: 8px;white-space: normal;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">简单的来说,一个查询请求过来以后会查询每个 Shard,然后做结果聚合,总的时间大概就是所有 Shard 查询所消耗的时间之和。</span></p> <p style="white-space: normal;line-height: normal;"><br></p> <p style="margin-right: 8px;margin-bottom: 5px;margin-left: 8px;white-space: normal;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(71, 193, 168);">指定 Routing 以后:</span></p> <p style="margin-right: 8px;margin-bottom: 5px;margin-left: 8px;white-space: normal;text-align: center;line-height: 1.75em;"><img class="" data-copyright="0" data-ratio="0.36363636363636365" data-s="300,640" src="/upload/3e43c187addfbba7c190fb5dfc5c5283.png" data-type="png" data-w="2178"></p> <p style="margin-right: 8px;margin-left: 8px;white-space: normal;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">会根据 Routing 查询特定的一个或多个 Shard,这样就大大减少了查询时间,提高了查询效率。</span></p> <p style="white-space: normal;line-height: normal;"><br></p> <p style="margin-right: 8px;margin-left: 8px;white-space: normal;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">当然,如何设置 Routing 是一个难点,需要一点技巧,要根据业务特点合理组合 Routing 的值,来划分 Shard 的存储,最终保持数据量相对均衡。</span></p> <p style="white-space: normal;line-height: normal;"><br></p> <p style="margin-right: 8px;margin-left: 8px;white-space: normal;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">可以组合几个维度做为 Routing ,有点类似于 Hbase Key,</span><span style="font-size: 15px;letter-spacing: 1px;color: rgb(71, 193, 168);">例如不同的业务线加不同的类别,不同的城市和不同的类型等等,如:</span></p> <ul class=" list-paddingleft-2"> <li><p style="line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">_search?routing=beijing:</span></strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">按城市。</span></p></li> <li><p style="line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">_search?routing=beijing_user123:</span></strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">按城市和用户。</span></p></li> <li><p style="line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">_search?routing=beijing_android,shanghai_android:</span></strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">按城市和手机类型等。</span></p></li> </ul> <p style="white-space: normal;line-height: normal;"><br></p> <p style="margin-right: 8px;margin-left: 8px;white-space: normal;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">数据不均衡?</span><span style="color: rgb(89, 89, 89);font-size: 15px;letter-spacing: 1px;line-height: 1.75em;">假如你的业务在北京、上海的数据远远大于其他二三线城市的数据。</span></p> <p style="white-space: normal;line-height: normal;"><br></p> <p style="margin-right: 8px;margin-left: 8px;white-space: normal;line-height: 1.75em;"><span style="color: rgb(89, 89, 89);font-size: 15px;letter-spacing: 1px;line-height: 1.75em;">再例如我们的业务场景,A 业务线的数据量级远远大于 B 业务线,有时候很难通过 Routing 指定一个值保证数据在所有 Shards 上均匀分布,会让部分 Shard 变的越来越大,影响查询性能,怎么办?</span></p> <p style="white-space: normal;line-height: normal;"><br></p> <p style="margin-right: 8px;margin-bottom: 5px;margin-left: 8px;white-space: normal;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">一种解决办法是单独为这些数据量大的渠道创建独立的 Index,如:</span></p> <section class="output_wrapper" style="letter-spacing: 0px;white-space: normal;font-size: 16px;color: rgb(62, 62, 62);line-height: 1.6;font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', Arial, sans-serif;"> <pre style="font-size: inherit;color: inherit;line-height: inherit;"><code class="hljs cpp" style="margin-right: 2px;margin-left: 2px;padding: 0.5em;line-height: 18px;font-size: 14px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;color: rgb(169, 183, 198);display: block !important;word-wrap: normal !important;word-break: normal !important;overflow: auto !important;background: rgb(40, 43, 46);">http:<span class="hljs-comment" style="font-size: inherit;line-height: inherit;color: rgb(128, 128, 128);word-wrap: inherit !important;word-break: inherit !important;">//localhost:9200/shanghai,beijing,other/_search?routing=android</span><br></code></pre> </section> <p style="white-space: normal;line-height: normal;"><br></p> <p style="margin-right: 8px;margin-left: 8px;white-space: normal;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">这样可以根据需要在不同 Index 之间查询,然而每个 Index 中 Shards 的数据可以做到相对均衡。</span></p> <p style="white-space: normal;line-height: normal;"><br></p> <p style="margin-right: 8px;margin-bottom: 5px;margin-left: 8px;white-space: normal;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">另一种办法是指定 Index 参数 index.routing_partition_size,来解决最终可能产生群集不均衡的问题,指定这个参数后新的算法如下:</span></p> <section class="output_wrapper" style="letter-spacing: 0px;white-space: normal;font-size: 16px;color: rgb(62, 62, 62);line-height: 1.6;font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', Arial, sans-serif;"> <pre style="font-size: inherit;color: inherit;line-height: inherit;"><code class="hljs bash" style="margin-right: 2px;margin-left: 2px;padding: 0.5em;line-height: 18px;font-size: 14px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;color: rgb(169, 183, 198);display: block !important;word-wrap: normal !important;word-break: normal !important;overflow: auto !important;background: rgb(40, 43, 46);">shard_num&nbsp;=&nbsp;(<span class="hljs-built_in" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">hash</span>(_routing)&nbsp;+&nbsp;<span class="hljs-built_in" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">hash</span>(_id)&nbsp;%&nbsp;routing_partition_size)&nbsp;%&nbsp;num_primary_shards<br></code></pre> </section> <p style="white-space: normal;line-height: normal;"><br></p> <p style="margin-right: 8px;margin-left: 8px;white-space: normal;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">index.routing_partition_size 应具有大于 1 且小于 index.number_of_shards 的值。</span></p> <p style="white-space: normal;line-height: normal;"><br></p> <p style="margin-right: 8px;margin-left: 8px;white-space: normal;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">最终数据会在 routing_partition_size 几个 Shard 上均匀存储,是哪个 Shard 取决于 hash(_id) % routing_partition_size 的计算结果。</span></p> <p style="white-space: normal;line-height: normal;"><br></p> <p style="margin-right: 8px;margin-left: 8px;white-space: normal;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">指定参数 index.routing_partition_size 后,索引中的 Mappings 必须指定 _routing 为 "required": true,另外 Mappings 不支持 parent-child 父子关系。</span></p> <p style="white-space: normal;line-height: normal;"><br></p> <p style="margin-right: 8px;margin-left: 8px;white-space: normal;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">很多情况下,指定 Routing 后会大幅提升查询性能,毕竟查询的 Shard 只有那么几个,但是如何设置 Routing 是个难题,可根据业务特性巧妙组合。</span></p> <p style="white-space: normal;line-height: normal;"><br></p> <section style="white-space: normal;box-sizing: border-box;font-size: 16px;"> <section powered-by="xiumi.us" style="box-sizing: border-box;"> <section style="margin-top: 0.5em;margin-bottom: 0.5em;border-bottom-width: 1px;border-bottom-style: solid;border-bottom-color: black;line-height: 1.2;box-sizing: border-box;"> <section style="margin-bottom: -1px;display: inline-block;border-bottom-width: 6px;border-bottom-style: solid;border-color: rgb(89, 89, 89);font-size: 20px;color: rgb(89, 89, 89);box-sizing: border-box;"> <p style="box-sizing: border-box;">索引拆分</p> </section> </section> </section> </section> <p style="white-space: normal;line-height: normal;"><br></p> <p style="margin-right: 8px;margin-left: 8px;white-space: normal;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">Index 通过横向扩展 Shards 实现分布式存储,这样可以解决 Index 大数据存储的问题。</span></p> <p style="white-space: normal;line-height: normal;"><br></p> <p style="margin-right: 8px;margin-left: 8px;white-space: normal;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">但在一个 Index 变的越来越大,单个 Shard 也越来越大,查询和存储的速度也越来越慢。</span></p> <p style="white-space: normal;line-height: normal;"><br></p> <p style="margin-right: 8px;margin-left: 8px;white-space: normal;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">更重要的是一个 Index 其实是有存储上限的(除非你设置足够多的 Shards 和机器),如官方声明单个 Shard 的文档数不能超过 20 亿(受限于 Lucene index,每个 Shard 是一个 Lucene index)。</span></p> <p style="white-space: normal;line-height: normal;"><br></p> <p style="margin-right: 8px;margin-left: 8px;white-space: normal;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">考虑到 I、O,针对 Index 每个 Node 的 Shards 数最好不超过 3 个,那面对这样一个庞大的 Index,我们是采用更多的 Shards,还是更多的 Index,我们如何选择?</span></p> <p style="white-space: normal;line-height: normal;"><br></p> <p style="margin-right: 8px;margin-left: 8px;white-space: normal;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">Index 的 Shards 总量也不宜太多,更多的 Shards 会带来更多的 I、O 开销,其实答案就已经很明确,除非你能接受长时间的查询等待。</span></p> <p style="white-space: normal;line-height: normal;"><br></p> <p style="margin-right: 8px;margin-left: 8px;white-space: normal;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">Index 拆分的思路很简单,时序索引有一个好处就是只有增加,没有变更,按时间累积,天然对索引的拆分友好支持,可以按照时间和数据量做任意时间段的拆分。</span></p> <p style="white-space: normal;line-height: normal;"><br></p> <p style="margin-right: 8px;margin-left: 8px;white-space: normal;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">ES 提供的 Rollover Api + Index Template 可以非常便捷和友好的实现 Index 的拆分工作,把单个 index docs 数量控制在百亿内,也就是一个 Index 默认 5 个 Shards 左右即可,保证查询的即时响应。</span></p> <p style="white-space: normal;line-height: normal;"><br></p> <p style="margin-right: 8px;margin-left: 8px;white-space: normal;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">简单介绍一下 Rollover API 和 Index Template 这两个东西,如何实现 index 的拆分。</span></p> <p style="white-space: normal;line-height: normal;"><br></p> <section style="white-space: normal;box-sizing: border-box;font-size: 16px;"> <section powered-by="xiumi.us" style="box-sizing: border-box;"> <section style="margin-top: 10px;margin-bottom: 10px;box-sizing: border-box;"> <section style="width: 0.6em;display: inline-block;vertical-align: middle;box-sizing: border-box;"> <span style="width: 0.6em;height: 0.6em;display: block;opacity: 0.2;box-sizing: border-box;background-color: rgb(89, 89, 89);"></span> <strong><span style="margin-top: 2px;margin-bottom: 2px;width: 0.6em;height: 0.6em;display: block;opacity: 0.6;box-sizing: border-box;background-color: rgb(89, 89, 89);"></span><span style="width: 0.6em;height: 0.6em;display: block;opacity: 1;box-sizing: border-box;background-color: rgb(89, 89, 89);"></span></strong> </section> <section style="padding-left: 5px;display: inline-block;vertical-align: middle;font-size: 18px;color: rgb(89, 89, 89);box-sizing: border-box;"> <p style="box-sizing: border-box;"><strong>Index Template</strong></p> </section> </section> </section> </section> <p style="white-space: normal;line-height: normal;"><br></p> <p style="margin-right: 8px;margin-left: 8px;white-space: normal;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">我们知道 ES 可以为同一目的或同一类索引创建一个 Index Template,之后创建的索引只要符合匹配规则就会套用这个 Template,不必每次指定 Settings 和 Mappings 等属性。</span></p> <p style="white-space: normal;line-height: normal;"><br></p> <p style="margin-right: 8px;margin-left: 8px;white-space: normal;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">一个 Index 可以被多个 Template 匹配,那 Settings 和 Mappings 就是多个 Template 合并后的结果。</span></p> <p style="white-space: normal;line-height: normal;"><br></p> <p style="margin-right: 8px;margin-left: 8px;white-space: normal;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">有冲突通过 Template 的属性"order" : 0 从低到高覆盖(这部分据说会在 ES6 中会做调整,更好的解决 Template 匹配冲突问题)。</span></p> <p style="white-space: normal;line-height: normal;"><br></p> <p style="margin-right: 8px;margin-bottom: 5px;margin-left: 8px;white-space: normal;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(71, 193, 168);">示例:</span></p> <section class="output_wrapper" style="letter-spacing: 0px;white-space: normal;font-size: 16px;color: rgb(62, 62, 62);line-height: 1.6;font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', Arial, sans-serif;"> <pre style="font-size: inherit;color: inherit;line-height: inherit;"><code class="hljs bash" style="margin-right: 2px;margin-left: 2px;padding: 0.5em;line-height: 18px;font-size: 14px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;color: rgb(169, 183, 198);display: block !important;word-wrap: normal !important;word-break: normal !important;overflow: auto !important;background: rgb(40, 43, 46);">PUT&nbsp;_template/template_1<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-string" style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);word-wrap: inherit !important;word-break: inherit !important;">"index_patterns"</span>&nbsp;:&nbsp;[<span class="hljs-string" style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);word-wrap: inherit !important;word-break: inherit !important;">"log-*"</span>],<br>&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-string" style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);word-wrap: inherit !important;word-break: inherit !important;">"order"</span>&nbsp;:&nbsp;0,<br>&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-string" style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);word-wrap: inherit !important;word-break: inherit !important;">"settings"</span>&nbsp;:&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-string" style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);word-wrap: inherit !important;word-break: inherit !important;">"number_of_shards"</span>&nbsp;:&nbsp;5<br>&nbsp;&nbsp;&nbsp;&nbsp;},<br>&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-string" style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);word-wrap: inherit !important;word-break: inherit !important;">"aliases"</span>&nbsp;:&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-string" style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);word-wrap: inherit !important;word-break: inherit !important;">"alias1"</span>&nbsp;:&nbsp;{}<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>}<br></code></pre> </section> <p style="white-space: normal;line-height: normal;"><br></p> <section style="white-space: normal;box-sizing: border-box;font-size: 16px;"> <section powered-by="xiumi.us" style="box-sizing: border-box;"> <section style="margin-top: 10px;margin-bottom: 10px;box-sizing: border-box;"> <section style="width: 0.6em;display: inline-block;vertical-align: middle;box-sizing: border-box;"> <span style="width: 0.6em;height: 0.6em;display: block;opacity: 0.2;box-sizing: border-box;background-color: rgb(89, 89, 89);"></span> <strong><span style="margin-top: 2px;margin-bottom: 2px;width: 0.6em;height: 0.6em;display: block;opacity: 0.6;box-sizing: border-box;background-color: rgb(89, 89, 89);"></span><span style="width: 0.6em;height: 0.6em;display: block;opacity: 1;box-sizing: border-box;background-color: rgb(89, 89, 89);"></span></strong> </section> <section style="padding-left: 5px;display: inline-block;vertical-align: middle;font-size: 18px;color: rgb(89, 89, 89);box-sizing: border-box;"> <p style="box-sizing: border-box;"><strong>Rollover Index</strong></p> </section> </section> </section> </section> <p style="white-space: normal;line-height: normal;"><br></p> <p style="margin-right: 8px;margin-bottom: 5px;margin-left: 8px;white-space: normal;text-align: center;line-height: 1.75em;"><img class="" data-copyright="0" data-ratio="0.2978723404255319" data-s="300,640" src="/upload/89a688c359ce6d1c51ea43d03cfd5cdd.png" data-type="png" data-w="658"></p> <p style="margin-right: 8px;margin-bottom: 5px;margin-left: 8px;white-space: normal;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">Rollover Index 可以将现有的索引通过一定的规则,如数据量和时间,索引的命名必须是 logs-000001 这种格式,并指定 aliases,示例:</span></p> <section class="output_wrapper" style="letter-spacing: 0px;white-space: normal;font-size: 16px;color: rgb(62, 62, 62);line-height: 1.6;font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', Arial, sans-serif;"> <pre style="font-size: inherit;color: inherit;line-height: inherit;"><code class="hljs bash" style="margin-right: 2px;margin-left: 2px;padding: 0.5em;line-height: 18px;font-size: 14px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;color: rgb(169, 183, 198);display: block !important;word-wrap: normal !important;word-break: normal !important;overflow: auto !important;background: rgb(40, 43, 46);">PUT&nbsp;/logs-000001&nbsp;<br>{<br>&nbsp;&nbsp;<span class="hljs-string" style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);word-wrap: inherit !important;word-break: inherit !important;">"aliases"</span>:&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-string" style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);word-wrap: inherit !important;word-break: inherit !important;">"logs_write"</span>:&nbsp;{}<br>&nbsp;&nbsp;}<br>}<br><br><span class="hljs-comment" style="font-size: inherit;line-height: inherit;color: rgb(128, 128, 128);word-wrap: inherit !important;word-break: inherit !important;">#&nbsp;Add&nbsp;&gt;&nbsp;1000&nbsp;documents&nbsp;to&nbsp;logs-000001</span><br><br>POST&nbsp;/logs_write/_rollover&nbsp;<br>{<br>&nbsp;&nbsp;<span class="hljs-string" style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);word-wrap: inherit !important;word-break: inherit !important;">"conditions"</span>:&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-string" style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);word-wrap: inherit !important;word-break: inherit !important;">"max_age"</span>:&nbsp;&nbsp;&nbsp;<span class="hljs-string" style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);word-wrap: inherit !important;word-break: inherit !important;">"7d"</span>,<br>&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-string" style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);word-wrap: inherit !important;word-break: inherit !important;">"max_docs"</span>:&nbsp;&nbsp;1000<br>&nbsp;&nbsp;}<br>}<br></code></pre> </section> <p style="white-space: normal;line-height: normal;"><br></p> <p style="margin-right: 8px;margin-left: 8px;white-space: normal;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">先创建索引并指定别名 logs_write,插入 1000 条数据,然后请求 _rollover api 并指定拆分规则。</span></p> <p style="white-space: normal;line-height: normal;"><br></p> <p style="margin-right: 8px;margin-left: 8px;white-space: normal;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">如果索引中的数据大于规则中指定的数据量或者时间过时,新的索引将被创建,索引名称为 logs-000002,并根据规则套用 Index Template,同时别名 logs_write 也将被变更到 logs-000002。</span></p> <p style="white-space: normal;line-height: normal;"><br></p> <p style="margin-right: 8px;margin-left: 8px;white-space: normal;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(71, 193, 168);">注意事项:</span></p> <ul class=" list-paddingleft-2"> <li><p style="line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">索引命名规则必须如同:logs-000001。</span></p></li> <li><p style="line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">索引必须指定 aliases。</span></p></li> <li><p style="line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">Rollover Index API 调用时才去检查索引是否超出指定规则,不会自动触发,需要手动调用,可以通过 Curator 实现自动化。</span></p></li> <li><p style="line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">如果符合条件会创建新的索引,老索引的数据不会发生变化,如果你已经插入 2000 条,拆分后还是 2000 条。</span></p></li> <li><p style="line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">插入数据时一定要用别名,否则你可能一直在往一个索引里追加数据。</span></p></li> </ul> <p style="white-space: normal;line-height: normal;"><br></p> <p style="margin-right: 8px;margin-bottom: 5px;margin-left: 8px;white-space: normal;line-height: 1.75em;"><span style="color: rgb(71, 193, 168);"><span style="font-size: 15px;letter-spacing: 1px;">技巧是</span><span style="font-size: 15px;letter-spacing: 1px;line-height: 1.75em;">按日期滚动索引:</span></span></p> <section class="output_wrapper" style="letter-spacing: 0px;white-space: normal;font-size: 16px;color: rgb(62, 62, 62);line-height: 1.6;font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', Arial, sans-serif;"> <pre style="font-size: inherit;color: inherit;line-height: inherit;"><code class="hljs vbscript" style="margin-right: 2px;margin-left: 2px;padding: 0.5em;line-height: 18px;font-size: 14px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;color: rgb(169, 183, 198);display: block !important;w

超详细的Elasticsearch高性能优化实践

作者:微信小助手

<section style="box-sizing: border-box;font-size: 16px;"> <section style="box-sizing: border-box;" powered-by="xiumi.us"> <section style="margin-top: 10px;margin-bottom: 10px;box-sizing: border-box;"> <section style="padding-top: 10px;padding-right: 10px;padding-left: 10px;box-sizing: border-box;background-color: rgb(239, 239, 239);"> <span style="display: inline-block;width: 5%;line-height: 0.8;font-weight: bolder;font-size: 48px;box-sizing: border-box;"> <section style="box-sizing: border-box;"> “ </section></span> <section style="display: inline-block;vertical-align: top;float: right;width: 90%;line-height: 1.5;font-size: 15px;color: rgb(89, 89, 89);box-sizing: border-box;"> <p style="box-sizing: border-box;"><span style="letter-spacing: 1px;">之前分享的一篇《<a href="http://mp.weixin.qq.com/s?__biz=MjM5ODI5Njc2MA==&amp;mid=2655824132&amp;idx=1&amp;sn=632d25f325a8de625197b3e3e402b279&amp;chksm=bd74e4d38a036dc5968aca6af5061037c1103115f11cbc27baa992d5d1b5b27968e055e64c82&amp;scene=21#wechat_redirect" target="_blank" data-itemshowtype="0" data-linktype="2">掌握它才说明你真正懂 Elasticsearch</a>》相信让大家对 ES 的原理都有所了解,这篇将从 ES 的 API 应用测试,性能优化,开发使用等方面展开,深入学习 ES。</span></p> </section> <section style="clear: both;box-sizing: border-box;"></section> </section> </section> </section> </section> <p style="line-height: 1.75em;"><br></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;margin-bottom: 5px;"><img class="rich_pages" data-copyright="0" data-ratio="0.5083870967741936" data-s="300,640" src="/upload/6b38a9e45d02a9823f02ff7d4d4ddd9f.png" data-type="png" data-w="775" style=""></p> <section style="white-space: normal;box-sizing: border-box;font-size: 16px;"> <section powered-by="xiumi.us" style="box-sizing: border-box;"> <section style="margin-top: 0.5em;margin-bottom: 0.5em;border-bottom-width: 1px;border-bottom-style: solid;border-bottom-color: black;line-height: 1.2;box-sizing: border-box;"> <section style="margin-bottom: -1px;display: inline-block;border-bottom-width: 6px;border-bottom-style: solid;border-color: rgb(89, 89, 89);font-size: 20px;color: rgb(89, 89, 89);box-sizing: border-box;"> <p style="box-sizing: border-box;">ES 性能调优</p> </section> </section> </section> </section> <p style="white-space: normal;line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">ES 的默认配置,是综合了数据可靠性、写入速度、搜索实时性等因素。实际使用时,我们需要根据公司要求,进行偏向性的优化。</span></p> <p style="line-height: normal;"><br></p> <section style="white-space: normal;box-sizing: border-box;font-size: 16px;"> <section powered-by="xiumi.us" style="box-sizing: border-box;"> <section style="margin-top: 10px;margin-bottom: 10px;box-sizing: border-box;"> <section style="width: 0.6em;display: inline-block;vertical-align: middle;box-sizing: border-box;"> <span style="width: 0.6em;height: 0.6em;display: block;opacity: 0.2;box-sizing: border-box;background-color: rgb(89, 89, 89);"></span> <span style="margin-top: 2px;margin-bottom: 2px;width: 0.6em;height: 0.6em;display: block;opacity: 0.6;box-sizing: border-box;background-color: rgb(89, 89, 89);"></span> <span style="width: 0.6em;height: 0.6em;display: block;opacity: 1;box-sizing: border-box;background-color: rgb(89, 89, 89);"></span> </section> <section style="padding-left: 5px;display: inline-block;vertical-align: middle;font-size: 18px;color: rgb(89, 89, 89);box-sizing: border-box;"> <p style="box-sizing: border-box;"><strong>写优化</strong></p> </section> </section> </section> </section> <p><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">假设我们的应用场景要求是,每秒 300 万的写入速度,每条 500 字节左右。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">针对这种对于搜索性能要求不高,但是对写入要求较高的场景,我们需要尽可能的选择恰当写优化策略。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(71, 193, 168);">综合来说,可以考虑以下几个方面来提升写索引的性能:</span></p> <ul class=" list-paddingleft-2" style="list-style-type: disc;"> <li><p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">加大 Translog Flush ,目的是降低 Iops、Writeblock。</span></p></li> <li><p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">增加 Index Refresh 间隔,目的是减少 Segment Merge 的次数。</span></p></li> <li><p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">调整 Bulk 线程池和队列。</span></p></li> <li><p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">优化节点间的任务分布。</span></p></li> <li><p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">优化 Lucene 层的索引建立,目的是降低 CPU 及 IO。</span></p></li> </ul> <p style="line-height: normal;"><br></p> <h5 data-anchor-id="43ez" style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">①批量提交</span></strong></h5> <p style="line-height: normal;"><br></p> <p style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">ES 提供了 Bulk API 支持批量操作,当我们有大量的写任务时,可以使用 Bulk 来进行批量写入。</span></p> <p style="line-height: normal;"><br></p> <p style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">每次提交的数据量为多少时,能达到最优的性能,主要受到文件大小、网络情况、数据类型、集群状态等因素影响。&nbsp;</span></p> <p style="line-height: normal;"><br></p> <p style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">通用的策略如下:</span></strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">Bulk 默认设置批量提交的数据量不能超过 100M。数据条数一般是根据文档的大小和服务器性能而定的,但是单次批处理的数据大小应从 5MB~15MB 逐渐增加,当性能没有提升时,把这个数据量作为最大值。</span></p> <p style="line-height: normal;"><br></p> <p style="margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">我们可以跟着,感受一下 Bulk 接口,如下所示:</span></p> <section class="output_wrapper" style="font-size: 16px;color: rgb(62, 62, 62);line-height: 1.6;letter-spacing: 0px;font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', Arial, sans-serif;"> <pre style="font-size: inherit;color: inherit;line-height: inherit;"><code class="hljs php" style="margin-right: 2px;margin-left: 2px;line-height: 18px;font-size: 14px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;color: rgb(169, 183, 198);padding: 0.5em;display: block !important;word-wrap: normal !important;word-break: normal !important;overflow: auto !important;background: rgb(40, 43, 46);">$&nbsp;vi&nbsp;request<br>$&nbsp;cat&nbsp;request<br>{&nbsp;<span class="hljs-string" style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);word-wrap: inherit !important;word-break: inherit !important;">"index"</span>&nbsp;:&nbsp;{&nbsp;<span class="hljs-string" style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);word-wrap: inherit !important;word-break: inherit !important;">"_index"</span>&nbsp;:&nbsp;<span class="hljs-string" style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);word-wrap: inherit !important;word-break: inherit !important;">"chandler"</span>,<span class="hljs-string" style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);word-wrap: inherit !important;word-break: inherit !important;">"_type"</span>:&nbsp;<span class="hljs-string" style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);word-wrap: inherit !important;word-break: inherit !important;">"test"</span>,&nbsp;<span class="hljs-string" style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);word-wrap: inherit !important;word-break: inherit !important;">"_id"</span>&nbsp;:&nbsp;<span class="hljs-string" style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);word-wrap: inherit !important;word-break: inherit !important;">"1"</span>&nbsp;}&nbsp;}<br>{&nbsp;<span class="hljs-string" style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);word-wrap: inherit !important;word-break: inherit !important;">"name"</span>&nbsp;:&nbsp;<span class="hljs-string" style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);word-wrap: inherit !important;word-break: inherit !important;">"钱丁君"</span>,<span class="hljs-string" style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);word-wrap: inherit !important;word-break: inherit !important;">"age"</span>:&nbsp;<span class="hljs-string" style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);word-wrap: inherit !important;word-break: inherit !important;">"18"</span>&nbsp;}<br>$&nbsp;curl&nbsp;-s&nbsp;-H&nbsp;<span class="hljs-string" style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);word-wrap: inherit !important;word-break: inherit !important;">"Content-Type:&nbsp;application/json"</span>&nbsp;-XPOST&nbsp;localhost:<span class="hljs-number" style="font-size: inherit;line-height: inherit;color: rgb(174, 135, 250);word-wrap: inherit !important;word-break: inherit !important;">9200</span>/_bulk&nbsp;--data-binary&nbsp;@request;&nbsp;<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">echo</span><br>{<span class="hljs-string" style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);word-wrap: inherit !important;word-break: inherit !important;">"took"</span>:<span class="hljs-number" style="font-size: inherit;line-height: inherit;color: rgb(174, 135, 250);word-wrap: inherit !important;word-break: inherit !important;">214</span>,<span class="hljs-string" style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);word-wrap: inherit !important;word-break: inherit !important;">"errors"</span>:<span class="hljs-keyword" style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);word-wrap: inherit !important;word-break: inherit !important;">false</span>,<span class="hljs-string" style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);word-wrap: inherit !important;word-break: inherit !important;">"items"</span>:[{<span class="hljs-string" style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);word-wrap: inherit !important;word-break: inherit !important;">"index"</span>:{<span class="hljs-string" style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);word-wrap: inherit !important;word-break: inherit !important;">"_index"</span>:<span class="hljs-string" style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);word-wrap: inherit !important;word-break: inherit !important;">"chandler"</span>,<span class="hljs-string" style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);word-wrap: inherit !important;word-break: inherit !important;">"_type"</span>:<span class="hljs-string" style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);word-wrap: inherit !important;word-break: inherit !important;">"test"</span>,<span class="hljs-string" style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);word-wrap: inherit !important;word-break: inherit !important;">"_id"</span>:<span class="hljs-string" style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);word-wrap: inherit !important;word-break: inherit !important;">"1"</span>,<span class="hljs-string" style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);word-wrap: inherit !important;word-break: inherit !important;">"_version"</span>:<span class="hljs-number" style="font-size: inherit;line-height: inherit;color: rgb(174, 135, 250);word-wrap: inherit !important;word-break: inherit !important;">1</span>,<span class="hljs-string" style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);word-wrap: inherit !important;word-break: inherit !important;">"result"</span>:<span class="hljs-string" style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);word-wrap: inherit !important;word-break: inherit !important;">"created"</span>,<span class="hljs-string" style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);word-wrap: inherit !important;word-break: inherit !important;">"_shards"</span>:{<span class="hljs-string" style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);word-wrap: inherit !important;word-break: inherit !important;">"total"</span>:<span class="hljs-number" style="font-size: inherit;line-height: inherit;color: rgb(174, 135, 250);word-wrap: inherit !important;word-break: inherit !important;">2</span>,<span class="hljs-string" style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);word-wrap: inherit !important;word-break: inherit !important;">"successful"</span>:<span class="hljs-number" style="font-size: inherit;line-height: inherit;color: rgb(174, 135, 250);word-wrap: inherit !important;word-break: inherit !important;">1</span>,<span class="hljs-string" style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);word-wrap: inherit !important;word-break: inherit !important;">"failed"</span>:<span class="hljs-number" style="font-size: inherit;line-height: inherit;color: rgb(174, 135, 250);word-wrap: inherit !important;word-break: inherit !important;">0</span>},<span class="hljs-string" style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);word-wrap: inherit !important;word-break: inherit !important;">"_seq_no"</span>:<span class="hljs-number" style="font-size: inherit;line-height: inherit;color: rgb(174, 135, 250);word-wrap: inherit !important;word-break: inherit !important;">0</span>,<span class="hljs-string" style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);word-wrap: inherit !important;word-break: inherit !important;">"_primary_term"</span>:<span class="hljs-number" style="font-size: inherit;line-height: inherit;color: rgb(174, 135, 250);word-wrap: inherit !important;word-break: inherit !important;">1</span>,<span class="hljs-string" style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);word-wrap: inherit !important;word-break: inherit !important;">"status"</span>:<span class="hljs-number" style="font-size: inherit;line-height: inherit;color: rgb(174, 135, 250);word-wrap: inherit !important;word-break: inherit !important;">201</span>}}]}<br>$&nbsp;curl&nbsp;-XGET&nbsp;localhost:<span class="hljs-number" style="font-size: inherit;line-height: inherit;color: rgb(174, 135, 250);word-wrap: inherit !important;word-break: inherit !important;">9200</span>/chandler/test/<span class="hljs-number" style="font-size: inherit;line-height: inherit;color: rgb(