diff --git a/404.html b/404.html new file mode 100644 index 00000000..dac91df8 --- /dev/null +++ b/404.html @@ -0,0 +1,20 @@ + + + + + + 鲁班 - 系统设计大全 + + + + + + + + +

404

That's a Four-Oh-Four.
+ Take me home. +
+ + + diff --git a/assets/css/0.styles.e0164599.css b/assets/css/0.styles.e0164599.css new file mode 100644 index 00000000..1b89e828 --- /dev/null +++ b/assets/css/0.styles.e0164599.css @@ -0,0 +1 @@ +code[class*=language-],pre[class*=language-]{color:#ccc;background:none;font-family:Consolas,Monaco,Andale Mono,Ubuntu Mono,monospace;font-size:1em;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-ms-hyphens:none;hyphens:none}pre[class*=language-]{padding:1em;margin:.5em 0;overflow:auto}:not(pre)>code[class*=language-],pre[class*=language-]{background:#2d2d2d}:not(pre)>code[class*=language-]{padding:.1em;border-radius:.3em;white-space:normal}.token.block-comment,.token.cdata,.token.comment,.token.doctype,.token.prolog{color:#999}.token.punctuation{color:#ccc}.token.attr-name,.token.deleted,.token.namespace,.token.tag{color:#e2777a}.token.function-name{color:#6196cc}.token.boolean,.token.function,.token.number{color:#f08d49}.token.class-name,.token.constant,.token.property,.token.symbol{color:#f8c555}.token.atrule,.token.builtin,.token.important,.token.keyword,.token.selector{color:#cc99cd}.token.attr-value,.token.char,.token.regex,.token.string,.token.variable{color:#7ec699}.token.entity,.token.operator,.token.url{color:#67cdcc}.token.bold,.token.important{font-weight:700}.token.italic{font-style:italic}.token.entity{cursor:help}.token.inserted{color:green}.theme-default-content code{color:#476582;padding:.25rem .5rem;margin:0;font-size:.85em;background-color:rgba(27,31,35,.05);border-radius:3px}.theme-default-content code .token.deleted{color:#ec5975}.theme-default-content code .token.inserted{color:#3eaf7c}.theme-default-content pre,.theme-default-content pre[class*=language-]{line-height:1.4;padding:1.25rem 1.5rem;margin:.85rem 0;background-color:#282c34;border-radius:6px;overflow:auto}.theme-default-content pre[class*=language-] code,.theme-default-content pre code{color:#fff;padding:0;background-color:transparent;border-radius:0}div[class*=language-]{position:relative;background-color:#282c34;border-radius:6px}div[class*=language-] .highlight-lines{-webkit-user-select:none;user-select:none;padding-top:1.3rem;position:absolute;top:0;left:0;width:100%;line-height:1.4}div[class*=language-] .highlight-lines .highlighted{background-color:rgba(0,0,0,.66)}div[class*=language-] pre,div[class*=language-] pre[class*=language-]{background:transparent;position:relative;z-index:1}div[class*=language-]:before{position:absolute;z-index:3;top:.8em;right:1em;font-size:.75rem;color:hsla(0,0%,100%,.4)}div[class*=language-]:not(.line-numbers-mode) .line-numbers-wrapper{display:none}div[class*=language-].line-numbers-mode .highlight-lines .highlighted{position:relative}div[class*=language-].line-numbers-mode .highlight-lines .highlighted:before{content:" ";position:absolute;z-index:3;left:0;top:0;display:block;width:3.5rem;height:100%;background-color:rgba(0,0,0,.66)}div[class*=language-].line-numbers-mode pre{padding-left:4.5rem;vertical-align:middle}div[class*=language-].line-numbers-mode .line-numbers-wrapper{position:absolute;top:0;width:3.5rem;text-align:center;color:hsla(0,0%,100%,.3);padding:1.25rem 0;line-height:1.4}div[class*=language-].line-numbers-mode .line-numbers-wrapper br{-webkit-user-select:none;user-select:none}div[class*=language-].line-numbers-mode .line-numbers-wrapper .line-number{position:relative;z-index:4;-webkit-user-select:none;user-select:none;font-size:.85em}div[class*=language-].line-numbers-mode:after{content:"";position:absolute;z-index:2;top:0;left:0;width:3.5rem;height:100%;border-radius:6px 0 0 6px;border-right:1px solid rgba(0,0,0,.66);background-color:#282c34}div[class~=language-js]:before{content:"js"}div[class~=language-ts]:before{content:"ts"}div[class~=language-html]:before{content:"html"}div[class~=language-md]:before{content:"md"}div[class~=language-vue]:before{content:"vue"}div[class~=language-css]:before{content:"css"}div[class~=language-sass]:before{content:"sass"}div[class~=language-scss]:before{content:"scss"}div[class~=language-less]:before{content:"less"}div[class~=language-stylus]:before{content:"stylus"}div[class~=language-go]:before{content:"go"}div[class~=language-java]:before{content:"java"}div[class~=language-c]:before{content:"c"}div[class~=language-sh]:before{content:"sh"}div[class~=language-yaml]:before{content:"yaml"}div[class~=language-py]:before{content:"py"}div[class~=language-docker]:before{content:"docker"}div[class~=language-dockerfile]:before{content:"dockerfile"}div[class~=language-makefile]:before{content:"makefile"}div[class~=language-javascript]:before{content:"js"}div[class~=language-typescript]:before{content:"ts"}div[class~=language-markup]:before{content:"html"}div[class~=language-markdown]:before{content:"md"}div[class~=language-json]:before{content:"json"}div[class~=language-ruby]:before{content:"rb"}div[class~=language-python]:before{content:"py"}div[class~=language-bash]:before{content:"sh"}div[class~=language-php]:before{content:"php"}.custom-block .custom-block-title{font-weight:600;margin-bottom:-.4rem}.custom-block.danger,.custom-block.tip,.custom-block.warning{padding:.1rem 1.5rem;border-left-width:.5rem;border-left-style:solid;margin:1rem 0}.custom-block.tip{background-color:#f3f5f7;border-color:#42b983}.custom-block.warning{background-color:rgba(255,229,100,.3);border-color:#e7c000;color:#6b5900}.custom-block.warning .custom-block-title{color:#b29400}.custom-block.warning a{color:#2c3e50}.custom-block.danger{background-color:#ffe6e6;border-color:#c00;color:#4d0000}.custom-block.danger .custom-block-title{color:#900}.custom-block.danger a{color:#2c3e50}.custom-block.details{display:block;position:relative;border-radius:2px;margin:1.6em 0;padding:1.6em;background-color:#eee}.custom-block.details h4{margin-top:0}.custom-block.details figure:last-child,.custom-block.details p:last-child{margin-bottom:0;padding-bottom:0}.custom-block.details summary{outline:none;cursor:pointer}.arrow{display:inline-block;width:0;height:0}.arrow.up{border-bottom:6px solid #ccc}.arrow.down,.arrow.up{border-left:4px solid transparent;border-right:4px solid transparent}.arrow.down{border-top:6px solid #ccc}.arrow.right{border-left:6px solid #ccc}.arrow.left,.arrow.right{border-top:4px solid transparent;border-bottom:4px solid transparent}.arrow.left{border-right:6px solid #ccc}.theme-default-content:not(.custom){max-width:740px;margin:0 auto;padding:2rem 2.5rem}@media (max-width:959px){.theme-default-content:not(.custom){padding:2rem}}@media (max-width:419px){.theme-default-content:not(.custom){padding:1.5rem}}.table-of-contents .badge{vertical-align:middle}body,html{padding:0;margin:0;background-color:#fff}body{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;font-size:16px;color:#2c3e50}.page{padding-left:20rem}.navbar{z-index:20;right:0;height:3.6rem;background-color:#fff;box-sizing:border-box;border-bottom:1px solid #eaecef}.navbar,.sidebar-mask{position:fixed;top:0;left:0}.sidebar-mask{z-index:9;width:100vw;height:100vh;display:none}.sidebar{font-size:16px;background-color:#fff;width:20rem;position:fixed;z-index:10;margin:0;top:3.6rem;left:0;bottom:0;box-sizing:border-box;border-right:1px solid #eaecef;overflow-y:auto}.theme-default-content:not(.custom)>:first-child{margin-top:3.6rem}.theme-default-content:not(.custom) a:hover{text-decoration:underline}.theme-default-content:not(.custom) p.demo{padding:1rem 1.5rem;border:1px solid #ddd;border-radius:4px}.theme-default-content:not(.custom) img{max-width:100%}.theme-default-content.custom{padding:0;margin:0}.theme-default-content.custom img{max-width:100%}a{font-weight:500;text-decoration:none}a,p a code{color:#3eaf7c}p a code{font-weight:400}kbd{background:#eee;border:.15rem solid #ddd;border-bottom:.25rem solid #ddd;border-radius:.15rem;padding:0 .15em}blockquote{font-size:1rem;color:#999;border-left:.2rem solid #dfe2e5;margin:1rem 0;padding:.25rem 0 .25rem 1rem}blockquote>p{margin:0}ol,ul{padding-left:1.2em}strong{font-weight:600}h1,h2,h3,h4,h5,h6{font-weight:600;line-height:1.25}.theme-default-content:not(.custom)>h1,.theme-default-content:not(.custom)>h2,.theme-default-content:not(.custom)>h3,.theme-default-content:not(.custom)>h4,.theme-default-content:not(.custom)>h5,.theme-default-content:not(.custom)>h6{margin-top:-3.1rem;padding-top:4.6rem;margin-bottom:0}.theme-default-content:not(.custom)>h1:first-child,.theme-default-content:not(.custom)>h2:first-child,.theme-default-content:not(.custom)>h3:first-child,.theme-default-content:not(.custom)>h4:first-child,.theme-default-content:not(.custom)>h5:first-child,.theme-default-content:not(.custom)>h6:first-child{margin-top:-1.5rem;margin-bottom:1rem}.theme-default-content:not(.custom)>h1:first-child+.custom-block,.theme-default-content:not(.custom)>h1:first-child+p,.theme-default-content:not(.custom)>h1:first-child+pre,.theme-default-content:not(.custom)>h2:first-child+.custom-block,.theme-default-content:not(.custom)>h2:first-child+p,.theme-default-content:not(.custom)>h2:first-child+pre,.theme-default-content:not(.custom)>h3:first-child+.custom-block,.theme-default-content:not(.custom)>h3:first-child+p,.theme-default-content:not(.custom)>h3:first-child+pre,.theme-default-content:not(.custom)>h4:first-child+.custom-block,.theme-default-content:not(.custom)>h4:first-child+p,.theme-default-content:not(.custom)>h4:first-child+pre,.theme-default-content:not(.custom)>h5:first-child+.custom-block,.theme-default-content:not(.custom)>h5:first-child+p,.theme-default-content:not(.custom)>h5:first-child+pre,.theme-default-content:not(.custom)>h6:first-child+.custom-block,.theme-default-content:not(.custom)>h6:first-child+p,.theme-default-content:not(.custom)>h6:first-child+pre{margin-top:2rem}h1:focus .header-anchor,h1:hover .header-anchor,h2:focus .header-anchor,h2:hover .header-anchor,h3:focus .header-anchor,h3:hover .header-anchor,h4:focus .header-anchor,h4:hover .header-anchor,h5:focus .header-anchor,h5:hover .header-anchor,h6:focus .header-anchor,h6:hover .header-anchor{opacity:1}h1{font-size:2.2rem}h2{font-size:1.65rem;padding-bottom:.3rem;border-bottom:1px solid #eaecef}h3{font-size:1.35rem}a.header-anchor{font-size:.85em;float:left;margin-left:-.87em;padding-right:.23em;margin-top:.125em;opacity:0}a.header-anchor:focus,a.header-anchor:hover{text-decoration:none}.line-number,code,kbd{font-family:source-code-pro,Menlo,Monaco,Consolas,Courier New,monospace}ol,p,ul{line-height:1.7}hr{border:0;border-top:1px solid #eaecef}table{border-collapse:collapse;margin:1rem 0;display:block;overflow-x:auto}tr{border-top:1px solid #dfe2e5}tr:nth-child(2n){background-color:#f6f8fa}td,th{border:1px solid #dfe2e5;padding:.6em 1em}.theme-container.sidebar-open .sidebar-mask{display:block}.theme-container.no-navbar .theme-default-content:not(.custom)>h1,.theme-container.no-navbar h2,.theme-container.no-navbar h3,.theme-container.no-navbar h4,.theme-container.no-navbar h5,.theme-container.no-navbar h6{margin-top:1.5rem;padding-top:0}.theme-container.no-navbar .sidebar{top:0}@media (min-width:720px){.theme-container.no-sidebar .sidebar{display:none}.theme-container.no-sidebar .page{padding-left:0}}@media (max-width:959px){.sidebar{font-size:15px;width:16.4rem}.page{padding-left:16.4rem}}@media (max-width:719px){.sidebar{top:0;padding-top:3.6rem;transform:translateX(-100%);transition:transform .2s ease}.page{padding-left:0}.theme-container.sidebar-open .sidebar{transform:translateX(0)}.theme-container.no-navbar .sidebar{padding-top:0}}@media (max-width:419px){h1{font-size:1.9rem}.theme-default-content div[class*=language-]{margin:.85rem -1.5rem;border-radius:0}}.gt-container{width:80%;margin-left:auto;margin-right:auto}html{scroll-behavior:smooth}.go-to-top[data-v-5fd4ef0c]{cursor:pointer;position:fixed;bottom:2rem;right:2.5rem;width:2rem;color:#3eaf7c;z-index:1}.go-to-top[data-v-5fd4ef0c]:hover{color:#72cda4}@media (max-width:959px){.go-to-top[data-v-5fd4ef0c]{display:none}}.fade-enter-active[data-v-5fd4ef0c],.fade-leave-active[data-v-5fd4ef0c]{transition:opacity .3s}.fade-enter[data-v-5fd4ef0c],.fade-leave-to[data-v-5fd4ef0c]{opacity:0}#nprogress{pointer-events:none}#nprogress .bar{background:#3eaf7c;position:fixed;z-index:1031;top:0;left:0;width:100%;height:2px}#nprogress .peg{display:block;position:absolute;right:0;width:100px;height:100%;box-shadow:0 0 10px #3eaf7c,0 0 5px #3eaf7c;opacity:1;transform:rotate(3deg) translateY(-4px)}#nprogress .spinner{display:block;position:fixed;z-index:1031;top:15px;right:15px}#nprogress .spinner-icon{width:18px;height:18px;box-sizing:border-box;border-color:#3eaf7c transparent transparent #3eaf7c;border-style:solid;border-width:2px;border-radius:50%;-webkit-animation:nprogress-spinner .4s linear infinite;animation:nprogress-spinner .4s linear infinite}.nprogress-custom-parent{overflow:hidden;position:relative}.nprogress-custom-parent #nprogress .bar,.nprogress-custom-parent #nprogress .spinner{position:absolute}@-webkit-keyframes nprogress-spinner{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}@keyframes nprogress-spinner{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}.icon.outbound{color:#aaa;display:inline-block;vertical-align:middle;position:relative;top:-1px}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border-width:0}.home{padding:3.6rem 2rem 0;max-width:960px;margin:0 auto;display:block}.home .hero{text-align:center}.home .hero img{max-width:100%;max-height:280px;display:block;margin:3rem auto 1.5rem}.home .hero h1{font-size:3rem}.home .hero .action,.home .hero .description,.home .hero h1{margin:1.8rem auto}.home .hero .description{max-width:35rem;font-size:1.6rem;line-height:1.3;color:#6a8bad}.home .hero .action-button{display:inline-block;font-size:1.2rem;color:#fff;background-color:#3eaf7c;padding:.8rem 1.6rem;border-radius:4px;transition:background-color .1s ease;box-sizing:border-box;border-bottom:1px solid #389d70}.home .hero .action-button:hover{background-color:#4abf8a}.home .features{border-top:1px solid #eaecef;padding:1.2rem 0;margin-top:2.5rem;display:flex;flex-wrap:wrap;align-items:flex-start;align-content:stretch;justify-content:space-between}.home .feature{flex-grow:1;flex-basis:30%;max-width:30%}.home .feature h2{font-size:1.4rem;font-weight:500;border-bottom:none;padding-bottom:0;color:#3a5169}.home .feature p{color:#4e6e8e}.home .footer{padding:2.5rem;border-top:1px solid #eaecef;text-align:center;color:#4e6e8e}@media (max-width:719px){.home .features{flex-direction:column}.home .feature{max-width:100%;padding:0 2.5rem}}@media (max-width:419px){.home{padding-left:1.5rem;padding-right:1.5rem}.home .hero img{max-height:210px;margin:2rem auto 1.2rem}.home .hero h1{font-size:2rem}.home .hero .action,.home .hero .description,.home .hero h1{margin:1.2rem auto}.home .hero .description{font-size:1.2rem}.home .hero .action-button{font-size:1rem;padding:.6rem 1.2rem}.home .feature h2{font-size:1.25rem}}.search-box{display:inline-block;position:relative;margin-right:1rem}.search-box input{cursor:text;width:10rem;height:2rem;color:#4e6e8e;display:inline-block;border:1px solid #cfd4db;border-radius:2rem;font-size:.9rem;line-height:2rem;padding:0 .5rem 0 2rem;outline:none;transition:all .2s ease;background:#fff url(/luban/assets/img/search.83621669.svg) .6rem .5rem no-repeat;background-size:1rem}.search-box input:focus{cursor:auto;border-color:#3eaf7c}.search-box .suggestions{background:#fff;width:20rem;position:absolute;top:2rem;border:1px solid #cfd4db;border-radius:6px;padding:.4rem;list-style-type:none}.search-box .suggestions.align-right{right:0}.search-box .suggestion{line-height:1.4;padding:.4rem .6rem;border-radius:4px;cursor:pointer}.search-box .suggestion a{white-space:normal;color:#5d82a6}.search-box .suggestion a .page-title{font-weight:600}.search-box .suggestion a .header{font-size:.9em;margin-left:.25em}.search-box .suggestion.focused{background-color:#f3f4f5}.search-box .suggestion.focused a{color:#3eaf7c}@media (max-width:959px){.search-box input{cursor:pointer;width:0;border-color:transparent;position:relative}.search-box input:focus{cursor:text;left:0;width:10rem}}@media (-ms-high-contrast:none){.search-box input{height:2rem}}@media (max-width:959px) and (min-width:719px){.search-box .suggestions{left:0}}@media (max-width:719px){.search-box{margin-right:0}.search-box input{left:1rem}.search-box .suggestions{right:0}}@media (max-width:419px){.search-box .suggestions{width:calc(100vw - 4rem)}.search-box input:focus{width:8rem}}.sidebar-button{cursor:pointer;display:none;width:1.25rem;height:1.25rem;position:absolute;padding:.6rem;top:.6rem;left:1rem}.sidebar-button .icon{display:block;width:1.25rem;height:1.25rem}@media (max-width:719px){.sidebar-button{display:block}}.dropdown-enter,.dropdown-leave-to{height:0!important}.dropdown-wrapper{cursor:pointer}.dropdown-wrapper .dropdown-title,.dropdown-wrapper .mobile-dropdown-title{display:block;font-size:.9rem;font-family:inherit;cursor:inherit;padding:inherit;line-height:1.4rem;background:transparent;border:none;font-weight:500;color:#2c3e50}.dropdown-wrapper .dropdown-title:hover,.dropdown-wrapper .mobile-dropdown-title:hover{border-color:transparent}.dropdown-wrapper .dropdown-title .arrow,.dropdown-wrapper .mobile-dropdown-title .arrow{vertical-align:middle;margin-top:-1px;margin-left:.4rem}.dropdown-wrapper .mobile-dropdown-title{display:none;font-weight:600}.dropdown-wrapper .mobile-dropdown-title font-size inherit:hover{color:#3eaf7c}.dropdown-wrapper .nav-dropdown .dropdown-item{color:inherit;line-height:1.7rem}.dropdown-wrapper .nav-dropdown .dropdown-item h4{margin:.45rem 0 0;border-top:1px solid #eee;padding:1rem 1.5rem .45rem 1.25rem}.dropdown-wrapper .nav-dropdown .dropdown-item .dropdown-subitem-wrapper{padding:0;list-style:none}.dropdown-wrapper .nav-dropdown .dropdown-item .dropdown-subitem-wrapper .dropdown-subitem{font-size:.9em}.dropdown-wrapper .nav-dropdown .dropdown-item a{display:block;line-height:1.7rem;position:relative;border-bottom:none;font-weight:400;margin-bottom:0;padding:0 1.5rem 0 1.25rem}.dropdown-wrapper .nav-dropdown .dropdown-item a.router-link-active,.dropdown-wrapper .nav-dropdown .dropdown-item a:hover{color:#3eaf7c}.dropdown-wrapper .nav-dropdown .dropdown-item a.router-link-active:after{content:"";width:0;height:0;border-left:5px solid #3eaf7c;border-top:3px solid transparent;border-bottom:3px solid transparent;position:absolute;top:calc(50% - 2px);left:9px}.dropdown-wrapper .nav-dropdown .dropdown-item:first-child h4{margin-top:0;padding-top:0;border-top:0}@media (max-width:719px){.dropdown-wrapper.open .dropdown-title{margin-bottom:.5rem}.dropdown-wrapper .dropdown-title{display:none}.dropdown-wrapper .mobile-dropdown-title{display:block}.dropdown-wrapper .nav-dropdown{transition:height .1s ease-out;overflow:hidden}.dropdown-wrapper .nav-dropdown .dropdown-item h4{border-top:0;margin-top:0;padding-top:0}.dropdown-wrapper .nav-dropdown .dropdown-item>a,.dropdown-wrapper .nav-dropdown .dropdown-item h4{font-size:15px;line-height:2rem}.dropdown-wrapper .nav-dropdown .dropdown-item .dropdown-subitem{font-size:14px;padding-left:1rem}}@media (min-width:719px){.dropdown-wrapper{height:1.8rem}.dropdown-wrapper.open .nav-dropdown,.dropdown-wrapper:hover .nav-dropdown{display:block!important}.dropdown-wrapper.open:blur{display:none}.dropdown-wrapper .nav-dropdown{display:none;height:auto!important;box-sizing:border-box;max-height:calc(100vh - 2.7rem);overflow-y:auto;position:absolute;top:100%;right:0;background-color:#fff;padding:.6rem 0;border:1px solid;border-color:#ddd #ddd #ccc;text-align:left;border-radius:.25rem;white-space:nowrap;margin:0}}.nav-links{display:inline-block}.nav-links a{line-height:1.4rem;color:inherit}.nav-links a.router-link-active,.nav-links a:hover{color:#3eaf7c}.nav-links .nav-item{position:relative;display:inline-block;margin-left:1.5rem;line-height:2rem}.nav-links .nav-item:first-child{margin-left:0}.nav-links .repo-link{margin-left:1.5rem}@media (max-width:719px){.nav-links .nav-item,.nav-links .repo-link{margin-left:0}}@media (min-width:719px){.nav-links a.router-link-active,.nav-links a:hover{color:#2c3e50}.nav-item>a:not(.external).router-link-active,.nav-item>a:not(.external):hover{margin-bottom:-2px;border-bottom:2px solid #46bd87}}.navbar{padding:.7rem 1.5rem;line-height:2.2rem}.navbar a,.navbar img,.navbar span{display:inline-block}.navbar .logo{height:2.2rem;min-width:2.2rem;margin-right:.8rem;vertical-align:top}.navbar .site-name{font-size:1.3rem;font-weight:600;color:#2c3e50;position:relative}.navbar .links{padding-left:1.5rem;box-sizing:border-box;background-color:#fff;white-space:nowrap;font-size:.9rem;position:absolute;right:1.5rem;top:.7rem;display:flex}.navbar .links .search-box{flex:0 0 auto;vertical-align:top}@media (max-width:719px){.navbar{padding-left:4rem}.navbar .can-hide{display:none}.navbar .links{padding-left:1.5rem}.navbar .site-name{width:calc(100vw - 9.4rem);overflow:hidden;white-space:nowrap;text-overflow:ellipsis}}.page-edit{max-width:740px;margin:0 auto;padding:2rem 2.5rem}@media (max-width:959px){.page-edit{padding:2rem}}@media (max-width:419px){.page-edit{padding:1.5rem}}.page-edit{padding-top:1rem;padding-bottom:1rem;overflow:auto}.page-edit .edit-link{display:inline-block}.page-edit .edit-link a{color:#4e6e8e;margin-right:.25rem}.page-edit .last-updated{float:right;font-size:.9em}.page-edit .last-updated .prefix{font-weight:500;color:#4e6e8e}.page-edit .last-updated .time{font-weight:400;color:#767676}@media (max-width:719px){.page-edit .edit-link{margin-bottom:.5rem}.page-edit .last-updated{font-size:.8em;float:none;text-align:left}}.page-nav{max-width:740px;margin:0 auto;padding:2rem 2.5rem}@media (max-width:959px){.page-nav{padding:2rem}}@media (max-width:419px){.page-nav{padding:1.5rem}}.page-nav{padding-top:1rem;padding-bottom:0}.page-nav .inner{min-height:2rem;margin-top:0;border-top:1px solid #eaecef;padding-top:1rem;overflow:auto}.page-nav .next{float:right}.page{padding-bottom:2rem;display:block}.sidebar-group .sidebar-group{padding-left:.5em}.sidebar-group:not(.collapsable) .sidebar-heading:not(.clickable){cursor:auto;color:inherit}.sidebar-group.is-sub-group{padding-left:0}.sidebar-group.is-sub-group>.sidebar-heading{font-size:.95em;line-height:1.4;font-weight:400;padding-left:2rem}.sidebar-group.is-sub-group>.sidebar-heading:not(.clickable){opacity:.5}.sidebar-group.is-sub-group>.sidebar-group-items{padding-left:1rem}.sidebar-group.is-sub-group>.sidebar-group-items>li>.sidebar-link{font-size:.95em;border-left:none}.sidebar-group.depth-2>.sidebar-heading{border-left:none}.sidebar-heading{color:#2c3e50;transition:color .15s ease;cursor:pointer;font-size:1.1em;font-weight:700;padding:.35rem 1.5rem .35rem 1.25rem;width:100%;box-sizing:border-box;margin:0;border-left:.25rem solid transparent}.sidebar-heading.open,.sidebar-heading:hover{color:inherit}.sidebar-heading .arrow{position:relative;top:-.12em;left:.5em}.sidebar-heading.clickable.active{font-weight:600;color:#3eaf7c;border-left-color:#3eaf7c}.sidebar-heading.clickable:hover{color:#3eaf7c}.sidebar-group-items{transition:height .1s ease-out;font-size:.95em;overflow:hidden}.sidebar .sidebar-sub-headers{padding-left:1rem;font-size:.95em}a.sidebar-link{font-size:1em;font-weight:400;display:inline-block;color:#2c3e50;border-left:.25rem solid transparent;padding:.35rem 1rem .35rem 1.25rem;line-height:1.4;width:100%;box-sizing:border-box}a.sidebar-link:hover{color:#3eaf7c}a.sidebar-link.active{font-weight:600;color:#3eaf7c;border-left-color:#3eaf7c}.sidebar-group a.sidebar-link{padding-left:2rem}.sidebar-sub-headers a.sidebar-link{padding-top:.25rem;padding-bottom:.25rem;border-left:none}.sidebar-sub-headers a.sidebar-link.active{font-weight:500}.sidebar ul{padding:0;margin:0;list-style-type:none}.sidebar a{display:inline-block}.sidebar .nav-links{display:none;border-bottom:1px solid #eaecef;padding:.5rem 0 .75rem}.sidebar .nav-links a{font-weight:600}.sidebar .nav-links .nav-item,.sidebar .nav-links .repo-link{display:block;line-height:1.25rem;font-size:1.1em;padding:.5rem 0 .5rem 1.5rem}.sidebar>.sidebar-links{padding:1.5rem 0}.sidebar>.sidebar-links>li>a.sidebar-link{font-size:1.1em;line-height:1.7;font-weight:700}.sidebar>.sidebar-links>li:not(:first-child){margin-top:.75rem}@media (max-width:719px){.sidebar .nav-links{display:block}.sidebar .nav-links .dropdown-wrapper .nav-dropdown .dropdown-item a.router-link-active:after{top:calc(1rem - 2px)}.sidebar>.sidebar-links{padding:1rem 0}}.badge[data-v-15b7b770]{display:inline-block;font-size:14px;height:18px;line-height:18px;border-radius:3px;padding:0 6px;color:#fff}.badge.green[data-v-15b7b770],.badge.tip[data-v-15b7b770],.badge[data-v-15b7b770]{background-color:#42b983}.badge.error[data-v-15b7b770]{background-color:#da5961}.badge.warn[data-v-15b7b770],.badge.warning[data-v-15b7b770],.badge.yellow[data-v-15b7b770]{background-color:#e7c000}.badge+.badge[data-v-15b7b770]{margin-left:5px}.theme-code-block[data-v-759a7d02]{display:none}.theme-code-block__active[data-v-759a7d02]{display:block}.theme-code-block>pre[data-v-759a7d02]{background-color:orange}.theme-code-group__nav[data-v-deefee04]{margin-bottom:-35px;background-color:#282c34;padding-bottom:22px;border-top-left-radius:6px;border-top-right-radius:6px;padding-left:10px;padding-top:10px}.theme-code-group__ul[data-v-deefee04]{margin:auto 0;padding-left:0;display:inline-flex;list-style:none}.theme-code-group__nav-tab[data-v-deefee04]{border:0;padding:5px;cursor:pointer;background-color:transparent;font-size:.85em;line-height:1.4;color:hsla(0,0%,100%,.9);font-weight:600}.theme-code-group__nav-tab-active[data-v-deefee04]{border-bottom:1px solid #42b983}.pre-blank[data-v-deefee04]{color:#42b983} \ No newline at end of file diff --git a/assets/img/API-gatway.405785fe.svg b/assets/img/API-gatway.405785fe.svg new file mode 100644 index 00000000..745349c9 --- /dev/null +++ b/assets/img/API-gatway.405785fe.svg @@ -0,0 +1,4 @@ + + + +
客户端
客户端
API 网关
API 网关
后端服务1
后端服务1
后端服务3
后端服务3
后端服务2
后端服务2
后端服务4
后端服务4
后端服务5
后端服务5
Text is not SVG - cannot display
\ No newline at end of file diff --git a/assets/img/DNS.98f8385d.svg b/assets/img/DNS.98f8385d.svg new file mode 100644 index 00000000..84cfa486 --- /dev/null +++ b/assets/img/DNS.98f8385d.svg @@ -0,0 +1,4 @@ + + + +
本地缓存
本地缓存
1 查询本地缓存
1 查询本地缓存
根域名服务器
根域名服务器
.com 顶级域名服务器
.com 顶级域名服务器
google.com 权威服务器
google.com 权威服务器
本地域名服务器:8.8.8.8
本地域名服务器:8.8.8.8
查询 mail.google.com
查询 mail.goog...
根域名服务器提供.com 的ip地址
根域名服务器提供.com 的ip地址
.com 服务器提供gogle.om 的ip地址
.com 服务器提供gogle.om 的ip地址
google.com 提供了最终结局 mail.google.com 的ip地址
google.com 提供了最终结局 mail.google.com 的ip地址
2 .查询本地域名服务器
2 .查询本地域名服务器
3.本地域名服务器查询根域名服务器
3.本地域名服务器查询根域名服务器
4. 查询顶级域名服务器
4. 查询顶级域名服务器
5. 查询google.com的权威服务器
5. 查询google.com的权威服务器
6. 本地域名服务器将最终访问的ip地址返回给用户
6. 本地域名服务器将最终访问的ip地址返回给用户
Text is not SVG - cannot display
\ No newline at end of file diff --git a/assets/img/docker.dbe2cc5f.jpg b/assets/img/docker.dbe2cc5f.jpg new file mode 100644 index 00000000..4f032c19 Binary files /dev/null and b/assets/img/docker.dbe2cc5f.jpg differ diff --git a/assets/img/dr.9275d9cb.svg b/assets/img/dr.9275d9cb.svg new file mode 100644 index 00000000..43a7105a --- /dev/null +++ b/assets/img/dr.9275d9cb.svg @@ -0,0 +1,4 @@ + + + +
Actor
Actor
LVS
LVS
公网ip 12.134.1.34
公网ip 12.134.1.34
修改 mac地址
修改 mac地址
虚拟ip:12.134.1.34
虚拟ip:12.134.1.34
虚拟ip:12.134.1.34
虚拟ip:12.134.1.34
虚拟ip:12.134.1.34
虚拟ip:12.134.1.34
Text is not SVG - cannot display
\ No newline at end of file diff --git a/assets/img/ebpf1.1a1bb6f1.png b/assets/img/ebpf1.1a1bb6f1.png new file mode 100644 index 00000000..20343ed4 Binary files /dev/null and b/assets/img/ebpf1.1a1bb6f1.png differ diff --git a/assets/img/full-nat.a5480bf0.svg b/assets/img/full-nat.a5480bf0.svg new file mode 100644 index 00000000..fc6a9c32 --- /dev/null +++ b/assets/img/full-nat.a5480bf0.svg @@ -0,0 +1,4 @@ + + + +
Actor
Actor
lvs
lvs
服务器1
服务器1
服务器2
服务器2
服务器3
服务器3
12.134.33.1
12.134.33.1
1.2.33.1
1.2.33.1
1.2.33.2
1.2.33.2
1.2.33.3
1.2.33.3
修改目标ip,并且修改源ip
修改目标ip,并且修改源ip
请求
请求
响应
响应
Text is not SVG - cannot display
\ No newline at end of file diff --git a/assets/img/lvs-cluster.e1267fa7.svg b/assets/img/lvs-cluster.e1267fa7.svg new file mode 100644 index 00000000..b6298e46 --- /dev/null +++ b/assets/img/lvs-cluster.e1267fa7.svg @@ -0,0 +1,4 @@ + + + +
Actor
Actor
lvs1 master
lvs1 m...
lvs1
备份
lvs1...
通过 keepalive 软件作为主备方案,来互斥共享一个公网虚拟 ip
通过 keepalive 软件作为主备方案,来互斥共享一个公网虚拟 ip
lvs1 :11.12.2.1
lvs1 :11.12.2.1
lvs2 master
lvs2 m...
lvs2
备份
lvs2...
通过 keepalive 软件作为主备方案,来互斥共享一个公网虚拟 ip
通过 keepalive 软件作为主备方案,来互斥共享一个公网虚拟 ip
lvs2:3.89.2.1
lvs2:3.89.2.1
这里的ip地址是公网ip,但是也是动态设置的,所以也是属于虚拟ip,所谓虚拟ip就是动态可设置的,不是写死的那种ip
这里的ip地址是公网ip,但是也是动态设置的,所以也是属于虚拟ip,所谓虚拟ip就是动态可设置的,不是写死的那种ip
DNS
DNS
11.12.2.1
11.12.2.1
3.89.2.1
3.89.2.1
使用这种互相交叉的转发方法可以互为备份
使用这种互相交叉的转发方法可以互为备份
服务1
服务1
服务2
服务2
服务3
服务3
使用这种互相交叉的访问方法,避免出现单点
使用这种互相交叉的访问方法,避免出现单点
主-主备份方案
主-主备份方案
主主备份方案中,对于部分组件的高可用没有特别高的要求,就是它死了,对系统整体影响没那么大,然后主备方案中,每个组件都不能死
主主备份方案中,对于部分组件的高可用没有特别高的要求,就是它死了,对系统整体影响没那么大,然后主备方案中,每个组件都不能死
Text is not SVG - cannot display
\ No newline at end of file diff --git a/assets/img/nat.8c0b59b4.svg b/assets/img/nat.8c0b59b4.svg new file mode 100644 index 00000000..47479845 --- /dev/null +++ b/assets/img/nat.8c0b59b4.svg @@ -0,0 +1,4 @@ + + + +
Actor
Actor
lvs
lvs
服务器1
服务器1
服务器2
服务器2
服务器3
服务器3
12.134.33.1
12.134.33.1
1.2.33.1
1.2.33.1
1.2.33.2
1.2.33.2
1.2.33.3
1.2.33.3
修改目标ip
修改目标ip
请求
请求
修改源ip
修改源ip
响应
响应
Text is not SVG - cannot display
\ No newline at end of file diff --git a/assets/img/nginx-hot-update.83988ad2.svg b/assets/img/nginx-hot-update.83988ad2.svg new file mode 100644 index 00000000..4def8afc --- /dev/null +++ b/assets/img/nginx-hot-update.83988ad2.svg @@ -0,0 +1,4 @@ + + + +
nginx
nginx
热更新器
热更新器
注册中心
注册中心
周期性拉取注册中心的配置新内容
周期性拉取注册中心的配置新内容
将数据使用 lua 脚本写入到 nginx 中
将数据使用 lua 脚本写入到 nginx 中
Text is not SVG - cannot display
\ No newline at end of file diff --git a/assets/img/nginx-proxy.d43eb7ba.svg b/assets/img/nginx-proxy.d43eb7ba.svg new file mode 100644 index 00000000..8b0b1384 --- /dev/null +++ b/assets/img/nginx-proxy.d43eb7ba.svg @@ -0,0 +1,4 @@ + + + +
nginx

1.1.1.0
nginx...
用户
用户
1.1.1.0/get0
1.1.1.0/ge...
1.1.1.0/get1
1.1.1.0/ge...
1.1.1.0/get2
1.1.1.0/ge...
1.1.1.1/get0
1.1.1.1/ge...
1.1.1.2/get0
1.1.1.2/ge...
1.1.1.3/get1
1.1.1.3/ge...
1.1.1.1.4/get1
1.1.1.1.4/...
1.1.1.5/get2
1.1.1.5/ge...
1.1.1.6/get2
1.1.1.6/ge...
用户访问 1.1.1.0路径下的 get0 get1 get2 的过程 
用户访问 1.1.1.0路径下的 get0 get1 get2 的过程 
Text is not SVG - cannot display
\ No newline at end of file diff --git a/assets/img/sdn.9ecec920.svg b/assets/img/sdn.9ecec920.svg new file mode 100644 index 00000000..f0b110e8 --- /dev/null +++ b/assets/img/sdn.9ecec920.svg @@ -0,0 +1,4 @@ + + + +
Actor
Actor
物理高性能路由器1
物理高性能路由器1
物理高性能路由器2
物理高性能路由器2
DNS
DNS
ip:1.32.4.4
ip:1.32.4.4
ip:2.53.55.1
ip:2.53.55.1
j靠
j靠
叫花鸡
叫花鸡
交换机1
交换机1
交换机2
交换机2
lvs集群1
lvs集群1
lvs集群2
lvs集群2
双网卡链路聚合
双网卡链路聚合
lvs集群
lvs集群
网卡1
网卡1
网卡2
网卡2
lvs服务器还可以部署双网卡,四端口的模式,通过双网卡聚合(相同ip,不同mac地址)可以理论上提高吞吐量的一倍,通过单网卡双端口,可以让两个交换机分别连接,主主备份
lvs服务器还可以部署双网卡,四端口的模式,通过双网卡聚合(相同ip,不同mac地址)可以理论上提高吞吐量的一倍,通过单网卡双端口,可以让两个交换机分别连接,主主备份
Text is not SVG - cannot display
\ No newline at end of file diff --git a/assets/img/search.83621669.svg b/assets/img/search.83621669.svg new file mode 100644 index 00000000..03d83913 --- /dev/null +++ b/assets/img/search.83621669.svg @@ -0,0 +1 @@ + diff --git a/assets/img/tun.11ae16cc.svg b/assets/img/tun.11ae16cc.svg new file mode 100644 index 00000000..4376c4cf --- /dev/null +++ b/assets/img/tun.11ae16cc.svg @@ -0,0 +1,4 @@ + + + +
Actor
Actor
LVS
LVS
公网ip 12.134.1.34
公网ip 12.134.1.34
ip 隧穿
ip 隧穿
虚拟ip:12.134.1.34
虚拟ip:12.134.1.34
虚拟ip:12.134.1.34
虚拟ip:12.134.1.34
虚拟ip:12.134.1.34
虚拟ip:12.134.1.34
Text is not SVG - cannot display
\ No newline at end of file diff --git a/assets/img/wechat.4a3030a4.png b/assets/img/wechat.4a3030a4.png new file mode 100644 index 00000000..81b494be Binary files /dev/null and b/assets/img/wechat.4a3030a4.png differ diff --git a/assets/js/10.4e08f7dd.js b/assets/js/10.4e08f7dd.js new file mode 100644 index 00000000..0cda93f5 --- /dev/null +++ b/assets/js/10.4e08f7dd.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[10],{428:function(e,o,t){e.exports=t.p+"assets/img/docker.dbe2cc5f.jpg"},452:function(e,o,t){"use strict";t.r(o);var r=t(36),c=Object(r.a)({},(function(){var e=this,o=e.$createElement,r=e._self._c||o;return r("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[r("h1",{attrs:{id:"docker-的基本概念"}},[e._v("docker 的基本概念")]),e._v(" "),r("p",[e._v("docker 项目的基本架构\n"),r("img",{attrs:{src:t(428),alt:""}})]),e._v(" "),r("p",[e._v("从图中我们知道,我们平时操控的 docker 只是 docker 的 client 部分,然后由 client 向 docker 的后台 docker daemon 发送命令,真正控制的是 docker daemon,这这种架构是我们常见的客户端/服务器 (cs) 架构,这样的架构可以最大限度的去保护系统的核心部位。")]),e._v(" "),r("p",[e._v("下面是 docker 的整体运作模式")]),e._v(" "),r("ol",[r("li",[e._v("用户使用 docker client 去向 docker daemon 请求命令")]),e._v(" "),r("li",[e._v("docker daemon 从远程服务器 Registry 获取镜像")]),e._v(" "),r("li",[e._v("docker daemon 将镜像下载到本地以后,生成并管理容器")])])])}),[],!1,null,null,null);o.default=c.exports}}]); \ No newline at end of file diff --git a/assets/js/11.854eb640.js b/assets/js/11.854eb640.js new file mode 100644 index 00000000..d425d9a3 --- /dev/null +++ b/assets/js/11.854eb640.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[11],{429:function(v,_,t){v.exports=t.p+"assets/img/API-gatway.405785fe.svg"},484:function(v,_,t){"use strict";t.r(_);var s=t(36),r=Object(s.a)({},(function(){var v=this,_=v.$createElement,s=v._self._c||_;return s("ContentSlotsDistributor",{attrs:{"slot-key":v.$parent.slotKey}},[s("h1",{attrs:{id:"api-网关-应用网关"}},[v._v("API 网关 (应用网关)")]),v._v(" "),s("p",[v._v("API 网关是所有请求的入口,它接收了所有的 http https tcp 的请求,并将请求转发给后面真正的服务,微服务模式下,这些服务一般都是一些容器,或者也可能是各个数据中心的各自的 API 网关,总而言之,API 网关是一切请求的入口处理工具,它工作相对较少,所以性能非常的高")]),v._v(" "),s("p",[v._v("API 网关通常被部署在后端服务的最前端,来充当安全保护,熔断,限流,等作用,"),s("strong",[v._v("nginx 就是一个简单化的 api 网关")]),v._v(",不过常见的 api 网关并不是 nginx,比较常见的有 "),s("strong",[v._v("kong")]),v._v(","),s("strong",[v._v("bfe")]),v._v(" 等")]),v._v(" "),s("h2",{attrs:{id:"api-网关的作用"}},[v._v("API 网关的作用")]),v._v(" "),s("ul",[s("li",[s("p",[s("strong",[v._v("解耦后端架构")]),v._v(":或者说灵活配置后端架构,它将需求和真实处理的服务解耦,可以构建更加灵活多样的后端架构 (BaaS)")])]),v._v(" "),s("li",[s("p",[s("strong",[v._v("减少 TLS 协议的使用")]),v._v(",TLS 协议加上 http 组成了 https,但是要知道 https 因为多了一层协议,所以势必比单纯的 http 慢,而且 tls 证书也是要花钱的,如果我们配置了 API 网关只需要在最前端部署 tls 协议即可,BaaS 中的服务都可以使用 RPC 协议或者一般的 http 协议")])]),v._v(" "),s("li",[s("p",[s("strong",[v._v("API 网关增加安全性")]),v._v(",可以对入口流量做鉴权,限流,降级,黑名单,白名单等措施,与此同时,后端的服务也仅仅可以放开对于 API 网关的 ip 访问,从而避免了各种安全风险")])]),v._v(" "),s("li",[s("p",[s("strong",[v._v("API 网关减少了运维的难度")]),v._v(",所有流量都经过 API 网关,可以做日志记录,监控,统计,这些行为都变得更加简单")])]),v._v(" "),s("li",[s("p",[s("strong",[v._v("API 网关可以对流量进行统一更改")]),v._v(",比如对于流量进行 gzip 压缩;可以一次性升级所有服务的协议,它只要升级为 http2 或者 3 这种新的协议,对外的服务就相当于升级了所有服务的协议,因为你入口升级了嘛,后端是什么协议都无所谓了,反正暴漏给客户端的协议是升级了;还可以对数据进行格式的转换,例如 xml 转换为 json 等")])])]),v._v(" "),s("p",[s("img",{attrs:{src:t(429),alt:"API 网关"}})]),v._v(" "),s("h2",{attrs:{id:"注册中心和服务发现"}},[v._v("注册中心和服务发现")]),v._v(" "),s("p",[v._v("服务发现是微服务架构中的一个关键环节,用于帮助各个服务能够互相定位并进行通信。以下是它的原理:")]),v._v(" "),s("h3",{attrs:{id:"服务注册"}},[v._v("服务注册")]),v._v(" "),s("p",[s("em",[s("strong",[v._v("服务信息收集")])])]),v._v(" "),s("p",[v._v("当一个服务启动时,它首先会"),s("strong",[v._v("收集自身的相关信息")]),v._v("。这些信息包括服务的名称、IP 地址、端口号、服务协议 (如 HTTP、gRPC 等)、服务版本等。例如,一个名为 “user - service” 的微服务,它的 IP 地址可能是 192.168.1.100,端口号是 8080,使用 HTTP 协议,版本是 v1.0。")]),v._v(" "),s("p",[s("em",[s("strong",[v._v("注册中心通信")])])]),v._v(" "),s("p",[v._v("服务会将收集到的这些信息发送给一个服务注册中心。"),s("strong",[v._v("服务注册中心是一个存储所有服务信息的地方")]),v._v(",常见的注册中心有 Consul、Eureka、Zookeeper 等。\n以 Eureka 为例,服务通过 RESTful API 与 Eureka Server 进行通信。服务发送一个包含自身信息的注册请求,Eureka Server 收到请求后,会将服务信息存储在其内部的注册表中。"),s("strong",[v._v("这个注册表是一个数据结构,通常是一个键值对的集合,键是服务名称,值是服务的详细信息列表。")])]),v._v(" "),s("h3",{attrs:{id:"服务发现过程"}},[v._v("服务发现过程")]),v._v(" "),s("p",[s("em",[s("strong",[v._v("客户端请求发现服务")])])]),v._v(" "),s("p",[v._v("当一个服务需要调用另一个服务时,它首先会"),s("strong",[v._v("向服务发现组件发送一个发现请求")]),v._v("。例如,一个订单服务需要调用用户服务来获取用户信息,订单服务就会发起服务发现请求。")]),v._v(" "),s("p",[s("em",[s("strong",[v._v("发现组件查询注册中心")])])]),v._v(" "),s("p",[v._v("服务发现组件收到请求后,会"),s("strong",[v._v("查询服务注册中心")]),v._v("。它会根据目标服务的名称在注册中心的注册表中查找对应的服务信息。\n假设使用 Consul 作为注册中心,服务发现组件会向 Consul 发送一个 HTTP GET 请求,请求的路径可能是类似 “/v1/catalog/service/user - service”,Consul 会返回用户服务的 IP 地址、端口号等信息。")]),v._v(" "),s("p",[s("em",[s("strong",[v._v("缓存机制")])])]),v._v(" "),s("p",[v._v("为了提高性能,很多服务发现系统会使用缓存。服务发现组件在获取服务信息后,会将信息缓存起来。这样,在一定时间内 (缓存有效期内),如果有相同的服务发现请求,就可以直接从缓存中获取信息,而不需要再次查询注册中心。")]),v._v(" "),s("p",[v._v("例如,一个缓存的有效期设置为 30 秒,在这 30 秒内,所有对某个服务的发现请求都可以直接使用缓存中的 IP 地址和端口号,减少了与注册中心的交互次数,提高了效率。")]),v._v(" "),s("p",[s("em",[s("strong",[v._v("返回服务信息给客户端")])])]),v._v(" "),s("p",[v._v("服务发现组件将从注册中心 (或者缓存) 获取的目标服务信息返回给客户端。客户端得到目标服务的 IP 地址和端口号后,就可以根据这些信息建立与目标服务的连接,并发起服务调用。例如,订单服务得到用户服务的 IP 地址和端口号后,就可以使用 HTTP 协议向用户服务发送请求,获取用户的详细信息。")]),v._v(" "),s("p",[s("em",[s("strong",[v._v("服务信息更新与同步")])])]),v._v(" "),s("p",[s("strong",[v._v("注册中心会定期检查服务的健康状态")]),v._v("。如果一个服务因为故障或者网络问题等不可用了,注册中心会将其标记为不可用状态,并且在服务发现时不会返回这个不可用服务的信息。\n同时,当服务的信息 (如 IP 地址因为重新部署而改变、服务版本升级等) 发生变化时,"),s("strong",[v._v("服务会主动向注册中心发送更新请求")]),v._v("。注册中心会更新注册表中的信息,并且通过合适的机制 (如推送通知或者客户端定期查询) "),s("strong",[v._v("将更新后的信息同步给服务发现组件")]),v._v(",以确保服务发现的信息始终是准确的。")]),v._v(" "),s("h3",{attrs:{id:"服务发现组件是怎么知道要调用哪个服务的呢"}},[v._v("服务发现组件是怎么知道要调用哪个服务的呢?")]),v._v(" "),s("p",[v._v("服务发现组件知道要调用哪个服务是由程序员通过服务名称的指定、配置文件设置或者编程接口使用等方式来"),s("strong",[v._v("主动控制的")])]),v._v(" "),s("p",[v._v("当新的服务组件注册到注册中心时,如果注册中心具有推送功能,它会尝试向已注册的服务发现推送更新信息。")])])}),[],!1,null,null,null);_.default=r.exports}}]); \ No newline at end of file diff --git a/assets/js/12.a2dbe4af.js b/assets/js/12.a2dbe4af.js new file mode 100644 index 00000000..4aca655e --- /dev/null +++ b/assets/js/12.a2dbe4af.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[12],{430:function(t,s,a){t.exports=a.p+"assets/img/DNS.98f8385d.svg"},486:function(t,s,a){"use strict";a.r(s);var n=a(36),v=Object(n.a)({},(function(){var t=this,s=t.$createElement,n=t._self._c||s;return n("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[n("h1",{attrs:{id:"dns-域名协议服务"}},[t._v("DNS 域名协议服务")]),t._v(" "),n("p",[t._v("dns 是域名解析协议,它负责将域名解析为具体的 ip 地址,例如 www.example.com 解析为 11.32.33.433")]),t._v(" "),n("h2",{attrs:{id:"dns-的多级寻找机制"}},[t._v("DNS 的多级寻找机制")]),t._v(" "),n("p",[t._v("dns 系统拥有本地缓存,所以它会优先查询本地缓存,这也是我们所谓的 “更改 hosts 就能访问 xx 网站” 的实现原理,因为 "),n("code",[t._v("hosts")]),t._v(" 中保存的就是域名对应的 ip 地址,当本地缓存中存在 URL 对应的 ip 地址时,就不会去请求本地域名服务器,直接返回具体的 ip 即可,当本地缓存失效之后,系统就会委托本地域名服务器 (本地 DNS --- Local DNS,比如谷歌的 8.8.8.8,阿里的 114.114.114.114 等等) 按照域名的层级来查询")]),t._v(" "),n("blockquote",[n("p",[t._v("hosts 不是本地缓存,系统会查询 hosts 然后再去查询本地缓存,不过 hosts 的优先级大于本地缓存,hosts 存在于 Linux 的 /etc/hosts Windows 的 C:\\Windows\\System32\\drivers\\etc\\hosts 中 macOS 的 /etc/hosts 中")])]),t._v(" "),n("p",[t._v("DNS 缓存存在于浏览器和操作系统中,hosts 也会存在一定的记录,其中优先级是 hosts 最高,浏览器缓存次之,操作系统缓存最低")]),t._v(" "),n("p",[t._v("在上述的描述中,当本地无缓存目标 URL 对应的 ip 时,通常会去使用本地域名服务商去查询,比如谷歌的 8.8.8.8,如果本地域名服务商有 URL 的缓存,返回数据即可,那么,如果本地域名服务商也没有数据,它会替代用户去不断的去请求更高一级的域名服务器,从 com 这个根域名服务器为开始,就开始查询不同层级域名的 ip 地址")]),t._v(" "),n("p",[n("strong",[t._v("这是一个域名解析的步骤图")])]),t._v(" "),n("p",[n("img",{attrs:{src:a(430),alt:"dns"}})]),t._v(" "),n("p",[t._v("需要说明的是,权威服务器返回的不一定就是 ip 地址,也可以有很多"),n("a",{attrs:{href:"https://zh.wikipedia.org/wiki/DNS%E8%AE%B0%E5%BD%95%E7%B1%BB%E5%9E%8B%E5%88%97%E8%A1%A8",target:"_blank",rel:"noopener noreferrer"}},[t._v("类型"),n("OutboundLink")],1)]),t._v(" "),n("p",[n("strong",[t._v("这是一个 dns 记录的例子")])]),t._v(" "),n("table",[n("thead",[n("tr",[n("th",[t._v("Domin(域名)")]),t._v(" "),n("th",[t._v("TTL(生存周期)")]),t._v(" "),n("th",[t._v("Class(协议类型)")]),t._v(" "),n("th",[t._v("Type(记录类型)")]),t._v(" "),n("th",[t._v("Rdata(记录数据)")])])]),t._v(" "),n("tbody",[n("tr",[n("td",[t._v("www.example.com")]),t._v(" "),n("td",[t._v("86400")]),t._v(" "),n("td",[t._v("IN")]),t._v(" "),n("td",[t._v("A")]),t._v(" "),n("td",[t._v("2.2.2.2")])])])]),t._v(" "),n("h2",{attrs:{id:"dns-本地缓存及其优先级"}},[t._v("DNS 本地缓存及其优先级")]),t._v(" "),n("p",[t._v("在 DNS 缓存系统中,一般的查询的优先级顺序一般如下:")]),t._v(" "),n("ol",[n("li",[n("p",[t._v("Hosts 文件:这是最优先的,任何在/etc/hosts 文件中定义的条目都会被直接使用,而不会发送 DNS 请求。")])]),t._v(" "),n("li",[n("p",[t._v("操作系统 DNS 缓存:如果 hosts 文件中没有相应的条目,操作系统会检查其自身的 DNS 缓存。在 macOS 中,这个缓存是由系统服务管理的,对于所有应用程序都是透明的。")])]),t._v(" "),n("li",[n("p",[t._v("浏览器 DNS 缓存:如果操作系统缓存中没有找到相应的记录,浏览器才会检查其自身的 DNS 缓存。浏览器缓存是特定于该浏览器进程的,并且在浏览器关闭后可能会被清除")])])]),t._v(" "),n("p",[t._v("为什么请求发生在浏览器,但是浏览器的缓存优先级不是最高的呢?:")]),t._v(" "),n("p",[t._v("浏览器缓存的优先级通常不会高于操作系统的 DNS 缓存或 hosts 文件中的条目。这是因为 DNS 解析是一个系统层面的操作,它发生在浏览器向 DNS 服务器发起请求之前。")]),t._v(" "),n("h2",{attrs:{id:"dns-预留技术"}},[t._v("DNS 预留技术")]),t._v(" "),n("div",{staticClass:"language-html extra-class"},[n("pre",{pre:!0,attrs:{class:"language-html"}},[n("code",[n("span",{pre:!0,attrs:{class:"token tag"}},[n("span",{pre:!0,attrs:{class:"token tag"}},[n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("link")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token attr-name"}},[t._v("rel")]),n("span",{pre:!0,attrs:{class:"token attr-value"}},[n("span",{pre:!0,attrs:{class:"token punctuation attr-equals"}},[t._v("=")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v('"')]),t._v("dns-prefetch"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v('"')])]),t._v(" "),n("span",{pre:!0,attrs:{class:"token attr-name"}},[t._v("href")]),n("span",{pre:!0,attrs:{class:"token attr-value"}},[n("span",{pre:!0,attrs:{class:"token punctuation attr-equals"}},[t._v("=")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v('"')]),t._v("//mail.example.com"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v('"')])]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v("\n")])])]),n("p",[t._v("dns 预留技术,通过在前端设置标签的方法,让浏览器提前对"),n("strong",[t._v("其他")]),t._v("所需的域名进行预解析,从而减少请求时间")]),t._v(" "),n("h2",{attrs:{id:"dns-的作用"}},[t._v("DNS 的作用")]),t._v(" "),n("p",[t._v("dns 其实就是用户和真实 ip 之间的桥梁,用户使用域名通过 dns 来访问网站。")]),t._v(" "),n("p",[t._v("我们在部署 dns 的时候,可以部署多个入口 ip,这样当某个 ip 挂了,其他 ip 可以继续提供服务,从而保证了服务的可用性,并且实现了负载均衡的功能,如果我们突然要更换 ip,那么就可以通过 dns 服务内部更换 ip 对客户完全无感")]),t._v(" "),n("h2",{attrs:{id:"dns-的安全性"}},[t._v("DNS 的安全性")]),t._v(" "),n("p",[t._v("最后,我们要知道,dns 服务通过多级缓存是,多级访问是有效的减少了不同层级的服务器的压力,但是同时也增加了被中间攻击的比例,分了多少层就会被攻击多少次,记不记得你浏览某个网站的时候你使用宽带上网和手机无线上网获取到的网页不一致的情况,就是因为被 dns 劫持了,某个正确 ip 被换成了广告 ip,广告 ip 将正常的网页 download 下来,然后加入广告发给你 (本来要去喝雪碧呢,tmd 饭店老板把雪碧买回来兑进去了好多白开水)")]),t._v(" "),n("p",[t._v("最近出现的 HTTP DNS 服务将原来的多级缓存多级查询的 DNS 服务给改成了基于一个 https 协议的查询服务器,一次性查询到 ip 地址,虽然增加了服务器开销和容积,但是确实减少了中间商,"),n("RouterLink",{attrs:{to:"/系统设计基础/网络在系统设计中的作用/HTTPDNS/"}},[t._v("下一节")]),t._v("我们重点谈谈 HTTP DNS 服务")],1)])}),[],!1,null,null,null);s.default=v.exports}}]); \ No newline at end of file diff --git a/assets/js/13.abbf4d52.js b/assets/js/13.abbf4d52.js new file mode 100644 index 00000000..8304bac1 --- /dev/null +++ b/assets/js/13.abbf4d52.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[13],{443:function(t,e,s){"use strict";s.r(e);var n=["There's nothing here.","How did we get here?","That's a Four-Oh-Four.","Looks like we've got some broken links."],o={methods:{getMsg:function(){return n[Math.floor(Math.random()*n.length)]}}},i=s(36),h=Object(i.a)(o,(function(){var t=this.$createElement,e=this._self._c||t;return e("div",{staticClass:"theme-container"},[e("div",{staticClass:"theme-default-content"},[e("h1",[this._v("404")]),this._v(" "),e("blockquote",[this._v(this._s(this.getMsg()))]),this._v(" "),e("RouterLink",{attrs:{to:"/"}},[this._v("\n Take me home.\n ")])],1)])}),[],!1,null,null,null);e.default=h.exports}}]); \ No newline at end of file diff --git a/assets/js/14.78fed171.js b/assets/js/14.78fed171.js new file mode 100644 index 00000000..a5563fd7 --- /dev/null +++ b/assets/js/14.78fed171.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[14],{447:function(t,e,n){"use strict";n.r(e);var s=n(36),l=Object(s.a)({},(function(){var t=this.$createElement;return(this._self._c||t)("ContentSlotsDistributor",{attrs:{"slot-key":this.$parent.slotKey}})}),[],!1,null,null,null);e.default=l.exports}}]); \ No newline at end of file diff --git a/assets/js/15.91a20535.js b/assets/js/15.91a20535.js new file mode 100644 index 00000000..4160a86c --- /dev/null +++ b/assets/js/15.91a20535.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[15],{450:function(t,s,i){"use strict";i.r(s);var r=i(36),v=Object(r.a)({},(function(){var t=this,s=t.$createElement,i=t._self._c||s;return i("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[i("h1",{attrs:{id:"云原生"}},[t._v("云原生")]),t._v(" "),i("h2",{attrs:{id:"微服务基础"}},[t._v("微服务基础")]),t._v(" "),i("h2",{attrs:{id:"容器技术基础知识"}},[t._v("容器技术基础知识")]),t._v(" "),i("h2",{attrs:{id:"docker"}},[t._v("docker")]),t._v(" "),i("h2",{attrs:{id:"k8s"}},[t._v("k8s")]),t._v(" "),i("h2",{attrs:{id:"istio"}},[t._v("istio")]),t._v(" "),i("h2",{attrs:{id:"dapr"}},[t._v("dapr")]),t._v(" "),i("h2",{attrs:{id:"knative"}},[t._v("knative")]),t._v(" "),i("h2",{attrs:{id:"参考资料"}},[t._v("参考资料")]),t._v(" "),i("ul",[i("li",[t._v("https://mp.weixin.qq.com/s/TNUn0lXyqvaLByX4E5R9WQ")])])])}),[],!1,null,null,null);s.default=v.exports}}]); \ No newline at end of file diff --git a/assets/js/16.4afe5806.js b/assets/js/16.4afe5806.js new file mode 100644 index 00000000..1bda61da --- /dev/null +++ b/assets/js/16.4afe5806.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[16],{449:function(t,s,e){"use strict";e.r(s);var n=e(36),i=Object(n.a)({},(function(){var t=this,s=t.$createElement,e=t._self._c||s;return e("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[e("h1",{attrs:{id:"dapr"}},[t._v("dapr")]),t._v(" "),e("h2",{attrs:{id:"参考资料"}},[t._v("参考资料")]),t._v(" "),e("ul",[e("li",[t._v("https://time.geekbang.org/column/article/253061")]),t._v(" "),e("li",[t._v("https://www.zhihu.com/question/351298264")]),t._v(" "),e("li",[t._v("https://mp.weixin.qq.com/s/vmP5k--a-n4cYMJlYdsRbA")]),t._v(" "),e("li",[t._v("https://docs.dapr.io/zh-hans/")])])])}),[],!1,null,null,null);s.default=i.exports}}]); \ No newline at end of file diff --git a/assets/js/17.1c5be6f8.js b/assets/js/17.1c5be6f8.js new file mode 100644 index 00000000..9f8f76fa --- /dev/null +++ b/assets/js/17.1c5be6f8.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[17],{451:function(t,e,s){"use strict";s.r(e);var n=s(36),r=Object(n.a)({},(function(){var t=this.$createElement,e=this._self._c||t;return e("ContentSlotsDistributor",{attrs:{"slot-key":this.$parent.slotKey}},[e("h1",{attrs:{id:"docker"}},[this._v("docker")])])}),[],!1,null,null,null);e.default=r.exports}}]); \ No newline at end of file diff --git a/assets/js/18.6b65197a.js b/assets/js/18.6b65197a.js new file mode 100644 index 00000000..5406d386 --- /dev/null +++ b/assets/js/18.6b65197a.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[18],{453:function(t,e,n){"use strict";n.r(e);var s=n(36),l=Object(s.a)({},(function(){var t=this.$createElement;return(this._self._c||t)("ContentSlotsDistributor",{attrs:{"slot-key":this.$parent.slotKey}})}),[],!1,null,null,null);e.default=l.exports}}]); \ No newline at end of file diff --git a/assets/js/19.3d1288e2.js b/assets/js/19.3d1288e2.js new file mode 100644 index 00000000..5161ac15 --- /dev/null +++ b/assets/js/19.3d1288e2.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[19],{455:function(t,s,i){"use strict";i.r(s);var e=i(36),n=Object(e.a)({},(function(){var t=this.$createElement,s=this._self._c||t;return s("ContentSlotsDistributor",{attrs:{"slot-key":this.$parent.slotKey}},[s("h1",{attrs:{id:"服务网格"}},[this._v("服务网格")]),this._v(" "),s("h2",{attrs:{id:"服务网格基础"}},[this._v("服务网格基础")]),this._v(" "),s("h2",{attrs:{id:"istio"}},[this._v("istio")])])}),[],!1,null,null,null);s.default=n.exports}}]); \ No newline at end of file diff --git a/assets/js/2.8bbf573c.js b/assets/js/2.8bbf573c.js new file mode 100644 index 00000000..336e95c6 --- /dev/null +++ b/assets/js/2.8bbf573c.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[2],{376:function(t,e,n){"use strict";n.d(e,"d",(function(){return i})),n.d(e,"a",(function(){return a})),n.d(e,"i",(function(){return s})),n.d(e,"f",(function(){return u})),n.d(e,"g",(function(){return l})),n.d(e,"h",(function(){return c})),n.d(e,"b",(function(){return h})),n.d(e,"e",(function(){return p})),n.d(e,"k",(function(){return f})),n.d(e,"l",(function(){return d})),n.d(e,"c",(function(){return v})),n.d(e,"j",(function(){return m}));n(32),n(97),n(377),n(127),n(209),n(206),n(96),n(99),n(10),n(100),n(45),n(130),n(204);var i=/#.*$/,r=/\.(md|html)$/,a=/\/$/,s=/^[a-z]+:/i;function o(t){return decodeURI(t).replace(i,"").replace(r,"")}function u(t){return s.test(t)}function l(t){return/^mailto:/.test(t)}function c(t){return/^tel:/.test(t)}function h(t){if(u(t))return t;var e=t.match(i),n=e?e[0]:"",r=o(t);return a.test(r)?t:r+".html"+n}function p(t,e){var n=decodeURIComponent(t.hash),r=function(t){var e=t.match(i);if(e)return e[0]}(e);return(!r||n===r)&&o(t.path)===o(e)}function f(t,e,n){if(u(e))return{type:"external",path:e};n&&(e=function(t,e,n){var i=t.charAt(0);if("/"===i)return t;if("?"===i||"#"===i)return e+t;var r=e.split("/");n&&r[r.length-1]||r.pop();for(var a=t.replace(/^\//,"").split("/"),s=0;s3&&void 0!==arguments[3]?arguments[3]:1;if("string"==typeof e)return f(n,e,i);if(Array.isArray(e))return Object.assign(f(n,e[0],i),{title:e[1]});var a=e.children||[];return 0===a.length&&e.path?Object.assign(f(n,e.path,i),{title:e.title}):{type:"group",path:e.path,title:e.title,sidebarDepth:e.sidebarDepth,initialOpenGroupIndex:e.initialOpenGroupIndex,children:a.map((function(e){return t(e,n,i,r+1)})),collapsable:!1!==e.collapsable}}(t,r,l)})):[]}return[]}function g(t){var e=v(t.headers||[]);return[{type:"group",collapsable:!1,title:t.title,path:null,children:e.map((function(e){return{type:"auto",title:e.title,basePath:t.path,path:t.path+"#"+e.slug,children:e.children||[]}}))}]}function v(t){var e;return(t=t.map((function(t){return Object.assign({},t)}))).forEach((function(t){2===t.level?e=t:e&&(e.children||(e.children=[])).push(t)})),t.filter((function(t){return 2===t.level}))}function m(t){return Object.assign(t,{type:t.items&&t.items.length?"links":"link"})}},377:function(t,e,n){"use strict";var i=n(6),r=n(137),a=n(11),s=n(69),o=n(15),u=n(25),l=n(46),c=n(138),h=n(139);r("match",(function(t,e,n){return[function(e){var n=u(this),r=null==e?void 0:l(e,t);return r?i(r,e,n):new RegExp(e)[t](o(n))},function(t){var i=a(this),r=o(t),u=n(e,i,r);if(u.done)return u.value;if(!i.global)return h(i,r);var l=i.unicode;i.lastIndex=0;for(var p,f=[],d=0;null!==(p=h(i,r));){var g=o(p[0]);f[d]=g,""===g&&(i.lastIndex=c(r,s(i.lastIndex),l)),d++}return 0===d?null:f}]}))},378:function(t,e,n){},379:function(t,e,n){"use strict";var i=n(1),r=n(207).trim;i({target:"String",proto:!0,forced:n(410)("trim")},{trim:function(){return r(this)}})},380:function(t,e,n){var i=n(7),r=n(0),a=n(2),s=n(101),o=n(133),u=n(20),l=n(47).f,c=n(33),h=n(135),p=n(15),f=n(381),d=n(131),g=n(212),v=n(14),m=n(3),b=n(9),k=n(37).enforce,_=n(211),x=n(5),C=n(205),y=n(214),$=x("match"),L=r.RegExp,w=L.prototype,O=r.SyntaxError,S=a(w.exec),I=a("".charAt),E=a("".replace),j=a("".indexOf),T=a("".slice),R=/^\?<[^\s\d!#%&*+<=>@^][^\s!#%&*+<=>@^]*>/,A=/a/g,N=/a/g,P=new L(A)!==A,D=d.MISSED_STICKY,U=d.UNSUPPORTED_Y,H=i&&(!P||D||C||y||m((function(){return N[$]=!1,L(A)!=A||L(N)==N||"/a/i"!=L(A,"i")})));if(s("RegExp",H)){for(var W=function(t,e){var n,i,r,a,s,l,d=c(w,this),g=h(t),v=void 0===e,m=[],_=t;if(!d&&g&&v&&t.constructor===W)return t;if((g||c(w,t))&&(t=t.source,v&&(e=f(_))),t=void 0===t?"":p(t),e=void 0===e?"":p(e),_=t,C&&"dotAll"in A&&(i=!!e&&j(e,"s")>-1)&&(e=E(e,/s/g,"")),n=e,D&&"sticky"in A&&(r=!!e&&j(e,"y")>-1)&&U&&(e=E(e,/y/g,"")),y&&(t=(a=function(t){for(var e,n=t.length,i=0,r="",a=[],s={},o=!1,u=!1,l=0,c="";i<=n;i++){if("\\"===(e=I(t,i)))e+=I(t,++i);else if("]"===e)o=!1;else if(!o)switch(!0){case"["===e:o=!0;break;case"("===e:S(R,T(t,i+1))&&(i+=2,u=!0),r+=e,l++;continue;case">"===e&&u:if(""===c||b(s,c))throw new O("Invalid capture group name");s[c]=!0,a[a.length]=[c,l],u=!1,c="";continue}u?c+=e:r+=e}return[r,a]}(t))[0],m=a[1]),s=o(L(t,e),d?this:w,W),(i||r||m.length)&&(l=k(s),i&&(l.dotAll=!0,l.raw=W(function(t){for(var e,n=t.length,i=0,r="",a=!1;i<=n;i++)"\\"!==(e=I(t,i))?a||"."!==e?("["===e?a=!0:"]"===e&&(a=!1),r+=e):r+="[\\s\\S]":r+=e+I(t,++i);return r}(t),n)),r&&(l.sticky=!0),m.length&&(l.groups=m)),t!==_)try{u(s,"source",""===_?"(?:)":_)}catch(t){}return s},G=l(L),B=0;G.length>B;)g(W,L,G[B++]);w.constructor=W,W.prototype=w,v(r,"RegExp",W,{constructor:!0})}_("RegExp")},381:function(t,e,n){var i=n(6),r=n(9),a=n(33),s=n(213),o=RegExp.prototype;t.exports=function(t){var e=t.flags;return void 0!==e||"flags"in o||r(t,"flags")||!a(o,t)?e:i(s,t)}},382:function(t,e,n){var i=n(0),r=n(7),a=n(205),s=n(26),o=n(383),u=n(37).get,l=RegExp.prototype,c=i.TypeError;r&&a&&o(l,"dotAll",{configurable:!0,get:function(){if(this!==l){if("RegExp"===s(this))return!!u(this).dotAll;throw c("Incompatible receiver, RegExp required")}}})},383:function(t,e,n){var i=n(210),r=n(12);t.exports=function(t,e,n){return n.get&&i(n.get,e,{getter:!0}),n.set&&i(n.set,e,{setter:!0}),r.f(t,e,n)}},384:function(t,e,n){var i=n(0),r=n(7),a=n(131).MISSED_STICKY,s=n(26),o=n(383),u=n(37).get,l=RegExp.prototype,c=i.TypeError;r&&a&&o(l,"sticky",{configurable:!0,get:function(){if(this!==l){if("RegExp"===s(this))return!!u(this).sticky;throw c("Incompatible receiver, RegExp required")}}})},385:function(t,e,n){"use strict";var i=n(98).PROPER,r=n(14),a=n(11),s=n(15),o=n(3),u=n(381),l=RegExp.prototype.toString,c=o((function(){return"/a/b"!=l.call({source:"a",flags:"b"})})),h=i&&"toString"!=l.name;(c||h)&&r(RegExp.prototype,"toString",(function(){var t=a(this);return"/"+s(t.source)+"/"+s(u(t))}),{unsafe:!0})},386:function(t,e,n){},387:function(t,e,n){},388:function(t,e,n){},389:function(t,e,n){},390:function(t,e,n){},391:function(t,e,n){},392:function(t,e){t.exports=function(t){return null==t}},393:function(t,e,n){},394:function(t,e,n){},395:function(t,e,n){},396:function(t,e,n){},397:function(t,e,n){},398:function(t,e,n){},402:function(t,e,n){"use strict";n.r(e);n(128),n(10);var i=n(376),r={name:"SidebarGroup",components:{DropdownTransition:n(403).a},props:["item","open","collapsable","depth"],beforeCreate:function(){this.$options.components.SidebarLinks=n(402).default},methods:{isActive:i.e}},a=(n(422),n(36)),s=Object(a.a)(r,(function(){var t=this,e=t.$createElement,n=t._self._c||e;return n("section",{staticClass:"sidebar-group",class:[{collapsable:t.collapsable,"is-sub-group":0!==t.depth},"depth-"+t.depth]},[t.item.path?n("RouterLink",{staticClass:"sidebar-heading clickable",class:{open:t.open,active:t.isActive(t.$route,t.item.path)},attrs:{to:t.item.path},nativeOn:{click:function(e){return t.$emit("toggle")}}},[n("span",[t._v(t._s(t.item.title))]),t._v(" "),t.collapsable?n("span",{staticClass:"arrow",class:t.open?"down":"right"}):t._e()]):n("p",{staticClass:"sidebar-heading",class:{open:t.open},on:{click:function(e){return t.$emit("toggle")}}},[n("span",[t._v(t._s(t.item.title))]),t._v(" "),t.collapsable?n("span",{staticClass:"arrow",class:t.open?"down":"right"}):t._e()]),t._v(" "),n("DropdownTransition",[t.open||!t.collapsable?n("SidebarLinks",{staticClass:"sidebar-group-items",attrs:{items:t.item.children,"sidebar-depth":t.item.sidebarDepth,"initial-open-group-index":t.item.initialOpenGroupIndex,depth:t.depth+1}}):t._e()],1)],1)}),[],!1,null,null,null).exports;n(423),n(32),n(127),n(96);function o(t,e,n,i,r){var a={props:{to:e,activeClass:"",exactActiveClass:""},class:{active:i,"sidebar-link":!0}};return r>2&&(a.style={"padding-left":r+"rem"}),t("RouterLink",a,n)}function u(t,e,n,r,a){var s=arguments.length>5&&void 0!==arguments[5]?arguments[5]:1;return!e||s>a?null:t("ul",{class:"sidebar-sub-headers"},e.map((function(e){var l=Object(i.e)(r,n+"#"+e.slug);return t("li",{class:"sidebar-sub-header"},[o(t,n+"#"+e.slug,e.title,l,e.level-1),u(t,e.children,n,r,a,s+1)])})))}var l={functional:!0,props:["item","sidebarDepth"],render:function(t,e){var n=e.parent,r=n.$page,a=(n.$site,n.$route),s=n.$themeConfig,l=n.$themeLocaleConfig,c=e.props,h=c.item,p=c.sidebarDepth,f=Object(i.e)(a,h.path),d="auto"===h.type?f||h.children.some((function(t){return Object(i.e)(a,h.basePath+"#"+t.slug)})):f,g="external"===h.type?function(t,e,n){return t("a",{attrs:{href:e,target:"_blank",rel:"noopener noreferrer"},class:{"sidebar-link":!0}},[n,t("OutboundLink")])}(t,h.path,h.title||h.path):o(t,h.path,h.title||h.path,d),v=[r.frontmatter.sidebarDepth,p,l.sidebarDepth,s.sidebarDepth,1].find((function(t){return void 0!==t})),m=l.displayAllHeaders||s.displayAllHeaders;return"auto"===h.type?[g,u(t,h.children,h.basePath,a,v)]:(d||m)&&h.headers&&!i.d.test(h.path)?[g,u(t,Object(i.c)(h.headers),h.path,a,v)]:g}};n(424);function c(t,e){if("group"===e.type){var n=e.path&&Object(i.e)(t,e.path),r=e.children.some((function(e){return"group"===e.type?c(t,e):"page"===e.type&&Object(i.e)(t,e.path)}));return n||r}return!1}var h={name:"SidebarLinks",components:{SidebarGroup:s,SidebarLink:Object(a.a)(l,void 0,void 0,!1,null,null,null).exports},props:["items","depth","sidebarDepth","initialOpenGroupIndex"],data:function(){return{openGroupIndex:this.initialOpenGroupIndex||0}},watch:{$route:function(){this.refreshIndex()}},created:function(){this.refreshIndex()},methods:{refreshIndex:function(){var t=function(t,e){for(var n=0;n-1&&(this.openGroupIndex=t)},toggleGroup:function(t){this.openGroupIndex=t===this.openGroupIndex?-1:t},isActive:function(t){return Object(i.e)(this.$route,t.regularPath)}}},p=Object(a.a)(h,(function(){var t=this,e=t.$createElement,n=t._self._c||e;return t.items.length?n("ul",{staticClass:"sidebar-links"},t._l(t.items,(function(e,i){return n("li",{key:i},["group"===e.type?n("SidebarGroup",{attrs:{item:e,open:i===t.openGroupIndex,collapsable:e.collapsable||e.collapsible,depth:t.depth},on:{toggle:function(e){return t.toggleGroup(i)}}}):n("SidebarLink",{attrs:{"sidebar-depth":t.sidebarDepth,item:e}})],1)})),0):t._e()}),[],!1,null,null,null);e.default=p.exports},403:function(t,e,n){"use strict";var i={name:"DropdownTransition",methods:{setHeight:function(t){t.style.height=t.scrollHeight+"px"},unsetHeight:function(t){t.style.height=""}}},r=(n(414),n(36)),a=Object(r.a)(i,(function(){var t=this.$createElement;return(this._self._c||t)("transition",{attrs:{name:"dropdown"},on:{enter:this.setHeight,"after-enter":this.unsetHeight,"before-leave":this.setHeight}},[this._t("default")],2)}),[],!1,null,null,null);e.a=a.exports},404:function(t,e,n){"use strict";var i=n(1),r=n(405);i({target:"String",proto:!0,forced:n(406)("link")},{link:function(t){return r(this,"a","href",t)}})},405:function(t,e,n){var i=n(2),r=n(25),a=n(15),s=/"/g,o=i("".replace);t.exports=function(t,e,n,i){var u=a(r(t)),l="<"+e;return""!==n&&(l+=" "+n+'="'+o(a(i),s,""")+'"'),l+">"+u+""}},406:function(t,e,n){var i=n(3);t.exports=function(t){return i((function(){var e=""[t]('"');return e!==e.toLowerCase()||e.split('"').length>3}))}},407:function(t,e,n){"use strict";n(378)},408:function(t,e,n){var i=n(1),r=n(409);i({global:!0,forced:parseInt!=r},{parseInt:r})},409:function(t,e,n){var i=n(0),r=n(3),a=n(2),s=n(15),o=n(207).trim,u=n(208),l=i.parseInt,c=i.Symbol,h=c&&c.iterator,p=/^[+-]?0x/i,f=a(p.exec),d=8!==l(u+"08")||22!==l(u+"0x16")||h&&!r((function(){l(Object(h))}));t.exports=d?function(t,e){var n=o(s(t));return l(n,e>>>0||(f(p,n)?16:10))}:l},410:function(t,e,n){var i=n(98).PROPER,r=n(3),a=n(208);t.exports=function(t){return r((function(){return!!a[t]()||"​…᠎"!=="​…᠎"[t]()||i&&a[t].name!==t}))}},411:function(t,e,n){"use strict";var i,r=n(1),a=n(2),s=n(34).f,o=n(69),u=n(15),l=n(134),c=n(25),h=n(136),p=n(16),f=a("".endsWith),d=a("".slice),g=Math.min,v=h("endsWith");r({target:"String",proto:!0,forced:!!(p||v||(i=s(String.prototype,"endsWith"),!i||i.writable))&&!v},{endsWith:function(t){var e=u(c(this));l(t);var n=arguments.length>1?arguments[1]:void 0,i=e.length,r=void 0===n?i:g(o(n),i),a=u(t);return f?f(e,a,r):d(e,r-a.length,r)===a}})},412:function(t,e,n){"use strict";n(386)},413:function(t,e,n){"use strict";n(387)},414:function(t,e,n){"use strict";n(388)},415:function(t,e,n){"use strict";n(389)},416:function(t,e,n){"use strict";n(390)},417:function(t,e,n){"use strict";n(391)},418:function(t,e,n){"use strict";n(393)},419:function(t,e,n){var i=n(49),r=n(21),a=n(38);t.exports=function(t){return"string"==typeof t||!r(t)&&a(t)&&"[object String]"==i(t)}},420:function(t,e,n){"use strict";n(394)},421:function(t,e,n){"use strict";n(395)},422:function(t,e,n){"use strict";n(396)},423:function(t,e,n){"use strict";var i=n(1),r=n(48).find,a=n(132),s=!0;"find"in[]&&Array(1).find((function(){s=!1})),i({target:"Array",proto:!0,forced:s},{find:function(t){return r(this,t,arguments.length>1?arguments[1]:void 0)}}),a("find")},424:function(t,e,n){"use strict";n(397)},425:function(t,e,n){"use strict";n(398)},442:function(t,e,n){"use strict";n.r(e);n(404),n(128),n(10),n(129);var i=n(376),r={name:"NavLink",props:{item:{required:!0}},computed:{link:function(){return Object(i.b)(this.item.link)},exact:function(){var t=this;return this.$site.locales?Object.keys(this.$site.locales).some((function(e){return e===t.link})):"/"===this.link},isNonHttpURI:function(){return Object(i.g)(this.link)||Object(i.h)(this.link)},isBlankTarget:function(){return"_blank"===this.target},isInternal:function(){return!Object(i.f)(this.link)&&!this.isBlankTarget},target:function(){return this.isNonHttpURI?null:this.item.target?this.item.target:Object(i.f)(this.link)?"_blank":""},rel:function(){return this.isNonHttpURI||!1===this.item.rel?null:this.item.rel?this.item.rel:this.isBlankTarget?"noopener noreferrer":null}},methods:{focusoutAction:function(){this.$emit("focusout")}}},a=n(36),s=Object(a.a)(r,(function(){var t=this,e=t.$createElement,n=t._self._c||e;return t.isInternal?n("RouterLink",{staticClass:"nav-link",attrs:{to:t.link,exact:t.exact},nativeOn:{focusout:function(e){return t.focusoutAction.apply(null,arguments)}}},[t._v("\n "+t._s(t.item.text)+"\n")]):n("a",{staticClass:"nav-link external",attrs:{href:t.link,target:t.target,rel:t.rel},on:{focusout:t.focusoutAction}},[t._v("\n "+t._s(t.item.text)+"\n "),t.isBlankTarget?n("OutboundLink"):t._e()],1)}),[],!1,null,null,null).exports,o={name:"Home",components:{NavLink:s},computed:{data:function(){return this.$page.frontmatter},actionLink:function(){return{link:this.data.actionLink,text:this.data.actionText}}}},u=(n(407),Object(a.a)(o,(function(){var t=this,e=t.$createElement,n=t._self._c||e;return n("main",{staticClass:"home",attrs:{"aria-labelledby":null!==t.data.heroText?"main-title":null}},[n("header",{staticClass:"hero"},[t.data.heroImage?n("img",{attrs:{src:t.$withBase(t.data.heroImage),alt:t.data.heroAlt||"hero"}}):t._e(),t._v(" "),null!==t.data.heroText?n("h1",{attrs:{id:"main-title"}},[t._v("\n "+t._s(t.data.heroText||t.$title||"Hello")+"\n ")]):t._e(),t._v(" "),null!==t.data.tagline?n("p",{staticClass:"description"},[t._v("\n "+t._s(t.data.tagline||t.$description||"Welcome to your VuePress site")+"\n ")]):t._e(),t._v(" "),t.data.actionText&&t.data.actionLink?n("p",{staticClass:"action"},[n("NavLink",{staticClass:"action-button",attrs:{item:t.actionLink}})],1):t._e()]),t._v(" "),t.data.features&&t.data.features.length?n("div",{staticClass:"features"},t._l(t.data.features,(function(e,i){return n("div",{key:i,staticClass:"feature"},[n("h2",[t._v(t._s(e.title))]),t._v(" "),n("p",[t._v(t._s(e.details))])])})),0):t._e(),t._v(" "),n("Content",{staticClass:"theme-default-content custom"}),t._v(" "),t.data.footer?n("div",{staticClass:"footer"},[t._v("\n "+t._s(t.data.footer)+"\n ")]):n("Content",{staticClass:"footer",attrs:{"slot-key":"footer"}})],1)}),[],!1,null,null,null).exports),l=(n(408),n(379),n(204),n(130),n(45),n(32),n(377),n(215),n(216),n(206),n(97),n(380),n(382),n(384),n(385),n(96),n(209),n(127),n(411),n(218)),c=n.n(l),h=function(t,e){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:null,i=c()(e,"title","");return c()(e,"frontmatter.tags")&&(i+=" ".concat(e.frontmatter.tags.join(" "))),n&&(i+=" ".concat(n)),p(t,i)},p=function(t,e){var n=function(t){return t.replace(/[-/\\^$*+?.()|[\]{}]/g,"\\$&")},i=new RegExp("[^\0-]"),r=t.split(/\s+/g).map((function(t){return t.trim()})).filter((function(t){return!!t}));if(i.test(t))return r.some((function(t){return e.toLowerCase().indexOf(t)>-1}));var a=t.endsWith(" ");return new RegExp(r.map((function(t,e){return r.length!==e+1||a?"(?=.*\\b".concat(n(t),"\\b)"):"(?=.*\\b".concat(n(t),")")})).join("")+".+","gi").test(e)},f={name:"SearchBox",data:function(){return{query:"",focused:!1,focusIndex:0,placeholder:void 0}},computed:{showSuggestions:function(){return this.focused&&this.suggestions&&this.suggestions.length},suggestions:function(){var t=this.query.trim().toLowerCase();if(t){for(var e=this.$site.pages,n=this.$site.themeConfig.searchMaxSuggestions||5,i=this.$localePath,r=[],a=0;a=n);a++){var s=e[a];if(this.getPageLocalePath(s)===i&&this.isSearchable(s))if(h(t,s))r.push(s);else if(s.headers)for(var o=0;o=n);o++){var u=s.headers[o];u.title&&h(t,s,u.title)&&r.push(Object.assign({},s,{path:s.path+"#"+u.slug,header:u}))}}return r}},alignRight:function(){return(this.$site.themeConfig.nav||[]).length+(this.$site.repo?1:0)<=2}},mounted:function(){this.placeholder=this.$site.themeConfig.searchPlaceholder||"",document.addEventListener("keydown",this.onHotkey)},beforeDestroy:function(){document.removeEventListener("keydown",this.onHotkey)},methods:{getPageLocalePath:function(t){for(var e in this.$site.locales||{})if("/"!==e&&0===t.path.indexOf(e))return e;return"/"},isSearchable:function(t){var e=null;return null===e||(e=Array.isArray(e)?e:new Array(e)).filter((function(e){return t.path.match(e)})).length>0},onHotkey:function(t){t.srcElement===document.body&&["s","/"].includes(t.key)&&(this.$refs.input.focus(),t.preventDefault())},onUp:function(){this.showSuggestions&&(this.focusIndex>0?this.focusIndex--:this.focusIndex=this.suggestions.length-1)},onDown:function(){this.showSuggestions&&(this.focusIndex "+t._s(e.header.title))]):t._e()])])})),0):t._e()])}),[],!1,null,null,null).exports),g=(n(413),Object(a.a)({},(function(){var t=this,e=t.$createElement,n=t._self._c||e;return n("div",{staticClass:"sidebar-button",on:{click:function(e){return t.$emit("toggle-sidebar")}}},[n("svg",{staticClass:"icon",attrs:{xmlns:"http://www.w3.org/2000/svg","aria-hidden":"true",role:"img",viewBox:"0 0 448 512"}},[n("path",{attrs:{fill:"currentColor",d:"M436 124H12c-6.627 0-12-5.373-12-12V80c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12z"}})])])}),[],!1,null,null,null).exports),v=n(67),m=(n(217),n(403)),b=n(219),k=n.n(b),_={name:"DropdownLink",components:{NavLink:s,DropdownTransition:m.a},props:{item:{required:!0}},data:function(){return{open:!1}},computed:{dropdownAriaLabel:function(){return this.item.ariaLabel||this.item.text}},watch:{$route:function(){this.open=!1}},methods:{setOpen:function(t){this.open=t},isLastItemOfArray:function(t,e){return k()(e)===t},handleDropdown:function(){0===event.detail&&this.setOpen(!this.open)}}},x=(n(415),{name:"NavLinks",components:{NavLink:s,DropdownLink:Object(a.a)(_,(function(){var t=this,e=t.$createElement,n=t._self._c||e;return n("div",{staticClass:"dropdown-wrapper",class:{open:t.open}},[n("button",{staticClass:"dropdown-title",attrs:{type:"button","aria-label":t.dropdownAriaLabel},on:{click:t.handleDropdown}},[n("span",{staticClass:"title"},[t._v(t._s(t.item.text))]),t._v(" "),n("span",{staticClass:"arrow down"})]),t._v(" "),n("button",{staticClass:"mobile-dropdown-title",attrs:{type:"button","aria-label":t.dropdownAriaLabel},on:{click:function(e){return t.setOpen(!t.open)}}},[n("span",{staticClass:"title"},[t._v(t._s(t.item.text))]),t._v(" "),n("span",{staticClass:"arrow",class:t.open?"down":"right"})]),t._v(" "),n("DropdownTransition",[n("ul",{directives:[{name:"show",rawName:"v-show",value:t.open,expression:"open"}],staticClass:"nav-dropdown"},t._l(t.item.items,(function(e,i){return n("li",{key:e.link||i,staticClass:"dropdown-item"},["links"===e.type?n("h4",[t._v("\n "+t._s(e.text)+"\n ")]):t._e(),t._v(" "),"links"===e.type?n("ul",{staticClass:"dropdown-subitem-wrapper"},t._l(e.items,(function(i){return n("li",{key:i.link,staticClass:"dropdown-subitem"},[n("NavLink",{attrs:{item:i},on:{focusout:function(n){t.isLastItemOfArray(i,e.items)&&t.isLastItemOfArray(e,t.item.items)&&t.setOpen(!1)}}})],1)})),0):n("NavLink",{attrs:{item:e},on:{focusout:function(n){t.isLastItemOfArray(e,t.item.items)&&t.setOpen(!1)}}})],1)})),0)])],1)}),[],!1,null,null,null).exports},computed:{userNav:function(){return this.$themeLocaleConfig.nav||this.$site.themeConfig.nav||[]},nav:function(){var t=this,e=this.$site.locales;if(e&&Object.keys(e).length>1){var n=this.$page.path,i=this.$router.options.routes,r=this.$site.themeConfig.locales||{},a={text:this.$themeLocaleConfig.selectText||"Languages",ariaLabel:this.$themeLocaleConfig.ariaLabel||"Select language",items:Object.keys(e).map((function(a){var s,o=e[a],u=r[a]&&r[a].label||o.lang;return o.lang===t.$lang?s=n:(s=n.replace(t.$localeConfig.path,a),i.some((function(t){return t.path===s}))||(s=a)),{text:u,link:s}}))};return[].concat(Object(v.a)(this.userNav),[a])}return this.userNav},userLinks:function(){return(this.nav||[]).map((function(t){return Object.assign(Object(i.j)(t),{items:(t.items||[]).map(i.j)})}))},repoLink:function(){var t=this.$site.themeConfig.repo;return t?/^https?:/.test(t)?t:"https://github.com/".concat(t):null},repoLabel:function(){if(this.repoLink){if(this.$site.themeConfig.repoLabel)return this.$site.themeConfig.repoLabel;for(var t=this.repoLink.match(/^https?:\/\/[^/]+/)[0],e=["GitHub","GitLab","Bitbucket"],n=0;nMath.abs(n)&&Math.abs(e)>40&&(e>0&&this.touchStart.x<=80?this.toggleSidebar(!0):this.toggleSidebar(!1))}}}),G=Object(a.a)(W,(function(){var t=this,e=t.$createElement,n=t._self._c||e;return n("div",{staticClass:"theme-container",class:t.pageClasses,on:{touchstart:t.onTouchStart,touchend:t.onTouchEnd}},[t.shouldShowNavbar?n("Navbar",{on:{"toggle-sidebar":t.toggleSidebar}}):t._e(),t._v(" "),n("div",{staticClass:"sidebar-mask",on:{click:function(e){return t.toggleSidebar(!1)}}}),t._v(" "),n("Sidebar",{attrs:{items:t.sidebarItems},on:{"toggle-sidebar":t.toggleSidebar},scopedSlots:t._u([{key:"top",fn:function(){return[t._t("sidebar-top")]},proxy:!0},{key:"bottom",fn:function(){return[t._t("sidebar-bottom")]},proxy:!0}],null,!0)}),t._v(" "),t.$page.frontmatter.home?n("Home"):n("Page",{attrs:{"sidebar-items":t.sidebarItems},scopedSlots:t._u([{key:"top",fn:function(){return[t._t("page-top")]},proxy:!0},{key:"bottom",fn:function(){return[t._t("page-bottom")]},proxy:!0}],null,!0)})],1)}),[],!1,null,null,null);e.default=G.exports}}]); \ No newline at end of file diff --git a/assets/js/20.13988d8b.js b/assets/js/20.13988d8b.js new file mode 100644 index 00000000..f6fa7b97 --- /dev/null +++ b/assets/js/20.13988d8b.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[20],{454:function(t,e,s){"use strict";s.r(e);var n=s(36),r=Object(n.a)({},(function(){var t=this,e=t.$createElement,s=t._self._c||e;return s("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[s("h1",{attrs:{id:"容器编排技术-kubernetes"}},[t._v("容器编排技术 kubernetes")]),t._v(" "),s("h2",{attrs:{id:"容器编排基础"}},[t._v("容器编排基础")]),t._v(" "),s("h2",{attrs:{id:"kubernetes"}},[t._v("kubernetes")]),t._v(" "),s("h2",{attrs:{id:"参考资料"}},[t._v("参考资料")]),t._v(" "),s("ul",[s("li",[t._v("https://mp.weixin.qq.com/s/MEhDJYg_lmjbPEdFFLdedg")])])])}),[],!1,null,null,null);e.default=r.exports}}]); \ No newline at end of file diff --git a/assets/js/21.6cb0ed9a.js b/assets/js/21.6cb0ed9a.js new file mode 100644 index 00000000..120da2f4 --- /dev/null +++ b/assets/js/21.6cb0ed9a.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[21],{456:function(t,e,n){"use strict";n.r(e);var s=n(36),l=Object(s.a)({},(function(){var t=this.$createElement;return(this._self._c||t)("ContentSlotsDistributor",{attrs:{"slot-key":this.$parent.slotKey}})}),[],!1,null,null,null);e.default=l.exports}}]); \ No newline at end of file diff --git a/assets/js/22.9337cfd7.js b/assets/js/22.9337cfd7.js new file mode 100644 index 00000000..6536dcaa --- /dev/null +++ b/assets/js/22.9337cfd7.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[22],{457:function(t,e,n){"use strict";n.r(e);var s=n(36),l=Object(s.a)({},(function(){var t=this.$createElement;return(this._self._c||t)("ContentSlotsDistributor",{attrs:{"slot-key":this.$parent.slotKey}})}),[],!1,null,null,null);e.default=l.exports}}]); \ No newline at end of file diff --git a/assets/js/23.0a94be7f.js b/assets/js/23.0a94be7f.js new file mode 100644 index 00000000..3b2017f9 --- /dev/null +++ b/assets/js/23.0a94be7f.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[23],{460:function(t,e,n){"use strict";n.r(e);var s=n(36),l=Object(s.a)({},(function(){var t=this.$createElement;return(this._self._c||t)("ContentSlotsDistributor",{attrs:{"slot-key":this.$parent.slotKey}})}),[],!1,null,null,null);e.default=l.exports}}]); \ No newline at end of file diff --git a/assets/js/24.841b7f8e.js b/assets/js/24.841b7f8e.js new file mode 100644 index 00000000..119e0684 --- /dev/null +++ b/assets/js/24.841b7f8e.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[24],{458:function(t,e,n){"use strict";n.r(e);var s=n(36),l=Object(s.a)({},(function(){var t=this.$createElement;return(this._self._c||t)("ContentSlotsDistributor",{attrs:{"slot-key":this.$parent.slotKey}})}),[],!1,null,null,null);e.default=l.exports}}]); \ No newline at end of file diff --git a/assets/js/25.725f3cd0.js b/assets/js/25.725f3cd0.js new file mode 100644 index 00000000..dd1d59a8 --- /dev/null +++ b/assets/js/25.725f3cd0.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[25],{459:function(t,e,n){"use strict";n.r(e);var s=n(36),l=Object(s.a)({},(function(){var t=this.$createElement;return(this._self._c||t)("ContentSlotsDistributor",{attrs:{"slot-key":this.$parent.slotKey}})}),[],!1,null,null,null);e.default=l.exports}}]); \ No newline at end of file diff --git a/assets/js/26.c014d074.js b/assets/js/26.c014d074.js new file mode 100644 index 00000000..66c2732e --- /dev/null +++ b/assets/js/26.c014d074.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[26],{461:function(t,e,n){"use strict";n.r(e);var s=n(36),l=Object(s.a)({},(function(){var t=this.$createElement;return(this._self._c||t)("ContentSlotsDistributor",{attrs:{"slot-key":this.$parent.slotKey}})}),[],!1,null,null,null);e.default=l.exports}}]); \ No newline at end of file diff --git a/assets/js/27.2b1b4fe8.js b/assets/js/27.2b1b4fe8.js new file mode 100644 index 00000000..40b4e3fe --- /dev/null +++ b/assets/js/27.2b1b4fe8.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[27],{463:function(t,e,n){"use strict";n.r(e);var s=n(36),l=Object(s.a)({},(function(){var t=this.$createElement;return(this._self._c||t)("ContentSlotsDistributor",{attrs:{"slot-key":this.$parent.slotKey}})}),[],!1,null,null,null);e.default=l.exports}}]); \ No newline at end of file diff --git a/assets/js/28.1203b191.js b/assets/js/28.1203b191.js new file mode 100644 index 00000000..badea5d6 --- /dev/null +++ b/assets/js/28.1203b191.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[28],{462:function(t,e,n){"use strict";n.r(e);var s=n(36),l=Object(s.a)({},(function(){var t=this.$createElement;return(this._self._c||t)("ContentSlotsDistributor",{attrs:{"slot-key":this.$parent.slotKey}})}),[],!1,null,null,null);e.default=l.exports}}]); \ No newline at end of file diff --git a/assets/js/29.b84e6329.js b/assets/js/29.b84e6329.js new file mode 100644 index 00000000..498d8508 --- /dev/null +++ b/assets/js/29.b84e6329.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[29],{464:function(t,e,n){"use strict";n.r(e);var s=n(36),l=Object(s.a)({},(function(){var t=this.$createElement;return(this._self._c||t)("ContentSlotsDistributor",{attrs:{"slot-key":this.$parent.slotKey}})}),[],!1,null,null,null);e.default=l.exports}}]); \ No newline at end of file diff --git a/assets/js/3.da2e3713.js b/assets/js/3.da2e3713.js new file mode 100644 index 00000000..cf9d9825 --- /dev/null +++ b/assets/js/3.da2e3713.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[3],{431:function(t,v,e){t.exports=e.p+"assets/img/nat.8c0b59b4.svg"},432:function(t,v,e){t.exports=e.p+"assets/img/full-nat.a5480bf0.svg"},433:function(t,v,e){t.exports=e.p+"assets/img/tun.11ae16cc.svg"},434:function(t,v,e){t.exports=e.p+"assets/img/dr.9275d9cb.svg"},435:function(t,v,e){t.exports=e.p+"assets/img/lvs-cluster.e1267fa7.svg"},436:function(t,v,e){t.exports=e.p+"assets/img/sdn.9ecec920.svg"},493:function(t,v,e){"use strict";e.r(v);var _=e(36),s=Object(_.a)({},(function(){var t=this,v=t.$createElement,_=t._self._c||v;return _("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[_("h1",{attrs:{id:"sdn"}},[t._v("sdn")]),t._v(" "),_("p",[t._v("(sdn software defined network) 软件定义网络,它将网络控制平面和数据层面分离,这里面有一个重要的技术 lvs 它就是三层负载均衡,二层负载均衡的运用。")]),t._v(" "),_("p",[_("strong",[t._v("其核心技术就是 LVS")])]),t._v(" "),_("h2",{attrs:{id:"lvs-基本原理"}},[t._v("lvs 基本原理")]),t._v(" "),_("p",[t._v("通过修改七层网络中的数据链路层的 mac 协议,网络层的 ip 协议,实现了交换机 (处理 mac 协议) 网关 (处理 ip 协议) 的数据包转发。从而将数据转发到真正的服务器上。")]),t._v(" "),_("p",[t._v("lvs 有四种模式")]),t._v(" "),_("ul",[_("li",[t._v("NAT 模式 (三层负载均衡)")]),t._v(" "),_("li",[t._v("FULL-NAT 模式 (三层负载均衡)")]),t._v(" "),_("li",[t._v("TUN 模式 (二层负载均衡,部分三层负载均衡)")]),t._v(" "),_("li",[t._v("DR 模式 (二层负载均衡)")])]),t._v(" "),_("p",[t._v("只有仅有二层负载均衡的就只能用在内网中,因为没有 ip 识别是无法在公网中使用的。")]),t._v(" "),_("p",[t._v("只有涉及到了三层负载均衡,就能用在公网中,所以显而易见的,DR 模式最底层,性能最高,但是只能用在内网中")]),t._v(" "),_("h3",{attrs:{id:"nat-模式"}},[t._v("NAT 模式")]),t._v(" "),_("p",[_("img",{attrs:{src:e(431),alt:"nat"}})]),t._v(" "),_("h3",{attrs:{id:"fullnat-模式"}},[t._v("FULLNAT 模式")]),t._v(" "),_("p",[_("img",{attrs:{src:e(432),alt:"fullNat"}})]),t._v(" "),_("h3",{attrs:{id:"tun-模式"}},[t._v("TUN 模式")]),t._v(" "),_("p",[t._v("由于第三层的数据包,即 IP 数据包中包含了源 (客户端) 和目标 (均衡器) 的 IP 地址,只有真实服务器保证自己的 IP 地址与数据包中的目标 IP 地址一致,这个数据包才能被正确处理。因此,使用这种负载均衡模式时,需要把真实物理服务器集群所有机器的虚拟 IP 地址 (Virtual IP Address,VIP) 配置成与负载均衡器的虚拟 IP 一样,这样经均衡器转发后的数据包就能在真实服务器中顺利地使用")]),t._v(" "),_("p",[_("img",{attrs:{src:e(433),alt:"tun"}})]),t._v(" "),_("h3",{attrs:{id:"dr-模式"}},[t._v("DR 模式")]),t._v(" "),_("p",[_("img",{attrs:{src:e(434),alt:"dr"}}),t._v("\n由于需要更改目标 mac 地址,这就意味着该负载均衡器必须与真实的服务在 mac 层能建立通信,所以这就意味着它只能运行在内网中")]),t._v(" "),_("h3",{attrs:{id:"四种模式对比"}},[t._v("四种模式对比")]),t._v(" "),_("table",[_("thead",[_("tr",[_("th",{staticStyle:{"text-align":"center"}},[t._v("模式")]),t._v(" "),_("th",{staticStyle:{"text-align":"center"}},[t._v("优势")]),t._v(" "),_("th",{staticStyle:{"text-align":"center"}},[t._v("劣势")])])]),t._v(" "),_("tbody",[_("tr",[_("td",{staticStyle:{"text-align":"center"}},[t._v("NAT")]),t._v(" "),_("td",{staticStyle:{"text-align":"center"}},[t._v("不需要配置虚拟 ip,可以跨网")]),t._v(" "),_("td",{staticStyle:{"text-align":"center"}},[t._v("流量必须双向流经 lvs,性能较差")])]),t._v(" "),_("tr",[_("td",{staticStyle:{"text-align":"center"}},[t._v("FULL-NAT")]),t._v(" "),_("td",{staticStyle:{"text-align":"center"}},[t._v("不需要配置虚拟 ip,可以跨网")]),t._v(" "),_("td",{staticStyle:{"text-align":"center"}},[t._v("丢失客户端 ip,流量必须双向流经 lvs,性能较差")])]),t._v(" "),_("tr",[_("td",{staticStyle:{"text-align":"center"}},[t._v("TUN")]),t._v(" "),_("td",{staticStyle:{"text-align":"center"}},[t._v("性能高")]),t._v(" "),_("td",{staticStyle:{"text-align":"center"}},[t._v("必须支持 ip 隧穿的功能,必须配置和 lvs 公网一致的虚拟 ip")])]),t._v(" "),_("tr",[_("td",{staticStyle:{"text-align":"center"}},[t._v("DAR")]),t._v(" "),_("td",{staticStyle:{"text-align":"center"}},[t._v("性能最高")]),t._v(" "),_("td",{staticStyle:{"text-align":"center"}},[t._v("仅支持内网通信,并且必须配置和 lvs 公网一致的虚拟 ip")])])])]),t._v(" "),_("h2",{attrs:{id:"虚拟-ip-的虚拟性质"}},[t._v("虚拟 ip 的虚拟性质")]),t._v(" "),_("p",[t._v("高可用性:VIP 的存在使得后端真实服务器对于客户端来说是一个统一的服务入口。即使某一个 LVS 服务器出现故障,客户端仍然可以通过 VIP 访问到服务,因为 VIP 可以动态地在不同的 LVS 服务器之间转移。这种灵活性和高可用性是与普通网卡 IP 不同的,普通网卡 IP 如果对应的网卡或主机出现故障,该 IP 就无法正常提供服务了。")]),t._v(" "),_("p",[t._v("负载均衡:VIP 作为前端的统一入口,LVS 服务器可以根据不同的负载均衡算法 (如轮询、加权轮询、最小连接数等) 将客户端请求分配到后端不同的真实服务器上。这就像一个虚拟的服务端点,隐藏了后端真实服务器的 IP 地址和复杂的网络拓扑结构,更像是一个抽象的、虚拟的服务 IP,而非单纯的一个网卡 IP")]),t._v(" "),_("h2",{attrs:{id:"keepalived"}},[t._v("keepalived")]),t._v(" "),_("p",[t._v("Keepalived 是一款基于 VRRP (Virtual Router Redundancy Protocol,虚拟路由器冗余协议) 实现的高可用性 (HA) 软件。它主要用于服务器的负载均衡和高可用性场景,能够确保在服务器出现故障或网络异常时,服务仍能持续、稳定地提供。")]),t._v(" "),_("p",[t._v("从网络外部看来,VIP 就像是一个独立的、可供访问的 IP 地址,但实际上这个 VIP 可以在多个 LVS 服务器之间灵活切换。在正常情况下,这个 VIP 可能被 “绑定” 在主 LVS 服务器的网卡上,对外提供服务。但这并不是传统意义上的网卡自身的固定 IP,因为当主服务器出现故障时,通过 VRRP 机制,这个 VIP 会迅速地被绑定到备用 LVS 服务器的网卡上。")]),t._v(" "),_("p",[t._v("它的基本原理是:")]),t._v(" "),_("ul",[_("li",[t._v("两台机器配置同一个 vip (虚拟 ip)")]),t._v(" "),_("li",[t._v("两台 lvs 系统通过 keepalived 频繁通信,评估哪个机器分数高,高的那个作为 master,另一台作为备份,得分高的通过 vrrp 组播报文宣称 vip 在这里")]),t._v(" "),_("li",[t._v("如果 master 宕机了,备份机器会立刻宣称 vip 在自己这里")])]),t._v(" "),_("p",[t._v("在没有发生故障转移时,备用 LVS 设备通常不会绑定和主设备相同的虚拟 IP (VIP)")]),t._v(" "),_("p",[t._v("在正常情况下,主 LVS 设备会响应 VRRP 通告,从而拥有 VIP 的所有权。此时,从网络层面看,VIP 是绑定在主 LVS 设备的网络接口上的,外部网络流量根据这个 VIP 指向主 LVS 设备。")]),t._v(" "),_("p",[t._v("备用 LVS 设备处于监听状态,它会接收主 LVS 设备发送的 VRRP 通告,以确认主设备的存活状态。"),_("strong",[t._v("它自身并没有绑定这个 VIP,因为如果同时绑定,可能会导致 IP 地址冲突和网络混乱,比如出现流量被不恰当的分流到备用设备或者产生路由环路等问题。")])]),t._v(" "),_("p",[t._v("这里的虚拟 ip 实际上就是一个公网 ip。")]),t._v(" "),_("blockquote",[_("p",[t._v("作为最前面的网关,防火墙作为网关,其公网接口同样具有真实 IP 地址")])]),t._v(" "),_("h2",{attrs:{id:"更多优化方法"}},[t._v("更多优化方法")]),t._v(" "),_("ul",[_("li",[t._v("dpdk,因为 lvs 基于 Linux 内核的 netilter,需要内核态和用户态切换,因此 dpdk,通过申请大内存,以及轮询替代中断,完成更高性能的表现,"),_("a",{attrs:{href:"https://github.com/iqiyi/dpvs",target:"_blank",rel:"noopener noreferrer"}},[t._v("dpvs"),_("OutboundLink")],1),t._v(" 是 dpdk 技术的开源项目")])]),t._v(" "),_("h2",{attrs:{id:"使用-lvs-nginx-或者-kong-的实战部署"}},[t._v("使用 lvs + nginx (或者 kong) 的实战部署")]),t._v(" "),_("p",[t._v("首先,为了提高可用性,我们都会采用集群的方式去部署 lvs 和 nginx,我们通常使用主-从的方式去部署高可用的 lvs 集群的方案,并且通过部署多个该集群来提供性能:、\n"),_("img",{attrs:{src:e(435),alt:"lvs-cluster"}})]),t._v(" "),_("h2",{attrs:{id:"一个更加高性能的物理路由-物理交换机-lvs-nginx-kong-的实战部署"}},[t._v("一个更加高性能的物理路由 + 物理交换机 + lvs + nginx(kong) 的实战部署")]),t._v(" "),_("p",[t._v("这种更加高性能的场景也遵循上文提到的高可用主从备份的方案。")]),t._v(" "),_("p",[t._v("由于从 lvs 开始,整个架构一致,所以我们仅画出前面的架构图\n"),_("img",{attrs:{src:e(436),alt:"sdn"}})])])}),[],!1,null,null,null);v.default=s.exports}}]); \ No newline at end of file diff --git a/assets/js/30.6f462146.js b/assets/js/30.6f462146.js new file mode 100644 index 00000000..9db65132 --- /dev/null +++ b/assets/js/30.6f462146.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[30],{465:function(t,e,n){"use strict";n.r(e);var s=n(36),l=Object(s.a)({},(function(){var t=this.$createElement;return(this._self._c||t)("ContentSlotsDistributor",{attrs:{"slot-key":this.$parent.slotKey}})}),[],!1,null,null,null);e.default=l.exports}}]); \ No newline at end of file diff --git a/assets/js/31.ec64e1af.js b/assets/js/31.ec64e1af.js new file mode 100644 index 00000000..59964b5c --- /dev/null +++ b/assets/js/31.ec64e1af.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[31],{466:function(t,e,n){"use strict";n.r(e);var s=n(36),l=Object(s.a)({},(function(){var t=this.$createElement;return(this._self._c||t)("ContentSlotsDistributor",{attrs:{"slot-key":this.$parent.slotKey}})}),[],!1,null,null,null);e.default=l.exports}}]); \ No newline at end of file diff --git a/assets/js/32.68d3442e.js b/assets/js/32.68d3442e.js new file mode 100644 index 00000000..404120db --- /dev/null +++ b/assets/js/32.68d3442e.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[32],{468:function(t,e,n){"use strict";n.r(e);var s=n(36),l=Object(s.a)({},(function(){var t=this.$createElement;return(this._self._c||t)("ContentSlotsDistributor",{attrs:{"slot-key":this.$parent.slotKey}})}),[],!1,null,null,null);e.default=l.exports}}]); \ No newline at end of file diff --git a/assets/js/33.dc3897f7.js b/assets/js/33.dc3897f7.js new file mode 100644 index 00000000..cbf79997 --- /dev/null +++ b/assets/js/33.dc3897f7.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[33],{467:function(t,e,n){"use strict";n.r(e);var s=n(36),l=Object(s.a)({},(function(){var t=this.$createElement;return(this._self._c||t)("ContentSlotsDistributor",{attrs:{"slot-key":this.$parent.slotKey}})}),[],!1,null,null,null);e.default=l.exports}}]); \ No newline at end of file diff --git a/assets/js/34.0499e647.js b/assets/js/34.0499e647.js new file mode 100644 index 00000000..e7f33ef8 --- /dev/null +++ b/assets/js/34.0499e647.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[34],{470:function(t,e,n){"use strict";n.r(e);var s=n(36),l=Object(s.a)({},(function(){var t=this.$createElement;return(this._self._c||t)("ContentSlotsDistributor",{attrs:{"slot-key":this.$parent.slotKey}})}),[],!1,null,null,null);e.default=l.exports}}]); \ No newline at end of file diff --git a/assets/js/35.08050ff8.js b/assets/js/35.08050ff8.js new file mode 100644 index 00000000..4cb15107 --- /dev/null +++ b/assets/js/35.08050ff8.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[35],{469:function(t,l,e){"use strict";e.r(l);var n=e(36),i=Object(n.a)({},(function(){var t=this,l=t.$createElement,e=t._self._c||l;return e("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[e("h1",{attrs:{id:"微服务架构"}},[t._v("微服务架构")]),t._v(" "),e("ul",[e("li",[t._v("重试")]),t._v(" "),e("li",[t._v("熔断和隔离")]),t._v(" "),e("li",[t._v("限流")]),t._v(" "),e("li",[t._v("自适应限流")]),t._v(" "),e("li",[t._v("降级策略")])])])}),[],!1,null,null,null);l.default=i.exports}}]); \ No newline at end of file diff --git a/assets/js/36.ebcbadd7.js b/assets/js/36.ebcbadd7.js new file mode 100644 index 00000000..a21af253 --- /dev/null +++ b/assets/js/36.ebcbadd7.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[36],{471:function(t,e,n){"use strict";n.r(e);var s=n(36),l=Object(s.a)({},(function(){var t=this.$createElement;return(this._self._c||t)("ContentSlotsDistributor",{attrs:{"slot-key":this.$parent.slotKey}})}),[],!1,null,null,null);e.default=l.exports}}]); \ No newline at end of file diff --git a/assets/js/37.89eb99f3.js b/assets/js/37.89eb99f3.js new file mode 100644 index 00000000..4d478c18 --- /dev/null +++ b/assets/js/37.89eb99f3.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[37],{472:function(t,e,n){"use strict";n.r(e);var s=n(36),l=Object(s.a)({},(function(){var t=this.$createElement;return(this._self._c||t)("ContentSlotsDistributor",{attrs:{"slot-key":this.$parent.slotKey}})}),[],!1,null,null,null);e.default=l.exports}}]); \ No newline at end of file diff --git a/assets/js/38.c289a86e.js b/assets/js/38.c289a86e.js new file mode 100644 index 00000000..9e948cbb --- /dev/null +++ b/assets/js/38.c289a86e.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[38],{473:function(v,_,t){"use strict";t.r(_);var i=t(36),l=Object(i.a)({},(function(){var v=this,_=v.$createElement,t=v._self._c||_;return t("ContentSlotsDistributor",{attrs:{"slot-key":v.$parent.slotKey}},[t("h1",{attrs:{id:"分布式"}},[v._v("分布式")]),v._v(" "),t("h2",{attrs:{id:"分布式理论"}},[v._v("分布式理论")]),v._v(" "),t("ul",[t("li",[t("RouterLink",{attrs:{to:"/系统设计基础/分布式/分布式理论/CAP/"}},[v._v("CAP")])],1),v._v(" "),t("li",[t("a",{attrs:{href:"./%E5%88%86%E5%B8%83%E5%BC%8F%E7%90%86%E8%AE%BA/BASE/README"}},[v._v("BASE")])]),v._v(" "),t("li",[t("RouterLink",{attrs:{to:"/系统设计基础/分布式/分布式理论/ACID/"}},[v._v("ACID")])],1)]),v._v(" "),t("h2",{attrs:{id:"分布式算法"}},[v._v("分布式算法")]),v._v(" "),t("ul",[t("li",[t("RouterLink",{attrs:{to:"/系统设计基础/分布式/分布式算法/paxos/"}},[v._v("paxos")])],1),v._v(" "),t("li",[t("RouterLink",{attrs:{to:"/系统设计基础/分布式/分布式算法/raft/"}},[v._v("raft")])],1),v._v(" "),t("li",[t("RouterLink",{attrs:{to:"/系统设计基础/分布式/分布式算法/一致性哈希/"}},[v._v("一致性哈希")])],1),v._v(" "),t("li",[t("RouterLink",{attrs:{to:"/系统设计基础/分布式/分布式算法/gossip/"}},[v._v("gossip")])],1),v._v(" "),t("li",[t("RouterLink",{attrs:{to:"/系统设计基础/分布式/分布式算法/quorumNWR/"}},[v._v("quorumNWR")])],1),v._v(" "),t("li",[t("RouterLink",{attrs:{to:"/系统设计基础/分布式/分布式算法/pbet/"}},[v._v("pbet")])],1),v._v(" "),t("li",[t("RouterLink",{attrs:{to:"/系统设计基础/分布式/分布式算法/pow/"}},[v._v("pow")])],1),v._v(" "),t("li",[t("RouterLink",{attrs:{to:"/系统设计基础/分布式/分布式算法/zab/"}},[v._v("zab")])],1)]),v._v(" "),t("h2",{attrs:{id:"分布式组件"}},[v._v("分布式组件")]),v._v(" "),t("ul",[t("li",[v._v("分布式锁")]),v._v(" "),t("li",[v._v("分布式事务")]),v._v(" "),t("li",[v._v("分布式关系数据库")]),v._v(" "),t("li",[t("RouterLink",{attrs:{to:"/系统设计基础/分布式/分布式组件/分布式缓存/"}},[v._v("分布式缓存")])],1),v._v(" "),t("li",[v._v("分布式 nosql")]),v._v(" "),t("li",[v._v("分布式消息队列")])]),v._v(" "),t("h2",{attrs:{id:"分布式关键技术-来自于左耳听风"}},[v._v("分布式关键技术 (来自于左耳听风)")]),v._v(" "),t("ul",[t("li",[t("RouterLink",{attrs:{to:"/系统设计基础/分布式/分布式关键技术/全栈监控/"}},[v._v("全栈监控")])],1),v._v(" "),t("li",[v._v("服务调度")]),v._v(" "),t("li",[v._v("流量与数据调度")])]),v._v(" "),t("h2",{attrs:{id:"分布式系统设计模式-来自于左耳听风"}},[v._v("分布式系统设计模式 (来自于左耳听风)")]),v._v(" "),t("h3",{attrs:{id:"高性能"}},[v._v("高性能")]),v._v(" "),t("ul",[t("li",[t("RouterLink",{attrs:{to:"/系统设计基础/分布式/分布式系统设计模式/高性能/缓存设计/"}},[v._v("缓存设计")])],1),v._v(" "),t("li",[v._v("异步处理")]),v._v(" "),t("li",[v._v("数据库扩展")]),v._v(" "),t("li",[v._v("秒杀")]),v._v(" "),t("li",[v._v("边缘计算")])]),v._v(" "),t("h3",{attrs:{id:"高可用"}},[v._v("高可用")]),v._v(" "),t("ul",[t("li",[t("RouterLink",{attrs:{to:"/系统设计基础/分布式/分布式系统设计模式/高可用/故障和弹力设计/"}},[v._v("故障和弹力设计")])],1),v._v(" "),t("li",[v._v("隔离设计")]),v._v(" "),t("li",[v._v("异步通信设计")]),v._v(" "),t("li",[v._v("幂等性设计")]),v._v(" "),t("li",[v._v("服务的状态")]),v._v(" "),t("li",[v._v("补偿事务")]),v._v(" "),t("li",[v._v("重试设计")]),v._v(" "),t("li",[v._v("熔断设计")]),v._v(" "),t("li",[v._v("限流设计")]),v._v(" "),t("li",[v._v("降级设计")])]),v._v(" "),t("h3",{attrs:{id:"可扩展"}},[v._v("可扩展")]),v._v(" "),t("ul",[t("li",[t("RouterLink",{attrs:{to:"/系统设计基础/分布式/分布式系统设计模式/可扩展/分布式锁/"}},[v._v("分布式锁")])],1),v._v(" "),t("li",[v._v("配置中心")]),v._v(" "),t("li",[v._v("sidecar")]),v._v(" "),t("li",[v._v("服务网格")]),v._v(" "),t("li",[v._v("网关")]),v._v(" "),t("li",[v._v("部署升级策略")])]),v._v(" "),t("h2",{attrs:{id:"分布式实践"}},[v._v("分布式实践")]),v._v(" "),t("ul",[t("li",[t("RouterLink",{attrs:{to:"/系统设计基础/分布式/分布式实践/分布式协调与同步/"}},[v._v("分布式协调与同步")])],1),v._v(" "),t("li",[v._v("分布式资源管理与负载调度")]),v._v(" "),t("li",[v._v("分布式计算技术")]),v._v(" "),t("li",[v._v("分布式通信技术")]),v._v(" "),t("li",[v._v("分布式数据存储")]),v._v(" "),t("li",[v._v("分布式高可靠")])])])}),[],!1,null,null,null);_.default=l.exports}}]); \ No newline at end of file diff --git a/assets/js/39.35f094fb.js b/assets/js/39.35f094fb.js new file mode 100644 index 00000000..62c11b60 --- /dev/null +++ b/assets/js/39.35f094fb.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[39],{474:function(t,e,n){"use strict";n.r(e);var s=n(36),l=Object(s.a)({},(function(){var t=this.$createElement;return(this._self._c||t)("ContentSlotsDistributor",{attrs:{"slot-key":this.$parent.slotKey}})}),[],!1,null,null,null);e.default=l.exports}}]); \ No newline at end of file diff --git a/assets/js/4.32572b67.js b/assets/js/4.32572b67.js new file mode 100644 index 00000000..0ac0464f --- /dev/null +++ b/assets/js/4.32572b67.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[4],{399:function(t,e,n){},439:function(t,e,n){"use strict";n(399)},506:function(t,e,n){"use strict";n.r(e);var i={functional:!0,props:{type:{type:String,default:"tip"},text:String,vertical:{type:String,default:"top"}},render:function(t,e){var n=e.props,i=e.slots;return t("span",{class:["badge",n.type],style:{verticalAlign:n.vertical}},n.text||i().default)}},r=(n(439),n(36)),p=Object(r.a)(i,void 0,void 0,!1,null,"15b7b770",null);e.default=p.exports}}]); \ No newline at end of file diff --git a/assets/js/40.9c39969c.js b/assets/js/40.9c39969c.js new file mode 100644 index 00000000..c11608b5 --- /dev/null +++ b/assets/js/40.9c39969c.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[40],{475:function(t,e,n){"use strict";n.r(e);var s=n(36),l=Object(s.a)({},(function(){var t=this.$createElement;return(this._self._c||t)("ContentSlotsDistributor",{attrs:{"slot-key":this.$parent.slotKey}})}),[],!1,null,null,null);e.default=l.exports}}]); \ No newline at end of file diff --git a/assets/js/41.7ca82be6.js b/assets/js/41.7ca82be6.js new file mode 100644 index 00000000..7c8af615 --- /dev/null +++ b/assets/js/41.7ca82be6.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[41],{476:function(t,e,n){"use strict";n.r(e);var s=n(36),l=Object(s.a)({},(function(){var t=this.$createElement;return(this._self._c||t)("ContentSlotsDistributor",{attrs:{"slot-key":this.$parent.slotKey}})}),[],!1,null,null,null);e.default=l.exports}}]); \ No newline at end of file diff --git a/assets/js/42.04e5aff3.js b/assets/js/42.04e5aff3.js new file mode 100644 index 00000000..bbbac8e6 --- /dev/null +++ b/assets/js/42.04e5aff3.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[42],{478:function(t,e,n){"use strict";n.r(e);var s=n(36),l=Object(s.a)({},(function(){var t=this.$createElement;return(this._self._c||t)("ContentSlotsDistributor",{attrs:{"slot-key":this.$parent.slotKey}})}),[],!1,null,null,null);e.default=l.exports}}]); \ No newline at end of file diff --git a/assets/js/43.b51229d8.js b/assets/js/43.b51229d8.js new file mode 100644 index 00000000..ba93e410 --- /dev/null +++ b/assets/js/43.b51229d8.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[43],{477:function(t,e,n){"use strict";n.r(e);var s=n(36),l=Object(s.a)({},(function(){var t=this.$createElement;return(this._self._c||t)("ContentSlotsDistributor",{attrs:{"slot-key":this.$parent.slotKey}})}),[],!1,null,null,null);e.default=l.exports}}]); \ No newline at end of file diff --git a/assets/js/44.cc446f41.js b/assets/js/44.cc446f41.js new file mode 100644 index 00000000..a0d48c85 --- /dev/null +++ b/assets/js/44.cc446f41.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[44],{479:function(t,e,n){"use strict";n.r(e);var s=n(36),l=Object(s.a)({},(function(){var t=this.$createElement;return(this._self._c||t)("ContentSlotsDistributor",{attrs:{"slot-key":this.$parent.slotKey}})}),[],!1,null,null,null);e.default=l.exports}}]); \ No newline at end of file diff --git a/assets/js/45.9f727341.js b/assets/js/45.9f727341.js new file mode 100644 index 00000000..bda56bb7 --- /dev/null +++ b/assets/js/45.9f727341.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[45],{480:function(t,e,n){"use strict";n.r(e);var s=n(36),l=Object(s.a)({},(function(){var t=this.$createElement;return(this._self._c||t)("ContentSlotsDistributor",{attrs:{"slot-key":this.$parent.slotKey}})}),[],!1,null,null,null);e.default=l.exports}}]); \ No newline at end of file diff --git a/assets/js/46.3a231b77.js b/assets/js/46.3a231b77.js new file mode 100644 index 00000000..bd049de2 --- /dev/null +++ b/assets/js/46.3a231b77.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[46],{481:function(t,v,_){"use strict";_.r(v);var i=_(36),s=Object(i.a)({},(function(){var t=this,v=t.$createElement,_=t._self._c||v;return _("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[_("h1",{attrs:{id:"分布式中的缓存"}},[t._v("分布式中的缓存")]),t._v(" "),_("p",[_("strong",[t._v("缓存是一个典型的空间换时间的优化手段")]),t._v(",对于软件角度的缓存,往往缺点大于优点,看似带来了一定的性能提升,但是随之而来的负面作用往往不可忽视,引入缓存,你要处理数据一致性问题,缓存的失效,更新等等各种问题,极大的增加了系统整体复杂度,从运维的角度来说,缓存的存在也掩盖了 bug,让 bug 出现在更久之后,距离真实现场更远的地方,从安全的角度来说,缓存也可能会泄露保密数据,但是,我要说但是,缓存的引入将带来极大的性能提升,不管是 cpu 还是 io 的角度。")]),t._v(" "),_("p",[t._v("从 cpu 的角度来说,本身要进行的复杂计算,使用缓存将数据存储起来,无需重复计算,从 io 的角度来说,从缓存去读取数据要远比从磁盘上的数据库读取数据快的多")]),t._v(" "),_("p",[t._v("缓存虽然是空间换时间的方法,但是缓存本身是用来缓解 cpu 和 io 的压力而生的,"),_("strong",[t._v("它的目的并不是直接的提升性能")]),t._v(",因为你完全可以直接升级 cpu 和 io 的性能,这样又不会引入那么多的缺陷不是吗?")]),t._v(" "),_("h2",{attrs:{id:"缓存的属性"}},[t._v("缓存的属性")]),t._v(" "),_("ul",[_("li",[t._v("吞吐量,读写操作的效率,使用 OPS (每秒的操作量) 来进行衡量,吞吐量越高越好")]),t._v(" "),_("li",[t._v("命中率,成功从缓存中返回的结果和总请求次数的比值,命中率越高越好")]),t._v(" "),_("li",[t._v("扩展功能,除了基本读写之外的扩展功能,比如,最大容量,失效时间,失效事件,命中率统计")]),t._v(" "),_("li",[t._v("是否支持分布式,缓存有进程缓存分布式缓存两大类,前者仅仅为本身节点提供服务,比如你在读写过程中引入了一个数组,或者哈希表,不需要反复读取磁盘,仅需要读取本地数据或者哈希表中的缓存即可获取数据,这种缓存并无网络操作,速度很快,但是缓存的数据不能在各个节点中共享,分布式缓存则相反,它存在于多个独立的缓存节点组成的集群中,这些节点可以分布于不同的数据中心,分布式缓存可以被不同的应用进程所共享,各个组件之间可以很方便的获取相同的缓存数据。")])]),t._v(" "),_("h3",{attrs:{id:"吞吐量"}},[t._v("吞吐量")]),t._v(" "),_("h3",{attrs:{id:"命中率"}},[t._v("命中率")]),t._v(" "),_("h3",{attrs:{id:"扩展功能"}},[t._v("扩展功能")]),t._v(" "),_("h3",{attrs:{id:"分布式支持"}},[t._v("分布式支持")]),t._v(" "),_("h2",{attrs:{id:"缓存的风险"}},[t._v("缓存的风险")]),t._v(" "),_("h3",{attrs:{id:"缓存穿透"}},[t._v("缓存穿透")]),t._v(" "),_("h3",{attrs:{id:"缓存击穿"}},[t._v("缓存击穿")]),t._v(" "),_("h3",{attrs:{id:"缓存雪崩"}},[t._v("缓存雪崩")]),t._v(" "),_("h3",{attrs:{id:"缓存污染"}},[t._v("缓存污染")])])}),[],!1,null,null,null);v.default=s.exports}}]); \ No newline at end of file diff --git a/assets/js/47.dfa34087.js b/assets/js/47.dfa34087.js new file mode 100644 index 00000000..5a9ebe67 --- /dev/null +++ b/assets/js/47.dfa34087.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[47],{482:function(t,l,e){"use strict";e.r(l);var n=e(36),i=Object(n.a)({},(function(){var t=this,l=t.$createElement,e=t._self._c||l;return e("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[e("h1",{attrs:{id:"架构安全性"}},[t._v("架构安全性")]),t._v(" "),e("ul",[e("li",[t._v("认证")]),t._v(" "),e("li",[t._v("授权")]),t._v(" "),e("li",[t._v("凭证")]),t._v(" "),e("li",[t._v("保密")]),t._v(" "),e("li",[t._v("传输")]),t._v(" "),e("li",[t._v("验证")])])])}),[],!1,null,null,null);l.default=i.exports}}]); \ No newline at end of file diff --git a/assets/js/48.4c7e4932.js b/assets/js/48.4c7e4932.js new file mode 100644 index 00000000..9dac3f6d --- /dev/null +++ b/assets/js/48.4c7e4932.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[48],{483:function(_,v,t){"use strict";t.r(v);var l=t(36),i=Object(l.a)({},(function(){var _=this,v=_.$createElement,t=_._self._c||v;return t("ContentSlotsDistributor",{attrs:{"slot-key":_.$parent.slotKey}},[t("h1",{attrs:{id:"系统设计理论基础"}},[_._v("系统设计理论基础")]),_._v(" "),t("p",[_._v("设计系统的工程师叫做架构师,就如同几千年之前的鲁班一样,设计出了精妙绝伦的系统。")]),_._v(" "),t("p",[_._v("架构不是一成不变的,从最早的单体服务,到如今的分布式服务,微服务,云原生,这要求架构师要不断的学习,变化是最重要的设计考虑因素。")]),_._v(" "),t("p",[_._v("世界上不存在银弹,或许你钟爱某一种形式的设计,但是技术不分好坏,我们总是在寻求利弊而已,我们架构师要做的不过是取舍。一切皆是权衡。")]),_._v(" "),t("h2",{attrs:{id:"技术广度和深度"}},[_._v("技术广度和深度")]),_._v(" "),t("p",[_._v("架构师需要掌握的技能,从技术角度分为技术广度和深度。通常来说,"),t("strong",[_._v("对于架构师,广度的重要性大于深度")]),_._v(",没有广度就无法纵观全局。")]),_._v(" "),t("p",[_._v("架构师不可能在所有领域都保持一定的深度,这不现实,人不会有这么多的空余时间,我的建议是,"),t("strong",[_._v("在某个领域保持绝对的技术深度的同时,提高自己的技术广度")]),_._v(",就好比,你是局长兼某科科长,在你的科你的技术是绝对的一流,但你还是局长,必须要了解其它科的技术,才能真正的掌握全局。")]),_._v(" "),t("h2",{attrs:{id:"权衡利弊"}},[_._v("权衡利弊")]),_._v(" "),t("p",[_._v("微服务一定比单体服务优秀吗?异步通信就是比同步通信好吗?")]),_._v(" "),t("p",[_._v("这个世界是现实的,任何的好处都是有代价的,微服务在可扩展性,高可用性等特征上的确比单体服务优秀,但是它要比单体服务性能更差,复杂度也高很多,花费也要高很多,当我们面向一个场景简单,用户量低的场景下,毫无疑问,选择单体服务是更好的选择。")]),_._v(" "),t("p",[_._v("架构选择没有对错,只有取舍和适合。")]),_._v(" "),t("h2",{attrs:{id:"模块化"}},[_._v("模块化")]),_._v(" "),t("p",[_._v("模块化的概念是什么?")]),_._v(" "),t("p",[_._v("我给出一个定义,构建更复杂结构中的一组标准化零件,一个复杂结构中的独立单元。一个函数就是整个代码集群中的一个模块,一个数据库组件就是数据库集群中的一个模块。")]),_._v(" "),t("p",[_._v("我们使用三个标准去评估模块之间的关系:")]),_._v(" "),t("ul",[t("li",[_._v("內聚性")]),_._v(" "),t("li",[_._v("耦合")]),_._v(" "),t("li",[_._v("共生性")])]),_._v(" "),t("p",[t("strong",[_._v("內聚性")]),_._v(":")]),_._v(" "),t("p",[_._v("也称之为内聚力,高内聚的模块指的是:功能单一,独立性强,逻辑清晰,如果分割该模块将得到更坏的结果")]),_._v(" "),t("p",[t("strong",[_._v("耦合")]),_._v(":")]),_._v(" "),t("p",[_._v("耦合度,指的是模块间的依赖关系,高耦合的模块指的是:模块间的依赖关系过多,模块间的修改会相互影响,如果分割该模块将得到更坏的结果")]),_._v(" "),t("p",[t("strong",[_._v("共生")]),_._v(":")]),_._v(" "),t("p",[_._v("模块间的依赖关系,如果一个组件的变更需要修改另一个组件才能保证系统整体的运行,那么他们之间是共生关系")]),_._v(" "),t("p",[_._v("一个合理的共生关系通常是合理的。通常来说,弱共生关系更合理")]),_._v(" "),t("h3",{attrs:{id:"高内聚低耦合的好处"}},[_._v("高内聚低耦合的好处")]),_._v(" "),t("p",[t("strong",[_._v("高内聚的好处")])]),_._v(" "),t("p",[_._v("提高软件质量:")]),_._v(" "),t("ul",[t("li",[_._v("功能明确:每个模块专注于特定的任务,使得代码逻辑更加清晰,易于理解和维护。开发人员可以快速定位问题所在,减少错误的发生。")]),_._v(" "),t("li",[_._v("可靠性高:由于模块内部的紧密协作,其功能实现更加稳定可靠。一个高内聚的模块通常经过良好的设计和测试,能够在各种情况下正确执行其特定任务。")])]),_._v(" "),t("p",[_._v("增强可维护性:")]),_._v(" "),t("ul",[t("li",[_._v("易于修改:当需要对软件进行修改时,高内聚的模块可以独立进行修改,而不会对其他模块产生过多的影响。这大大降低了维护成本和风险,提高了维护效率。")]),_._v(" "),t("li",[_._v("可扩展性强:可以方便地在不影响其他模块的情况下,为高内聚的模块添加新的功能或改进现有功能。这种可扩展性使得软件能够适应不断变化的需求。")])]),_._v(" "),t("p",[_._v("提升开发效率:")]),_._v(" "),t("ul",[t("li",[_._v("分工明确:开发人员可以根据模块的功能进行分工合作,提高开发效率。每个开发人员专注于特定的模块,能够更好地理解和实现其功能,减少开发过程中的冲突和重复工作。\n可重用性高:高内聚的模块通常具有较高的可重用性,可以在不同的项目或系统中重复使用。这不仅节省了开发时间,还提高了代码的质量和一致性。")])]),_._v(" "),t("p",[t("strong",[_._v("低耦合的好处")])]),_._v(" "),t("p",[_._v("提高软件的灵活性:")]),_._v(" "),t("ul",[t("li",[_._v("易于替换:当需要更换某个模块时,低耦合的设计使得可以轻松地替换该模块,而不会对其他模块产生重大影响。这为软件的升级和改进提供了更大的灵活性。")]),_._v(" "),t("li",[_._v("适应变化:低耦合的软件能够更好地适应需求的变化。当需求发生变化时,可以只对受影响的模块进行修改,而不会波及整个系统。")])]),_._v(" "),t("p",[_._v("增强软件的可维护性:")]),_._v(" "),t("ul",[t("li",[_._v("独立测试:低耦合的模块可以独立进行测试,这使得测试更加容易和高效。可以针对每个模块编写独立的测试用例,确保其功能的正确性,而不需要考虑其他模块的影响。\n降低维护成本:由于模块之间的依赖关系较少,维护一个低耦合的软件系统相对容易。当出现问题时,可以快速定位问题所在的模块,并进行修复,而不会影响到其他模块。\n提高软件的可扩展性:")]),_._v(" "),t("li",[_._v("方便添加新功能:低耦合的设计使得可以方便地添加新的模块或功能,而不会对现有系统造成太大的影响。新的模块可以独立开发和测试,然后与现有系统进行集成。")]),_._v(" "),t("li",[_._v("支持分布式开发:低耦合的软件更适合分布式开发,不同的开发团队可以独立开发不同的模块,然后进行集成。这种开发方式可以提高开发效率,降低开发风险。")])]),_._v(" "),t("h2",{attrs:{id:"架构特征"}},[_._v("架构特征")]),_._v(" "),t("h3",{attrs:{id:"功能性相关"}},[_._v("功能性相关")]),_._v(" "),t("ul",[t("li",[_._v("可用性:指系统或产品能够被正常使用的程度。")]),_._v(" "),t("li",[_._v("性能:系统或产品在运行时所表现出的各种能力指标。")]),_._v(" "),t("li",[_._v("可扩展性:系统能够方便地进行功能扩展。")]),_._v(" "),t("li",[_._v("弹性:系统能够适应变化和压力的能力。")]),_._v(" "),t("li",[_._v("高效性:强调系统在执行任务时能够以较少的资源消耗实现较高的产出。")])]),_._v(" "),t("h3",{attrs:{id:"安装与部署相关"}},[_._v("安装与部署相关")]),_._v(" "),t("ul",[t("li",[_._v("可安装性:系统或产品能够在特定环境中成功安装的容易程度。")]),_._v(" "),t("li",[_._v("兼容性:指系统能够与其他不同的软件、硬件或系统协同工作的能力。")])]),_._v(" "),t("h3",{attrs:{id:"维护与管理相关"}},[_._v("维护与管理相关")]),_._v(" "),t("ul",[t("li",[_._v("可维护性:系统易于进行维护和修复的程度。")]),_._v(" "),t("li",[_._v("可支持性:系统能够获得技术支持和维护的程度。")]),_._v(" "),t("li",[_._v("可测试性:系统易于进行测试,以便发现和修复潜在的问题。")]),_._v(" "),t("li",[_._v("可观察性:可以对系统的运行状态进行监控和观察。")])]),_._v(" "),t("h3",{attrs:{id:"数据与资源管理相关"}},[_._v("数据与资源管理相关")]),_._v(" "),t("ul",[t("li",[_._v("可重复利用性:可以多次使用系统的某些部分或整体。")]),_._v(" "),t("li",[_._v("可归档性:系统或数据能够被有效地存档保存。")]),_._v(" "),t("li",[_._v("准确性:对于数据处理或计算任务,确保结果的准确无误。")])]),_._v(" "),t("h3",{attrs:{id:"用户体验相关"}},[_._v("用户体验相关")]),_._v(" "),t("ul",[t("li",[_._v("易用性:系统易于使用和操作的程度。")]),_._v(" "),t("li",[_._v("可访问性:确保用户能够方便地访问系统或获取信息的程度。")]),_._v(" "),t("li",[_._v("可定制性:允许用户根据自己的特定需求对系统进行个性化设置和调整。")])]),_._v(" "),t("h3",{attrs:{id:"安全与合规相关"}},[_._v("安全与合规相关")]),_._v(" "),t("ul",[t("li",[_._v("可恢复性:系统在出现故障或问题后能够恢复到正常状态的能力。")]),_._v(" "),t("li",[_._v("安全性:保障系统免受各种安全威胁。")]),_._v(" "),t("li",[_._v("认证:确认用户或系统的身份、真实性等的过程。")]),_._v(" "),t("li",[_._v("授权:给予特定用户或实体特定的权利或权限。")]),_._v(" "),t("li",[_._v("可审计性:能够对系统的操作和数据访问进行记录和审查。")]),_._v(" "),t("li",[_._v("法律:与系统或业务相关的法律法规要求。")]),_._v(" "),t("li",[_._v("隐私性:保护用户或系统的私密信息不被泄露的特性。")])]),_._v(" "),t("h3",{attrs:{id:"其他特性"}},[_._v("其他特性")]),_._v(" "),t("ul",[t("li",[_._v("连续性:事物持续不间断的状态。")]),_._v(" "),t("li",[_._v("稳定性:系统在长时间运行过程中保持可靠。")]),_._v(" "),t("li",[_._v("及时性:系统能够在规定的时间内完成任务或响应请求。")]),_._v(" "),t("li",[_._v("互操作性:不同的系统或组件之间能够进行有效的交互和协作。")])]),_._v(" "),t("h2",{attrs:{id:"给架构师的忠告"}},[_._v("给架构师的忠告")]),_._v(" "),t("p",[t("strong",[_._v("第一条,不要执迷于架构特征的数量,要尽可能保证简单")]),_._v(",举个例子,一个用户量只有几万的小项目,你不能执迷于可扩展性,弹性,高可用性这种架构特性,它要的就是简单而已,做好一定的限流措施,就够了。")]),_._v(" "),t("p",[t("strong",[_._v("第二条,确定系统特性的优先级")]),_._v(",比如,我确定了,弹性和性能是优先级,那么该系统的设计就主要围绕这些特性去设计。")]),_._v(" "),t("p",[t("strong",[_._v("第三条,架构师跟外人沟通的时候要使用通用语言")]),_._v(",比如,把可行性和简单行改成预算低,时间短,把性能,容错,降级等改成用户满意度,记住,架构师不仅仅是一个技术人员,也是技术管理者,当一个管理者要沟通的时候,他应该使用通用语言,而不是他的专有语言。")]),_._v(" "),t("p",[t("strong",[_._v("第四条,架构师应该会从需求中提炼架构特征")]),_._v(",比如,1 万人的学校,需要一个搜索系统,那么你可以提取需要的架构特征,人数不大,可用性要高,预算可能不是太充足,所以后期运维要简单,比如一个企业,员工 100 万,需要一个财务系统,那么这个系统就跟刚才的不同,需要满足高可用行,高性能,需要考虑容灾和服务降级,需要考虑高防护性")]),_._v(" "),t("blockquote",[t("p",[t("a",{attrs:{href:"https://www.architecturalkatas.com/",target:"_blank",rel:"noopener noreferrer"}},[_._v("kata"),t("OutboundLink")],1),_._v(" 是架构师 ted neward 创建的架构设计训练网站,里面有很多的需求,我们可以使用这个网站去锻炼自己提取需求的能力,设计架构的能力")])])])}),[],!1,null,null,null);v.default=i.exports}}]); \ No newline at end of file diff --git a/assets/js/49.1d5aec5c.js b/assets/js/49.1d5aec5c.js new file mode 100644 index 00000000..9a165a38 --- /dev/null +++ b/assets/js/49.1d5aec5c.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[49],{485:function(v,_,N){"use strict";N.r(_);var D=N(36),C=Object(D.a)({},(function(){var v=this,_=v.$createElement,N=v._self._c||_;return N("ContentSlotsDistributor",{attrs:{"slot-key":v.$parent.slotKey}},[N("h1",{attrs:{id:"cdn-内容分发网络"}},[v._v("CDN 内容分发网络")]),v._v(" "),N("p",[v._v("我们是用 CDN 就是要解决三个问题\n1。网站服务器接入网络运营商带宽有限的问题\n2。网络各个中间节点连接太长的问题\n3。网站到用户延迟太长的问题")]),v._v(" "),N("p",[v._v("当我们的网站将源地址发送给 CDN 的时候,CDN 服务商就会给你一个 CNAME 网址,例如 shgopher.cdn.github.io")]),v._v(" "),N("blockquote",[N("p",[v._v("CNAME:域名别名")])]),v._v(" "),N("p",[N("strong",[v._v("你得到的 CNAME 会在你的 DNS 服务商注册一条 CNAME 记录")])]),v._v(" "),N("p",[v._v("当第一次未命中 CDN 地址的 DNS 查询,域名服务商解析 CNAME 后会返回给本地 DNS 缓存")]),v._v(" "),N("p",[v._v("当你为你的网站资源部署 CDN 的时候,CDN 域名会在 DNS 或者 HTTP DNS 系统中返回 N 个 IP 地址,这些是位于全国或者全球各个部分,距离用户最近的 IP 地址,所以使用 HTTP DNS + CDN 才能获取最佳的体验")]),v._v(" "),N("p",[v._v("这个时候你访问的 CDN 就会去访问源站,CDN 会将请求转发到源站,源站返回数据,CDN 将数据返回给用户,然后 CDN 就会缓存数据,下次访问的时候直接从缓存中读取,从而减少请求的次数,从而提高网站访问速度")]),v._v(" "),N("p",[v._v("关于 CDN 请求源站的方法其实有两种,一种是被动的,等 cdn 访问就行了,另一种是主动的,就是在部署 cdn 的时候就同时主动去访问源站来形成缓存,一般都采用主动触发加上被动设置缓存失效时间的方式。")]),v._v(" "),N("h2",{attrs:{id:"cdn-寻找最近的-ip"}},[v._v("CDN 寻找最近的 ip")]),v._v(" "),N("p",[v._v("CDN (内容分发网络) 在众多 IP 地址中选中一个距离用户最近的 IP 主要通过以下几种方式:")]),v._v(" "),N("p",[N("strong",[v._v("一、地理定位")])]),v._v(" "),N("p",[v._v("CDN 通常会利用 IP 地址定位技术来确定用户的大致地理位置。每个 IP 地址都可以被映射到一个特定的地理区域,CDN 系统会维护一个庞大的 IP 地址数据库,通过查询这个数据库,能够快速判断用户的位置。例如,根据 IP 地址的分配规则,可以确定某个特定 IP 段来自亚洲地区,更具体地可能来自中国的某个省份或城市。")]),v._v(" "),N("p",[N("strong",[v._v("二、网络测量和延迟评估")])]),v._v(" "),N("p",[N("em",[N("strong",[v._v("主动测量")])])]),v._v(" "),N("p",[v._v("CDN 节点会定期向不同的网络位置发送探测数据包,以测量网络延迟和带宽等参数。这些探测可以针对特定的 IP 地址范围或者广泛的网络区域进行。例如,CDN 节点会向各个主要的网络运营商的骨干节点发送探测包,以了解到不同地区的网络状况。\n通过这些主动测量,CDN 可以建立一个网络延迟矩阵,记录从每个 CDN 节点到不同地理位置的网络延迟情况。当用户请求内容时,CDN 系统可以根据用户的地理位置,查询这个延迟矩阵,找到延迟最小的 CDN 节点对应的 IP 地址返回给用户。")]),v._v(" "),N("p",[N("em",[N("strong",[v._v("被动测量")])])]),v._v(" "),N("p",[v._v("当用户首次访问 CDN 服务时,CDN 系统可以在后台记录"),N("strong",[v._v("用户的请求路径和延迟信息")]),v._v("。")]),v._v(" "),N("p",[v._v("例如,记录用户请求经过的网络路由器、交换机等设备的 IP 地址和延迟时间。通过对大量用户请求的被动测量,CDN 系统可以不断优化对不同地区用户的 IP 地址选择策略。如果发现某个地区的用户普遍对某个特定的 CDN 节点响应速度较快,那么在后续的请求中,对于来自该地区的用户,系统就更有可能选择这个节点的 IP 地址。")]),v._v(" "),N("p",[N("strong",[v._v("三、DNS 智能解析")])]),v._v(" "),N("p",[N("em",[N("strong",[v._v("负载均衡考虑")])])]),v._v(" "),N("p",[v._v("除了距离因素外,CDN 的 DNS 系统还会考虑各个 CDN 节点的负载情况。如果某个距离用户较近的 CDN 节点负载过高,系统可能会选择一个稍微远一些但负载较低的节点,以确保用户能够获得快速稳定的服务。例如,当多个用户同时请求同一内容时,DNS 系统会动态地分配请求到不同的 CDN 节点,以平衡负载。")]),v._v(" "),N("h2",{attrs:{id:"cdn-应用内容"}},[v._v("CDN 应用内容")]),v._v(" "),N("ol",[N("li",[v._v("静态资源:如 CSS、JS、图片等,这些资源可以缓存一段时间,减少请求次数,提高网站性能。")]),v._v(" "),N("li",[v._v("安全防御:CDN 可以作为堡垒机来防范攻击对于源站的影响")]),v._v(" "),N("li",[v._v("协议隔离:很多源站是 http 协议,但是又想使用 https,CDN 可以做协议转换,将 http 协议转换为 https 协议")]),v._v(" "),N("li",[v._v("缓存控制:CDN 可以根据缓存策略来控制缓存时间,例如,对于静态资源,可以设置缓存时间为一年,对于动态资源,可以设置缓存时间为10分钟。")]),v._v(" "),N("li",[v._v("修改资源:CDN 可以修改源站的资源,例如,将源站的图片压缩,将源站的 CSS、JS 合并,将源站的 HTML 压缩等,从而提高网站性能。")]),v._v(" "),N("li",[v._v("访问控制:CDN 可以实现白名单,黑名单的控制,可以根据 ip 的访问流量去限流控制")]),v._v(" "),N("li",[v._v("注入功能:CDN 可以在不改变源站的配置的情况下,向源站注入自定义的脚本,例如,注入广告代码,统计代码等。")]),v._v(" "),N("li",[v._v("充当 VPN 的功能")])])])}),[],!1,null,null,null);_.default=C.exports}}]); \ No newline at end of file diff --git a/assets/js/5.4dbb0540.js b/assets/js/5.4dbb0540.js new file mode 100644 index 00000000..7f2b77eb --- /dev/null +++ b/assets/js/5.4dbb0540.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[5],{400:function(t,e,a){},440:function(t,e,a){"use strict";a(400)},444:function(t,e,a){"use strict";a.r(e);var n={name:"CodeBlock",props:{title:{type:String,required:!0},active:{type:Boolean,default:!1}},mounted:function(){this.$parent&&this.$parent.loadTabs&&this.$parent.loadTabs()}},i=(a(440),a(36)),s=Object(i.a)(n,(function(){var t=this.$createElement;return(this._self._c||t)("div",{staticClass:"theme-code-block",class:{"theme-code-block__active":this.active}},[this._t("default")],2)}),[],!1,null,"759a7d02",null);e.default=s.exports}}]); \ No newline at end of file diff --git a/assets/js/50.df8c4aad.js b/assets/js/50.df8c4aad.js new file mode 100644 index 00000000..69ac676f --- /dev/null +++ b/assets/js/50.df8c4aad.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[50],{487:function(t,s,a){"use strict";a.r(s);var n=a(36),p=Object(n.a)({},(function(){var t=this,s=t.$createElement,a=t._self._c||s;return a("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[a("h1",{attrs:{id:"http-dns-技术"}},[t._v("HTTP DNS 技术")]),t._v(" "),a("p",[t._v("传统本地 DNS 服务器使用 udp 的方式进行多级查询,每一层都有被钓鱼,被更换属于很多的风险,那么我们的本地 DNS 服务器是否可以改为使用 HTTP 协议呢?是否可以不需要逐层查询直接访问到目标服务器?HTTP DNS 就是基于 HTTP 协议的域名解析服务,它将域名解析请求发送到 HTTP 服务器,HTTP 服务器根据域名解析请求直接返回对应的 ip 地址,从而实现域名解析的功能,从而解决了传统 DNS 服务器多级缓存和 DNS 劫持的问题,你可以理解为 HTTP DNS 仿佛一个代理,它就拥有了所有域名解析的功能,并且可以做到无中间商,阿里的 "),a("a",{attrs:{href:"https://www.alibabacloud.com/help/zh/dns/what-is-alibaba-cloud-public-dns",target:"_blank",rel:"noopener noreferrer"}},[t._v("HTTP DNS"),a("OutboundLink")],1),t._v(" 介绍在这里")]),t._v(" "),a("h2",{attrs:{id:"使用-dns-的弊端"}},[t._v("使用 dns 的弊端")]),t._v(" "),a("ol",[a("li",[t._v("传统的 local DNS 服务尽管拥有缓存机制,但不可避免的还是会有递归查询的问题,这严重的影响了响应时间")]),t._v(" "),a("li",[t._v("权威 dns 服务是针对本地域名服务器的 ip 去返回 ip 的,这跟真实用户的 ip 地址不同,严重影响了负载均衡的本意")]),t._v(" "),a("li",[t._v("DNS 劫持,给你一个假网站,运营商通过本地域名服务器直接给你造假 DNS 劫持,黑客选择篡改计算器的 Hosts 去 dns 劫持")])]),t._v(" "),a("h2",{attrs:{id:"http-dns-的原理"}},[t._v("HTTP DNS 的原理")]),t._v(" "),a("p",[t._v("客户端使用 http DNS 去解析域名,HTTP DNS 如果有缓存直接返回,如果没有它会去权威 DNS 服务器发起域名解析请求,并返回最优 ip,这其中减少了去根 dns,顶层 dns 的访问,客户端可能发送一个类似于 “http://11.1.1.1/?dn=[domain_name]” 的请求,其中 “[domain_name]” 是要解析的域名,如果你需要更加安全,也可以将此处的 http 改成 https")]),t._v(" "),a("p",[t._v("客户端通过访问一个固定的 HTTP DNS IP 地址去解析域名,不是通过一个域名 (如果通过域名还不是还得解析这个域名的 ip 嘛。。。对吧)")]),t._v(" "),a("p",[t._v("为了保证高性能和高可用,HTTP DNS 通过 BGP 边界网关协议让这个 ip 地址让全国的运营商客户都能就近访问,同时多个数据中心部署多个 HTTP DNS 服务节点,主备方案,任意节点故障均可切换备份节点")]),t._v(" "),a("h2",{attrs:{id:"配置高可用的-dns-服务-包括-http-dns-和-local-dns"}},[t._v("配置高可用的 DNS 服务 --- 包括 HTTP DNS 和 local DNS")]),t._v(" "),a("ol",[a("li",[t._v("首先我们优先在客户端布置 HTTP DNS 服务")]),t._v(" "),a("li",[t._v("为了防止 HTTP DNS 服务器故障,我们可以在 HTTP DNS 后面部署传统的 local DNS 服务")]),t._v(" "),a("li",[t._v("HTTP DNS 服务可以返回多个 ip 地址,我们可以逐个测试连通性,不通就换下一个")]),t._v(" "),a("li",[t._v("如果本地 local DNS 服务也失败了,我们为了高可用,可以在 app 中硬写入一个映射表,写入一些兜底的 ip 地址")]),t._v(" "),a("li",[t._v("预请求 IP 并且缓存起来")])]),t._v(" "),a("h2",{attrs:{id:"传统使用-udp-协议的-dns-服务请求代码"}},[t._v("传统使用 UDP 协议的 DNS 服务请求代码")]),t._v(" "),a("div",{staticClass:"language-py extra-class"},[a("pre",{pre:!0,attrs:{class:"language-py"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" struct\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" socket\n\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("def")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("send_dns_query")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("domain_name"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" query_type"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 创建 UDP 套接字")]),t._v("\n sock "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" socket"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("socket"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("socket"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("AF_INET"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" socket"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("SOCK_DGRAM"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 从这看出来 使用的是 UDP 的传输协议")]),t._v("\n\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 设置 DNS 服务器地址和端口")]),t._v("\n dns_server "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"8.8.8.8"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("53")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 构造 DNS 请求报文")]),t._v("\n transaction_id "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("0x1234")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 可以设置一个随机的事务 ID")]),t._v("\n flags "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("0x0100")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 标准查询,递归查询标志位设为 1")]),t._v("\n num_questions "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),t._v("\n num_answers "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),t._v("\n num_authority_rrs "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),t._v("\n num_additional_rrs "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),t._v("\n\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 处理域名,采用域名压缩格式")]),t._v("\n parts "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" domain_name"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("split"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'.'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n encoded_domain "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('b""')]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" part "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("in")]),t._v(" parts"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n encoded_domain "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("bytes")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("len")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("part"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+")]),t._v(" part"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("encode"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n encoded_domain "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('b"\\x00"')]),t._v("\n\n query_type_code "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"A"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"AAAA"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("28")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 添加其他查询类型的代码映射")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n qtype "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" query_type_code"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("query_type"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n qclass "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# IN(Internet)类")]),t._v("\n\n request "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" struct"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("pack"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('">HHHHHH"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" transaction_id"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" flags"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" num_questions"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" num_answers"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" num_authority_rrs"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" num_additional_rrs"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n request "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+=")]),t._v(" encoded_domain\n request "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+=")]),t._v(" struct"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("pack"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('">HH"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" qtype"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" qclass"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 发送请求")]),t._v("\n sock"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("sendto"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("request"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" dns_server"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 接收响应")]),t._v("\n response"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" _ "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" sock"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("recvfrom"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("4096")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 处理响应")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("#...(这里省略处理响应报文的具体代码)")]),t._v("\n\n sock"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("close"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])]),a("h2",{attrs:{id:"在浏览器中使用-http-dns"}},[t._v("在浏览器中使用 HTTP DNS")]),t._v(" "),a("p",[t._v("HTTP DNS 通常是为客户端应用程序设计的,而浏览器本身并不直接支持 HTTP DNS\n因此如果要实现 http DNS 通常要使用插件")]),t._v(" "),a("p",[t._v("使用支持 HTTP DNS 的浏览器插件:")]),t._v(" "),a("p",[t._v("一些专门的插件可以在浏览器环境下实现 HTTP DNS 功能。这些插件通常会拦截浏览器的 DNS 请求,然后通过 HTTP 协议将请求发送到特定的 HTTP DNS 服务器进行解析。安装并启用这类插件后,插件会在后台自动处理域名解析,用户无需进行复杂的设置。例如,某些网络优化插件就具备这样的功能,它们可以改善网络访问速度和稳定性,同时防止 DNS 劫持。")]),t._v(" "),a("p",[t._v("浏览器厂商集成 HTTP DNS 功能:")]),t._v(" "),a("p",[t._v("部分先进的浏览器可能会在未来的版本中集成 HTTP DNS 功能。如果浏览器厂商决定支持 HTTP DNS,他们可以在浏览器的设置中提供相应的选项,让用户可以选择启用 HTTP DNS 解析。当用户开启此功能后,浏览器会自动使用 HTTP DNS 服务器进行域名解析,而不再依赖于传统的 DNS 系统。这样可以提高浏览器的安全性和性能,确保用户能够快速、准确地访问网站。")]),t._v(" "),a("p",[t._v("通过网络代理或 VPN 服务:")]),t._v(" "),a("p",[t._v("一些网络代理或 VPN 服务可能会内置 HTTP DNS 功能。当用户连接到这些代理或 VPN 时,它们可以拦截浏览器的网络流量,并使用自己的 HTTP DNS 服务器进行域名解析。这种方式虽然不是直接在浏览器中实现 HTTP DNS,但可以通过第三方服务来实现类似的效果。不过,使用网络代理或 VPN 也可能会带来一些其他问题,如网络速度下降、隐私问题等,因此需要谨慎选择可靠的服务提供商。\n总的来说,目前在浏览器中使用 HTTP DNS 可能需要借助一些额外的工具或服务,但随着技术的发展,未来可能会有更多直接在浏览器中实现 HTTP DNS 的方法出现。")]),t._v(" "),a("h2",{attrs:{id:"在-app-中使用-http-dns"}},[t._v("在 app 中使用 HTTP DNS")]),t._v(" "),a("p",[t._v("许多流行的网络请求库 (如 OkHttp、Volley 等) 支持自定义 DNS 解析器。可以通过编写自定义的 DNS 解析器来实现 HTTP DNS 功能。")]),t._v(" "),a("div",{staticClass:"language-java extra-class"},[a("pre",{pre:!0,attrs:{class:"language-java"}},[a("code",[a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("OkHttpClient")]),t._v(" client "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("new")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("OkHttpClient"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("Builder")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("dns")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("new")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("MyHttpDnsResolver")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("build")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),a("p",[t._v("全局设置 http dns")]),t._v(" "),a("div",{staticClass:"language-java extra-class"},[a("pre",{pre:!0,attrs:{class:"language-java"}},[a("code",[a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("HttpDnsManager")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("getInstance")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("init")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"your_http_dns_server_url"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),a("h2",{attrs:{id:"在-http-dns-中的本地缓存优先级"}},[t._v("在 HTTP DNS 中的本地缓存优先级")]),t._v(" "),a("p",[t._v("HTTP DNS 请求是由应用层直接发起的,而不是通过操作系统的 DNS 解析器。这意味着 HTTP DNS 请求不会经过传统的 DNS 解析路径,包括不会检查 hosts 文件或操作系统的 DNS 缓存")]),t._v(" "),a("p",[t._v("HTTP DNS 场景下的缓存优先级:")]),t._v(" "),a("ol",[a("li",[t._v("HTTP DNS 服务端返回的数据:应用程序直接从 HTTP DNS 服务端获取域名解析结果,并根据返回的信息进行后续操作。")]),t._v(" "),a("li",[t._v("应用程序内部缓存:应用程序可能会在内部缓存 HTTP DNS 返回的结果,以便在一定时间内重复使用这些信息。")])]),t._v(" "),a("p",[t._v("所以 HTTP DNS 系统的本地客户端缓存:")]),t._v(" "),a("ul",[a("li",[t._v("不会检查 /etc/hosts 文件。")]),t._v(" "),a("li",[t._v("不会查询操作系统的 DNS 缓存。")]),t._v(" "),a("li",[t._v("不会依赖浏览器的 DNS 缓存。")])])])}),[],!1,null,null,null);s.default=p.exports}}]); \ No newline at end of file diff --git a/assets/js/51.baf9f53b.js b/assets/js/51.baf9f53b.js new file mode 100644 index 00000000..1519658f --- /dev/null +++ b/assets/js/51.baf9f53b.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[51],{488:function(t,a,s){"use strict";s.r(a);var e=s(36),n=Object(e.a)({},(function(){var t=this,a=t.$createElement,s=t._self._c||a;return s("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[s("h1",{attrs:{id:"http-缓存"}},[t._v("HTTP 缓存")]),t._v(" "),s("p",[t._v("HTTP 缓存指的是不经过后端,客户端直接根据缓存的内容对目标网站状态进行判断。")]),t._v(" "),s("p",[t._v("常见的 HTTP 缓存的典型应用就是 301 重定向,你会发现如果你不手动删除浏览器缓存,服务器设置的新的 301 重定向,浏览器还是读取旧的缓存,而不是重新请求。")]),t._v(" "),s("h2",{attrs:{id:"http-强制缓存"}},[t._v("HTTP 强制缓存")]),t._v(" "),s("p",[t._v("强制缓存,强制你去缓存,设置一个时间,这个时间内,你后端不管咋变,反正我都给你缓存了")]),t._v(" "),s("ul",[s("li",[t._v("Expires")]),t._v(" "),s("li",[t._v("Cache-Control")])]),t._v(" "),s("p",[t._v("用后面那个,前面那个设置的不完善,设计的 bug 很多")]),t._v(" "),s("h2",{attrs:{id:"协商缓存"}},[t._v("协商缓存")]),t._v(" "),s("p",[t._v("协商缓存跟强制缓存不同,它没有规定时间段内必须缓存的机制,当你设置参数时它才会去缓存,所以属于协商机制")]),t._v(" "),s("ul",[s("li",[t._v("Last-Modified if-modified-since:Last-Modified 服务器响应时返回的 header,告知客户端这个资源的最后修改时间,当客户端再次请求的时候会通过 if-modified-since 把之前收到的资源最后修改时间传给服务器,服务器根据这个时间判断是否需要返回最新资源,如果不需要返回最新资源,则返回 304")])]),t._v(" "),s("p",[t._v("比如 last-modified:Wed,08 Jun 2016 08:05:08 GMT,最后的修改时间是 8 点5分8秒,那么客户端的下次请求就将这个时间发送给服务器,服务器去查看资源有没有更新的版本,如果没有就返回 304,如果有就返回新的资源和新的 last-modified")]),t._v(" "),s("ul",[s("li",[t._v("ETag 和 if-none-match 跟上面的那一对差不多其实,只是这个 Etag 是一个资源唯一标识,如果客户端发送的 if-none-match 和这个 ETag 相同,则返回 304,服务器根据这个 ETag 判断是否需要返回最新资源")])]),t._v(" "),s("p",[t._v("那么 Etag 机制和 Last-Modified 机制有什么区别呢?"),s("strong",[t._v("Etag 精度高但是性能差,因为它需要计算哈希值嘛,而 Last-Modified 精度低但是性能高,它只需要比较时间戳")])]),t._v(" "),s("h3",{attrs:{id:"内容协商机制"}},[t._v("内容协商机制")]),t._v(" "),s("p",[t._v("在 http 协议中,一个 url 地址是可能根据比如语言不同,压缩方法不同,一个 URL 返回不同的资源的,所以我们需要设置 Accept-"),s("em",[t._v("和 content-")]),t._v(" 去协商内容的,使用 Vay 标识符去设置协商内容")]),t._v(" "),s("div",{staticClass:"language-js extra-class"},[s("pre",{pre:!0,attrs:{class:"language-js"}},[s("code",[s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("//客户端请求:")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token constant"}},[t._v("GET")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("/")]),t._v("resource "),s("span",{pre:!0,attrs:{class:"token constant"}},[t._v("HTTP")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("/")]),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("1.1")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token literal-property property"}},[t._v("Host")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" example"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("com\nAccept"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("-")]),t._v("Language"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" zh"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("-")]),s("span",{pre:!0,attrs:{class:"token constant"}},[t._v("CN")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("zh"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("q"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("0.9")]),t._v("\nUser"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("-")]),t._v("Agent"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("Your User"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("-")]),t._v("Agent String"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n\n\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 服务器响应:")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token constant"}},[t._v("HTTP")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("/")]),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("1.1")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("200")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token constant"}},[t._v("OK")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token literal-property property"}},[t._v("Vary")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" Accept"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("-")]),t._v("Language"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" User"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("-")]),t._v("Agent "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Vay是服务器告知客户端,服务器将根据vay后面的字段来返回不同的资源内容")]),t._v("\nContent"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("-")]),t._v("Language"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" zh"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("-")]),s("span",{pre:!0,attrs:{class:"token constant"}},[t._v("CN")]),t._v("\nContent"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("-")]),t._v("Type"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("Appropriate Content"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("-")]),t._v("Type"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("Resource Content "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("in")]),t._v(" Chinese Simplified"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n\n")])])]),s("p",[t._v("原理:当客户端发送请求时,Accept-Language 传达了语言偏好,同时 User-Agent 可以提供关于客户端类型等信息。服务器在响应时,将 Accept-Language 和 User-Agent 放在 Vary 响应头后面,表示缓存机制需要根据这两个请求头的值来决定是否返回缓存的资源。如果不同的客户端发送的 Accept-Language 或 User-Agent 不同,服务器可能会返回不同版本的资源。这样可以确保在不同语言偏好和不同客户端类型的情况下,都能为用户提供最合适的资源内容。")]),t._v(" "),s("h3",{attrs:{id:"协商机制的失效"}},[t._v("协商机制的失效")]),t._v(" "),s("p",[t._v("协商机制在地址输入,跳转,甚至刷新的时候都会生效,如果想让失效,只能强制刷新 control+ F5 或者禁止缓存才会失效,失效的话,客户端就会向服务器发送 “Cache-Control:no-cache” 的标志,服务器如果获取这个标识就会发生新的资源")]),t._v(" "),s("h3",{attrs:{id:"协商机制的局限性"}},[t._v("协商机制的局限性")]),t._v(" "),s("p",[t._v("http 协议并非强制性协议,服务器也可以完全不 care 这个 no-cache 标志,不过这属于服务器设计与实际预期不一致的情况,属于设计不规范的行为。")])])}),[],!1,null,null,null);a.default=n.exports}}]); \ No newline at end of file diff --git a/assets/js/52.02b36727.js b/assets/js/52.02b36727.js new file mode 100644 index 00000000..061a5005 --- /dev/null +++ b/assets/js/52.02b36727.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[52],{489:function(t,e,n){"use strict";n.r(e);var s=n(36),l=Object(s.a)({},(function(){var t=this.$createElement;return(this._self._c||t)("ContentSlotsDistributor",{attrs:{"slot-key":this.$parent.slotKey}})}),[],!1,null,null,null);e.default=l.exports}}]); \ No newline at end of file diff --git a/assets/js/53.d2fcd1c5.js b/assets/js/53.d2fcd1c5.js new file mode 100644 index 00000000..6cc2fcd1 --- /dev/null +++ b/assets/js/53.d2fcd1c5.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[53],{490:function(e,n,l){"use strict";l.r(n);var t=l(36),o=Object(t.a)({},(function(){var e=this,n=e.$createElement,l=e._self._c||n;return l("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[l("h1",{attrs:{id:"web-服务器-nginx"}},[e._v("web 服务器 Nginx")]),e._v(" "),l("p",[e._v("web 服务器 (web server) 又叫做 HTTP 服务器,它有两大功能,其一是承载了 HTML JS CSS 等静态资源,第二是接收来自浏览器的请求,并返回响应。")]),e._v(" "),l("p",[e._v("常见的 web 服务器有 Apache Nginx,当然现在更多的使用 GO Nodejs 去构建服务,充当了 web 服务器")]),e._v(" "),l("p",[e._v("关于 GO 去充当 web 服务器的,可以去查阅 "),l("a",{attrs:{href:"https://github.com/shgopher/GOFamily",target:"_blank",rel:"noopener noreferrer"}},[e._v("GOFamily"),l("OutboundLink")],1),e._v(",本章主要介绍 Nginx 充当 web 服务器这个功能的使用,至于 Nginx 的七层负载均衡的使用可以查看本章的"),l("RouterLink",{attrs:{to:"/系统设计基础/网络在系统设计中的作用/负载均衡/"}},[e._v("负载均衡")])],1),e._v(" "),l("p",[e._v("Nginx 性能非常的不错,这跟它使用了基于事件驱动的并发模型有关")]),e._v(" "),l("p",[e._v("Nginx 使用了主进程去管理工作进程,每一个工作进程都是一个单线程,所以 Nginx 属于多进程和单线程结合的模型,每一个线程都是使用基于事件驱动的并发模型去处理高 io,这跟 js 的并发模型是一致的。")]),e._v(" "),l("blockquote",[l("p",[e._v("基于事件驱动的并发模型之所以会设计成单线程模型,主要有四个原因:1。避免线程切换带来的开销,2。简化并发模型 3。单线程更易水平扩展 4。单线程 cpu 缓存命中率高")])]),e._v(" "),l("p",[e._v("由于 nginx 并没有并行的需求,所以对于一个只考虑高 IO 的设备来说,基于事件驱动的单线程回调模型性能更好,实现更简单,出错率更低。")]),e._v(" "),l("h2",{attrs:{id:"epoll-事件驱动的模型产物"}},[e._v("epoll --- 事件驱动的模型产物")]),e._v(" "),l("p",[l("strong",[e._v("io 多路复用:")])]),e._v(" "),l("p",[e._v("IO 多路复用允许一个进程同时监视多个文件描述符 (或者其它的内容),当其中任何一个文件描述符变为可读或可写状态时,进程就会被通知,从而可以进行相应的读写操作。这样,进程就"),l("strong",[e._v("不需要为每个文件描述符都创建一个单独的线程或进程来进行阻塞式的等待,而是可以在一个线程中高效地处理多个文件描述符")])]),e._v(" "),l("p",[e._v("**事件驱动的并发模型:**基于事件,当事件触发的时候即可执行之前注册的 callback 函数。当没有触发事件的时候,callback 函数处于等待状态。具体到 epoll 的实现上,它使用一个红黑树去管理文件描述符。当文件描述符上的事件发生时,epoll 会将事件通知放入一个就绪列表中,随后用户程序可以从就绪列表中获取事件,并根据事件类型执行相应的 callback 函数进行处理。")]),e._v(" "),l("p",[e._v("epoll 是 linux 内核提供的一个事件驱动的基于 io 多路复用并发模型,它基于事件驱动的回调模型,在 linux 中,每一个文件描述符都可以注册一个事件,当文件描述符发生变化的时候,内核会通知应用层,应用层通过回调函数处理,并且建议一个通道,复用多个 io,这样就完成了高并发的处理")]),e._v(" "),l("p",[e._v("Nginx 利用了 Linux 内核的 epoll API 来实现了海量流量的处理,Nginx 的工作进程通过 epoll 来监听客户端的请求,当有客户端请求的时候,nginx 会通过回调函数处理请求,处理完请求后,nginx 会通过 epoll 将请求响应给客户端。")])])}),[],!1,null,null,null);n.default=o.exports}}]); \ No newline at end of file diff --git a/assets/js/54.3f8b19d6.js b/assets/js/54.3f8b19d6.js new file mode 100644 index 00000000..8c8b9861 --- /dev/null +++ b/assets/js/54.3f8b19d6.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[54],{491:function(t,r,i){"use strict";i.r(r);var o=i(36),e=Object(o.a)({},(function(){var t=this,r=t.$createElement,i=t._self._c||r;return i("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[i("h1",{attrs:{id:"网络在系统设计中的重要作用"}},[t._v("网络在系统设计中的重要作用")]),t._v(" "),i("ul",[i("li",[i("RouterLink",{attrs:{to:"/系统设计基础/网络在系统设计中的作用/多级分流/"}},[t._v("系统的多级分流")])],1),t._v(" "),i("li",[i("RouterLink",{attrs:{to:"/系统设计基础/网络在系统设计中的作用/HTTP缓存/"}},[t._v("HTTP 缓存")])],1),t._v(" "),i("li",[i("RouterLink",{attrs:{to:"/系统设计基础/网络在系统设计中的作用/DNS/"}},[t._v("DNS")])],1),t._v(" "),i("li",[i("RouterLink",{attrs:{to:"/系统设计基础/网络在系统设计中的作用/HTTPDNS/"}},[t._v("HTTP DNS")])],1),t._v(" "),i("li",[i("RouterLink",{attrs:{to:"/系统设计基础/网络在系统设计中的作用/传输链路/"}},[t._v("传输链路")])],1),t._v(" "),i("li",[i("RouterLink",{attrs:{to:"/系统设计基础/网络在系统设计中的作用/CDN/"}},[t._v("CDN")])],1),t._v(" "),i("li",[i("RouterLink",{attrs:{to:"/系统设计基础/网络在系统设计中的作用/Nginx/"}},[t._v("web 服务器")])],1),t._v(" "),i("li",[i("RouterLink",{attrs:{to:"/系统设计基础/网络在系统设计中的作用/负载均衡/"}},[t._v("负载均衡")])],1),t._v(" "),i("li",[i("RouterLink",{attrs:{to:"/系统设计基础/网络在系统设计中的作用/API网关/"}},[t._v("API 网关 (应用网关)")])],1),t._v(" "),i("li",[i("RouterLink",{attrs:{to:"/系统设计基础/网络在系统设计中的作用/SDN/"}},[t._v("SDN")])],1),t._v(" "),i("li",[i("RouterLink",{attrs:{to:"/系统设计基础/网络在系统设计中的作用/clickAWebSite/"}},[t._v("面试题:当你点击访问一个网站时,到底经历什么什么步骤")])],1)])])}),[],!1,null,null,null);r.default=e.exports}}]); \ No newline at end of file diff --git a/assets/js/55.0cc09109.js b/assets/js/55.0cc09109.js new file mode 100644 index 00000000..68f82111 --- /dev/null +++ b/assets/js/55.0cc09109.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[55],{492:function(t,e,s){"use strict";s.r(e);var n=s(36),i=Object(n.a)({},(function(){var t=this,e=t.$createElement,s=t._self._c||e;return s("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[s("h1",{attrs:{id:"经典面试题之当你点击一个网站的时候到底经历了什么步骤"}},[t._v("经典面试题之当你点击一个网站的时候到底经历了什么步骤")]),t._v(" "),s("h2",{attrs:{id:"客户端"}},[t._v("客户端")]),t._v(" "),s("p",[t._v("点击 "),s("code",[t._v("www.baidu.com")]),t._v(" -> 查询本地 DNS 缓存系统,没有就查询各级 DNS 服务器 (App 可以直接使用 HTTP DNS 系统) 查询到 ip 地址 -> 通过 ip 地址访问到目标路由器,(可能通过 DNS 查询到多个 ip 地址) -> 进入到交换机中 -> 进入 lvs 系统 -> 进入 API 网关 -> 如果是 web,就开始返回 HTML 给浏览器,进而在 HTML 中点击其他的链接去访问 BAAS 服务,在这个过程中,通常会使用 https 的方式建立一个长链接 (时间较长的连接),这个过程中双方会有协商,交换密钥,使用 io 多路复用等处理方案")]),t._v(" "),s("p",[t._v("比如在 web 中请求了一个图片,那么这个请求很有可能就是一个 cdn 的请求")]),t._v(" "),s("h2",{attrs:{id:"后端"}},[t._v("后端")])])}),[],!1,null,null,null);e.default=i.exports}}]); \ No newline at end of file diff --git a/assets/js/56.4c5bb99a.js b/assets/js/56.4c5bb99a.js new file mode 100644 index 00000000..a43e1765 --- /dev/null +++ b/assets/js/56.4c5bb99a.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[56],{496:function(t,s,n){"use strict";n.r(s);var a=n(36),p=Object(a.a)({},(function(){var t=this,s=t.$createElement,n=t._self._c||s;return n("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[n("h1",{attrs:{id:"传输链路优化"}},[t._v("传输链路优化")]),t._v(" "),n("p",[t._v("虽然我们不能左右网络提供商例如联通移动的网络质量,但是我们可以通过一些手段来优化传输链路。")]),t._v(" "),n("ol",[n("li",[t._v("用 HTTP2 替代 HTTP 1.1")])]),t._v(" "),n("p",[t._v("尽管我们在 1.1 的版本中使用了例如 keep-alive 的方法去保持长连接,然后让所有的请求按照 FIFO 的方法去请求,进而减少三次握手所带来的时间延迟,但随之而来的队列阻塞问题也是一个很大的缺陷。")]),t._v(" "),n("p",[t._v("HTTP1.1 中流是最小的单位,在 1.1 中我们没办法将请求拆开,一起发送,因为客户端无法识别这些碎片,然而 HTTP2 帧 (frame) 是最小的单位,用来描述各种资源,每个帧只要带上唯一标识就能判断是同属一个流,客户端可以通过标识来组装成一个完整的流")]),t._v(" "),n("p",[t._v("通过 io 多路复用,每一个域名仅需一个 TCP 的连接,我们可以任意传输资源,因为不需要考虑 tcp 的延迟问题,所以我们也不用刻意缩小连接的次数,所以在 1.1 上把小数据改成大数据的优化方法在 2 上反而变成了反模式,不过 2 中传输大数据如果不分片的话,反而比 1.1 要慢,毕竟你单点人 1.1 是多路分布式传输肯定比你更快了。")]),t._v(" "),n("p",[t._v("应用层 HTTP 的传输层协议在 1.1 和2时代都是 TCP 协议,然而在 HTTP3 的时候我们将 TCP 协议替换为 UDP 协议,UDP 没有丢包重传的机制,UDP 传了就不管了,所以 http3 的可靠性不依靠传输层,而是在应用层上进行安全设置的,HTTP3 可以对每一个流都能单独控制,在 2 的时候 io 多路复用,TCP 协议接收到了大量的数据然后遇到了损坏,这个时候又要开始重传,这就是 HTTP2 传输大文件慢的原因,HTTP3 不使用 TCP 所以它没有这个缺陷,tcp 在连接时不可避免的会三次握手,这在游戏等领域存在了超时,中断,重连,这个过程带来的问题非常的难受,HTTP3 拥有连接标识符,这个唯一标识符就是标识了客户端和浏览器的连接 token,切换网络的时候,只需要向服务器发送一个包含该 token 的数据包就可以重新连接了,即便 IP 地址发生更改也可以连接")]),t._v(" "),n("p",[t._v("总结一下,搞什么优化,用 HTTP3 不香吗?")]),t._v(" "),n("p",[t._v("下面演示一下 HTTP3 tls 证书,ipv6 的静态服务器")]),t._v(" "),n("div",{staticClass:"language-go extra-class"},[n("pre",{pre:!0,attrs:{class:"language-go"}},[n("code",[n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("package")]),t._v(" main\n\n"),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string"}},[t._v('"github.com/gin-gonic/gin"')]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string"}},[t._v('"github.com/quic-go/quic-go/http3"')]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token string"}},[t._v('"log"')]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n"),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("func")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("main")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n router "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":=")]),t._v(" gin"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("Default")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n router"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("Static")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token string"}},[t._v('"/"')]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string"}},[t._v('"./static"')]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 指定现成的 TLS 证书和私钥文件路径")]),t._v("\n tlsCertPath "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":=")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string"}},[t._v('"path/to/your/cert.pem"')]),t._v("\n tlsKeyPath "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":=")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string"}},[t._v('"path/to/your/key.pem"')]),t._v("\n\n server "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":=")]),t._v(" http3"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("Server"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 可以自动开启ipv6和ipv4")]),t._v("\n Addr"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string"}},[t._v('":8080"')]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n Handler"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" router"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n TLSConfig"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("generateTLSConfig")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("tlsCertPath"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" tlsKeyPath"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n err "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":=")]),t._v(" server"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("ListenAndServeTLS")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token string"}},[t._v('""')]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token string"}},[t._v('""')]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" err"),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!=")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("nil")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("panic")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("err"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n"),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("func")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("generateTLSConfig")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("certPath"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" keyPath "),n("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("string")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),t._v("http3"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("TLSConfig "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("http3"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("TLSConfig"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n Certificates"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("loadCertificates")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("certPath"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" keyPath"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n"),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("func")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("loadCertificates")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("certPath"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" keyPath "),n("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("string")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("http3"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("TLSConfigCertificate "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n cert"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" err "),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":=")]),t._v(" tls"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("LoadX509KeyPair")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("certPath"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" keyPath"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" err"),n("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!=")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("nil")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n log"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),n("span",{pre:!0,attrs:{class:"token function"}},[t._v("Fatalf")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),n("span",{pre:!0,attrs:{class:"token string"}},[t._v('"加载证书和私钥失败: %v"')]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" err"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("http3"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("TLSConfigCertificate"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("cert"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])])])}),[],!1,null,null,null);s.default=p.exports}}]); \ No newline at end of file diff --git a/assets/js/57.e2d39181.js b/assets/js/57.e2d39181.js new file mode 100644 index 00000000..91a2a537 --- /dev/null +++ b/assets/js/57.e2d39181.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[57],{494:function(t,n,v){"use strict";v.r(n);var _=v(36),l=Object(_.a)({},(function(){var t=this,n=t.$createElement,v=t._self._c||n;return v("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[v("h1",{attrs:{id:"系统的多级分流"}},[t._v("系统的多级分流")]),t._v(" "),v("p",[t._v("我们使用的现在互联网系统,都存在多个分流的装置,从最开始的 DNS 开始就可以部署分流,继而去到网关,负载均衡器,缓存,服务集群,数据库集群,等等。")]),t._v(" "),v("p",[t._v("分流系统根据所在的部位不同也可以分为不同的种类")]),t._v(" "),v("ul",[v("li",[t._v("客户端等位于用户最近的部分,例如 http 本地缓存,可以减少后端的 io 数量,dns 缓存,减少 dns 的请求数量,cdn,反向代理,这些都是位于客户端的分流系统")]),t._v(" "),v("li",[t._v("可线性扩展的构建,比如分布式缓存,数据库集群")]),t._v(" "),v("li",[t._v("运维构建,例如,注册中心,配置中心,这种辅助的系统,对于整个系统至关重要,对于这些影响全局的运维构建,必须部署集群,来时刻提高容灾能力")]),t._v(" "),v("li",[t._v("容易形成单点的部件,必须提高竖向能力,也就是提示该机器的性能,比如负载均衡器,网关,入口路由")])]),t._v(" "),v("h2",{attrs:{id:"设计要点"}},[t._v("设计要点")]),t._v(" "),v("ul",[v("li",[v("strong",[t._v("减少单点服务的数量,提高单点服务的性能")])]),t._v(" "),v("li",[v("strong",[t._v("最大程度减少达到单点部件的流量,尽可能让需求分流")]),t._v(",比如一个数据,http 缓存可以提供,cdn 可以提供,web 服务器可以提供,后端服务可以提供,数据库可以提供,那么就应该让各个组件分流这些请求,能用 http 缓存的流量就别后面请求,能让 cdn 提供的,就分流一部分给 cdn。")]),t._v(" "),v("li",[v("strong",[t._v("简单的系统才是好系统")]),t._v(",在满足需求的情况下,系统越简单越好,组件越多,出错的几率越高")])])])}),[],!1,null,null,null);n.default=l.exports}}]); \ No newline at end of file diff --git a/assets/js/58.7285a164.js b/assets/js/58.7285a164.js new file mode 100644 index 00000000..fe16ea41 --- /dev/null +++ b/assets/js/58.7285a164.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[58],{497:function(t,e,n){"use strict";n.r(e);var s=n(36),l=Object(s.a)({},(function(){var t=this.$createElement;return(this._self._c||t)("ContentSlotsDistributor",{attrs:{"slot-key":this.$parent.slotKey}})}),[],!1,null,null,null);e.default=l.exports}}]); \ No newline at end of file diff --git a/assets/js/59.c6ac4490.js b/assets/js/59.c6ac4490.js new file mode 100644 index 00000000..5fc369e9 --- /dev/null +++ b/assets/js/59.c6ac4490.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[59],{498:function(t,e,n){"use strict";n.r(e);var s=n(36),l=Object(s.a)({},(function(){var t=this.$createElement;return(this._self._c||t)("ContentSlotsDistributor",{attrs:{"slot-key":this.$parent.slotKey}})}),[],!1,null,null,null);e.default=l.exports}}]); \ No newline at end of file diff --git a/assets/js/6.88270a80.js b/assets/js/6.88270a80.js new file mode 100644 index 00000000..40665310 --- /dev/null +++ b/assets/js/6.88270a80.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[6],{401:function(e,t,a){},441:function(e,t,a){"use strict";a(401)},445:function(e,t,a){"use strict";a.r(t);a(96),a(45),a(10),a(99),a(100);var o={name:"CodeGroup",data:function(){return{codeTabs:[],activeCodeTabIndex:-1}},watch:{activeCodeTabIndex:function(e){this.activateCodeTab(e)}},mounted:function(){this.loadTabs()},methods:{changeCodeTab:function(e){this.activeCodeTabIndex=e},loadTabs:function(){var e=this;this.codeTabs=(this.$slots.default||[]).filter((function(e){return Boolean(e.componentOptions)})).map((function(t,a){return""===t.componentOptions.propsData.active&&(e.activeCodeTabIndex=a),{title:t.componentOptions.propsData.title,elm:t.elm}})),-1===this.activeCodeTabIndex&&this.codeTabs.length>0&&(this.activeCodeTabIndex=0),this.activateCodeTab(0)},activateCodeTab:function(e){this.codeTabs.forEach((function(e){e.elm&&e.elm.classList.remove("theme-code-block__active")})),this.codeTabs[e].elm&&this.codeTabs[e].elm.classList.add("theme-code-block__active")}}},n=(a(441),a(36)),c=Object(n.a)(o,(function(){var e=this,t=e.$createElement,a=e._self._c||t;return a("ClientOnly",[a("div",{staticClass:"theme-code-group"},[a("div",{staticClass:"theme-code-group__nav"},[a("ul",{staticClass:"theme-code-group__ul"},e._l(e.codeTabs,(function(t,o){return a("li",{key:t.title,staticClass:"theme-code-group__li"},[a("button",{staticClass:"theme-code-group__nav-tab",class:{"theme-code-group__nav-tab-active":o===e.activeCodeTabIndex},on:{click:function(t){return e.changeCodeTab(o)}}},[e._v("\n "+e._s(t.title)+"\n ")])])})),0)]),e._v(" "),e._t("default"),e._v(" "),e.codeTabs.length<1?a("pre",{staticClass:"pre-blank"},[e._v("// Make sure to add code blocks to your code group")]):e._e()],2)])}),[],!1,null,"deefee04",null);t.default=c.exports}}]); \ No newline at end of file diff --git a/assets/js/60.110aa8a1.js b/assets/js/60.110aa8a1.js new file mode 100644 index 00000000..b5b2dafe --- /dev/null +++ b/assets/js/60.110aa8a1.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[60],{499:function(t,e,n){"use strict";n.r(e);var s=n(36),l=Object(s.a)({},(function(){var t=this.$createElement;return(this._self._c||t)("ContentSlotsDistributor",{attrs:{"slot-key":this.$parent.slotKey}})}),[],!1,null,null,null);e.default=l.exports}}]); \ No newline at end of file diff --git a/assets/js/61.a14d2cd8.js b/assets/js/61.a14d2cd8.js new file mode 100644 index 00000000..4dd186f0 --- /dev/null +++ b/assets/js/61.a14d2cd8.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[61],{501:function(t,e,n){"use strict";n.r(e);var s=n(36),l=Object(s.a)({},(function(){var t=this.$createElement;return(this._self._c||t)("ContentSlotsDistributor",{attrs:{"slot-key":this.$parent.slotKey}})}),[],!1,null,null,null);e.default=l.exports}}]); \ No newline at end of file diff --git a/assets/js/62.ec556a2a.js b/assets/js/62.ec556a2a.js new file mode 100644 index 00000000..8f1dcef2 --- /dev/null +++ b/assets/js/62.ec556a2a.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[62],{500:function(t,e,n){"use strict";n.r(e);var s=n(36),l=Object(s.a)({},(function(){var t=this.$createElement;return(this._self._c||t)("ContentSlotsDistributor",{attrs:{"slot-key":this.$parent.slotKey}})}),[],!1,null,null,null);e.default=l.exports}}]); \ No newline at end of file diff --git a/assets/js/63.fdcf5105.js b/assets/js/63.fdcf5105.js new file mode 100644 index 00000000..474ea562 --- /dev/null +++ b/assets/js/63.fdcf5105.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[63],{502:function(t,e,n){"use strict";n.r(e);var s=n(36),l=Object(s.a)({},(function(){var t=this.$createElement;return(this._self._c||t)("ContentSlotsDistributor",{attrs:{"slot-key":this.$parent.slotKey}})}),[],!1,null,null,null);e.default=l.exports}}]); \ No newline at end of file diff --git a/assets/js/64.7eab1b29.js b/assets/js/64.7eab1b29.js new file mode 100644 index 00000000..bc31562c --- /dev/null +++ b/assets/js/64.7eab1b29.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[64],{504:function(t,e,n){"use strict";n.r(e);var s=n(36),l=Object(s.a)({},(function(){var t=this.$createElement;return(this._self._c||t)("ContentSlotsDistributor",{attrs:{"slot-key":this.$parent.slotKey}})}),[],!1,null,null,null);e.default=l.exports}}]); \ No newline at end of file diff --git a/assets/js/65.c72267e4.js b/assets/js/65.c72267e4.js new file mode 100644 index 00000000..7069ee76 --- /dev/null +++ b/assets/js/65.c72267e4.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[65],{503:function(t,e,n){"use strict";n.r(e);var s=n(36),l=Object(s.a)({},(function(){var t=this.$createElement;return(this._self._c||t)("ContentSlotsDistributor",{attrs:{"slot-key":this.$parent.slotKey}})}),[],!1,null,null,null);e.default=l.exports}}]); \ No newline at end of file diff --git a/assets/js/66.2179da8e.js b/assets/js/66.2179da8e.js new file mode 100644 index 00000000..9675fca5 --- /dev/null +++ b/assets/js/66.2179da8e.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[66],{505:function(t,e,n){"use strict";n.r(e);var s=n(36),l=Object(s.a)({},(function(){var t=this.$createElement;return(this._self._c||t)("ContentSlotsDistributor",{attrs:{"slot-key":this.$parent.slotKey}})}),[],!1,null,null,null);e.default=l.exports}}]); \ No newline at end of file diff --git a/assets/js/7.6a32d15b.js b/assets/js/7.6a32d15b.js new file mode 100644 index 00000000..d87f0fdf --- /dev/null +++ b/assets/js/7.6a32d15b.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[7],{437:function(t,s,a){t.exports=a.p+"assets/img/nginx-proxy.d43eb7ba.svg"},438:function(t,s,a){t.exports=a.p+"assets/img/nginx-hot-update.83988ad2.svg"},495:function(t,s,a){"use strict";a.r(s);var n=a(36),e=Object(n.a)({},(function(){var t=this,s=t.$createElement,n=t._self._c||s;return n("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[n("h1",{attrs:{id:"负载均衡"}},[t._v("负载均衡")]),t._v(" "),n("p",[t._v("一共分为七层网络模型,分别是")]),t._v(" "),n("ul",[n("li",[t._v("7 应用层:http")]),t._v(" "),n("li",[t._v("6 表达层")]),t._v(" "),n("li",[t._v("5 会话层")]),t._v(" "),n("li",[t._v("4 传输层:tcp")]),t._v(" "),n("li",[t._v("3 网络层:ip")]),t._v(" "),n("li",[t._v("2 数据链路层:wifi")]),t._v(" "),n("li",[t._v("1 物理层:物理网卡")])]),t._v(" "),n("h2",{attrs:{id:"四层负载均衡"}},[t._v("四层负载均衡")]),t._v(" "),n("p",[t._v("四层负载均衡的意思是指的是这些负载均衡的工作模式特点是维持同一个 tcp 连接,并不是第四层的负载均衡,但是其实做负载均衡的是在第二层和第三层")]),t._v(" "),n("h3",{attrs:{id:"二层"}},[t._v("二层")]),t._v(" "),n("p",[t._v("数据链路层传输的内容是数据帧,我们这里讨论的是以太网帧,其中以太网帧还有很多的数据,我们关注 MAC 目标地址和 Mac 源地址,每一块网卡都有一个专属直接的 Mac 地址,以太帧会告诉交换机此连接从哪个网卡来的到哪个网卡去的。")]),t._v(" "),n("p",[t._v("链路层要做的转发就是将目标帧的 MAC 地址给修改了,对于三层来说,根本察觉不到,这才是真的转发,而不是代理")]),t._v(" "),n("p",[t._v("只要真实服务器的 ip 地址保证跟数据包中的 ip 地址一致,数据就可以被转发")]),t._v(" "),n("p",[t._v("我们要做的就是将真实物理服务器所在的虚拟 ip 地址配置成跟负载均衡器的虚拟 ip 一致即可")]),t._v(" "),n("blockquote",[n("p",[t._v("虚拟 IP 地址的实现方式通常是通过软件来进行配置和管理。例如,在网络设备、服务器操作系统或者负载均衡软件中,可以设置虚拟 IP 地址,并将其与特定的服务或应用程序关联起来。同时,虚拟 IP 地址也需要与网络基础设施进行配合,确保数据包能够正确地路由到对应的服务器上。")])]),t._v(" "),n("p",[t._v("这种转发叫做三角模式,因为响应就不需要经过转发器了")]),t._v(" "),n("p",[t._v("二层负载均衡器有个缺点就是只能在"),n("strong",[t._v("一个子网中使用")]),t._v(",因为它是修改的 mac 地址,这就说明它与真实的服务器通信必须是二层可达的状态。")]),t._v(" "),n("h3",{attrs:{id:"三层"}},[t._v("三层")]),t._v(" "),n("p",[t._v("以 ip 协议为例,ip 协议包括 headers 和 payload,其中我们只关注 headers 中的源 ip 和目标 ip")]),t._v(" "),n("p",[t._v("三层负载均衡有两种转发模式")]),t._v(" "),n("p",[t._v("第一种,保持原来的数据包不变,新创建一个包,将原来包的 headers 和 payload 作为另外新包的 Payload 内容,在新包的 headers 中写入真实的服务器 ip 作为目标 ip,然后在达到目标服务器之后,再进行拆包动作")]),t._v(" "),n("p",[t._v("这种模式仍必须通过专门的配置,必须保证所有的真实服务器与均衡器有着相同的虚拟 IP 地址")]),t._v(" "),n("p",[t._v("NAT 模式:也可以直接替换 header 中的目标 ip,不过这样的话,这个转发器就不能取消了,必须充当中间人的身份了,服务器返回的内容中源 ip,客户端可不认识啊。客户端只认识中间的转发器,所以不能取消")]),t._v(" "),n("p",[t._v("还有一种更加彻底的 NAT 模式:即均衡器在转发时,不仅修改目标 IP 地址,连源 IP 地址也一起改了,源地址就改成均衡器自己的 IP,但是这样有一些需要根据目标 IP 进行控制的业务逻辑就无法进行")]),t._v(" "),n("h2",{attrs:{id:"七层负载均衡"}},[t._v("七层负载均衡")]),t._v(" "),n("p",[t._v("只有二三层属于数据的转发,到 tcp 之后都属于代理,因为 tcp 协议之后的内容都已经到了目标服务器了,是无法再进行转发数据的。")]),t._v(" "),n("p",[t._v("转发是指的【用户】【四层负载均衡】【服务器】之间是一个通道,代理是用户和七层负载均衡一个通道,七层负载均衡和服务器之间一个通道")]),t._v(" "),n("h3",{attrs:{id:"七层负载均衡的能力"}},[t._v("七层负载均衡的能力")]),t._v(" "),n("ul",[n("li",[t._v("静态资源缓存,协议升级,安全防护,访问控制,这种 cdn 能做到的事,七层负载均衡也可以做到,毕竟都是加一层保护膜对吧")]),t._v(" "),n("li",[t._v("可以实现更加智能,更加多样的路由")]),t._v(" "),n("li",[t._v("使用反向代理去防止攻击")]),t._v(" "),n("li",[t._v("微服务中的链路治理都需要在七层负载均衡中去做 (通常是 API 网关,nginx 也算 api 网关但是跟专业的比治理方面功能性差很多) 比如服务降级,熔断,异常注入等内容")])]),t._v(" "),n("h3",{attrs:{id:"负载均衡算法"}},[t._v("负载均衡算法")]),t._v(" "),n("ul",[n("li",[t._v("轮询")]),t._v(" "),n("li",[t._v("权重轮询,就是虚拟化服务器,权重大的服务器数量上就会变多")]),t._v(" "),n("li",[t._v("随机")]),t._v(" "),n("li",[t._v("权重随机")]),t._v(" "),n("li",[t._v("一致性哈希,其实就是权重轮询,但是环形结构,只有在环形结构上与该节点相邻的部分数据需要进行重新分配,而不是像传统哈希算法那样需要对所有数据进行重新计算和分配。")]),t._v(" "),n("li",[t._v("响应速度均衡,根据服务器响应时间,将请求分配到响应时间快的服务器上")]),t._v(" "),n("li",[t._v("最少连接,将请求分配到连接数最少的服务器上")])]),t._v(" "),n("h2",{attrs:{id:"nginx-实现七层负载均衡器"}},[t._v("nginx 实现七层负载均衡器")]),t._v(" "),n("p",[t._v("nginx 的配置文件 nginx.conf")]),t._v(" "),n("p",[t._v("我们配置假设一台负载均衡器 nginx 后面有三个服务:/get0 /get1 /get2")]),t._v(" "),n("div",{staticClass:"language-nginx extra-class"},[n("pre",{pre:!0,attrs:{class:"language-nginx"}},[n("code",[n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# nginx 配置 /get0 /get1 /get2")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token directive"}},[n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("worker_processes")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token number"}},[t._v("3")])]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 标识服务器进程数")]),t._v("\n\n"),n("span",{pre:!0,attrs:{class:"token directive"}},[n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("events")])]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\n"),n("span",{pre:!0,attrs:{class:"token directive"}},[n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("worker_connections")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token number"}},[t._v("1024")])]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 标识单个worker进程能同时处理的最大连接数")]),t._v("\n\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n"),n("span",{pre:!0,attrs:{class:"token directive"}},[n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("http")])]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 标识http块")]),t._v("\n\n"),n("span",{pre:!0,attrs:{class:"token directive"}},[n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("keepalive_timeout")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token number"}},[t._v("60")])]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 标识服务器和客户蹲连接超过60秒没有行为就会断掉")]),t._v("\n\n"),n("span",{pre:!0,attrs:{class:"token directive"}},[n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("upstream")]),t._v(" get0")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 标识upstream块")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token directive"}},[n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("server")]),t._v(" 192.168.1.209:8080")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 标识upstream块中的server")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token directive"}},[n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("server")]),t._v(" 192.168.1.209:8081")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 192.168.1.209:8081/get0 提供服务,就是nginx的路由要跟提供服务的服务路由一致才可以")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n"),n("span",{pre:!0,attrs:{class:"token directive"}},[n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("upstream")]),t._v(" get1")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token directive"}},[n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("server")]),t._v(" 192.168.1.209:8082")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token directive"}},[n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("server")]),t._v(" 192.168.1.209:8083")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token directive"}},[n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("upstream")]),t._v(" get2")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token directive"}},[n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("server")]),t._v(" 192.168.1.209:8084 weight=1")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 配置权重,权重越大被访问的几率越高")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token directive"}},[n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("server")]),t._v(" 192.168.1.209:8085 weight=3")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n \n"),n("span",{pre:!0,attrs:{class:"token directive"}},[n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("server")])]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 标识server块")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token directive"}},[n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("listen")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token number"}},[t._v("80")])]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 标识监听端口")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token directive"}},[n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("server_name")]),t._v(" 192.168.1.209")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 标识服务器名")]),t._v("\n \n \n "),n("span",{pre:!0,attrs:{class:"token directive"}},[n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("location")]),t._v(" /get0")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 标识location块")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token directive"}},[n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("proxy_pass")]),t._v(" http://get0")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 标识代理目标")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n "),n("span",{pre:!0,attrs:{class:"token directive"}},[n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("location")]),t._v(" /get1")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token directive"}},[n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("porxy_pass")]),t._v(" http://get1")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" \n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token directive"}},[n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("location")]),t._v(" /get2")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token directive"}},[n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("proxy_pass")]),t._v(" http://get2")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),n("p",[t._v("nginx 配置中,nginx 的路由要跟提供服务的服务器路由保持一致,不过也有不一致的方法,比如:")]),t._v(" "),n("div",{staticClass:"language-bash extra-class"},[n("pre",{pre:!0,attrs:{class:"language-bash"}},[n("code",[t._v(" location /get0 "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n proxy_pass http://get0/api/get0"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),n("p",[t._v("这种方法中,如果访问 nginx 的路由 /get0 那么它就会默认去寻找 192.168.1.209:8080/api/get0 或者 192.168.1.209:8081/api/get1")]),t._v(" "),n("p",[t._v("不过,为了保持简洁性,减少复杂度以及潜在的 bug,为了保证运维的逻辑更加清晰,请保持路由的一致:")]),t._v(" "),n("p",[n("img",{attrs:{src:a(437),alt:"nginx-proxy"}})]),t._v(" "),n("h3",{attrs:{id:"nginx-常用负载均衡策略"}},[t._v("Nginx 常用负载均衡策略")]),t._v(" "),n("ul",[n("li",[n("p",[t._v("轮询,就是你啥都不设置,就是这个策略")])]),t._v(" "),n("li",[n("p",[t._v("加权轮询,设置 weight=3,权重越大就越被优先访问,优先级按照权重去配比")]),t._v(" "),n("div",{staticClass:"language-nginx extra-class"},[n("pre",{pre:!0,attrs:{class:"language-nginx"}},[n("code",[n("span",{pre:!0,attrs:{class:"token directive"}},[n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("upstream")]),t._v(" get0")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token directive"}},[n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("server")]),t._v(" 192.168.1.209:8080 weight=3")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token directive"}},[n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("server")]),t._v(" 192.168.1.209:8081 weight=1")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n")])])])]),t._v(" "),n("li",[n("p",[t._v("ip_hash,为每一个用户的 ip 地址的哈希值结果分配服务器,让来自同一个 ip 的请求一直访问同一个服务器,注意这里的策略不能很好的践行负载均衡的理论,而且这里的哈希映射不是一致性哈希")]),t._v(" "),n("div",{staticClass:"language-nginx extra-class"},[n("pre",{pre:!0,attrs:{class:"language-nginx"}},[n("code",[n("span",{pre:!0,attrs:{class:"token directive"}},[n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("upstream")]),t._v(" get1")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token directive"}},[n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("ip_hash")])]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token directive"}},[n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("server")]),t._v(" 192.168.1.209:8082 max_fails=3 fail_timeout=30s")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 设置服务器的故障检测,当连续3次请求失败后,nginx会认为服务器已经挂了,并在30秒内不再访问该服务器")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token directive"}},[n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("server")]),t._v(" 192.168.1.209:8083")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token directive"}},[n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("server")]),t._v(" 192.168.1.210:8084 backup")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 当所有的主服务器(通过ip_hash分配的正常服务器)都无法处理请求时,备份服务器就会启用")]),t._v("\n"),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])])]),t._v(" "),n("li",[n("p",[t._v("least_conn,将请求分配到连接数最少的服务器上")]),t._v(" "),n("div",{staticClass:"language-nginx extra-class"},[n("pre",{pre:!0,attrs:{class:"language-nginx"}},[n("code",[t._v(" "),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 当有两个策略的时候,通常会一起使用 ")]),t._v("\n\n"),n("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 当有新请求到来时,Nginx 首先会考虑least_conn策略,即找出当前连接数最少的服务器。但在这些连接数最少的服务器中,weight会影响请求分配的概率。")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token directive"}},[n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("upstream")]),t._v(" get2")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token directive"}},[n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("least_conn")])]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token directive"}},[n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("server")]),t._v(" 192.168.1.209:8084 weight=1 max_fails=3 fail_timeout=30s")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token directive"}},[n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("server")]),t._v(" 192.168.1.209:8085 weight=3 max_fails=3 fail_timeout=30s")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])])]),t._v(" "),n("li",[n("p",[t._v("url_hash,三方库 uginx-upstream-hash,类似于 ip_hash 策略,但是它是对请求的 URL 做哈希运算 (一个是对 ip 地址做哈希,一个是对 URL 做哈希)")])]),t._v(" "),n("li",[n("p",[t._v("fair,三方库 nginx-upstream-fair,根据每个服务器事例的请求响应时间,失败数,当前请求总量,综合选择一个最轻松的服务器")])])]),t._v(" "),n("h3",{attrs:{id:"nginx-如何加载三方库"}},[t._v("Nginx 如何加载三方库")]),t._v(" "),n("ul",[n("li",[n("p",[t._v("确定所需第三方模块")]),t._v(" "),n("ul",[n("li",[t._v("首先要明确你需要使用的第三方 Nginx 模块。例如,如果你需要对请求进行更高级的访问控制,可以考虑使用 ngx_http_auth_request_module;如果想增强缓存功能,可能会用到 ngx_cache_purge 模块。这些模块通常是为了满足特定的功能需求,如安全性、性能优化等。")])])]),t._v(" "),n("li",[n("p",[t._v("检查模块兼容性")]),t._v(" "),n("ul",[n("li",[t._v("确认模块与你的 Nginx 版本兼容。不同的 Nginx 版本对模块的支持有所不同。你可以查看模块的官方文档或者在相关的开发者社区、论坛中查找模块与 Nginx 版本的兼容性信息。例如,一些新开发的模块可能只支持较新的 Nginx 版本,而旧版本的 Nginx 可能无法正确加载这些模块。")])])]),t._v(" "),n("li",[n("p",[t._v("下载模块源代码")]),t._v(" "),n("ul",[n("li",[t._v("从可靠的来源获取模块的源代码。通常,模块的官方代码仓库 (如在 GitHub 等平台上) 是最好的选择。例如,如果要下载 ngx_http_auth_request_module,可以访问 Nginx 官方网站或者对应的代码托管平台,找到该模块的源代码下载链接或者仓库地址,然后使用版本控制系统工具 (如 git) 或者直接下载压缩包的方式获取源代码。")])])]),t._v(" "),n("li",[n("p",[t._v("编译安装 Nginx (包含第三方模块)")]),t._v(" "),n("ul",[n("li",[n("p",[t._v("方法一:重新编译 Nginx\n如果是自己手动编译 Nginx,需要将第三方模块的源代码放置在合适的位置,通常是在 Nginx 源代码目录的 modules 目录下 (如果没有这个目录,可以创建一个)。然后在配置 Nginx 编译选项时,需要指定包含这个第三方模块。例如,使用 "),n("code",[t._v("./configure")]),t._v(" 命令配置 Nginx 编译选项时,需要添加类似于 "),n("code",[t._v("--add - module = path/to/third - party/module")]),t._v(" 的选项,其中 "),n("code",[t._v("path/to/third - party/module")]),t._v(" 是第三方模块源代码的实际路径。\n配置完成后,使用 make 命令编译 Nginx,再使用 make install 命令安装编译好的 Nginx。这样,新安装的 Nginx 就包含了这个第三方模块。")])]),t._v(" "),n("li",[n("p",[t._v("方法二:使用动态模块 (适用于支持动态模块加载的 Nginx 版本)\n对于支持动态模块加载的 Nginx 版本 (如 Nginx 1.9.11 及以上),首先按照上述步骤下载模块源代码。然后在编译模块时,使用 "),n("code",[t._v("ngx_build_module")]),t._v(" 工具 (这个工具通常随 Nginx 一起提供) 或者按照模块文档中的特殊编译步骤进行编译。\n编译完成后,得到一个动态模块文件 (通常是以。so 结尾的文件)。将这个动态模块文件放置在 Nginx 的模块目录下 (例如 "),n("code",[t._v("/usr/lib/nginx/modules/")]),t._v("),然后在 Nginx 的主配置文件 (nginx.conf) 中,使用 load_module 指令加载这个模块。例如,"),n("code",[t._v("load_module modules/ngx_http_auth_request_module.so")]),t._v(";,这样就可以在 Nginx 中使用这个第三方模块了。")])])])]),t._v(" "),n("li",[n("p",[t._v("配置和使用第三方模块")]),t._v(" "),n("ul",[n("li",[t._v("在 Nginx 的配置文件 (nginx.conf) 或相关的虚拟主机配置文件中,根据模块的功能进行配置。例如,对于 ngx_http_auth_request_module,可以配置如下:")])]),t._v(" "),n("div",{staticClass:"language-nginx extra-class"},[n("pre",{pre:!0,attrs:{class:"language-nginx"}},[n("code",[t._v(" "),n("span",{pre:!0,attrs:{class:"token directive"}},[n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("server")])]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token directive"}},[n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("listen")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token number"}},[t._v("80")])]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token directive"}},[n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("server_name")]),t._v(" example.com")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token directive"}},[n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("location")]),t._v(" /")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token directive"}},[n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("auth_request")]),t._v(" /auth")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token directive"}},[n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("proxy_pass")]),t._v(" http://backend")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token directive"}},[n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("location")]),t._v(" = /auth")]),t._v(" "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token directive"}},[n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("internal")])]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token directive"}},[n("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("proxy_pass")]),t._v(" http://auth - server")]),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),n("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),n("p",[t._v("这里通过 "),n("code",[t._v("auth_request")]),t._v(" 指令使用了 "),n("code",[t._v("ngx_http_auth_request_module")]),t._v(" 来进行请求的身份验证。不同的第三方模块有不同的配置方法和指令,需要根据模块的文档进行具体的配置和使用。")])])]),t._v(" "),n("h3",{attrs:{id:"nginx-热更新"}},[t._v("Nginx 热更新")]),t._v(" "),n("ul",[n("li",[t._v("使用 "),n("code",[t._v("ngx_lua")]),t._v(" 将 lua 脚本嵌入到 nginx 中,允许编写的 lua 脚本运行在 nginx 中")]),t._v(" "),n("li",[n("code",[t._v("ngx_http_dyups_module")]),t._v(",使用这个模块,去不断的主动访问一个服务注册中心,里面是服务的具体内容,然后生成新的配置")])]),t._v(" "),n("p",[n("img",{attrs:{src:a(438),alt:"nginx-hot-update"}})]),t._v(" "),n("h3",{attrs:{id:"ngix-优势"}},[t._v("Ngix 优势")]),t._v(" "),n("ul",[n("li",[t._v("DNS 服务指向 Nginx,具体服务 IP 跟 DNS 解耦")]),t._v(" "),n("li",[t._v("使用 Nginx 做了负载均衡")]),t._v(" "),n("li",[t._v("对外只暴漏一个公网 ip,节约 ip 资源,nginx 和具体服务内部通信即可")]),t._v(" "),n("li",[t._v("防止业务 ip 暴漏")]),t._v(" "),n("li",[t._v("增加了业务服务器的可扩展性")]),t._v(" "),n("li",[t._v("提高了整体服务的可用性")]),t._v(" "),n("li",[t._v("提高了系统的整体性能")])]),t._v(" "),n("h2",{attrs:{id:"负载均衡的高级用法"}},[t._v("负载均衡的高级用法")]),t._v(" "),n("p",[t._v("通常下面的高级用法都部署在七层负载均衡上,因为它更加灵活,设置起来更方便一些,四层负载均衡主要侧重于性能,所以一般不会有非常复杂的设置。")]),t._v(" "),n("ul",[n("li",[t._v("蓝绿发布,通过在"),n("strong",[t._v("两个生产环境之间")]),t._v(" (蓝色绿色) 切换来实现零停机时间部署")]),t._v(" "),n("li",[t._v("红蓝发布,跟蓝绿发布类似,只不过蓝绿发布的两个环境大体一致,红蓝发布中,蓝色为正常安全环境,红色为危险易受到攻击的环境")]),t._v(" "),n("li",[t._v("金丝雀发布,渐进式发布策略,"),n("strong",[t._v("逐步将新版本推向生产环境")]),t._v(",只有一部分人会看到新版本,一旦出现问题就回滚旧版本")]),t._v(" "),n("li",[t._v("灰度发布,"),n("strong",[t._v("根据用户的流量特点")]),t._v(",将新版本推送给特定用户,在不影响整体用户体验的情况下进行测试和验证")]),t._v(" "),n("li",[t._v("AB 测试,相同环境的不同设置推送给不同的用户用于测试效果")]),t._v(" "),n("li",[t._v("rolling update 滚动测试,部分服务器更新升级,然后逐步替换 (红蓝更新需要两套完整的环境,rolling update 则是替换掉一个)")]),t._v(" "),n("li",[t._v("影子发布 (Shadow Deployment),影子发布是指在实际的生产环境旁边,部署一份新版本的服务,这个新版本的服务会接收和生产环境相同的请求流量,但不会对用户产生实际的影响。它主要用于观察新版本在真实流量下的性能和行为。")]),t._v(" "),n("li",[t._v("分批发布 (Batch Deployment),将用户或者服务器等分成若干批次,按批次逐步发布新版本。每一批次发布后,可以观察一段时间,确保没有问题后再发布下一批次。")]),t._v(" "),n("li",[t._v("特性开关发布 (Feature Toggles),也叫功能开关或特性标记。它允许开发团队在不发布整个新版本的情况下,通过控制开关来启用或禁用新功能。新功能在代码中已经存在,但通过配置来决定是否对用户可见")]),t._v(" "),n("li",[t._v("主动调节后端服务压力")]),t._v(" "),n("li",[t._v("屏蔽失效的后端服务")])]),t._v(" "),n("h3",{attrs:{id:"发布模式与负载均衡的原理"}},[t._v("发布模式与负载均衡的原理")]),t._v(" "),n("ol",[n("li",[n("p",[t._v("红蓝发布 (或者蓝绿发布)")]),t._v(" "),n("ul",[n("li",[t._v("通常需要负载均衡作为切换器。在红蓝发布中,有红色和蓝色两个完整的生产环境。负载均衡器可以根据配置规则,将流量从一个环境 (如红色) 快速切换到另一个环境 (如蓝色)。例如,在正常情况下,负载均衡器将所有用户请求导向红色环境,当红色环境需要更新时,通过负载均衡器的配置调整,将流量切换到蓝色环境,从而实现零停机时间部署。这样可以确保在切换过程中,用户请求能够被合理地分配,并且能够灵活地控制流量的走向。")])])]),t._v(" "),n("li",[n("p",[t._v("金丝雀发布")]),t._v(" "),n("ul",[n("li",[t._v("负载均衡在金丝雀发布中也起到关键作用。它可以用于将一小部分用户流量导向新版本的服务 (金丝雀环境),而将大部分用户流量继续导向旧版本的服务。通过负载均衡器的流量分配策略,如按比例分配 (例如,将 10% 的流量分配给新版本,90% 分配给旧版本),可以实现逐步将新版本推向生产环境。当发现新版本出现问题时,负载均衡器可以快速调整流量分配,将所有流量重新导向旧版本,从而实现回滚。")])])]),t._v(" "),n("li",[n("p",[t._v("灰度发布")]),t._v(" "),n("ul",[n("li",[t._v("同样依赖负载均衡。灰度发布是根据用户的流量特点,将新版本推送给特定用户。负载均衡器可以根据用户的属性 (如地理位置、用户等级、设备类型等) 来进行流量分配。例如,将新版本发布给某个特定地区的用户或者高价值用户。它能够精准地控制哪些用户流量被导向新版本,哪些被导向旧版本,在不影响整体用户体验的情况下进行测试和验证。")])])]),t._v(" "),n("li",[n("p",[t._v("AB 测试")]),t._v(" "),n("ul",[n("li",[t._v("负载均衡对于 AB 测试也是必不可少的。它可以将相同环境的不同设置 (如不同的界面布局、不同的推荐算法等) 推送给不同的用户。通过负载均衡器的分流规则,例如,可以将 50% 的用户导向 A 版本,50% 的用户导向 B 版本,然后对比两组用户的行为和反馈,来测试不同设置的效果。")])])]),t._v(" "),n("li",[n("p",[t._v("特性开关发布 (Feature Toggles)")]),t._v(" "),n("ul",[n("li",[t._v("负载均衡不是必需的。这种发布模式主要是通过软件内部的特性开关来控制功能的启用和禁用,而不是通过流量分配来实现发布。不过,在一些复杂的场景下,如果需要结合特性开关和流量控制来进行更精细的发布,也可以使用负载均衡。")])])]),t._v(" "),n("li",[n("p",[t._v("影子发布 (Shadow Deployment)")]),t._v(" "),n("ul",[n("li",[t._v("负载均衡起到辅助作用。影子发布主要是为了在不影响用户的情况下,让新版本接收相同的流量进行性能测试。负载均衡可以帮助复制流量到影子环境,但它不是用于切换流量给用户的主要工具,因为影子版本的输出通常不会直接提供给用户。")])])]),t._v(" "),n("li",[n("p",[t._v("分批发布 (Batch Deployment)")]),t._v(" "),n("ul",[n("li",[t._v("可以使用负载均衡,但不是绝对依赖。在分批发布中,负载均衡可以用于将流量按批次导向不同的服务器组 (其中有些是已更新的,有些是未更新的)。不过,也可以通过其他方式,如服务器分组和手动配置等,来实现按批次发布,不一定完全依靠负载均衡来进行流量切换。")])])])]),t._v(" "),n("h3",{attrs:{id:"金丝雀发布和灰度发布的区别"}},[t._v("金丝雀发布和灰度发布的区别")]),t._v(" "),n("p",[t._v("金丝雀发布通常是随机的少量的用户,而灰度发布通常是选取特定特征的人群,比如按照地域按照性别,灰度发布更强调策略,金丝雀更强调随机性")]),t._v(" "),n("p",[t._v("金丝雀发布的人群相对更低,一旦有问题就回滚,主要用于最早期的验证,灰度发布因为选择的是特定人群,所以相对用户是很多的,风险是加大的")]),t._v(" "),n("p",[n("strong",[t._v("金丝雀发布侧重于技术验证")]),t._v(","),n("strong",[t._v("灰度发布侧重于业务验证")])]),t._v(" "),n("h3",{attrs:{id:"红蓝发布和蓝绿发布的区别"}},[t._v("红蓝发布和蓝绿发布的区别")]),t._v(" "),n("p",[t._v("红蓝发布和蓝绿发布意思比较相近,但也有一些细微差别。")]),t._v(" "),n("p",[t._v("蓝绿发布 (Blue - Green Deployment)")]),t._v(" "),n("p",[t._v("概念:蓝绿发布是一种部署策略,它有两个完全相同的生产环境,分别称为蓝环境和绿环境。"),n("strong",[t._v("在任何时刻,只有一个环境 (例如绿环境) 在处理实际的用户流量,另一个 (蓝环境) 处于空闲或者预发布状态")]),t._v("。当需要发布新版本时,开发人员会将新版本部署到空闲的环境 (蓝环境) 中,对其进行充分的测试,包括功能测试、性能测试等。一旦测试通过,就可以通过负载均衡器或者其他切换工具将用户流量从旧环境 (绿环境) 切换到新环境 (蓝环境)。这个切换过程通常可以非常快速地完成,实现几乎零停机时间的部署。切换后,原来的旧环境 (绿环境) 可以被闲置,用于下一次发布或者作为备份。")]),t._v(" "),n("p",[t._v("示例:假设一个在线购物网站,绿环境是当前正在为用户提供服务的环境。当有新功能需要发布时,先将新功能部署到蓝环境,经过测试人员在蓝环境中进行购物流程的测试,确认没有问题后,将负载均衡的流量指向从绿环境切换到蓝环境,用户就开始使用新环境中的购物网站,整个过程用户可能几乎感觉不到服务的中断。")]),t._v(" "),n("p",[t._v("特点:")]),t._v(" "),n("p",[t._v("提供了快速回滚的能力。如果在新环境 (蓝环境) 出现问题,能够迅速将流量切换回旧环境 (绿环境),将影响降到最低。")]),t._v(" "),n("p",[t._v("两个环境可以独立维护和测试,有助于保证发布质量。")]),t._v(" "),n("p",[t._v("红蓝发布 (Red - Blue Deployment)")]),t._v(" "),n("p",[t._v("概念:和蓝绿发布类似,也有红色和蓝色两个生产环境。不过,红蓝发布在概念上更强调这两个环境之间的对比或者竞争关系。例如,在安全领域,红色环境可能代表容易受到攻击的环境,蓝色环境代表具有安全防护措施的环境,通过在两个环境之间切换来测试安全策略的有效性等特殊场景;在常规软件发布场景下,其原理和蓝绿发布类似,也是通过两个环境的切换来实现部署,但可能在应用场景或者侧重点上有所不同。")]),t._v(" "),n("p",[t._v("示例:在一些对数据安全性要求极高的金融系统中,红色环境可以模拟外部网络攻击频繁的情况,蓝色环境则是部署了最新安全防护软件的环境。系统可以在两个环境之间切换用户流量,观察安全防护措施的实际效果。在软件更新场景下,也可以像蓝绿发布一样,将新版本部署在蓝色环境,经过测试后切换用户流量到蓝色环境来实现更新。")]),t._v(" "),n("p",[t._v("特点:")]),t._v(" "),n("p",[t._v("除了用于常规的软件发布,还可以用于一些特殊的测试场景,如安全性测试、兼容性测试等。")]),t._v(" "),n("p",[t._v("强调两个环境之间的差异对比和相互验证。")])])}),[],!1,null,null,null);s.default=e.exports}}]); \ No newline at end of file diff --git a/assets/js/8.55f97d69.js b/assets/js/8.55f97d69.js new file mode 100644 index 00000000..c9fe32b8 --- /dev/null +++ b/assets/js/8.55f97d69.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[8],{426:function(t,r,e){t.exports=e.p+"assets/img/wechat.4a3030a4.png"},446:function(t,r,e){"use strict";e.r(r);var o=e(36),a=Object(o.a)({},(function(){var t=this,r=t.$createElement,o=t._self._c||r;return o("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[o("h1",{attrs:{id:"鲁班讲系统设计"}},[t._v("鲁班讲系统设计")]),t._v(" "),o("p",{attrs:{align:"left"}},[t._v("\nhey~,我是科科人神,目前就职于国内一家互联网公司,你们可以加我"),o("a",{attrs:{href:"#wechat.png"}},[t._v("微信")]),t._v(",交个朋友吧~\n")]),t._v(" "),o("br"),t._v(" "),o("p",{attrs:{align:"center"}},[o("a",{attrs:{href:"#wechat.png",target:"_blank"}},[o("img",{attrs:{src:"https://img.shields.io/static/v1?label=%E7%A7%91%E7%A7%91%E4%BA%BA%E7%A5%9E&message=%E5%85%AC%E4%BC%97%E5%8F%B7&color="}})]),t._v(" "),o("a",{attrs:{href:"https://www.youtube.com/channel/UCK8wjBe9sh4VHSowLQmWOzg",target:"_blank"}},[o("img",{attrs:{src:"https://img.shields.io/static/v1?label=youtube&message=YouTube&color=red"}})]),t._v(" "),o("a",{attrs:{href:"https://space.bilibili.com/478621088",target:"_blank"}},[o("img",{attrs:{src:"https://img.shields.io/static/v1?label=bilibili&message=b%E7%AB%99&color=blue"}})]),t._v(" "),o("a",{attrs:{href:"https://www.zhihu.com/people/shgopher",target:"_blank"}},[o("img",{attrs:{src:"https://img.shields.io/static/v1?label=zhihu&message=%E7%9F%A5%E4%B9%8E&color=blue"}})]),t._v(" "),o("a",{attrs:{href:"https://blog.csdn.net/zyfljxzby",target:"_blank"}},[o("img",{attrs:{src:"https://img.shields.io/static/v1?label=csdn&message=CSDN&color=red"}})]),t._v(" "),o("a",{attrs:{href:"https://www.toutiao.com/c/user/token/MS4wLjABAAAAIGeO1-kCUelF-G8GW3AvJlrEL7tiO24WHJmnX4nV1bs",target:"_blank"}},[o("img",{attrs:{src:"https://img.shields.io/static/v1?label=toutiao&message=%E5%A4%B4%E6%9D%A1&color=red"}})])]),t._v("\n添加微信公众号:"),o("a",{attrs:{href:"#wechat.png"}},[t._v("科科人神")]),t._v(", 回复:\n"),o("ul",[o("li",[o("p",[o("code",[t._v("面试题")]),t._v(",获取经典 go 面试大全。")])]),t._v(" "),o("li",[o("p",[o("code",[t._v("好友")]),t._v(",可以添加作者的微信好友")])])]),t._v(" "),o("h2",{attrs:{id:"系统设计基础-100"}},[t._v("系统设计基础 (100%)")]),t._v(" "),o("ul",[o("li",[o("RouterLink",{attrs:{to:"/系统设计基础/系统设计理论基础/"}},[t._v("系统设计理论基础")])],1),t._v(" "),o("li",[o("RouterLink",{attrs:{to:"/系统设计基础/网络在系统设计中的作用/"}},[t._v("网络在系统设计中的作用")])],1),t._v(" "),o("li",[o("RouterLink",{attrs:{to:"/系统设计基础/分布式/"}},[t._v("分布式")])],1),t._v(" "),o("li",[o("RouterLink",{attrs:{to:"/系统设计基础/架构安全性/"}},[t._v("架构安全性")])],1)]),t._v(" "),o("h2",{attrs:{id:"架构分类"}},[t._v("架构分类")]),t._v(" "),o("ul",[o("li",[o("RouterLink",{attrs:{to:"/架构分类/单体架构/"}},[t._v("单体架构")])],1),t._v(" "),o("li",[o("RouterLink",{attrs:{to:"/架构分类/分层架构/"}},[t._v("分层架构")])],1),t._v(" "),o("li",[o("RouterLink",{attrs:{to:"/架构分类/管道架构/"}},[t._v("管道架构")])],1),t._v(" "),o("li",[o("RouterLink",{attrs:{to:"/架构分类/微内核架构/"}},[t._v("微内核架构")])],1),t._v(" "),o("li",[o("RouterLink",{attrs:{to:"/架构分类/事件驱动架构/"}},[t._v("事件驱动架构")])],1),t._v(" "),o("li",[o("RouterLink",{attrs:{to:"/架构分类/面向事务的架构/"}},[t._v("面向事务的架构")])],1),t._v(" "),o("li",[o("RouterLink",{attrs:{to:"/架构分类/微服务架构/"}},[t._v("微服务架构")])],1)]),t._v(" "),o("h2",{attrs:{id:"云原生"}},[t._v("云原生")]),t._v(" "),o("ul",[o("li",[o("RouterLink",{attrs:{to:"/云原生/容器/"}},[t._v("容器")])],1),t._v(" "),o("li",[o("RouterLink",{attrs:{to:"/云原生/容器编排/"}},[t._v("容器编排")])],1),t._v(" "),o("li",[o("RouterLink",{attrs:{to:"/云原生/服务网格/"}},[t._v("服务网格")])],1),t._v(" "),o("li",[o("RouterLink",{attrs:{to:"/云原生/ebpf/"}},[t._v("ebpf")])],1),t._v(" "),o("li",[o("RouterLink",{attrs:{to:"/云原生/serverless/"}},[t._v("serverless")])],1),t._v(" "),o("li",[o("RouterLink",{attrs:{to:"/云原生/API网关/"}},[t._v("API 网关")])],1),t._v(" "),o("li",[o("RouterLink",{attrs:{to:"/云原生/消息队列/"}},[t._v("MQ")])],1),t._v(" "),o("li",[o("RouterLink",{attrs:{to:"/云原生/rpc/"}},[t._v("RPC")])],1),t._v(" "),o("li",[o("RouterLink",{attrs:{to:"/云原生/服务发现治理/"}},[t._v("服务发现治理")])],1),t._v(" "),o("li",[o("RouterLink",{attrs:{to:"/云原生/搜索引擎/"}},[t._v("搜索引擎")])],1)]),t._v(" "),o("h2",{attrs:{id:"系统设计实战"}},[t._v("系统设计实战")]),t._v(" "),o("h3",{attrs:{id:"基础架构组件设计"}},[t._v("基础架构组件设计")]),t._v(" "),o("ul",[o("li",[o("RouterLink",{attrs:{to:"/系统设计实战/基础架构组件设计/分布式锁/"}},[t._v("分布式锁")])],1),t._v(" "),o("li",[o("RouterLink",{attrs:{to:"/系统设计实战/基础架构组件设计/负载均衡器/"}},[t._v("负载均衡器")])],1),t._v(" "),o("li",[o("RouterLink",{attrs:{to:"/系统设计实战/基础架构组件设计/限流中间件/"}},[t._v("限流中间件")])],1),t._v(" "),o("li",[o("RouterLink",{attrs:{to:"/系统设计实战/基础架构组件设计/唯一id生成器/"}},[t._v("唯一 id 生成器")])],1),t._v(" "),o("li",[o("RouterLink",{attrs:{to:"/系统设计实战/基础架构组件设计/用户登陆服务/"}},[t._v("用户登陆服务")])],1),t._v(" "),o("li",[o("RouterLink",{attrs:{to:"/系统设计实战/基础架构组件设计/海量推送系统/"}},[t._v("海量推送系统")])],1)]),t._v(" "),o("h3",{attrs:{id:"核心服务设计"}},[t._v("核心服务设计")]),t._v(" "),o("ul",[o("li",[o("RouterLink",{attrs:{to:"/系统设计实战/核心服务设计/内容发布系统/"}},[t._v("内容发布系统")])],1),t._v(" "),o("li",[o("RouterLink",{attrs:{to:"/系统设计实战/核心服务设计/通用计数系统/"}},[t._v("通用计数系统")])],1),t._v(" "),o("li",[o("RouterLink",{attrs:{to:"/系统设计实战/核心服务设计/排行榜服务/"}},[t._v("排行榜服务")])],1),t._v(" "),o("li",[o("RouterLink",{attrs:{to:"/系统设计实战/核心服务设计/用户关系服务/"}},[t._v("用户关系服务")])],1),t._v(" "),o("li",[o("RouterLink",{attrs:{to:"/系统设计实战/核心服务设计/timelineFeed服务/"}},[t._v("timeline feed 服务")])],1),t._v(" "),o("li",[o("RouterLink",{attrs:{to:"/系统设计实战/核心服务设计/评论服务/"}},[t._v("评论服务")])],1),t._v(" "),o("li",[o("RouterLink",{attrs:{to:"/系统设计实战/核心服务设计/im服务/"}},[t._v("im 服务")])],1),t._v(" "),o("li",[o("RouterLink",{attrs:{to:"/系统设计实战/核心服务设计/分布式爬虫/"}},[t._v("分布式爬虫")])],1),t._v(" "),o("li",[o("RouterLink",{attrs:{to:"/系统设计实战/核心服务设计/秒杀系统/"}},[t._v("秒杀系统")])],1),t._v(" "),o("li",[o("RouterLink",{attrs:{to:"/系统设计实战/核心服务设计/推荐系统/"}},[t._v("推荐系统")])],1),t._v(" "),o("li",[o("RouterLink",{attrs:{to:"/系统设计实战/核心服务设计/智能客服系统/"}},[t._v("智能客服系统")])],1),t._v(" "),o("li",[o("RouterLink",{attrs:{to:"/系统设计实战/核心服务设计/风险评估系统/"}},[t._v("风险评估系统")])],1),t._v(" "),o("li",[o("RouterLink",{attrs:{to:"/系统设计实战/核心服务设计/直播系统/"}},[t._v("直播系统")])],1),t._v(" "),o("li",[t._v("设计 rpc 框架")]),t._v(" "),o("li",[t._v("微信抢红包")]),t._v(" "),o("li",[t._v("设计点赞功能")]),t._v(" "),o("li",[t._v("微博 feed 流/微信朋友圈")]),t._v(" "),o("li",[t._v("分布式定时任务")])]),t._v(" "),o("h2",{attrs:{id:"更多内容"}},[t._v("更多内容")]),t._v(" "),o("blockquote",[o("p",[t._v("👷 正在施工中...")])]),t._v(" "),o("ul",[o("li",[o("a",{attrs:{href:"https://github.com/shgopher/GOFamily",target:"_blank",rel:"noopener noreferrer"}},[t._v("GOFamily"),o("OutboundLink")],1),t._v(" go 后端程序员宝典:go 基础语法,go 底层数据结构,go runtime 实现原理,go 并发模式,go 语言项目经验")]),t._v(" "),o("li",[o("a",{attrs:{href:"https://github.com/shgopher/408",target:"_blank",rel:"noopener noreferrer"}},[t._v("408"),o("OutboundLink")],1),t._v(" 关于 408 的相关知识,例如算法数据结构,网络,操作系统,数据库等。")]),t._v(" "),o("li",[o("a",{attrs:{href:"https://github.com/shgopher/luban",target:"_blank",rel:"noopener noreferrer"}},[t._v("luban"),o("OutboundLink")],1),t._v(" 系统设计相关内容,例如分布式共识算法,消息队列,容器,RPC 等内容。")]),t._v(" "),o("li",[o("a",{attrs:{href:"https://github.com/shgopher/dingdang",target:"_blank",rel:"noopener noreferrer"}},[t._v("dingdang"),o("OutboundLink")],1),t._v(" 各种工具类的使用,例如 git,正则表达式,ddd,CI/CD 等内容。")]),t._v(" "),o("li",[o("a",{attrs:{href:"https://github.com/shgopher/god",target:"_blank",rel:"noopener noreferrer"}},[t._v("god"),o("OutboundLink")],1),t._v(" 关于程序员自身的一些看法,例如面试经历,赚钱窍门,创业门道,如何向上\n管理等。")]),t._v(" "),o("li",[o("a",{attrs:{href:"https://github.com/shgopher/RustFamily",target:"_blank",rel:"noopener noreferrer"}},[t._v("RustFamily"),o("OutboundLink")],1),t._v(" rust 基础知识,rust 并发编程,rust 项目实践,rust 底层原理。。")])]),t._v(" "),o("h2",{attrs:{id:"参考资料"}},[t._v("参考资料")]),t._v(" "),o("ul",[o("li",[o("a",{attrs:{href:"https://book.douban.com/subject/35487561/",target:"_blank",rel:"noopener noreferrer"}},[t._v("软件架构架构模式,特征及实践指南"),o("OutboundLink")],1)]),t._v(" "),o("li",[o("a",{attrs:{href:"https://pphc.lvwenhan.com",target:"_blank",rel:"noopener noreferrer"}},[t._v("高并发的哲学原理"),o("OutboundLink")],1)]),t._v(" "),o("li",[o("a",{attrs:{href:"https://icyfenix.cn/",target:"_blank",rel:"noopener noreferrer"}},[t._v("凤凰架构"),o("OutboundLink")],1)]),t._v(" "),o("li",[o("a",{attrs:{href:"https://book.douban.com/subject/36864478/",target:"_blank",rel:"noopener noreferrer"}},[t._v("亿级流量系统架构设计与实战"),o("OutboundLink")],1)]),t._v(" "),o("li",[o("a",{attrs:{href:"https://time.geekbang.org/column/intro/100006601",target:"_blank",rel:"noopener noreferrer"}},[t._v("从 0 开始学架构"),o("OutboundLink")],1)]),t._v(" "),o("li",[o("a",{attrs:{href:"https://book.douban.com/subject/36855388/",target:"_blank",rel:"noopener noreferrer"}},[t._v("微服务设计"),o("OutboundLink")],1)]),t._v(" "),o("li",[o("a",{attrs:{href:"https://time.geekbang.org/column/intro/100002201",target:"_blank",rel:"noopener noreferrer"}},[t._v("左耳听风"),o("OutboundLink")],1)]),t._v(" "),o("li",[o("a",{attrs:{href:"https://time.geekbang.org/column/intro/100025201",target:"_blank",rel:"noopener noreferrer"}},[t._v("许式伟的架构课"),o("OutboundLink")],1)]),t._v(" "),o("li",[o("a",{attrs:{href:"https://time.geekbang.org/column/article/457122",target:"_blank",rel:"noopener noreferrer"}},[t._v("郭东白的架构课"),o("OutboundLink")],1)])]),t._v(" "),o("h2",{attrs:{id:"扫一扫添加我的公众号-回复-加群-可以加入微信群。"}},[t._v("扫一扫添加我的公众号,回复 “加群”,可以加入微信群。")]),t._v(" "),o("p",{attrs:{id:"wechat.png",align:"center"}},[o("br"),t._v(" "),o("br"),t._v(" "),o("img",{attrs:{src:e(426),alt:"公众号搜:科科人神"}})]),t._v(" "),o("h2",{attrs:{id:"star"}},[t._v("star")]),t._v(" "),o("p",[o("a",{attrs:{href:"https://starchart.cc/shgopher/luban",target:"_blank",rel:"noopener noreferrer"}},[o("img",{attrs:{src:"https://starchart.cc/shgopher/luban.svg",alt:"Stargazers over time"}}),o("OutboundLink")],1)]),t._v(" "),o("h2",{attrs:{id:"证书"}},[t._v("证书")]),t._v(" "),o("p",[o("a",{attrs:{rel:"license",href:"http://creativecommons.org/licenses/by/3.0/"}},[o("img",{staticStyle:{"border-width":"0"},attrs:{alt:"知识共享许可协议",src:"https://i.creativecommons.org/l/by/3.0/88x31.png"}})]),o("br"),t._v("本作品采用"),o("a",{attrs:{rel:"license",href:"http://creativecommons.org/licenses/by/3.0/"}},[t._v("知识共享署名 3.0 未本地化版本许可协议")]),t._v("进行许可。")])])}),[],!1,null,null,null);r.default=a.exports}}]); \ No newline at end of file diff --git a/assets/js/9.3fdecccf.js b/assets/js/9.3fdecccf.js new file mode 100644 index 00000000..9498b522 --- /dev/null +++ b/assets/js/9.3fdecccf.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[9],{427:function(t,e,i){t.exports=i.p+"assets/img/ebpf1.1a1bb6f1.png"},448:function(t,e,i){"use strict";i.r(e);var s=i(36),n=Object(s.a)({},(function(){var t=this,e=t.$createElement,s=t._self._c||e;return s("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[s("h1",{attrs:{id:"cilium"}},[t._v("cilium")]),t._v(" "),s("h2",{attrs:{id:"ebpf"}},[t._v("eBPF")]),t._v(" "),s("p",[t._v("用一句话来形容 ebpf,它是可以运行在 Linux 内核中的沙箱,你可以想象成 docker 运行在了内核里。它可以做到不改变内核源代码以及不加载内核的情况下,做到安全的拓展内核功能。")]),t._v(" "),s("p",[t._v("eBPF "),s("a",{attrs:{href:"https://github.com/cilium/ebpf",target:"_blank",rel:"noopener noreferrer"}},[t._v("go 库"),s("OutboundLink")],1),t._v("提供了一个通用的 eBPF 库,它将 eBPF 字节码的获取过程与 eBPF 程序的加载和管理操作分离。")]),t._v(" "),s("p",[t._v("eBPF 程序通常是通过编写高级语言创建的,然后使用 clang/LLVM 编译器编译为 eBPF 字节码。")]),t._v(" "),s("p",[t._v("所以 ebpf 有点像 wasm,它不是一种软件,更像是一种规则,只要符合它的规则任何高级语言都可以去生成复合它要求的代码。")]),t._v(" "),s("p",[t._v("这是它的基本运行原理图\n"),s("img",{attrs:{src:i(427),alt:""}})]),t._v(" "),s("h2",{attrs:{id:"参考资料"}},[t._v("参考资料")]),t._v(" "),s("ul",[s("li",[t._v("https://ebpf.io/what-is-ebpf/")]),t._v(" "),s("li",[t._v("https://isovalent.com/data/liz-rice-what-is-ebpf.pdf?continueFlag=6021d2a27ddea20f1b8750770c4bd9fb")]),t._v(" "),s("li",[t._v("https://mp.weixin.qq.com/s/KIsIA2tPzXZwGJSrfxm54g")]),t._v(" "),s("li",[t._v("https://mp.weixin.qq.com/s/8bgabA5UdJOUYXqdjiO1Dw")]),t._v(" "),s("li",[t._v("https://mp.weixin.qq.com/s/Xr8ECrS_fR3aCT1vKJ9yIg")])])])}),[],!1,null,null,null);e.default=n.exports}}]); \ No newline at end of file diff --git a/assets/js/app.2672b9a3.js b/assets/js/app.2672b9a3.js new file mode 100644 index 00000000..88a3104c --- /dev/null +++ b/assets/js/app.2672b9a3.js @@ -0,0 +1,17 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[0],[]]);!function(t){function e(e){for(var r,i,a=e[0],c=e[1],u=e[2],B=0,f=[];B=n.length?{value:void 0,done:!0}:(t=r(n,o),e.index+=t.length,{value:t,done:!1})}))},function(t,e,n){var r=n(7),o=n(12),E=n(41);t.exports=r?function(t,e,n){return o.f(t,e,E(1,n))}:function(t,e,n){return t[e]=n,t}},function(t,e){var n=Array.isArray;t.exports=n},function(t,e,n){var r=n(0),o=n(4),E=n(54),i=r.TypeError;t.exports=function(t){if(o(t))return t;throw i(E(t)+" is not a function")}},function(t,e,n){var r=n(0),o=n(169),E=n(170),i=n(140),a=n(20),c=n(5),u=c("iterator"),s=c("toStringTag"),B=i.values,f=function(t,e){if(t){if(t[u]!==B)try{a(t,u,B)}catch(e){t[u]=B}if(t[s]||a(t,s,e),o[e])for(var n in i)if(t[n]!==i[n])try{a(t,n,i[n])}catch(e){t[n]=i[n]}}};for(var l in o)f(r[l]&&r[l].prototype,l);f(E,"DOMTokenList")},function(t,e,n){var r=n(176),o="object"==typeof self&&self&&self.Object===Object&&self,E=r||o||Function("return this")();t.exports=E},function(t,e,n){var r=n(0).TypeError;t.exports=function(t){if(null==t)throw r("Can't call method on "+t);return t}},function(t,e,n){var r=n(2),o=r({}.toString),E=r("".slice);t.exports=function(t){return E(o(t),8,-1)}},function(t,e,n){var r,o=n(11),E=n(142),i=n(106),a=n(55),c=n(147),u=n(72),s=n(76),B=s("IE_PROTO"),f=function(){},l=function(t){return" + + diff --git "a/\344\272\221\345\216\237\347\224\237/API\347\275\221\345\205\263/index.html" "b/\344\272\221\345\216\237\347\224\237/API\347\275\221\345\205\263/index.html" new file mode 100644 index 00000000..aba38c39 --- /dev/null +++ "b/\344\272\221\345\216\237\347\224\237/API\347\275\221\345\205\263/index.html" @@ -0,0 +1,54 @@ + + + + + + 鲁班 - 系统设计大全 + + + + + + + + + + + + diff --git "a/\344\272\221\345\216\237\347\224\237/cilium/index.html" "b/\344\272\221\345\216\237\347\224\237/cilium/index.html" new file mode 100644 index 00000000..2875161a --- /dev/null +++ "b/\344\272\221\345\216\237\347\224\237/cilium/index.html" @@ -0,0 +1,55 @@ + + + + + + cilium | 鲁班 - 系统设计大全 + + + + + + + + +

cilium

eBPF

用一句话来形容 ebpf,它是可以运行在 Linux 内核中的沙箱,你可以想象成 docker 运行在了内核里。它可以做到不改变内核源代码以及不加载内核的情况下,做到安全的拓展内核功能。

eBPF go 库 (opens new window)提供了一个通用的 eBPF 库,它将 eBPF 字节码的获取过程与 eBPF 程序的加载和管理操作分离。

eBPF 程序通常是通过编写高级语言创建的,然后使用 clang/LLVM 编译器编译为 eBPF 字节码。

所以 ebpf 有点像 wasm,它不是一种软件,更像是一种规则,只要符合它的规则任何高级语言都可以去生成复合它要求的代码。

这是它的基本运行原理图 +

参考资料

  • https://ebpf.io/what-is-ebpf/
  • https://isovalent.com/data/liz-rice-what-is-ebpf.pdf?continueFlag=6021d2a27ddea20f1b8750770c4bd9fb
  • https://mp.weixin.qq.com/s/KIsIA2tPzXZwGJSrfxm54g
  • https://mp.weixin.qq.com/s/8bgabA5UdJOUYXqdjiO1Dw
  • https://mp.weixin.qq.com/s/Xr8ECrS_fR3aCT1vKJ9yIg
+ + + diff --git "a/\344\272\221\345\216\237\347\224\237/dapr/index.html" "b/\344\272\221\345\216\237\347\224\237/dapr/index.html" new file mode 100644 index 00000000..2fa5db40 --- /dev/null +++ "b/\344\272\221\345\216\237\347\224\237/dapr/index.html" @@ -0,0 +1,54 @@ + + + + + + dapr | 鲁班 - 系统设计大全 + + + + + + + + + + + + diff --git "a/\344\272\221\345\216\237\347\224\237/docker/index.html" "b/\344\272\221\345\216\237\347\224\237/docker/index.html" new file mode 100644 index 00000000..c8fdfc39 --- /dev/null +++ "b/\344\272\221\345\216\237\347\224\237/docker/index.html" @@ -0,0 +1,54 @@ + + + + + + docker | 鲁班 - 系统设计大全 + + + + + + + + + + + + diff --git "a/\344\272\221\345\216\237\347\224\237/docker/\345\237\272\346\234\254\346\246\202\345\277\265/index.html" "b/\344\272\221\345\216\237\347\224\237/docker/\345\237\272\346\234\254\346\246\202\345\277\265/index.html" new file mode 100644 index 00000000..e2cb4e5a --- /dev/null +++ "b/\344\272\221\345\216\237\347\224\237/docker/\345\237\272\346\234\254\346\246\202\345\277\265/index.html" @@ -0,0 +1,55 @@ + + + + + + docker 的基本概念 | 鲁班 - 系统设计大全 + + + + + + + + +

docker 的基本概念

docker 项目的基本架构 +

从图中我们知道,我们平时操控的 docker 只是 docker 的 client 部分,然后由 client 向 docker 的后台 docker daemon 发送命令,真正控制的是 docker daemon,这这种架构是我们常见的客户端/服务器 (cs) 架构,这样的架构可以最大限度的去保护系统的核心部位。

下面是 docker 的整体运作模式

  1. 用户使用 docker client 去向 docker daemon 请求命令
  2. docker daemon 从远程服务器 Registry 获取镜像
  3. docker daemon 将镜像下载到本地以后,生成并管理容器
+ + + diff --git "a/\344\272\221\345\216\237\347\224\237/ebpf/index.html" "b/\344\272\221\345\216\237\347\224\237/ebpf/index.html" new file mode 100644 index 00000000..52d642fb --- /dev/null +++ "b/\344\272\221\345\216\237\347\224\237/ebpf/index.html" @@ -0,0 +1,54 @@ + + + + + + 鲁班 - 系统设计大全 + + + + + + + + + + + + diff --git "a/\344\272\221\345\216\237\347\224\237/index.html" "b/\344\272\221\345\216\237\347\224\237/index.html" new file mode 100644 index 00000000..29df8c9f --- /dev/null +++ "b/\344\272\221\345\216\237\347\224\237/index.html" @@ -0,0 +1,54 @@ + + + + + + 云原生 | 鲁班 - 系统设计大全 + + + + + + + + + + + + diff --git "a/\344\272\221\345\216\237\347\224\237/istio/index.html" "b/\344\272\221\345\216\237\347\224\237/istio/index.html" new file mode 100644 index 00000000..517b4e29 --- /dev/null +++ "b/\344\272\221\345\216\237\347\224\237/istio/index.html" @@ -0,0 +1,54 @@ + + + + + + 服务网格 | 鲁班 - 系统设计大全 + + + + + + + + + + + + diff --git "a/\344\272\221\345\216\237\347\224\237/k8s/index.html" "b/\344\272\221\345\216\237\347\224\237/k8s/index.html" new file mode 100644 index 00000000..a5116c18 --- /dev/null +++ "b/\344\272\221\345\216\237\347\224\237/k8s/index.html" @@ -0,0 +1,54 @@ + + + + + + 容器编排技术 kubernetes | 鲁班 - 系统设计大全 + + + + + + + + + + + + diff --git "a/\344\272\221\345\216\237\347\224\237/rpc/index.html" "b/\344\272\221\345\216\237\347\224\237/rpc/index.html" new file mode 100644 index 00000000..56b62e1a --- /dev/null +++ "b/\344\272\221\345\216\237\347\224\237/rpc/index.html" @@ -0,0 +1,54 @@ + + + + + + 鲁班 - 系统设计大全 + + + + + + + + + + + + diff --git "a/\344\272\221\345\216\237\347\224\237/serverless/index.html" "b/\344\272\221\345\216\237\347\224\237/serverless/index.html" new file mode 100644 index 00000000..a3e9e0c1 --- /dev/null +++ "b/\344\272\221\345\216\237\347\224\237/serverless/index.html" @@ -0,0 +1,54 @@ + + + + + + 鲁班 - 系统设计大全 + + + + + + + + + + + + diff --git "a/\344\272\221\345\216\237\347\224\237/zookeeper/index.html" "b/\344\272\221\345\216\237\347\224\237/zookeeper/index.html" new file mode 100644 index 00000000..5657fd02 --- /dev/null +++ "b/\344\272\221\345\216\237\347\224\237/zookeeper/index.html" @@ -0,0 +1,54 @@ + + + + + + 鲁班 - 系统设计大全 + + + + + + + + + + + + diff --git "a/\344\272\221\345\216\237\347\224\237/\345\256\271\345\231\250/index.html" "b/\344\272\221\345\216\237\347\224\237/\345\256\271\345\231\250/index.html" new file mode 100644 index 00000000..0f5326c6 --- /dev/null +++ "b/\344\272\221\345\216\237\347\224\237/\345\256\271\345\231\250/index.html" @@ -0,0 +1,54 @@ + + + + + + 鲁班 - 系统设计大全 + + + + + + + + + + + + diff --git "a/\344\272\221\345\216\237\347\224\237/\345\256\271\345\231\250\347\274\226\346\216\222/index.html" "b/\344\272\221\345\216\237\347\224\237/\345\256\271\345\231\250\347\274\226\346\216\222/index.html" new file mode 100644 index 00000000..6432821b --- /dev/null +++ "b/\344\272\221\345\216\237\347\224\237/\345\256\271\345\231\250\347\274\226\346\216\222/index.html" @@ -0,0 +1,54 @@ + + + + + + 鲁班 - 系统设计大全 + + + + + + + + + + + + diff --git "a/\344\272\221\345\216\237\347\224\237/\345\276\256\346\234\215\345\212\241\345\237\272\347\241\200\346\246\202\345\277\265/index.html" "b/\344\272\221\345\216\237\347\224\237/\345\276\256\346\234\215\345\212\241\345\237\272\347\241\200\346\246\202\345\277\265/index.html" new file mode 100644 index 00000000..0820c60e --- /dev/null +++ "b/\344\272\221\345\216\237\347\224\237/\345\276\256\346\234\215\345\212\241\345\237\272\347\241\200\346\246\202\345\277\265/index.html" @@ -0,0 +1,54 @@ + + + + + + 鲁班 - 系统设计大全 + + + + + + + + + + + + diff --git "a/\344\272\221\345\216\237\347\224\237/\346\220\234\347\264\242\345\274\225\346\223\216/index.html" "b/\344\272\221\345\216\237\347\224\237/\346\220\234\347\264\242\345\274\225\346\223\216/index.html" new file mode 100644 index 00000000..54adc0ab --- /dev/null +++ "b/\344\272\221\345\216\237\347\224\237/\346\220\234\347\264\242\345\274\225\346\223\216/index.html" @@ -0,0 +1,54 @@ + + + + + + 鲁班 - 系统设计大全 + + + + + + + + + + + + diff --git "a/\344\272\221\345\216\237\347\224\237/\346\234\215\345\212\241\345\217\221\347\216\260\346\262\273\347\220\206/index.html" "b/\344\272\221\345\216\237\347\224\237/\346\234\215\345\212\241\345\217\221\347\216\260\346\262\273\347\220\206/index.html" new file mode 100644 index 00000000..dc271c35 --- /dev/null +++ "b/\344\272\221\345\216\237\347\224\237/\346\234\215\345\212\241\345\217\221\347\216\260\346\262\273\347\220\206/index.html" @@ -0,0 +1,54 @@ + + + + + + 鲁班 - 系统设计大全 + + + + + + + + + + + + diff --git "a/\344\272\221\345\216\237\347\224\237/\346\234\215\345\212\241\347\275\221\346\240\274/index.html" "b/\344\272\221\345\216\237\347\224\237/\346\234\215\345\212\241\347\275\221\346\240\274/index.html" new file mode 100644 index 00000000..6bfebf54 --- /dev/null +++ "b/\344\272\221\345\216\237\347\224\237/\346\234\215\345\212\241\347\275\221\346\240\274/index.html" @@ -0,0 +1,54 @@ + + + + + + 鲁班 - 系统设计大全 + + + + + + + + + + + + diff --git "a/\344\272\221\345\216\237\347\224\237/\346\266\210\346\201\257\351\230\237\345\210\227/index.html" "b/\344\272\221\345\216\237\347\224\237/\346\266\210\346\201\257\351\230\237\345\210\227/index.html" new file mode 100644 index 00000000..b9f88368 --- /dev/null +++ "b/\344\272\221\345\216\237\347\224\237/\346\266\210\346\201\257\351\230\237\345\210\227/index.html" @@ -0,0 +1,54 @@ + + + + + + 鲁班 - 系统设计大全 + + + + + + + + + + + + diff --git "a/\346\236\266\346\236\204\345\210\206\347\261\273/\344\272\213\344\273\266\351\251\261\345\212\250\346\236\266\346\236\204/index.html" "b/\346\236\266\346\236\204\345\210\206\347\261\273/\344\272\213\344\273\266\351\251\261\345\212\250\346\236\266\346\236\204/index.html" new file mode 100644 index 00000000..3a4e508a --- /dev/null +++ "b/\346\236\266\346\236\204\345\210\206\347\261\273/\344\272\213\344\273\266\351\251\261\345\212\250\346\236\266\346\236\204/index.html" @@ -0,0 +1,54 @@ + + + + + + 鲁班 - 系统设计大全 + + + + + + + + + + + + diff --git "a/\346\236\266\346\236\204\345\210\206\347\261\273/\345\210\206\345\261\202\346\236\266\346\236\204/index.html" "b/\346\236\266\346\236\204\345\210\206\347\261\273/\345\210\206\345\261\202\346\236\266\346\236\204/index.html" new file mode 100644 index 00000000..44cfce2e --- /dev/null +++ "b/\346\236\266\346\236\204\345\210\206\347\261\273/\345\210\206\345\261\202\346\236\266\346\236\204/index.html" @@ -0,0 +1,54 @@ + + + + + + 鲁班 - 系统设计大全 + + + + + + + + + + + + diff --git "a/\346\236\266\346\236\204\345\210\206\347\261\273/\345\215\225\344\275\223\346\236\266\346\236\204/index.html" "b/\346\236\266\346\236\204\345\210\206\347\261\273/\345\215\225\344\275\223\346\236\266\346\236\204/index.html" new file mode 100644 index 00000000..97921d8a --- /dev/null +++ "b/\346\236\266\346\236\204\345\210\206\347\261\273/\345\215\225\344\275\223\346\236\266\346\236\204/index.html" @@ -0,0 +1,54 @@ + + + + + + 鲁班 - 系统设计大全 + + + + + + + + + + + + diff --git "a/\346\236\266\346\236\204\345\210\206\347\261\273/\345\276\256\345\206\205\346\240\270\346\236\266\346\236\204/index.html" "b/\346\236\266\346\236\204\345\210\206\347\261\273/\345\276\256\345\206\205\346\240\270\346\236\266\346\236\204/index.html" new file mode 100644 index 00000000..eccd47dc --- /dev/null +++ "b/\346\236\266\346\236\204\345\210\206\347\261\273/\345\276\256\345\206\205\346\240\270\346\236\266\346\236\204/index.html" @@ -0,0 +1,54 @@ + + + + + + 鲁班 - 系统设计大全 + + + + + + + + + + + + diff --git "a/\346\236\266\346\236\204\345\210\206\347\261\273/\345\276\256\346\234\215\345\212\241\346\236\266\346\236\204/index.html" "b/\346\236\266\346\236\204\345\210\206\347\261\273/\345\276\256\346\234\215\345\212\241\346\236\266\346\236\204/index.html" new file mode 100644 index 00000000..4c41a1da --- /dev/null +++ "b/\346\236\266\346\236\204\345\210\206\347\261\273/\345\276\256\346\234\215\345\212\241\346\236\266\346\236\204/index.html" @@ -0,0 +1,54 @@ + + + + + + 微服务架构 | 鲁班 - 系统设计大全 + + + + + + + + + + + + diff --git "a/\346\236\266\346\236\204\345\210\206\347\261\273/\347\256\241\351\201\223\346\236\266\346\236\204/index.html" "b/\346\236\266\346\236\204\345\210\206\347\261\273/\347\256\241\351\201\223\346\236\266\346\236\204/index.html" new file mode 100644 index 00000000..4373da09 --- /dev/null +++ "b/\346\236\266\346\236\204\345\210\206\347\261\273/\347\256\241\351\201\223\346\236\266\346\236\204/index.html" @@ -0,0 +1,54 @@ + + + + + + 鲁班 - 系统设计大全 + + + + + + + + + + + + diff --git "a/\346\236\266\346\236\204\345\210\206\347\261\273/\351\235\242\345\220\221\344\272\213\345\212\241\347\232\204\346\236\266\346\236\204/index.html" "b/\346\236\266\346\236\204\345\210\206\347\261\273/\351\235\242\345\220\221\344\272\213\345\212\241\347\232\204\346\236\266\346\236\204/index.html" new file mode 100644 index 00000000..ee59b4a2 --- /dev/null +++ "b/\346\236\266\346\236\204\345\210\206\347\261\273/\351\235\242\345\220\221\344\272\213\345\212\241\347\232\204\346\236\266\346\236\204/index.html" @@ -0,0 +1,54 @@ + + + + + + 鲁班 - 系统设计大全 + + + + + + + + + + + + diff --git "a/\347\263\273\347\273\237\350\256\276\350\256\241\345\237\272\347\241\200/\345\210\206\345\270\203\345\274\217/index.html" "b/\347\263\273\347\273\237\350\256\276\350\256\241\345\237\272\347\241\200/\345\210\206\345\270\203\345\274\217/index.html" new file mode 100644 index 00000000..9566bdcb --- /dev/null +++ "b/\347\263\273\347\273\237\350\256\276\350\256\241\345\237\272\347\241\200/\345\210\206\345\270\203\345\274\217/index.html" @@ -0,0 +1,54 @@ + + + + + + 鲁班 - 系统设计大全 + + + + + + + + +

分布式

分布式理论

分布式算法

分布式组件

  • 分布式锁
  • 分布式事务
  • 分布式关系数据库
  • 分布式缓存
  • 分布式 nosql
  • 分布式消息队列

分布式关键技术 (来自于左耳听风)

分布式系统设计模式 (来自于左耳听风)

高性能

  • 缓存设计
  • 异步处理
  • 数据库扩展
  • 秒杀
  • 边缘计算

高可用

  • 故障和弹力设计
  • 隔离设计
  • 异步通信设计
  • 幂等性设计
  • 服务的状态
  • 补偿事务
  • 重试设计
  • 熔断设计
  • 限流设计
  • 降级设计

可扩展

  • 分布式锁
  • 配置中心
  • sidecar
  • 服务网格
  • 网关
  • 部署升级策略

分布式实践

  • 分布式协调与同步
  • 分布式资源管理与负载调度
  • 分布式计算技术
  • 分布式通信技术
  • 分布式数据存储
  • 分布式高可靠
+ + + diff --git "a/\347\263\273\347\273\237\350\256\276\350\256\241\345\237\272\347\241\200/\345\210\206\345\270\203\345\274\217/\345\210\206\345\270\203\345\274\217\345\205\263\351\224\256\346\212\200\346\234\257/\345\205\250\346\240\210\347\233\221\346\216\247/index.html" "b/\347\263\273\347\273\237\350\256\276\350\256\241\345\237\272\347\241\200/\345\210\206\345\270\203\345\274\217/\345\210\206\345\270\203\345\274\217\345\205\263\351\224\256\346\212\200\346\234\257/\345\205\250\346\240\210\347\233\221\346\216\247/index.html" new file mode 100644 index 00000000..dc58570a --- /dev/null +++ "b/\347\263\273\347\273\237\350\256\276\350\256\241\345\237\272\347\241\200/\345\210\206\345\270\203\345\274\217/\345\210\206\345\270\203\345\274\217\345\205\263\351\224\256\346\212\200\346\234\257/\345\205\250\346\240\210\347\233\221\346\216\247/index.html" @@ -0,0 +1,54 @@ + + + + + + 鲁班 - 系统设计大全 + + + + + + + + + + + + diff --git "a/\347\263\273\347\273\237\350\256\276\350\256\241\345\237\272\347\241\200/\345\210\206\345\270\203\345\274\217/\345\210\206\345\270\203\345\274\217\345\256\236\350\267\265/\345\210\206\345\270\203\345\274\217\345\215\217\350\260\203\344\270\216\345\220\214\346\255\245/index.html" "b/\347\263\273\347\273\237\350\256\276\350\256\241\345\237\272\347\241\200/\345\210\206\345\270\203\345\274\217/\345\210\206\345\270\203\345\274\217\345\256\236\350\267\265/\345\210\206\345\270\203\345\274\217\345\215\217\350\260\203\344\270\216\345\220\214\346\255\245/index.html" new file mode 100644 index 00000000..a1fa2291 --- /dev/null +++ "b/\347\263\273\347\273\237\350\256\276\350\256\241\345\237\272\347\241\200/\345\210\206\345\270\203\345\274\217/\345\210\206\345\270\203\345\274\217\345\256\236\350\267\265/\345\210\206\345\270\203\345\274\217\345\215\217\350\260\203\344\270\216\345\220\214\346\255\245/index.html" @@ -0,0 +1,54 @@ + + + + + + 鲁班 - 系统设计大全 + + + + + + + + + + + + diff --git "a/\347\263\273\347\273\237\350\256\276\350\256\241\345\237\272\347\241\200/\345\210\206\345\270\203\345\274\217/\345\210\206\345\270\203\345\274\217\347\220\206\350\256\272/CAP/index.html" "b/\347\263\273\347\273\237\350\256\276\350\256\241\345\237\272\347\241\200/\345\210\206\345\270\203\345\274\217/\345\210\206\345\270\203\345\274\217\347\220\206\350\256\272/CAP/index.html" new file mode 100644 index 00000000..e23edc7c --- /dev/null +++ "b/\347\263\273\347\273\237\350\256\276\350\256\241\345\237\272\347\241\200/\345\210\206\345\270\203\345\274\217/\345\210\206\345\270\203\345\274\217\347\220\206\350\256\272/CAP/index.html" @@ -0,0 +1,54 @@ + + + + + + 鲁班 - 系统设计大全 + + + + + + + + + + + + diff --git "a/\347\263\273\347\273\237\350\256\276\350\256\241\345\237\272\347\241\200/\345\210\206\345\270\203\345\274\217/\345\210\206\345\270\203\345\274\217\347\256\227\346\263\225/paxos/index.html" "b/\347\263\273\347\273\237\350\256\276\350\256\241\345\237\272\347\241\200/\345\210\206\345\270\203\345\274\217/\345\210\206\345\270\203\345\274\217\347\256\227\346\263\225/paxos/index.html" new file mode 100644 index 00000000..f978f66b --- /dev/null +++ "b/\347\263\273\347\273\237\350\256\276\350\256\241\345\237\272\347\241\200/\345\210\206\345\270\203\345\274\217/\345\210\206\345\270\203\345\274\217\347\256\227\346\263\225/paxos/index.html" @@ -0,0 +1,54 @@ + + + + + + 鲁班 - 系统设计大全 + + + + + + + + + + + + diff --git "a/\347\263\273\347\273\237\350\256\276\350\256\241\345\237\272\347\241\200/\345\210\206\345\270\203\345\274\217/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237\350\256\276\350\256\241\346\250\241\345\274\217/\345\217\257\346\211\251\345\261\225/\345\210\206\345\270\203\345\274\217\351\224\201/index.html" "b/\347\263\273\347\273\237\350\256\276\350\256\241\345\237\272\347\241\200/\345\210\206\345\270\203\345\274\217/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237\350\256\276\350\256\241\346\250\241\345\274\217/\345\217\257\346\211\251\345\261\225/\345\210\206\345\270\203\345\274\217\351\224\201/index.html" new file mode 100644 index 00000000..41c54b65 --- /dev/null +++ "b/\347\263\273\347\273\237\350\256\276\350\256\241\345\237\272\347\241\200/\345\210\206\345\270\203\345\274\217/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237\350\256\276\350\256\241\346\250\241\345\274\217/\345\217\257\346\211\251\345\261\225/\345\210\206\345\270\203\345\274\217\351\224\201/index.html" @@ -0,0 +1,54 @@ + + + + + + 鲁班 - 系统设计大全 + + + + + + + + + + + + diff --git "a/\347\263\273\347\273\237\350\256\276\350\256\241\345\237\272\347\241\200/\345\210\206\345\270\203\345\274\217/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237\350\256\276\350\256\241\346\250\241\345\274\217/\351\253\230\345\217\257\347\224\250/\346\225\205\351\232\234\345\222\214\345\274\271\345\212\233\350\256\276\350\256\241/index.html" "b/\347\263\273\347\273\237\350\256\276\350\256\241\345\237\272\347\241\200/\345\210\206\345\270\203\345\274\217/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237\350\256\276\350\256\241\346\250\241\345\274\217/\351\253\230\345\217\257\347\224\250/\346\225\205\351\232\234\345\222\214\345\274\271\345\212\233\350\256\276\350\256\241/index.html" new file mode 100644 index 00000000..0285bb49 --- /dev/null +++ "b/\347\263\273\347\273\237\350\256\276\350\256\241\345\237\272\347\241\200/\345\210\206\345\270\203\345\274\217/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237\350\256\276\350\256\241\346\250\241\345\274\217/\351\253\230\345\217\257\347\224\250/\346\225\205\351\232\234\345\222\214\345\274\271\345\212\233\350\256\276\350\256\241/index.html" @@ -0,0 +1,54 @@ + + + + + + 鲁班 - 系统设计大全 + + + + + + + + + + + + diff --git "a/\347\263\273\347\273\237\350\256\276\350\256\241\345\237\272\347\241\200/\345\210\206\345\270\203\345\274\217/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237\350\256\276\350\256\241\346\250\241\345\274\217/\351\253\230\346\200\247\350\203\275/\347\274\223\345\255\230\350\256\276\350\256\241/index.html" "b/\347\263\273\347\273\237\350\256\276\350\256\241\345\237\272\347\241\200/\345\210\206\345\270\203\345\274\217/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237\350\256\276\350\256\241\346\250\241\345\274\217/\351\253\230\346\200\247\350\203\275/\347\274\223\345\255\230\350\256\276\350\256\241/index.html" new file mode 100644 index 00000000..b51aa9cb --- /dev/null +++ "b/\347\263\273\347\273\237\350\256\276\350\256\241\345\237\272\347\241\200/\345\210\206\345\270\203\345\274\217/\345\210\206\345\270\203\345\274\217\347\263\273\347\273\237\350\256\276\350\256\241\346\250\241\345\274\217/\351\253\230\346\200\247\350\203\275/\347\274\223\345\255\230\350\256\276\350\256\241/index.html" @@ -0,0 +1,54 @@ + + + + + + 鲁班 - 系统设计大全 + + + + + + + + + + + + diff --git "a/\347\263\273\347\273\237\350\256\276\350\256\241\345\237\272\347\241\200/\345\210\206\345\270\203\345\274\217/\345\210\206\345\270\203\345\274\217\347\273\204\344\273\266/\345\210\206\345\270\203\345\274\217\347\274\223\345\255\230/index.html" "b/\347\263\273\347\273\237\350\256\276\350\256\241\345\237\272\347\241\200/\345\210\206\345\270\203\345\274\217/\345\210\206\345\270\203\345\274\217\347\273\204\344\273\266/\345\210\206\345\270\203\345\274\217\347\274\223\345\255\230/index.html" new file mode 100644 index 00000000..5a578be5 --- /dev/null +++ "b/\347\263\273\347\273\237\350\256\276\350\256\241\345\237\272\347\241\200/\345\210\206\345\270\203\345\274\217/\345\210\206\345\270\203\345\274\217\347\273\204\344\273\266/\345\210\206\345\270\203\345\274\217\347\274\223\345\255\230/index.html" @@ -0,0 +1,54 @@ + + + + + + 鲁班 - 系统设计大全 + + + + + + + + +

分布式中的缓存

缓存是一个典型的空间换时间的优化手段,对于软件角度的缓存,往往缺点大于优点,看似带来了一定的性能提升,但是随之而来的负面作用往往不可忽视,引入缓存,你要处理数据一致性问题,缓存的失效,更新等等各种问题,极大的增加了系统整体复杂度,从运维的角度来说,缓存的存在也掩盖了 bug,让 bug 出现在更久之后,距离真实现场更远的地方,从安全的角度来说,缓存也可能会泄露保密数据,但是,我要说但是,缓存的引入将带来极大的性能提升,不管是 cpu 还是 io 的角度。

从 cpu 的角度来说,本身要进行的复杂计算,使用缓存将数据存储起来,无需重复计算,从 io 的角度来说,从缓存去读取数据要远比从磁盘上的数据库读取数据快的多

缓存虽然是空间换时间的方法,但是缓存本身是用来缓解 cpu 和 io 的压力而生的,它的目的并不是直接的提升性能,因为你完全可以直接升级 cpu 和 io 的性能,这样又不会引入那么多的缺陷不是吗?

缓存的属性

  • 吞吐量,读写操作的效率,使用 OPS (每秒的操作量) 来进行衡量,吞吐量越高越好
  • 命中率,成功从缓存中返回的结果和总请求次数的比值,命中率越高越好
  • 扩展功能,除了基本读写之外的扩展功能,比如,最大容量,失效时间,失效事件,命中率统计
  • 是否支持分布式,缓存有进程缓存分布式缓存两大类,前者仅仅为本身节点提供服务,比如你在读写过程中引入了一个数组,或者哈希表,不需要反复读取磁盘,仅需要读取本地数据或者哈希表中的缓存即可获取数据,这种缓存并无网络操作,速度很快,但是缓存的数据不能在各个节点中共享,分布式缓存则相反,它存在于多个独立的缓存节点组成的集群中,这些节点可以分布于不同的数据中心,分布式缓存可以被不同的应用进程所共享,各个组件之间可以很方便的获取相同的缓存数据。

吞吐量

命中率

扩展功能

分布式支持

缓存的风险

缓存穿透

缓存击穿

缓存雪崩

缓存污染

+ + + diff --git "a/\347\263\273\347\273\237\350\256\276\350\256\241\345\237\272\347\241\200/\346\236\266\346\236\204\345\256\211\345\205\250\346\200\247/index.html" "b/\347\263\273\347\273\237\350\256\276\350\256\241\345\237\272\347\241\200/\346\236\266\346\236\204\345\256\211\345\205\250\346\200\247/index.html" new file mode 100644 index 00000000..6ebef239 --- /dev/null +++ "b/\347\263\273\347\273\237\350\256\276\350\256\241\345\237\272\347\241\200/\346\236\266\346\236\204\345\256\211\345\205\250\346\200\247/index.html" @@ -0,0 +1,54 @@ + + + + + + 架构安全性 | 鲁班 - 系统设计大全 + + + + + + + + + + + + diff --git "a/\347\263\273\347\273\237\350\256\276\350\256\241\345\237\272\347\241\200/\347\263\273\347\273\237\350\256\276\350\256\241\347\220\206\350\256\272\345\237\272\347\241\200/index.html" "b/\347\263\273\347\273\237\350\256\276\350\256\241\345\237\272\347\241\200/\347\263\273\347\273\237\350\256\276\350\256\241\347\220\206\350\256\272\345\237\272\347\241\200/index.html" new file mode 100644 index 00000000..d1ebf3ce --- /dev/null +++ "b/\347\263\273\347\273\237\350\256\276\350\256\241\345\237\272\347\241\200/\347\263\273\347\273\237\350\256\276\350\256\241\347\220\206\350\256\272\345\237\272\347\241\200/index.html" @@ -0,0 +1,57 @@ + + + + + + 系统设计理论基础 | 鲁班 - 系统设计大全 + + + + + + + + +

系统设计理论基础

设计系统的工程师叫做架构师,就如同几千年之前的鲁班一样,设计出了精妙绝伦的系统。

架构不是一成不变的,从最早的单体服务,到如今的分布式服务,微服务,云原生,这要求架构师要不断的学习,变化是最重要的设计考虑因素。

世界上不存在银弹,或许你钟爱某一种形式的设计,但是技术不分好坏,我们总是在寻求利弊而已,我们架构师要做的不过是取舍。一切皆是权衡。

技术广度和深度

架构师需要掌握的技能,从技术角度分为技术广度和深度。通常来说,对于架构师,广度的重要性大于深度,没有广度就无法纵观全局。

架构师不可能在所有领域都保持一定的深度,这不现实,人不会有这么多的空余时间,我的建议是,在某个领域保持绝对的技术深度的同时,提高自己的技术广度,就好比,你是局长兼某科科长,在你的科你的技术是绝对的一流,但你还是局长,必须要了解其它科的技术,才能真正的掌握全局。

权衡利弊

微服务一定比单体服务优秀吗?异步通信就是比同步通信好吗?

这个世界是现实的,任何的好处都是有代价的,微服务在可扩展性,高可用性等特征上的确比单体服务优秀,但是它要比单体服务性能更差,复杂度也高很多,花费也要高很多,当我们面向一个场景简单,用户量低的场景下,毫无疑问,选择单体服务是更好的选择。

架构选择没有对错,只有取舍和适合。

模块化

模块化的概念是什么?

我给出一个定义,构建更复杂结构中的一组标准化零件,一个复杂结构中的独立单元。一个函数就是整个代码集群中的一个模块,一个数据库组件就是数据库集群中的一个模块。

我们使用三个标准去评估模块之间的关系:

  • 內聚性
  • 耦合
  • 共生性

內聚性

也称之为内聚力,高内聚的模块指的是:功能单一,独立性强,逻辑清晰,如果分割该模块将得到更坏的结果

耦合

耦合度,指的是模块间的依赖关系,高耦合的模块指的是:模块间的依赖关系过多,模块间的修改会相互影响,如果分割该模块将得到更坏的结果

共生

模块间的依赖关系,如果一个组件的变更需要修改另一个组件才能保证系统整体的运行,那么他们之间是共生关系

一个合理的共生关系通常是合理的。通常来说,弱共生关系更合理

高内聚低耦合的好处

高内聚的好处

提高软件质量:

  • 功能明确:每个模块专注于特定的任务,使得代码逻辑更加清晰,易于理解和维护。开发人员可以快速定位问题所在,减少错误的发生。
  • 可靠性高:由于模块内部的紧密协作,其功能实现更加稳定可靠。一个高内聚的模块通常经过良好的设计和测试,能够在各种情况下正确执行其特定任务。

增强可维护性:

  • 易于修改:当需要对软件进行修改时,高内聚的模块可以独立进行修改,而不会对其他模块产生过多的影响。这大大降低了维护成本和风险,提高了维护效率。
  • 可扩展性强:可以方便地在不影响其他模块的情况下,为高内聚的模块添加新的功能或改进现有功能。这种可扩展性使得软件能够适应不断变化的需求。

提升开发效率:

  • 分工明确:开发人员可以根据模块的功能进行分工合作,提高开发效率。每个开发人员专注于特定的模块,能够更好地理解和实现其功能,减少开发过程中的冲突和重复工作。 +可重用性高:高内聚的模块通常具有较高的可重用性,可以在不同的项目或系统中重复使用。这不仅节省了开发时间,还提高了代码的质量和一致性。

低耦合的好处

提高软件的灵活性:

  • 易于替换:当需要更换某个模块时,低耦合的设计使得可以轻松地替换该模块,而不会对其他模块产生重大影响。这为软件的升级和改进提供了更大的灵活性。
  • 适应变化:低耦合的软件能够更好地适应需求的变化。当需求发生变化时,可以只对受影响的模块进行修改,而不会波及整个系统。

增强软件的可维护性:

  • 独立测试:低耦合的模块可以独立进行测试,这使得测试更加容易和高效。可以针对每个模块编写独立的测试用例,确保其功能的正确性,而不需要考虑其他模块的影响。 +降低维护成本:由于模块之间的依赖关系较少,维护一个低耦合的软件系统相对容易。当出现问题时,可以快速定位问题所在的模块,并进行修复,而不会影响到其他模块。 +提高软件的可扩展性:
  • 方便添加新功能:低耦合的设计使得可以方便地添加新的模块或功能,而不会对现有系统造成太大的影响。新的模块可以独立开发和测试,然后与现有系统进行集成。
  • 支持分布式开发:低耦合的软件更适合分布式开发,不同的开发团队可以独立开发不同的模块,然后进行集成。这种开发方式可以提高开发效率,降低开发风险。

架构特征

功能性相关

  • 可用性:指系统或产品能够被正常使用的程度。
  • 性能:系统或产品在运行时所表现出的各种能力指标。
  • 可扩展性:系统能够方便地进行功能扩展。
  • 弹性:系统能够适应变化和压力的能力。
  • 高效性:强调系统在执行任务时能够以较少的资源消耗实现较高的产出。

安装与部署相关

  • 可安装性:系统或产品能够在特定环境中成功安装的容易程度。
  • 兼容性:指系统能够与其他不同的软件、硬件或系统协同工作的能力。

维护与管理相关

  • 可维护性:系统易于进行维护和修复的程度。
  • 可支持性:系统能够获得技术支持和维护的程度。
  • 可测试性:系统易于进行测试,以便发现和修复潜在的问题。
  • 可观察性:可以对系统的运行状态进行监控和观察。

数据与资源管理相关

  • 可重复利用性:可以多次使用系统的某些部分或整体。
  • 可归档性:系统或数据能够被有效地存档保存。
  • 准确性:对于数据处理或计算任务,确保结果的准确无误。

用户体验相关

  • 易用性:系统易于使用和操作的程度。
  • 可访问性:确保用户能够方便地访问系统或获取信息的程度。
  • 可定制性:允许用户根据自己的特定需求对系统进行个性化设置和调整。

安全与合规相关

  • 可恢复性:系统在出现故障或问题后能够恢复到正常状态的能力。
  • 安全性:保障系统免受各种安全威胁。
  • 认证:确认用户或系统的身份、真实性等的过程。
  • 授权:给予特定用户或实体特定的权利或权限。
  • 可审计性:能够对系统的操作和数据访问进行记录和审查。
  • 法律:与系统或业务相关的法律法规要求。
  • 隐私性:保护用户或系统的私密信息不被泄露的特性。

其他特性

  • 连续性:事物持续不间断的状态。
  • 稳定性:系统在长时间运行过程中保持可靠。
  • 及时性:系统能够在规定的时间内完成任务或响应请求。
  • 互操作性:不同的系统或组件之间能够进行有效的交互和协作。

给架构师的忠告

第一条,不要执迷于架构特征的数量,要尽可能保证简单,举个例子,一个用户量只有几万的小项目,你不能执迷于可扩展性,弹性,高可用性这种架构特性,它要的就是简单而已,做好一定的限流措施,就够了。

第二条,确定系统特性的优先级,比如,我确定了,弹性和性能是优先级,那么该系统的设计就主要围绕这些特性去设计。

第三条,架构师跟外人沟通的时候要使用通用语言,比如,把可行性和简单行改成预算低,时间短,把性能,容错,降级等改成用户满意度,记住,架构师不仅仅是一个技术人员,也是技术管理者,当一个管理者要沟通的时候,他应该使用通用语言,而不是他的专有语言。

第四条,架构师应该会从需求中提炼架构特征,比如,1 万人的学校,需要一个搜索系统,那么你可以提取需要的架构特征,人数不大,可用性要高,预算可能不是太充足,所以后期运维要简单,比如一个企业,员工 100 万,需要一个财务系统,那么这个系统就跟刚才的不同,需要满足高可用行,高性能,需要考虑容灾和服务降级,需要考虑高防护性

kata (opens new window) 是架构师 ted neward 创建的架构设计训练网站,里面有很多的需求,我们可以使用这个网站去锻炼自己提取需求的能力,设计架构的能力

+ + + diff --git "a/\347\263\273\347\273\237\350\256\276\350\256\241\345\237\272\347\241\200/\347\275\221\347\273\234\345\234\250\347\263\273\347\273\237\350\256\276\350\256\241\344\270\255\347\232\204\344\275\234\347\224\250/API\347\275\221\345\205\263/index.html" "b/\347\263\273\347\273\237\350\256\276\350\256\241\345\237\272\347\241\200/\347\275\221\347\273\234\345\234\250\347\263\273\347\273\237\350\256\276\350\256\241\344\270\255\347\232\204\344\275\234\347\224\250/API\347\275\221\345\205\263/index.html" new file mode 100644 index 00000000..a9216991 --- /dev/null +++ "b/\347\263\273\347\273\237\350\256\276\350\256\241\345\237\272\347\241\200/\347\275\221\347\273\234\345\234\250\347\263\273\347\273\237\350\256\276\350\256\241\344\270\255\347\232\204\344\275\234\347\224\250/API\347\275\221\345\205\263/index.html" @@ -0,0 +1,57 @@ + + + + + + 鲁班 - 系统设计大全 + + + + + + + + +

API 网关 (应用网关)

API 网关是所有请求的入口,它接收了所有的 http https tcp 的请求,并将请求转发给后面真正的服务,微服务模式下,这些服务一般都是一些容器,或者也可能是各个数据中心的各自的 API 网关,总而言之,API 网关是一切请求的入口处理工具,它工作相对较少,所以性能非常的高

API 网关通常被部署在后端服务的最前端,来充当安全保护,熔断,限流,等作用,nginx 就是一个简单化的 api 网关,不过常见的 api 网关并不是 nginx,比较常见的有 kongbfe

API 网关的作用

  • 解耦后端架构:或者说灵活配置后端架构,它将需求和真实处理的服务解耦,可以构建更加灵活多样的后端架构 (BaaS)

  • 减少 TLS 协议的使用,TLS 协议加上 http 组成了 https,但是要知道 https 因为多了一层协议,所以势必比单纯的 http 慢,而且 tls 证书也是要花钱的,如果我们配置了 API 网关只需要在最前端部署 tls 协议即可,BaaS 中的服务都可以使用 RPC 协议或者一般的 http 协议

  • API 网关增加安全性,可以对入口流量做鉴权,限流,降级,黑名单,白名单等措施,与此同时,后端的服务也仅仅可以放开对于 API 网关的 ip 访问,从而避免了各种安全风险

  • API 网关减少了运维的难度,所有流量都经过 API 网关,可以做日志记录,监控,统计,这些行为都变得更加简单

  • API 网关可以对流量进行统一更改,比如对于流量进行 gzip 压缩;可以一次性升级所有服务的协议,它只要升级为 http2 或者 3 这种新的协议,对外的服务就相当于升级了所有服务的协议,因为你入口升级了嘛,后端是什么协议都无所谓了,反正暴漏给客户端的协议是升级了;还可以对数据进行格式的转换,例如 xml 转换为 json 等

API 网关

注册中心和服务发现

服务发现是微服务架构中的一个关键环节,用于帮助各个服务能够互相定位并进行通信。以下是它的原理:

服务注册

服务信息收集

当一个服务启动时,它首先会收集自身的相关信息。这些信息包括服务的名称、IP 地址、端口号、服务协议 (如 HTTP、gRPC 等)、服务版本等。例如,一个名为 “user - service” 的微服务,它的 IP 地址可能是 192.168.1.100,端口号是 8080,使用 HTTP 协议,版本是 v1.0。

注册中心通信

服务会将收集到的这些信息发送给一个服务注册中心。服务注册中心是一个存储所有服务信息的地方,常见的注册中心有 Consul、Eureka、Zookeeper 等。 +以 Eureka 为例,服务通过 RESTful API 与 Eureka Server 进行通信。服务发送一个包含自身信息的注册请求,Eureka Server 收到请求后,会将服务信息存储在其内部的注册表中。这个注册表是一个数据结构,通常是一个键值对的集合,键是服务名称,值是服务的详细信息列表。

服务发现过程

客户端请求发现服务

当一个服务需要调用另一个服务时,它首先会向服务发现组件发送一个发现请求。例如,一个订单服务需要调用用户服务来获取用户信息,订单服务就会发起服务发现请求。

发现组件查询注册中心

服务发现组件收到请求后,会查询服务注册中心。它会根据目标服务的名称在注册中心的注册表中查找对应的服务信息。 +假设使用 Consul 作为注册中心,服务发现组件会向 Consul 发送一个 HTTP GET 请求,请求的路径可能是类似 “/v1/catalog/service/user - service”,Consul 会返回用户服务的 IP 地址、端口号等信息。

缓存机制

为了提高性能,很多服务发现系统会使用缓存。服务发现组件在获取服务信息后,会将信息缓存起来。这样,在一定时间内 (缓存有效期内),如果有相同的服务发现请求,就可以直接从缓存中获取信息,而不需要再次查询注册中心。

例如,一个缓存的有效期设置为 30 秒,在这 30 秒内,所有对某个服务的发现请求都可以直接使用缓存中的 IP 地址和端口号,减少了与注册中心的交互次数,提高了效率。

返回服务信息给客户端

服务发现组件将从注册中心 (或者缓存) 获取的目标服务信息返回给客户端。客户端得到目标服务的 IP 地址和端口号后,就可以根据这些信息建立与目标服务的连接,并发起服务调用。例如,订单服务得到用户服务的 IP 地址和端口号后,就可以使用 HTTP 协议向用户服务发送请求,获取用户的详细信息。

服务信息更新与同步

注册中心会定期检查服务的健康状态。如果一个服务因为故障或者网络问题等不可用了,注册中心会将其标记为不可用状态,并且在服务发现时不会返回这个不可用服务的信息。 +同时,当服务的信息 (如 IP 地址因为重新部署而改变、服务版本升级等) 发生变化时,服务会主动向注册中心发送更新请求。注册中心会更新注册表中的信息,并且通过合适的机制 (如推送通知或者客户端定期查询) 将更新后的信息同步给服务发现组件,以确保服务发现的信息始终是准确的。

服务发现组件是怎么知道要调用哪个服务的呢?

服务发现组件知道要调用哪个服务是由程序员通过服务名称的指定、配置文件设置或者编程接口使用等方式来主动控制的

当新的服务组件注册到注册中心时,如果注册中心具有推送功能,它会尝试向已注册的服务发现推送更新信息。

+ + + diff --git "a/\347\263\273\347\273\237\350\256\276\350\256\241\345\237\272\347\241\200/\347\275\221\347\273\234\345\234\250\347\263\273\347\273\237\350\256\276\350\256\241\344\270\255\347\232\204\344\275\234\347\224\250/CDN/index.html" "b/\347\263\273\347\273\237\350\256\276\350\256\241\345\237\272\347\241\200/\347\275\221\347\273\234\345\234\250\347\263\273\347\273\237\350\256\276\350\256\241\344\270\255\347\232\204\344\275\234\347\224\250/CDN/index.html" new file mode 100644 index 00000000..74dd9bd9 --- /dev/null +++ "b/\347\263\273\347\273\237\350\256\276\350\256\241\345\237\272\347\241\200/\347\275\221\347\273\234\345\234\250\347\263\273\347\273\237\350\256\276\350\256\241\344\270\255\347\232\204\344\275\234\347\224\250/CDN/index.html" @@ -0,0 +1,58 @@ + + + + + + 鲁班 - 系统设计大全 + + + + + + + + +

CDN 内容分发网络

我们是用 CDN 就是要解决三个问题 +1。网站服务器接入网络运营商带宽有限的问题 +2。网络各个中间节点连接太长的问题 +3。网站到用户延迟太长的问题

当我们的网站将源地址发送给 CDN 的时候,CDN 服务商就会给你一个 CNAME 网址,例如 shgopher.cdn.github.io

CNAME:域名别名

你得到的 CNAME 会在你的 DNS 服务商注册一条 CNAME 记录

当第一次未命中 CDN 地址的 DNS 查询,域名服务商解析 CNAME 后会返回给本地 DNS 缓存

当你为你的网站资源部署 CDN 的时候,CDN 域名会在 DNS 或者 HTTP DNS 系统中返回 N 个 IP 地址,这些是位于全国或者全球各个部分,距离用户最近的 IP 地址,所以使用 HTTP DNS + CDN 才能获取最佳的体验

这个时候你访问的 CDN 就会去访问源站,CDN 会将请求转发到源站,源站返回数据,CDN 将数据返回给用户,然后 CDN 就会缓存数据,下次访问的时候直接从缓存中读取,从而减少请求的次数,从而提高网站访问速度

关于 CDN 请求源站的方法其实有两种,一种是被动的,等 cdn 访问就行了,另一种是主动的,就是在部署 cdn 的时候就同时主动去访问源站来形成缓存,一般都采用主动触发加上被动设置缓存失效时间的方式。

CDN 寻找最近的 ip

CDN (内容分发网络) 在众多 IP 地址中选中一个距离用户最近的 IP 主要通过以下几种方式:

一、地理定位

CDN 通常会利用 IP 地址定位技术来确定用户的大致地理位置。每个 IP 地址都可以被映射到一个特定的地理区域,CDN 系统会维护一个庞大的 IP 地址数据库,通过查询这个数据库,能够快速判断用户的位置。例如,根据 IP 地址的分配规则,可以确定某个特定 IP 段来自亚洲地区,更具体地可能来自中国的某个省份或城市。

二、网络测量和延迟评估

主动测量

CDN 节点会定期向不同的网络位置发送探测数据包,以测量网络延迟和带宽等参数。这些探测可以针对特定的 IP 地址范围或者广泛的网络区域进行。例如,CDN 节点会向各个主要的网络运营商的骨干节点发送探测包,以了解到不同地区的网络状况。 +通过这些主动测量,CDN 可以建立一个网络延迟矩阵,记录从每个 CDN 节点到不同地理位置的网络延迟情况。当用户请求内容时,CDN 系统可以根据用户的地理位置,查询这个延迟矩阵,找到延迟最小的 CDN 节点对应的 IP 地址返回给用户。

被动测量

当用户首次访问 CDN 服务时,CDN 系统可以在后台记录用户的请求路径和延迟信息

例如,记录用户请求经过的网络路由器、交换机等设备的 IP 地址和延迟时间。通过对大量用户请求的被动测量,CDN 系统可以不断优化对不同地区用户的 IP 地址选择策略。如果发现某个地区的用户普遍对某个特定的 CDN 节点响应速度较快,那么在后续的请求中,对于来自该地区的用户,系统就更有可能选择这个节点的 IP 地址。

三、DNS 智能解析

负载均衡考虑

除了距离因素外,CDN 的 DNS 系统还会考虑各个 CDN 节点的负载情况。如果某个距离用户较近的 CDN 节点负载过高,系统可能会选择一个稍微远一些但负载较低的节点,以确保用户能够获得快速稳定的服务。例如,当多个用户同时请求同一内容时,DNS 系统会动态地分配请求到不同的 CDN 节点,以平衡负载。

CDN 应用内容

  1. 静态资源:如 CSS、JS、图片等,这些资源可以缓存一段时间,减少请求次数,提高网站性能。
  2. 安全防御:CDN 可以作为堡垒机来防范攻击对于源站的影响
  3. 协议隔离:很多源站是 http 协议,但是又想使用 https,CDN 可以做协议转换,将 http 协议转换为 https 协议
  4. 缓存控制:CDN 可以根据缓存策略来控制缓存时间,例如,对于静态资源,可以设置缓存时间为一年,对于动态资源,可以设置缓存时间为10分钟。
  5. 修改资源:CDN 可以修改源站的资源,例如,将源站的图片压缩,将源站的 CSS、JS 合并,将源站的 HTML 压缩等,从而提高网站性能。
  6. 访问控制:CDN 可以实现白名单,黑名单的控制,可以根据 ip 的访问流量去限流控制
  7. 注入功能:CDN 可以在不改变源站的配置的情况下,向源站注入自定义的脚本,例如,注入广告代码,统计代码等。
  8. 充当 VPN 的功能
+ + + diff --git "a/\347\263\273\347\273\237\350\256\276\350\256\241\345\237\272\347\241\200/\347\275\221\347\273\234\345\234\250\347\263\273\347\273\237\350\256\276\350\256\241\344\270\255\347\232\204\344\275\234\347\224\250/DNS/index.html" "b/\347\263\273\347\273\237\350\256\276\350\256\241\345\237\272\347\241\200/\347\275\221\347\273\234\345\234\250\347\263\273\347\273\237\350\256\276\350\256\241\344\270\255\347\232\204\344\275\234\347\224\250/DNS/index.html" new file mode 100644 index 00000000..64d1c560 --- /dev/null +++ "b/\347\263\273\347\273\237\350\256\276\350\256\241\345\237\272\347\241\200/\347\275\221\347\273\234\345\234\250\347\263\273\347\273\237\350\256\276\350\256\241\344\270\255\347\232\204\344\275\234\347\224\250/DNS/index.html" @@ -0,0 +1,55 @@ + + + + + + 鲁班 - 系统设计大全 + + + + + + + + +

DNS 域名协议服务

dns 是域名解析协议,它负责将域名解析为具体的 ip 地址,例如 www.example.com 解析为 11.32.33.433

DNS 的多级寻找机制

dns 系统拥有本地缓存,所以它会优先查询本地缓存,这也是我们所谓的 “更改 hosts 就能访问 xx 网站” 的实现原理,因为 hosts 中保存的就是域名对应的 ip 地址,当本地缓存中存在 URL 对应的 ip 地址时,就不会去请求本地域名服务器,直接返回具体的 ip 即可,当本地缓存失效之后,系统就会委托本地域名服务器 (本地 DNS --- Local DNS,比如谷歌的 8.8.8.8,阿里的 114.114.114.114 等等) 按照域名的层级来查询

hosts 不是本地缓存,系统会查询 hosts 然后再去查询本地缓存,不过 hosts 的优先级大于本地缓存,hosts 存在于 Linux 的 /etc/hosts Windows 的 C:\Windows\System32\drivers\etc\hosts 中 macOS 的 /etc/hosts 中

DNS 缓存存在于浏览器和操作系统中,hosts 也会存在一定的记录,其中优先级是 hosts 最高,浏览器缓存次之,操作系统缓存最低

在上述的描述中,当本地无缓存目标 URL 对应的 ip 时,通常会去使用本地域名服务商去查询,比如谷歌的 8.8.8.8,如果本地域名服务商有 URL 的缓存,返回数据即可,那么,如果本地域名服务商也没有数据,它会替代用户去不断的去请求更高一级的域名服务器,从 com 这个根域名服务器为开始,就开始查询不同层级域名的 ip 地址

这是一个域名解析的步骤图

dns

需要说明的是,权威服务器返回的不一定就是 ip 地址,也可以有很多类型 (opens new window)

这是一个 dns 记录的例子

Domin(域名) TTL(生存周期) Class(协议类型) Type(记录类型) Rdata(记录数据)
www.example.com 86400 IN A 2.2.2.2

DNS 本地缓存及其优先级

在 DNS 缓存系统中,一般的查询的优先级顺序一般如下:

  1. Hosts 文件:这是最优先的,任何在/etc/hosts 文件中定义的条目都会被直接使用,而不会发送 DNS 请求。

  2. 操作系统 DNS 缓存:如果 hosts 文件中没有相应的条目,操作系统会检查其自身的 DNS 缓存。在 macOS 中,这个缓存是由系统服务管理的,对于所有应用程序都是透明的。

  3. 浏览器 DNS 缓存:如果操作系统缓存中没有找到相应的记录,浏览器才会检查其自身的 DNS 缓存。浏览器缓存是特定于该浏览器进程的,并且在浏览器关闭后可能会被清除

为什么请求发生在浏览器,但是浏览器的缓存优先级不是最高的呢?:

浏览器缓存的优先级通常不会高于操作系统的 DNS 缓存或 hosts 文件中的条目。这是因为 DNS 解析是一个系统层面的操作,它发生在浏览器向 DNS 服务器发起请求之前。

DNS 预留技术

<link rel="dns-prefetch" href="//mail.example.com">
+

dns 预留技术,通过在前端设置标签的方法,让浏览器提前对其他所需的域名进行预解析,从而减少请求时间

DNS 的作用

dns 其实就是用户和真实 ip 之间的桥梁,用户使用域名通过 dns 来访问网站。

我们在部署 dns 的时候,可以部署多个入口 ip,这样当某个 ip 挂了,其他 ip 可以继续提供服务,从而保证了服务的可用性,并且实现了负载均衡的功能,如果我们突然要更换 ip,那么就可以通过 dns 服务内部更换 ip 对客户完全无感

DNS 的安全性

最后,我们要知道,dns 服务通过多级缓存是,多级访问是有效的减少了不同层级的服务器的压力,但是同时也增加了被中间攻击的比例,分了多少层就会被攻击多少次,记不记得你浏览某个网站的时候你使用宽带上网和手机无线上网获取到的网页不一致的情况,就是因为被 dns 劫持了,某个正确 ip 被换成了广告 ip,广告 ip 将正常的网页 download 下来,然后加入广告发给你 (本来要去喝雪碧呢,tmd 饭店老板把雪碧买回来兑进去了好多白开水)

最近出现的 HTTP DNS 服务将原来的多级缓存多级查询的 DNS 服务给改成了基于一个 https 协议的查询服务器,一次性查询到 ip 地址,虽然增加了服务器开销和容积,但是确实减少了中间商,下一节我们重点谈谈 HTTP DNS 服务

+ + + diff --git "a/\347\263\273\347\273\237\350\256\276\350\256\241\345\237\272\347\241\200/\347\275\221\347\273\234\345\234\250\347\263\273\347\273\237\350\256\276\350\256\241\344\270\255\347\232\204\344\275\234\347\224\250/HTTPDNS/index.html" "b/\347\263\273\347\273\237\350\256\276\350\256\241\345\237\272\347\241\200/\347\275\221\347\273\234\345\234\250\347\263\273\347\273\237\350\256\276\350\256\241\344\270\255\347\232\204\344\275\234\347\224\250/HTTPDNS/index.html" new file mode 100644 index 00000000..37068c1b --- /dev/null +++ "b/\347\263\273\347\273\237\350\256\276\350\256\241\345\237\272\347\241\200/\347\275\221\347\273\234\345\234\250\347\263\273\347\273\237\350\256\276\350\256\241\344\270\255\347\232\204\344\275\234\347\224\250/HTTPDNS/index.html" @@ -0,0 +1,107 @@ + + + + + + 鲁班 - 系统设计大全 + + + + + + + + +

HTTP DNS 技术

传统本地 DNS 服务器使用 udp 的方式进行多级查询,每一层都有被钓鱼,被更换属于很多的风险,那么我们的本地 DNS 服务器是否可以改为使用 HTTP 协议呢?是否可以不需要逐层查询直接访问到目标服务器?HTTP DNS 就是基于 HTTP 协议的域名解析服务,它将域名解析请求发送到 HTTP 服务器,HTTP 服务器根据域名解析请求直接返回对应的 ip 地址,从而实现域名解析的功能,从而解决了传统 DNS 服务器多级缓存和 DNS 劫持的问题,你可以理解为 HTTP DNS 仿佛一个代理,它就拥有了所有域名解析的功能,并且可以做到无中间商,阿里的 HTTP DNS (opens new window) 介绍在这里

使用 dns 的弊端

  1. 传统的 local DNS 服务尽管拥有缓存机制,但不可避免的还是会有递归查询的问题,这严重的影响了响应时间
  2. 权威 dns 服务是针对本地域名服务器的 ip 去返回 ip 的,这跟真实用户的 ip 地址不同,严重影响了负载均衡的本意
  3. DNS 劫持,给你一个假网站,运营商通过本地域名服务器直接给你造假 DNS 劫持,黑客选择篡改计算器的 Hosts 去 dns 劫持

HTTP DNS 的原理

客户端使用 http DNS 去解析域名,HTTP DNS 如果有缓存直接返回,如果没有它会去权威 DNS 服务器发起域名解析请求,并返回最优 ip,这其中减少了去根 dns,顶层 dns 的访问,客户端可能发送一个类似于 “http://11.1.1.1/?dn=[domain_name]” 的请求,其中 “[domain_name]” 是要解析的域名,如果你需要更加安全,也可以将此处的 http 改成 https

客户端通过访问一个固定的 HTTP DNS IP 地址去解析域名,不是通过一个域名 (如果通过域名还不是还得解析这个域名的 ip 嘛。。。对吧)

为了保证高性能和高可用,HTTP DNS 通过 BGP 边界网关协议让这个 ip 地址让全国的运营商客户都能就近访问,同时多个数据中心部署多个 HTTP DNS 服务节点,主备方案,任意节点故障均可切换备份节点

配置高可用的 DNS 服务 --- 包括 HTTP DNS 和 local DNS

  1. 首先我们优先在客户端布置 HTTP DNS 服务
  2. 为了防止 HTTP DNS 服务器故障,我们可以在 HTTP DNS 后面部署传统的 local DNS 服务
  3. HTTP DNS 服务可以返回多个 ip 地址,我们可以逐个测试连通性,不通就换下一个
  4. 如果本地 local DNS 服务也失败了,我们为了高可用,可以在 app 中硬写入一个映射表,写入一些兜底的 ip 地址
  5. 预请求 IP 并且缓存起来

传统使用 UDP 协议的 DNS 服务请求代码

import struct
+import socket
+
+def send_dns_query(domain_name, query_type):
+    # 创建 UDP 套接字
+    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # 从这看出来 使用的是 UDP 的传输协议
+
+    # 设置 DNS 服务器地址和端口
+    dns_server = ("8.8.8.8", 53)
+
+    # 构造 DNS 请求报文
+    transaction_id = 0x1234  # 可以设置一个随机的事务 ID
+    flags = 0x0100  # 标准查询,递归查询标志位设为 1
+    num_questions = 1
+    num_answers = 0
+    num_authority_rrs = 0
+    num_additional_rrs = 0
+
+    # 处理域名,采用域名压缩格式
+    parts = domain_name.split('.')
+    encoded_domain = b""
+    for part in parts:
+        encoded_domain += bytes([len(part)]) + part.encode()
+    encoded_domain += b"\x00"
+
+    query_type_code = {
+        "A": 1,
+        "AAAA": 28,
+        # 添加其他查询类型的代码映射
+    }
+    qtype = query_type_code[query_type]
+    qclass = 1  # IN(Internet)类
+
+    request = struct.pack(">HHHHHH", transaction_id, flags, num_questions, num_answers, num_authority_rrs, num_additional_rrs)
+    request += encoded_domain
+    request += struct.pack(">HH", qtype, qclass)
+
+    # 发送请求
+    sock.sendto(request, dns_server)
+
+    # 接收响应
+    response, _ = sock.recvfrom(4096)
+
+    # 处理响应
+    #...(这里省略处理响应报文的具体代码)
+
+    sock.close()
+

在浏览器中使用 HTTP DNS

HTTP DNS 通常是为客户端应用程序设计的,而浏览器本身并不直接支持 HTTP DNS +因此如果要实现 http DNS 通常要使用插件

使用支持 HTTP DNS 的浏览器插件:

一些专门的插件可以在浏览器环境下实现 HTTP DNS 功能。这些插件通常会拦截浏览器的 DNS 请求,然后通过 HTTP 协议将请求发送到特定的 HTTP DNS 服务器进行解析。安装并启用这类插件后,插件会在后台自动处理域名解析,用户无需进行复杂的设置。例如,某些网络优化插件就具备这样的功能,它们可以改善网络访问速度和稳定性,同时防止 DNS 劫持。

浏览器厂商集成 HTTP DNS 功能:

部分先进的浏览器可能会在未来的版本中集成 HTTP DNS 功能。如果浏览器厂商决定支持 HTTP DNS,他们可以在浏览器的设置中提供相应的选项,让用户可以选择启用 HTTP DNS 解析。当用户开启此功能后,浏览器会自动使用 HTTP DNS 服务器进行域名解析,而不再依赖于传统的 DNS 系统。这样可以提高浏览器的安全性和性能,确保用户能够快速、准确地访问网站。

通过网络代理或 VPN 服务:

一些网络代理或 VPN 服务可能会内置 HTTP DNS 功能。当用户连接到这些代理或 VPN 时,它们可以拦截浏览器的网络流量,并使用自己的 HTTP DNS 服务器进行域名解析。这种方式虽然不是直接在浏览器中实现 HTTP DNS,但可以通过第三方服务来实现类似的效果。不过,使用网络代理或 VPN 也可能会带来一些其他问题,如网络速度下降、隐私问题等,因此需要谨慎选择可靠的服务提供商。 +总的来说,目前在浏览器中使用 HTTP DNS 可能需要借助一些额外的工具或服务,但随着技术的发展,未来可能会有更多直接在浏览器中实现 HTTP DNS 的方法出现。

在 app 中使用 HTTP DNS

许多流行的网络请求库 (如 OkHttp、Volley 等) 支持自定义 DNS 解析器。可以通过编写自定义的 DNS 解析器来实现 HTTP DNS 功能。

OkHttpClient client = new OkHttpClient.Builder()
+   .dns(new MyHttpDnsResolver())
+   .build();
+

全局设置 http dns

HttpDnsManager.getInstance().init("your_http_dns_server_url");
+

在 HTTP DNS 中的本地缓存优先级

HTTP DNS 请求是由应用层直接发起的,而不是通过操作系统的 DNS 解析器。这意味着 HTTP DNS 请求不会经过传统的 DNS 解析路径,包括不会检查 hosts 文件或操作系统的 DNS 缓存

HTTP DNS 场景下的缓存优先级:

  1. HTTP DNS 服务端返回的数据:应用程序直接从 HTTP DNS 服务端获取域名解析结果,并根据返回的信息进行后续操作。
  2. 应用程序内部缓存:应用程序可能会在内部缓存 HTTP DNS 返回的结果,以便在一定时间内重复使用这些信息。

所以 HTTP DNS 系统的本地客户端缓存:

  • 不会检查 /etc/hosts 文件。
  • 不会查询操作系统的 DNS 缓存。
  • 不会依赖浏览器的 DNS 缓存。
+ + + diff --git "a/\347\263\273\347\273\237\350\256\276\350\256\241\345\237\272\347\241\200/\347\275\221\347\273\234\345\234\250\347\263\273\347\273\237\350\256\276\350\256\241\344\270\255\347\232\204\344\275\234\347\224\250/HTTP\347\274\223\345\255\230/index.html" "b/\347\263\273\347\273\237\350\256\276\350\256\241\345\237\272\347\241\200/\347\275\221\347\273\234\345\234\250\347\263\273\347\273\237\350\256\276\350\256\241\344\270\255\347\232\204\344\275\234\347\224\250/HTTP\347\274\223\345\255\230/index.html" new file mode 100644 index 00000000..4777d539 --- /dev/null +++ "b/\347\263\273\347\273\237\350\256\276\350\256\241\345\237\272\347\241\200/\347\275\221\347\273\234\345\234\250\347\263\273\347\273\237\350\256\276\350\256\241\344\270\255\347\232\204\344\275\234\347\224\250/HTTP\347\274\223\345\255\230/index.html" @@ -0,0 +1,68 @@ + + + + + + HTTP 缓存 | 鲁班 - 系统设计大全 + + + + + + + + +

HTTP 缓存

HTTP 缓存指的是不经过后端,客户端直接根据缓存的内容对目标网站状态进行判断。

常见的 HTTP 缓存的典型应用就是 301 重定向,你会发现如果你不手动删除浏览器缓存,服务器设置的新的 301 重定向,浏览器还是读取旧的缓存,而不是重新请求。

HTTP 强制缓存

强制缓存,强制你去缓存,设置一个时间,这个时间内,你后端不管咋变,反正我都给你缓存了

  • Expires
  • Cache-Control

用后面那个,前面那个设置的不完善,设计的 bug 很多

协商缓存

协商缓存跟强制缓存不同,它没有规定时间段内必须缓存的机制,当你设置参数时它才会去缓存,所以属于协商机制

  • Last-Modified if-modified-since:Last-Modified 服务器响应时返回的 header,告知客户端这个资源的最后修改时间,当客户端再次请求的时候会通过 if-modified-since 把之前收到的资源最后修改时间传给服务器,服务器根据这个时间判断是否需要返回最新资源,如果不需要返回最新资源,则返回 304

比如 last-modified:Wed,08 Jun 2016 08:05:08 GMT,最后的修改时间是 8 点5分8秒,那么客户端的下次请求就将这个时间发送给服务器,服务器去查看资源有没有更新的版本,如果没有就返回 304,如果有就返回新的资源和新的 last-modified

  • ETag 和 if-none-match 跟上面的那一对差不多其实,只是这个 Etag 是一个资源唯一标识,如果客户端发送的 if-none-match 和这个 ETag 相同,则返回 304,服务器根据这个 ETag 判断是否需要返回最新资源

那么 Etag 机制和 Last-Modified 机制有什么区别呢?Etag 精度高但是性能差,因为它需要计算哈希值嘛,而 Last-Modified 精度低但是性能高,它只需要比较时间戳

内容协商机制

在 http 协议中,一个 url 地址是可能根据比如语言不同,压缩方法不同,一个 URL 返回不同的资源的,所以我们需要设置 Accept-和 content- 去协商内容的,使用 Vay 标识符去设置协商内容

//客户端请求:
+GET /resource HTTP/1.1
+Host: example.com
+Accept-Language: zh-CN,zh;q=0.9
+User-Agent: [Your User-Agent String]
+
+
+// 服务器响应:
+HTTP/1.1 200 OK
+Vary: Accept-Language, User-Agent // Vay是服务器告知客户端,服务器将根据vay后面的字段来返回不同的资源内容
+Content-Language: zh-CN
+Content-Type: [Appropriate Content-Type]
+[Resource Content in Chinese Simplified]
+
+

原理:当客户端发送请求时,Accept-Language 传达了语言偏好,同时 User-Agent 可以提供关于客户端类型等信息。服务器在响应时,将 Accept-Language 和 User-Agent 放在 Vary 响应头后面,表示缓存机制需要根据这两个请求头的值来决定是否返回缓存的资源。如果不同的客户端发送的 Accept-Language 或 User-Agent 不同,服务器可能会返回不同版本的资源。这样可以确保在不同语言偏好和不同客户端类型的情况下,都能为用户提供最合适的资源内容。

协商机制的失效

协商机制在地址输入,跳转,甚至刷新的时候都会生效,如果想让失效,只能强制刷新 control+ F5 或者禁止缓存才会失效,失效的话,客户端就会向服务器发送 “Cache-Control:no-cache” 的标志,服务器如果获取这个标识就会发生新的资源

协商机制的局限性

http 协议并非强制性协议,服务器也可以完全不 care 这个 no-cache 标志,不过这属于服务器设计与实际预期不一致的情况,属于设计不规范的行为。

+ + + diff --git "a/\347\263\273\347\273\237\350\256\276\350\256\241\345\237\272\347\241\200/\347\275\221\347\273\234\345\234\250\347\263\273\347\273\237\350\256\276\350\256\241\344\270\255\347\232\204\344\275\234\347\224\250/LVS/index.html" "b/\347\263\273\347\273\237\350\256\276\350\256\241\345\237\272\347\241\200/\347\275\221\347\273\234\345\234\250\347\263\273\347\273\237\350\256\276\350\256\241\344\270\255\347\232\204\344\275\234\347\224\250/LVS/index.html" new file mode 100644 index 00000000..52406393 --- /dev/null +++ "b/\347\263\273\347\273\237\350\256\276\350\256\241\345\237\272\347\241\200/\347\275\221\347\273\234\345\234\250\347\263\273\347\273\237\350\256\276\350\256\241\344\270\255\347\232\204\344\275\234\347\224\250/LVS/index.html" @@ -0,0 +1,54 @@ + + + + + + 鲁班 - 系统设计大全 + + + + + + + + + + + + diff --git "a/\347\263\273\347\273\237\350\256\276\350\256\241\345\237\272\347\241\200/\347\275\221\347\273\234\345\234\250\347\263\273\347\273\237\350\256\276\350\256\241\344\270\255\347\232\204\344\275\234\347\224\250/Nginx/index.html" "b/\347\263\273\347\273\237\350\256\276\350\256\241\345\237\272\347\241\200/\347\275\221\347\273\234\345\234\250\347\263\273\347\273\237\350\256\276\350\256\241\344\270\255\347\232\204\344\275\234\347\224\250/Nginx/index.html" new file mode 100644 index 00000000..99681ecd --- /dev/null +++ "b/\347\263\273\347\273\237\350\256\276\350\256\241\345\237\272\347\241\200/\347\275\221\347\273\234\345\234\250\347\263\273\347\273\237\350\256\276\350\256\241\344\270\255\347\232\204\344\275\234\347\224\250/Nginx/index.html" @@ -0,0 +1,54 @@ + + + + + + 鲁班 - 系统设计大全 + + + + + + + + +

web 服务器 Nginx

web 服务器 (web server) 又叫做 HTTP 服务器,它有两大功能,其一是承载了 HTML JS CSS 等静态资源,第二是接收来自浏览器的请求,并返回响应。

常见的 web 服务器有 Apache Nginx,当然现在更多的使用 GO Nodejs 去构建服务,充当了 web 服务器

关于 GO 去充当 web 服务器的,可以去查阅 GOFamily (opens new window),本章主要介绍 Nginx 充当 web 服务器这个功能的使用,至于 Nginx 的七层负载均衡的使用可以查看本章的负载均衡

Nginx 性能非常的不错,这跟它使用了基于事件驱动的并发模型有关

Nginx 使用了主进程去管理工作进程,每一个工作进程都是一个单线程,所以 Nginx 属于多进程和单线程结合的模型,每一个线程都是使用基于事件驱动的并发模型去处理高 io,这跟 js 的并发模型是一致的。

基于事件驱动的并发模型之所以会设计成单线程模型,主要有四个原因:1。避免线程切换带来的开销,2。简化并发模型 3。单线程更易水平扩展 4。单线程 cpu 缓存命中率高

由于 nginx 并没有并行的需求,所以对于一个只考虑高 IO 的设备来说,基于事件驱动的单线程回调模型性能更好,实现更简单,出错率更低。

epoll --- 事件驱动的模型产物

io 多路复用:

IO 多路复用允许一个进程同时监视多个文件描述符 (或者其它的内容),当其中任何一个文件描述符变为可读或可写状态时,进程就会被通知,从而可以进行相应的读写操作。这样,进程就不需要为每个文件描述符都创建一个单独的线程或进程来进行阻塞式的等待,而是可以在一个线程中高效地处理多个文件描述符

**事件驱动的并发模型:**基于事件,当事件触发的时候即可执行之前注册的 callback 函数。当没有触发事件的时候,callback 函数处于等待状态。具体到 epoll 的实现上,它使用一个红黑树去管理文件描述符。当文件描述符上的事件发生时,epoll 会将事件通知放入一个就绪列表中,随后用户程序可以从就绪列表中获取事件,并根据事件类型执行相应的 callback 函数进行处理。

epoll 是 linux 内核提供的一个事件驱动的基于 io 多路复用并发模型,它基于事件驱动的回调模型,在 linux 中,每一个文件描述符都可以注册一个事件,当文件描述符发生变化的时候,内核会通知应用层,应用层通过回调函数处理,并且建议一个通道,复用多个 io,这样就完成了高并发的处理

Nginx 利用了 Linux 内核的 epoll API 来实现了海量流量的处理,Nginx 的工作进程通过 epoll 来监听客户端的请求,当有客户端请求的时候,nginx 会通过回调函数处理请求,处理完请求后,nginx 会通过 epoll 将请求响应给客户端。

+ + + diff --git "a/\347\263\273\347\273\237\350\256\276\350\256\241\345\237\272\347\241\200/\347\275\221\347\273\234\345\234\250\347\263\273\347\273\237\350\256\276\350\256\241\344\270\255\347\232\204\344\275\234\347\224\250/SDN/index.html" "b/\347\263\273\347\273\237\350\256\276\350\256\241\345\237\272\347\241\200/\347\275\221\347\273\234\345\234\250\347\263\273\347\273\237\350\256\276\350\256\241\344\270\255\347\232\204\344\275\234\347\224\250/SDN/index.html" new file mode 100644 index 00000000..c187c287 --- /dev/null +++ "b/\347\263\273\347\273\237\350\256\276\350\256\241\345\237\272\347\241\200/\347\275\221\347\273\234\345\234\250\347\263\273\347\273\237\350\256\276\350\256\241\344\270\255\347\232\204\344\275\234\347\224\250/SDN/index.html" @@ -0,0 +1,57 @@ + + + + + + 鲁班 - 系统设计大全 + + + + + + + + +

sdn

(sdn software defined network) 软件定义网络,它将网络控制平面和数据层面分离,这里面有一个重要的技术 lvs 它就是三层负载均衡,二层负载均衡的运用。

其核心技术就是 LVS

lvs 基本原理

通过修改七层网络中的数据链路层的 mac 协议,网络层的 ip 协议,实现了交换机 (处理 mac 协议) 网关 (处理 ip 协议) 的数据包转发。从而将数据转发到真正的服务器上。

lvs 有四种模式

  • NAT 模式 (三层负载均衡)
  • FULL-NAT 模式 (三层负载均衡)
  • TUN 模式 (二层负载均衡,部分三层负载均衡)
  • DR 模式 (二层负载均衡)

只有仅有二层负载均衡的就只能用在内网中,因为没有 ip 识别是无法在公网中使用的。

只有涉及到了三层负载均衡,就能用在公网中,所以显而易见的,DR 模式最底层,性能最高,但是只能用在内网中

NAT 模式

nat

FULLNAT 模式

fullNat

TUN 模式

由于第三层的数据包,即 IP 数据包中包含了源 (客户端) 和目标 (均衡器) 的 IP 地址,只有真实服务器保证自己的 IP 地址与数据包中的目标 IP 地址一致,这个数据包才能被正确处理。因此,使用这种负载均衡模式时,需要把真实物理服务器集群所有机器的虚拟 IP 地址 (Virtual IP Address,VIP) 配置成与负载均衡器的虚拟 IP 一样,这样经均衡器转发后的数据包就能在真实服务器中顺利地使用

tun

DR 模式

dr +由于需要更改目标 mac 地址,这就意味着该负载均衡器必须与真实的服务在 mac 层能建立通信,所以这就意味着它只能运行在内网中

四种模式对比

模式 优势 劣势
NAT 不需要配置虚拟 ip,可以跨网 流量必须双向流经 lvs,性能较差
FULL-NAT 不需要配置虚拟 ip,可以跨网 丢失客户端 ip,流量必须双向流经 lvs,性能较差
TUN 性能高 必须支持 ip 隧穿的功能,必须配置和 lvs 公网一致的虚拟 ip
DAR 性能最高 仅支持内网通信,并且必须配置和 lvs 公网一致的虚拟 ip

虚拟 ip 的虚拟性质

高可用性:VIP 的存在使得后端真实服务器对于客户端来说是一个统一的服务入口。即使某一个 LVS 服务器出现故障,客户端仍然可以通过 VIP 访问到服务,因为 VIP 可以动态地在不同的 LVS 服务器之间转移。这种灵活性和高可用性是与普通网卡 IP 不同的,普通网卡 IP 如果对应的网卡或主机出现故障,该 IP 就无法正常提供服务了。

负载均衡:VIP 作为前端的统一入口,LVS 服务器可以根据不同的负载均衡算法 (如轮询、加权轮询、最小连接数等) 将客户端请求分配到后端不同的真实服务器上。这就像一个虚拟的服务端点,隐藏了后端真实服务器的 IP 地址和复杂的网络拓扑结构,更像是一个抽象的、虚拟的服务 IP,而非单纯的一个网卡 IP

keepalived

Keepalived 是一款基于 VRRP (Virtual Router Redundancy Protocol,虚拟路由器冗余协议) 实现的高可用性 (HA) 软件。它主要用于服务器的负载均衡和高可用性场景,能够确保在服务器出现故障或网络异常时,服务仍能持续、稳定地提供。

从网络外部看来,VIP 就像是一个独立的、可供访问的 IP 地址,但实际上这个 VIP 可以在多个 LVS 服务器之间灵活切换。在正常情况下,这个 VIP 可能被 “绑定” 在主 LVS 服务器的网卡上,对外提供服务。但这并不是传统意义上的网卡自身的固定 IP,因为当主服务器出现故障时,通过 VRRP 机制,这个 VIP 会迅速地被绑定到备用 LVS 服务器的网卡上。

它的基本原理是:

  • 两台机器配置同一个 vip (虚拟 ip)
  • 两台 lvs 系统通过 keepalived 频繁通信,评估哪个机器分数高,高的那个作为 master,另一台作为备份,得分高的通过 vrrp 组播报文宣称 vip 在这里
  • 如果 master 宕机了,备份机器会立刻宣称 vip 在自己这里

在没有发生故障转移时,备用 LVS 设备通常不会绑定和主设备相同的虚拟 IP (VIP)

在正常情况下,主 LVS 设备会响应 VRRP 通告,从而拥有 VIP 的所有权。此时,从网络层面看,VIP 是绑定在主 LVS 设备的网络接口上的,外部网络流量根据这个 VIP 指向主 LVS 设备。

备用 LVS 设备处于监听状态,它会接收主 LVS 设备发送的 VRRP 通告,以确认主设备的存活状态。它自身并没有绑定这个 VIP,因为如果同时绑定,可能会导致 IP 地址冲突和网络混乱,比如出现流量被不恰当的分流到备用设备或者产生路由环路等问题。

这里的虚拟 ip 实际上就是一个公网 ip。

作为最前面的网关,防火墙作为网关,其公网接口同样具有真实 IP 地址

更多优化方法

  • dpdk,因为 lvs 基于 Linux 内核的 netilter,需要内核态和用户态切换,因此 dpdk,通过申请大内存,以及轮询替代中断,完成更高性能的表现,dpvs (opens new window) 是 dpdk 技术的开源项目

使用 lvs + nginx (或者 kong) 的实战部署

首先,为了提高可用性,我们都会采用集群的方式去部署 lvs 和 nginx,我们通常使用主-从的方式去部署高可用的 lvs 集群的方案,并且通过部署多个该集群来提供性能:、 +lvs-cluster

一个更加高性能的物理路由 + 物理交换机 + lvs + nginx(kong) 的实战部署

这种更加高性能的场景也遵循上文提到的高可用主从备份的方案。

由于从 lvs 开始,整个架构一致,所以我们仅画出前面的架构图 +sdn

+ + + diff --git "a/\347\263\273\347\273\237\350\256\276\350\256\241\345\237\272\347\241\200/\347\275\221\347\273\234\345\234\250\347\263\273\347\273\237\350\256\276\350\256\241\344\270\255\347\232\204\344\275\234\347\224\250/clickAWebSite/index.html" "b/\347\263\273\347\273\237\350\256\276\350\256\241\345\237\272\347\241\200/\347\275\221\347\273\234\345\234\250\347\263\273\347\273\237\350\256\276\350\256\241\344\270\255\347\232\204\344\275\234\347\224\250/clickAWebSite/index.html" new file mode 100644 index 00000000..5a61d337 --- /dev/null +++ "b/\347\263\273\347\273\237\350\256\276\350\256\241\345\237\272\347\241\200/\347\275\221\347\273\234\345\234\250\347\263\273\347\273\237\350\256\276\350\256\241\344\270\255\347\232\204\344\275\234\347\224\250/clickAWebSite/index.html" @@ -0,0 +1,54 @@ + + + + + + 经典面试题之当你点击一个网站的时候到底经历了什么步骤 | 鲁班 - 系统设计大全 + + + + + + + + +

经典面试题之当你点击一个网站的时候到底经历了什么步骤

客户端

点击 www.baidu.com -> 查询本地 DNS 缓存系统,没有就查询各级 DNS 服务器 (App 可以直接使用 HTTP DNS 系统) 查询到 ip 地址 -> 通过 ip 地址访问到目标路由器,(可能通过 DNS 查询到多个 ip 地址) -> 进入到交换机中 -> 进入 lvs 系统 -> 进入 API 网关 -> 如果是 web,就开始返回 HTML 给浏览器,进而在 HTML 中点击其他的链接去访问 BAAS 服务,在这个过程中,通常会使用 https 的方式建立一个长链接 (时间较长的连接),这个过程中双方会有协商,交换密钥,使用 io 多路复用等处理方案

比如在 web 中请求了一个图片,那么这个请求很有可能就是一个 cdn 的请求

后端

+ + + diff --git "a/\347\263\273\347\273\237\350\256\276\350\256\241\345\237\272\347\241\200/\347\275\221\347\273\234\345\234\250\347\263\273\347\273\237\350\256\276\350\256\241\344\270\255\347\232\204\344\275\234\347\224\250/index.html" "b/\347\263\273\347\273\237\350\256\276\350\256\241\345\237\272\347\241\200/\347\275\221\347\273\234\345\234\250\347\263\273\347\273\237\350\256\276\350\256\241\344\270\255\347\232\204\344\275\234\347\224\250/index.html" new file mode 100644 index 00000000..a9e00e69 --- /dev/null +++ "b/\347\263\273\347\273\237\350\256\276\350\256\241\345\237\272\347\241\200/\347\275\221\347\273\234\345\234\250\347\263\273\347\273\237\350\256\276\350\256\241\344\270\255\347\232\204\344\275\234\347\224\250/index.html" @@ -0,0 +1,54 @@ + + + + + + 鲁班 - 系统设计大全 + + + + + + + + + + + + diff --git "a/\347\263\273\347\273\237\350\256\276\350\256\241\345\237\272\347\241\200/\347\275\221\347\273\234\345\234\250\347\263\273\347\273\237\350\256\276\350\256\241\344\270\255\347\232\204\344\275\234\347\224\250/\344\274\240\350\276\223\351\223\276\350\267\257/index.html" "b/\347\263\273\347\273\237\350\256\276\350\256\241\345\237\272\347\241\200/\347\275\221\347\273\234\345\234\250\347\263\273\347\273\237\350\256\276\350\256\241\344\270\255\347\232\204\344\275\234\347\224\250/\344\274\240\350\276\223\351\223\276\350\267\257/index.html" new file mode 100644 index 00000000..0bb1e5e7 --- /dev/null +++ "b/\347\263\273\347\273\237\350\256\276\350\256\241\345\237\272\347\241\200/\347\275\221\347\273\234\345\234\250\347\263\273\347\273\237\350\256\276\350\256\241\344\270\255\347\232\204\344\275\234\347\224\250/\344\274\240\350\276\223\351\223\276\350\267\257/index.html" @@ -0,0 +1,95 @@ + + + + + + 鲁班 - 系统设计大全 + + + + + + + + +

传输链路优化

虽然我们不能左右网络提供商例如联通移动的网络质量,但是我们可以通过一些手段来优化传输链路。

  1. 用 HTTP2 替代 HTTP 1.1

尽管我们在 1.1 的版本中使用了例如 keep-alive 的方法去保持长连接,然后让所有的请求按照 FIFO 的方法去请求,进而减少三次握手所带来的时间延迟,但随之而来的队列阻塞问题也是一个很大的缺陷。

HTTP1.1 中流是最小的单位,在 1.1 中我们没办法将请求拆开,一起发送,因为客户端无法识别这些碎片,然而 HTTP2 帧 (frame) 是最小的单位,用来描述各种资源,每个帧只要带上唯一标识就能判断是同属一个流,客户端可以通过标识来组装成一个完整的流

通过 io 多路复用,每一个域名仅需一个 TCP 的连接,我们可以任意传输资源,因为不需要考虑 tcp 的延迟问题,所以我们也不用刻意缩小连接的次数,所以在 1.1 上把小数据改成大数据的优化方法在 2 上反而变成了反模式,不过 2 中传输大数据如果不分片的话,反而比 1.1 要慢,毕竟你单点人 1.1 是多路分布式传输肯定比你更快了。

应用层 HTTP 的传输层协议在 1.1 和2时代都是 TCP 协议,然而在 HTTP3 的时候我们将 TCP 协议替换为 UDP 协议,UDP 没有丢包重传的机制,UDP 传了就不管了,所以 http3 的可靠性不依靠传输层,而是在应用层上进行安全设置的,HTTP3 可以对每一个流都能单独控制,在 2 的时候 io 多路复用,TCP 协议接收到了大量的数据然后遇到了损坏,这个时候又要开始重传,这就是 HTTP2 传输大文件慢的原因,HTTP3 不使用 TCP 所以它没有这个缺陷,tcp 在连接时不可避免的会三次握手,这在游戏等领域存在了超时,中断,重连,这个过程带来的问题非常的难受,HTTP3 拥有连接标识符,这个唯一标识符就是标识了客户端和浏览器的连接 token,切换网络的时候,只需要向服务器发送一个包含该 token 的数据包就可以重新连接了,即便 IP 地址发生更改也可以连接

总结一下,搞什么优化,用 HTTP3 不香吗?

下面演示一下 HTTP3 tls 证书,ipv6 的静态服务器

package main
+
+import (
+    "github.com/gin-gonic/gin"
+    "github.com/quic-go/quic-go/http3"
+    "log"
+)
+
+func main() {
+    router := gin.Default()
+    router.Static("/", "./static")
+
+    // 指定现成的 TLS 证书和私钥文件路径
+    tlsCertPath := "path/to/your/cert.pem"
+    tlsKeyPath := "path/to/your/key.pem"
+
+    server := http3.Server{ // 可以自动开启ipv6和ipv4
+        Addr: ":8080",
+        Handler: router,
+        TLSConfig: generateTLSConfig(tlsCertPath, tlsKeyPath),
+    }
+
+    err := server.ListenAndServeTLS("", "")
+    if err!= nil {
+        panic(err)
+    }
+}
+
+func generateTLSConfig(certPath, keyPath string) *http3.TLSConfig {
+    return &http3.TLSConfig{
+        Certificates: loadCertificates(certPath, keyPath),
+    }
+}
+
+func loadCertificates(certPath, keyPath string) []http3.TLSConfigCertificate {
+    cert, err := tls.LoadX509KeyPair(certPath, keyPath)
+    if err!= nil {
+        log.Fatalf("加载证书和私钥失败: %v", err)
+    }
+    return []http3.TLSConfigCertificate{cert}
+}
+
+ + + diff --git "a/\347\263\273\347\273\237\350\256\276\350\256\241\345\237\272\347\241\200/\347\275\221\347\273\234\345\234\250\347\263\273\347\273\237\350\256\276\350\256\241\344\270\255\347\232\204\344\275\234\347\224\250/\345\244\232\347\272\247\345\210\206\346\265\201/index.html" "b/\347\263\273\347\273\237\350\256\276\350\256\241\345\237\272\347\241\200/\347\275\221\347\273\234\345\234\250\347\263\273\347\273\237\350\256\276\350\256\241\344\270\255\347\232\204\344\275\234\347\224\250/\345\244\232\347\272\247\345\210\206\346\265\201/index.html" new file mode 100644 index 00000000..3c9f0708 --- /dev/null +++ "b/\347\263\273\347\273\237\350\256\276\350\256\241\345\237\272\347\241\200/\347\275\221\347\273\234\345\234\250\347\263\273\347\273\237\350\256\276\350\256\241\344\270\255\347\232\204\344\275\234\347\224\250/\345\244\232\347\272\247\345\210\206\346\265\201/index.html" @@ -0,0 +1,54 @@ + + + + + + 鲁班 - 系统设计大全 + + + + + + + + +

系统的多级分流

我们使用的现在互联网系统,都存在多个分流的装置,从最开始的 DNS 开始就可以部署分流,继而去到网关,负载均衡器,缓存,服务集群,数据库集群,等等。

分流系统根据所在的部位不同也可以分为不同的种类

  • 客户端等位于用户最近的部分,例如 http 本地缓存,可以减少后端的 io 数量,dns 缓存,减少 dns 的请求数量,cdn,反向代理,这些都是位于客户端的分流系统
  • 可线性扩展的构建,比如分布式缓存,数据库集群
  • 运维构建,例如,注册中心,配置中心,这种辅助的系统,对于整个系统至关重要,对于这些影响全局的运维构建,必须部署集群,来时刻提高容灾能力
  • 容易形成单点的部件,必须提高竖向能力,也就是提示该机器的性能,比如负载均衡器,网关,入口路由

设计要点

  • 减少单点服务的数量,提高单点服务的性能
  • 最大程度减少达到单点部件的流量,尽可能让需求分流,比如一个数据,http 缓存可以提供,cdn 可以提供,web 服务器可以提供,后端服务可以提供,数据库可以提供,那么就应该让各个组件分流这些请求,能用 http 缓存的流量就别后面请求,能让 cdn 提供的,就分流一部分给 cdn。
  • 简单的系统才是好系统,在满足需求的情况下,系统越简单越好,组件越多,出错的几率越高
+ + + diff --git "a/\347\263\273\347\273\237\350\256\276\350\256\241\345\237\272\347\241\200/\347\275\221\347\273\234\345\234\250\347\263\273\347\273\237\350\256\276\350\256\241\344\270\255\347\232\204\344\275\234\347\224\250/\350\264\237\350\275\275\345\235\207\350\241\241/index.html" "b/\347\263\273\347\273\237\350\256\276\350\256\241\345\237\272\347\241\200/\347\275\221\347\273\234\345\234\250\347\263\273\347\273\237\350\256\276\350\256\241\344\270\255\347\232\204\344\275\234\347\224\250/\350\264\237\350\275\275\345\235\207\350\241\241/index.html" new file mode 100644 index 00000000..9891b792 --- /dev/null +++ "b/\347\263\273\347\273\237\350\256\276\350\256\241\345\237\272\347\241\200/\347\275\221\347\273\234\345\234\250\347\263\273\347\273\237\350\256\276\350\256\241\344\270\255\347\232\204\344\275\234\347\224\250/\350\264\237\350\275\275\345\235\207\350\241\241/index.html" @@ -0,0 +1,138 @@ + + + + + + 鲁班 - 系统设计大全 + + + + + + + + +

负载均衡

一共分为七层网络模型,分别是

  • 7 应用层:http
  • 6 表达层
  • 5 会话层
  • 4 传输层:tcp
  • 3 网络层:ip
  • 2 数据链路层:wifi
  • 1 物理层:物理网卡

四层负载均衡

四层负载均衡的意思是指的是这些负载均衡的工作模式特点是维持同一个 tcp 连接,并不是第四层的负载均衡,但是其实做负载均衡的是在第二层和第三层

二层

数据链路层传输的内容是数据帧,我们这里讨论的是以太网帧,其中以太网帧还有很多的数据,我们关注 MAC 目标地址和 Mac 源地址,每一块网卡都有一个专属直接的 Mac 地址,以太帧会告诉交换机此连接从哪个网卡来的到哪个网卡去的。

链路层要做的转发就是将目标帧的 MAC 地址给修改了,对于三层来说,根本察觉不到,这才是真的转发,而不是代理

只要真实服务器的 ip 地址保证跟数据包中的 ip 地址一致,数据就可以被转发

我们要做的就是将真实物理服务器所在的虚拟 ip 地址配置成跟负载均衡器的虚拟 ip 一致即可

虚拟 IP 地址的实现方式通常是通过软件来进行配置和管理。例如,在网络设备、服务器操作系统或者负载均衡软件中,可以设置虚拟 IP 地址,并将其与特定的服务或应用程序关联起来。同时,虚拟 IP 地址也需要与网络基础设施进行配合,确保数据包能够正确地路由到对应的服务器上。

这种转发叫做三角模式,因为响应就不需要经过转发器了

二层负载均衡器有个缺点就是只能在一个子网中使用,因为它是修改的 mac 地址,这就说明它与真实的服务器通信必须是二层可达的状态。

三层

以 ip 协议为例,ip 协议包括 headers 和 payload,其中我们只关注 headers 中的源 ip 和目标 ip

三层负载均衡有两种转发模式

第一种,保持原来的数据包不变,新创建一个包,将原来包的 headers 和 payload 作为另外新包的 Payload 内容,在新包的 headers 中写入真实的服务器 ip 作为目标 ip,然后在达到目标服务器之后,再进行拆包动作

这种模式仍必须通过专门的配置,必须保证所有的真实服务器与均衡器有着相同的虚拟 IP 地址

NAT 模式:也可以直接替换 header 中的目标 ip,不过这样的话,这个转发器就不能取消了,必须充当中间人的身份了,服务器返回的内容中源 ip,客户端可不认识啊。客户端只认识中间的转发器,所以不能取消

还有一种更加彻底的 NAT 模式:即均衡器在转发时,不仅修改目标 IP 地址,连源 IP 地址也一起改了,源地址就改成均衡器自己的 IP,但是这样有一些需要根据目标 IP 进行控制的业务逻辑就无法进行

七层负载均衡

只有二三层属于数据的转发,到 tcp 之后都属于代理,因为 tcp 协议之后的内容都已经到了目标服务器了,是无法再进行转发数据的。

转发是指的【用户】【四层负载均衡】【服务器】之间是一个通道,代理是用户和七层负载均衡一个通道,七层负载均衡和服务器之间一个通道

七层负载均衡的能力

  • 静态资源缓存,协议升级,安全防护,访问控制,这种 cdn 能做到的事,七层负载均衡也可以做到,毕竟都是加一层保护膜对吧
  • 可以实现更加智能,更加多样的路由
  • 使用反向代理去防止攻击
  • 微服务中的链路治理都需要在七层负载均衡中去做 (通常是 API 网关,nginx 也算 api 网关但是跟专业的比治理方面功能性差很多) 比如服务降级,熔断,异常注入等内容

负载均衡算法

  • 轮询
  • 权重轮询,就是虚拟化服务器,权重大的服务器数量上就会变多
  • 随机
  • 权重随机
  • 一致性哈希,其实就是权重轮询,但是环形结构,只有在环形结构上与该节点相邻的部分数据需要进行重新分配,而不是像传统哈希算法那样需要对所有数据进行重新计算和分配。
  • 响应速度均衡,根据服务器响应时间,将请求分配到响应时间快的服务器上
  • 最少连接,将请求分配到连接数最少的服务器上

nginx 实现七层负载均衡器

nginx 的配置文件 nginx.conf

我们配置假设一台负载均衡器 nginx 后面有三个服务:/get0 /get1 /get2

# nginx 配置 /get0 /get1 /get2
+worker_processes 3; # 标识服务器进程数
+
+events {
+
+worker_connections 1024; # 标识单个worker进程能同时处理的最大连接数
+
+}
+
+http { # 标识http块
+
+keepalive_timeout 60;# 标识服务器和客户蹲连接超过60秒没有行为就会断掉
+
+upstream get0{ # 标识upstream块
+        server 192.168.1.209:8080; # 标识upstream块中的server
+        server 192.168.1.209:8081; # 192.168.1.209:8081/get0 提供服务,就是nginx的路由要跟提供服务的服务路由一致才可以
+        }
+
+upstream get1{
+        server 192.168.1.209:8082;
+        server 192.168.1.209:8083;
+
+        }
+upstream get2{
+        server 192.168.1.209:8084 weight=1; # 配置权重,权重越大被访问的几率越高
+        server 192.168.1.209:8085 weight=3;
+
+        }
+        
+server { # 标识server块
+          listen 80; # 标识监听端口
+          server_name 192.168.1.209; # 标识服务器名
+        
+        
+        location /get0 { # 标识location块
+                proxy_pass http://get0; # 标识代理目标
+                }
+
+        location /get1 {
+                porxy_pass http://get1; 
+                }
+        location /get2 {
+                proxy_pass http://get2;
+              }
+        }
+}
+

nginx 配置中,nginx 的路由要跟提供服务的服务器路由保持一致,不过也有不一致的方法,比如:

   location /get0 {
+       proxy_pass http://get0/api/get0;
+   }
+

这种方法中,如果访问 nginx 的路由 /get0 那么它就会默认去寻找 192.168.1.209:8080/api/get0 或者 192.168.1.209:8081/api/get1

不过,为了保持简洁性,减少复杂度以及潜在的 bug,为了保证运维的逻辑更加清晰,请保持路由的一致:

nginx-proxy

Nginx 常用负载均衡策略

  • 轮询,就是你啥都不设置,就是这个策略

  • 加权轮询,设置 weight=3,权重越大就越被优先访问,优先级按照权重去配比

    upstream get0{
    +      server 192.168.1.209:8080 weight=3;
    +      server 192.168.1.209:8081 weight=1;
    +      }
    +
    +
  • ip_hash,为每一个用户的 ip 地址的哈希值结果分配服务器,让来自同一个 ip 的请求一直访问同一个服务器,注意这里的策略不能很好的践行负载均衡的理论,而且这里的哈希映射不是一致性哈希

    upstream get1{
    +      ip_hash;
    +      server 192.168.1.209:8082 max_fails=3 fail_timeout=30s;# 设置服务器的故障检测,当连续3次请求失败后,nginx会认为服务器已经挂了,并在30秒内不再访问该服务器
    +      server 192.168.1.209:8083;
    +      server 192.168.1.210:8084 backup; # 当所有的主服务器(通过ip_hash分配的正常服务器)都无法处理请求时,备份服务器就会启用
    +}
    +
  • least_conn,将请求分配到连接数最少的服务器上

     # 当有两个策略的时候,通常会一起使用     
    +
    +# 当有新请求到来时,Nginx 首先会考虑least_conn策略,即找出当前连接数最少的服务器。但在这些连接数最少的服务器中,weight会影响请求分配的概率。
    + upstream get2{
    +       least_conn;
    +       server 192.168.1.209:8084 weight=1 max_fails=3 fail_timeout=30s;
    +       server 192.168.1.209:8085 weight=3 max_fails=3 fail_timeout=30s;
    +   }
    +
  • url_hash,三方库 uginx-upstream-hash,类似于 ip_hash 策略,但是它是对请求的 URL 做哈希运算 (一个是对 ip 地址做哈希,一个是对 URL 做哈希)

  • fair,三方库 nginx-upstream-fair,根据每个服务器事例的请求响应时间,失败数,当前请求总量,综合选择一个最轻松的服务器

Nginx 如何加载三方库

  • 确定所需第三方模块

    • 首先要明确你需要使用的第三方 Nginx 模块。例如,如果你需要对请求进行更高级的访问控制,可以考虑使用 ngx_http_auth_request_module;如果想增强缓存功能,可能会用到 ngx_cache_purge 模块。这些模块通常是为了满足特定的功能需求,如安全性、性能优化等。
  • 检查模块兼容性

    • 确认模块与你的 Nginx 版本兼容。不同的 Nginx 版本对模块的支持有所不同。你可以查看模块的官方文档或者在相关的开发者社区、论坛中查找模块与 Nginx 版本的兼容性信息。例如,一些新开发的模块可能只支持较新的 Nginx 版本,而旧版本的 Nginx 可能无法正确加载这些模块。
  • 下载模块源代码

    • 从可靠的来源获取模块的源代码。通常,模块的官方代码仓库 (如在 GitHub 等平台上) 是最好的选择。例如,如果要下载 ngx_http_auth_request_module,可以访问 Nginx 官方网站或者对应的代码托管平台,找到该模块的源代码下载链接或者仓库地址,然后使用版本控制系统工具 (如 git) 或者直接下载压缩包的方式获取源代码。
  • 编译安装 Nginx (包含第三方模块)

    • 方法一:重新编译 Nginx +如果是自己手动编译 Nginx,需要将第三方模块的源代码放置在合适的位置,通常是在 Nginx 源代码目录的 modules 目录下 (如果没有这个目录,可以创建一个)。然后在配置 Nginx 编译选项时,需要指定包含这个第三方模块。例如,使用 ./configure 命令配置 Nginx 编译选项时,需要添加类似于 --add - module = path/to/third - party/module 的选项,其中 path/to/third - party/module 是第三方模块源代码的实际路径。 +配置完成后,使用 make 命令编译 Nginx,再使用 make install 命令安装编译好的 Nginx。这样,新安装的 Nginx 就包含了这个第三方模块。

    • 方法二:使用动态模块 (适用于支持动态模块加载的 Nginx 版本) +对于支持动态模块加载的 Nginx 版本 (如 Nginx 1.9.11 及以上),首先按照上述步骤下载模块源代码。然后在编译模块时,使用 ngx_build_module 工具 (这个工具通常随 Nginx 一起提供) 或者按照模块文档中的特殊编译步骤进行编译。 +编译完成后,得到一个动态模块文件 (通常是以。so 结尾的文件)。将这个动态模块文件放置在 Nginx 的模块目录下 (例如 /usr/lib/nginx/modules/),然后在 Nginx 的主配置文件 (nginx.conf) 中,使用 load_module 指令加载这个模块。例如,load_module modules/ngx_http_auth_request_module.so;,这样就可以在 Nginx 中使用这个第三方模块了。

  • 配置和使用第三方模块

    • 在 Nginx 的配置文件 (nginx.conf) 或相关的虚拟主机配置文件中,根据模块的功能进行配置。例如,对于 ngx_http_auth_request_module,可以配置如下:
       server {
    +       listen       80;
    +       server_name  example.com;
    +       location / {
    +           auth_request /auth;
    +           proxy_pass http://backend;
    +       }
    +       location = /auth {
    +           internal;
    +           proxy_pass http://auth - server;
    +       }
    +   }
    +

    这里通过 auth_request 指令使用了 ngx_http_auth_request_module 来进行请求的身份验证。不同的第三方模块有不同的配置方法和指令,需要根据模块的文档进行具体的配置和使用。

Nginx 热更新

  • 使用 ngx_lua 将 lua 脚本嵌入到 nginx 中,允许编写的 lua 脚本运行在 nginx 中
  • ngx_http_dyups_module,使用这个模块,去不断的主动访问一个服务注册中心,里面是服务的具体内容,然后生成新的配置

nginx-hot-update

Ngix 优势

  • DNS 服务指向 Nginx,具体服务 IP 跟 DNS 解耦
  • 使用 Nginx 做了负载均衡
  • 对外只暴漏一个公网 ip,节约 ip 资源,nginx 和具体服务内部通信即可
  • 防止业务 ip 暴漏
  • 增加了业务服务器的可扩展性
  • 提高了整体服务的可用性
  • 提高了系统的整体性能

负载均衡的高级用法

通常下面的高级用法都部署在七层负载均衡上,因为它更加灵活,设置起来更方便一些,四层负载均衡主要侧重于性能,所以一般不会有非常复杂的设置。

  • 蓝绿发布,通过在两个生产环境之间 (蓝色绿色) 切换来实现零停机时间部署
  • 红蓝发布,跟蓝绿发布类似,只不过蓝绿发布的两个环境大体一致,红蓝发布中,蓝色为正常安全环境,红色为危险易受到攻击的环境
  • 金丝雀发布,渐进式发布策略,逐步将新版本推向生产环境,只有一部分人会看到新版本,一旦出现问题就回滚旧版本
  • 灰度发布,根据用户的流量特点,将新版本推送给特定用户,在不影响整体用户体验的情况下进行测试和验证
  • AB 测试,相同环境的不同设置推送给不同的用户用于测试效果
  • rolling update 滚动测试,部分服务器更新升级,然后逐步替换 (红蓝更新需要两套完整的环境,rolling update 则是替换掉一个)
  • 影子发布 (Shadow Deployment),影子发布是指在实际的生产环境旁边,部署一份新版本的服务,这个新版本的服务会接收和生产环境相同的请求流量,但不会对用户产生实际的影响。它主要用于观察新版本在真实流量下的性能和行为。
  • 分批发布 (Batch Deployment),将用户或者服务器等分成若干批次,按批次逐步发布新版本。每一批次发布后,可以观察一段时间,确保没有问题后再发布下一批次。
  • 特性开关发布 (Feature Toggles),也叫功能开关或特性标记。它允许开发团队在不发布整个新版本的情况下,通过控制开关来启用或禁用新功能。新功能在代码中已经存在,但通过配置来决定是否对用户可见
  • 主动调节后端服务压力
  • 屏蔽失效的后端服务

发布模式与负载均衡的原理

  1. 红蓝发布 (或者蓝绿发布)

    • 通常需要负载均衡作为切换器。在红蓝发布中,有红色和蓝色两个完整的生产环境。负载均衡器可以根据配置规则,将流量从一个环境 (如红色) 快速切换到另一个环境 (如蓝色)。例如,在正常情况下,负载均衡器将所有用户请求导向红色环境,当红色环境需要更新时,通过负载均衡器的配置调整,将流量切换到蓝色环境,从而实现零停机时间部署。这样可以确保在切换过程中,用户请求能够被合理地分配,并且能够灵活地控制流量的走向。
  2. 金丝雀发布

    • 负载均衡在金丝雀发布中也起到关键作用。它可以用于将一小部分用户流量导向新版本的服务 (金丝雀环境),而将大部分用户流量继续导向旧版本的服务。通过负载均衡器的流量分配策略,如按比例分配 (例如,将 10% 的流量分配给新版本,90% 分配给旧版本),可以实现逐步将新版本推向生产环境。当发现新版本出现问题时,负载均衡器可以快速调整流量分配,将所有流量重新导向旧版本,从而实现回滚。
  3. 灰度发布

    • 同样依赖负载均衡。灰度发布是根据用户的流量特点,将新版本推送给特定用户。负载均衡器可以根据用户的属性 (如地理位置、用户等级、设备类型等) 来进行流量分配。例如,将新版本发布给某个特定地区的用户或者高价值用户。它能够精准地控制哪些用户流量被导向新版本,哪些被导向旧版本,在不影响整体用户体验的情况下进行测试和验证。
  4. AB 测试

    • 负载均衡对于 AB 测试也是必不可少的。它可以将相同环境的不同设置 (如不同的界面布局、不同的推荐算法等) 推送给不同的用户。通过负载均衡器的分流规则,例如,可以将 50% 的用户导向 A 版本,50% 的用户导向 B 版本,然后对比两组用户的行为和反馈,来测试不同设置的效果。
  5. 特性开关发布 (Feature Toggles)

    • 负载均衡不是必需的。这种发布模式主要是通过软件内部的特性开关来控制功能的启用和禁用,而不是通过流量分配来实现发布。不过,在一些复杂的场景下,如果需要结合特性开关和流量控制来进行更精细的发布,也可以使用负载均衡。
  6. 影子发布 (Shadow Deployment)

    • 负载均衡起到辅助作用。影子发布主要是为了在不影响用户的情况下,让新版本接收相同的流量进行性能测试。负载均衡可以帮助复制流量到影子环境,但它不是用于切换流量给用户的主要工具,因为影子版本的输出通常不会直接提供给用户。
  7. 分批发布 (Batch Deployment)

    • 可以使用负载均衡,但不是绝对依赖。在分批发布中,负载均衡可以用于将流量按批次导向不同的服务器组 (其中有些是已更新的,有些是未更新的)。不过,也可以通过其他方式,如服务器分组和手动配置等,来实现按批次发布,不一定完全依靠负载均衡来进行流量切换。

金丝雀发布和灰度发布的区别

金丝雀发布通常是随机的少量的用户,而灰度发布通常是选取特定特征的人群,比如按照地域按照性别,灰度发布更强调策略,金丝雀更强调随机性

金丝雀发布的人群相对更低,一旦有问题就回滚,主要用于最早期的验证,灰度发布因为选择的是特定人群,所以相对用户是很多的,风险是加大的

金丝雀发布侧重于技术验证灰度发布侧重于业务验证

红蓝发布和蓝绿发布的区别

红蓝发布和蓝绿发布意思比较相近,但也有一些细微差别。

蓝绿发布 (Blue - Green Deployment)

概念:蓝绿发布是一种部署策略,它有两个完全相同的生产环境,分别称为蓝环境和绿环境。在任何时刻,只有一个环境 (例如绿环境) 在处理实际的用户流量,另一个 (蓝环境) 处于空闲或者预发布状态。当需要发布新版本时,开发人员会将新版本部署到空闲的环境 (蓝环境) 中,对其进行充分的测试,包括功能测试、性能测试等。一旦测试通过,就可以通过负载均衡器或者其他切换工具将用户流量从旧环境 (绿环境) 切换到新环境 (蓝环境)。这个切换过程通常可以非常快速地完成,实现几乎零停机时间的部署。切换后,原来的旧环境 (绿环境) 可以被闲置,用于下一次发布或者作为备份。

示例:假设一个在线购物网站,绿环境是当前正在为用户提供服务的环境。当有新功能需要发布时,先将新功能部署到蓝环境,经过测试人员在蓝环境中进行购物流程的测试,确认没有问题后,将负载均衡的流量指向从绿环境切换到蓝环境,用户就开始使用新环境中的购物网站,整个过程用户可能几乎感觉不到服务的中断。

特点:

提供了快速回滚的能力。如果在新环境 (蓝环境) 出现问题,能够迅速将流量切换回旧环境 (绿环境),将影响降到最低。

两个环境可以独立维护和测试,有助于保证发布质量。

红蓝发布 (Red - Blue Deployment)

概念:和蓝绿发布类似,也有红色和蓝色两个生产环境。不过,红蓝发布在概念上更强调这两个环境之间的对比或者竞争关系。例如,在安全领域,红色环境可能代表容易受到攻击的环境,蓝色环境代表具有安全防护措施的环境,通过在两个环境之间切换来测试安全策略的有效性等特殊场景;在常规软件发布场景下,其原理和蓝绿发布类似,也是通过两个环境的切换来实现部署,但可能在应用场景或者侧重点上有所不同。

示例:在一些对数据安全性要求极高的金融系统中,红色环境可以模拟外部网络攻击频繁的情况,蓝色环境则是部署了最新安全防护软件的环境。系统可以在两个环境之间切换用户流量,观察安全防护措施的实际效果。在软件更新场景下,也可以像蓝绿发布一样,将新版本部署在蓝色环境,经过测试后切换用户流量到蓝色环境来实现更新。

特点:

除了用于常规的软件发布,还可以用于一些特殊的测试场景,如安全性测试、兼容性测试等。

强调两个环境之间的差异对比和相互验证。

+ + + diff --git "a/\347\263\273\347\273\237\350\256\276\350\256\241\345\256\236\346\210\230/\345\237\272\347\241\200\346\236\266\346\236\204\347\273\204\344\273\266\350\256\276\350\256\241/\345\210\206\345\270\203\345\274\217\351\224\201/index.html" "b/\347\263\273\347\273\237\350\256\276\350\256\241\345\256\236\346\210\230/\345\237\272\347\241\200\346\236\266\346\236\204\347\273\204\344\273\266\350\256\276\350\256\241/\345\210\206\345\270\203\345\274\217\351\224\201/index.html" new file mode 100644 index 00000000..b646004c --- /dev/null +++ "b/\347\263\273\347\273\237\350\256\276\350\256\241\345\256\236\346\210\230/\345\237\272\347\241\200\346\236\266\346\236\204\347\273\204\344\273\266\350\256\276\350\256\241/\345\210\206\345\270\203\345\274\217\351\224\201/index.html" @@ -0,0 +1,54 @@ + + + + + + 鲁班 - 系统设计大全 + + + + + + + + + + + + diff --git "a/\347\263\273\347\273\237\350\256\276\350\256\241\345\256\236\346\210\230/\345\237\272\347\241\200\346\236\266\346\236\204\347\273\204\344\273\266\350\256\276\350\256\241/\345\224\257\344\270\200id\347\224\237\346\210\220\345\231\250/index.html" "b/\347\263\273\347\273\237\350\256\276\350\256\241\345\256\236\346\210\230/\345\237\272\347\241\200\346\236\266\346\236\204\347\273\204\344\273\266\350\256\276\350\256\241/\345\224\257\344\270\200id\347\224\237\346\210\220\345\231\250/index.html" new file mode 100644 index 00000000..7a0aa65d --- /dev/null +++ "b/\347\263\273\347\273\237\350\256\276\350\256\241\345\256\236\346\210\230/\345\237\272\347\241\200\346\236\266\346\236\204\347\273\204\344\273\266\350\256\276\350\256\241/\345\224\257\344\270\200id\347\224\237\346\210\220\345\231\250/index.html" @@ -0,0 +1,54 @@ + + + + + + 鲁班 - 系统设计大全 + + + + + + + + + + + + diff --git "a/\347\263\273\347\273\237\350\256\276\350\256\241\345\256\236\346\210\230/\345\237\272\347\241\200\346\236\266\346\236\204\347\273\204\344\273\266\350\256\276\350\256\241/\346\265\267\351\207\217\346\216\250\351\200\201\347\263\273\347\273\237/index.html" "b/\347\263\273\347\273\237\350\256\276\350\256\241\345\256\236\346\210\230/\345\237\272\347\241\200\346\236\266\346\236\204\347\273\204\344\273\266\350\256\276\350\256\241/\346\265\267\351\207\217\346\216\250\351\200\201\347\263\273\347\273\237/index.html" new file mode 100644 index 00000000..f4aac90a --- /dev/null +++ "b/\347\263\273\347\273\237\350\256\276\350\256\241\345\256\236\346\210\230/\345\237\272\347\241\200\346\236\266\346\236\204\347\273\204\344\273\266\350\256\276\350\256\241/\346\265\267\351\207\217\346\216\250\351\200\201\347\263\273\347\273\237/index.html" @@ -0,0 +1,54 @@ + + + + + + 鲁班 - 系统设计大全 + + + + + + + + + + + + diff --git "a/\347\263\273\347\273\237\350\256\276\350\256\241\345\256\236\346\210\230/\345\237\272\347\241\200\346\236\266\346\236\204\347\273\204\344\273\266\350\256\276\350\256\241/\347\224\250\346\210\267\347\231\273\351\231\206\346\234\215\345\212\241/index.html" "b/\347\263\273\347\273\237\350\256\276\350\256\241\345\256\236\346\210\230/\345\237\272\347\241\200\346\236\266\346\236\204\347\273\204\344\273\266\350\256\276\350\256\241/\347\224\250\346\210\267\347\231\273\351\231\206\346\234\215\345\212\241/index.html" new file mode 100644 index 00000000..c1a2be89 --- /dev/null +++ "b/\347\263\273\347\273\237\350\256\276\350\256\241\345\256\236\346\210\230/\345\237\272\347\241\200\346\236\266\346\236\204\347\273\204\344\273\266\350\256\276\350\256\241/\347\224\250\346\210\267\347\231\273\351\231\206\346\234\215\345\212\241/index.html" @@ -0,0 +1,54 @@ + + + + + + 鲁班 - 系统设计大全 + + + + + + + + + + + + diff --git "a/\347\263\273\347\273\237\350\256\276\350\256\241\345\256\236\346\210\230/\345\237\272\347\241\200\346\236\266\346\236\204\347\273\204\344\273\266\350\256\276\350\256\241/\350\264\237\350\275\275\345\235\207\350\241\241\345\231\250/index.html" "b/\347\263\273\347\273\237\350\256\276\350\256\241\345\256\236\346\210\230/\345\237\272\347\241\200\346\236\266\346\236\204\347\273\204\344\273\266\350\256\276\350\256\241/\350\264\237\350\275\275\345\235\207\350\241\241\345\231\250/index.html" new file mode 100644 index 00000000..6497d9ee --- /dev/null +++ "b/\347\263\273\347\273\237\350\256\276\350\256\241\345\256\236\346\210\230/\345\237\272\347\241\200\346\236\266\346\236\204\347\273\204\344\273\266\350\256\276\350\256\241/\350\264\237\350\275\275\345\235\207\350\241\241\345\231\250/index.html" @@ -0,0 +1,54 @@ + + + + + + 鲁班 - 系统设计大全 + + + + + + + + + + + + diff --git "a/\347\263\273\347\273\237\350\256\276\350\256\241\345\256\236\346\210\230/\345\237\272\347\241\200\346\236\266\346\236\204\347\273\204\344\273\266\350\256\276\350\256\241/\351\231\220\346\265\201\344\270\255\351\227\264\344\273\266/index.html" "b/\347\263\273\347\273\237\350\256\276\350\256\241\345\256\236\346\210\230/\345\237\272\347\241\200\346\236\266\346\236\204\347\273\204\344\273\266\350\256\276\350\256\241/\351\231\220\346\265\201\344\270\255\351\227\264\344\273\266/index.html" new file mode 100644 index 00000000..3a28a012 --- /dev/null +++ "b/\347\263\273\347\273\237\350\256\276\350\256\241\345\256\236\346\210\230/\345\237\272\347\241\200\346\236\266\346\236\204\347\273\204\344\273\266\350\256\276\350\256\241/\351\231\220\346\265\201\344\270\255\351\227\264\344\273\266/index.html" @@ -0,0 +1,54 @@ + + + + + + 鲁班 - 系统设计大全 + + + + + + + + + + + + diff --git "a/\347\263\273\347\273\237\350\256\276\350\256\241\345\256\236\346\210\230/\346\240\270\345\277\203\346\234\215\345\212\241\350\256\276\350\256\241/\345\206\205\345\256\271\345\217\221\345\270\203\347\263\273\347\273\237/index.html" "b/\347\263\273\347\273\237\350\256\276\350\256\241\345\256\236\346\210\230/\346\240\270\345\277\203\346\234\215\345\212\241\350\256\276\350\256\241/\345\206\205\345\256\271\345\217\221\345\270\203\347\263\273\347\273\237/index.html" new file mode 100644 index 00000000..460c446c --- /dev/null +++ "b/\347\263\273\347\273\237\350\256\276\350\256\241\345\256\236\346\210\230/\346\240\270\345\277\203\346\234\215\345\212\241\350\256\276\350\256\241/\345\206\205\345\256\271\345\217\221\345\270\203\347\263\273\347\273\237/index.html" @@ -0,0 +1,54 @@ + + + + + + 鲁班 - 系统设计大全 + + + + + + + + + + + + diff --git "a/\347\263\273\347\273\237\350\256\276\350\256\241\345\256\236\346\210\230/\346\240\270\345\277\203\346\234\215\345\212\241\350\256\276\350\256\241/\346\216\222\350\241\214\346\246\234\346\234\215\345\212\241/index.html" "b/\347\263\273\347\273\237\350\256\276\350\256\241\345\256\236\346\210\230/\346\240\270\345\277\203\346\234\215\345\212\241\350\256\276\350\256\241/\346\216\222\350\241\214\346\246\234\346\234\215\345\212\241/index.html" new file mode 100644 index 00000000..a3fb733f --- /dev/null +++ "b/\347\263\273\347\273\237\350\256\276\350\256\241\345\256\236\346\210\230/\346\240\270\345\277\203\346\234\215\345\212\241\350\256\276\350\256\241/\346\216\222\350\241\214\346\246\234\346\234\215\345\212\241/index.html" @@ -0,0 +1,54 @@ + + + + + + 鲁班 - 系统设计大全 + + + + + + + + + + + + diff --git "a/\347\263\273\347\273\237\350\256\276\350\256\241\345\256\236\346\210\230/\346\240\270\345\277\203\346\234\215\345\212\241\350\256\276\350\256\241/\351\200\232\347\224\250\350\256\241\346\225\260\347\263\273\347\273\237/index.html" "b/\347\263\273\347\273\237\350\256\276\350\256\241\345\256\236\346\210\230/\346\240\270\345\277\203\346\234\215\345\212\241\350\256\276\350\256\241/\351\200\232\347\224\250\350\256\241\346\225\260\347\263\273\347\273\237/index.html" new file mode 100644 index 00000000..910829e0 --- /dev/null +++ "b/\347\263\273\347\273\237\350\256\276\350\256\241\345\256\236\346\210\230/\346\240\270\345\277\203\346\234\215\345\212\241\350\256\276\350\256\241/\351\200\232\347\224\250\350\256\241\346\225\260\347\263\273\347\273\237/index.html" @@ -0,0 +1,54 @@ + + + + + + 鲁班 - 系统设计大全 + + + + + + + + + + + +