作者:微信小助手
<section class="xmteditor" style="display:none;" data-tools="新媒体管家" data-label="powered by xmt.cn"></section> <p><img class="" data-backh="291" data-backw="654" data-before-oversubscription-url="http://mmbiz.qpic.cn/mmbiz_jpg/l89kosVutokUHRNwJ4MFA9ej36Ry1MHibYxMtEBq4iaUtHVkDTPEic2edmOXlswVAiaWOK9icv57rD0ltQe339bRIiaw/?wx_fmt=jpeg" data-croporisrc="/upload/bb7063a7c8d902bf4de436328d6ee139.png" data-cropx1="0" data-cropx2="660.9999999999999" data-cropy1="0" data-cropy2="295.12538226299694" data-ratio="0.44478063540090773" src="https://mmbiz.qpic.cn/mmbiz_jpg/l89kosVutokUHRNwJ4MFA9ej36Ry1MHibYxMtEBq4iaUtHVkDTPEic2edmOXlswVAiaWOK9icv57rD0ltQe339bRIiaw/640?wx_fmt=jpeg" data-type="jpeg" data-w="661" style="width: 100%;height: auto;"></p> <p><br></p> <h2 style="margin-top: 10px;margin-bottom: 10px;font-weight: bold;font-size: 1.4em;white-space: normal;border-bottom: 1px solid rgb(238, 238, 238);line-height: 1.75em;"><span style="font-size: 20px;color: rgb(171, 25, 66);">1. 服务异常的处理流程</span><br></h2> <p style="white-space: normal;text-align: center;line-height: 1.75em;margin-top: 1.2em !important;margin-bottom: 1.2em !important;"><img class="" data-ratio="1.1121751025991793" src="/upload/fdf0eec33e058f21f0794d409ea12a45.png" data-type="png" data-w="731"></p> <h2 style="margin-top: 10px;margin-bottom: 10px;font-weight: bold;font-size: 1.4em;white-space: normal;border-bottom: 1px solid rgb(238, 238, 238);line-height: 1.75em;"><span style="color: rgb(171, 25, 66);font-size: 20px;">2. 负载</span></h2> <h3 style="margin-top: 10px;margin-bottom: 10px;font-weight: bold;font-size: 1.3em;white-space: normal;line-height: 1.75em;"><span style="font-size: 18px;">2.1 查看机器 cpu 的负载</span></h3> <pre style="margin-top: 1.2em;margin-bottom: 1.2em;font-size: 1em;font-family: Consolas, Inconsolata, Courier, monospace;line-height: 1.2em;"> <section data-mpa-preserve-tpl-color="t" data-mpa-template="t" class="mpa-template" mpa-preserve="t" mpa-from-tpl="t"> <pre style="margin:0;padding:0;border-radius:none;background:none;"><code style="border-radius: 4px;font-size: 0.85em;margin: 0px 0.15em;background: rgb(40, 44, 52);color: rgb(171, 178, 191);display: block;padding: 5.95px;overflow-x: auto;white-space: nowrap;" class="hljs-default"><span class="hljs-default-attribute" style="color: rgb(152, 195, 121);background: rgba(0, 0, 0, 0);display: inline;width: 20px;text-decoration: none solid rgb(152, 195, 121);font-weight: 400;font-style: normal;">top</span> -b -n 1 |grep java|awk '{print <span class="hljs-default-string" style="color: rgb(152, 195, 121);background: rgba(0, 0, 0, 0);display: inline;width: 46px;text-decoration: none solid rgb(152, 195, 121);font-weight: 400;font-style: normal;">"VIRT:"</span><span class="hljs-default-number" style="color: rgb(209, 154, 102);background: rgba(0, 0, 0, 0);display: inline;width: 13px;text-decoration: none solid rgb(209, 154, 102);font-weight: 400;font-style: normal;">$5</span>,<span class="hljs-default-string" style="color: rgb(152, 195, 121);background: rgba(0, 0, 0, 0);display: inline;width: 39px;text-decoration: none solid rgb(152, 195, 121);font-weight: 400;font-style: normal;">"RES:"</span><span class="hljs-default-number" style="color: rgb(209, 154, 102);background: rgba(0, 0, 0, 0);display: inline;width: 13px;text-decoration: none solid rgb(209, 154, 102);font-weight: 400;font-style: normal;">$6</span>,<span class="hljs-default-string" style="color: rgb(152, 195, 121);background: rgba(0, 0, 0, 0);display: inline;width: 39px;text-decoration: none solid rgb(152, 195, 121);font-weight: 400;font-style: normal;">"cpu:"</span><span class="hljs-default-number" style="color: rgb(209, 154, 102);background: rgba(0, 0, 0, 0);display: inline;width: 13px;text-decoration: none solid rgb(209, 154, 102);font-weight: 400;font-style: normal;">$9</span><span class="hljs-default-string" style="color: rgb(152, 195, 121);background: rgba(0, 0, 0, 0);display: inline;width: 19px;text-decoration: none solid rgb(152, 195, 121);font-weight: 400;font-style: normal;">"%"</span>,<span class="hljs-default-string" style="color: rgb(152, 195, 121);background: rgba(0, 0, 0, 0);display: inline;width: 39px;text-decoration: none solid rgb(152, 195, 121);font-weight: 400;font-style: normal;">"mem:"</span><span class="hljs-default-number" style="color: rgb(209, 154, 102);background: rgba(0, 0, 0, 0);display: inline;width: 20px;text-decoration: none solid rgb(209, 154, 102);font-weight: 400;font-style: normal;">$10</span><span class="hljs-default-string" style="color: rgb(152, 195, 121);background: rgba(0, 0, 0, 0);display: inline;width: 20px;text-decoration: none solid rgb(152, 195, 121);font-weight: 400;font-style: normal;">"%"</span>}'</code></pre> </section><p><span style="font-size: 12px;"></span><br></p></pre> <h3 style="margin-top: 10px;margin-bottom: 10px;font-weight: bold;font-size: 1.3em;white-space: normal;line-height: 1.75em;"><span style="font-size: 18px;">2.2 查找 cpu 占用率高的线程</span></h3> <section data-mpa-preserve-tpl-color="t" data-mpa-template="t" class="mpa-template" mpa-preserve="t" mpa-from-tpl="t"> <pre style="margin:0;padding:0;border-radius:none;background:none;"><code style="border-radius: 4px;font-size: 0.85em;margin: 0px 0.15em;background: rgb(40, 44, 52);color: rgb(171, 178, 191);display: block;padding: 5.95px;overflow-x: auto;white-space: nowrap;" class="hljs-default">top -<span class="hljs-default-keyword" style="color: rgb(198, 120, 221);background: rgba(0, 0, 0, 0);display: inline;width: 7px;text-decoration: none solid rgb(198, 120, 221);font-weight: 400;font-style: normal;">p</span> <span class="hljs-default-number" style="color: rgb(209, 154, 102);background: rgba(0, 0, 0, 0);display: inline;width: 33px;text-decoration: none solid rgb(209, 154, 102);font-weight: 400;font-style: normal;">25603</span> -H<br mpa-from-tpl="t"><span class="hljs-default-built_in" style="color: rgb(230, 192, 123);background: rgba(0, 0, 0, 0);display: inline;width: 39px;text-decoration: none solid rgb(230, 192, 123);font-weight: 400;font-style: normal;">printf</span> <span class="hljs-default-number" style="color: rgb(209, 154, 102);background: rgba(0, 0, 0, 0);display: inline;width: 7px;text-decoration: none solid rgb(209, 154, 102);font-weight: 400;font-style: normal;">0</span><span class="hljs-default-keyword" style="color: rgb(198, 120, 221);background: rgba(0, 0, 0, 0);display: inline;width: 7px;text-decoration: none solid rgb(198, 120, 221);font-weight: 400;font-style: normal;">x</span>%<span class="hljs-default-keyword" style="color: rgb(198, 120, 221);background: rgba(0, 0, 0, 0);display: inline;width: 7px;text-decoration: none solid rgb(198, 120, 221);font-weight: 400;font-style: normal;">x</span> <span class="hljs-default-number" style="color: rgb(209, 154, 102);background: rgba(0, 0, 0, 0);display: inline;width: 33px;text-decoration: none solid rgb(209, 154, 102);font-weight: 400;font-style: normal;">25842</span><br mpa-from-tpl="t">jstack <span class="hljs-default-number" style="color: rgb(209, 154, 102);background: rgba(0, 0, 0, 0);display: inline;width: 33px;text-decoration: none solid rgb(209, 154, 102);font-weight: 400;font-style: normal;">25603</span> | <span class="hljs-default-keyword" style="color: rgb(198, 120, 221);background: rgba(0, 0, 0, 0);display: inline;width: 27px;text-decoration: none solid rgb(198, 120, 221);font-weight: 400;font-style: normal;">grep</span> <span class="hljs-default-number" style="color: rgb(209, 154, 102);background: rgba(0, 0, 0, 0);display: inline;width: 6px;text-decoration: none solid rgb(209, 154, 102);font-weight: 400;font-style: normal;">0</span>x64f2<br mpa-from-tpl="t"><br mpa-from-tpl="t"><span class="hljs-default-keyword" style="color: rgb(198, 120, 221);background: rgba(0, 0, 0, 0);display: inline;width: 20px;text-decoration: none solid rgb(198, 120, 221);font-weight: 400;font-style: normal;">cat</span> /proc/interrupts</code></pre> </section> <p style="white-space: normal;line-height: 1.75em;margin-top: 1.2em !important;margin-bottom: 1.2em !important;"><span style="font-size: 15px;"></span></p> <p style="white-space: normal;line-height: 1.75em;margin-top: 1.2em !important;margin-bottom: 1.2em !important;"><span style="font-size: 15px;">(1)CPU<br>(2)Memory<br>(3)IO<br>(4)Network</span></p> <p style="white-space: normal;line-height: 1.75em;margin-top: 1.2em !important;margin-bottom: 1.2em !important;"><span style="font-size: 15px;">可以从以下几个方面监控CPU的信息:<br>(1)中断;<br>(2)上下文切换;<br>(3)可运行队列;<br>(4)CPU 利用率。</span></p> <h2 style="margin-top: 10px;margin-bottom: 10px;font-weight: bold;font-size: 1.4em;white-space: normal;border-bottom: 1px solid rgb(238, 238, 238);line-height: 1.75em;"><span style="color: rgb(171, 25, 66);font-size: 20px;">3. 内存</span></h2> <h3 style="margin-top: 10px;margin-bottom: 10px;font-weight: bold;font-size: 1.3em;white-space: normal;line-height: 1.75em;"><span style="font-size: 18px;">3.1 系统内存</span></h3> <p style="white-space: normal;line-height: 1.75em;margin-top: 1.2em !important;margin-bottom: 1.2em !important;"><span style="font-size: 15px;">free 命令<br></span></p> <section data-mpa-preserve-tpl-color="t" data-mpa-template="t" class="mpa-template" mpa-preserve="t" mpa-from-tpl="t"> <pre style="margin:0;padding:0;border-radius:none;background:none;"><code style="border-radius: 4px;font-size: 0.85em;margin: 0px 0.15em;background: rgb(40, 44, 52);color: rgb(171, 178, 191);display: block;padding: 5.95px;overflow-x: auto;white-space: nowrap;" class="hljs-default">[root@server ~]<span class="hljs-default-comment" style="color: rgb(92, 99, 112);background: rgba(0, 0, 0, 0);display: inline;width: 39px;text-decoration: none solid rgb(92, 99, 112);font-weight: 400;font-style: italic;"># free</span><br mpa-from-tpl="t"> total used free shared buffers cached<br mpa-from-tpl="t"><span class="hljs-default-symbol" style="color: rgb(97, 174, 238);background: rgba(0, 0, 0, 0);display: inline;width: 26px;text-decoration: none solid rgb(97, 174, 238);font-weight: 400;font-style: normal;">Mem:</span> <span class="hljs-default-number" style="color: rgb(209, 154, 102);background: rgba(0, 0, 0, 0);display: inline;width: 46px;text-decoration: none solid rgb(209, 154, 102);font-weight: 400;font-style: normal;">3266180</span> <span class="hljs-default-number" style="color: rgb(209, 154, 102);background: rgba(0, 0, 0, 0);display: inline;width: 47px;text-decoration: none solid rgb(209, 154, 102);font-weight: 400;font-style: normal;">3250000</span> <span class="hljs-default-number" style="color: rgb(209, 154, 102);background: rgba(0, 0, 0, 0);display: inline;width: 32px;text-decoration: none solid rgb(209, 154, 102);font-weight: 400;font-style: normal;">10000</span> <span class="hljs-default-number" style="color: rgb(209, 154, 102);background: rgba(0, 0, 0, 0);display: inline;width: 7px;text-decoration: none solid rgb(209, 154, 102);font-weight: 400;font-style: normal;">0</span> <span class="hljs-default-number" style="color: rgb(209, 154, 102);background: rgba(0, 0, 0, 0);display: inline;width: 40px;text-decoration: none solid rgb(209, 154, 102);font-weight: 400;font-style: normal;">201000</span> <span class="hljs-default-number" style="color: rgb(209, 154, 102);background: rgba(0, 0, 0, 0);display: inline;width: 46px;text-decoration: none solid rgb(209, 154, 102);font-weight: 400;font-style: normal;">3002000</span><br mpa-from-tpl="t">-<span class="hljs-default-regexp" style="color: rgb(152, 195, 121);background: rgba(0, 0, 0, 0);display: inline;width: 104px;text-decoration: none solid rgb(152, 195, 121);font-weight: 400;font-style: normal;">/+ buffers/cache</span>: <span class="hljs-default-number" style="color: rgb(209, 154, 102);background: rgba(0, 0, 0, 0);display: inline;width: 33px;text-decoration: none solid rgb(209, 154, 102);font-weight: 400;font-style: normal;">47000</span> <span class="hljs-default-number" style="color: rgb(209, 154, 102);background: rgba(0, 0, 0, 0);display: inline;width: 46px;text-decoration: none solid rgb(209, 154, 102);font-weight: 400;font-style: normal;">3213000</span><br mpa-from-tpl="t"><span class="hljs-default-symbol" style="color: rgb(97, 174, 238);background: rgba(0, 0, 0, 0);display: inline;width: 32px;text-decoration: none solid rgb(97, 174, 238);font-weight: 400;font-style: normal;">Swap:</span> <span class="hljs-default-number" style="color: rgb(209, 154, 102);background: rgba(0, 0, 0, 0);display: inline;width: 46px;text-decoration: none solid rgb(209, 154, 102);font-weight: 400;font-style: normal;">2048276</span> <span class="hljs-default-number" style="color: rgb(209, 154, 102);background: rgba(0, 0, 0, 0);display: inline;width: 33px;text-decoration: none solid rgb(209, 154, 102);font-weight: 400;font-style: normal;">80160</span> <span class="hljs-default-number" style="color: rgb(209, 154, 102);background: rgba(0, 0, 0, 0);display: inline;width: 46px;text-decoration: none solid rgb(209, 154, 102);font-weight: 400;font-style: normal;">1968116</span></code></pre> </section> <p style="white-space: normal;line-height: 1.75em;margin-top: 1.2em !important;margin-bottom: 1.2em !important;"><span style="font-size: 15px;">这里的默认显示单位是 kb。</span></p> <p style="white-space: normal;line-height: 1.75em;margin-top: 1.2em !important;margin-bottom: 1.2em !important;"><strong><span style="font-size: 15px;">各项指标解释</span></strong></p> <ul class=" list-paddingleft-2" style=""> <li><p style="margin-top: 10px;margin-bottom: 10px;line-height: 1.75em;text-align: left;"><span style="font-size: 15px;">total:总计物理内存的大小。</span></p></li> <li><p style="margin-top: 10px;margin-bottom: 10px;line-height: 1.75em;text-align: left;"><span style="font-size: 15px;">used:已使用多大。</span></p></li> <li><p style="margin-top: 10px;margin-bottom: 10px;line-height: 1.75em;text-align: left;"><span style="font-size: 15px;">free:可用有多少。</span></p></li> <li><p style="margin-top: 10px;margin-bottom: 10px;line-height: 1.75em;text-align: left;"><span style="font-size: 15px;">Shared:多个进程共享的内存总额。</span></p></li> <li><p style="margin-top: 10px;margin-bottom: 10px;line-height: 1.75em;text-align: left;"><span style="font-size: 15px;">buffers: 磁盘缓存的大小。</span></p></li> <li><p style="margin-top: 10px;margin-bottom: 10px;line-height: 1.75em;text-align: left;"><span style="font-size: 15px;">cache:磁盘缓存的大小。</span></p></li> <li><p style="margin-top: 10px;margin-bottom: 10px;line-height: 1.75em;text-align: left;"><span style="font-size: 15px;">-/+ buffers/cached): used:已使用多大,free:可用有多少。</span></p></li> <li><p style="margin-top: 10px;margin-bottom: 10px;line-height: 1.75em;text-align: left;"><span style="font-size: 15px;">已用内存 = 系统used memory - buffers - cached<br>(47000 = 3250000-201000-3002000)</span></p></li> <li><p style="margin-top: 10px;margin-bottom: 10px;line-height: 1.75em;text-align: left;"><span style="font-size: 15px;">可用内存 = 系统free memory + buffers + cached<br>(3213000 = 10000+201000+3002000)</span></p></li> </ul> <h3 style="margin-top: 10px;margin-bottom: 10px;font-weight: bold;font-size: 1.3em;white-space: normal;line-height: 1.75em;"><span style="font-size: 18px;">什么是buffer/cache?</span></h3> <ul class=" list-paddingleft-2" style="list-style-type: square;"> <li><p style="white-space: normal;line-height: 1.75em;margin-top: 1.2em !important;margin-bottom: 1.2em !important;"><span style="font-size: 15px;">buffer 指 Linux 内存的:Buffer cache,缓冲区缓</span></p></li> <li><p style="white-space: normal;line-height: 1.75em;margin-top: 1.2em !important;margin-bottom: 1.2em !important;"><span style="font-size: 15px;"><span style="font-size: 15px;">cache 指 Linux内存中的:</span><span style="font-size: 15px;">Page cache,页面缓存</span><br><br></span></p></li> </ul> <h4 style="margin-top: 10px;margin-bottom: 10px;font-weight: bold;font-size: 1.2em;white-space: normal;line-height: 1.75em;"><span style="font-size: 18px;">page cache</span></h4> <p style="white-space: normal;line-height: 1.75em;margin-top: 1.2em !important;margin-bottom: 1.2em !important;"><span style="font-size: 15px;">page cache 主要用来作为文件系统上的文件数据的缓存来用,尤其是针对当进程对文件有 read/write 操作的时候。</span></p> <p style="white-space: normal;line-height: 1.75em;margin-top: 1.2em !important;margin-bottom: 1.2em !important;"><span style="font-size: 15px;">如果你仔细想想的话,作为可以映射文件到内存的系统调用:mmap是不是很自然的也应该用到 page cache?在当前的系统实现里,page cache 也被作为其它文件类型的缓存设备来用,所以事实上 page cache 也负责了大部分的块设备文件的缓存工作。</span></p> <h4 style="margin-top: 10px;margin-bottom: 10px;font-weight: bold;font-size: 1.2em;white-space: normal;line-height: 1.75em;"><span style="font-size: 18px;">buffer cache</span></h4> <p style="white-space: normal;line-height: 1.75em;margin-top: 1.2em !important;margin-bottom: 1.2em !important;"><span style="font-size: 15px;">buffer cache 主要用来在系统对块设备进行读写的时候,对块进行数据缓存的系统来使用。这意味着某些对块的操作会使用 buffer cache 进行缓存,比如我们在格式化文件系统的时候。</span></p> <p style="white-space: normal;line-height: 1.75em;margin-top: 1.2em !important;margin-bottom: 1.2em !important;"><span style="font-size: 15px;">一般情况下两个缓存系统是一起配合使用的,比如当我们对一个文件进行写操作的时候,page cache 的内容会被改变,而 buffer cache 则可以用来将 page 标记为不同的缓冲区,并记录是哪一个缓冲区被修改了。这样,内核在后续执行脏数据的回写(writeback)时,就不用将整个 page 写回,而只需要写回修改的部分即可。</span></p> <p style="white-space: normal;line-height: 1.75em;margin-top: 1.2em !important;margin-bottom: 1.2em !important;"><span style="font-size: 15px;">在当前的内核中,page cache 是针对内存页的缓存,说白了就是,如果有内存是以page进行分配管理的,都可以使用page cache作为其缓存来管理使用。</span></p> <p style="white-space: normal;line-height: 1.75em;margin-top: 1.2em !important;margin-bottom: 1.2em !important;"><span style="font-size: 15px;">当然,不是所有的内存都是以页(page)进行管理的,也有很多是针对块(block)进行管理的,这部分内存使用如果要用到 cache 功能,则都集中到 buffer cache中来使用。(从这个角度出发,是不是buffer cache改名叫做block cache更好?)然而,也不是所有块(block)都有固定长度,系统上块的长度主要是根据所使用的块设备决定的,而页长度在X86 上无论是 32位还是 64位都是 4k。</span></p> <h3 style="margin-top: 10px;margin-bottom: 10px;font-weight: bold;font-size: 1.3em;white-space: normal;line-height: 1.75em;"><span style="color: rgb(171, 25, 66);font-size: 20px;"><strong>3.2 进程内存</strong></span></h3> <h4 style="margin-top: 10px;margin-bottom: 10px;font-weight: bold;font-size: 1.2em;white-space: normal;line-height: 1.75em;"><span style="font-size: 18px;">3.2.1 进程内存统计</span></h4> <p style="white-space: normal;line-height: 1.75em;margin-top: 1.2em !important;margin-bottom: 1.2em !important;"><span style="font-size: 15px;">/proc/[pid]/status<br>通过/proc//status可以查看进程的内存使用情况,包括虚拟内存大小(VmSize),物理内存大小(VmRSS),数据段大小(VmData),栈的大小(VmStk),代码段的大小(VmExe),共享库的代码段大小(VmLib)等等。</span></p> <section data-mpa-preserve-tpl-color="t" data-mpa-template="t" class="mpa-template" mpa-preserve="t" mpa-from-tpl="t"> <pre style="margin:0;padding:0;border-radius:none;background:none;"><code style="border-radius: 4px;font-size: 0.85em;margin: 0px 0.15em;background: rgb(40, 44, 52);color: rgb(171, 178, 191);display: block;padding: 5.95px;overflow-x: auto;white-space: nowrap;" class="hljs-default"><span class="hljs-default-attribute" style="color: rgb(152, 195, 121);background: rgba(0, 0, 0, 0);display: inline;width: 26px;text-decoration: none solid rgb(152, 195, 121);font-weight: 400;font-style: normal;">Name</span>: gedit <span class="hljs-default-comment" style="color: rgb(92, 99, 112);background: rgba(0, 0, 0, 0);display: inline;width: 97px;text-decoration: none solid rgb(92, 99, 112);font-weight: 400;font-style: italic;">/*进程的程序名*/</span><br mpa-from-tpl="t"><span class="hljs-default-attribute" style="color: rgb(152, 195, 121);background: rgba(0, 0, 0, 0);display: inline;width: 32px;text-decoration: none solid rgb(152, 195, 121);font-weight: 400;font-style: normal;">State</span>: S (sleeping) <span class="hljs-default-comment" style="color: rgb(92, 99, 112);background: rgba(0, 0, 0, 0);display: inline;width: 522px;text-decoration: none solid rgb(92, 99, 112);font-weight: 400;font-style: italic;">/*进程的状态信息,具体参见http://blog.chinaunix.net/u2/73528/showart_1106510.html*/</span><br mpa-from-tpl="t"><span class="hljs-default-attribute" style="color: rgb(152, 195, 121);background: rgba(0, 0, 0, 0);display: inline;width: 26px;text-decoration: none solid rgb(152, 195, 121);font-weight: 400;font-style: normal;">Tgid</span>: <span class="hljs-default-number" style="color: rgb(209, 154, 102);background: rgba(0, 0, 0, 0);display: inline;width: 27px;text-decoration: none solid rgb(209, 154, 102);font-weight: 400;font-style: normal;">9744</span> <span class="hljs-default-comment" style="color: rgb(92, 99, 112);background: rgba(0, 0, 0, 0);display: inline;width: 73px;text-decoration: none solid rgb(92, 99, 112);font-weight: 400;font-style: italic;">/*线程组号*/</span><br mpa-from-tpl="t"><span class="hljs-default-attribute" style="color: rgb(152, 195, 121);background: rgba(0, 0, 0, 0);display: inline;width: 20px;text-decoration: none solid rgb(152, 195, 121);font-weight: 400;font-style: normal;">Pid</span>: <span class="hljs-default-number" style="color: rgb(209, 154, 102);background: rgba(0, 0, 0, 0);display: inline;width: 27px;text-decoration: none solid rgb(209, 154, 102);font-weight: 400;font-style: normal;">9744</span> <span class="hljs-default-comment" style="color: rgb(92, 99, 112);background: rgba(0, 0, 0, 0);display: inline;width: 69px;text-decoration: none solid rgb(92, 99, 112);font-weight: 400;font-style: italic;">/*进程pid*/</span><br mpa-from-tpl="t"><span class="hljs-default-attribute" style="color: rgb(152, 195, 121);background: rgba(0, 0, 0, 0);display: inline;width: 26px;text-decoration: none solid rgb(152, 195, 121);font-weight: 400;font-style: normal;">PPid</span>: <span class="hljs-default-number" style="color: rgb(209, 154, 102);background: rgba(0, 0, 0, 0);display: inline;width: 27px;text-decoration: none solid rgb(209, 154, 102);font-weight: 400;font-style: normal;">7672</span> <span class="hljs-default-comment" style="color: rgb(92, 99, 112);background: rgba(0, 0, 0, 0);display: inline;width: 93px;text-decoration: none solid rgb(92, 99, 112);font-weight: 400;font-style: italic;">/*父进程的pid*/</span><br mpa-from-tpl="t"><span class="hljs-default-attribute" style="color: rgb(152, 195, 121);background: rgba(0, 0, 0, 0);display: inline;width: 59px;text-decoration: none solid rgb(152, 195, 121);font-weight: 400;font-style: normal;">TracerPid</span>: <span class="hljs-default-number" style="color: rgb(209, 154, 102);background: rgba(0, 0, 0, 0);display: inline;width: 7px;text-decoration: none solid rgb(209, 154, 102);font-weight: 400;font-style: normal;">0</span> <span class="hljs-default-comment" style="color: rgb(92, 99, 112);background: rgba(0, 0, 0, 0);display: inline;width: 106px;text-decoration: none solid rgb(92, 99, 112);font-weight: 400;font-style: italic;">/*跟踪进程的pid*/</span><br mpa-from-tpl="t"><span class="hljs-default-attribute" style="color: rgb(152, 195, 121);background: rgba(0, 0, 0, 0);display: inline;width: 39px;text-decoration: none solid rgb(152, 195, 121);font-weight: 400;font-style: normal;">VmPeak</span>: <span class="hljs-default-number" style="color: rgb(209, 154, 102);background: rgba(0, 0, 0, 0);display: inline;width: 32px;text-decoration: none solid rgb(209, 154, 102);font-weight: 400;font-style: normal;">60184</span> kB <span class="hljs-default-comment" style="color: rgb(92, 99, 112);background: rgba(0, 0, 0, 0);display: inline;width: 133px;text-decoration: none solid rgb(92, 99, 112);font-weight: 400;font-style: italic;">/*进程地址空间的大小*/</span><br mpa-from-tpl="t"><span class="hljs-default-attribute" style="color: rgb(152, 195, 121);background: rgba(0, 0, 0, 0);display: inline;width: 39px;text-decoration: none solid rgb(152, 195, 121);font-weight: 400;font-style: normal;">VmSize</span>: <span class="hljs-default-number" style="color: rgb(209, 154, 102);background: rgba(0, 0, 0, 0);display: inline;width: 32px;text-decoration: none solid rgb(209, 154, 102);font-weight: 400;font-style: normal;">60180</span> kB <span class="hljs-default-comment" style="color: rgb(92, 99, 112);background: rgba(0, 0, 0, 0);display: inline;width: 431px;text-decoration: none solid rgb(92, 99, 112);font-weight: 400;font-style: italic;">/*进程虚拟地址空间的大小reserved_vm:进程在预留或特殊的内存间的物理页*/</span><br mpa-from-tpl="t"><span class="hljs-default-attribute" style="color: rgb(152, 195, 121);background: rgba(0, 0, 0, 0);display: inline;width: 32px;text-decoration: none solid rgb(152, 195, 121);font-weight: 400;font-style: normal;">VmLck</span>: <span class="hljs-default-number" style="color: rgb(209, 154, 102);background: rgba(0, 0, 0, 0);display: inline;width: 7px;text-decoration: none solid rgb(209, 154, 102);font-weight: 400;font-style: normal;">0</span> kB <span class="hljs-default-comment" style="color: rgb(92, 99, 112);background: rgba(0, 0, 0, 0);display: inline;width: 366px;text-decoration: none solid rgb(92, 99, 112);font-weight: 400;font-style: italic;">/*进程已经锁住的物理内存的大小.锁住的物理内存不能交换到硬盘*/</span><br mpa-from-tpl="t"><span class="hljs-default-attribute" style="color: rgb(152, 195, 121);background: rgba(0, 0, 0, 0);display: inline;width: 32px;text-decoration: none solid rgb(152, 195, 121);font-weight: 400;font-style: normal;">VmHWM</span>: <span class="hljs-default-number" style="color: rgb(209, 154, 102);background: rgba(0, 0, 0, 0);display: inline;width: 33px;text-decoration: none solid rgb(209, 154, 102);font-weight: 400;font-style: normal;">18020</span> kB <span class="hljs-default-comment" style="color: rgb(92, 99, 112);background: rgba(0, 0, 0, 0);display: inline;width: 217px;text-decoration: none solid rgb(92, 99, 112);font-weight: 400;font-style: italic;">/*文件内存映射和匿名内存映射的大小*/</span><br mpa-from-tpl="t"><span class="hljs-default-attribute" style="color: rgb(152, 195, 121);background: rgba(0, 0, 0, 0);display: inline;width: 32px;text-decoration: none solid rgb(152, 195, 121);font-weight: 400;font-style: normal;">VmRSS</span>: <span class="hljs-default-number" style="color: rgb(209, 154, 102);background: rgba(0, 0, 0, 0);display: inline;width: 33px;text-decoration: none solid rgb(209, 154, 102);font-weight: 400;font-style: normal;">18020</span> kB <span class="hljs-default-comment" style="color: rgb(92, 99, 112);background: rgba(0, 0, 0, 0);display: inline;width: 419px;text-decoration: none solid rgb(92, 99, 112);font-weight: 400;font-style: italic;">/*应用程序正在使用的物理内存的大小,就是用ps命令的参数rss的值 (rss)*/</span><br mpa-from-tpl="t"><span class="hljs-default-attribute" style="color: rgb(152, 195, 121);background: rgba(0, 0, 0, 0);display: inline;width: 39px;text-decoration: none solid rgb(152, 195, 121);font-weight: 400;font-style: normal;">VmData</span>: <span class="hljs-default-number" style="color: rgb(209, 154, 102);background: rgba(0, 0, 0, 0);display: inline;width: 32px;text-decoration: none solid rgb(209, 154, 102);font-weight: 400;font-style: normal;">12240</span> kB <span class="hljs-default-comment" style="color: rgb(92, 99, 112);background: rgba(0, 0, 0, 0);display: inline;width: 371px;text-decoration: none solid rgb(92, 99, 112);font-weight: 400;font-style: italic;">/*程序数据段的大小(所占虚拟内存的大小),存放初始化了的数据*/</span><br mpa-from-tpl="t"><span class="hljs-default-attribute" style="color: rgb(152, 195, 121);background: rgba(0, 0, 0, 0);display: inline;width: 32px;text-decoration: none solid rgb(152, 195, 121);font-weight: 400;font-style: normal;">VmStk</span>: <span class="hljs-default-number" style="color: rgb(209, 154, 102);background: rgba(0, 0, 0, 0);display: inline;width: 13px;text-decoration: none solid rgb(209, 154, 102);font-weight: 400;font-style: normal;">84</span> kB <span class="hljs-default-comment" style="color: rgb(92, 99, 112);background: rgba(0, 0, 0, 0);display: inline;width: 158px;text-decoration: none solid rgb(92, 99, 112);font-weight: 400;font-style: italic;">/*进程在用户态的栈的大小*/</span><br mpa-from-tpl="t"><span class="hljs-default-attribute" style="color: rgb(152, 195, 121);background: rgba(0, 0, 0, 0);display: inline;width: 32px;text-decoration: none solid rgb(152, 195, 121);font-weight: 400;font-style: normal;">VmExe</span>: <span class="hljs-default-number" style="color: rgb(209, 154, 102);background: rgba(0, 0, 0, 0);display: inline;width: 20px;text-decoration: none solid rgb(209, 154, 102);font-weight: 400;font-style: normal;">576</span> kB <span class="hljs-default-comment" style="color: rgb(92, 99, 112);background: rgba(0, 0, 0, 0);display: inline;width: 379px;text-decoration: none solid rgb(92, 99, 112);font-weight: 400;font-style: italic;">/*程序所拥有的可执行虚拟内存的大小,代码段,不包括任务使用的库 */</span><br mpa-from-tpl="t"><span class="hljs-default-attribute" style="color: rgb(152, 195, 121);background: rgba(0, 0, 0, 0);display: inline;width: 32px;text-decoration: none solid rgb(152, 195, 121);font-weight: 400;font-style: normal;">VmLib</span>: <span class="hljs-default-number" style="color: rgb(209, 154, 102);background: rgba(0, 0, 0, 0);display: inline;width: 33px;text-decoration: none solid rgb(209, 154, 102);font-weight: 400;font-style: normal;">21072</span> kB <span class="hljs-default-comment" style="color: rgb(92, 99, 112);background: rgba(0, 0, 0, 0);display: inline;width: 240px;text-decoration: none solid rgb(92, 99, 112);font-weight: 400;font-style: italic;">/*被映像到任务的虚拟内存空间的库的大小*/</span><br mpa-from-tpl="t"><span class="hljs-default-attribute" style="color: rgb(152, 195, 121);background: rgba(0, 0, 0, 0);display: inline;width: 32px;text-decoration: none solid rgb(152, 195, 121);font-weight: 400;font-style: normal;">VmPTE</span>: <span class="hljs-default-number" style="color: rgb(209, 154, 102);background: rgba(0, 0, 0, 0);display: inline;width: 13px;text-decoration: none solid rgb(209, 154, 102);font-weight: 400;font-style: normal;">56</span> kB <span class="hljs-default-comment" style="color: rgb(92, 99, 112);background: rgba(0, 0, 0, 0);display: inline;width: 158px;text-decoration: none solid rgb(92, 99, 112);font-weight: 400;font-style: italic;">/*该进程的所有页表的大小*/</span><br mpa-from-tpl="t"><span class="hljs-default-attribute" style="color: rgb(152, 195, 121);background: rgba(0, 0, 0, 0);display: inline;width: 46px;text-decoration: none solid rgb(152, 195, 121);font-weight: 400;font-style: normal;">Threads</span>: <span class="hljs-default-number" style="color: rgb(209, 154, 102);background: rgba(0, 0, 0, 0);display: inline;width: 7px;text-decoration: none solid rgb(209, 154, 102);font-weight: 400;font-style: normal;">1</span> <span class="hljs-default-comment" style="color: rgb(92, 99, 112);background: rgba(0, 0, 0, 0);display: inline;width: 216px;text-decoration: none solid rgb(92, 99, 112);font-weight: 400;font-style: italic;">/*共享使用该信号描述符的任务的个数*/</span></code></pre> </section> <p style="white-space: normal;line-height: 1.75em;margin-top: 1.2em !important;margin-bottom: 1.2em !important;"><span style="font-size: 15px;"></span></p> <h4 style="margin-top: 10px;margin-bottom: 10px;font-weight: bold;font-size: 1.2em;white-space: normal;line-height: 1.75em;"><span style="font-size: 18px;">3.2.2 JVM 内存分配</span></h4> <p style="white-space: normal;line-height: 1.75em;margin-top: 1.2em !important;margin-bottom: 1.2em !important;"><span style="font-size: 15px;">java内存组成介绍:堆(Heap)和非堆(Non-heap)内存</span></p> <p style="white-space: normal;line-height: 1.75em;margin-top: 1.2em !important;margin-bottom: 1.2em !important;"><span style="font-size: 15px;">按照官方的说法:“Java 虚拟机具有一个堆,堆是运行时数据区域,所有类实例和数组的内存均从此处分配。堆是在 Java 虚拟机启动时创建的。” “在JVM中堆之外的内存称为非堆内存(Non-heap memory)”。</span></p> <p style="white-space: normal;line-height: 1.75em;margin-top: 1.2em !important;margin-bottom: 1.2em !important;"><span style="font-size: 15px;">可以看出JVM主要管理两种类型的内存:堆和非堆。</span></p> <p style="white-space: normal;line-height: 1.75em;margin-top: 1.2em !important;margin-bottom: 1.2em !important;"><span style="font-size: 15px;">简单来说堆就是Java代码可及的内存,是留给开发人员使用的;非堆就是JVM留给自己用的。</span></p> <p style="white-space: normal;line-height: 1.75em;margin-top: 1.2em !important;margin-bottom: 1.2em !important;"><span style="font-size: 15px;">所以方法区、JVM内部处理或优化所需的内存(如JIT编译后的代码缓存)、每个类结构(如运行时常数池、字段和方法数据)以及方法和构造方法 的代码都在非堆内存中。</span></p> <ol class=" list-paddingleft-2" style=""> <li><p style="margin-top: 10px;margin-bottom: 10px;line-height: 1.75em;text-align: left;"><span style="font-size: 15px;">JVM 本身需要的内存,包括其加载的第三方库以及这些库分配的内存</span></p></li> <li><p style="margin-top: 10px;margin-bottom: 10px;line-height: 1.75em;text-
作者:じ☆ve宝贝
我们接着讨论设计模式,这章开始,我将讲下7种结构型模式:适配器模式、装饰模式、代理模式、外观模式、桥接模式、组合模式、享元模式。其中对象的适配器模式是各种模式的起源,我们看下面的图:  ##6.适配器模式(Adapter) 适配器模式将某个类的接口转换成客户端期望的另一个接口,目的是消除由于接口不匹配所造成的类的兼容性问题。主要分为三类:类的适配器模式、对象的适配器模式、接口的适配器模式。首先,我们来看看类的适配器模式,先看类图:  核心思想就是:有一个Source类,拥有一个方法,待适配,目标接口是Targetable,通过Adapter类,将Source的功能扩展到Targetable里,看代码: ``` public class Source { public void method1() { System.out.println("this is original method!"); } } ``` ``` public interface Targetable { /* 与原类中的方法相同 */ public void method1(); /* 新类的方法 */ public void method2(); } ``` ``` public class Adapter extends Source implements Targetable { @Override public void method2() { System.out.println("this is the targetable method!"); } } ``` Adapter类继承Source类,实现Targetable接口,下面是测试类: ``` public class AdapterTest { public static void main(String[] args) { Targetable target = new Adapter(); target.method1(); target.method2(); } } ``` 输出: this is original method! this is the targetable method! 这样Targetable接口的实现类就具有了Source类的功能。 对象的适配器模式 基本思路和类的适配器模式相同,只是将Adapter类作修改,这次不继承Source类,而是持有Source类的实例,以达到解决兼容性的问题。看图:  只需要修改Adapter类的源码即可: ``` public class Wrapper implements Targetable { private Source source; public Wrapper(Source source){ super(); this.source = source; } @Override public void method2() { System.out.println("this is the targetable method!"); } @Override public void method1() { source.method1(); } } ``` 测试类: ``` public class AdapterTest { public static void main(String[] args) { Source source = new Source(); Targetable target = new Wrapper(source); target.method1(); target.method2(); } } ``` 输出与第一种一样,只是适配的方法不同而已。 第三种适配器模式是接口的适配器模式,接口的适配器是这样的:有时我们写的一个接口中有多个抽象方法,当我们写该接口的实现类时,必须实现该接口的所有方法,这明显有时比较浪费,因为并不是所有的方法都是我们需要的,有时只需要某一些,此处为了解决这个问题,我们引入了接口的适配器模式,借助于一个抽象类,该抽象类实现了该接口,实现了所有的方法,而我们不和原始的接口打交道,只和该抽象类取得联系,所以我们写一个类,继承该抽象类,重写我们需要的方法就行。看一下类图:  这个很好理解,在实际开发中,我们也常会遇到这种接口中定义了太多的方法,以致于有时我们在一些实现类中并不是都需要。看代码: ``` public interface Sourceable { public void method1(); public void method2(); } ``` 抽象类Wrapper2: ``` public abstract class Wrapper2 implements Sourceable{ public void method1(){} public void method2(){} } ``` ``` public class SourceSub1 extends Wrapper2 { public void method1(){ System.out.println("the sourceable interface's first Sub1!"); } } ``` ``` public class SourceSub2 extends Wrapper2 { public void method2(){ System.out.println("the sourceable interface's second Sub2!"); } } ``` 测试类: ``` public class WrapperTest { public static void main(String[] args) { Sourceable source1 = new SourceSub1(); Sourceable source2 = new SourceSub2(); source1.method1(); source1.method2(); source2.method1(); source2.method2(); } } ``` 测试输出: the sourceable interface's first Sub1! the sourceable interface's second Sub2! 达到了我们的效果! 讲了这么多,总结一下三种适配器模式的应用场景: 类的适配器模式:当希望将一个类转换成满足另一个新接口的类时,可以使用类的适配器模式,创建一个新类,继承原有的类,实现新的接口即可。 对象的适配器模式:当希望将一个对象转换成满足另一个新接口的对象时,可以创建一个Wrapper类,持有原类的一个实例,在Wrapper类的方法中,调用实例的方法就行。 接口的适配器模式:当不希望实现一个接口中所有的方法时,可以创建一个抽象类Wrapper,实现所有方法,我们写别的类的时候,继承抽象类即可。
作者:不要哭啦
目前前后端对接其实主要是面向 API 文档开发,而 API 的设计中,有一种 RESTful API 的设计,具有规范,从某一种角度,我觉得 RESTful API 可以很好的把后端 API 从繁杂的业务中抽象出来,更好地进行管理和编写,同时也具有良好的可读性。 对于一些现代化的 MVC 框架,在脚手架阶段可能就会自动生成 RESTful 风格的 Controller。 **资源的拆分** 路由中 URI 中的资源都是名词,即一个个实体,对于代码而言,可以看做一个个类到 URI 的映射,比如: ``` GET /repos/:owner/:repo/stargazers GET /organizations ``` **HTTP 动词** 对于 RESTful API 中,常用的动词有以下几种: > GET(SELECT):从服务器取出资源(一项或多项)。 POST(CREATE):在服务器新建一个资源。 PUT(UPDATE):在服务器更新资源(客户端提供改变后的完整资源)。 PATCH(UPDATE):在服务器更新资源(客户端提供改变的属性)。 DELETE(DELETE):从服务器删除资源。 PUT 和 PATCH 的区别主要在于更新整个资源还是更新局部资源。 **版本** 当 API 可能出现重大变更,无法向后兼容时,RESTful API 提供了版本花的概念,可以保证旧版和新版的 API 的使用,有三种方法存放版本号: 1. 在uri中放版本信息:GET /v1/users/1 2. Accept Header:Accept: application/json+v1 3. 自定义 Header:X-Api-Version: 1 没有版本号的 API 并不是一个好的 RESTful API(对不起我又设计了辣鸡的 API)。 **过滤** API 应该提供一定的筛选条件,比如: > ?limit=10:指定返回记录的数量 ?offset=10:指定返回记录的开始位置。 ?page=2&per_page=100:指定第几页,以及每页的记录数。 ?sortby=name&order=asc:指定返回结果按照哪个属性排序,以及排序顺序。 ?animal_type_id=1:指定筛选条件 **状态码** 服务器返回的状态码应该复合 HTTP 的规范,比如: > 200 OK - [GET]:服务器成功返回用户请求的数据,该操作是幂等的(Idempotent)。 201 CREATED - [POST/PUT/PATCH]:用户新建或修改数据成功。 202 Accepted - []:表示一个请求已经进入后台排队(异步任务) 204 NO CONTENT - [DELETE]:用户删除数据成功。 400 INVALID REQUEST - [POST/PUT/PATCH]:用户发出的请求有错误,服务器没有进行新建或修改数据的操作,该操作是幂等的。 401 Unauthorized - []:表示用户没有权限(令牌、用户名、密码错误)。 403 Forbidden - [] 表示用户得到授权(与401错误相对),但是访问是被禁止的。 404 NOT FOUND - []:用户发出的请求针对的是不存在的记录,服务器没有进行操作,该操作是幂等的。 406 Not Acceptable - [GET]:用户请求的格式不可得(比如用户请求JSON格式,但是只有XML格式)。 410 Gone -[GET]:用户请求的资源被永久删除,且不会再得到的。 422 Unprocesable entity - [POST/PUT/PATCH] 当创建一个对象时,发生一个验证错误。 500 INTERNAL SERVER ERROR - [*]:服务器发生错误,用户将无法判断发出的请求是否成功。 **返回 JSON** RESTful API 应该尽可能的返回 JSON,对于错误的请求,需要为用户提供错误的信息。 ``` { "code": 1234, "message": "Something bad happened :-(", "description": "More details about the error here" } ``` **不进行无意义的包装** body 只需要直接返回数据,不需要进行包装比如: ``` { "success": true, "data": {"id":1,"name":"xiaotuan"}, } ``` **不止于 RESTful** 尽管 RESTful API 的设计规范清晰可读,但是针对一些特殊的需求,我们可能也不一定要强制遵守 RESTful API 的设计规范。比如批量删除,DELETE 在 HTTP 规范中是没有参数的,这就给批量删除接口带来了一定的麻烦,可以考虑改用 POST。
作者:微信小助手
<p style="max-width: 100%;min-height: 1em;font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);text-align: left;line-height: 1.75em;box-sizing: border-box !important;word-wrap: break-word !important;"><img class="rich_pages" data-backh="156" data-backw="335" data-before-oversubscription-url="http://mmbiz.qpic.cn/mmbiz_jpg/Z6bicxIx5naLeVZgUCcIia1HmCGTRuicibGx9x3pX6TdciaqKzPSPRKhQAJb8TXjnS5NSM2QQxwDgiacUtPF7sL5q9tQ/0?wx_fmt=jpeg" data-croporisrc="/upload/1be7dfaa8a93008de5562109a5c8609a.jpg" data-cropx1="218.25783972125436" data-cropx2="848.5714285714286" data-cropy1="124.18118466898956" data-cropy2="417.70034843205576" data-oversubscription-url="http://mmbiz.qpic.cn/mmbiz_jpg/Z6bicxIx5naLeVZgUCcIia1HmCGTRuicibGxtKg4vQnwKhgFELNGUicNK6narV7FZ36jiaUylwLYBic69ytH53sMlGApw/0?wx_fmt=jpeg" data-ratio="0.4650793650793651" data-s="300,640" src="https://mmbiz.qpic.cn/mmbiz_jpg/Z6bicxIx5naLeVZgUCcIia1HmCGTRuicibGxtKg4vQnwKhgFELNGUicNK6narV7FZ36jiaUylwLYBic69ytH53sMlGApw/640?wx_fmt=jpeg" data-type="jpeg" data-w="630" style="letter-spacing: 0.544px;text-align: center;width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;visibility: visible !important;"></p> <section class="" powered-by="xiumi.us" style="max-width: 100%;font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;line-height: 27.2px;background-color: rgb(255, 255, 255);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;"> <section style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;"> <section style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;"> <section class="" powered-by="xiumi.us" style="max-width: 100%;letter-spacing: 0.544px;box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;"> <section class="" style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;"> <section label="Copyright Reserved by PLAYHUDONG." donone="shifuMouseDownCard('shifu_c_008')" style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;"> <section class="" powered-by="xiumi.us" style="max-width: 100%;letter-spacing: 0.612px;box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;"> <section style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;"> <section style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;"> <section class="" powered-by="xiumi.us" style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;"> <section class="" powered-by="xiumi.us" style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;"> <section label="Copyright Reserved by PLAYHUDONG." donone="shifuMouseDownCard('shifu_c_008')" style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;"> <section class="" powered-by="xiumi.us" style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;"> <section style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;"> <section style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;"> <section class="" powered-by="xiumi.us" style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;"> <section class="" powered-by="xiumi.us" style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;"> <section label="Copyright Reserved by PLAYHUDONG." donone="shifuMouseDownCard('shifu_c_008')" style="margin-right: 0em;margin-left: 0em;padding: 0.5em 1em;max-width: 100%;border-style: none;background-color: rgb(235, 235, 235);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;"> <p style="max-width: 100%;min-height: 1em;letter-spacing: 0.612px;line-height: 1.75em;box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(136, 136, 136);font-size: 15px;letter-spacing: 0.612px;box-sizing: border-box !important;word-wrap: break-word !important;">阿里妹导读:响应时间长,</span><span style="max-width: 100%;color: rgb(136, 136, 136);letter-spacing: 0.612px;font-size: 15px;box-sizing: border-box !important;word-wrap: break-word !important;">遇到性能瓶颈时,开发者第一个想到的总是性能优化。</span><span style="letter-spacing: 0.612px;max-width: 100%;color: rgb(136, 136, 136);font-size: 15px;box-sizing: border-box !important;word-wrap: break-word !important;"><a href="https://mp.weixin.qq.com/s?__biz=MzIzOTU0NTQ0MA==&mid=2247492440&idx=1&sn=054c2f8bc65cfbfc5e2ccff8d98d1fae&chksm=e92ade57de5d5741cf76cad2589eb351780fa642bd75fefeb5a943fecfb8238c43f7cd687500&token=1596877999&lang=zh_CN&scene=21#wechat_redirect" target="_blank" data-linktype="2" style="letter-spacing: 0.612px;">《什么技能产品经理不会提,但技术人必须懂?</a><a href="https://mp.weixin.qq.com/s?__biz=MzIzOTU0NTQ0MA==&mid=2247492440&idx=1&sn=054c2f8bc65cfbfc5e2ccff8d98d1fae&chksm=e92ade57de5d5741cf76cad2589eb351780fa642bd75fefeb5a943fecfb8238c43f7cd687500&token=1596877999&lang=zh_CN&scene=21#wechat_redirect" target="_blank" data-linktype="2" style="letter-spacing: 0.612px;">》</a>讲到了什么时候需要使用缓存。但缓存的用法是什么?一旦缓存使用不当,或稍有不注意,反而会翻车,导致系统投入更多的维护成本,陡增更高的复杂度。今天,科怀就来讲讲缓存的正确使用姿势。</span></p> </section> </section> </section> </section> </section> </section> </section> </section> </section> </section> </section> </section> </section> </section> </section> </section> </section> </section> <section style="text-align: justify;line-height: 1.75em;"> <strong><span style="font-size: 15px;color: rgb(255, 104, 39);"></span></strong> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <strong style="color: rgb(255, 104, 39);"><span style="font-size: 15px;">1. 常见概念</span></strong> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="color: rgb(255, 104, 39);"><strong><span style="font-size: 15px;"></span></strong></span> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><br></span> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">在合理应用缓存前,需要了解缓存领域里相关的几个常用术语:</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><br></span> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">1)缓存命中:表示数据能够从缓存中获取,不需要回源;</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><br></span> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">2)Cache miss:表示没有命中缓存,如果缓存内存中还有内存空间的话,会将数据加入到缓存中;</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><br></span> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><span style="color: rgb(62, 62, 62);">3)</span>存储成本:当没有命中缓存时,回源获取后会将数据放置到存储中,整个将数据放置到存储空间所需要的时间以及空间称之为存储成本;</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><br></span> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><span style="color: rgb(62, 62, 62);">4)</span>缓存失效:当源数据发生变更后,意味着缓存中的数据失效;</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><br></span> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><span style="color: rgb(62, 62, 62);">5)</span>缓存污染:将不经常访问的数据放置到缓存存储空间中,以至于高频访问的数据无法放置到缓存中;</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><br></span> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><span style="color: rgb(62, 62, 62);">6)</span>替代策略:当数据放置到缓存空间时,由于空间不足时,就需要从缓存空间中去除已有的数据,选择去除哪些数据就是由替代策略决定的。常见的替代策略有如下这些:</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><br></span> </section> <ul class=" list-paddingleft-2" style="list-style-type: disc;"> <li><p><span style="font-size: 15px;color: rgb(62, 62, 62);">Least-Recently-Used(LRU)</span></p></li> <li><p><span style="color: rgb(62, 62, 62);font-size: 15px;">Least-Frequently-Used(LF</span><span style="color: rgb(62, 62, 62);font-size: 15px;">U)</span><br></p></li> <li><p><span style="color: rgb(62, 62, 62);font-size: 15px;">SIZE</span><br></p></li> <li><p><span style="color: rgb(62, 62, 62);font-size: 15px;">First in First Out(FIFO)</span><br></p></li> </ul> <section style="text-align: justify;line-height: 1.75em;"></section> <section style="text-align: justify;line-height: 1.75em;"></section> <section style="text-align: justify;line-height: 1.75em;"></section> <section style="text-align: justify;line-height: 1.75em;"></section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">由于存储空间有限,替代策略要解决的核心问题是尽量保留高频访问的缓存数据,降低缓存污染以提升缓存命中率和整体的缓存效率,难点在于,需要基于数据历史访问情况,以一种合适的对未来访问情况的预估才能找到更佳的策略。</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <strong><span style="font-size: 15px;color: rgb(62, 62, 62);"><br></span></strong> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="color: rgb(255, 104, 39);"><strong><span style="font-size: 15px;">2. 访问缓存场景</span></strong></span> <span style="color: rgb(255, 104, 39);"><strong><span style="font-size: 15px;">分析</span></strong></span> <strong><span style="font-size: 15px;color: rgb(62, 62, 62);"></span></strong> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><br></span> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">使用缓存通常的操作是,请求先访问缓存数据,如果缓存中不存在的话,就会回源到数据库中然后将数据写入到缓存中;如果存在的话就直接返回数据。从整个过程来看,缓存层就处于数据访问的前置环节,分担数据库在高并发容易出现系统故障的风险,所以在使用过程中需要对缓存层很谨慎的进行分析。在访问缓存数据时,有常见的三大场景:缓存穿透、缓存击穿以及缓存雪崩。</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><br></span> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><strong>2.1 缓存穿透</strong></span> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><br></span> </section> <section style="text-align: justify;line-height: 1.75em;"> <strong><span style="font-size: 15px;color: rgb(62, 62, 62);">现象:</span></strong> <span style="font-size: 15px;color: rgb(62, 62, 62);">每次请求直接穿透缓存层,直接回源到数据库中,给数据库带来了巨大访问压力,甚至宕机。</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><br></span> </section> <section style="text-align: justify;line-height: 1.75em;"> <strong><span style="font-size: 15px;color: rgb(62, 62, 62);">原因:</span></strong> <span style="font-size: 15px;color: rgb(62, 62, 62);">访问数据会先访问缓存,如果数据不存在缓存中才会查询数据库,但是如果查询数据库也查询不出来数据,也是说当前访问数据永远不会写入缓存中。这样就导致了,访问一定不存在的数据,就相当于缓存层形同虚设,每次请求都会到db层,造成数据库负担过大。</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><br></span> </section> <section style="text-align: justify;line-height: 1.75em;"> <strong><span style="font-size: 15px;color: rgb(62, 62, 62);">解决方案:</span></strong> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <ul class=" list-paddingleft-2" style="list-style-type: disc;"> <li><p><span style="font-size: 15px;color: rgb(62, 62, 62);">方案一:采用bloom filter保存缓存过的key,在访问请求到来时可以过滤掉不存在的key,防止这些请求到db层;</span></p></li> <li><p><span style="font-size: 15px;color: rgb(62, 62, 62);">方案二:如果db查询不到数据,保存空对象到缓存层,设置较短的失效时间;</span></p></li> <li><p><span style="font-size: 15px;color: rgb(62, 62, 62);">方案三:针对业务场景对请求的参数进行有效性校验,防止非法请求击垮db。</span></p></li> </ul> <section style="text-align: justify;line-height: 1.75em;"></section> <section style="text-align: justify;line-height: 1.75em;"></section> <section style="text-align: justify;line-height: 1.75em;"></section> <section style="text-align: justify;line-height: 1.75em;"> <span style="color: rgb(62, 62, 62);font-size: 15px;"><br></span> </section> <section style="text-align: justify;line-height: 1.75em;"> <strong><span style="color: rgb(62, 62, 62);font-size: 15px;">2.2 缓存击穿</span></strong> <span style="color: rgb(62, 62, 62);font-size: 15px;"></span> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="color: rgb(62, 62, 62);font-size: 15px;"><br></span> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><strong>现象:</strong>当某一key失效时,造成大量请求到db层,击垮存储层。</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><br></span> </section> <section style="text-align: justify;line-height: 1.75em;"> <strong><span style="font-size: 15px;color: rgb(62, 62, 62);">原因:</span></strong> <span style="font-size: 15px;color: rgb(62, 62, 62);">为了保证缓存数据的时效性,通常会设置一个失效时间,如果是热点key,高并发时会有海量请求直接越过缓存层到数据库,这样就会给数据库造成的负担增大,设置宕机。</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><br></span> </section> <section style="text-align: justify;line-height: 1.75em;"> <strong><span style="font-size: 15px;color: rgb(62, 62, 62);">解决方案</span></strong> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><br></span> </section> <ul class=" list-paddingleft-2" style="list-style-type: disc;"> <li><p><span style="font-size: 15px;color: rgb(62, 62, 62);">方案一:使用互斥锁,当缓存数据失效时,保证一个请求能够访问到数据库,并更新缓存,其他线程等待并重试;</span></p></li> <li><p><span style="font-size: 15px;color: rgb(62, 62, 62);">方案二:缓存数据“永远不过期”,如果缓存数据不设置失效时间的话,就不会存在热点key过期造成了大量请求到数据库。但是,缓存数据就变成“静态数据”,因此当缓存数据快要过期时,采用异步线程的方式提前进行更新缓存数据。</span></p></li> </ul> <section style="text-align: justify;line-height: 1.75em;"></section> <section style="text-align: justify;line-height: 1.75em;"></section> <section style="text-align: justify;line-height: 1.75em;"> <span style="color: rgb(62, 62, 62);font-size: 15px;"><br></span> </section> <section style="text-align: justify;line-height: 1.75em;"> <strong><span style="color: rgb(62, 62, 62);font-size: 15px;">2.3 缓存雪崩</span><span style="color: rgb(62, 62, 62);font-size: 15px;"></span></strong> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="color: rgb(62, 62, 62);font-size: 15px;"><br></span> </section> <section style="text-align: justify;line-height: 1.75em;"> <strong><span style="font-size: 15px;color: rgb(62, 62, 62);">现象:</span></strong> <span style="font-size: 15px;color: rgb(62, 62, 62);">多个key失效,造成大量请求到db层,导致db层负担过重甚至宕机。</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <strong><span style="font-size: 15px;color: rgb(62, 62, 62);">原因:</span></strong> <span style="font-size: 15px;color: rgb(62, 62, 62);">缓存雪崩是指在我们设置缓存时采用了相同的过期时间,导致缓存在某一时刻同时失效,请求全部转发到数据库,最终导致数据库瞬时压力过大而崩溃。</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <strong><span style="font-size: 15px;color: rgb(62, 62, 62);"><br></span></strong> </section> <section style="text-align: justify;line-height: 1.75em;"> <strong><span style="font-size: 15px;color: rgb(62, 62, 62);">解决方案:</span></strong> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><br></span> </section> <ul class=" list-paddingleft-2" style="list-style-type: disc;"> <li><p><span style="font-size: 15px;color: rgb(62, 62, 62);">方案一:使用互斥锁的方式,保证只有单个线程进行请求能够达到db;</span></p></li> <li><p><span style="font-size: 15px;color: rgb(62, 62, 62);">方案二:多每个key的失效时间在基础时间上再加上一个1~5分钟的随机值,这样就能保证大规模key集体失效的概率,并且需要尽量让多个key的失效时间能够均匀分布;</span></p></li> </ul> <section style="text-align: justify;line-height: 1.75em;"></section> <section style="text-align: justify;line-height: 1.75em;"></section> <section style="text-align: justify;line-height: 1.75em;"> <span style="color: rgb(62, 62, 62);font-size: 15px;"><br></span> </section> <section style="text-align: justify;line-height: 1.75em;"> <strong><span style="color: rgb(62, 62, 62);font-size: 15px;">2.4 总结</span><span style="color: rgb(62, 62, 62);font-size: 15px;"></span></strong> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="color: rgb(62, 62, 62);font-size: 15px;"><br></span> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">缓存穿透、缓存击穿以及缓存雪崩这三个术语很容易弄混,也是读缓存中典型的三个场景问题,做一下简单的总结是很有必要的。缓存穿透强调是获取本不存在的缓存数据,请求必然会越过缓存层直接到达到存储层,很明显这是利用业务规则的漏洞对系统发起攻击,解决方案的核心原则是过滤这些非法业务请求,与是否是热点数据、缓存失效时间等因素没有关系。</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><br></span> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">缓存击穿强调的是热点key的失效,导致某一时刻大量请求会直接到db层,解决方案的核心原则是规避数据库的并发操作。缓存雪崩强调的多个key的集体失效,与key是否是热点数据并不是必然的因素,解决方案的核心原则则让key之间的失效时间分布更加均匀,避免集体失效的情况。</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><br></span> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="color: rgb(255, 104, 39);"><strong><span style="font-size: 15px;">3 数据更新场景分析</span></strong><strong><span style="font-size: 15px;"></span></strong></span> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><br></span> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">引入缓存后数据会分别存放到缓存以及数据库两个地方,因此数据更新时,需要涉及到这两处地方得更新,并且更新时序的不同会有不同的结果。关于数据更新目前业界已经沉淀了Cache Aside Pattern,Read/Write through等多种方式。</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="color: rgb(62, 62, 62);font-size: 15px;"><strong>3.1 Cache Aside Pattern</strong></span> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"> </span> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">这是很通用的更新策略,主要流程如下:</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><br></span> </section> <section style="text-align: center;line-height: 1.75em;"> <img class="image lake-drag-image" data-ratio="0.31333333333333335" src="/upload/df1e5d32086d791f4c6a99e6d97fefaa.png" data-type="png" data-w="600" height="170" style="box-sizing: content-box;border-width: 0px;border-style: none;border-color: initial;vertical-align: middle;" title="cache aside pattern-1.png" width="543"> </section> <section style="text-align: center;line-height: 1.75em;"> <img class="image lake-drag-image" data-ratio="0.31" src="/upload/82f4e66556d84436745dccdfed0e010e.png" data-type="png" data-w="600" height="165" style="box-sizing: content-box;border-width: 0px;border-style: none;border-color: initial;vertical-align: middle;" title="cache-aside-pattern-2.png" width="532"> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 14px;color: rgb(136, 136, 136);">图片来源:</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="color:#888888;"><span style="font-size: 14px;">https://coolshell.cn/articles/17416.html</span></span> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">主要涉及到如下几点:</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><br></span> </section> <ul style="" class=" list-paddingleft-2"> <li> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">失效:应用程序先从cache取数据,没有得到,则从数据库中取数据,成功后,放到缓存中。</span> </section></li> <li> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">命中:应用程序从cache中取数据,取到后返回。</span> </section></li> <li> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">更新:先把数据存到数据库中,成功后,再让缓存失效。</span> </section></li> </ul> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><br></span> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">Cache Aside Pattern在数据更新的时候是采用先更新数据库,再失效缓存。为什么需要采用这样的方式来解决数据更新的问题,先假设更新数据库以及缓存都会事务成功,由于某一种更新导致的不一致性在下一章节进行讨论。</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><br></span> </section> <section style="text-align: justify;line-height: 1.75em;"> <strong><span style="font-size: 15px;color: rgb(62, 62, 62);"><span style="color: rgb(62, 62, 62);">1)</span>为什么不是更新缓存,而是失效(删除)缓存?</span></strong> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="color: rgb(62, 62, 62);font-size: 15px;"><br></span> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="color: rgb(62, 62, 62);font-size: 15px;">❶ 并发写容易写覆盖造成脏数据问题:</span> <span style="font-size: 15px;color: rgb(62, 62, 62);">当数据发生更新的时候,针对缓存数据可以有两种方式来进行处理分别是更新缓存数据以及失效数据让下一次读请求重新从db中获取数据后重载入缓存中。假设更新缓存数据的话,在并发情况下会存在多线程写缓存造成脏数据的问题,如下图:</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><br></span> </section> <section style="text-align: justify;line-height: 1.75em;"> <img class="image lake-drag-image" data-ratio="0.6731898238747553" src="/upload/6ccf9d28615a92d4988aa0067d7808a3.png" data-type="png" data-w="1022" height="287" style="box-sizing: content-box;border-width: 0px;border-style: none;border-color: initial;vertical-align: middle;" title="更新缓存带来的脏数据问题.png" width="426"> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><br></span> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">如上图所示,假设A、B两个线程,A先更新数据库后 B再更新数据库,然后分别进行更新缓存,但是B先更新缓存成功,A后更新缓存成功,这样就导致数据库是最新的数据但是缓存中是旧的脏数据。而如果失效缓存数据的话,可以保证下一次读请求回源到数据库将最新的数据载入到缓存中,避免脏数据的问题。因此,针对数据更新缓存采用失效的方式进行处理,也可以参考这篇文章《Why does Facebook use delete to remove the key-value pair in Memcached instead of updating the Memcached during write request to the backend?》。</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><br></span> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">❷ 双写不同数据源容易造成数据不一致:同时写数据库以及缓存数据,任何一个更新失败都会造成数据不一致,由于“物理失败”造成的数据不一致在下一个章节进行阐述。另外事务都成功,无论是先更新缓存还是再更新数据库,还是先更新数据库再更新缓存,这两种情况在并发的情况下也很容易出现双写不成功,操作时序如下图,这种方式不推荐。 </span> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="color: rgb(62, 62, 62);font-size: 15px;"><br></span> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="color: rgb(62, 62, 62);font-size: 15px;">❸ 先更新缓存再更新数据库</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="color: rgb(62, 62, 62);font-size: 15px;"><br></span> </section> <section style="text-align: center;line-height: 1.75em;"> <img class="image lake-drag-image" data-ratio="0.7279843444227005" src="/upload/a3bc810a2907b725aea79b001db472fe.png" data-type="png" data-w="1022" height="345" style="box-sizing: content-box;border-width: 0px;border-style: none;border-color: initial;vertical-align: middle;" title="先更新缓存再更新数据库的问题.png" width="473"> </section> <section style="text-align: left;line-height: 1.75em;"> <br> </section> <section style="text-align: left;line-height: 1.75em;"> <span style="color: rgb(62, 62, 62);font-size: 15px;text-align: justify;">❹ 先更新数据库再更新缓存</span> </section> <section style="text-align: left;line-height: 1.75em;"> <span style="color: rgb(62, 62, 62);font-size: 15px;text-align: justify;"><br></span> </section> <section style="text-align: center;line-height: 1.75em;"> <img class="image lake-drag-image" data-ratio="0.7279843444227005" src="/upload/8337464fd6f9e7f733a336c455b1af04.png" data-type="png" data-w="1022" height="338" style="box-sizing: content-box;border-width: 0px;border-style: none;border-color: initial;vertical-align: middle;" title="先更新数据库再更新缓存的问题.png" width="464"> </section> <section style="text-align: center;line-height: 1.75em;"> <span style="text-align: justify;font-size: 15px;color: rgb(62, 62, 62);"><br></span> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="text-align: justify;font-size: 15px;color: rgb(62, 62, 62);"> <span style="font-size:20px;">❺</span> 违背数据懒加载,避免不必要的计算消耗:如果有些缓存值是需要经过复杂的计算才能得出,所以如果每次更新数据的时候都更新缓存,但是后续在一段时间内并没有读取该缓存数据,这样就白白浪费了大量的计算性能,完全可以后续由读请求的时候,再去计算即可,这样更符合数据懒加载,降低计算开销。</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="text-align: justify;font-size: 15px;color: rgb(62, 62, 62);"><br></span> </section> <section style="text-align: justify;line-height: 1.75em;"> <strong><span style="font-size: 15px;color: rgb(62, 62, 62);">2)可能存在的更新时序?</span></strong> <span style="font-size: 15px;color: rgb(62, 62, 62);"> </span> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="color: rgb(62, 62, 62);font-size: 15px;"><br style="box-sizing: border-box;"></span> <span style="font-size: 15px;color: rgb(62, 62, 62);">在确定数据更新后缓存会失效来进行处理的话,针对数据库以及缓存更新时序就存在如下这几种:</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="color: rgb(62, 62, 62);font-size: 15px;"><br></span> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="color: rgb(62, 62, 62);font-size: 15px;">❶ 先失效缓存再更新数据库</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: center;line-height: 1.75em;"> <img class="image lake-drag-image" data-ratio="0.7181996086105675" src="/upload/5e67ceba83241109082a9de846b3e4a2.png" data-type="png" data-w="1022" height="362" title="image.png" width="504" style="text-align: center;box-sizing: content-box;border-width: 0px;border-style: none;border-color: initial;vertical-align: middle;"> </section> <section style="text-align: center;line-height: 1.75em;"> <span style="text-align: justify;font-size: 15px;color: rgb(62, 62, 62);"><br></span> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="text-align: justify;font-size: 15px;color: rgb(62, 62, 62);">❷ 假设在并发的情况下,按照这种更新时序会存在什么问题? </span> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><br></span> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">如时序图所示,线程A先失效缓存数据的时候,B线程读请求发现缓存数据为空的话,就会从数据库中读取旧值放入到缓存中,这样就导致后续的读请求读到的都是缓存中的脏数据。针对这样的情况可以采用延时双删的策略来有效避免,伪代码 如下:</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><br></span> </section> <pre class="cm-s-default" style="text-align: justify;"> <section style="line-height: 1.75em;"></section> <section class="code-snippet__fix code-snippet__js"> <ul class="code-snippet__line-index code-snippet__js"> <li></li> <li></li> <li></li> <li></li> </ul> <pre class="code-snippet__js" data-lang="css"><code><span class="code-snippet_outer">cache.delKey(key);</span></code><code><span class="code-snippet_outer"> db.update(data);</span></code><code><span class="code-snippet_outer"> Thread.sleep(xxx);</span></code><code><span class="code-snippet_outer"> cache.delKey(key);</span></code></pre> </section> <section style="line-height: 1.75em;"> <br> </section></pre> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">主要是在写请求更新完数据库后进行休眠一段时间,然后删除可能由读请求带来的脏数据存入到缓存。另外,数据库如果采用的是主从分离的架构的话,读出来的数据也有可能是主从未同步完成造成的脏数据。这种通过延时双删的方式需要线程休眠,因此很显然会降低系统吞吐量,并不是一种优雅的解决方式,也可以采用异步删除的方式。当然可以设置过期时间,到期后缓存失效载入最新的数据,需要系统能够容忍一段时间的数据不一致。</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="color: rgb(62, 62, 62);font-size: 15px;"><br></span> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="color: rgb(62, 62, 62);font-size: 15px;">❸ 先更新数据库再失效缓存 :这是推荐的更新数据时采用的方式,实际上这也是可能存在数据不一致的情况,时序图如下:</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: center;line-height: 1.75em;"> <img class="image lake-drag-image" data-ratio="0.8571428571428571" src="/upload/19653ddd1d1899cfcb430c91685017a4.png" data-type="png" data-w="1022" height="350" title="image.png" width="408" style="box-sizing: content-box;border-width: 0px;border-style: none;border-color: initial;vertical-align: middle;"> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">❹ 假设缓存刚好到期失效时,读请求从db中读取数据,写请求更新完数据后再失效缓存后,读请求将旧数据存入到缓存中,这种情况也会导致脏数据的问题。实际上这种情况发生的概率很低,要发生这种情况的前提条件是写数据库要先于读数据库完成,一般而言读数据库相比于写数据库要耗时更短,这种前提条件成立的概率很低。针对这种”逻辑失败“造成的数据不一致,可以采用上面所说的异步双删的策略以及过期失效的方式来避免。</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><br></span> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">可以看出在并发的情况下,如果条件苛刻的话,这两种更新的时序都有可能导致脏数据的情况。只不过在大概率的情况下先更新数据库再失效缓存能够保证数据一致,也是业界推荐的处理方式,包括Facebook的论文《Scaling Memcache at Facebook》也使用了这个策略。当数据发生变更上,需要考虑的是最新的数据放置在哪里?很显然cache aside pattern 选择的是将最新的数据放到了db上(cache asside pattern:缓存靠边站),因为数据不一致的情况大概率会存在,需要根据业务场景选择合适的可信设备存储最新的数据。</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><br></span> </section> <section style="text-align: justify;line-height: 1.75em;"> <strong><span style="font-size: 15px;color: rgb(62, 62, 62);">3.2 Write/Read Through</span><span style="font-size: 15px;color: rgb(62, 62, 62);"></span></strong> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><br></span> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">Cache Aside Pattern对db以及缓存的更新逻辑是由调用方自己去控制,很显然这是一个很复杂的过程。Write/Read Through对调用方而言,缓存是作为整个的数据存储,而不用关系缓存后面的db,数据库的更新则是由缓存统一进行管理,对调用方而言只需要和缓存进行交互,整体过程是透明的。</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><br></span> </section> <ul style="" class=" list-paddingleft-2"> <li> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">Read Through:当数据发生更新时,查询缓存时更新缓存,然后由缓存层同步的更新数据库即可,对调用方而言只需要和缓存层交互即可;</span> </section></li> <li> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">Write Through:Write Through 套路和Read Through相仿,不过是在更新数据时发生。当有数据更新的时候,如果没有命中缓存,直接更新数据库,然后返回。如果命中了缓存,则更新缓存,然后再由Cache自己同步更新数据库。如下图所示(来源于网络):</span> </section></li> </ul> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: center;line-height: 1.75em;"> <img class="image lake-drag-image" data-ratio="1.3478260869565217" src="/upload/87990a5981ec0ede2b246bee8fdcf243.png" data-type="png" data-w="460" height="540" style="box-sizing: content-box;border-width: 0px;border-style: none;border-color: initial;vertical-align: middle;" title="Write Through.png" width="401"> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <strong><span style="font-size: 15px;color: rgb(62, 62, 62);">3.3 Write Behind Cache Pattern</span></strong> <span style="font-size: 15px;color: rgb(62, 62, 62);"></span> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><br></span> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">这种模式是当数据更新的时候直接更新缓存数据,然后建立异步任务去更新数据库。这种异步方式请求响应会很快,系统的吞吐量会明显提升。但是,因为是异步更新数据库,数据一致性的保障就会变弱,如果更新数据库失败则会永远的造成系统脏数据,需要很精细设计系统重试的策略,另外如果异步服务宕机的话,还要考虑更新的数据如何持久化,服务重启后能够迅速恢复。在更新数据库时,由于并发多任务的存在,还需要考虑并发写是否会造成脏数据的问题,就需要追溯每次更新数据的时序。使用这种模式需要考虑的细节会有很多,设计出一套好的方案是件很不容易的事情。</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><br></span> </section> <section style="text-align: justify;line-height: 1.75em;"> <strong><span style="font-size: 15px;color: rgb(62, 62, 62);">3.4 更新策略的思考</span><span style="font-size: 15px;color: rgb(62, 62, 62);"></span></strong> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><br></span> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">上面这四种更新策略是非常经典的,也是业界经过大规模业务总结下来的经验,如果认真分析这四种更新策略的话,也会是受益匪浅,在更新策略的设计我得理解是主要关注如下两个方面:</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><br></span> </section> <section style="text-align: justify;line-height: 1.75em;"> <strong><span style="font-size: 15px;color: rgb(62, 62, 62);">最新的数据应该放置在哪里?</span></strong> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="color: rgb(62, 62, 62);font-size: 15px;"><br style="box-sizing: border-box;"></span> <span style="font-size: 15px;color: rgb(62, 62, 62);">缓存的存在是为了系统高性能,利用内存的IO读取的高速的特性,来提升系统的性能,提高系统吞吐量,另外,缓存的存在会让一部分读请求不会到达db层,分解了db的压力,毕竟db是最容易出现瓶颈的地方。这是为什么利用缓存的两个重要原因。但是,带来的问题就是,数据会存在在两个地方分别是缓存以及数据库中,当数据更新的时候就需要思考让”正确的数据应该放在哪个最可信的存储介质上“,就需要结合业务性质在两个数据存储介质上进行选择。</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><br></span> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">Cache Aside Pattern选择先更新数据库,再失效缓存,这样可以保证最新最正确的数据一定会落在数据库中,这样可以保证核心的业务数据在数据库中一定是可信的,但是带来的问题是业务逻辑更复杂,系统处理更新逻辑耗时更长。如果是非核心数据的更新,可以选择write behind cache pattern的方式,只需要更新缓存即可,能够快速的响应。缺点是很容易造成数据不一致,数据库中的数据不一定的就是最可信的数据。所以,不同的更新策略实际上也是将最新的数据优先选择放在哪里更合适以及系统性能的一种权衡,需要结合业务场景做好trade-off。</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><br></span> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="color: rgb(255, 104, 39);"><strong><span style="font-size: 15px;">4. 数据不一致性</span></strong><strong><span style="font-size: 15px;"></span></strong></span> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><br></span> </section> <h2 style="text-align: justify;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(62, 62, 62);">4.1 数据不一致的原因</span><span style="font-size: 15px;color: rgb(62, 62, 62);"></span></strong></h2> <p><span style="font-size: 15px;color: rgb(62, 62, 62);"><br></span></p> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">由于引入缓存,数据就会分散在两处不同数据源,当数据更新时,实时上很难做到数据一致,除非采用强一致性方案,这里不在进行讨论。在找出合适的解决方案前,需要分析下存在数据不一致的主要原因,才能对症下药:</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><br></span> </section> <section style="text-align: justify;line-height: 1.75em;"> <strong><span style="font-size: 15px;color: rgb(62, 62, 62);">1)逻辑失败造成的数据不一致:</span></strong> <span style="font-size: 15px;color: rgb(62, 62, 62);">在上一章主要分析了更新数据时的四种更新策略,在并发的情况下,无论是先删除缓存还是更新数据库,还是更新数据库再失效缓存,都会数据不一致的情况,主要是因为异步读写请求在并发情况下的操作时序导致的数据不一致,称之为”逻辑失败“。解决这种因为并发时序导致的问题,核心的解决思想是将异步操作进行串行化。</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><br></span> </section> <section style="text-align: justify;line-height: 1.75em;"> <strong><span style="font-size: 15px;color: rgb(62, 62, 62);">2)物理失败造成的数据不一致:</span></strong> <span style="font-size: 15px;color: rgb(62, 62, 62);">在cache aside pattern中先更新数据库再删除缓存以及异步双删策略等等,如果删除缓存失败时都出现数据不一致的情况。但是数据库更新以及缓存操作是没办法放到一个事务中,一般来说,使用缓存是分布式缓存如果缓存服务很耗时,那么将更新数据库以及失效缓存放到一个事务中,就会造成大量的数据库连接挂起,严重的降低系统性能,甚至会因为数据库连接数过多,导致系统崩溃。像这种因为缓存操作失败,导致的数据不一致称之为”物理失败“。大多数情况物理失败的情况会重用重试的方式进行解决。</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><br></span> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><strong>4.2 数据一致性的解决方案</strong></span> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><br></span> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">在绝大部分业务场景中,追求的是最终一致性,针对物理失败造成的数据不一致常用的方案有:消费消息异步删除缓存以及订阅Binlog的方式,针对逻辑失败造成的数据不一致常用的方案有:队列异步操作同步化。</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><br></span> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">4.2.1 消费消息异步删除缓存</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><br></span> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">主要流程如下图所示:</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><br></span> </section> <section style="text-align: center;line-height: 1.75em;"> <img class="image lake-drag-image" data-ratio="0.7686915887850467" src="/upload/17e1aa7b9b18201ddef0c3ff74e6c7e8.png" data-type="png" data-w="856" height="326" style="box-sizing: content-box;border-width: 0px;border-style: none;border-color: initial;vertical-align: middle;" title="消费消息异步删除.png" width="424"> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">4.2.2 订阅Binlog</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><br></span> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">主要流程如下图所示:</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><br></span> </section> <section style="text-align: center;line-height: 1.75em;"> <img class="image lake-drag-image" data-ratio="0.9934924078091106" src="/upload/614a56099441c1b32182dbbcd42bca66.png" data-type="png" data-w="922" height="434" style="box-sizing: content-box;border-width: 0px;border-style: none;border-color: initial;vertical-align: middle;" title="订阅binlog保证最终一致性.png" width="437"> </section> <section style="text-align: justify;line-height: 1.75em;"> <br> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">4.2.3 利用队列串行化</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><br></span> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">在分析cache aside pattern发现在并发的情况下也会存在数据不一致的场景,只不过发生的概率很低,另外如果先删除缓存再更新数据库在并发读写的情况下也会存在数据不一致的情况。类似这种由于并发时序导致的数据不一致的情况,都是因为写请求还没有结束读请求读取的是旧数据,如果读请求在写请求之后处理,即请求的处理能够串行化的话,就能保证读请求读到的是写请求更新的最新的数据。</span> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><br></span> </section> <section style="text-align: justify;line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">将请求进行串行化,最常用的方式是采用队列的方式,一个队列只能对应一个工作线程,更新数据的写请求放置队列中,等待异步处理;读请求如果能从缓存中获取数据,则返回,如果缓存中没有数据,就将读请求放置到队列中,等待写请求数据更新完成。这种方案需要考虑的问题有:</span> </section> <section style="text-align: justif
作者:じ☆ve宝贝
> 经过247天的持续研发,阿里巴巴于10月14日在杭州云栖大会上,正式发布众所期待的《阿里巴巴Java开发规约》扫描插件! ## 如何安装IDEA插件? 目前,我们已将IDEA版的插件,发布至IDEA官方仓库中(最低支持版本14.1.7,JDK1.7+)。你只需打开 Settings >> Plugins >> Browse repositories 输入 Alibaba 搜索,看到对应插件后即可安装。 至于具体如何使用,请大家到官方Github仓库中进行查看。IDEA会自动检测插件新版,并提示出来,所以大家不用担心插件的更新问题。 Github仓库地址:https://github.com/alibaba/p3c ## 如何安装Eclipse插件? Eclipse版插件支持4.2(Juno,JDK1.8+)及以上版本,我们提供自主的Update Site,通过 Help >> Install New Software 然后输入https://p3c.alibaba.com/plugin/eclipse/update 即可看到安装列表。大家可以通过 Help >> Check for Udates 进行插件新版检测。
作者:じ☆ve宝贝
<section class="layout" style="font-size: 16px;color: black;padding: 10px;line-height: 1.6;letter-spacing: 0px;overflow-wrap: break-word;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;word-break: break-all;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;"> <h2 style="margin-top: 20px;margin-bottom: 10px;font-weight: bold;border-bottom: 2px solid rgb(239, 112, 96);font-size: 1.3em;"><span style="display: inline-block;font-weight: normal;background: rgb(239, 112, 96);color: #ffffff;padding: 3px 10px 1px;border-top-right-radius: 3px;border-top-left-radius: 3px;margin-right: 3px;">1.简介</span><span style="display: inline-block;vertical-align: bottom;border-bottom: 36px solid #efebe9;border-right: 20px solid transparent;"> </span></h2> <blockquote style="font-size: 0.9em;overflow: auto;color: rgb(106, 115, 125);padding: 10px 10px 10px 20px;margin-bottom: 20px;margin-top: 20px;border-left-color: rgb(239, 112, 96);background: rgb(239, 235, 233);"> <p style="font-size: 16px;padding-top: 5px;padding-bottom: 5px;color: black;line-height: 26px;">本文主要介绍SpringBoot2.1.5 + Dubbo 2.7.3 + Mybatis 3.4.2 + Nacos 1.1.3 +Seata 0.8.0整合来实现Dubbo分布式事务管理,使用Nacos 作为 Dubbo和Seata的注册中心和配置中心,使用 MySQL 数据库和 MyBatis来操作数据。</p> </blockquote> <p style="padding-top: 5px;padding-bottom: 5px;line-height: 26px;">如果你还对<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">SpringBoot</code>、<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">Dubbo</code>、<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">Nacos</code>、<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">Seata</code>、<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">Mybatis</code> 不是很了解的话,这里我为大家整理个它们的官网网站,如下</p> <ul style="" class=" list-paddingleft-2"> <li><p style="padding-top: 5px;padding-bottom: 5px;line-height: 26px;">SpringBoot:https://spring.io/projects/spring-boot</p></li> <li><p style="padding-top: 5px;padding-bottom: 5px;line-height: 26px;">Dubbo:http://dubbo.apache.org/en-us/</p></li> <li><p style="padding-top: 5px;padding-bottom: 5px;line-height: 26px;">Nacos:https://nacos.io/zh-cn/docs/quick-start.html</p></li> <li><p style="padding-top: 5px;padding-bottom: 5px;line-height: 26px;">Seata:https://github.com/seata/seata/wiki/Home_Chinese</p></li> <li><p style="padding-top: 5px;padding-bottom: 5px;line-height: 26px;">MyBatis:http://www.mybatis.org/mybatis-3/zh/index.html</p></li> </ul> <p style="padding-top: 5px;padding-bottom: 5px;line-height: 26px;">在这里我们就不一个一个介绍它们是怎么使用和原理,详细请学习官方文档,在这里我将开始对它们进行整合,完成一个简单的案例,来让大家了解<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">Seata</code>来实现<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">Dubbo</code>分布式事务管理的基本流程。</p> <h2 style="margin-top: 20px;margin-bottom: 10px;font-weight: bold;border-bottom: 2px solid rgb(239, 112, 96);font-size: 1.3em;"><span style="display: inline-block;font-weight: normal;background: rgb(239, 112, 96);color: #ffffff;padding: 3px 10px 1px;border-top-right-radius: 3px;border-top-left-radius: 3px;margin-right: 3px;">2.环境准备</span><span style="display: inline-block;vertical-align: bottom;border-bottom: 36px solid #efebe9;border-right: 20px solid transparent;"> </span></h2> <h2 style="margin-top: 20px;margin-bottom: 10px;font-weight: bold;border-bottom: 2px solid rgb(239, 112, 96);font-size: 1.3em;"><span style="display: inline-block;font-weight: normal;background: rgb(239, 112, 96);color: #ffffff;padding: 3px 10px 1px;border-top-right-radius: 3px;border-top-left-radius: 3px;margin-right: 3px;">2.1 下载nacos并安装启动</span><span style="display: inline-block;vertical-align: bottom;border-bottom: 36px solid #efebe9;border-right: 20px solid transparent;"> </span></h2> <p style="padding-top: 5px;padding-bottom: 5px;line-height: 26px;">nacos下载:https://github.com/alibaba/nacos/releases/tag/1.1.3</p> <p style="padding-top: 5px;padding-bottom: 5px;line-height: 26px;">Nacos 快速入门:https://nacos.io/en-us/docs/quick-start.html</p> <section class="code-snippet__fix code-snippet__js"> <ul class="code-snippet__line-index code-snippet__js"> <li></li> </ul> <pre class="code-snippet__js" data-lang="shell"><code style=" border-radius: 0px;padding: 2px;text-align: left;white-space: pre;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;background: rgba(0, 0, 0, 0); "><span class="code-snippet_outer" style="line-height: 20px;">sh startup.sh -m standalone</span></code></pre> </section> <p style="padding-top: 5px;padding-bottom: 5px;line-height: 26px;">在浏览器打开Nacos web 控制台:http://192.168.10.200:8848/nacos/index.html</p> <p style="padding-top: 5px;padding-bottom: 5px;line-height: 26px;">输入nacos的账号和密码 分别为nacos:nacos</p> <p style="padding-top: 5px;padding-bottom: 5px;line-height: 26px;"><img class="" data-ratio="0.3875" src="/upload/929b57934b7f678cad2faeccc10a33a0.png" data-type="png" data-w="1920" style="display: block;margin-right: auto;margin-left: auto;width: 100%;">这<span style="background-color: rgba(9, 187, 7, 0.31);">zhihou </span>后naocs 就正常启动了。</p> <h2 style="margin-top: 20px;margin-bottom: 10px;font-weight: bold;border-bottom: 2px solid rgb(239, 112, 96);font-size: 1.3em;"><span style="display: inline-block;font-weight: normal;background: rgb(239, 112, 96);color: #ffffff;padding: 3px 10px 1px;border-top-right-radius: 3px;border-top-left-radius: 3px;margin-right: 3px;">2.2 下载seata0.8.0 并安装启动</span><span style="display: inline-block;vertical-align: bottom;border-bottom: 36px solid #efebe9;border-right: 20px solid transparent;"> </span></h2> <h4 style="margin-top: 20px;margin-bottom: 10px;font-weight: bold;font-size: 18px;">2.2.1 在 Seata Release 下载最新版的 Seata Server 并解压得到如下目录:</h4> <section class="code-snippet__fix code-snippet__js"> <pre class="code-snippet__js" data-lang="shell"><code style=" border-radius: 0px;padding: 2px;text-align: left;white-space: pre;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;background: rgba(0, 0, 0, 0); "><span class="code-snippet_outer" style="line-height: 20px;">.</span></code><code style=" border-radius: 0px;padding: 2px;text-align: left;white-space: pre;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;background: rgba(0, 0, 0, 0); "><span class="code-snippet_outer" style="line-height: 20px;">├──bin</span></code><code style=" border-radius: 0px;padding: 2px;text-align: left;white-space: pre;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;background: rgba(0, 0, 0, 0); "><span class="code-snippet_outer" style="line-height: 20px;">├──conf</span></code><code style=" border-radius: 0px;padding: 2px;text-align: left;white-space: pre;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;background: rgba(0, 0, 0, 0); "><span class="code-snippet_outer" style="line-height: 20px;">├──file_store</span></code><code style=" border-radius: 0px;padding: 2px;text-align: left;white-space: pre;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;background: rgba(0, 0, 0, 0); "><span class="code-snippet_outer" style="line-height: 20px;">└──lib</span></code></pre> </section> <h4 style="margin-top: 20px;margin-bottom: 10px;font-weight: bold;font-size: 18px;">2.2.2 修改 conf/registry.conf 配置,</h4> <p style="padding-top: 5px;padding-bottom: 5px;line-height: 26px;">目前seata支持如下的file、nacos 、apollo、zk、consul的注册中心和配置中心。这里我们以<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">nacos</code> 为例。将 type 改为 nacos</p> <section class="code-snippet__fix code-snippet__js"> <pre class="code-snippet__js" data-lang="shell"><code style=" border-radius: 0px;padding: 2px;text-align: left;white-space: pre;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;background: rgba(0, 0, 0, 0); "><span class="code-snippet_outer" style="line-height: 20px;">registry {</span></code><code style=" border-radius: 0px;padding: 2px;text-align: left;white-space: pre;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;background: rgba(0, 0, 0, 0); "><span class="code-snippet_outer" style="line-height: 20px;"> # file nacos</span></code><code style=" border-radius: 0px;padding: 2px;text-align: left;white-space: pre;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;background: rgba(0, 0, 0, 0); "><span class="code-snippet_outer" style="line-height: 20px;"> type = "nacos"</span></code><code style=" border-radius: 0px;padding: 2px;text-align: left;white-space: pre;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;background: rgba(0, 0, 0, 0); "><span class="code-snippet_outer"><br></span></code><code style=" border-radius: 0px;padding: 2px;text-align: left;white-space: pre;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;background: rgba(0, 0, 0, 0); "><span class="code-snippet_outer" style="line-height: 20px;"> nacos {</span></code><code style=" border-radius: 0px;padding: 2px;text-align: left;white-space: pre;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;background: rgba(0, 0, 0, 0); "><span class="code-snippet_outer" style="line-height: 20px;"> serverAddr = "192.168.10.200"</span></code><code style=" border-radius: 0px;padding: 2px;text-align: left;white-space: pre;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;background: rgba(0, 0, 0, 0); "><span class="code-snippet_outer" style="line-height: 20px;"> namespace = "public"</span></code><code style=" border-radius: 0px;padding: 2px;text-align: left;white-space: pre;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;background: rgba(0, 0, 0, 0); "><span class="code-snippet_outer" style="line-height: 20px;"> cluster = "default"</span></code><code style=" border-radius: 0px;padding: 2px;text-align: left;white-space: pre;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;background: rgba(0, 0, 0, 0); "><span class="code-snippet_outer" style="line-height: 20px;"> }</span></code><code style=" border-radius: 0px;padding: 2px;text-align: left;white-space: pre;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;background: rgba(0, 0, 0, 0); "><span class="code-snippet_outer" style="line-height: 20px;"> file {</span></code><code style=" border-radius: 0px;padding: 2px;text-align: left;white-space: pre;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;background: rgba(0, 0, 0, 0); "><span class="code-snippet_outer" style="line-height: 20px;"> name = "file.conf"</span></code><code style=" border-radius: 0px;padding: 2px;text-align: left;white-space: pre;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;background: rgba(0, 0, 0, 0); "><span class="code-snippet_outer" style="line-height: 20px;"> }</span></code><code style=" border-radius: 0px;padding: 2px;text-align: left;white-space: pre;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;background: rgba(0, 0, 0, 0); "><span class="code-snippet_outer" style="line-height: 20px;">}</span></code><code style=" border-radius: 0px;padding: 2px;text-align: left;white-space: pre;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;background: rgba(0, 0, 0, 0); "><span class="code-snippet_outer"><br></span></code><code style=" border-radius: 0px;padding: 2px;text-align: left;white-space: pre;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;background: rgba(0, 0, 0, 0); "><span class="code-snippet_outer" style="line-height: 20px;">config {</span></code><code style=" border-radius: 0px;padding: 2px;text-align: left;white-space: pre;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;background: rgba(0, 0, 0, 0); "><span class="code-snippet_outer" style="line-height: 20px;"> # file、nacos 、apollo、zk、consul</span></code><code style=" border-radius: 0px;padding: 2px;text-align: left;white-space: pre;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;background: rgba(0, 0, 0, 0); "><span class="code-snippet_outer" style="line-height: 20px;"> type = "nacos"</span></code><code style=" border-radius: 0px;padding: 2px;text-align: left;white-space: pre;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;background: rgba(0, 0, 0, 0); "><span class="code-snippet_outer"><br></span></code><code style=" border-radius: 0px;padding: 2px;text-align: left;white-space: pre;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;background: rgba(0, 0, 0, 0); "><span class="code-snippet_outer" style="line-height: 20px;"> nacos {</span></code><code style=" border-radius: 0px;padding: 2px;text-align: left;white-space: pre;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;background: rgba(0, 0, 0, 0); "><span class="code-snippet_outer" style="line-height: 20px;"> serverAddr = "192.168.10.200"</span></code><code style=" border-radius: 0px;padding: 2px;text-align: left;white-space: pre;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;background: rgba(0, 0, 0, 0); "><span class="code-snippet_outer" style="line-height: 20px;"> namespace = "public"</span></code><code style=" border-radius: 0px;padding: 2px;text-align: left;white-space: pre;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;background: rgba(0, 0, 0, 0); "><span class="code-snippet_outer" style="line-height: 20px;"> cluster = "default"</span></code><code style=" border-radius: 0px;padding: 2px;text-align: left;white-space: pre;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;background: rgba(0, 0, 0, 0); "><span class="code-snippet_outer" style="line-height: 20px;"> }</span></code><code style=" border-radius: 0px;padding: 2px;text-align: left;white-space: pre;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;background: rgba(0, 0, 0, 0); "><span class="code-snippet_outer"><br></span></code><code style=" border-radius: 0px;padding: 2px;text-align: left;white-space: pre;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;background: rgba(0, 0, 0, 0); "><span class="code-snippet_outer" style="line-height: 20px;"> file {</span></code><code style=" border-radius: 0px;padding: 2px;text-align: left;white-space: pre;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;background: rgba(0, 0, 0, 0); "><span class="code-snippet_outer" style="line-height: 20px;"> name = "file.conf"</span></code><code style=" border-radius: 0px;padding: 2px;text-align: left;white-space: pre;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;background: rgba(0, 0, 0, 0); "><span class="code-snippet_outer" style="line-height: 20px;"> }</span></code><code style=" border-radius: 0px;padding: 2px;text-align: left;white-space: pre;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;background: rgba(0, 0, 0, 0); "><span class="code-snippet_outer" style="line-height: 20px;">}</span></code><code style=" border-radius: 0px;padding: 2px;text-align: left;white-space: pre;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;background: rgba(0, 0, 0, 0); "><span class="code-snippet_outer"><br></span></code></pre> </section> <ul style="" class=" list-paddingleft-2"> <li><p>serverAddr = "192.168.10.200" :nacos 的地址</p></li> <li><p>namespace = "public" :nacos的命名空间默认为<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">public</code></p></li> <li><p>cluster = "default" :集群设置未默认 <code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">default</code></p></li> </ul> <h4 style="margin-top: 20px;margin-bottom: 10px;font-weight: bold;font-size: 18px;">2.2.3 修改 conf/nacos-config.txt配置</h4> <section class="code-snippet__fix code-snippet__js"> <pre class="code-snippet__js" data-lang=""><code style=" border-radius: 0px;padding: 2px;text-align: left;white-space: pre;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;background: rgba(0, 0, 0, 0); "><span class="code-snippet_outer" style="line-height: 20px;">transport.type=TCP</span></code><code style=" border-radius: 0px;padding: 2px;text-align: left;white-space: pre;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;background: rgba(0, 0, 0, 0); "><span class="code-snippet_outer" style="line-height: 20px;">transport.server=NIO</span></code><code style=" border-radius: 0px;padding: 2px;text-align: left;white-space: pre;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;background: rgba(0, 0, 0, 0); "><span class="code-snippet_outer" style="line-height: 20px;">transport.heartbeat=true</span></code><code style=" border-radius: 0px;padding: 2px;text-align: left;white-space: pre;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;background: rgba(0, 0, 0, 0); "><span class="code-snippet_outer" style="line-height: 20px;">transport.thread-factory.boss-thread-prefix=NettyBoss</span></code><code style=" border-radius: 0px;padding: 2px;text-align: left;white-space: pre;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;background: rgba(0, 0, 0, 0); "><span class="code-snippet_outer" style="line-height: 20px;">transport.thread-factory.worker-thread-prefix=NettyServerNIOWorker</span></code><code style=" border-radius: 0px;padding: 2px;text-align: left;white-space: pre;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;background: rgba(0, 0, 0, 0); "><span class="code-snippet_outer" style="line-height: 20px;">transport.thread-factory.server-executor-thread-prefix=NettyServerBizHandler</span></code><code style=" border-radius: 0px;padding: 2px;text-align: left;white-space: pre;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;background: rgba(0, 0, 0, 0); "><span class="code-snippet_outer" style="line-height: 20px;">transport.thread-factory.share-boss-worker=false</span></code><code style=" border-radius: 0px;padding: 2px;text-align: left;white-space: pre;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;background: rgba(0, 0, 0, 0); "><span class="code-snippet_outer" style="line-height: 20px;">transport.thread-factory.client-selector-thread-prefix=NettyClientSelector</span></code><code style=" border-radius: 0px;padding: 2px;text-align: left;white-space: pre;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;background: rgba(0, 0, 0, 0); "><span class="code-snippet_outer" style="line-height: 20px;">transport.thread-factory.client-selector-thread-size=1</span></code><code style=" border-radius: 0px;padding: 2px;text-align: left;white-space: pre;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;background: rgba(0, 0, 0, 0); "><span class="code-snippet_outer" style="line-height: 20px;">transport.thread-factory.client-worker-thread-prefix=NettyClientWorkerThread</span></code><code style=" border-radius: 0px;padding: 2px;text-align: left;white-space: pre;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;background: rgba(0, 0, 0, 0); "><span class="code-snippet_outer" style="line-height: 20px;">transport.thread-factory.boss-thread-size=1</span></code><code style=" border-radius: 0px;padding: 2px;text-align: left;white-space: pre;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;background: rgba(0, 0, 0, 0); "><span class="code-snippet_outer" style="line-height: 20px;">transport.thread-factory.worker-thread-size=8</span></code><code style=" border-radius: 0px;padding: 2px;text-align: left;white-space: pre;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;background: rgba(0, 0, 0, 0); "><span class="code-snippet_outer" style="line-height: 20px;">transport.shutdown.wait=3</span></code><code style=" border-radius: 0px;padding: 2px;text-align: left;white-space: pre;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;background: rgba(0, 0, 0, 0); "><span class="code-snippet_outer" style="line-height: 20px;">service.vgroup_mapping.order-service-seata-service-group=default</span></code><code style=" border-radius: 0px;padding: 2px;text-align: left;white-space: pre;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;background: rgba(0, 0, 0, 0); "><span class="code-snippet_outer" style="line-height: 20px;">service.vgroup_mapping.account-service-seata-service-group=default</span></code><code style=" border-radius: 0px;padding: 2px;text-align: left;white-space: pre;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;background: rgba(0, 0, 0, 0); "><span class="code-snippet_outer" style="line-height: 20px;">service.vgroup_mapping.storage-service-seata-service-group=default</span></code><code style=" border-radius: 0px;padding: 2px;text-align: left;white-space: pre;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;background: rgba(0, 0, 0, 0); "><span class="code-snippet_outer" style="line-height: 20px;">service.vgroup_mapping.business-service-seata-service-group=default</span></code><code style=" border-radius: 0px;padding: 2px;text-align: left;white-space: pre;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;background: rgba(0, 0, 0, 0); "><span class="code-snippet_outer" style="line-height: 20px;">service.enableDegrade=false</span></code><code style=" border-radius: 0px;padding: 2px;text-align: left;white-space: pre;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;background: rgba(0, 0, 0, 0); "><span class="code-snippet_outer" style="line-height: 20px;">service.disable=false</span></code><code style=" border-radius: 0px;padding: 2px;text-align: left;white-space: pre;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;background: rgba(0, 0, 0, 0); "><span class="code-snippet_outer" style="line-height: 20px;">service.max.commit.retry.timeout=-1</span></code><code style=" border-radius: 0px;padding: 2px;text-align: left;white-space: pre;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;background: rgba(0, 0, 0, 0); "><span class="code-snippet_outer" style="line-height: 20px;">service.max.rollback.retry.timeout=-1</span></code><code style=" border-radius: 0px;padding: 2px;text-align: left;white-space: pre;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;background: rgba(0, 0, 0, 0); "><span class="code-snippet_outer" style="line-height: 20px;">client.async.commit.buffer.limit=10000</span></code><code style=" border-radius: 0px;padding: 2px;text-align: left;white-space: pre;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;background: rgba(0, 0, 0, 0); "><span class="code-snippet_outer" style="line-height: 20px;">client.lock.retry.internal=10</span></code><code style=" border-radius: 0px;padding: 2px;text-align: left;white-space: pre;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;background: rgba(0, 0, 0, 0); "><span class="code-snippet_outer" style="line-height: 20px;">client.lock.retry.times=30</span></code><code style=" border-radius: 0px;padding: 2px;text-align: left;white-space: pre;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;background: rgba(0, 0, 0, 0); "><span class="code-snippet_outer" style="line-height: 20px;">store.mode=db</span></code><code style=" border-radius: 0px;padding: 2px;text-align: left;white-space: pre;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;background: rgba(0, 0, 0, 0); "><span class="code-snippet_outer" style="line-height: 20px;">store.file.dir=file_store/data</span></code><code style=" border-radius: 0px;padding: 2px;text-align: left;white-space: pre;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;background: rgba(0, 0, 0, 0); "><span class="code-snippet_outer" style="line-height: 20px;">store.file.max-branch-session-size=16384</span></code><code style=" border-radius: 0px;padding: 2px;text-align: left;white-space: pre;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;background: rgba(0, 0, 0, 0); "><span class="code-snippet_outer" style="line-height: 20px;">store.file.max-global-session-size=512</span></code><code style=" border-radius: 0px;padding: 2px;text-align: left;white-space: pre;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;background: rgba(0, 0, 0, 0); "><span class="code-snippet_outer" style="line-height: 20px;">store.file.file-write-buffer-cache-size=16384</span></code><code style=" border-radius: 0px;padding: 2px;text-align: left;white-space: pre;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;background: rgba(0, 0, 0, 0); "><span class="code-snippet_outer" style="line-height: 20px;">store.file.flush-disk-mode=async</span></code><code style=" border-radius: 0px;padding: 2px;text-align: left;white-space: pre;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;background: rgba(0, 0, 0, 0); "><span class="code-snippet_outer" style="line-height: 20px;">store.file.session.reload.read_size=100</span></code><code style=" border-radius: 0px;padding: 2px;text-align: left;white-space: pre;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;background: rgba(0, 0, 0, 0); "><span class="code-snippet_outer" style="line-height: 20px;">store.db.driver-class-name=com.mysql.jdbc.Driver</span></code><code style=" border-radius: 0px;padding: 2px;text-align: left;white-space: pre;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;background: rgba(0, 0, 0, 0); "><span class="code-snippet_outer" style="line-height: 20px;">store.db.datasource=dbcp</span></code><code style=" border-radius: 0px;padding: 2px;text-align: left;white-space: pre;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;background: rgba(0, 0, 0, 0); "><span class="code-snippet_outer" style="line-height: 20px;">store.db.db-type=mysql</span></code><code style=" border-radius: 0px;padding: 2px;text-align: left;white-space: pre;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;background: rgba(0, 0, 0, 0); "><span class="code-snippet_outer" style="line-height: 20px;">store.db.url=jdbc:mysql://192.168.10.200:3306/seata?useUnicode=true</span></code><code style=" border-radius: 0px;padding: 2px;text-align: left;white-space: pre;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;background: rgba(0, 0, 0, 0); "><span class="code-snippet_outer" style="line-height: 20px;">store.db.user=lidong</span></code><code style=" border-radius: 0px;padding: 2px;text-align: left;white-space: pre;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;background: rgba(0, 0, 0, 0); "><span class="code-snippet_outer" style="line-height: 20px;">store.db.password=cwj887766@@</span></code><code style=" border-radius: 0px;padding: 2px;text-align: left;white-space: pre;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;background: rgba(0, 0, 0, 0); "><span class="code-snippet_outer" style="line-height: 20px;">store.db.min-conn=1</span></code><code style=" border-radius: 0px;padding: 2px;text-align: left;white-space: pre;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;background: rgba(0, 0, 0, 0); "><span class="code-snippet_outer" style="line-height: 20px;">store.db.max-conn=3</span></code><code style=" border-radius: 0px;padding: 2px;text-align: left;white-space: pre;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;background: rgba(0, 0, 0, 0); "><span class="code-snippet_outer" style="line-height: 20px;">store.db.global.table=global_table</span></code><code style=" border-radius: 0px;padding: 2px;text-align: left;white-space: pre;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;background: rgba(0, 0, 0, 0); "><span class="code-snippet_outer" style="line-height: 20px;">store.db.branch.table=branch_table</span></code><code style=" border-radius: 0px;padding: 2px;text-align: left;white-space: pre;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;background: rgba(0, 0, 0, 0); "><span class="code-snippet_outer" style="line-height: 20px;">store.db.query-limit=100</span></code><code style=" border-radius: 0px;padding: 2px;text-align: left;white-space: pre;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;background: rgba(0, 0, 0, 0); "><span class="code-snippet_outer" style="line-height: 20px;">store.db.lock-table=lock_table</span></code><code style=" border-radius: 0px;padding: 2px;text-align: left;white-space: pre;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;background: rgba(0, 0, 0, 0); "><span class="code-snippet_outer" style="line-height: 20px;">recovery.committing-retry-period=1000</span></code><code style=" border-radius: 0px;padding: 2px;text-align: left;white-space: pre;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;background: rgba(0, 0, 0, 0); "><span class="code-snippet_outer" style="line-height: 20px;">recovery.asyn-committing-retry-period=1000</span></code><code style=" border-radius: 0px;padding: 2px;text-align: left;white-space: pre;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;background: rgba(0, 0, 0, 0); "><span class="code-snippet_outer" style="line-height: 20px;">recovery.rollbacking-retry-period=1000</span></code><code style=" border-radius: 0px;padding: 2px;text-align: left;white-space: pre;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;background: rgba(0, 0, 0, 0); "><span class="code-snippet_outer" style="line-height: 20px;">recovery.timeout-retry-period=1000</span></code><code style=" border-radius: 0px;padding: 2px;text-align: left;white-space: pre;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;background: rgba(0, 0, 0, 0); "><span class="code-snippet_outer" style="line-height: 20px;">transaction.undo.data.validation=true</span></code><code style=" border-radius: 0px;padding: 2px;text-align: left;white-space: pre;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;background: rgba(0, 0, 0, 0); "><span class="code-snippet_outer" style="line-height: 20px;">transaction.undo.log.serialization=jackson</span></code><code style=" border-radius: 0px;padding: 2px;text-align: left;white-space: pre;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;background: rgba(0, 0, 0, 0); "><span class="code-snippet_outer" style="line-height: 20px;">transaction.undo.log.save.days=7</span></code><code style=" border-radius: 0px;padding: 2px;text-align: left;white-space: pre;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;background: rgba(0, 0, 0, 0); "><span class="code-snippet_outer" style="line-height: 20px;">transaction.undo.log.delete.period=86400000</span></code><code style=" border-radius: 0px;padding: 2px;text-align: left;white-space: pre;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;background: rgba(0, 0, 0, 0); "><span class="code-snippet_outer" style="line-height: 20px;">transaction.undo.log.table=undo_log</span></code><code style=" border-radius: 0px;padding: 2px;text-align: left;white-space: pre;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;background: rgba(0, 0, 0, 0); "><span class="code-snippet_outer" style="line-height: 20px;">transport.serialization=seata</span></code><code style=" border-radius: 0px;padding: 2px;text-align: left;white-space: pre;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;background: rgba(0, 0, 0, 0); "><span class="code-snippet_outer" style="line-height: 20px;">transport.compressor=none</span></code><code style=" border-radius: 0px;padding: 2px;text-align: left;white-space: pre;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;background: rgba(0, 0, 0, 0); "><span class="code-snippet_outer" style="line-height: 20px;">metrics.enabled=false</span></code><code style=" border-radius: 0px;padding: 2px;text-align: left;white-space: pre;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;background: rgba(0, 0, 0, 0); "><span class="code-snippet_outer" style="line-height: 20px;">metrics.registry-type=compact</span></code><code style=" border-radius: 0px;padding: 2px;text-align: left;white-space: pre;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;background: rgba(0, 0, 0, 0); "><span class="code-snippet_outer" style="line-height: 20px;">metrics.exporter-list=prometheus</span></code><code style=" border-radius: 0px;padding: 2px;text-align: left;white-space: pre;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;background: rgba(0, 0, 0, 0); "><span class="code-snippet_outer" style="line-height: 20px;">metrics.exporter-prometheus-port=9898</span></code></pre> </section> <p style="padding-top: 5px;padding-bottom: 5px;line-height: 26px;">这里主要修改了如下几项:</p> <ul style="" class=" list-paddingleft-2"> <li><p>store.mode :存储模式 默认file 这里我修改为db 模式 ,并且需要两个表<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">global_table</code>和<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">branch_table</code></p></li> <li><p>store.db.driver-class-name:默认没有,会报错。添加了 <code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">com.mysql.jdbc.Driver</code></p></li> <li><p>store.db.datasource=dbcp :数据源 dbcp</p></li> <li><p>store.db.db-type=mysql : 存储数据库的类型为<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">mysql</code></p></li> <li><p>store.db.url=jdbc:mysql://192.168.10.200:3306/seata?useUnicode=true : 修改为自己的数据库<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">url</code>、<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">port</code>、<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">数据库名称</code></p></li> <li><p>store.db.user=lidong :数据库的账号</p></li> <li><p>store.db.password=cwj887766@@ :数据库的密码</p></li> <li><p>service.vgroup_mapping.order-service-seata-service-group=default</p></li> <li><p>service.vgroup_mapping.account-service-seata-service-group=default</p></li> <li><p>service.vgroup_mapping.storage-service-seata-service-group=default</p></li> <li><p>service.vgroup_mapping.business-service-seata-service-group=default</p></li> </ul> <p style="padding-top: 5px;padding-bottom: 5px;line-height: 26px;">也可以在 Nacos 配置页面添加,data-id 为 service.vgroup_mapping.${YOUR_SERVICE_NAME}-seata-service-group, group 为 SEATA_GROUP, 如果不添加该配置,启动后会提示no available server to connect</p> <p style="padding-top: 5px;padding-bottom: 5px;line-height: 26px;"><strong>注意:</strong> 配置文件末尾有空行,需要删除,否则会提示失败,尽管实际上是成功的</p> <p style="padding-top: 5px;padding-bottom: 5px;line-height: 26px;"><code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">global_table</code>的表结构</p> <section class="code-snippet__fix code-snippet__js"> <pre class="code-snippet__js" data-lang="sql"><code style=" border-radius: 0px;padding: 2px;text-align: left;white-space: pre;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;background: rgba(0, 0, 0, 0); "><span class="code-snippet_outer" style="line-height: 20px;">CREATE TABLE `global_table` (</span></code><code style=" border-radius: 0px;padding: 2px;text-align: left;white-space: pre;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;background: rgba(0, 0, 0, 0); "><span class="code-snippet_outer" style="line-height: 20px;"> `xid` varchar(128) NOT NULL,</span></code><code style=" border-radius: 0px;padding: 2px;text-align: left;white-space: pre;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;background: rgba(0, 0, 0, 0); "><span class="code-snippet_outer" style="line-height: 20px;"> `transaction_id` bigint(20) DEFAULT NULL,</span></code><code style=" border-radius: 0px;padding: 2px;text-align: left;white-space: pre;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;background: rgba(0, 0, 0, 0); "><span class="code-snippet_outer" style="line-height: 20px;"> `status` tinyint(4) NOT NULL,</span></code><code style=" border-radius: 0px;padding: 2px;text-align: left;white-space: pre;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;background: rgba(0, 0, 0, 0); "><span class="code-snippet_outer" style="line-height: 20px;"> `application_id` varchar(64) DEFAULT NULL,</span></code><code style=" border-radius: 0px;padding: 2px;text-align: left;white-space: pre;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;background: rgba(0, 0, 0, 0); "><span class="code-snippet_outer" style="line-height: 20px;"> `transaction_service_group` varchar(64) DEFAULT NULL,</span></code><code style=" border-radius: 0px;padding: 2px;text-align: left;white-space: pre;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;background: rgba(0, 0, 0, 0); "><span class="code-snippet_outer" style="line-height: 20px;"> `transaction_name` varchar(64) DEFAULT NULL,</span></code><code style=" border-radius: 0px;padding: 2px;text-align: left;white-space: pre;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;background: rgba(0, 0, 0, 0); "><span class="code-snippet_outer" style="line-height: 20px;"> `timeout` int(11) DEFAULT NULL,</span></code><code style=" border-radius: 0px;padding: 2px;text-align: left;white-space: pre;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;background: rgba(0, 0, 0, 0); "><span class="code-snippet_outer" style="line-height: 20px;"> `begin_time` bigint(20) DEFAULT NULL,</span></code><code style=" border-radius: 0px;padding: 2px;text-align: left;white-space: pre;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;background: rgba(0, 0, 0, 0); "><span class="code-snippet_outer" style="line-height: 20px;"> `application_data` varchar(2000) DEFAULT NULL,</span></code><code style=" border-radius: 0px;padding: 2px;text-align: left;white-space: pre;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;background: rgba(0, 0, 0, 0); "><span class="code-snippet_outer" style="line-height: 20px;"> `gmt_create` datetime DEFAULT NULL,</span></code><code style=" border-radius: 0px;padding: 2px;text-align: left;white-space: pre;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;background: rgba(0, 0, 0, 0); "><span class="code-snippet_outer" style="line-height: 20px;"> `gmt_modified` datetime DEFAULT NULL,</span></code><code style=" border-radius: 0px;padding: 2px;text-align: left;white-space: pre;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;background: rgba(0, 0, 0, 0); "><span class="code-snippet_outer" style="line-height: 20px;"> PRIMARY KEY (`xid`),</span></code><code style=" border-radius: 0px;padding: 2px;text-align: left;white-space: pre;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;background: rgba(0, 0, 0, 0); "><span class="code-snippet_outer" style="line-height: 20px;"> KEY `idx_gmt_modified_status` (`gmt_modified`,`status`),</span></code><code style=" border-radius: 0px;padding: 2px;text-align: left;white-space: pre;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;background: rgba(0, 0, 0, 0); "><span class="code-snippet_outer" style="line-height: 20px;"> KEY `idx_transaction_id` (`transaction_id`)</span></code><code style=" border-radius: 0px;padding: 2px;text-align: left;white-space: pre;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;background: rgba(0, 0, 0, 0); "><span class="code-snippet_outer" style="line-height: 20px;">) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;</span></code><code style=" border-radius: 0px;padding: 2px;text-align: left;white-space: pre;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;background: rgba(0, 0, 0, 0); "><span class="code-snippet_outer"><br></span></code></pre> </section> <p style="padding-top: 5px;padding-bottom: 5px;line-height: 26px;"><code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">branch_table</code>的表结构</p> <section class="code-snippet__fix code-snippet__js"> <pre class="code-snippet__js" data-lang="sql"><code style=" border-radius: 0px;padding: 2px;text-align: left;white-space: pre;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;background: rgba(0, 0, 0, 0); "><span class="code-snippet_outer" style="line-height: 20px;">CREATE TABLE `branch_table` (</span></code><code style=" border-radius: 0px;padding: 2px;text-align: left;white-space: pre;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;background: rgba(0, 0, 0, 0); "><span class="code-snippet_outer" style="line-height: 20px;"> `branch_id` bigint(20) NOT NULL,</span></code><code style=" border-radius: 0px;padding: 2px;text-align: left;white-space: pre;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;background: rgba(0, 0, 0, 0); "><span class="code-snippet_outer" style="line-height: 20px;"> `xid` varchar(128) NOT NULL,</span></code><code style=" border-radius: 0px;padding: 2px;text-align: left;white-space: pre;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;background: rgba(0, 0, 0, 0); "><span class="code-snippet_outer" style="line-height: 20px;"> `transaction_id` bigint(20) DEFAULT NULL,</span></code><code style=" border-radius: 0px;padding: 2px;text-align: left;white-space: pre;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;background: rgba(0, 0, 0, 0); "><span class="code-snippet_outer" style="line-height: 20px;"> `resource_group_id` varchar(32) DEFAULT NULL,</span></code><code style=" border-radius: 0px;padding: 2px;text-align: left;white-space: pre;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;background: rgba(0, 0, 0, 0); "><span class="code-snippet_outer" style="line-height: 20px;"> `resource_id` varchar(256) DEFAULT NULL,</span></code><code style=" border-radius: 0px;padding: 2px;text-align: left;white-space: pre;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;background: rgba(0, 0, 0, 0); "><span class="code-snippet_outer" style="line-height: 20px;"> `lock_key` varchar(128) DEFAULT NULL,</span></code><code style=" border-radius: 0px;padding: 2px;text-align: left;white-space: pre;display: flex; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;background: rgba(0, 0, 0, 0); "><span class="code-snippet_outer" style="line-height: 20px;"> `branch_type` varchar(8) DEFAULT NULL,</span></code><code style=" border-radius: 0px;padding: 2px;text-align: left;white-space: pre;display: flex; font-family: Consolas, "
作者:じ☆ve宝贝
``` package cn.studyjava; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import org.springframework.context.ApplicationListener; import org.springframework.context.event.ContextRefreshedEvent; import org.springframework.stereotype.Component; /** * <p> * Description: 扫描自定义的注解 * </p> * * @author: zsljava * @version 1.0.0 * <p> * History: * ----------------------------------------------- * @Date: 2018年3月8日 下午1:44:53 * @author: zsljava * @version 1.0.0 * @OP: Create * ----------------------------------------------- * </p> * * @since * @see */ @Component public class ScanAnnotation implements ApplicationListener<ContextRefreshedEvent> { /** * @Title: onApplicationEvent * @Description: TODO * @param event * @see org.springframework.context.ApplicationListener#onApplicationEvent(org.springframework.context.ApplicationEvent) */ @Override public void onApplicationEvent(ContextRefreshedEvent event) { Map<String, Object> services = event.getApplicationContext().getBeansWithAnnotation(Table.class);// 自定义的注解 Iterator<String> it = services.keySet().iterator(); Map<String, Object> map = new HashMap<>(); while(it.hasNext()){ String key = it.next(); System.out.println(key + ":" + services.get(key)); } } } ```
作者:微信小助手
<h1 style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;font-size: 24px;margin-top: 36px;margin-bottom: 22px;font-weight: 700;line-height: 32px;color: rgb(34, 34, 34);font-family: "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", "Helvetica Neue", Arial, sans-serif;white-space: normal;background-color: rgb(255, 255, 255);">网络编程</h1> <ol style="" class=" list-paddingleft-2"> <li><p>ISO模型与协议</p></li> <li><p>http1.0:需要使用keep-alive参数来告知服务器端要建立一个长连接</p></li> <li><p>http1.1:默认长连接。支持只发送header信息,可以用作权限请求。支持Host域。</p></li> <li><p>http2.0:多路复用的技术,做到同一个连接并发处理多个请求。HTTP2.0使用HPACK算法对header的数据进行压缩。支持HTTP2.0的web server请求数据的时候,服务器会顺便把一些客户端需要的资源一起推送到客户端,免得客户端再次创建连接发送请求到服务器端获取。这种方式非常合适加载静态资源。</p></li> <li><p>会话层:负责管理主机之间的会话进程,负责建立、管理、终止进程之间的会话。</p></li> <li><p>传输层:将上层数据分段并提供端到端的、可靠的或不可靠的传输,还要处理端到端的差错控制和流量控制问题。协议TCP、UDP、SPX</p></li> <li><p>网络层:对子网间的数据包进行路由选择。此外,网络层还可以实现拥塞控制、网际互连等功能。协议IP、IPX、RIP、OSPF</p></li> <li><p>数据链路层:在不可靠的物理介质上提供可靠的传输。该层的作用包括:物理地址寻址、数据的成帧、流量控制、数据的检错、重发等。协议SDLC、HDLC、PPP、STP、帧中继</p></li> <li><p>TCPIP模型与协议</p></li> <li><p>应用层:单位是数据段,协议有FTP、TELNET、HTTP、SMTP、SNMP、TFTP、NTP、DNS</p></li> <li><p>运输层:单位是数据包,协议有TCP、UDP</p></li> <li><p>网络层:单位是数据帧,协议有IP</p></li> <li><p>网络接口层:单位是比特,ARP、RARP</p></li> <li><p>三次握手与四次挥手</p></li> <li><p>BIO NIO AIO</p></li> <li><p>BIO:同步阻塞IO,每个请求都要一个线程来处理。</p></li> <li><p>NIO:同步非阻塞IO,一个线程可以处理多个请求,适用于短连接、小数据。</p></li> <li><p>AIO:异步非阻塞IO,一个线程处理多个请求,使用回调函数实现,适用于长连接、大数据。</p></li> <li><p>DDOS攻击原理与防御方式</p></li> <li><p>HTTP Get Flood:发送大量会产生sql查询的连接,使得数据库负载很高。</p></li> <li><p>CSRF跨站请求伪造原理攻击者盗用了你的身份,以你的名义发送恶意请求。</p></li> <li><p>CSRF攻击是源于WEB的隐式身份验证机制!WEB的身份验证机制虽然可以保证一个请求是来自于某个用户的浏览器,但却无法保证该请求是用户批准发送的!</p></li> <li><p>防御方式:1.验证码;2. 后台生成token,让前端请求携带。3.使用对称加密,后端随机给前端一个密钥,前端进行加密,后端解密。</p></li> <li><p>会话劫持通过暴力破解、 预测、窃取(通过XSS攻击)等方式获取到用户session</p></li> <li><p>XSS攻击XSS攻击是Web攻击中最常见的攻击方法之一,它是通过对网页注入可执行代码且成功地被浏览器执行,达到攻击的目的,形成了一次有效XSS攻击,一旦攻击成功,它可以获取用户的联系人列表,然后向联系人发送虚假诈骗信息,可以删除用户的日志等等,有时候还和其他攻击方式同时实施比如SQL注入攻击服务器和数据库、Click劫持、相对链接劫持等实施钓鱼,它带来的危害是巨大的,是web安全的头号大敌。</p></li> <li><p>XSS反射型攻击,恶意代码并没有保存在目标网站,通过引诱用户点击一个链接到目标网站的恶意链接来实施攻击的。</p></li> <li><p>XSS存储型攻击,恶意代码被保存到目标网站的服务器中,这种攻击具有较强的稳定性和持久性,比较常见场景是在博客,论坛等社交网站上,但OA系统,和CRM系统上也能看到它身影,比如:某CRM系统的客户投诉功能上存在XSS存储型漏洞,黑客提交了恶意攻击代码,当系统管理员查看投诉信息时恶意代码执行,窃取了客户的资料,然而管理员毫不知情,这就是典型的XSS存储型攻击。</p></li> </ol> <ul style="list-style-type: square;" class=" list-paddingleft-2"> <li><p>解决方法</p></li> <li><p>在表单提交或者url参数传递前,对需要的参数进行过滤</p></li> <li><p>过滤用户输入。检查用户输入的内容中是否有非法内容。如<>(尖括号)、”(引号)、 ‘(单引号)、%(百分比符号)、;(分号)、()(括号)、&(& 符号)、+(加号)等</p></li> </ul> <p style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;margin-top: 16px;margin-bottom: 16px;color: rgb(34, 34, 34);font-family: "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", "Helvetica Neue", Arial, sans-serif;font-size: 16px;white-space: normal;background-color: rgb(255, 255, 255);">28.RPC与HTTP服务的区别</p> <h1 style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;font-size: 24px;margin-top: 36px;margin-bottom: 22px;font-weight: 700;line-height: 32px;color: rgb(34, 34, 34);font-family: "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", "Helvetica Neue", Arial, sans-serif;white-space: normal;background-color: rgb(255, 255, 255);">数据库原理</h1> <ol style="" class=" list-paddingleft-2"> <li><p>MYISAM与innodb搜索引擎原理MyISAM引擎使用B+Tree作为索引结构,叶节点的data域存放的是数据记录的地址。其采用索引文件与数据文件,索引文件只存放索引,叶子节点存放数据的物理地址。数据文件存放数据。其索引方式是非聚集的。</p></li> <li><p>InnoDB也使用B+Tree作为索引结构。但是它的主索引与数据都放在一个文件中。这种索引叫做聚集索引,因为InnoDB的数据文件本身要按主键聚集,所以InnoDB要求表必须有主键(MyISAM可以没有),如果没有显式指定,则MySQL系统会自动选择一个可以唯一标识数据记录的列作为主键,如果不存在这种列,则MySQL自动为InnoDB表生成一个隐含字段作为主键,这个字段长度为6个字节,类型为长整形。</p></li> </ol> <ul style="list-style-type: square;" class=" list-paddingleft-2"> <li><p>区别一:InnoDB的主索引与数据都放在一个文件中。而MYISAM是分开存放的。</p></li> <li><p>区别二:InnoDB的辅助索引data域存储相应记录主键的值而不是地址。</p></li> <li><p>区别三:InnoDB的主键索引是聚集索引,而MYISAM不是聚集索引。</p></li> </ul> <p style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;margin-top: 16px;margin-bottom: 16px;color: rgb(34, 34, 34);font-family: "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", "Helvetica Neue", Arial, sans-serif;font-size: 16px;white-space: normal;background-color: rgb(255, 255, 255);">3.索引,聚簇索引和二级索引的加锁区别</p> <ul style="list-style-type: square;" class=" list-paddingleft-2"> <li><p>聚集(clustered)索引,也叫聚簇索引。数据行的物理顺序与列值(一般是主键的那一列)的逻辑顺序相同,一个表中只能拥有一个聚集索引。</p></li> <li><p>非聚集(unclustered)索引。该索引中索引的逻辑顺序与磁盘上行的物理存储顺序不同,一个表中可以拥有多个非聚集索引。会发生二次查询。</p></li> <li><p>稠密索引:稠密索引文件中的索引块保持键的顺序与文件中的排序顺序一致。</p></li> <li><p>稀疏索引:稀疏索引没有为每个数据都创建一个索引,它比稠密索引节省了更多的存储空间,但查找给定值的记录需更多的时间。只有当数据文件是按照某个查找键排序时,在该查找键上建立的稀疏索引才能被使用,而稠密索引则可以应用在任何的查找键。</p></li> <li><p>联合索引:将一张表中多个列组成联合索引(col1,col2,col3),其生效方式满足最左前缀原则。</p></li> <li><p>覆盖索引:对于二级索引而言,在innodb中一般是需要先根据二级索引查询到主键,然后在根据一级索引查询到数据。但是如果select的列都在索引中,就避免进行一级查询。</p></li> </ul> <p style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;margin-top: 16px;margin-bottom: 16px;color: rgb(34, 34, 34);font-family: "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", "Helvetica Neue", Arial, sans-serif;font-size: 16px;white-space: normal;background-color: rgb(255, 255, 255);">4.主键选择</p> <ul style="list-style-type: square;" class=" list-paddingleft-2"> <li><p>在使用InnoDB存储引擎时,如果没有特别的需要,请永远使用一个与业务无关的自增字段作为主键。</p></li> <li><p>where 1 = 1:能够方便我们拼sql,但是使用了之后就无法使用索引优化策略,因此会进行全表扫描,影响效率。</p></li> </ul> <p style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;margin-top: 16px;margin-bottom: 16px;color: rgb(34, 34, 34);font-family: "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", "Helvetica Neue", Arial, sans-serif;font-size: 16px;white-space: normal;background-color: rgb(255, 255, 255);">5.分表分库</p> <ul style="list-style-type: square;" class=" list-paddingleft-2"> <li><p>水平拆分:依据表中的数据的逻辑关系,将同一个表中的数据依照某种条件拆分到多台数据库(主机)上面。按照1个或多个字段以及相应的规则,将一张表重的数据分到多张表中去。比如按照id%5的规则,将一张大表拆分成5张小表。适合具有超大表的系统。</p></li> <li><p>垂直拆分:依照不同的表(或者Schema)来切分到不同的数据库(主机)之上。一般按照模块来分库。适合各业务之间耦合度非常低的系统。</p></li> </ul> <p style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;margin-top: 16px;margin-bottom: 16px;color: rgb(34, 34, 34);font-family: "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", "Helvetica Neue", Arial, sans-serif;font-size: 16px;white-space: normal;background-color: rgb(255, 255, 255);">6.隔离级别</p> <ul style="list-style-type: square;" class=" list-paddingleft-2"> <li><p>read uncommit:读不加锁,写加共享锁。会产生脏读、幻读。</p></li> <li><p>read commit:读加共享锁,写加排它锁,但不加间隙锁。间隙锁的主要作用是防止不可重复读,但会加大锁的范围。</p></li> <li><p>repeatable read(innodb默认):读加共享锁,写加间隙排它锁。注意,Innodb对这个级别进行了特殊处理,使得这个级别能够避免幻读,但不是所有引擎都能够防止幻读!(网易面试官问)</p></li> <li><p>serialization:会给整张表加锁,强一致,但是效率低。</p></li> </ul> <p style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;margin-top: 16px;margin-bottom: 16px;color: rgb(34, 34, 34);font-family: "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", "Helvetica Neue", Arial, sans-serif;font-size: 16px;white-space: normal;background-color: rgb(255, 255, 255);">7.innodb中的锁</p> <ul style="list-style-type: square;" class=" list-paddingleft-2"> <li><p>MVCC(multi-Version Concurrency Control):读不加锁,读写不冲突。适合写少读多的场景。读操作分为:快照读(返回记录的可见版本,不加锁)、当前读(记录的最新版本,加锁,保证<span style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;">其它</span>记录不修改)。</p></li> <li><p>LBCC(Lock-Based Concurrency Control):</p></li> <li><p>join原理Simple Nested-Loop Join:效率最低,按照join的次序,在join的属性上一个个扫描,并合并结果。</p></li> <li><p>Index Nested-Loop Join:效率最高,join的属性上面有索引,根据索引来匹配。</p></li> <li><p>Block Nested-Loop Join:用于没有索引的列。它会采用join buffer,将外表的值缓存到join buffer中,然后与内表进行批量比较,这样可以降低对外表的访问频率</p></li> </ul> <p style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;margin-top: 16px;margin-bottom: 16px;color: rgb(34, 34, 34);font-family: "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", "Helvetica Neue", Arial, sans-serif;font-size: 16px;white-space: normal;background-color: rgb(255, 255, 255);">8.galera</p> <ul style="list-style-type: square;" class=" list-paddingleft-2"> <li><p>多主架构:真正的多点读写的集群,在任何时候读写数据,都是最新的。</p></li> <li><p>同步复制,各节点间无延迟且节点宕机不会导致数据丢失。</p></li> <li><p>紧密耦合,所有节点均保持相同状态,节点间无不同数据。</p></li> <li><p>无需主从切换操作。</p></li> <li><p>无需进行读写分离。</p></li> <li><p>并发复制:从节点在APPLY数据时,支持并行执行,有更好的性能表现。</p></li> <li><p>故障切换:在出现数据库故障时,因为支持多点写入,切的非常容易。</p></li> <li><p>热插拔:在服务期间,如果数据库挂了,只要监控程序发现的够快,不可服务时间就会非常少。在节点故障期间,节点本身对集群的影响非常小。</p></li> <li><p>自动节点克隆:在新增节点,或者停机维护时,增量数据或者基础数据不需要人工手动备份提供,Galera Cluster会自动拉取在线节点数据,最终集群会变为一致。</p></li> <li><p>对应用透明:集群的维护,对应用程序是透明的,几乎感觉不到。</p></li> </ul> <p style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;margin-top: 16px;margin-bottom: 16px;color: rgb(34, 34, 34);font-family: "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", "Helvetica Neue", Arial, sans-serif;font-size: 16px;white-space: normal;background-color: rgb(255, 255, 255);">9.LSM Tree,主要应用于nessDB、leveldb、hbase</p> <ul style="list-style-type: square;" class=" list-paddingleft-2"> <li><p>核心思想的核心就是放弃部分读能力,换取写入的最大化能力。它假设假定内存足够大,因此不需要每次有数据更新就必须将数据写入到磁盘中,而可以先将最新的数据驻留在内存中,等到积累到最后多之后,再使用<span style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;font-weight: 700;">归并排序</span>的方式将内存内的数据合并追加到磁盘队尾。(使用归并排序是要因为带排序树都是有序树)</p></li> <li><p>LSM具有批量特性,存储延迟。B树在insert的时候可能会造成分裂,可能会造成随机读写。而LSM将多次单页随机写,变成一次多页随机写,复用了磁盘寻道时间,极大提升效率。</p></li> <li><p>LSM Tree放弃磁盘读性能来换取写的顺序性。</p></li> <li><p>一般会使用Bloom Filter来优化LSM。当将内存中的数据与磁盘数据合并的时候,先要判断数据是否有重复,如果不用Bloom Filter就需要在磁盘上一层层地找,而使用了之后就会降低搜索代价。</p></li> </ul> <h1 style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;font-size: 24px;margin-top: 36px;margin-bottom: 22px;font-weight: 700;line-height: 32px;color: rgb(34, 34, 34);font-family: "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", "Helvetica Neue", Arial, sans-serif;white-space: normal;background-color: rgb(255, 255, 255);">多线程</h1> <ol style="" class=" list-paddingleft-2"> <li><p>synchronized、CAS</p></li> <li><p>Collections</p></li> <li><p>支持高并发的数据结构,如ConcurrentHashMap</p></li> <li><p>基于AQS实现的锁、信号量、计数器原理</p></li> <li><p>Runnable与Callable的区别</p></li> <li><p>线程池</p></li> <li><p>作用</p></li> </ol> <ul style="list-style-type: square;" class=" list-paddingleft-2"> <li><p>减少在创建和销毁线程上所花的时间以及系统资源的开销 。</p></li> <li><p>当前任务与主线程隔离,能实现和主线程的异步执行,特别是很多可以分开重复执行的任务。</p></li> </ul> <p style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;margin-top: 16px;margin-bottom: 16px;color: rgb(34, 34, 34);font-family: "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", "Helvetica Neue", Arial, sans-serif;font-size: 16px;white-space: normal;background-color: rgb(255, 255, 255);">8.阻塞队列</p> <p style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;margin-top: 16px;margin-bottom: 16px;color: rgb(34, 34, 34);font-family: "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", "Helvetica Neue", Arial, sans-serif;font-size: 16px;white-space: normal;background-color: rgb(255, 255, 255);">9.threadlocal</p> <h1 style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;font-size: 24px;margin-top: 36px;margin-bottom: 22px;font-weight: 700;line-height: 32px;color: rgb(34, 34, 34);font-family: "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", "Helvetica Neue", Arial, sans-serif;white-space: normal;background-color: rgb(255, 255, 255);"><span style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;">Spring框架</span></h1> <ol style="" class=" list-paddingleft-2"> <li><p>IOC/DI</p></li> <li><p>Core、Beans、Context、Expression Language</p></li> <li><p>JDBC、ORM、OXM、JMS、Transaction</p></li> <li><p>AOP</p></li> <li><p>Web</p></li> <li><p>Test</p></li> <li><p>@Autowired原理</p></li> <li><p>工厂模式</p></li> <li><p>反射</p></li> <li><p>自动配置@ConfigurationProperties(prefix = "hello"):读取以hello为开头的配置,属性类使用</p></li> <li><p>@Configuration:指名当前类为配置类</p></li> <li><p>@EnableConfigurationProperties(Properties):指名配置属性类</p></li> <li><p>@ConditionalOnClass(Condition.class):条件类,只有Condition.class存在,当前配置类才生效</p></li> <li><p>Spring Boot在spring.factories配置了很多全限定名的配置类。</p></li> </ol> <h1 style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;font-size: 24px;margin-top: 36px;margin-bottom: 22px;font-weight: 700;line-height: 32px;color: rgb(34, 34, 34);font-family: "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", "Helvetica Neue", Arial, sans-serif;white-space: normal;background-color: rgb(255, 255, 255);"><span style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;">Redis</span></h1> <p style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;margin-top: 16px;margin-bottom: 16px;color: rgb(34, 34, 34);font-family: "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", "Helvetica Neue", Arial, sans-serif;font-size: 16px;white-space: normal;background-color: rgb(255, 255, 255);"><span style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;font-weight: 700;">核心原理</span></p> <ol style="" class=" list-paddingleft-2"> <li><p>常用数据类型String:二进制安全,可以存任何数据,比如序列化的图片。最大长度位512M.</p></li> <li><p>Hash:是KV对集合,本质是String类型的KV映射,适合存储对象。</p></li> <li><p>List:简单字符串链表,可以在left、right两边插入,本质是双向链表。缓冲区也是用这个实现。</p></li> <li><p>Set:String类型的无序集合,内部实现是一个 value永远为null的HashMap,实际就是通过计算hash的方式来快速排重的,这也是set能提供判断一个成员是否在集合内的原因。</p></li> <li><p>zset:有序集合,每个元素会关联一个double类型的score,然后根据score进行排序。注意:元素不能重复,但是score是可以重复的。使用HashMap和跳跃表(SkipList)来保证数据的存储和有序,HashMap里放的是成员到score的映射,而跳跃表里存放的是所有的成员,排序依据是HashMap里存的score.</p></li> </ol> <ul style="list-style-type: square;" class=" list-paddingleft-2"> <li><p>pub/sub:在Redis中,你可以设定对某一个key值进行消息发布及消息订阅,当一个key值上进行了消息发布后,所有订阅它的客户端都会收到相应的消息。</p></li> </ul> <p style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;margin-top: 16px;margin-bottom: 16px;color: rgb(34, 34, 34);font-family: "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", "Helvetica Neue", Arial, sans-serif;font-size: 16px;white-space: normal;background-color: rgb(255, 255, 255);"><span style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;font-weight: 700;">持久化</span></p> <ol style="" class=" list-paddingleft-2"> <li><p>RDB:一种是手动执行持久化命令来持久化快照;另一种是在配置文件中配置策略,来自动持久化。持久化命令有save、bgsave两种,bgsave会调用fork命令,产生子进程来进行持久化,而父进程继续处理数据,但是持久化的快照是fork那一刻的快照,因此这种策略可能会丢失一部分数据。特点:每次都记录所有数据,恢复快,子进程不影响父进程性能。</p></li> <li><p>AOF:append only file,将每条操作命令都记录到appendonly.aof文件中,但是不会立马写入硬盘,我们可以配置always(每有一个命令,都同步)、everysec(每秒同步一次)、no(没30秒同步一次)。往往everysec就够了。aof数据损失要比RDB小。特点:有序记录所有操作,数据丢失更少,会对操作做压缩优化,bgrewriteaof也会fork子进程,不影响父进程性能</p></li> </ol> <p style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;margin-top: 16px;margin-bottom: 16px;color: rgb(34, 34, 34);font-family: "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", "Helvetica Neue", Arial, sans-serif;font-size: 16px;white-space: normal;background-color: rgb(255, 255, 255);"><span style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;font-weight: 700;">事务</span></p> <ol style="" class=" list-paddingleft-2"> <li><p>Transactions:不是严格的ACID的事务,但是这个Transactions还是提供了基本的命令打包执行的功能(在服务器不出问题的情况下,可以保证一连串的命令是顺序在一起执行的,中间有会有其它客户端命令插进来执行)。</p></li> <li><p>Redis还提供了一个Watch功能,你可以对一个key进行Watch,然后再执行Transactions,在这过程中,如果这个Watched的值进行了修改,那么这个Transactions会发现并拒绝执行。</p></li> </ol> <h1 style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;font-size: 24px;margin-top: 36px;margin-bottom: 22px;font-weight: 700;line-height: 32px;color: rgb(34, 34, 34);font-family: "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", "Helvetica Neue", Arial, sans-serif;white-space: normal;background-color: rgb(255, 255, 255);"><span style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;">KafKA</span></h1> <ol style="" class=" list-paddingleft-2"> <li><p>topic</p></li> <li><p>broker</p></li> <li><p>partition</p></li> <li><p>consumer</p></li> <li><p>producer</p></li> <li><p>stream</p></li> <li><p>存储机制</p></li> <li><p>网络模型</p></li> <li><p>注意:partition之间是无序的</p></li> <li><p>消息队列的生产者消费者中消费者没有收到消息怎么办,消息有顺序比如1.2.3但是收到的却是1.3.2怎么办?消息发过来的过程中损坏或者出错怎么办</p></li> </ol> <h1 style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;font-size: 24px;margin-top: 36px;margin-bottom: 22px;font-weight: 700;line-height: 32px;color: rgb(34, 34, 34);font-family: "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", "Helvetica Neue", Arial, sans-serif;white-space: normal;background-color: rgb(255, 255, 255);"><span style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;">Spring security</span></h1> <ol style="" class=" list-paddingleft-2"> <li><p>拦截器栈</p></li> <li><p>@PreAuthorize</p></li> <li><p>@PostAuthorize</p></li> <li><p>支持Expression Language</p></li> </ol> <h1 style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;font-size: 24px;margin-top: 36px;margin-bottom: 22px;font-weight: 700;line-height: 32px;color: rgb(34, 34, 34);font-family: "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", "Helvetica Neue", Arial, sans-serif;white-space: normal;background-color: rgb(255, 255, 255);"><span style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;">jvm原理</span></h1> <p style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;margin-top: 16px;margin-bottom: 16px;color: rgb(34, 34, 34);font-family: "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", "Helvetica Neue", Arial, sans-serif;font-size: 16px;white-space: normal;background-color: rgb(255, 255, 255);">内存模型、垃圾收集器、CMS与G1是重点</p> <p style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;margin-top: 16px;margin-bottom: 16px;color: rgb(34, 34, 34);font-family: "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", "Helvetica Neue", Arial, sans-serif;font-size: 16px;white-space: normal;background-color: rgb(255, 255, 255);"><span style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;font-weight: 700;">垃圾收集算法</span></p> <ul style="list-style-type: square;" class=" list-paddingleft-2"> <li><p>标记-清除(CMS)容易产生碎片,当碎片太多会提前触发Full GC</p></li> <li><p>复制(年轻代基本用这个算法)会浪费一半的可能感觉</p></li> <li><p>标记-整理(serial Old、Parallel Old)</p></li> <li><p>Serial:采用单线程stop-the-world的方式进行收集。当内存不足时,串行GC设置停顿标识,待所有线程都进入安全点(Safepoint)时,应用线程暂停,串行GC开始工作,采用单线程方式回收空间并整理内存。串行收集器特别适合堆内存不高、单核甚至双核CPU的场合。</p></li> <li><p>ParNew</p></li> <li><p>Parallel Scavenge</p></li> </ul> <p style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;margin-top: 16px;margin-bottom: 16px;color: rgb(34, 34, 34);font-family: "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", "Helvetica Neue", Arial, sans-serif;font-size: 16px;white-space: normal;background-color: rgb(255, 255, 255);"><span style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;font-weight: 700;">CMS</span>:</p> <ul style="list-style-type: square;" class=" list-paddingleft-2"> <li><p>初始标记(stop of world)</p></li> <li><p>并行标记、预清理</p></li> <li><p>重新标记(stop of world)</p></li> <li><p>并行清理</p></li> </ul> <p style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;margin-top: 16px;margin-bottom: 16px;color: rgb(34, 34, 34);font-family: "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", "Helvetica Neue", Arial, sans-serif;font-size: 16px;white-space: normal;background-color: rgb(255, 255, 255);"><span style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;font-weight: 700;">G1</span></p> <p style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;margin-top: 16px;margin-bottom: 16px;color: rgb(34, 34, 34);font-family: "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", "Helvetica Neue", Arial, sans-serif;font-size: 16px;white-space: normal;background-color: rgb(255, 255, 255);">将堆分成很多region,可以同时堆年轻代与老年代进行收集</p> <ul style="list-style-type: square;" class=" list-paddingleft-2"> <li><p>初始标记(stop of world):初始标记(Initial Mark)负责标记所有能被直接可达的根对象(原生栈对象、全局对象、JNI对象)</p></li> <li><p>并行标记:</p></li> <li><p>重新标记(stop of world):</p></li> <li><p>清理(stop of world):</p></li> <li><p>重置</p></li> </ul> <p style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;margin-top: 16px;margin-bottom: 16px;color: rgb(34, 34, 34);font-family: "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", "Helvetica Neue", Arial, sans-serif;font-size: 16px;white-space: normal;background-color: rgb(255, 255, 255);"><span style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;font-weight: 700;">gc触发条件</span></p> <ol style="" class=" list-paddingleft-2"> <li><p>从年轻代分区拷贝存活对象时,无法找到可用的空闲分区,会触发Minor GC</p></li> <li><p>从老年代分区转移存活对象时,无法找到可用的空闲分区,会触发Major GC</p></li> <li><p>分配巨型对象时在老年代无法找到足够的连续分区,会触发Major GC</p></li> <li><p>可达性分析:通过检查一块内存空间能否被root达到,来判断是否对其进行回收。</p></li> </ol> <p style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;margin-top: 16px;margin-bottom: 16px;color: rgb(34, 34, 34);font-family: "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", "Helvetica Neue", Arial, sans-serif;font-size: 16px;white-space: normal;background-color: rgb(255, 255, 255);"><span style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;font-weight: 700;">jdk不同版本新增的部分特性</span></p> <p style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;margin-top: 16px;margin-bottom: 16px;color: rgb(34, 34, 34);font-family: "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", "Helvetica Neue", Arial, sans-serif;font-size: 16px;white-space: normal;background-color: rgb(255, 255, 255);"><span style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;font-weight: 700;">jvm调优</span></p> <ul style="list-style-type: square;" class=" list-paddingleft-2"> <li><p>VisualVM:JDK自带JVM可视化工具,能过对内存、gc、cpu、thread、class、变量等等信息进行可视化。</p></li> </ul> <h1 style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;font-size: 24px;margin-top: 36px;margin-bottom: 22px;font-weight: 700;line-height: 32px;color: rgb(34, 34, 34);font-family: "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", "Helvetica Neue", Arial, sans-serif;white-space: normal;background-color: rgb(255, 255, 255);">设计模式</h1> <ol style="" class=" list-paddingleft-2"> <li><p>单例双重检查</p></li> <li><p>观察者模式</p></li> <li><p>装饰者模式:jdk中输入输出流用到了该模式</p></li> <li><p>适配器模式:jdk中Reader、writer用到了该模式</p></li> <li><p>代理模式</p></li> <li><p>静态代理</p></li> <li><p>JDK动态代理</p></li> <li><p>Cglib到动态代理</p></li> <li><p>生产者消费者模式</p></li> <li><p>工厂模式</p></li> </ol> <h1 style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;font-size: 24px;margin-top: 36px;margin-bottom: 22px;font-weight: 700;line-height: 32px;color: rgb(34, 34, 34);font-family: "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", "Helvetica Neue", Arial, sans-serif;white-space: normal;background-color: rgb(255, 255, 255);">项目管理与运维工具</h1> <ol style="" class=" list-paddingleft-2"> <li><p>git+Jenkins</p></li> <li><p>maven</p></li> <li><p>K8Spod:Pod是所有业务类型的基础,所有的容器均在Pod中运行,它是一个或多个容器的组合。每一个Pod都会被指派一个唯一的Ip地址,在Pod中的每一个容器共享网络命名空间,包括Ip地址和网络端口。Pod能够被指定共享存储卷的集合,在Pod中所有的容器能够访问共享存储卷,允许这些容器共享数据。</p></li> <li><p>kubelet:kubelet负责管理pods和它们上面的容器,images镜像、volumes、etc。</p></li> <li><p>ingress,用于负载均衡</p></li> <li><p>docker</p></li> <li><p>docker与虚拟机的区别</p></li> </ol> <h1 style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;font-size: 24px;margin-top: 36px;margin-bottom: 22px;font-weight: 700;line-height: 32px;color: rgb(34, 34, 34);font-family: "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", "Helvetica Neue", Arial, sans-serif;white-space: normal;background-color: rgb(255, 255, 255);">数据结构</h1> <ol style="" class=" list-paddingleft-2"> <li><p>平衡二叉树AVL</p></li> <li><p>高度log(n)</p></li> <li><p>插入时间复杂度log(n)</p></li> <li><p>红黑树</p></li> <li><p>插入时间复杂度log(n)</p></li> <li><p>查找时间复杂度log(n)</p></li> <li><p>在查找是,红黑树虽然复杂度也是log(n),但是从效率上比要略低于AVL。但是其优势在于插入元素的时候,不会像AVL那样频繁地旋转。</p></li> <li><p>B+Tree:只有叶子节点存值,非叶子节点只存key和child,因此同样大小的物理页上能存放更多的节点。每一层的节点数量越多,意味着层次越少,也就意味着IO次数越少,因此非常适合数据库以及文件系统。</p></li> <li><p>大根堆:采用数组存储树,是一个完全树。先插入到数组最后的位置上,然后采用上浮的思想,将该元素与比它小的父元素调换,直到parent>target,浮到root;然后将root与未排序的最后一个元素交换位置;重复以上步骤,直到所有元素都有序。插入如查找的复杂度都是log(n)。</p></li> <li><p>优先队列PriorityQueue,Java中使用小根堆实现,非线程安全。</p></li> <li><p>优先阻塞队列PriorityBlockQueue,线程安全。</p></li> </ol> <h1 style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;font-size: 24px;margin-top: 36px;margin-bottom: 22px;font-weight: 700;line-height: 32px;color: rgb(34, 34, 34);font-family: "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", "Helvetica Neue", Arial, sans-serif;white-space: normal;background-color: rgb(255, 255, 255);">算法</h1> <ol style="" class=" list-paddingleft-2"> <li><p>快排</p></li> <li><p>时间复杂度O(nlog(n))</p></li> <li><p>空间复杂度O(log(n))</p></li> <li><p>堆排序</p></li> <li><p>时间复杂度O(nlog(n))</p></li> <li><p>空间复杂度O(1)</p></li> <li><p>归并排序</p></li> <li><p>时间复杂度O(nlog(n))</p></li> <li><p>空间复杂度O(n)</p></li> <li><p>跳表时间复杂度O(log(n))</p></li> <li><p>空间复杂度O(2n)</p></li> <li><p>高度O(log(n))</p></li> </ol> <h1 style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;font-size: 24px;margin-top: 36px;margin-bottom: 22px;font-weight: 700;line-height: 32px;color: rgb(34, 34, 34);font-family: "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", "Helvetica Neue", Arial, sans-serif;white-space: normal;background-color: rgb(255, 255, 255);">分布式</h1> <p style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;margin-top: 16px;margin-bottom: 16px;color: rgb(34, 34, 34);font-family: "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", "Helvetica Neue", Arial, sans-serif;font-size: 16px;white-space: normal;background-color: rgb(255, 255, 255);"><span style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;font-weight: 700;">cap理论</span></p> <ol style="" class=" list-paddingleft-2"> <li><p>可用性</p></li> <li><p>一致性</p></li> <li><p>分区容忍性:对网络断开的容忍度,有点像鲁棒性</p></li> <li><p>拜占庭将军问题</p></li> </ol> <p style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;margin-top: 16px;margin-bottom: 16px;color: rgb(34, 34, 34);font-family: "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", "Helvetica Neue", Arial, sans-serif;font-size: 16px;white-space: normal;background-color: rgb(255, 255, 255);"><span style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;font-weight: 700;">Raft 算法</span></p> <ul style="list-style-type: square;" class=" list-paddingleft-2"> <li><p>有leader、follower、candidate</p></li> </ul> <p style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;margin-top: 16px;margin-bottom: 16px;color: rgb(34, 34, 34);font-family: "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", "Helvetica Neue", Arial, sans-serif;font-size: 16px;white-space: normal;background-color: rgb(255, 255, 255);"><span style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;font-weight: 700;">同步流程</span></p> <ol style="" class=" list-paddingleft-2"> <li><p>由客户端提交数据到Leader节点。</p></li> <li><p>由Leader节点把数据复制到集群内所有的Follower节点。如果一次复制失败,会不断进行重试。</p></li> <li><p>Follower节点们接收到复制的数据,会反馈给Leader节点。</p></li> <li><p>如果Leader节点接收到超过半数的Follower反馈,表明复制成功。于是提交自己的数据,并通知客户端数据提交成功。</p></li> <li><p>由Leader节点通知集群内所有的Follower节点提交数据,从而完成数据同步流程。</p></li> </ol> <p style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;margin-top: 16px;margin-bottom: 16px;color: rgb(34, 34, 34);font-family: "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", "Helvetica Neue", Arial, sans-serif;font-size: 16px;white-space: normal;background-color: rgb(255, 255, 255);"><span style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;font-weight: 700;">zookeeper</span></p> <ol style="" class=" list-paddingleft-2"> <li><p>Zab(Zookeeper Atomic Broadcast)协议,有两种模式:</p></li> </ol> <ul style="list-style-type: square;" class=" list-paddingleft-2"> <li><p>它们分别是:恢复模式(选主)和广播模式(同步)。</p></li> <li><p>有两种算法:1. basic paxos;2. fast paxos(默认)</p></li> </ul> <ol style="" class=" list-paddingleft-2"> <li><p>文件系统:zookeeper的通知机制、分布式锁、队列管理、配置管理都是基于文件系统的。</p></li> <li><p>分布式锁:有了zookeeper的一致性文件系统,锁的问题变得容易。锁服务可以分为两类,一个是保持独占,另一个是控制时序。</p></li> <li><p>独占锁:将zookeeper上的一个znode看作是一把锁,通过createznode的方式来实现。所有客户端都去创建 /distribute_lock 节点,最终成功创建的那个客户端也即拥有了这把锁。用完删除掉自己创建的distribute_lock 节点就释放出锁。</p></li> <li><p>控制时序锁:/distribute_lock 已经预先存在,所有客户端在它下面创建临时顺序编号目录节点,和选master一样,编号最小的获得锁,用完删除。</p></li> <li><p>队列管理,分为同步队列、非同步队列</p></li> <li><p>数据复制的好处</p></li> </ol> <ul style="list-style-type: square;" class=" list-paddingleft-2"> <li><p>容错:一个节点出错,不致于让整个系统停止工作,别的节点可以接管它的工作;</p></li> <li><p>提高系统的扩展能力 :把负载分布到多个节点上,或者增加节点来提高系统的负载能力;</p></li> <li><p>提高性能:让客户端本地访问就近的节点,提高用户访问速度。</p></li> </ul> <p style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;margin-top: 16px;margin-bottom: 16px;color: rgb(34, 34, 34);font-family: "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", "Helvetica Neue", Arial, sans-serif;font-size: 16px;white-space: normal;background-color: rgb(255, 255, 255);">5.一致性hash算法原理</p> <h1 style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;font-size: 24px;margin-top: 36px;margin-bottom: 22px;font-weight: 700;line-height: 32px;color: rgb(34, 34, 34);font-family: "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", "Helvetica Neue", Arial, sans-serif;white-space: normal;background-color: rgb(255, 255, 255);">微服务</h1> <p style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;margin-top: 16px;margin-bottom: 16px;color: rgb(34, 34, 34);font-family: "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", "Helvetica Neue", Arial, sans-serif;font-size: 16px;white-space: normal;background-color: rgb(255, 255, 255);"><span style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;font-weight: 700;">Spring cloud</span></p> <ul style="list-style-type: square;" class=" list-paddingleft-2"> <li><p>网关:zuul</p></li> <li><p>分布式版本化配置 config</p></li> <li><p>服务注册和发现:Eureka,配置时需要注意多久刷新列表一次,多久监测心跳等。</p></li> <li><p>service-to-service 调用</p></li> <li><p>负载均衡:Ribbon;在生成RestTemplate的bean时,通过@LoadBalanced注解可以使得RestTemplate的调用</p></li> <li><p>断路器:Hystrix</p></li> <li><p>监控:spring admin。在启动类上加@EnableAdminServer注解。</p></li> </ul> <h1 style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;font-size: 24px;margin-top: 36px;margin-bottom: 22px;font-weight: 700;line-height: 32px;color: rgb(34, 34, 34);font-family: "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", "Helvetica Neue", Arial, sans-serif;white-space: normal;background-color: rgb(255, 255, 255);">java web</h1> <ol style="" class=" list-paddingleft-2"> <li><p>servlet工作原理</p></li> <li><p>tomcat工作原理,好文,强推</p></li> <li><p>container</p></li> </ol> <h1 style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;font-size: 24px;margin-top: 36px;margin-bottom: 22px;font-weight: 700;line-height: 32px;color: rgb(34, 34, 34);font-family: "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", "Helvetica Neue", Arial, sans-serif;white-space: normal;background-color: rgb(255, 255, 255);">linux</h1> <ol style="" class=" list-paddingleft-2"> <li><p>系统结构,讲得很好,强推</p></li> <li><p>硬链接与软连接</p></li> <li><p>硬链接:数据节点通过引用计数的方式来对指向它的硬链接计数,当计数为0就删除。</p></li> <li><p>软连接:我们可以把它看成是快捷方式,它只是记录了某个文件的硬链接的路径,如果我们把源文件删除,再重新创建一个相同名字的文件,那么软连接指向的就是新创建的文件。</p></li> <li><p>虚拟文件系统(VFS):文件系统是有很多实现的,比如ext2、ext3、FAT等等,而VFS则是存在于应用程序与文件系统中间,它封装了open、close、read、write等等操作文件系统的接口,为应用程序屏蔽掉不同文件系统之间的差异。</p></li> <li><p>VFS数据结构</p></li> </ol> <h1 style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;font-size: 24px;margin-top: 36px;margin-bottom: 22px;font-weight: 700;line-height: 32px;color: rgb(34, 34, 34);font-family: "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", "Helvetica Neue", Arial, sans-serif;white-space: normal;background-color: rgb(255, 255, 255);">其它</h1> <ul style="list-style-type: square;" class=" list-paddingleft-2"> <li><p>bitmap,大文件交集</p></li> <li><p>Elasticsearch索引原理</p></li> <li><p>从内存到屏幕经历了啥</p></li> <li><p>高并发场景的限流,你怎么来确定限流限多少,模拟场景和实际场景有区别怎么解决,</p></li> </ul> <h1 style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;font-size: 24px;margin-top: 36px;margin-bottom: 22px;font-weight: 700;line-height: 32px;color: rgb(34, 34, 34);font-family: "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", "Helvetica Neue", Arial, sans-serif;white-space: normal;background-color: rgb(255, 255, 255);">百度面试</h1> <ul style="list-style-type: square;" class=" list-paddingleft-2"> <li><p>说一下redis与kafka,redis持久化策略</p></li> <li><p>git中rebase与merge区别</p></li> <li><p>docker底层原理,依赖操作系统的什么</p></li> <li><p>ls -l | grep xxx的执行过程,尽可能的细,是多进程还是单进程?</p></li> <li><p>两个有序数组求中位数</p></li> <li><p>算法 3Sum、中序遍历非递归实现、循环打印矩阵</p></li> <li><p>final、finally、finanize</p></li> <li><p>jvm内存模型</p></li> <li><p>垃圾回收器</p></li> <li><p>Spring特点介绍下</p></li> <li><p>Synchronize与ReentrantLock的区别、使用场景</p></li> <li><p>CAS使用场景</p></li> <li><p>聊了下git+jekins+K8S+docker实现自动化部署</p></li> <li><p>innodb原理,使用场景,与MYISAM在场景上的区别</p></li> <li><p>weakReference、softReference等</p></li> <li><p>Hbase的原理,LSM Tree</p></li> <li><p>Linux中,哪种进程可以使用管道</p></li> </ul> <h1 style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;font-size: 24px;margin-top: 36px;margin-bottom: 22px;font-weight: 700;line-height: 32px;color: rgb(34, 34, 34);font-family: "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", "Helvetica Neue", Arial, sans-serif;white-space: normal;background-color: rgb(255, 255, 255);">美团</h1> <ul style="list-style-type: square;" class=" list-paddingleft-2"> <li><p>权限模型</p></li> <li><p>介绍下线程池,阻塞队列的用法,无界队列真的无界吗?</p></li> <li><p>说一下redis</p></li> <li><p>kafka存储模型与网络模型</p></li> <li><p>zookeeper与redis实现分布式锁</p></li> <li><p>乐观锁与悲观锁</p></li> <li><p>算法:有n个人,给你ai与aj的身高关系,如ai比aj高,进行身高排序,如果条件不满足,则输出“不满足”</p></li> <li><p>Spring boot的特性</p></li> </ul> <section class="_135editor" data-tools="135编辑器" data-id="85996" style="border-width: 0px;border-style: none;border-color: initial;box-sizing: border-box;"> <section style="text-align:center;"> <section style="background-color: rgb(244, 244, 244);box-sizing: border-box;padding: 40px;"> <section style="margin-bottom: 10px;"> <span style="font-size: 18px;"><span style="color: #030303;font-weight: 600;">Java高级架构 </span><span style="color: #3f3f3f;">∣</span></span> <span style="color:#030303;" class="135brush" data-brushtype="text">干货|学习</span> </section> <section> <section style="display:inline-block;vertical-align: top;margin-top: 14px;width: 50%;text-align: right;" data-width="50%"> <img border="0" class="" data-ratio="0.993993993993994" src="/upload/b65b49bf5b4b93db5800dd70c5faae54.png" data-type="png" data-w="666" height="auto" opacity="" style="width: 120px;" title="" width="120"> </section> <section style="display:inline-block;box-sizing:border-box;padding-left: 10px;width: 50%;text-align: left;" data-width="50%"> <img class="" data-ratio="1.39" src="/upload/9d2924f9c5be1305d2d10457a2988b10.png" data-type="png" data-w="100" style="width: 100px;"> </section> </section> <section style="margin-top: 6px;"> <span style="color: #0c0c0c;" class="135brush" data-brushtype="text">长按,识别二维码,加关注</span> </section> </section> </section> </section> <section class="_135editor" data-id="image-96175" style="border-width: 0px;border-style: none;border-color: initial;box-sizing: border-box;"> <section class="_135editor" data-tools="135编辑器" data-id="92353" style="border-width: 0px;border-style: none;border-color: initial;box-sizing: border-box;"> <section data-role="paragraph" class="_135editor" style="border-width: 0px;border-style: none;border-color: initial;box-sizing: border-box;"> <section style="padding: 10px;box-sizing: border-box;"> <section style="width: 130px;height: 30px;background-image: url("https://mmbiz.qpic.cn/mmbiz_png/YUYc62VIvE05v65wfubMkibvCMQyaag7p0UhALSARRVMTOMc9hDtPEebia7uic711RoftVxJicZnKezl2UIXbOo2dQ/640?wx_fmt=png");background-size: 100%;background-repeat: no-repeat;background-position: center center;margin-left: 25px;transform: translateZ(10px);"> <section style="width: 118px;height: 30px;text-align: center;line-height: 30px;color: #fefefe;letter-spacing: 3px;"> <p class="135brush" data-brushtype="text"><strong>温馨提示</strong></p> </section> </section> <section style="box-shadow: rgb(204, 204, 204) 0px 0px 7px;border-radius: 15px;color: rgb(51, 51, 51);padding: 15px;margin-top: -20px;box-sizing: border-box;"> <section style="line-height: 25px;margin-top: 15px;font-size: 14px;" class="135brush"> <p>如果你喜欢本文,请分享到朋友圈,想要获得更多信息,请关注我。关注本文说说你的看法吧,下方评论哦。。。Java劝退师........</p> </section> </section> </section> </section> </section> </section> <section class="_135editor" data-id="image-96108" style="border-width: 0px;border-style: none;border-color: initial;box-sizing: border-box;"> <p style="text-align:center;"><br></p> </section> <p style="text-align: center;"><img class="" data-copyright="0" data-ratio="0.7418181818181818" data-s="300,640" src="/upload/7cd7c01efb5a3c4a87a753be3ff45346.png" data-type="png" data-w="550" style=""></p> <p style="text-align: center;">想获取上方资料加群:859729143 点击<span style="color: rgb(255, 41, 65);">阅读原文</span>即可进群</p> <p style="text-align: center;"><img class="" data-ratio="1.3703703703703705" data-s="300,640" src="/upload/89a5720d4f18a6352feaab6d50da7683.png" data-type="png" data-w="540" style="width: 213px;height: 291px;"></p> <p style="text-align: center;">扫一扫即可领取资料学习</p> <p><br></p>
作者:じ☆ve宝贝
### html(一定要引入jquery.js) ``` <form action="" id="form" method="post" enctype="multipart/form-data"> <P id="localImg">本地图片:<input id="upimg" onchange="ajaxFileUpload()" type="file"><span>系统支持的图片格式为:gif,jpg,jpeg,png</span></P> </form> ``` ### js部分 ``` function ajaxFileUpload(obj,src) { var imgData = new FormData(); var imgFile = $('#upimg')[0].files[0]; if (!isEmpty(imgFile)) { imgData.append('files', imgFile); } var type = "localmedia"; // 其他参数 if (!isEmpty(type)) { imgData.append('type', type); } $.ajax({ url: '${baseUrl}/files', type: "POST", data: imgData, enctype: 'multipart/form-data', processData: false, contentType: false, cache: false, headers: { 'X-Token':token }, success: function (data){ alert('成功'); } }) } ``` 注意,在含有这个对象的form表单中一定要加入enctype="multipart/form-data"
作者:微信小助手
<section class="xmteditor" style="display:none;" data-tools="新媒体管家" data-label="powered by xmt.cn"></section> <blockquote style="box-sizing: border-box;margin: 20px 10px;padding-top: 1px;padding-bottom: 1px;font-size: 16px;white-space: normal;text-align: left;color: rgb(91, 91, 91);line-height: 1.5;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;background: rgba(158, 158, 158, 0.1);border-left-color: rgb(158, 158, 158);"> <p style="box-sizing: border-box;margin: 10px;color: rgb(63, 63, 63);line-height: 1.6;">标题显得有点标题党的味道?看了文章内容之后就知道是干货了!这篇文章用来入门或者复习Java的Lambda表达式都是非常不错的。我在文章补充了少部分知识点,比如Java 开发使用手册对<code style="box-sizing: border-box;padding: 3px 5px;color: rgb(255, 53, 2);line-height: 1.5;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 14.4px;background: rgb(248, 245, 236);border-radius: 2px;">Arrays.asList()</code>方法使用的介绍、IDEA在Lambda表达式这块的智能提示......</p> <p style="box-sizing: border-box;margin: 10px;color: rgb(63, 63, 63);line-height: 1.6;">本文转载自:https://dwz.cn/5H0shOuC 作者 :吴仙杰</p> </blockquote> <h2 style="margin-top: 1.5em;margin-bottom: 1.5em;font-weight: bold;font-size: 1.4em;max-width: 100%;box-sizing: border-box;letter-spacing: 0.544px;white-space: normal;color: rgb(63, 63, 63);line-height: inherit;text-align: left;overflow-wrap: break-word !important;"><span style="max-width: 100%;box-sizing: border-box;color: inherit;line-height: inherit;font-size: 18px;overflow-wrap: break-word !important;">相关文章推荐:</span><a href="https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247484744&idx=1&sn=9db31dca13d327678845054af75efb74&chksm=cea24a83f9d5c3956f4feb9956b068624ab2fdd6c4a75fe52d5df5dca356a016577301399548&token=1082669959&lang=zh_CN&scene=21#wechat_redirect" title="Java 8 新特性最佳指南" data-linktype="2" style="letter-spacing: 0.544px;color: rgb(20, 140, 228);-webkit-tap-highlight-color: rgba(0, 0, 0, 0);max-width: 100%;box-sizing: border-box;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;text-indent: -20px;background-color: rgb(255, 255, 255);overflow-wrap: break-word !important;">Java 8 新特性最佳指南</a></h2> <h2 style="margin-top: 1.5em;margin-bottom: 1.5em;font-weight: bold;font-size: 1.4em;max-width: 100%;box-sizing: border-box;letter-spacing: 0.544px;white-space: normal;color: rgb(63, 63, 63);line-height: inherit;text-align: left;overflow-wrap: break-word !important;"><span style="letter-spacing: 0.544px;font-size: 1.6em;text-align: justify;"></span></h2> <h1 style="box-sizing: border-box;margin-top: 1.5em;margin-bottom: 1.5em;font-weight: bold;font-size: 1.6em;color: rgb(63, 63, 63);line-height: inherit;"><span style="box-sizing: border-box;font-size: inherit;color: inherit;line-height: inherit;">1. 引言</span><br></h1> <p style="box-sizing: border-box;margin-top: 1.5em;margin-bottom: 1.5em;color: rgb(62, 62, 62);line-height: inherit;">在 Java 8 以前,若我们想要把某些功能传递给某些方法,总要去写匿名类。以前注册事件监听器的写法与下面的示例代码就很像:</p> <pre style="box-sizing: border-box;color: rgb(62, 62, 62);line-height: inherit;text-align: start;background-color: rgb(255, 255, 255);"><code class="java language-java hljs" style="box-sizing: border-box;padding: 0.5em;font-size: 14px;color: rgb(67, 79, 84);line-height: 18px;background-image: initial;background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;display: block;font-family: Consolas, Inconsolata, Courier, monospace;overflow-x: auto;letter-spacing: 0px;box-shadow: rgb(221, 221, 221) 0px 0px 15px 3px;margin: 30px 8px 20px !important;overflow-wrap: normal !important;border-radius: 8px !important;word-break: normal !important;overflow-y: auto !important;">manager.addScheduleListener(<span class="hljs-keyword" style="box-sizing: border-box;font-size: inherit;color: rgb(0, 151, 157);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">new</span> ScheduleListener() {<br style="box-sizing: border-box;font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;"> <span class="hljs-meta" style="box-sizing: border-box;font-size: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">@Override</span><br style="box-sizing: border-box;font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;"> <span class="hljs-function" style="box-sizing: border-box;font-size: inherit;color: rgb(114, 142, 0);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;"><span class="hljs-keyword" style="box-sizing: border-box;font-size: inherit;color: rgb(0, 151, 157);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">public</span> <span class="hljs-keyword" style="box-sizing: border-box;font-size: inherit;color: rgb(0, 151, 157);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">void</span> <span class="hljs-title" style="box-sizing: border-box;font-size: inherit;color: rgb(136, 0, 0);line-height: inherit;font-weight: bold;overflow-wrap: inherit !important;word-break: inherit !important;">onSchedule</span><span class="hljs-params" style="box-sizing: border-box;font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">(ScheduleEvent e)</span> </span>{ <br style="box-sizing: border-box;font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;"> <span class="hljs-comment" style="box-sizing: border-box;font-size: inherit;color: rgba(149, 165, 166, 0.8);line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">// Event listener implementation goes here...</span><br style="box-sizing: border-box;font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;"> }<br style="box-sizing: border-box;font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">});<br style="box-sizing: border-box;font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;"></code></pre> <p style="box-sizing: border-box;margin-top: 1.5em;margin-bottom: 1.5em;color: rgb(62, 62, 62);line-height: inherit;">这里我们添加了一些自定义代码到 Schedule 监听器中,需要先定义匿名内部类,然后传递一些功能到 <code style="box-sizing: border-box;margin-right: 2px;margin-left: 2px;padding: 2px 4px;font-size: inherit;color: rgb(233, 105, 0);line-height: inherit;overflow-wrap: break-word;border-radius: 4px;background: rgb(248, 248, 248);">onSchedule</code> 方法中。</p> <p style="box-sizing: border-box;margin-top: 1.5em;margin-bottom: 1.5em;color: rgb(62, 62, 62);line-height: inherit;">正是 Java 在作为参数传递普通方法或功能的限制,Java 8 增加了一个全新语言级别的功能,称为 <strong style="box-sizing: border-box;color: rgb(255, 87, 34);font-size: inherit;line-height: inherit;">Lambda 表达式</strong>。</p> <h1 style="box-sizing: border-box;margin-top: 1.5em;margin-bottom: 1.5em;font-weight: bold;font-size: 1.6em;color: rgb(63, 63, 63);line-height: inherit;"><span style="box-sizing: border-box;font-size: inherit;color: inherit;line-height: inherit;">2. 为什么 Java 需要 Lambda 表达式</span></h1> <p style="box-sizing: border-box;margin-top: 1.5em;margin-bottom: 1.5em;color: rgb(62, 62, 62);line-height: inherit;">Java 是<strong style="box-sizing: border-box;color: rgb(255, 87, 34);font-size: inherit;line-height: inherit;">面向对象</strong>语言,除了原始数据类型之处,Java 中的所有内容都是一个对象。而在<strong style="box-sizing: border-box;color: rgb(255, 87, 34);font-size: inherit;line-height: inherit;">函数式</strong>语言中,我们只需要给函数分配变量,并将这个函数作为参数传递给其它函数就可实现特定的功能。JavaScript 就是功能编程语言的典范(闭包)。</p> <p style="box-sizing: border-box;margin-top: 1.5em;margin-bottom: 1.5em;color: rgb(62, 62, 62);line-height: inherit;">Lambda 表达式的加入,使得 Java 拥有了函数式编程的能力。在其它语言中,Lambda 表达式的类型是一个函数;但在 Java 中,Lambda 表达式被表示为对象,因此它们必须绑定到被称为<strong style="box-sizing: border-box;color: rgb(255, 87, 34);font-size: inherit;line-height: inherit;">功能接口</strong>的特�