├── .DS_Store ├── README.md ├── 学习笔记 ├── .DS_Store ├── Cplusplus │ ├── C++高性能优化指南.md │ ├── 在main函数前执行一条语句.md │ ├── 在main函数后执行一条语句.md │ ├── 在main函数执行前的初始化.md │ ├── 循环队列.md │ ├── 编写类String 的构造函数,析构函数,拷贝构造函数和赋值函数.cpp │ ├── 虚函数,多态,重写.md │ ├── 虚表的简单查看.md │ ├── 面试题(1 - 25).md │ ├── 面试题(26 - 50).md │ └── 面试题(51 - INF).md ├── Crawler │ └── 爬虫进阶.md ├── DataBase │ ├── MySQL-Practices.md │ └── 面试题(1 - 25).md ├── Docker │ ├── Docker_Run参数详解.md │ ├── Docker用途.md │ ├── docker 指定 cpu.md │ ├── docker.png │ ├── virtual-machines.png │ └── 什么是docker.md ├── Github │ ├── Fork 更新同步.md │ ├── github基本使用.md │ └── 提交PR.md ├── IQ │ └── 智力题.md ├── Inter-algo │ └── 算法面试题.md ├── K8S │ ├── Kubernetes.in.Action.2017.12.pdf │ ├── README.md │ ├── picture │ │ ├── 1 │ │ ├── dashboard.png │ │ └── dashboard_login.png │ ├── 第一天-kubeadm安装k8s.md │ ├── 第三天-Kubelet.md │ ├── 第二天-kubectl命令.md │ └── 第四天-K8S架构.md ├── Linux │ └── 面试题.md ├── Lua │ └── linux下如何安装lua.md ├── MapReduce │ └── tutorial.md ├── MongoDB │ └── MongoDB的安装.md ├── NetWorking │ ├── TCP建立连接的三次握手.md │ ├── TCP释放连接的四次挥手.md │ ├── img │ │ ├── 1.png │ │ ├── 2.png │ │ ├── 3.png │ │ ├── 4.png │ │ ├── 5.png │ │ ├── 6.png │ │ ├── 7.png │ │ └── 8.png │ └── 面试题(1 - 25).md ├── Node.js │ ├── cluster │ │ ├── Example │ │ │ ├── process.js │ │ │ └── server.js │ │ └── master.js │ └── http │ │ ├── Example │ │ ├── index.html │ │ └── server.js │ │ └── app.js ├── Online_tmp │ ├── README.md │ ├── largeint_struct.hpp │ └── main.cpp ├── Python │ └── getopt的使用.md ├── Redis │ ├── Redis各种数据类型的应用场景.md │ └── Redis脚本(Lua解释器).md ├── RegexExpressions │ └── RegexJS.md ├── Tool │ ├── MacOS下的ATOM配置.md │ ├── Ubuntu 16.04安装Oh-my-zsh.md │ └── Ubuntu_Terminator配色.md ├── Traefik │ └── README.md ├── istio │ ├── istio 中文文档.pdf │ ├── istio_mesh_for_microservices_r1.pdf │ └── istio介绍.md └── tmp.txt └── 读书笔记 ├── HBase不睡觉书.md ├── 亿级流量网站架构核心技术.md ├── 论加班对你的危害.md └── 软技能-代码之外的生存之道.md /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzyrapx/Notes/9d7665195e6ae4807f9b77edb529f3a35e768542/.DS_Store -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 这是一些笔记.(This is my notes) 2 | *** 3 | ## Example: 4 | ## Notes 5 | ### 理性分析 C++(-O2) 和 JS 的性能差距. 6 | ### On Intel(R) Core(TM) i7-8550U CPU @ 1.80GHz. 7 | ### Test1: 8 | #### 最后一行:时间(ms) 9 | ``` 10 | #pragma GCC optimize("O2") 11 | #include 12 | using namespace std; 13 | int main(int argc, char const *argv[]) { 14 | int t = clock(); 15 | int a = 1000000000,b = 1; 16 | while(a) { 17 | b <<= 1; 18 | a--; 19 | } 20 | printf("%d ms\n",clock() - t); 21 | return 0; 22 | } 23 | 24 | // 0 ms 25 | ``` 26 | 27 | ``` 28 | var t; 29 | t = new Date; 30 | var a = 1000000000, 31 | b = 1; 32 | while(a) { 33 | b <<= 1; 34 | a--; 35 | } 36 | console.log(new Date - t + "ms"); 37 | 38 | // 915ms 39 | ``` 40 | ### Test2: 41 | ``` 42 | #pragma GCC optimize("O2") 43 | #include 44 | using namespace std; 45 | int a[10000100]; 46 | void quick_sort(int a[], int l, int r) { 47 | if (l < r) { 48 | int i = l, j = r, x = a[l]; 49 | while (i < j) { 50 | while(i < j && a[j] >= x) j--; 51 | if(i < j) a[i++] = a[j]; 52 | while(i < j && a[i] < x) i++; 53 | if(i < j) a[j--] = a[i]; 54 | } 55 | a[i] = x; 56 | quick_sort(a, l, i - 1); 57 | quick_sort(a, i + 1, r); 58 | } 59 | } 60 | int main(int argc, char const *argv[]) { 61 | srand((int)time(0)); 62 | for(int i = 0;i < 10000000; i++) { 63 | a[i] = rand(); 64 | } 65 | int t = clock(); 66 | quick_sort(a,0,10000000); 67 | printf("%d ms\n",clock() -t); 68 | return 0; 69 | } 70 | 71 | // 1738 ms 72 | ``` 73 | ``` 74 | function quick_sort(a,l,r) { 75 | if (l < r) { 76 | var i = l, j = r, x = a[l]; 77 | while (i < j) { 78 | while(i < j && a[j] >= x) j--; 79 | if(i < j) a[i++] = a[j]; 80 | while(i < j && a[i] < x) i++; 81 | if(i < j) a[j--] = a[i]; 82 | } 83 | a[i] = x; 84 | quick_sort(a, l, i - 1); 85 | quick_sort(a, i + 1, r); 86 | } 87 | } 88 | var s,i,t; 89 | for(i=0,s=[];i<10000000;i++) s.push(Math.random()*1E7|0); 90 | t = new Date; 91 | quick_sort(s,0,10000000); 92 | console.log(new Date - t + " ms"); 93 | 94 | // 3080 ms 95 | ``` 96 | ### Test3: 97 | ``` 98 | #pragma GCC optimize("O2") 99 | #include 100 | using namespace std; 101 | const int maxn = 50000000; 102 | int a[maxn]; 103 | int p[maxn],m[maxn]; 104 | int pc; 105 | int main(int argc, char const *argv[]) { 106 | int t = clock(); 107 | for(int i = 2; i < maxn; i++) { 108 | if(m[i] == 0) { 109 | p[++pc] = m[i] = i; 110 | } 111 | int k = 0; 112 | for(int j = 1; j <= pc && p[j] <= m[i] && (k = p[j] * i) < maxn; j++) { 113 | m[k] = p[j]; 114 | } 115 | } 116 | int ans = 0; 117 | for(int i = 1; i <= pc; i++) { 118 | ans ^= p[i]; 119 | } 120 | printf("%d\n", ans); 121 | printf("%d ms\n",clock() - t); 122 | return 0; 123 | } 124 | 125 | // 338 ms 126 | ``` 127 | ``` 128 | var pc = 0; 129 | 130 | var m = []; 131 | var p = []; 132 | function solve() { 133 | // console.log("ok"); 134 | var i; 135 | for(i = 2 ;i < 50000000;i++) { 136 | if(m[i] == null) { 137 | // console.log(i); 138 | p[++pc] = m[i] = i; 139 | } 140 | var k = 0; 141 | var j ; 142 | for(j = 1; j <= pc && p[j] <= m[i] && (k = p[j] * i) < 50000000; j++) { 143 | m[k] = p[j]; 144 | } 145 | } 146 | // console.log("pc = " + pc); 147 | var ans = 0; 148 | for(var i = 1; i <= pc; i++) { 149 | ans ^= p[i]; 150 | } 151 | console.log("ans= " + ans); 152 | } 153 | t = new Date; 154 | solve(); 155 | console.log(new Date - t + " ms"); 156 | 157 | // 8096 ms 158 | 159 | ``` 160 | ### Test4: 161 | ``` 162 | #pragma GCC optimize("O2") 163 | #include 164 | using namespace std; 165 | const int maxn = 1000; 166 | 167 | int G[1000][1000]; 168 | int sed = 0; 169 | inline int getRand() 170 | { 171 | return sed = (sed * sed * 73 + sed * 233 + 19260817) & 0x0000ffff; 172 | } 173 | int main(int argc, char const *argv[]) { 174 | int t = clock(); 175 | for(int i = 0; i < maxn; i++) { 176 | for(int j = 0; j < maxn; j++) { 177 | G[i][j] = getRand(); 178 | } 179 | } 180 | for(int i = 0; i < maxn; i++) { 181 | for(int j = 0; j < maxn; j++) { 182 | for(int k = 0; k < maxn; k++) { 183 | if(G[j][k] > G[j][i] + G[i][k]) { 184 | G[j][k] = G[j][i] + G[i][k]; 185 | } 186 | } 187 | } 188 | } 189 | int ans = 0; 190 | for(int i = 0; i < maxn; i++) { 191 | for(int j = 0; j < maxn; j++) { 192 | ans ^= G[i][j]; 193 | } 194 | } 195 | printf("%d\n", ans); 196 | printf("%d ms\n",clock() - t); 197 | return 0; 198 | } 199 | 200 | // 1718 ms 201 | ``` 202 | ``` 203 | var sed = 0; 204 | var G = new Array(); 205 | function getRand() { 206 | var res = sed = (sed * sed * 73 + sed * 233 + 19260817) & 0x0000ffff; 207 | // console.log("res = " + res); 208 | return res; 209 | } 210 | function solve() { 211 | // console.log("ok"); 212 | for(var i = 0; i < 1000; i++) { 213 | G[i] = new Array(); 214 | for(var j = 0; j < 1000; j++) { 215 | G[i][j] = getRand(); 216 | } 217 | } 218 | for(var i = 0; i < 1000; i++) { 219 | for(var j = 0; j < 1000; j++) { 220 | for(var k = 0; k < 1000; k++) { 221 | if(G[j][k] > G[j][i] + G[i][k]) { 222 | G[j][k] = G[j][i] + G[i][k]; 223 | } 224 | } 225 | } 226 | } 227 | var ans = 0; 228 | for(var i = 0; i < 1000; i++) { 229 | for(var j = 0; j < 1000; j++) { 230 | ans ^= G[i][j]; 231 | } 232 | } 233 | console.log("ans= " + ans); 234 | } 235 | t = new Date; 236 | solve(); 237 | console.log(new Date - t + " ms"); 238 | 239 | // 3440 ms 240 | 241 | ``` 242 | ### Test5: 243 | ``` 244 | #pragma GCC optimize("O2") 245 | #include 246 | using namespace std; 247 | const int maxn = 1000000000; // 1e9 248 | typedef unsigned long long ull; 249 | int P = 1000000007; 250 | 251 | int main(int argc, char const *argv[]) { 252 | int t = clock(); 253 | ull ans = 1; 254 | for(int i = 1; i < maxn; i++) { 255 | ans = ans * i % P; 256 | } 257 | printf("%llu\n",ans); 258 | printf("%d ms\n",clock() - t); 259 | return 0; 260 | } 261 | 262 | // 11953 ms 263 | ``` 264 | ``` 265 | var P = 1000000007; 266 | var maxn = 1000000000;// 1e9 267 | function solve() { 268 | // console.log("ok"); 269 | var ans = 1; 270 | for(var i = 1; i < maxn; i++) { 271 | ans = ans * i % P; 272 | } 273 | console.log("ans= " + ans); 274 | } 275 | t = new Date; 276 | solve(); 277 | console.log(new Date - t + " ms"); 278 | 279 | // 32175 ms 280 | ``` 281 | -------------------------------------------------------------------------------- /学习笔记/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzyrapx/Notes/9d7665195e6ae4807f9b77edb529f3a35e768542/学习笔记/.DS_Store -------------------------------------------------------------------------------- /学习笔记/Cplusplus/C++高性能优化指南.md: -------------------------------------------------------------------------------- 1 | # C++高性能优化指南 2 | * 这是一篇关于C++性能优化指南的学习笔记,主要是通过阅读学习Kurt Guntheroth著的 Optimized C++:Proven Techniques for Heightened Performance。 这是一本知识量和信息量很大的一本书书,书里详细介绍了影响C++程序性能的原因,也给出了很多提高性能的优化策略。 3 | * 书中不仅讲解了软件和系统方面的相关内容,还涉及了计算机的硬件组成的基础知识,使读者可以全面的了解计算机和程序设计。书中介绍的方法是具有通用性的,可以延伸至其他的编程语言,个人认为这是一本可以提升程序设计能力、感受到优化之美的一本值得一读的好书。 4 | 5 | 6 | 7 | 8 | ### 一、C++代码优化策略总结 9 | 10 | * 1、用好的编译器并用好编译器(支持C++11的编译器,IntelC++(速度最快)、GNU的C++编译器GCC/G++(非常符合标准),Visual C++(性能折中),clang(最年轻Mac OS x))。 11 | * 2、使用更好的算法。 12 | * 3、使用更好的数据结构(不同的数据结构在使用内存管理器的方式也有所不同)。 13 | * 4、使用更好的库(熟悉和掌握标准C++模板库对于进行性能优化的开发员是必须的技能,Boost Project 和 Google Code 公开了很多有用的库)。 14 | * 5、减少内存分配和复制(减少对内存管理器的调用是一种非常有效的优化手段)。 15 | * 6、优化内存管理(内存管理器的调度,丰富的API)。 16 | * 7、移除计算(对于单条的C++语句进行优化)。 17 | * 8、提高并发性(多个处理核心执行指令)。 18 | 19 | 20 | 21 | ### 二、影响优化的计算机行为 22 | 23 | * 1、计算机的物理组成本身对计算机性能的限制。 24 | * 2、计算机的主内存是比较慢的(通往主内存的接口是限制执行速度的瓶颈(冯.诺伊曼瓶颈),(摩尔定理)每年处理器的核心的数量都会增加,但是计算机的性能未必会提高,因为这些核心只是等待访问内存的机会(内存墙memory wall))。 25 | * 3、计算机内存的访问方式(并非以字节为单位),某些内存访问会比其他的更慢(分为一级高速缓存(cache memory)、二级高速缓存、三级高速缓存、主内存、磁盘上的虚拟内存页)。 26 | * 4、内存的容量是有限的,每个程序都会与其他程序竞争计算机资源,计算比做决定快。 27 | * 5、在处理器中,访问内存的性能开销远比其他操作的性能开销大,非对齐访问所需要的时间是所有字节都在同一字节中的两倍。 28 | * 6、访问频繁使用的内存地址的速度比访问非频繁使用的地址快,访问相邻地址的内存的速度比访问相互远隔的地址的内存块。 29 | * 7、访问线程间共享的数据比访问非共享的数据资源慢很多。当并发线程共享数据时,同步代码降低了并发量。 30 | * 8、有些语句隐藏了大量的计算,从语句的外表上看不出语句的性能开销会有多大。 31 | 32 | 33 | 34 | ### 三、性能测量 35 | 36 | * 1、90/10规则:一个程序会花费90%的运行时去执行10%的代码。 37 | * 2、只有正确且精确的测量才是准确的测量。 38 | * 3、分辨率不是准确性。 39 | * 4、在Windows上,clock()函数提供了可靠的毫秒级的时钟计时功能。在Windows8和之后的版本中,GetSystemTimePreciseAsfileTime()提供了亚微秒的计时功能。 40 | * 5、计算一条C++语句对内存的读写次数,可以估算出一句C++ 语句的性能开销。 41 | 42 | 43 | 44 | ### 四、优化字符串的使用 45 | 46 | * 1、由于字符串是动态分配内存的,因此它们的性能开销非常大。它们在表达式中的行为与值类似,它们的实现方式中需要大量的复制。 47 | * 2、将字符串作为对象而非值可以降低内存分配和复制的频率。 48 | * 3、为字符串预留内存空间可以减少内存分配的开销。 49 | * 4、将指向字符串的常量引用传递给函数与传递值的结果几乎一样,但是更加高效。 50 | * 5、将函数的结果通过输出参数作为引用返回给调用方会复用实参的存储空间,这可能比分配新的存储空间更加高效。 51 | * 6、即使只是有时候会减少内存分配的开销,仍然是一种优化。 52 | 53 | 54 | 55 | ### 五、优化动态分配内存的变量 56 | 57 | * 1、在C++程序中,乱用动态分配内存的变量是最大的“性能杀手”。 58 | * 2、C++变量(每个普通数据类型的变量;每个数组,结构体或类实例)在内存中的布局都是固定的,它们的大小在编译时就已经确定了。 59 | * 3、每个变量都有它的存储期(生命周期),只有在这段时间内变量所占用的存储空间或者内存字节中的值才是有意义的。为变量分配内存的开销取决于存储期(静态存储期、线性局部存储期、自动存储期、动态存储期)。 60 | * 4、C++变量的所有者决定了变量什么时候会被创建,什么时候会被析构(变量所有权是一个单独的概念,与存储期不同)。动态变量的所有权必须有程序员执行并编写在程序逻辑中,它不受编译器控制,也不由C++定义。具有强定义所有权的程序会比所有权分散的程序更高效。 61 | * 5、在C++中,动态变量是由 new 表达式创建,由 delete 表达式释放的。它们会调用C++标准库的内存管理函数。 62 | * 6、智能指针会通过耦合动态变量的生命周期与拥有该变量的智能指针的生命周期,来实现动态变量所有权的自动化。C++允许多个指针和引用指向同一个动态变量,共享了所有权的动态变量开销更大。 63 | * 7、静态的创建类成员并且在有必要时采用“两段初始化”,这样可以节省为这些成员变量分配内存的开销。 64 | * 8、让主指针来拥有动态变量,使用无主指针替代共享所有权。 65 | * 9、从性能优化的角度上看,使用指针或是引用进行赋值和参数传递,或是返回指针或引用更加高效,因为指针和引用时存储在寄存器中的。 66 | * 10、当一个数据结构中的元素被存储在连续的存储空间中时,我们称这个数据结构为扁平的,相比于通用指针链接在一起的数据结构,扁平数据结构具有显著的性能优势。 67 | 68 | 69 | 70 | ### 六、优化热点语句 71 | 72 | * 1、除非有一些因素放大了语句的性能开销,否则不值得进行语句级别的性能优化,因为所能带来的性能提升不大。 73 | * 2、循环中的语句的性能开销被放大的倍数是循环的次数。函数中的语句的性能开销被放大的倍数是函数被调用的次数。被频繁地调用的编程惯用法的性能开销被放大的倍数是其被调用的次数。 74 | * 3、从循环中移除不变性代码(当代码不依赖于循环的归纳变量时,它就具有循环不变性),不过现代编译器非常善于找出循环中被重复计算的具有循环不变性的代码。 75 | * 4、从循环中移除无谓的函数调用,一次函数调用可能会执行大量指令,这是影响程序性能的一个重要因素,如果一个函数具有循环不变性,那么将它移除到循环外有助于改善性能。有一种函数永远都可以被移动到循环外部,那就是返回值只依赖于函数参数而且没有副作用的纯函数。 76 | * 5、从循环中移除隐含的函数调用;如果将函数签名从通过值传递实参修改为传递指向类的引用和指针,有时候可以在进行隐式函数调用时移除形参构建。 77 | * 6、调用函数的开销是非常小的,只是执行函数体的开销可能非常大,如果一个函数被重复调用多次则累积的开销会变得很大。函数调用的开销主要包括函数调用的基本开销、虚函数的开销、继承中的成员函数调用、函数指针的开销等。函数的调用开销虽然很大,但正因为函数调用才实现了程序的一些复杂的功能。 78 | * 6、调用操作系统的函数的开销是高成本的。 79 | * 7、内联函数是一种有效的移除函数调用开销的方法。 80 | 81 | 82 | ### 七、使用更好的库 83 | 84 | * 1、C++为常用功能提供了一个简洁的标准库。 85 | - 确定哪些依赖于实现的行为,如每种数据类型的最大值和最小值。 86 | - 易于使用但是编写和验证都很繁琐的可移植的超越函数(超越函数指的是变量之间的关系不能用有限次加、减、乘、除、乘方、开方运算表示的函数),如正弦函数和余弦函数、对数函数和幂函数、随机数函数等等。 87 | - 除了内存分配外,不依赖于操作系统的可移植的通用数据结构、如字符串、链表和表。 88 | - 可移植的通用数据查找算法、数据排序算法和数据转换算法。 89 | - 以一种独立于操作系统的方式与操作系统的基础服务相联系的执行内存分配、操作线程、管理和维护时间以及流I/O等任务的函数。 90 | 91 | * 2、使用C++标准库的注意事项 92 | - 标准库的实现中有bug,(标准库和编译器是单独维护的,编译器中也可能存在bug,标准需求的改变、责任的分散、计划问题以及标准库的复杂度都会不可避免地影响它们的质量)。 93 | - 标准库的实现可能不符合C++标准,(库的发布计划和编译器是不同的,而编译器的发布计划与与C++标准不同,一个标准库的实现可能会领先或是落后于编译器)。 94 | - 对于标准库开发人员来说,性能并非是最终要的事情,(因为库会被长期使用,所以库的简单性和可维护性更加重要)。 95 | - 库的实现可能会让一些优化手段失效,C++标准库中的有些部分并非是有用的。 96 | - 标准库不如最好的原生函数,(标准库没有为某些操作系统提供异步文件I/O等特性,性能优化人员只能通过调用原生函数,牺牲可移植性来换取运行速度)。 97 | 98 | * 3、C++标准库之所以提供这些函数和类,是因为要么无法以其他方式提供这些函数和类,要么这些函数和类被广泛地用于多种操作系统上。在对库进行性能优化时,测试用例非常关键;接口的稳定性是可交付的库的核心。 99 | 100 | * 4、扁平继承层次关系(多数抽象都不会有超高三层类继承层次,一旦超高三次可能表明类的层次结构不够清晰,其引入的复杂性会导致性能的下降)。 101 | 扁平调用链(绝大多数抽象的实现都不会超高三层嵌套函数的调用,在已经充分解耦的库中是不会包含冗长的嵌套抽象调用链的)。 102 | 103 | 104 | 105 | ### 八、优化算法 106 | 107 | * 1、高效的算法是计算机科学一直研究的主题,计算机科学家十分重视算法和数据结构的研究,因为它是展示优化代码的典型事例。当一个程序需要数秒内执行完毕,实际上却要花费数小时时,唯一可以用成功的优化方法可能就是选择一种高效的算法了。算法是一个非常重要且不能简而概之的主题,可以参考《算法导论》,进行更深入的学习。 108 | 109 | * 2、优化模式 110 | 开发人员研究算法和数据结构的原因之一是其中蕴含着用于改善性能的“思维库”,这些改善性能的通用技巧是非常的使用的,其中的一些模式也是数据结构、C++语言特性和硬件创新的核心。 111 | * 预计算;可以在程序早期,通过在热点代码前执行执行计算来将计算从热点部分中移除。 112 | * 延迟计算;通过在正真需要执行计算时才执行计算,可将计算从某些代码路径上移除。 113 | * 批量处理;每次对多个元素一起进行计算,而不是一次只对一个元素进行计算。 114 | * 缓存;通过保存和复用高代价计算的结果来减少计算量,而不是重复进行计算。 115 | * 特化;通过移除未使用的共性来减少计算量。 116 | * 提高处理量;通过一次处理一大组数据来减少循环处理的开销。 117 | * 提示;通过在代码中加入可能会改善性能的提示来减少计算量。 118 | * 优化期待路径;以期待频率从高到低的顺序对输入数据或是运行时发生的事件进行测试。 119 | * 散列法;计算可变成字符串等大型数据结构的压缩数值映射(散列值)。在进行比较时,用散列代替数据结构可以提高性能。 120 | * 双重检查;通过先进行一项开销不大的检查,然后只在必要时才进行另外一项开销昂贵的检查来减少计算量。 121 | 122 | 123 | ### 九、优化查找和排序 124 | 125 | * 1、改善查找性能的工具箱,测量当前的实现方式的性能来得到比较基准,识别出待优化的抽象活动,将待优化的活动分解为组件算法和数据结构,修改或是替换那些可能并非最优的算法和数据结构,然后进行性能测试以确定修改是否有效果。 126 | 127 | * 2、标准库查找算法接受两个迭代器参数:一个指向待查找序列的开始位置,另一个则指向待查找序列的末尾位置(最后一个元素的下一个位置)。所有的算法还都接受一个要查找的键作为参数以及一个可选的比较函数参数。 128 | 129 | * 3、使用C++标准库优化排序,在能够使用分而治之算法高效地进行查找之前,我们必须先对序列容器排序,C++标准库提供了两种能够高效地对序列容器进行排序的标准算法——std::sort()和std::stable_sort()。 130 | 131 | 132 | 133 | ### 十、优化并发 134 | 135 | * 1、并发是多线程控制的同步执行,并发的目标不是减少指令执行的次数或是每秒访问数据的次数,而是通过提高计算资源的使用率来减少程序运行的时间的。 136 | 137 | * 2、有很多机制能够为程序提供并发,其中有些基于操作系统或是硬件。C++标准库直接支持线程共享内存的并发模型。 138 | 139 | * 3、计算机硬件、操作系统、函数库以及C++自身的特性都能够为程序提供并发支持。 140 | 141 | * 时间分隔;这是操作系统的一个调度函数,为每个程序都分配时间块。操作系统是依赖于处理器和硬件的。它会使用计时器和周期性的中断来调整处理器的调度。 142 | * 虚拟化;虚拟化技术是让操作系统将处理器的时间块分配给客户虚拟机,计算资源能够根据每台客户虚拟机上正在运行的程序的需求进行分配。 143 | * 容器化;容器中包含了程序在检查点的文件系统镜像和内存镜像,其主机是一个操作系统,能够直接提供I/O和系统资源。 144 | * 对称式多处理;是一种包含若干执行相同机器代码并访问相同物理内存的执行单元的计算机,现代多核处理器都是对称式多处理器。使用正真的硬件并发执行多线程控制。 145 | * 同步多线程;有些处理器的硬件核心有两个或多个寄存器集,可以相应地执行两条或多条指令流。最高效第使用软件线程的方法是让软件线程数量与硬件线程数量匹配。 146 | * 多进程;进程是并发的执行流,这些执行流有它们自己的受保护的虚拟内存空间,进程之间通过管道、队列、网路I/O或是其他不共享的机制进行通信,进程的主要优点是操作系统会隔离各个进程,使其不会互相干扰影响。 147 | * 分布式处理;是指程序活动分布在一组处理器上,这些处理器可以不同。分布式处理系统通常会被分解为子系统,形成模块化的,易于理解的和能够重新配置的体系结构。 148 | * 线程;线程是进程中的并发执行流,它们之间共享内存;与进程相比,线程的优点在于消耗的资源更少、创建和切换也更快。由于进程中的所有线程都共享相同的内存空间,所以一个线程写入无效的内存地址可能会覆盖掉其他线程的数据结构,导致线程奔溃或是出现不可预测的情况。 149 | * 任务;任务是一个独立线程的上下文中能够被异步调用的执行单元,任务运行的基础是线性池。基于任务的并发构建于线程之上,因此任务也具有线程的优点和缺点。 150 | 151 | 4、如果没有竞争,那么一个多线程C++程序具有顺序一致性,理想的竞争一块短临界区的核心数量是两个。在临界区中执行I/O操作无法优化性能,可运行线程的数量应当少于或等于处理器核心数量。 152 | -------------------------------------------------------------------------------- /学习笔记/Cplusplus/在main函数前执行一条语句.md: -------------------------------------------------------------------------------- 1 | ``` 2 | #include 3 | #include 4 | #include 5 | 6 | using namespace std; 7 | 8 | // lambda expression 9 | auto a = []() { 10 | std::cout << "before main" << '\n'; 11 | return 0; 12 | }(); 13 | 14 | // function b = [](){ 15 | // cout << "ok" << endl; 16 | // return 0; 17 | // }; 18 | int main(int argc, char const *argv[]) { 19 | std::cout << "main" << '\n'; 20 | return 0; 21 | } 22 | 23 | ``` 24 | -------------------------------------------------------------------------------- /学习笔记/Cplusplus/在main函数后执行一条语句.md: -------------------------------------------------------------------------------- 1 | ``` 2 | #include 3 | #include 4 | using namespace std; 5 | 6 | /* 7 | atexit()函数是在函数正常终止之前被调用执行的函数, 8 | 而且执行顺序和调用顺序正好相反。 9 | 原型: int atexit( void (*)(void) ); 10 | 在一个函数中最多可以用 atexit注册32个函数。 11 | 12 | 全局对象的析构函数会在main函数之后执行; 13 | 可以用 atexit() 注册一个函数,它会在main之后执行; 14 | */ 15 | int atexit(void (*function)(void)); 16 | 17 | void gao(){ 18 | printf( "This is executed last.\n" ); 19 | } 20 | 21 | int main(){ 22 | atexit( gao ); 23 | printf( "This is executed first.\n" ); 24 | return 0; 25 | } 26 | ``` 27 | -------------------------------------------------------------------------------- /学习笔记/Cplusplus/在main函数执行前的初始化.md: -------------------------------------------------------------------------------- 1 | main函数执行之前,主要就是初始化系统相关资源: 2 | 3 | 1.设置栈指针。 4 | 5 | 2.初始化static静态和global全局变量,即data段的内容。 6 | 7 | 3.将未初始化部分的赋初值:数值型short,int,long等为0,bool为FALSE,指针为NULL,等等,即.bss段的内容。 8 | 9 | 4.运行全局构造器,估计是C++中构造函数之类的吧。 10 | 11 | 5.将main函数的参数,argc,argv等传递给main函数,然后才真正运行main函数。 12 | 13 | main 函数之后会执行相反的工作。 14 | -------------------------------------------------------------------------------- /学习笔记/Cplusplus/循环队列.md: -------------------------------------------------------------------------------- 1 | #### 循环队列 2 | ``` 3 | #include 4 | #include 5 | #include 6 | 7 | using namespace std; 8 | using ll = long long; 9 | const int maxn = 123; 10 | 11 | #define queue_len 16; 12 | #define arr_size (16 + 1) 13 | 14 | typedef struct student { 15 | int math; 16 | int english; 17 | char name[32]; 18 | }student; 19 | 20 | 21 | static student student_table[arr_size]; 22 | static unsigned int front; 23 | static unsigned int tail; 24 | 25 | bool Is_empty() { 26 | return front == tail ? true : false; 27 | } 28 | bool Is_full() { 29 | return ((tail + 1) % arr_size == front) ? true :false; 30 | } 31 | 32 | bool queue_insert(student val) { 33 | if(Is_full()) return false; 34 | student_table[tail] = val; 35 | tail = (tail + 1) % arr_size; 36 | return true; 37 | } 38 | 39 | bool queue_delete(student val) { 40 | if(Is_empty()) return false; 41 | front = (front + 1) % arr_size; 42 | return true; 43 | } 44 | int main(int argc, char const *argv[]) { 45 | student stu; 46 | stu.math = 99; 47 | stu.english = 100; 48 | char name[32] = "LzyRapx"; 49 | memcpy(stu.name,name,sizeof(name)); 50 | queue_insert(stu); 51 | 52 | stu.math = 123; 53 | stu.english = 234; 54 | memset(name,0,sizeof(name)); 55 | sprintf(name,"XiaoZhao",sizeof(name)); 56 | memcpy(stu.name,name,sizeof(name)); 57 | queue_insert(stu); 58 | 59 | printf("front = %d,tail = %d,name = %s\n",front,tail,student_table[front].name); 60 | queue_delete(stu); 61 | printf("front = %d,tail = %d,name = %s\n",front,tail,student_table[front].name); 62 | 63 | return 0; 64 | } 65 | 66 | ``` 67 | -------------------------------------------------------------------------------- /学习笔记/Cplusplus/编写类String 的构造函数,析构函数,拷贝构造函数和赋值函数.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | class String { 5 | public: 6 | String(const char *str = NULL); // 普通构造函数 7 | String(const String &other); // 拷贝构造函数 8 | ~String(void); // 析构函数 9 | String & operator =(const String &other); // 赋值函数 10 | private: 11 | char *data; // 用来保存字符串 12 | }; 13 | 14 | // 普通构造函数 15 | String::String(const char *str) { 16 | if(str == NULL) { 17 | data = new char[1]; 18 | *data = '\0'; // 结束标志'\0' 19 | } 20 | else { 21 | int length = strlen(str); 22 | data = new char[length + 1]; 23 | strcpy(data,str); 24 | } 25 | } 26 | // 析构函数 27 | String::~String(void) { 28 | delete []data; 29 | } 30 | // 拷贝构造函数 31 | String::String(const String &other) { 32 | int length = strlen(other.data); 33 | data = new char[length + 1]; 34 | strcpy(data,other.data); 35 | } 36 | // 赋值函数 37 | String &String::operator =(const String &other) { 38 | if(this == &other) { // 检查自赋值 39 | return *this; 40 | } 41 | delete []data; 42 | int length = strlen(other.data); 43 | data = new char[length + 1]; 44 | strcpy(data, other.data); 45 | return *this; // 返回本对象的引用 46 | } 47 | 48 | int main(int argc, char const *argv[]) { 49 | String s = "asdasd"; 50 | String a; 51 | String b("abc"); 52 | // printf("%s\n", b.data); // 因为定义了private,封装了所以访问不了 53 | return 0; 54 | } 55 | -------------------------------------------------------------------------------- /学习笔记/Cplusplus/虚函数,多态,重写.md: -------------------------------------------------------------------------------- 1 | ``` 2 | #include 3 | 4 | using namespace std; 5 | 6 | class A 7 | { 8 | public: 9 | virtual void fun1() { 10 | std::cout << "A1.finish !" << '\n'; 11 | } 12 | virtual void fun2() { 13 | std::cout << "A2.finish !" << '\n'; 14 | } 15 | private: 16 | int _a; 17 | }; 18 | 19 | class B : public A { 20 | public: 21 | virtual void fun1() { // 这里会重写 类 A中的 fun1 22 | std::cout << "B1.finish !" << '\n'; 23 | } 24 | virtual void fun3() { 25 | std::cout << "B2.finish !" << '\n'; 26 | } 27 | private: 28 | int _b; 29 | }; 30 | 31 | /* 32 | 在funtest函数里面用基类的引用作为参数 33 | 真正传过去的是派生类的对象 34 | 而且在派生类里面对 fun1 数进行了重写 35 | 所以在执行期间会根据所引用的具体类型调用相应的函数。 36 | */ 37 | void funtest(A &s) { 38 | s.fun1(); // B1.finish ! 39 | s.fun2(); // A2.finish ! 40 | } 41 | 42 | int main(int argc, char const *argv[]) { 43 | B b; 44 | funtest(b); 45 | 46 | return 0; 47 | } 48 | ``` 49 | -------------------------------------------------------------------------------- /学习笔记/Cplusplus/虚表的简单查看.md: -------------------------------------------------------------------------------- 1 | ``` 2 | #include 3 | 4 | using namespace std; 5 | 6 | class A 7 | { 8 | public: 9 | virtual void fun1() { 10 | std::cout << "A1.finish !" << '\n'; 11 | } 12 | virtual void fun2() { 13 | std::cout << "A2.finish !" << '\n'; 14 | } 15 | // private: 16 | int _a; 17 | }; 18 | 19 | class B : public A { 20 | public: 21 | virtual void fun1() { // 这里会重写 类 A中的 fun1 22 | std::cout << "B1.finish !" << '\n'; 23 | } 24 | virtual void fun3() { 25 | std::cout << "B2.finish !" << '\n'; 26 | } 27 | // private: 28 | int _b; 29 | }; 30 | 31 | // 虚表的简单查看 32 | typedef void(*pvf)(); 33 | void print() 34 | { 35 | B b1; 36 | b1._a = 1; 37 | b1._b = 2; 38 | pvf *fun = (pvf *)*(int*)&b1; 39 | while (*fun) 40 | { 41 | (*fun)(); 42 | fun++; 43 | } 44 | } 45 | 46 | void FunTest() 47 | { 48 | std::cout << sizeof(A) << '\n'; // 8 49 | std::cout << sizeof(B) << endl; // 12 50 | } 51 | 52 | int main(int argc, char const *argv[]) { 53 | B b; 54 | FunTest(); 55 | /* 56 | B1.finish ! 57 | A2.finish ! 58 | B2.finish ! 59 | */ 60 | print(); 61 | return 0; 62 | } 63 | 64 | ``` 65 | -------------------------------------------------------------------------------- /学习笔记/Cplusplus/面试题(1 - 25).md: -------------------------------------------------------------------------------- 1 | ### 1.C 和 C++ 有什么区别 ? 2 | 3 | 答:c++在c的基础上增添类,C是一个结构化语言,它的重点在于算法和数据结构。 4 | C程序的设计首要考虑的是如何通过一个过程,对输入(或环境条件)进行运算处理得到输出(或实现过程(事务)控制). 5 | 而对于C++,首要考虑的是如何构造一个对象模型,让这个模型能够契合与之对应的问题域, 6 | 这样就可以通过获取对象的状态信息得到输出或实现过程(事务)控制。 7 | 8 | ### 2.const 有什么用途? 9 | 10 | 主要有三点: 11 | 12 | 1:定义只读变量,即常量. 13 | 14 | 2:修饰函数的参数和函数的返回值. 15 | 16 | 3: 修饰函数的定义体,这里的函数为类的成员函数,被const修饰的成员函数代表不修改成员变量的值. 17 | 18 | ### 3.指针和引用的区别 19 | 20 | 1:引用是变量的一个别名,内部实现是只读指针 21 | 22 | 2:引用只能在初始化时被赋值,其他时候值不能被改变,指针的值可以在任何时候被改变 23 | 24 | 3:引用不能为NULL,指针可以为NULL 25 | 26 | 4:引用变量内存单元保存的是被引用变量的地址 27 | 28 | 5:“sizeof 引用" = 指向变量的大小 , "sizeof 指针"= 指针本身的大小 29 | 30 | 6:引用可以取地址操作,返回的是被引用变量本身所在的内存单元地址 31 | 32 | 7:引用使用在源代码级相当于普通的变量一样使用,做函数参数时,内部传递的实际是变量地址 33 | 34 | ### 4.C++中有了malloc / free , 为什么还需要 new / delete 35 | 36 | 1:malloc与free是C++/C语言的标准库函数,new/delete是C++的运算符。它们都可用于申请动态内存和释放内存。 37 | 2:对于非内部数据类型的对象而言,光用maloc/free无法满足动态对象的要求。 38 | 对象在创建的同时要自动执行构造函数,对象在消亡之前要自动执行析构函数。 39 | 由于malloc/free是库函数而不是运算符,不在编译器控制权限之内,不能够把执行构造函数和析构函数的任务强加于malloc/free。 40 | 3:因此C++语言需要一个能完成动态内存分配和初始化工作的运算符new,以一个能完成清理与释放内存工作的运算符delete。 41 | 注意new/delete不是库函数。 42 | 43 | ### 5. 编写类String 的构造函数,析构函数,拷贝构造函数和赋值函数 44 | ``` 45 | #include 46 | #include 47 | using namespace std; 48 | class String { 49 | public: 50 | String(const char *str = NULL); // 普通构造函数 51 | String(const String &other); // 拷贝构造函数 52 | ~String(void); // 析构函数 53 | String & operator =(const String &other); // 赋值函数 54 | private: 55 | char *data; // 用来保存字符串 56 | }; 57 | 58 | // 普通构造函数 59 | String::String(const char *str) { 60 | if(str == NULL) { 61 | data = new char[1]; 62 | *data = '\0'; // 结束标志'\0' 63 | } 64 | else { 65 | int length = strlen(str); 66 | data = new char[length + 1]; 67 | strcpy(data,str); 68 | } 69 | } 70 | // 析构函数 71 | String::~String(void) { 72 | delete []data; 73 | } 74 | // 拷贝构造函数 75 | String::String(const String &other) { 76 | int length = strlen(other.data); 77 | data = new char[length + 1]; 78 | strcpy(data,other.data); 79 | } 80 | // 赋值函数 81 | String &String::operator =(const String &other) { 82 | if(this == &other) { // 检查自赋值 83 | return *this; 84 | } 85 | delete []data; 86 | int length = strlen(other.data); 87 | data = new char[length + 1]; 88 | strcpy(data, other.data); 89 | return *this; // 返回本对象的引用 90 | } 91 | 92 | int main(int argc, char const *argv[]) { 93 | String s = "asdasd"; 94 | String a; 95 | String b("abc"); 96 | // printf("%s\n", b.data); // 因为定义了private,封装了所以访问不了 97 | return 0; 98 | } 99 | 100 | ``` 101 | 102 | ### 6. 多态的实现与原理: 103 | 104 | [C++ 多态的实现及原理](https://www.cnblogs.com/cxq0017/p/6074247.html) 105 | 106 | C++的多态性用一句话概括就是:在基类的函数前加上virtual关键字,在派生类中重写该函数, 107 | 运行时将会根据对象的实际类型来调用相应的函数。 108 | 如果对象类型是派生类,就调用派生类的函数; 109 | 如果对象类型是基类,就调用基类的函数 110 | 1:用virtual关键字申明的函数叫做虚函数,虚函数肯定是类的成员函数。 111 | 2:存在虚函数的类都有一个一维的虚函数表叫做虚表,类的对象有一个指向虚表开始的虚指针。 112 | 虚表是和类对应的,虚表指针是和对象对应的。 113 | 3:多态性是一个接口多种实现,是面向对象的核心,分为类的多态性和函数的多态性。 114 | 4:多态用虚函数来实现,结合动态绑定. 115 | 5:纯虚函数是虚函数再加上 = 0; 116 | 6:抽象类是指包括至少一个纯虚函数的类。 117 | 纯虚函数:virtual void fun()=0;即抽象类!必须在子类实现这个函数, 118 | 即先有名称,没有内容,在派生类实现内容。 119 | 120 | ### 7.单链表的逆置: 121 | ``` 122 | /** 123 | * Definition for singly-linked list. 124 | * struct ListNode { 125 | * int val; 126 | * ListNode *next; 127 | * ListNode(int x) : val(x), next(NULL) {} 128 | * }; 129 | */ 130 | class Solution { 131 | public: 132 | ListNode* reverseList(ListNode* head) { 133 | if(head == NULL) return NULL; 134 | ListNode* pre = NULL; 135 | ListNode* now = head; 136 | while(now != NULL) 137 | { 138 | ListNode* tmp = now -> next; 139 | now -> next = pre; 140 | pre = now; 141 | now = tmp; 142 | } 143 | return pre; 144 | } 145 | }; 146 | ``` 147 | ### 8.堆和栈的区别 148 | 一个由c/C++编译的程序占用的内存分为以下几个部分: 149 | 150 | 1:栈区(stack):由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。 151 | 其操作方式类似于数据结构中的栈。 152 | 2:堆区(heap):一般由程序员分配释放,若程序员不释放,程序结束时可能由OS回收 。 153 | 注意它与数据结构中的堆是两回事,分配方式类似于链表。 154 | 3:全局区(静态区)(static) : 全局变量和静态变量的存储是放在一块的, 155 | 初始化的全局变量和静态变量在一块区域, 未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。 156 | 程序结束后有系统释放 . 157 | 4:文字常量区 :常量字符串就是放在这里的。 程序结束后由系统释放 . 158 | 5:程序代码区:存放函数体的二进制代码。 159 | 160 | ### 9.不调用C/C++ 的字符串库函数,编写strcpy: 161 | ``` 162 | char *strcpy(char *strDest, char *strSrc) { 163 | if((strDest == NULL) || strSrc == NULL) { 164 | return NULL; 165 | } 166 | char *strDestCopy = strDest; 167 | while((*strDest++ = *strSrc++) != '\0'); 168 | *strDest = '\0'; 169 | return strDestCopy; 170 | } 171 | ``` 172 | ### 10.关键字static的作用 173 | 1. 函数体内 static 变量的作用范围为该函数体,不同于 auto 变量, 174 | 该变量的内存只被分配一次,因此其值在下次调用时仍维持上次的值. 175 | 2. 在模块内的 static 全局变量可以被模块内所有函数访问,但不能被模块外其他函数访问. 176 | 3. 在模块内的static 函数只可被这一模块内的其他函数调用,这个函数的使用范围被限制在声明它的模块内. 177 | 4. 在类的static 成员变量属于整个类所拥有,对类的所有对象只有一份拷贝. 178 | 5. 在类中的 static 成员函数属于整个类所拥有,这个函数不接收 this 指针,因而只能访问类的 static 成员变量. 179 | 180 | ### 11.在c++程序中调用被C编译器编译后的函数,为什么要加 extern“C”? 181 | ``` 182 | C++语言支持函数重载,C语言不支持函数重载,函数被C++编译器编译后在库中的名字与C编译器编译后不同。 183 | 假设某个函数的原型为: 184 | void foo(int x, int y); 185 | 该函数被C编译后在库中的名字为:_foo 186 | 而C++编译器则会产生像 _foo_int_int 之类的名字。 187 | 为了解决此类名字匹配的问题,C++提供了C链接交换指定符号 extern "C". 188 | ``` 189 | ### 12.头文件中的ifndef/define/endif 是干什么用的? 190 | ``` 191 | 防止头文件被重复包含. 192 | ``` 193 | 194 | ### 13.线程和进程的联系与区别 195 | [线程和进程的联系与区别](https://blog.csdn.net/wolenski/article/details/7969908) 196 | ``` 197 | 1、线程是进程的一部分,所以线程有的时候被称为是轻权进程或者轻量级进程。 198 | 2、一个没有线程的进程是可以被看作单线程的,如果一个进程内拥有多个进程,进程的执行过程不是一条线(线程)的,而是多条线(线程)共同完成的。 199 | 3、系统在运行的时候会为每个进程分配不同的内存区域,但是不会为线程分配内存(线程所使用的资源是它所属的进程的资源),线程组只能共享资源。 200 | 那就是说,出了CPU之外(线程在运行的时候要占用CPU资源),计算机内部的软硬件资源的分配与线程无关,线程只能共享它所属进程的资源。 201 | 4、与进程的控制表PCB相似,线程也有自己的控制表TCB,但是TCB中所保存的线程状态比PCB表中少多了。 202 | 5、进程是系统所有资源分配时候的一个基本单位,拥有一个完整的虚拟空间地址,并不依赖线程而独立存在。 203 | ``` 204 | 205 | ### 14.线程有哪几种状态? 206 | ``` 207 | 线程有四种状态:新生状态、可运行状态、被阻塞状态、死亡状态. 208 | ``` 209 | [线程有哪几种状态](https://blog.csdn.net/wolenski/article/details/7969908) 210 | 211 | ### 15.进程间的通行方式? 212 | ``` 213 | 管道,有名管道,信号,共享内存,消息队列,信息量,套接字. 214 | ``` 215 | ``` 216 | # 管道( pipe ):管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用。 217 | 进程的亲缘关系通常是指父子进程关系。 218 | # 有名管道 (named pipe) : 有名管道也是半双工的通信方式,但是它允许无亲缘关系进程间的通信。 219 | # 信号量( semophore ) : 信号量是一个计数器,可以用来控制多个进程对共享资源的访问。 220 | 它常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源。 221 | 因此,主要作为进程间以及同一进程内不同线程之间的同步手段。 222 | # 消息队列( message queue ) : 消息队列是由消息的链表,存放在内核中并由消息队列标识符标识。 223 | 消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点。 224 | # 信号 ( sinal ) : 信号是一种比较复杂的通信方式,用于通知接收进程某个事件已经发生。 225 | # 共享内存( shared memory ) :共享内存就是映射一段能被其他进程所访问的内存,这段共享内存由一个进程创建,但多个进程都可以访问。 226 | 共享内存是最快的 IPC 方式,它是针对其他进程间通信方式运行效率低而专门设计的。 227 | 它往往与其他通信机制,如信号两,配合使用,来实现进程间的同步和通信。 228 | # 套接字( socket ) : 套解口也是一种进程间通信机制,与其他通信机制不同的是,它可用于不同及其间的进程通信。 229 | ``` 230 | ### 16.线程同步和线程互斥的区别: 231 | ``` 232 | 线程同步是指线程之间所具有的一种制约关系,一个线程的执行依赖另一个线程的消息, 233 | 当它没有得到另一个线程的消息时应等待,直到消息到达时才被唤醒。 234 | 235 | 线程互斥是指对于共享的进程系统资源,在各单个线程访问时的排它性。当 236 | 有若干个线程都要使用某一共享资源时,任何时刻最多只允许一个线程去使用,其它要使用该资源的线程必须等待,直到占用资源者释放该资源。 237 | 线程互斥可以看成是一种特殊的线程同步. 238 | ``` 239 | [线程同步和线程互斥的区别](https://blog.csdn.net/wolenski/article/details/7969908) 240 | 241 | ### 17.线程同步的方式 : 242 | [Linux线程同步的三种方法](https://blog.csdn.net/zsf8701/article/details/7844316) 243 | ``` 244 | Linux: 互斥锁、条件变量和信号量 245 | ``` 246 | ### 18.网络OSI七层和TCP/IP五层: 247 | [网络OSI七层 , TCP/IP五层及各层作用](https://blog.csdn.net/u011774517/article/details/67631439) 248 | 249 | ### 19.TCP和UDP有什么区别? 250 | ``` 251 | TCP---传输控制协议,提供的是面向连接、可靠的字节流服务。 252 | 当客户和服务器彼此交换数据前,必须先在双方之间建立一个TCP连接,之后才能传输数据。 253 | TCP提供超时重发,丢弃重复数据,检验数据,流量控制等功能,保证数据能从一端传到另一端。 254 | 255 | UDP---用户数据报协议,是一个简单的面向数据报的运输层协议。 256 | UDP不提供可靠性,它只是把应用程序传给IP层的数据报发送出去,但是并不能保证它们能到达目的地。 257 | 由于UDP在传输数据报前不用在客户和服务器之间建立一个连接,且没有超时重发等机制,故而传输速度很快. 258 | 259 | ``` 260 | ### 20.编写socket套接字的步骤. 261 | [编写socket套接字的步骤](https://blog.csdn.net/zhubo22/article/details/8045537) 262 | 263 | ### 21.TCP三次握手和四次挥手, 以及各个状态的作用 264 | [TCP三次握手和四次挥手过程](https://www.cnblogs.com/Andya/p/7272462.html) 265 | 266 | [TCP的三次握手与四次挥手过程,各个状态名称与含义,TIMEWAIT的作用](https://blog.csdn.net/sinat_32487221/article/details/55272305) 267 | 268 | ### 22.HTTP协议 269 | ``` 270 | http(超文本传输协议)是一个基于请求与响应模式的、无状态的、应用层的协议,常基于TCP的连接方式, 271 | HTTP1.1版本中给出一种持续连接的机制,绝大多数的 Web 开发,都是构建在 HTTP 协议之上的 Web 应用。 272 | ``` 273 | [TCP 和 HTTP区别]( http://blog.csdn.net/lemonxuexue/article/details/4485877) 274 | 275 | ### 23.使用过的 shell 命令 276 | ``` 277 | cp , mv , rm , mkdir , touch , pwd , cd , ls , top , cat , tail , less , df , du , man , find , kill , sudo , cat 278 | ``` 279 | ### 24.使用过的 vim 命令 280 | ``` 281 | wq!, dd , dw , yy , p , i , %s/old/new/g , /abc 向后搜索字符串abc , ?abc向前搜索字符串abc 282 | ``` 283 | ### 25.使用过的 gdb 命令 284 | [比较全面的gdb调试命令](https://blog.csdn.net/dadalan/article/details/3758025) 285 | 286 | 287 | 288 | 289 | 290 | 291 | -------------------------------------------------------------------------------- /学习笔记/Cplusplus/面试题(26 - 50).md: -------------------------------------------------------------------------------- 1 | ### 26.快速排序 2 | 思想: 3 | 4 | 1.先从数列中取出一个数作为基准数。 5 | 6 | 2.分区过程,将比这个数大的数全放到它的右边,小于或等于它的数全放到它的左边。 7 | 8 | 3.再对左右区间重复第二步,直到各区间只有一个数。 9 | 10 | 时空复杂度: 11 | 平均时间复杂度:O(nlogn) 12 | 13 | 最优的情况下空间复杂度为:O(logn) ;每一次都平分数组的情况 14 | 15 | 最差的情况下空间复杂度为:O(n) ;退化为冒泡排序的情况 16 | ``` 17 | #pragma GCC optimize("O2") 18 | #include 19 | using namespace std; 20 | int a[10000100]; 21 | void quick_sort(int a[], int l, int r) { 22 | if (l < r) { 23 | int i = l, j = r, x = a[l]; 24 | while (i < j) { 25 | while(i < j && a[j] >= x) j--; 26 | if(i < j) a[i++] = a[j]; 27 | while(i < j && a[i] < x) i++; 28 | if(i < j) a[j--] = a[i]; 29 | } 30 | a[i] = x; 31 | quick_sort(a, l, i - 1); 32 | quick_sort(a, i + 1, r); 33 | } 34 | } 35 | int main(int argc, char const *argv[]) { 36 | srand((int)time(0)); 37 | for(int i = 0;i < 10000000; i++) { 38 | a[i] = rand(); 39 | } 40 | int t = clock(); 41 | quick_sort(a,0,10000000); 42 | printf("%d ms\n",clock() -t); 43 | return 0; 44 | } 45 | ``` 46 | ### 27.归并排序 47 | [归并排序的实现](https://blog.csdn.net/yuehailin/article/details/68961304) 48 | ``` 49 | #pragma GCC optimize("O2") 50 | #include 51 | using namespace std; 52 | int a[123]; 53 | 54 | // 将二个有序数列a[first...mid]和a[mid...last]合并。 55 | void mergeArray(int a[],int first, int mid, int last, int tmp[]) 56 | { 57 | int i = first; 58 | int j = mid + 1; 59 | 60 | int m = mid; 61 | int n = last; 62 | 63 | int k = 0; 64 | while(i <= m && j <= n) { 65 | if(a[i] <= a[j]) { 66 | tmp[k++] = a[i++]; 67 | } 68 | else { 69 | tmp[k++] = a[j++]; 70 | } 71 | } 72 | while(i <= m) { 73 | tmp[k++] = a[i++]; 74 | } 75 | while(j <= n) { 76 | tmp[k++] = a[j++]; 77 | } 78 | for(i = 0; i < k; i++) { 79 | a[first + i] = tmp[i]; 80 | } 81 | } 82 | 83 | void merge(int a[], int first, int last, int tmp[]) 84 | { 85 | if(first < last) { 86 | int mid =(first + last) / 2; 87 | merge(a, first, mid, tmp); //左边有序 88 | merge(a, mid + 1, last, tmp); //右边有序 89 | mergeArray(a, first, mid, last, tmp); //再将二个有序数列合并 90 | } 91 | } 92 | int p[123]; 93 | void mergeSort(int a[],int n) { 94 | merge(a, 0 ,n - 1, p); 95 | } 96 | int main(int argc, char const *argv[]) { 97 | srand((int)time(0)); 98 | for(int i = 0;i < 100; i++) { 99 | a[i] = rand(); 100 | } 101 | int t = clock(); 102 | mergeSort(a,100); 103 | for(int i = 0; i < 100; i++) { 104 | cout << a[i] << " "; 105 | } 106 | std::cout << '\n'; 107 | printf("%d ms\n",clock() -t); 108 | return 0; 109 | } 110 | 111 | ``` 112 | 113 | ### 28.堆排序 114 | [堆排序原理及算法实现](https://blog.csdn.net/xiaoxiaoxuewen/article/details/7570621) 115 | ``` 116 | #pragma GCC optimize("O2") 117 | #include 118 | using namespace std; 119 | int a[123]; 120 | 121 | // 大顶堆 122 | void heapAdjust(int a[], int i, int n) 123 | { 124 | int lchild = 2 * i; 125 | int rchild = 2 * i + 1; 126 | int max = i; 127 | if(i <= n / 2) 128 | { 129 | if(lchild <= n && a[lchild] > a[max]) { 130 | max = lchild; 131 | } 132 | if(rchild <= n && a[rchild] > a[max]) { 133 | max = rchild; 134 | } 135 | if(max != i) { 136 | swap(a[i], a[max]); 137 | heapAdjust(a, max, n); //避免调整之后以max为父节点的子树不是堆 138 | } 139 | } 140 | } 141 | 142 | void buildHeap(int a[], int n) //建立堆 143 | { 144 | for(int i = n / 2; i >= 1; --i) { // 非叶节点最大序号值为 n/2 145 | heapAdjust(a, i, n); 146 | } 147 | } 148 | 149 | void heapSort(int a[], int n) { 150 | buildHeap(a,n); 151 | for(int i = n; i >= 1; --i) { 152 | //交换堆顶和最后一个元素,即每次将剩余元素中的最大者放到最后面 153 | swap(a[1],a[i]); 154 | buildHeap(a, i - 1); //将余下元素重新建立为大顶堆 155 | heapAdjust(a, 1, i - 1); //重新调整堆顶节点成为大顶堆 156 | } 157 | } 158 | 159 | int main(int argc, char const *argv[]) { 160 | srand((int)time(0)); 161 | for(int i = 1;i <= 100; i++) { 162 | a[i] = rand(); 163 | } 164 | int t = clock(); 165 | heapSort(a,100); 166 | for(int i = 1; i <= 100; i++) { 167 | cout << a[i] << " "; 168 | } 169 | std::cout << '\n'; 170 | printf("%d ms\n",clock() -t); 171 | return 0; 172 | } 173 | 174 | ``` 175 | ### 29.排序算法稳定性分析 176 | [排序算法稳定性分析](https://baike.baidu.com/item/%E6%8E%92%E5%BA%8F%E7%AE%97%E6%B3%95%E7%A8%B3%E5%AE%9A%E6%80%A7) 177 | ``` 178 | 稳定: 179 | 冒泡排序,插入排序,归并排序,基数排序(桶排) 180 | ``` 181 | 182 | ### 30.静态链表和动态链表的区别: 183 | [静态链表和动态链表的区别](http://blog.csdn.net/toonny1985/article/details/4868786) 184 | 185 | ### 31.大并发(epoll) 186 | 优点:[深入linux网络编程(三):异步阻塞IO —— epoll](https://blog.csdn.net/sunyurun/article/details/8194979) 187 | 188 | 实例:[Linux IO多路复用之epoll网络编程(含源码)](http://www.cnblogs.com/ggjucheng/archive/2012/01/17/2324974.html) 189 | 190 | ### 32.海量数据处理的知识点(hash表,hash统计) 191 | [大数据处理:hash表](https://blog.csdn.net/yusiguyuan/article/details/12882309) 192 | 193 | [海量数据处理方法](https://blog.csdn.net/v_july_v/article/details/7382693) 194 | 195 | ### 33. 什么时候要用到虚析构函数? 196 | 197 | 通过基类的指针来删除派生类的对象时,基类的析构函数应该是虚的。否则其删除效果将无法实现。 198 | 一般情况下,这样的删除只能够删除基类对象,而不能删除子类对象,形成了删除一半形象,从而千万内存泄漏。 199 | 原因: 200 | 在公有继承中,基类对派生类及其对象的操作,只能影响到那些从基类继承下来的成员。 201 | 如果想要用基类对非继承成员进行操作,则要把基类的这个操作(函数)定义为虚函数。 202 | 那么,析构函数自然也应该如此:如果它想析构子类中的重新定义或新的成员及对象,当然也应该声明为虚的。 203 | 注意: 204 | 如果不需要基类对派生类及对象进行操作,则不能定义虚函数(包括虚析构函数),因为这样会增加内存开销。 205 | 206 | ### 34.c++怎样让返回对象的函数不调用拷贝构造函数 207 | ``` 208 | 拷贝构造函数前加 “explicit” 关键字 209 | ``` 210 | ### 35.孤儿进程和僵尸进程 211 | * 孤儿进程:一个父进程退出,而它的一个或多个子进程还在运行,那么那些子进程将成为孤儿进程。孤儿进程将被init进程(进程号为1)所收养,并由init进程对它们完成状态收集工作。 212 | 213 | * 僵尸进程:一个进程使用fork创建子进程,如果子进程退出,而父进程并没有调用wait或waitpid获取子进程的状态信息,那么子进程的进程描述符仍然保存在系统中。这种进程称之为僵死进程。 214 | 215 | [孤儿进程和僵尸进程](http://www.cnblogs.com/Anker/p/3271773.html) 216 | 217 | ### 36.请用简单的语言告诉我C++ 是什么? 218 | ``` 219 | C++是在C语言的基础上开发的一种面向对象编程语言,应用广泛。C++支持多种编程范式 --面向对象编程、泛型编程和过程化编程。 220 | 其编程领域众广,常用于系统开发,引擎开发等应用领域,是最受广大程序员受用的最强大编程语言之一,支持类:类、封装、重载等特性。 221 | ``` 222 | ### 37.C 和 C++ 的区别? 223 | ``` 224 | c++在 c 的基础上增添类,C是一个结构化语言,它的重点在于算法和数据结构。 225 | C 程序的设计首要考虑的是如何通过一个过程,对输入(或环境条件)进行运算处理得到输出(或实现过程(事务)控制). 226 | 而对于C++,首要考虑的是如何构造一个对象模型, 让这个模型能够契合与之对应的问题域, 227 | 这样就可以通过获取对象的状态信息得到输出或实现过程(事务)控制。 228 | ``` 229 | ### 38.什么是面向对象(OOP)? 230 | ``` 231 | 面向对象是一种对现实世界理解和抽象的方法、思想,通过将需求要素转化为对象进行问题处理的一种思想。 232 | ``` 233 | ### 39.什么是多态? 234 | ``` 235 | 多态是指相同的操作或函数、过程可作用于多种类型的对象上并获得不同的结果。 236 | 不同的对象,收到同一消息可以产生不同的结果,这种现象称为多态。 237 | ``` 238 | ### 40.设计模式懂吗,简单举个例子? 239 | ``` 240 | 设计模式(Design pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。 241 | 242 | 比如单例模式,保证一个类仅有一个实例,并提供一个访问它的全局访问点。 243 | 适用于:当类只能有一个实例而且客户可以从一个众所周知的访问点访问它时; 244 | 当这个唯一实例应该是通过子类化可扩展的,并且客户应该无需更改代码就能使用一个扩展的实例时。 245 | 246 | 比如工厂模式:定义一个用于创建对象的接口,让子类决定实例化哪一个类。Factory Method 使一个类的实例化延迟到其子类。 247 | 适用于:当一个类不知道它所必须创建的对象的类的时候;当一个类希望由它的子类来指定它所创建的对象的时候; 248 | 当类将创建对象的职责委托给多个帮助子类中的某一个,并且你希望将哪一个帮助子类是代理者这一信息局部化的时候。 249 | ``` 250 | ### 41.const 知道吗?解释其作用。 251 | ``` 252 | 1.const 修饰类的成员变量,表示成员常量,不能被修改。 253 | 2.const修饰函数承诺在本函数内部不会修改类内的数据成员,不会调用其它非 const 成员函数。 254 | 3.如果 const 构成函数重载,const 对象只能调用 const 函数,非 const 对象优先调用非 const 函数。 255 | 4.const 函数只能调用 const 函数。非 const 函数可以调用 const 函数。 256 | 5.类体外定义的 const 成员函数,在定义和声明处都需要 const 修饰符。 257 | ``` 258 | ### 42.类的 static 变量在什么时候初始化?函数的 static 变量在什么时候初始化? 259 | ``` 260 | 类的静态成员变量在类实例化之前就已经存在了,并且分配了内存。 261 | 函数的static变量在执行此函数时进行初始化。 262 | ``` 263 | ### 43.堆和栈的区别?堆和栈的生命周期? 264 | #### 一.堆栈空间分配区别: 265 | ``` 266 | 1、栈(操作系统):由操作系统自动分配释放 ,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈; 267 | 2、堆(操作系统): 一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收,分配方式倒是类似于链表。 268 | ``` 269 | #### 二.堆栈缓存方式区别: 270 | ``` 271 | 堆(数据结构):堆可以被看成是一棵树,如:堆排序; 272 | 栈(数据结构):一种先进后出的数据结构。 273 | ``` 274 | #### 三、堆栈数据结构区别: 275 | ``` 276 | 堆(数据结构):堆可以被看成是一棵树:如:堆排序; 277 | 栈(数据结构):一种先进后出的数据结构. 278 | ``` 279 | ### 44.解释下封装、继承和多态? 280 | 281 | #### 一.封装: 282 | ``` 283 | 封装是实现面向对象程序设计的第一步,封装就是将数据或函数等集合在一个个的单元中(我们称之为类)。 284 | 封装的意义在于保护或者防止代码(数据)被我们无意中破坏。 285 | ``` 286 | #### 二.继承: 287 | ``` 288 | 继承主要实现重用代码,节省开发时间。 289 | 子类可以继承父类的一些东西。 290 | ``` 291 | #### 三.多态: 292 | ``` 293 | 多态:同一操作作用于不同的对象,可以有不同的解释,产生不同的执行结果。 294 | 在运行时,可以通过指向基类的指针,来调用实现派生类中的方法。 295 | ``` 296 | ### 45.指针和引用的区别? 297 | ``` 298 | 1. 指针是一个变量,只不过这个变量存储的是一个地址,指向内存的一个存储单元;而引用仅是个别名; 299 | 2. 引用使用时无需解引用(*),指针需要解引用; 300 | 3. 引用只能在定义时被初始化一次,之后不可变;指针可变; 301 | 4. 引用没有 const,指针有 const; 302 | 5. 引用不能为空,指针可以为空; 303 | 6. “sizeof 引用”得到的是所指向的变量(对象)的大小,而“sizeof 指针”得到的是指针本身的大小; 304 | 7. 指针和引用的自增(++)运算意义不一样; 305 | 8. 指针可以有多级,但是引用只能是一级(int **p;合法 而 int &&a是不合法的) 306 | 9.从内存分配上看:程序为指针变量分配内存区域,而引用不需要分配内存区域。 307 | ``` 308 | ### 46.什么是内存泄漏?面对内存泄漏和指针越界,你有哪些方法?你通常采用哪些方法来避免和减少这类错误? 309 | ``` 310 | 用动态存储分配函数动态开辟的空间,在使用完毕后未释放,结果导致一直占据该内存单元即为内存泄露. 311 | 使用的时候要记得指针的长度. 312 | malloc的时候得确定在那里free. 313 | 对指针赋值的时候应该注意被赋值指针需要不需要释放. 314 | 动态分配内存的指针最好不要再次赋值. 315 | ``` 316 | ### 47.new 和 malloc 的区别? 317 | ``` 318 | 1、malloc与free是C++/C语言的标准库函数,new/delete是C++的运算符。它们都可用于申请动态内存和释放内存。 319 | 2、对于非内部数据类型的对象而言,光用malloc/free无法满足动态对象的要求。 320 | 对象在创建的同时要自动执行构造函数,对象在消亡之前要自动执行析构函数。 321 | 3、由于malloc/free是库函数而不是运算符,不在编译器控制权限之内,不能够把执行构造函数和析构函数的任务强加于malloc/free。 322 | 因此 C++ 语言需要一个能完成动态内存分配和初始化工作的运算符 new,以一个能完成清理与释放内存工作的运算符delete。注意 new/delete 不是库函数。 323 | 4、C++ 程序经常要调用C函数,而 C 程序只能用 malloc/free 管理动态内存。 324 | 5、new 可以认为是 malloc 加构造函数的执行。new 出来的指针是直接带类型信息的。而 malloc 返回的都是 void 指针。 325 | ``` 326 | ### 48.TCP 和 UDP 通信的差别?什么是IOCP? 327 | ``` 328 | 1.TCP面向连接, UDP面向无连接的 329 | 2.TCP有保障的,UDP传输无保障的 330 | 3.TCP是效率低的,UDP效率高的 331 | 4.TCP是基于流的,UDP基于数据报文 332 | 5.TCP传输重要数据,UDP传输不重要的数据 333 | IOCP全称I/O Completion Port,中文译为I/O完成端口。 334 | IOCP是一个异步I/O的API,它可以高效地将I/O事件通知给应用程序。 335 | 与使用select()或是其它异步方法不同的是,一个套接字[socket]与一个完成端口关联了起来,然后就可继续进行正常的Winsock操作了。 336 | 然而,当一个事件发生的时候,此完成端口就将被操作系统加入一个队列中。然后应用程序可以对核心层进行查询以得到此完成端口。 337 | ``` 338 | ### 49.同步IO和异步IO的区别? 339 | ``` 340 | A. 同步 341 | 所谓同步,就是在发出一个功能调用时,在没有得到结果之前,该调用就不返回。 342 | 按照这个定义,其实绝大多数函数都是同步调用(例如sin isdigit等)。 343 | 但是一般而言,我们在说同步、异步的时候,特指那些需要其他部件协作或者需要一定时间完成的任务。 344 | 最常见的例子就是 SendMessage。 345 | 该函数发送一个消息给某个窗口,在对方处理完消息之前,这个函数不返回。 346 | 当对方处理完毕以后,该函数才把消息处理函数所返回的值返回给调用者。 347 | 348 | B. 异步 349 | 异步的概念和同步相对。 350 | 当一个异步过程调用发出后,调用者不会立刻得到结果。 351 | 实际处理这个调用的部件是在调用发出后,通过状态、通知来通知调用者,或通过回调函数处理这个调用。 352 | ``` 353 | ### 50.解释C++中静态函数和静态变量? 354 | ``` 355 | (1)类静态数据成员在编译时创建并初始化:在该类的任何对象建立之前就存在,不属于任何对象, 356 | 而非静态类成员变量则是属于对象所有的。类静态数据成员只有一个拷贝,为所有此类的对象所共享。 357 | (2)类静态成员函数属于整个类,不属于某个对象,由该类所有对象共享。 358 | 1、static 成员变量实现了同类对象间信息共享。 359 | 2、static 成员类外存储,求类大小,并不包含在内。 360 | 3、static 成员是命名空间属于类的全局变量,存储在 data 区的rw段。 361 | 4、static 成员只能类外初始化。 362 | 5、可以通过类名访问(无对象生成时亦可),也可以通过对象访问。 363 | 1、静态成员函数的意义,不在于信息共享,数据沟通,而在于管理静态数据成员,完成对静态数据成员的封装。 364 | 2、静态成员函数只能访问静态数据成员。原因:非静态成员函数,在调用时 this指针时被当作参数传进。 365 | 而静态成员函数属于类,而不属于对象,没有 this 指针。 366 | ``` 367 | 368 | 369 | 370 | -------------------------------------------------------------------------------- /学习笔记/Cplusplus/面试题(51 - INF).md: -------------------------------------------------------------------------------- 1 | ### 51. 说下你对内存的了解? 2 | ``` 3 | 1.栈 - 由编译器自动分配释放 4 | 2.堆 - 一般由程序员分配释放,若程序员不释放,程序结束时可能由OS回收 5 | 3.全局区(静态区),全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域, 6 | 未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。- 程序结束释放 7 | 4.另外还有一个专门放常量的地方。- 程序结束释放 8 | 5.程序代码区,存放2进制代码。 9 | 在函数体中定义的变量通常是在栈上,用malloc, calloc, realloc等分配内存的函数分配得到的就是在堆上。 10 | 在所有函数体外定义的是全局量,加了static修饰符后不管在哪里都存放在全局区(静态区)。 11 | 在所有函数体外定义的static变量表示在该文件中有效,不能extern到别的文件用,在函数体内定义的static表示只在该函数体内有效。 12 | 另外,函数中的"adgfdf"这样的字符串存放在常量区。 13 | ``` 14 | ### 52.如何初始化一个指针数组. 15 | ``` 16 | 首先明确一个概念,就是指向数组的指针,和存放指针的数组。 17 | 指向数组的指针:char (*array)[5]; 含义是一个指向存放5个字符的数组的指针。 18 | 存放指针的数组:char *array[5];含义是一个数组中存放了5个指向字符型数据的指针。 19 | 按照题意,我理解为初始化一个存放指针的数组,char *array[2]={“China”,”Beijing”}; 20 | 其含义是初始化了一个有两个指向字符型数据的指针的数组,这两个指针分别指向字符串”China”和”Beijing”。 21 | ``` 22 | ### 53.关键字const是什么含意? 23 | ``` 24 | 我只要一听到被面试者说:“const意味着常数”,我就知道我正在和一个业余者打交道。 25 | 去年Dan Saks已经在他的文章里完全概括了const的所有用法,因此ESP(译者:Embedded Systems Programming)的 26 | 每一位读者应该非常熟悉const能做什么和不能做什么.如果你从没有读到那篇文章, 27 | 只要能说出const意味着“只读”就可以了。 28 | 尽管这个答案不是完全的答案,但我接受它作为一个正确的答案。 29 | (如果你想知道更详细的答案,仔细读一下Saks的文章吧。) 30 | 如果应试者能正确回答这 个问题,我将问他一个附加的问题:下面的声明都是什么意思? 31 | ``` 32 | ``` 33 | const int a; 34 | 35 | int const a; 36 | 37 | const int *a; 38 | 39 | int * const a; 40 | 41 | int const * a const; 42 | 43 | 前两个的作用是一样,a是一个常整型数。 44 | 第三个意味着a是一个指向常整型数的指针(也就是,整型数是不可修改的,但指针可以)。 45 | 第四个意思a是一个指向整 型数的常指针(也就是说,指针指向的整型数是可以修改的,但指针是不可修改的)。 46 | 最后一个意味着a是一个指向常整型数的常指针(也就是说,指针指向的整型 数是不可修改的,同时指针也是不可修改的)。 47 | 如果应试者能正确回答这些问题,那么他就给我留下了一个好印象。 48 | 顺带提一句,也许你可能会问,即使不用关键字 const,也还是能很容易写出功能正确的程序, 49 | 那么我为什么还要如此看重关键字const呢?我也如下的几下理由: 50 | 1). 关键字const的作用是为给读你代码的人传达非常有用的信息,实际上,声明一个参数为常量是为了告诉了用户这个参数的应用目的。 51 | 如果你曾花很多时间清理 其它人留下的垃圾,你就会很快学会感谢这点多余的信息。 52 | (当然,懂得用const的程序员很少会留下的垃圾让别人来清理的。) 53 | 2). 通过给优化器一些附加的信息,使用关键字const也许能产生更紧凑的代码。 54 | 3). 合理地使用关键字const可以使编译器很自然地保护那些不希望被改变的参数,防止其被无意的代码修改。 55 | 简而言之,这样可以减少bug的出现。 56 | ``` 57 | ### 54.什么是动态特性? 58 | ``` 59 | 在绝大多数情况下, 程序的功能是在编译的时候就确定下来的, 我们称之为静态特性。 60 | 反之, 如果程序的功能是在运行时刻才能确定下来的, 则称之为动态特性。 61 | C++中, 虚函数,抽象基类, 动态绑定和多态构成了出色的动态特性。 62 | ``` 63 | ### 55.基类的有1个虚函数,子类还需要申明为 virtual吗?为什么。 64 | ``` 65 | 不申明没有关系的。 不过,我总是喜欢显式申明,使得代码更加清晰。 66 | ``` 67 | ### 56.在C++ 程序中调用被 C 编译器编译后的函数,为什么要加 extern “C”声明? 68 | ``` 69 | 函数和变量被C++编译后在符号库中的名字与C语言的不同,被extern “C”修饰的变量和函数是按照C语言方式编译和连接的。 70 | 由于编译后的名字不同,C++程序不能直接调用C 函数。C++提供了一个C 连接交换指定符号extern“C”来解决这个问题。 71 | ``` 72 | ### 57.如何定义Bool变量的TRUE和FALSE的值. 73 | ``` 74 | 一般来说先要把TURE和FALSE给定义了. 75 | 使用#define就可以: 76 | #define TURE 1 77 | #define FALSE 0 78 | 如果有一个变量需要定义成bool型的, 79 | 举个例子: 80 | bool a = TURE; 81 | 就可以了 82 | ``` 83 | ### 58.内联函数 inline 和宏定义一起使用的区别. 84 | ``` 85 | 内联函数是在编译的时候已经做好将对应的函数代码替换嵌入到对应的位置,适用于代码较少的函数。 86 | 宏定义是简单的替换变量,如果定义的是有参数的函数形式,参数不做类型校验。 87 | ``` 88 | ### 59.ICMP是什么协议,处于哪一层? 89 | ``` 90 | Internet控制报文协议,处于网络层(IP层) 91 | ``` 92 | ### 60. C 中 static 有什么作用? 93 | ``` 94 | (1)隐藏。 95 | 当我们同时编译多个文件时,所有未加static前缀的全局变量和函数都具有全局可见性, 96 | 故使用static在不同的文件中定义同名函数和同名变量,而不必担心命名冲突。 97 | 98 | (2)static的第二个作用是保持变量内容的持久。 99 | 存储在静态数据区的变量会在程序刚开始运行时就完成初始化,也是唯一的一次初始化。 100 | 共有两种变量存储在静态存储区:全局变量和static变量。 101 | 102 | (3)static的第三个作用是默认初始化为0。 103 | 其实全局变量也具备这一属性,因为全局变量也存储在静态数据区。 104 | 在静态数据区,内存中所有的字节默认值都是0×00,某些时候这一特点可以减少程序员的工作量。 105 | ``` 106 | ### 61. malloc 和 new 的区别。 107 | ``` 108 | 1、malloc/free是C/C++中的方法(函数),new/delete是C++中的操作符。 109 | 2、malloc申请的是heap区的内存空间,而new则是申请的free store区的内存空间。 110 | 3、使用free之前要判断,使其free的指针是!NULL的,使用delete则无须判断。 111 | 4、free掉的内存是该指针指向的一段内存空间,里面应该是空的。而delete掉的内存是里面确实存有数据或者对象的。 112 | ``` 113 | ### 62. malloc 最大能申请多大的内存.(我8G内存能申请1.7G左右) 114 | 测试代码: 115 | ``` 116 | #include 117 | 118 | using namespace std; 119 | 120 | int main(int argc, char const *argv[]) { 121 | unsigned int blocksize[] = {1024 * 1024, 1024, 1}; 122 | int max = 0; 123 | for(int i = 0; i < 3; i++) { 124 | for(int cnt = 1; ; cnt++) { 125 | void* block = malloc(max + blocksize[i] * cnt); 126 | if(block) { 127 | max += blocksize[i] * cnt; 128 | free(block); 129 | } 130 | else { 131 | break; 132 | } 133 | } 134 | } 135 | std::cout << "max malloc size = " << max << "B \n"; 136 | std::cout << "max malloc size = " << 1. * max / 1024.0 / 1024.0 / 1024.0 << "GB \n"; 137 | return 0; 138 | } 139 | 140 | ``` 141 | ### 63.C++ 空类,默认产生哪些成员函数? 142 | ``` 143 | 默认构造函数、默认拷贝构造函数、默认析构函数、默认赋值运算符 这四个是我们通常大都知道的。 144 | 但是除了这四个,还有两个,那就是取址运算符和 取址运算符 const. 145 | 即总共有六个函数。 146 | ``` 147 | ``` 148 | class Empty 149 | { 150 | public: 151 | Empty(); // 缺省构造函数 152 | Empty( const Empty& ); // 拷贝构造函数 153 | ~Empty(); // 析构函数 154 | Empty& operator=( const Empty& ); // 赋值运算符 155 | Empty* operator&(); // 取址运算符 156 | const Empty* operator&() const; // 取址运算符 const 157 | }; 158 | ``` 159 | ``` 160 | 但是,C++默认生成的函数,只有在被需要的时候,才会产生。 161 | 即当我们定义一个类,而不创建类的对象时,就不会创建类的构造函数、析构函数等。 162 | ``` 163 | ### 64.一个程序从开始运行到结束的完整过程? 164 | ``` 165 | 预处理 -> 编译 ->生成.obj文件 -> 汇编 -> 链接 ->生成exe可执行文件. 166 | ``` 167 | [一个程序从开始运行到结束的完整过程](http://www.cnblogs.com/xidian2014/p/8504580.html) 168 | 169 | ### 65.手写memcpy() 函数: 170 | ``` 171 | void *memcpy(void *dest, const void *src, size_t len) { 172 | if(dest == NULL || src == NULL) { 173 | return NULL; 174 | } 175 | void *ret = dest; 176 | // memcpy对内存空间有要求的, dest 和 src 所指向的内存空间不能重叠 177 | // 否则复制的数据是错误的 178 | if(dest <= src || (char *)dest >= (char *)src + len) }{ 179 | // 从前往后拷贝(如果没有重叠区域) 180 | while(len --) { 181 | *(char *)dest = *(char *)src; 182 | dest = (char *)dest + 1; 183 | src = (char *)src + 1; 184 | } 185 | } 186 | else { // 从后往前拷贝(如果有重叠区域) 187 | src = (char *)src + len - 1; 188 | dest = (char *)dest + len - 1; 189 | while(len --) { 190 | *(char *) dest = *(char *)src; 191 | dest = (char *)dest - 1; 192 | src = (char *)src - 1; 193 | } 194 | } 195 | return ret; 196 | } 197 | ``` 198 | ### 66. 线程和进程各自有什么区别和优劣? 199 | ``` 200 | 1.进程是资源分配的最小单位,线程是程序执行的最小单位。 201 | 202 | 2.进程有自己的独立地址空间,每启动一个进程,系统就会为它分配地址空间,建立数据表来维护代码段、堆栈段和数据段,这种操作非常昂贵。 203 | 而线程是共享进程中的数据的,使用相同的地址空间,因此CPU切换一个线程的花费远比进程要小很多,同时创建一个线程的开销也比进程要小很多。 204 | 205 | 3.线程之间的通信更方便,同一进程下的线程共享全局变量、静态变量等数据,而进程之间的通信需要以通信的方式(IPC)进行。 206 | 不过如何处理好同步与互斥是编写多线程程序的难点。 207 | 208 | 4.但是多进程程序更健壮,多线程程序只要有一个线程死掉,整个进程也死掉了, 209 | 而一个进程死掉并不会对另外一个进程造成影响,因为进程有自己独立的地址空间。 210 | ``` 211 | ### 67.封装,继承,多态,抽象 212 | ``` 213 | 1) 封装:指能够把一个实体的信息、功能、响应都装入一个单独的对象中的特性。 214 | 2) 继承:继承的方法允许在不改动原程序的基础上对其进行扩充,这样使得原功能得以保存,而新功能也得以扩展。这有利于减少重复编码,提高软件的开发效率。 215 | 3) 多态:同一操作作用于不同的对象,可以有不同的解释,产生不同的执行结果。在运行时,可以通过指向基类的指针,来调用实现派生类中的方法。 216 | 4) 抽象:抽象(Abstraction)是简化复杂的现实问题的途径,它可以为具体问题找到最恰当的类定义,并且可以在最恰当的继承级别解释问题。 217 | ``` 218 | ### 68. STL中vector,Map,Set的内部实现原理 219 | [STL中vector,Map,Set的内部实现原理](https://www.cnblogs.com/jijiji/p/4861651.html) 220 | 221 | ### 69. 64位系统int,long,long long分别是几位? 222 | ##### 64位 223 | ``` 224 | char : 1 225 | int : 4 226 | long : 8 227 | long long : 8 228 | ``` 229 | ##### 32位 230 | ``` 231 | char: 1 232 | int : 4 233 | long : 4 234 | long long : 8 235 | ``` 236 | [32位与64位系统基本数据类型的字节数](https://blog.csdn.net/u012611878/article/details/52455576) 237 | 238 | ### 70.手写c++的单例模式,要考虑线程同步 239 | [C++的单例模式与线程安全单例模式(懒汉/饿汉)](https://www.cnblogs.com/qiaoconglovelife/p/5851163.html) 240 | 241 | ### 71.虚函数的作用: 242 | ``` 243 | 虚函数的作用是减少了对基类的重复,代价是增加了虚表指针的负担(更多的虚表指针)。 244 | ``` 245 | 246 | ### 72.当基类有虚函数时。总结: 247 | ``` 248 | 1.每个类都有虚指针和虚表。 249 | 2.如果不是虚继承,那么子类将父类的虚指针继承下来,并指向自身的虚表 (发生在对象构造时), 250 | 有多少个虚函数,虚表里面的项就会有多少。多重继承时,可能存在多个的基类虚表和虚指针。 251 | 3.如果是虚继承,那么子类会有两份虚指针,一份指着自己的虚表,一份指向虚基表,多重继承时虚基表与虚基表指针有且只有一份。 252 | ``` 253 | ### 73.虚函数表存放在哪里? 254 | ``` 255 | 1.虚函数表是全局共享的元素,即全局仅有一个. 256 | 2.虚函数表类似一个数组,类对象中存储vptr指针,指向虚函数表.即虚函数表不是函数,不是程序代码,不肯能存储在代码段. 257 | 3.虚函数表存储虚函数的地址,即虚函数表的元素是指向类成员函数的指针,而类中虚函数的个数在编译时期可以确定. 258 | 即虚函数表的大小可以确定,即大小是在编译时期确定的,不必动态分配内存空间存储虚函数表,所以不再堆中. 259 | 根据以上特征,虚函数表类似于类中静态成员变量.静态成员变量也是全局共享,大小确定. 260 | 所以我推测虚函数表和静态成员变量一样,存放在全局区(静态区). 261 | ``` 262 | ### 74.define和inline有什么区别? 263 | ``` 264 | 1:编译阶段: 265 | 宏define在预处理阶段完成;inline在编译阶段 266 | 2:类型安全检查: 267 | inline函数是函数:要做类型检查; 268 | 3:替换方式 269 | define字符串替换; 270 | inline是指嵌入代码,在编译过程中不单独产生代码,在调用函数的地方不是跳转, 271 | 而是把代码直接写到那里去,对于短小的函数比较实用,且安全可靠。 272 | ``` 273 | ### 75. volatile关键字作用: 274 | ``` 275 | volatile 关键字是一种类型修饰符,用它声明的类型变量表示可以被某些编译器未知的因素更改, 276 | 比如:操作系统、硬件或者其它线程等。遇到这个关键字声明的变量,编译器对访问该变量的代码就不再进行优化, 277 | 从而可以提供对特殊地址的稳定访问. 278 | 当要求使用 volatile 声明的变量的值的时候,系统总是重新从它所在的内存读取数据,即使它前面的指令刚刚从该处读取过数据。 279 | 而且读取的数据立刻被保存。 280 | ``` 281 | 282 | -------------------------------------------------------------------------------- /学习笔记/Crawler/爬虫进阶.md: -------------------------------------------------------------------------------- 1 | - 1.了解爬虫的基本原理及过程 2 | - 2.Requests+Xpath 实现通用爬虫套路 3 | - 3.了解非结构化数据的存储 4 | - 4.学习scrapy,搭建工程化爬虫 5 | - 5.学习数据库知识,应对大规模数据存储与提取 6 | - 6.掌握各种技巧,应对特殊网站的反爬措施 7 | - 7.分布式爬虫,实现大规模并发采集,提升效率 8 | -------------------------------------------------------------------------------- /学习笔记/DataBase/MySQL-Practices.md: -------------------------------------------------------------------------------- 1 | #### 已知有如下4张表: 2 | #### 学生表:`Student(s_id,s_name,s_birth,s_sex)` –学生编号,学生姓名, 出生年月,学生性别 3 | 4 | #### 课程表:`Course(c_id,c_name,t_id)` – –课程编号, 课程名称, 教师编号 5 | 6 | #### 教师表:`Teacher(t_id,t_name)` –教师编号,教师姓名 7 | 8 | #### 成绩表:`Score(s_id,c_id,s_s_score)` –学生编号,课程编号,分数 9 | 10 | #### 1、查询课程编号为“001”的课程比“002”的课程成绩高的所有学生的学号。 11 | 12 | 【解题思路】首先查询课程编号分别为001和002的所有学生的学号及其分数作为内嵌视图A和B,然后将A和B通过学号关联,过滤条件就是A的分数大于B的分数,最终SQL如下: 13 | ``` 14 | SELECT A.S_ID 15 | 16 | FROM(SELECT S_ID,S_SCORE FROM Score WHERE C_ID='001') A, 17 | 18 | (SELECT S_ID,S_SCORE FROM Score WHERE C_ID='002')B 19 | 20 | WHERE A.S_SCORE>B.S_SCORE 21 | 22 | AND A.S_ID=B.S_ID; 23 | 24 | ``` 25 | #### 2、查询平均成绩大于60分的学生的学号和平均成绩 26 | 【解题思路】通过Score表即可获取,按照Score表的S_ID分组后即可求出平均成绩,最后通过HAVING子句来过滤平均分大于60的学生: 27 | ``` 28 | select S_ID, avg(s_score) from Score group by S_ID having avg(s_score)>60; 29 | ``` 30 | 31 | #### 3、查询所有学生的学号、姓名、选课数、总成绩 32 | 【解题思路】学生姓名通过STUDENT表获取,成绩通过SC表获取,考察的是COUNT和GROUPBY函数,最终SQL如下: 33 | ``` 34 | select student.s_id,student.s_name,count(score.s_id),sum(score.s_score) 35 | from student 36 | join score 37 | on student.s_id=score.s_id 38 | group by student.s_id; 39 | 40 | ``` 41 | #### 4、查询姓“猴”的老师的个数 42 | 【解题思路】考察模糊查询 43 | ``` 44 | select count(T_ID) 45 | from teacher 46 | where t_name like '猴%'; 47 | ``` 48 | #### 5、查询没学过“猴子”老师课的学生的学号、姓名 49 | 【解题思路】首先查询学习过“猴子”老师课的学生的学号作为子查询,而“猴子”老师涉及到TEACHER表,TEACHER表要和学生有关联必须通过课程和成绩表。 50 | ``` 51 | select Student.S_ID, Student.S_name 52 | from Student 53 | where S_ID not in (select distinct(SCORE.S_ID) from SCORE,Course,Teacher 54 | where Score.C_ID=Course.C_ID AND teacher.T_ID=Course.T_ID AND Teahcer.T_name ='猴子'); 55 | ``` 56 | #### 6、查询学过“猴子”老师所教的所有课的同学的学号、姓名 57 | 【解题思路】题目说的是查询学过“猴子”老师所教的所有课的同学的学号、姓名,举个例子,比如“猴子”老师教过语文和数学,那么就得找出哪些同学同时学习了语文和数学这2门课程。 58 | ``` 59 | select S_ID,S_name 60 | from Student 61 | where S_ID in (select S_ID from SCORE ,Course ,Teacher 62 | where SCORE.C_ID=Course.C_ID and Teacher.T_ID=Course.T_ID 63 | and Teacher.T_name='猴子' group by S_ID 64 | having count(SCORE.C_ID)=(select count(C_ID) from Course,Teacher 65 | where Teacher.T_ID=Course.T_ID and T_name='猴子')); 66 | ``` 67 | #### 7、查询学过编号为“001”的课程并且也学过编号为“002”的课程的学生的学号、姓名. 68 | ``` 69 | select Student.S_ID,Student.S_name 70 | from Student,SCORE where Student.S_ID=SCORE.S_ID 71 | and SCORE.C_ID='001'and 72 | exists( Select * from SCORE as SCORE_2 where SCORE_2.S_ID=SCORE.S_ID and SCORE_2.C_ID='002'); 73 | ``` 74 | 75 | 76 | #### 8、查询课程编号为“002”的总成绩 77 | 【解题思路】考查SUM 函数 78 | ``` 79 | select sum(s_score) from SCORE where C_ID='002'; 80 | ``` 81 | 82 | #### 9、查询所有课程成绩小于60分的学生的学号、姓名 83 | ``` 84 | select S_ID, s_name 85 | from Student 86 | where s_id not in 87 | (select Student.s_id from Student, Score where s.s_id = Score.s_id and s_score>60); 88 | ``` 89 | 90 | #### 10、查询没有学全所有课的学生的学号、姓名 91 | 【解题思路】也就是学生学习的课程数小于总的课程数 92 | ``` 93 | select Student.s_id, Student.s_name 94 | from Student, Score 95 | where Student.s_id=Score.s_id 96 | group by Student.s_id, Student.s_name 97 | having count(c_id)<(select count(c_id) from Course); 98 | ``` 99 | 100 | #### 11、查询至少有一门课与学号为“1001”的学生所学课程相同的学生的学号和姓名 101 | 【解题思路】首先找出学号为1001的学生学习过的课程,然后根据这些课程号就可以找到有哪些学生学习过部分1001学生学习过的课程 102 | ``` 103 | select s_id, S_name 104 | from Student, SCORE 105 | where Student.s_id = Score.s_id 106 | and c_id in (select c_id from SCORE where s_id='1001'); 107 | ``` 108 | #### 12、查询和“1001”号同学所学课程完全相同的其他同学的学号 109 | 【解题思路】首先找出学号为1001的学生学习过的课程,然后根据这些课程号和所学课程总数就可以找到有哪些同学学习过和他一样的课程 110 | ``` 111 | select sno from Score 112 | where c_id in(select c_id from Score where sno='1001') 113 | group by sno 114 | having count(*)=(select count(*) from Score where sno='1001') 115 | ``` 116 | 117 | #### 13、把“SCORE”表中“猴子”老师教的课的成绩都更改为此课程的平均成绩 118 | 【解题思路】考察数据库更改操作。首先找到“猴子”老师教过哪些课程及其课程的平均成绩,然后根据课程号关联成绩表进行更新 119 | ``` 120 | Update Score Set S_score = (Select Avg(s2_S_score) From Score s2 Where s2.c_id=Score.c_id) 121 | Where c_id IN 122 | (Select c_id From Score cs INNER JOIN Teacher tc ON cs.t_id = tc.t_id WHERE t_name ='猴子'); 123 | ``` 124 | 125 | #### 14、查询和“1002”号的同学学习的课程完全相同的其他同学学号和姓名 126 | ``` 127 | select s_id from Score where c_id 128 | in (select c_id from Score where s_id='1002') 129 | group by s_id having count(*)= 130 | (select count(*) from Score where s_id='1002'); 131 | ``` 132 | 133 | #### 15、删除学习过“猴子”老师课的成绩表记录 134 | 【解题思路】 135 | ``` 136 | delect Score 137 | from Course, Teacher 138 | where Course.c_id=Score.c_id 139 | and Course.t_id=teacher.t_id 140 | and t_name='猴子'; 141 | ``` 142 | 143 | #### 16、向成绩表中插入一些记录这些记录要求符合以下条件:没有上过编号为“003”课程的学生的学号、编号为002的课程的平均成绩 144 | ``` 145 | Insert SCORE select S_ID,'002', 146 | (Select avg(s_score) from SCORE where C_ID='002') 147 | from Student where S_ID not in (Select S_ID from SCORE where C_ID='003'); 148 | ``` 149 | 150 | #### 17、按平均成绩从高到低显示所有学生的“数据库”(c_id='004')、“企业管理”(c_id='001')、“英语”(c_id='006')三门的课程成绩,按如下形式显示:学生ID,数据库,企业管理,英语,有效课程数,有效平均分select s_id as 学生ID, 151 | ``` 152 | select s_id from Student as 学生ID, 153 | (select s_score from Score where Score.s_id=t.s_id and c_id='004') as 数据库, 154 | (select s_score from Score where Score.s_id=t.s_id and c_id='001') as 企业管理, 155 | (select s_score from Score where Score.s_id=t.s_id and c_id='006') as 英语, 156 | count(*) as 有效课程数, avg(t.s_score) as 平局成绩 157 | from Score as t 158 | group by s_id 159 | order by avg(t.s_score) 160 | ``` 161 | #### 18、查询各科成绩最高和最低的分: 以如下的形式显示:课程ID,最高分,最低分 162 | ``` 163 | select L.c_id as 课程ID, L.s_score as 最高分, 164 | R.s_score as 最低分 from Score L, Score R 165 | where L.c_id = R.c_id 166 | and 167 | L.s_score = (select max(IL.s_score) from Score as IL, Student as IM where L.c_id=IL.c_id and IM.s_id=IL.s_id group by IL.c_id) 168 | and 169 | R.s_score = (select min(IR.s_score) from Score as IR where R.c_id = IR.c_id group by IR.c_id); 170 | ``` 171 | #### 19、按各科平均成绩从低到高和及格率的百分数从高到低排列,以如下形式显示:课程号 课程名 平均成绩 及格百分数 172 | ``` 173 | SELECT t.C_ID AS 课程号, 174 | max(Course.C_name )AS 课程名, 175 | isnull(AVG(s_score),0) AS 平均成绩, 176 | 100 * SUM(CASE WHEN isnull(s_score,0)>=60 THEN 1 ELSE 0 END)/COUNT(*) AS 及格百分数 177 | FROM SCORE T,Course 178 | where t.C_ID=Course.C_ID 179 | GROUP BY t.C_ID 180 | ORDER BY 100 * SUM(CASE WHEN isnull(s_score,0)>=60 THEN 1 ELSE 0 END)/COUNT(*) DESC; 181 | ``` 182 | #### 20、查询如下课程平均成绩和及格率的百分数(用1行显示),其中,企业管理为001,马克思为002,UML为003,数据库为004 183 | ``` 184 | 这个不做 185 | ``` 186 | #### 21、查询不同老师所教不同课程平均分从高到低显示,其中,教师ID,教师姓名,课程ID,平均成绩 187 | ``` 188 | SELECT max(Z.T_ID) AS 教师ID, 189 | MAX(Z.T_name) AS 教师姓名, 190 | C.C_ID AS 课程ID, 191 | AVG(S_score) AS 平均成绩 192 | FROM SCORE AS T,Course AS C ,Teacher AS Z 193 | where T.C_ID=C.C_ID and C.T_ID=Z.T_ID 194 | GROUP BY C.C_ID 195 | ORDER BY AVG(S_score) DESC; 196 | ``` 197 | #### 22、查询如下课程成绩第3名到第6名的学生成绩单,其中,企业管理为001,马克思为002,UML为003,数据库为004,以如下形式显示:学生ID 学生姓名 企业管理 马克思 UML 数据库 平均成绩 198 | ``` 199 | 这个不做 200 | ``` 201 | #### 23、使用分段[100-85],[85-70],[70-60],[<60]来统计各科成绩,分别统计各分数段人数:课程ID 和 课程名称 202 | ``` 203 | SELECT SCORE.C_ID as 课程ID, C_name as 课程名称, 204 | SUM(CASE WHEN s_score BETWEEN 85 AND 100 THEN 1 ELSE 0 END) AS [100 - 85] , 205 | SUM(CASE WHEN s_score BETWEEN 70 AND 85 THEN 1 ELSE 0 END) AS [85 - 70], 206 | SUM(CASE WHEN s_score BETWEEN 60 AND 70 THEN 1 ELSE 0 END) AS [70 - 60], 207 | SUM(CASE WHEN s_score < 60 THEN 1 ELSE 0 END) AS [ < 60] 208 | FROM SCORE,Course 209 | where SCORE.C_ID=Course.C_ID 210 | GROUP BY SCORE.C_ID,C_name; 211 | ``` 212 | #### 24、查询学生平均成绩及其名次 213 | ``` 214 | SELECT 1+(SELECT COUNT( distinct 平均成绩) FROM (SELECT S_ID,AVG(s_score) AS 平均成绩 FROM SCORE GROUP BY S_ID ) AS T1 215 | WHERE 平均成绩 > T2.平均成绩) as 名次, S_ID as 学生学号,平均成绩 216 | FROM (SELECT S_ID,AVG(s_score) as 学生ID, 平均成绩 FROM SCORE GROUP BY S_ID ) AS T2 217 | ORDER BY 平均成绩 desc; 218 | ``` 219 | #### 25、查询各科成绩前三名的记录(不考虑成绩并列情况) 220 | ``` 221 | SELECT t1.S_ID as 学生ID,t1.C_ID as 课程ID, S_score as 分数 222 | FROM SCORE t1 223 | WHERE s_score IN (SELECT TOP 3 s_score FROM SCORE WHERE t1.C_ID= C_ID ORDER BY s_score DESC) ; 224 | ``` 225 | #### 26、查询每门课程被选修的学生数 226 | ``` 227 | select c_id, count(s_id) from Score group by c_id; 228 | ``` 229 | #### 27、查询出只选修了一门课程的全部学生的学号和姓名 230 | ``` 231 | select Score.s_id, Student.s_name, count(c_id) as 选课数 232 | from Score,Student 233 | where Score.s_id =Student.s_id 234 | group by Score.s_id,Student.s_name 235 | having count(c_id)=1; 236 | ``` 237 | #### 28、查询男生、女生人数 238 | ``` 239 | select count(S_sex) as 男生人数 240 | from Student group by S_sex having S_sex='男'; 241 | select count(S_sex) as 女生人数 242 | from Student group by S_sex having S_sex='女'; 243 | ``` 244 | #### 29、查询姓“张”的学生名单 245 | ``` 246 | select s_name from Student where s_name like '张%'; 247 | ``` 248 | #### 30、查询同名同性学生名单并统计同名人数 249 | ``` 250 | select sanme,count(*) from Student 251 | group by s_name 252 | having count(*)>1; 253 | ``` 254 | #### 31、1981年出生的学生名单(注:Student表中s_birth列的类型是datetime) 255 | ``` 256 | select s_name, convert(char(11),DATEPART(year,s_birth)) as age 257 | from Student 258 | where convert(char(11),DATEPART(year,S_birth))='1981'; 259 | ``` 260 | #### 32、查询平均成绩大于85的所有学生的学号、姓名和平均成绩 261 | ``` 262 | select S_name,SCORE.S_ID ,avg(s_score) 263 | from Student,SCORE 264 | where Student.S_ID=SCORE.S_ID 265 | group by SCORE.S_ID,S_name 266 | having avg(s_score)>85; 267 | ``` 268 | #### 33、查询每门课程的平均成绩,结果按平均成绩升序排序,平均成绩相同时,按课程号降序排列 269 | ``` 270 | select C_ID, avg(s_score) 271 | from Score 272 | group by c_id 273 | order by avg(s_score), c_id desc; 274 | ``` 275 | #### 34、查询课程名称为“数据库”且分数低于60的学生姓名和分数 276 | ``` 277 | select s_name, isnull(s_score,0) 278 | from Student, Score ,Course 279 | where Score.s_id=Student.s_id 280 | and Score.c_id=Course.c_id and Course.c_name='数据库' and s_score<60; 281 | ``` 282 | #### 35、查询所有学生的选课情况 283 | ``` 284 | select Score.s_id,Score.c_id,s_name,c_name 285 | from Score,Student Course 286 | where Score.s_id=Student.s_id and Score.c_id=Course.c_id; 287 | ``` 288 | #### 36、查询任何一门课程成绩在70分以上的姓名、课程名称和分数 289 | ``` 290 | select distinct Student.s_id,Student.s_name,Score.c_id,Score.s_score 291 | from Student,Score 292 | where Score.s_score>=70 and Score.s_id=Student.s_id; 293 | ``` 294 | #### 37、查询不及格的课程并按课程号从大到小排列 295 | ``` 296 | select c_id from Score 297 | where s_score < 60 order by c_id desc; 298 | ``` 299 | #### 38、查询课程编号为003且课程成绩在80分以上的学生的学号和姓名 300 | ``` 301 | select Score.s_id,Student.s_name 302 | from Score,Student 303 | where Score.s_id=Student.s_id and s_score>80 and c_id='003'; 304 | ``` 305 | #### 39、查询选了课程的学生人数 306 | ``` 307 | select count(*) from Score; 308 | ``` 309 | #### 40、查询选修“猴子”老师所授课程的学生中成绩最高的学生姓名及其成绩 310 | ``` 311 | select Student.s_name,s_score 312 | from Student,Score,Course c, teacher 313 | where Student.s_id=Score.S_ID and Score.c_id=c.c_id 314 | and c.T_ID=teacher.T_ID 315 | and teacher.t_name='猴子' 316 | and Score.s_score=(select max(s_score) from Score where c_id=c.c_id); 317 | ``` 318 | #### 41、查询各个课程及相应的选修人数 319 | ``` 320 | select count(*) from Score group by c_id; 321 | ``` 322 | #### 42、查询有2门不同课程成绩相同的学生的学号、课程号、学生成绩 323 | ``` 324 | select distinct a.s_id,b.s_score 325 | from Score a ,Score b 326 | where a.s_score=b.s_score 327 | and a.c_id<>b.c_id; 328 | ``` 329 | #### 43、查询每门课程成绩最好的前两名 330 | ``` 331 | select t1.s_id as 学生ID,t1.c_id 课程ID, S_score as 分数 332 | from Score t1 333 | where s_score in (select top 2 s_score from Score 334 | where t1.c_id=c_id 335 | order by s_score desc)order by t1.c_id; 336 | ``` 337 | #### 44、统计每门课程的学生选修人数(超过10人的课程才统计)。要求输出课程号和选修人数,查询结果按人数降序排序,若人数相同,按课程号升序排序 338 | ``` 339 | select c_id as 课程号,count(*) as 人数 340 | from Score group by c_id 341 | order by count(*) desc c_id; 342 | ``` 343 | #### 45、查询至少选修两门课程的学生学号 344 | ``` 345 | select s_id 346 | from Score 347 | group by s_id having count(*)>=2; 348 | ``` 349 | #### 46、查询全部学生都选修的课程的课程号和课程名 350 | ``` 351 | select c_id ,c_name 352 | from Course 353 | where c_id in (select c_id from Score group by c_id); 354 | ``` 355 | #### 47、查询没学过“猴子”老师讲授的任一门课程的学生姓名 356 | ``` 357 | select s_name 358 | from Student 359 | where s_id not in (select s_id from Course,teacher,Score 360 | where Course.t_id=teacher.t_id and Score.c_id=Course.c_id 361 | and t_name='猴子'); 362 | ``` 363 | #### 48、查询两门以上不及格课程的同学的学号及其平均成绩 364 | ``` 365 | select s_id,avg(isnull(s_score,0)) 366 | from Score 367 | where s_id in (select s_id from Score 368 | where s_score<60 group by s_id having count(*)>2) 369 | group by s_id; 370 | ``` 371 | #### 49、检索课程编号为“004”且分数小于60的学生学号,结果按按分数降序排列 372 | ``` 373 | select s_id 374 | from Score 375 | where c_id='004' and s_score<60 376 | order by s_score desc; 377 | ``` 378 | #### 50、删除学生编号为“002”的课程编号为“001”的成绩 379 | ``` 380 | delect from Score where s_id='002' and c_id='001'; 381 | ``` 382 | 383 | 384 | -------------------------------------------------------------------------------- /学习笔记/DataBase/面试题(1 - 25).md: -------------------------------------------------------------------------------- 1 | ### 1. Mysql数据库隔离级别 2 | ``` 3 | MySQL数据库为我们提供的四种隔离级别: 4 | 1.Serializable (串行化):可避免脏读、不可重复读、幻读的发生。 5 | 2.Repeatable read (可重复读):可避免脏读、不可重复读的发生。 6 | 3.Read committed (读已提交):可避免脏读的发生。 7 | 4.Read uncommitted (读未提交):最低级别,任何情况都无法保证。 8 | ``` 9 | ### 2. 乐观锁与悲观锁原理及实现 10 | ``` 11 | 乐观锁:总是认为不会产生并发问题,每次去取数据的时候总认为不会有其他线程对数据进行修改,因此不会上锁, 12 | 但是在更新时会判断其他线程在这之前有没有对数据进行修改,一般会使用版本号机制或CAS操作实现。 13 | ``` 14 | ``` 15 | version方式:一般是在数据表中加上一个数据版本号version字段,表示数据被修改的次数,当数据被修改时,version值会加一。 16 | 当线程A要更新数据值时,在读取数据的同时也会读取version值,在提交更新时, 17 | 若刚才读取到的version值为当前数据库中的version值相等时才更新,否则重试更新操作,直到更新成功。 18 | ``` 19 | ##### 核心SQL代码: 20 | ``` 21 | update table set x=x+1, version=version+1 where id=#{id} and version=#{version}; 22 | ``` 23 | ``` 24 | CAS操作方式:即compare and swap 或者 compare and set,涉及到三个操作数,数据所在的内存值,预期值,新值。 25 | 当需要更新时,判断当前内存值与之前取到的值是否相等,若相等,则用新值更新. 26 | 若失败则重试,一般情况下是一个自旋操作,即不断的重试。 27 | ``` 28 | ``` 29 | 悲观锁:总是假设最坏的情况,每次取数据时都认为其他线程会修改,所以都会加锁(读锁、写锁、行锁等), 30 | 当其他线程想要访问数据时,都需要阻塞挂起。 31 | 可以依靠数据库实现,如行锁、读锁和写锁等,都是在操作之前加锁. 32 | 在Java中,synchronized的思想也是悲观锁。 33 | ``` 34 | ### 3. SQL的四种连接-左外连接、右外连接、内连接、全连接? 35 | [深入理解SQL的四种连接-左外连接、右外连接、内连接、全连接](https://www.cnblogs.com/yyjie/p/7788413.html) 36 | 37 | ### 4. innodb和myisam的区别 38 | [mysql中engine=innodb和engine=myisam的区别](https://www.cnblogs.com/avivahe/p/5427884.html) 39 | 40 | ### 5.drop, truncate和delete的区别是什么? 41 | ``` 42 | 当你不再需要该表时, 用 drop; 43 | 当你仍要保留该表,但要删除所有记录时, 用 truncate; 44 | 当你要删除部分记录时(always with a WHERE clause), 用 delete. 45 | ``` 46 | 47 | -------------------------------------------------------------------------------- /学习笔记/Docker/Docker_Run参数详解.md: -------------------------------------------------------------------------------- 1 | #### Usage: docker run [OPTIONS] IMAGE [COMMAND] [ARG...] 2 | 3 | |OPTIONS|COMMAND| 4 | |------:|---:| 5 | | -d, --detach=false | 指定容器运行于前台还是后台,默认为false 6 | | -i, --interactive=false | 打开STDIN,用于控制台交互 | 7 | | -t, --tty=false | 分配tty设备,该可以支持终端登录,默认为false | 8 | | -u, --user="" | 指定容器的用户 | 9 | | -a, --attach=[] | 登录容器(必须是以docker run -d启动的容器)| 10 | | -w, --workdir="" | 指定容器的工作目录 | 11 | | -c, --cpu-shares=0 | 设置容器CPU权重,在CPU共享场景使用 | 12 | | -e, --env=[] | 指定环境变量,容器中可以使用该环境变量 | 13 | | -m, --memory="" | 指定容器的内存上限 | 14 | | -P, --publish-all=false | 指定容器暴露的端口 | 15 | | -p, --publish=[] | 指定容器暴露的端口 | 16 | | -h, --hostname="" | 指定容器的主机名 | 17 | | -v, --volume=[] | 给容器挂载存储卷,挂载到容器的某个目录 | 18 | | --volumes-from=[] | 给容器挂载其他容器上的卷,挂载到容器的某个目录| 19 | | --cap-add=[] | 添加权限,权限清单详见:http://linux.die.net/man/7/capabilities | 20 | | --cap-drop=[] | 删除权限,权限清单详见:http://linux.die.net/man/7/capabilities 21 | | --cidfile="" | 运行容器后,在指定文件中写入容器PID值,一种典型的监控系统用法 | 22 | | --cpuset="" | 设置容器可以使用哪些CPU,此参数可以用来容器独占CPU | 23 | | --device=[] | 添加主机设备给容器,相当于设备直通 | 24 | | --dns=[] | 指定容器的dns服务器 | 25 | | --dns-search=[] | 指定容器的dns搜索域名,写入到容器的/etc/resolv.conf文件 | 26 | | --entrypoint="" | 覆盖image的入口点 | 27 | | --env-file=[] | 指定环境变量文件,文件格式为每行一个环境变量 | 28 | | --expose=[] | 指定容器暴露的端口,即修改镜像的暴露端口 | 29 | | --link=[] | 指定容器间的关联,使用其他容器的IP、env等信息 | 30 | | --lxc-conf=[] | 指定容器的配置文件,只有在指定--exec-driver=lxc时使用 | 31 | | --name="" | 指定容器名字,后续可以通过名字进行容器管理; links特性需要使用名字: container:NAME_or_ID >//使用其他容器的网路,共享IP和PORT等网络资源; none: 容器使用自己的网络(类似--net=bridge),但是不进行配置 | 32 | | --privileged=false | 指定容器是否为特权容器,特权容器拥有所有的capabilities | 33 | | --restart="no" | 指定容器停止后的重启策略: no:容器退出时不重启; on-failure:容器故障退出(返回值非零)时重启; always:容器退出时总是重启 | 34 | | --rm=false | 指定容器停止后自动删除容器(不支持以docker run -d启动的容器) | 35 | | --sig-proxy=true | 设置由代理接受并处理信号,但是SIGCHLD、SIGSTOP和SIGKILL不能被代理| 36 | -------------------------------------------------------------------------------- /学习笔记/Docker/Docker用途.md: -------------------------------------------------------------------------------- 1 | ## Docker用途 2 | #### Docker 的主要用途,目前有三大类。 3 | (1)**提供一次性的环境。** 4 | #### 比如,本地测试他人的软件、持续集成的时候提供单元测试和构建的环境。 5 | (2)**提供弹性的云服务。** 6 | #### 因为 Docker 容器可以随开随关,很适合动态扩容和缩容。 7 | (3)**组建微服务架构。** 8 | #### 通过多个容器,一台机器可以跑多个服务,因此在本机就可以模拟出微服务架构。 9 | -------------------------------------------------------------------------------- /学习笔记/Docker/docker 指定 cpu.md: -------------------------------------------------------------------------------- 1 | ### 指定容器cpu个数,--cpus=2 表示容器最多可以使用主机上两个 CPU: 2 | ``` 3 | docker run -it --rm --cpus=2 ubuntu:latest /bin/bash 4 | ``` 5 | 6 | ### 指定容器cpu个数和编号: 7 | ``` 8 | docker run -it --rm --cpuset-cpus="1,3" ubuntu:latest /bin/bash 9 | ``` 10 | -------------------------------------------------------------------------------- /学习笔记/Docker/docker.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzyrapx/Notes/9d7665195e6ae4807f9b77edb529f3a35e768542/学习笔记/Docker/docker.png -------------------------------------------------------------------------------- /学习笔记/Docker/virtual-machines.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzyrapx/Notes/9d7665195e6ae4807f9b77edb529f3a35e768542/学习笔记/Docker/virtual-machines.png -------------------------------------------------------------------------------- /学习笔记/Docker/什么是docker.md: -------------------------------------------------------------------------------- 1 | ## 什么是docker? 2 | 3 | #### IT软件中,Docker指容器化技术,用于支持创建和使用Linux容器。Docker 在容器的基础上,进行了进一步的封装,从文件系统、网络互联到进程隔离等等,极大的简化了容器的创建和维护。使得 Docker 技术比虚拟机技术更为轻便、快捷。 4 | 5 | #### 虚拟机运行另一个操作系统,占用资源多,需要分配内存和硬盘,冗余,启动慢。而Linux 容器不是模拟一个完整的操作系统,而是对进程进行隔离。具有启动快,占用资源少,体积小,便于迁移等优点。 6 | 7 | #### Docker 属于 Linux 容器的一种封装,提供简单易用的容器使用接口。 它是目前最流行的 Linux 容器解决方案。 8 | 9 | #### Docker 将应用程序与该程序的依赖,打包在一个文件里面。运行这个文件,就会生成一个虚拟容器。程序在这个虚拟容器里运行,就好像在真实的物理机上运行一样。有了 Docker,就不用担心环境问题。 10 | 11 | #### 总体来说,Docker 的接口相当简单,用户可以方便地创建和使用容器,把自己的应用放入容器。容器还可以进行版本管理、复制、分享、修改,就像管理普通的代码一样。 12 | ![virtual-machines](https://github.com/LzyRapx/Notes/blob/master/Docker/virtual-machines.png) 13 | ![docker](https://github.com/LzyRapx/Notes/blob/master/Docker/docker.png) 14 | -------------------------------------------------------------------------------- /学习笔记/Github/Fork 更新同步.md: -------------------------------------------------------------------------------- 1 | #### 1. github fork 别人的项目源作者更新后如何同步更新 2 | ``` 3 | https://blog.csdn.net/zhongzunfa/article/details/80344585 4 | ``` 5 | -------------------------------------------------------------------------------- /学习笔记/Github/github基本使用.md: -------------------------------------------------------------------------------- 1 | 1.首先让自己本地的`ssh`私钥和`github`上的私钥一致: 2 | 本地没有私钥就通过:`ssh-keygen`命令生成`ssh`私钥 3 | 然后需要你`Enter passphrase`,直接不断按【Enter】就可以了。 4 | 然后会显示: 5 | ``` 6 | The key's randomart image is: 7 | +---[RSA 2048]----+ 8 | | x... | 9 | | o..o . | 10 | |oo. . . | 11 | |ooo o.o.. | 12 | |xx . S+== | 13 | |xx | 14 | |xx | 15 | |oxx | 16 | | . .o .*+ | 17 | +----[SHA256]-----+ 18 | ``` 19 | 这样就成功了。 20 | 21 | 2.然后执行 :`cat ~/.ssh/id_rsa.pub` 命令,查看`ssh`私钥,复制粘贴到`github`的`ssh-key`设置里就行了。 22 | 23 | 3.然后在本地:`git clone`【项目ssh地址】 24 | 25 | 4.进入刚`clone`下来的项目里, 然后你更新项目后。。。想也更新上`github`. 26 | 27 | 5.在项目里面执行以下命令: 28 | 29 | (1)`git config --global user.name "github用户名"` 30 | 31 | (2) `git config --global user.email "注册邮箱"` 32 | 33 | (3) `git init` 34 | 35 | (4) `git add 文件名 或者 git add -A` 36 | 37 | (5) `git status (查看状态)` 38 | 39 | (6) `git commit -m "改动评论"` 40 | 41 | (6) `git remote add origin 项目ssh地址` 42 | 43 | (如果出现`fatal: remote origin already exists.`就执行 `git remote rm origin`, 再重新执行(6)) 44 | 45 | (7) `git push -u orgin master` 46 | (报错 47 | fatal: 'orgin' does not appear to be a git repository 48 | fatal: Could not read from remote repository. 49 | 50 | Please make sure you have the correct access rights 51 | and the repository exists. 52 | 就直接执行:`git push` 或者 ` git push --set-upstream origin master`) 53 | 54 | 但使用一些git的操作仍然需要输入账号和密码,这需要:`git config --global credential.helper store` 55 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /学习笔记/Github/提交PR.md: -------------------------------------------------------------------------------- 1 | - fork 到自己的仓库 2 | 3 | `git clone 到本地(克隆自己fork的)` 4 | 5 | - 上游建立连接 6 | 7 | `git remote add upstream 开源项目地址` 8 | 9 | - 创建开发分支 (非必须) 10 | 11 | `git checkout -b dev` 12 | 13 | - 修改提交代码 14 | 15 | `git status ` 16 | 17 | `git add . ` 18 | 19 | `git commit -m “xxx”` 20 | 21 | `git push origin xxx` 22 | 23 | - 同步代码三部曲 24 | 25 | `git fetch upstream` 26 | 27 | `git rebase upstream/master` 28 | 29 | `git push origin master` 30 | 31 | 或者: 32 | 33 | ``` 34 | git remote -v 35 | 36 | git remote add upstream git@github.com:xxx/xxx.git 37 | 38 | git fetch upstream 39 | 40 | git merge upstream/master 41 | 42 | git push 43 | ``` 44 | - 提交pr 45 | 46 | `去自己github仓库对应fork的项目下 new pull request` 47 | 48 | --- 49 | https://blog.csdn.net/vim_wj/article/details/78300239 50 | -------------------------------------------------------------------------------- /学习笔记/IQ/智力题.md: -------------------------------------------------------------------------------- 1 | ### 1.吃豆子过桥问题 2 | [吃豆子过桥问题](https://blog.csdn.net/yjf3151731373/article/details/52180371) 3 | ``` 4 | #include 5 | 6 | using namespace std; 7 | 8 | // f(n,m) = f(n - 1, m) + 2 * T + 1 (T表示往返次数), 其中 T = ceil( f(n-1,m)-(m-1)) / (m-2) ) 9 | // f(n-1,m) + ceil( f(n-1,m)-(m-1)) / (m-2) ) * 2+ 1 10 | // = f(n-1,m) + ( f(n-1,m) - 2) / (m-2) ) * 2 + 1 (len < max_num) 11 | 12 | int get_min_num(int len, int max_num) { 13 | if(len <= max_num){ 14 | return len; 15 | } 16 | int ans = max_num; 17 | for(int i = max_num; i < len; i++) { 18 | ans = ans + ((ans - 2) / (max_num - 2) ) * 2 + 1; 19 | } 20 | return ans; 21 | } 22 | // 原点有无数豆子, 可以放豆子,可以折返,有最大可带豆子数 23 | int main(int argc, char const *argv[]) { 24 | int max_num = 0; 25 | int len = 0; 26 | // len 为路的长度, max_num 为最大可带的豆子数 27 | std::cin >> len >> max_num; 28 | std::cout << get_min_num(len , max_num) << '\n'; // 最少需要吃多少颗豆子才能走完路 29 | return 0; 30 | } 31 | 32 | ``` 33 | ### 2.有12个球,称3次找出那个异常球,并判断轻重? 34 | ``` 35 | 首先,把12个小球分成三等份,每份四只。 36 | 拿出其中两份放到天平两侧称(第一次) 37 | 38 | 情况一:天平是平衡的。 39 | 那么那八个拿上去称的小球都是正常的,特殊的在四个里面。 40 | 把剩下四个小球拿出三个放到一边,另一边放三个正常的小球(第二次) 41 | 如天平平衡,特殊的是剩下那个。 42 | 如果不平衡,在天平上面的那三个里。而且知道是重了还是轻了。 43 | 剩下三个中拿两个来称,因为已经知道重轻,所以就可以知道特殊的了。(第三次) 44 | 45 | 情况二:天平倾斜。 46 | 特殊的小球在天平的那八个里面。 47 | 把重的一侧四个球记为A1A2A3A4,轻的记为B1B2B3B4。 48 | 剩下的确定为四个正常的记为C。 49 | 把A1B2B3B4放到一边,B1和三个正常的C小球放一边。(第二次) 50 | 51 | 情况一:天平平衡了。 52 | 特殊小球在A2A3A4里面,而且知道特殊小球比较重。 53 | 把A2A3称一下,就知道三个里面哪个是特殊的了。(第三次) 54 | 55 | 情况二:天平依然是A1的那边比较重。 56 | 特殊的小球在A1和B1之间。 57 | 随便拿一个和正常的称,就知道哪个特殊了。(第三次) 58 | 59 | 情况三:天平反过来,B1那边比较重了。 60 | 特殊小球在B2B3B4中间,而且知道特殊小球比较轻。 61 | 把B2B3称一下,就知道哪个是特殊的了。(第三次) 62 | 63 | ``` 64 | -------------------------------------------------------------------------------- /学习笔记/Inter-algo/算法面试题.md: -------------------------------------------------------------------------------- 1 | #### 1. 给你一个数组, 保证递增, 首先找到一个数字k, 然后找到最靠近这个数字k的m个数, m可能很大(几百万), 比如 1 3 5 7 8 10, 首先找到数字5, 最靠近它的两个数是3和7. 2 | ``` 3 | 1.维护一个堆 4 | 2.参考一下算法导论上求最靠近中位数k的m个数. 5 | ``` 6 | #### 2.你有很多关键词, 但是内存能存下这么多关键词. 现在发表一条评论, 要求判断有没有包含关键词? 7 | ``` 8 | 1.字典树,关键词不会太长而且相同前缀短,匹配的时候跑一下评论的所有后缀. 9 | 2.AC自动机 10 | ``` 11 | #### 3.给你一个数组, 数组中第i个数值是num[i], 表示从当前位置i最多能跳num[i]步, 判断是否能到达最后一个数字并且求出最小跳数? 12 | ``` 13 | dp. 14 | class Solution { 15 | public: 16 | int jump(int A[], int n) { 17 | vector dp; // dp[i]表示到点 i 的最小步数 18 | for(int i = 0; i < n; i++) 19 | { 20 | int maxp = min(i+A[i],n-1); // 从 i 出发能走到的最远距离 21 | for (int j = i + 1; j <= maxp; j ++) { 22 | if(dp[j] == 0 || dp[j] > dp[i]+1) 23 | dp[j] = dp[i] + 1; // 如果位置没被走过,或者可以用更少步数到达,则到达j点的步数为dp[i]+1 24 | } 25 | } 26 | return dp[n-1]; 27 | } 28 | }; 29 | ``` 30 | #### 4. 手写一个LRU, 各个细节讲清楚. 31 | [Leetcode 146. LRU Cache](https://leetcode.com/problems/lru-cache/description/) 32 | ``` 33 | // 使用map和list实现的LRU。 实现了get和put操作 34 | // 最近最少使用算法:如果数据最近被访问过,那么将来被访问的几率也更高 35 | class LRUCache { 36 | private: 37 | // 当缓存满了的时候,要移除list的最后一个,同时还要移除map中对应的那个key 38 | // 所以list要保存list到map的映射关系key,不能只保存value 39 | list> lis; 40 | // key, value 41 | // value存储的是一个迭代器 42 | // 它指明了key在list中的位置,这样我们就不需要使用find函数来寻找key,这种做法能够降低时间复杂度 43 | map >::iterator> mp; 44 | int cap; 45 | public: 46 | LRUCache(int capacity) { 47 | cap = capacity; 48 | } 49 | 50 | int get(int key) { // get 得到对应的value,并将其移到队列首 51 | int val = -1; 52 | if(mp.count(key)) { 53 | val = mp[key] -> second; 54 | put(key,val); 55 | } 56 | return val; 57 | } 58 | // put:要移除很久未使用的map 59 | // 如果不存在:队列首加入,此时根据容量可能会挤掉尾元素。如存在:移动到队列首。 60 | void put(int key, int value) { 61 | if(mp.count(key)) { // 存在缓存, 之前的就不要了 62 | lis.erase(mp[key]); 63 | } 64 | else if(lis.size() == cap) { 65 | mp.erase(lis.back().first); 66 | lis.pop_back(); 67 | } 68 | lis.push_front(make_pair(key,value)); 69 | mp[key] = lis.begin(); 70 | } 71 | }; 72 | 73 | /** 74 | * Your LRUCache object will be instantiated and called as such: 75 | * LRUCache obj = new LRUCache(capacity); 76 | * int param_1 = obj.get(key); 77 | * obj.put(key,value); 78 | */ 79 | ``` 80 | #### 5.给出n个数, 数值是1~n, 然后给你m个关系 a-b, 表示a和b有关系, 你现在需要选出k个数, 判断是否能选出. 对于有关系的数a-b, 要么全选要么全不选. 比如有关系 a-b, b-c, 很显然 a b c三个数要么全选要么全不选? 81 | ``` 82 | 如果只query一次的话dfs找联通分量就行了,否则使用带size的并查集+背包. 83 | ``` 84 | #### 6.手写一个LFU. 85 | [460. LFU Cache](https://leetcode.com/problems/lfu-cache/description/) 86 | ``` 87 | // 最不经常使用算法 88 | // 如果数据过去被访问多次,那么将来被访问的频率也更高. 89 | // minFreq is the smallest frequency so far 90 | // The main idea is to put all keys with the same frequency to a linked list so the most recent one can be evicted; 91 | // mp_ptr stored the key's position in the linked list; 92 | class LFUCache { 93 | public: 94 | int minFreq = 0; // 记录最小访问频率记录 95 | unordered_map>mp; // value: {value, freq}, 有序 96 | unordered_map::iterator> mp_ptr; // value : list iterator。存list的迭代器,有序 97 | unordered_map > mp_freq; // value : list 记录访问频率,有序 98 | 99 | int cap = 0; 100 | int cur_size = 0; 101 | LFUCache(int capacity) { 102 | cap = capacity; 103 | cur_size = 0; 104 | } 105 | // Get the value (will always be positive) of the key if the key exists in the cache, otherwise return -1. 106 | int get(int key) { 107 | if(mp.count(key) == 0) return -1; 108 | 109 | mp_freq[mp[key].second].erase(mp_ptr[key]); // 移除已经存在的list 110 | 111 | mp[key].second ++; // 访问频率 + 1 112 | 113 | mp_freq[mp[key].second].push_back(key); // 更新key访问频率 114 | 115 | mp_ptr[key] = (--mp_freq[mp[key].second].end()); // 更新迭代器 116 | 117 | if(mp_freq[minFreq].size() == 0) minFreq++; 118 | 119 | return mp[key].first; 120 | } 121 | // Set or insert the value if the key is not already present. 122 | // When the cache reaches its capacity, it should invalidate the least frequently used item before inserting a new item. 123 | // For the purpose of this problem, when there is a tie (i.e., two or more keys that have the same frequency), 124 | // the least recently used key would be evicted. 125 | void put(int key, int value) { 126 | if(cap <= 0) return; 127 | 128 | int exist = get(key); 129 | if(exist != -1) { 130 | mp[key].first = value; 131 | return; 132 | } 133 | 134 | while(cur_size >= cap) { // 当前容量大于或等于规定容量时 135 | mp.erase( mp_freq[minFreq].front() ); 136 | mp_ptr.erase( mp_freq[minFreq].front() ); 137 | mp_freq[minFreq].pop_front(); 138 | cur_size --; 139 | } 140 | mp[key] = make_pair(value, 1); 141 | mp_freq[1].push_back(key); 142 | mp_ptr[key] = (--mp_freq[1].end()); 143 | 144 | minFreq = 1; 145 | cur_size ++; 146 | } 147 | }; 148 | 149 | /** 150 | * Your LFUCache object will be instantiated and called as such: 151 | * LFUCache obj = new LFUCache(capacity); 152 | * int param_1 = obj.get(key); 153 | * obj.put(key,value); 154 | */ 155 | ``` 156 | -------------------------------------------------------------------------------- /学习笔记/K8S/Kubernetes.in.Action.2017.12.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzyrapx/Notes/9d7665195e6ae4807f9b77edb529f3a35e768542/学习笔记/K8S/Kubernetes.in.Action.2017.12.pdf -------------------------------------------------------------------------------- /学习笔记/K8S/README.md: -------------------------------------------------------------------------------- 1 | ### 文档: 2 | #### http://docs.kubernetes.org.cn/ 3 | #### https://www.kubernetes.org.cn/docs 4 | 5 | ### 1.Kubernetes集群中移除Node: 6 | 在master节点上执行: 7 | ``` 8 | kubectl drain xxx --delete-local-data --force --ignore-daemonsets 9 | kubectl delete node xxx 10 | ``` 11 | 12 | -------------------------------------------------------------------------------- /学习笔记/K8S/picture/1: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /学习笔记/K8S/picture/dashboard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzyrapx/Notes/9d7665195e6ae4807f9b77edb529f3a35e768542/学习笔记/K8S/picture/dashboard.png -------------------------------------------------------------------------------- /学习笔记/K8S/picture/dashboard_login.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzyrapx/Notes/9d7665195e6ae4807f9b77edb529f3a35e768542/学习笔记/K8S/picture/dashboard_login.png -------------------------------------------------------------------------------- /学习笔记/K8S/第一天-kubeadm安装k8s.md: -------------------------------------------------------------------------------- 1 | ## 说明 2 | - 初步接触`kubernets`,记录学习过程 3 | - 本教程目的利用`kubeadm`在`ubuntu server 16.04 64`位系统离线安装`kubernets v1.10.0` 4 | 5 | ## 环境信息 6 | 7 | 节点IP地址|角色 8 | -- |-- 9 | 192.168.1.196|master(管理节点) 10 | 192.168.1.197|worker(计算节点) 11 | 12 | 13 | ## 安装软件 14 | 以下操作需要在所有的`master`和`worker`节点上执行 15 | 1. 安装以下依赖,命令:`dpkg -i *.deb` 16 | 17 | ```sh 18 | root@k8s-master-01:/home/zcs/dep# ls -lh 19 | total 6.1M 20 | -rw-r--r-- 1 root root 78K Jun 1 2017 ebtables_2.0.10.4-3.4ubuntu2_amd64.deb 21 | -rw-r--r-- 1 root root 5.7M Mar 29 17:06 kubernetes-cni_0.6.0-00_amd64.deb 22 | -rw-r--r-- 1 root root 38K Feb 8 2016 libltdl7_2.4.6-0.1_amd64.deb 23 | -rw-r--r-- 1 root root 314K Feb 3 2016 socat_1.7.3.1-1_amd64.deb 24 | root@k8s-master-01:/home/zcs/deb# dpkg -i *.deb 25 | ``` 26 | 27 | 2. 安装`docker`,`kubeadm`,`kubectl`,`kubelet`,命令:`dpkg -i *.deb` 28 | 29 | ```sh 30 | root@k8s-master-01:/home/zcs/deb# ls -lh 31 | total 67M 32 | -rw-r--r-- 1 root root 19M Jun 28 2017 docker-ce_17.03.2~ce-0~ubuntu-xenial_amd64.deb 33 | -rw-r--r-- 1 root root 20M Mar 29 17:04 kubeadm_1.10.0-00_amd64.deb 34 | -rw-r--r-- 1 root root 8.5M Mar 29 17:04 kubectl_1.10.0-00_amd64.deb 35 | -rw-r--r-- 1 root root 21M Mar 29 17:05 kubelet_1.10.0-00_amd64.deb 36 | root@k8s-master-01:/home/zcs/deb# dpkg -i *.deb 37 | ``` 38 | 39 | - `kubernets`官方说支持`docker`到`17.03`,高于此版本的未测试,可能出现问题 40 | 41 | - 不同的操作系统依赖可能不一样,如果有缺少依赖的情况,可以使用 `apt-get -f install` 命令修复依赖(需要联网) 42 | 43 | 3. 导入以下镜像,`for images in $(ls | grep img); do docker load < $images;done` 44 | 45 | ``` sh 46 | root@k8s-master-01:/home/zcs# ls -lh|grep img 47 | -rw-r--r-- 1 root root 15M Apr 2 21:48 k8s-dns-kube-dns-amd64_1.14.9.img 48 | -rw-r--r-- 1 root root 185M Mar 30 14:01 k8s.gcr.io_etcd-amd64_3.1.12.img 49 | -rw-r--r-- 1 root root 40M Mar 30 14:01 k8s.gcr.io_k8s-dns-dnsmasq-nanny-amd64_1.14.8.img 50 | -rw-r--r-- 1 root root 49M Mar 30 14:01 k8s.gcr.io_k8s-dns-kube-dns-amd64_1.14.8.img 51 | -rw-r--r-- 1 root root 41M Mar 30 14:01 k8s.gcr.io_k8s-dns-sidecar-amd64_1.14.8.img 52 | -rw-r--r-- 1 root root 215M Mar 30 14:01 k8s.gcr.io_kube-apiserver-amd64_v1.10.0.img 53 | -rw-r--r-- 1 root root 142M Mar 30 14:01 k8s.gcr.io_kube-controller-manager-amd64_v1.10.0.img 54 | -rw-r--r-- 1 root root 95M Mar 30 14:01 k8s.gcr.io_kube-proxy-amd64_v1.10.0.img 55 | -rw-r--r-- 1 root root 99M Mar 30 14:01 k8s.gcr.io_kubernetes-dashboard-amd64_v1.8.3.img 56 | -rw-r--r-- 1 root root 49M Mar 30 14:01 k8s.gcr.io_kube-scheduler-amd64_v1.10.0.img 57 | -rw-r--r-- 1 root root 737K Mar 30 14:01 k8s.gcr.io_pause-amd64_3.1.img 58 | -rw-r--r-- 1 root root 67M Mar 30 14:01 quay.io_calico_cni_v2.0.3.img 59 | -rw-r--r-- 1 root root 53M Mar 30 14:01 quay.io_calico_kube-controllers_v2.0.2.img 60 | -rw-r--r-- 1 root root 266M Mar 30 14:01 quay.io_calico_node_v3.0.4.img 61 | -rw-r--r-- 1 root root 34M Apr 3 17:12 quay.io_coreos_etcd-v3.1.10.img 62 | root@k8s-master-01:/home/zcs# for images in $(ls | grep img); do docker load < $images;done 63 | · 64 | · 65 | · 66 | root@k8s-master-01:/home/zcs# docker images 67 | REPOSITORY TAG IMAGE ID CREATED SIZE 68 | quay.io/calico/node v3.0.4 5361c5a52912 6 days ago 278 MB 69 | k8s.gcr.io/kube-proxy-amd64 v1.10.0 bfc21aadc7d3 8 days ago 97 MB 70 | k8s.gcr.io/kube-scheduler-amd64 v1.10.0 704ba848e69a 8 days ago 50.4 MB 71 | k8s.gcr.io/kube-controller-manager-amd64 v1.10.0 ad86dbed1555 8 days ago 148 MB 72 | k8s.gcr.io/kube-apiserver-amd64 v1.10.0 af20925d51a3 8 days ago 225 MB 73 | quay.io/calico/kube-controllers v2.0.2 0754e1c707e7 13 days ago 55.1 MB 74 | quay.io/calico/cni v2.0.3 cef0252b1749 13 days ago 69.1 MB 75 | k8s.gcr.io/etcd-amd64 3.1.12 52920ad46f5b 3 weeks ago 193 MB 76 | k8s.gcr.io/kubernetes-dashboard-amd64 v1.8.3 0c60bcf89900 7 weeks ago 102 MB 77 | k8s.gcr.io/k8s-dns-dnsmasq-nanny-amd64 1.14.8 c2ce1ffb51ed 2 months ago 41 MB 78 | k8s.gcr.io/k8s-dns-sidecar-amd64 1.14.8 6f7f2dc7fab5 2 months ago 42.2 MB 79 | k8s.gcr.io/k8s-dns-kube-dns-amd64 1.14.8 80cc5ea4b547 2 months ago 50.5 MB 80 | k8s.gcr.io/pause-amd64 3.1 da86e6ba6ca1 3 months ago 742 kB 81 | quay.io/coreos/etcd v3.1.10 47bb9dd99916 8 months ago 34.6 MB 82 | ``` 83 | 84 | ## 宿主机设置 85 | 以下操作需要在所有的`master`和`worker`节点上执行 86 | 1. 设置hostname 87 | 88 | ``` sh 89 | root@k8s-master-01:/home/zcs# hostname k8s-master-01 90 | root@k8s-master-01:/home/zcs# echo "k8s-master-01" > /etc/hostname 91 | ``` 92 | 93 | - 推荐修改成容易识别的主机名,方便管理 94 | 95 | 2. 关闭swap 96 | 97 | ``` sh 98 | root@k8s-master-01:/home/zcs# swapoff -a 99 | root@k8s-master-01:/home/zcs# sed -i 's/^\(.*swap.*$\)/#\1/' /etc/fstab 100 | ``` 101 | 102 | 3. 设置hosts 103 | 104 | ``` sh 105 | root@k8s-master-01:/home/zcs# echo "192.168.1.196 k8s-master-01" >> /etc/hosts 106 | root@k8s-master-01:/home/zcs# echo "192.168.1.197 k8s-worker-01" >> /etc/hosts 107 | ``` 108 | 109 | - 注意这里要把集群中所有的机器添加进来,每台机器的`hosts`文件都要包括集群中所有机器 110 | 111 | 4. 关闭防火墙 112 | 113 | ``` sh 114 | root@k8s-master-01:/home/zcs# ufw disable 115 | ``` 116 | 117 | 5. 配置`master`到`worker`的无密码访问 118 | 此操作只需要在`master`执行 119 | ``` sh 120 | root@k8s-master-01:/home/zcs# ssh-keygen 121 | Generating public/private rsa key pair. 122 | Enter file in which to save the key (/root/.ssh/id_rsa): 123 | Created directory '/root/.ssh'. 124 | Enter passphrase (empty for no passphrase): 125 | Enter same passphrase again: 126 | Your identification has been saved in /root/.ssh/id_rsa. 127 | Your public key has been saved in /root/.ssh/id_rsa.pub. 128 | The key fingerprint is: 129 | SHA256:QvRfjA1qvfdhqo9rXAcg8EHdcu9/QZCoP5rOaArpd8E root@k8s-master-01 130 | The key's randomart image is: 131 | +---[RSA 2048]----+ 132 | | ooo.... . | 133 | | . o.++*oo | 134 | | . =.+++.. | 135 | | . . o o. .. | 136 | | o S + .o+ | 137 | | . E +.+oo | 138 | | o ..o.o....| 139 | | . .. ooooo o| 140 | | ...+..++o. .| 141 | +----[SHA256]-----+ 142 | 143 | root@k8s-master-01:/home/zcs# ssh-copy-id k8s-worker-01 144 | /usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/root/.ssh/id_rsa.pub" 145 | The authenticity of host 'k8s-worker-01 (192.168.1.197)' can't be established. 146 | ECDSA key fingerprint is SHA256:HRWd/qs0nqKPGkiyVyXC2uAN5vIVepBokkSh8UtkYOw. 147 | Are you sure you want to continue connecting (yes/no)? yes 148 | /usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed 149 | /usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys 150 | root@k8s-worker-01's password: 151 | 152 | Number of key(s) added: 1 153 | 154 | Now try logging into the machine, with: "ssh 'k8s-worker-01'" 155 | and check to make sure that only the key(s) you wanted were added. 156 | ``` 157 | 158 | ## 初始化k8s集群 159 | 1. 利用`kubeadm`初始化集群:`kubeadm init --pod-network-cidr=10.244.0.0/16` 160 | 161 | ``` sh 162 | root@k8s-master-01:/home/zcs# kubeadm init --pod-network-cidr=10.244.0.0/16 163 | [init] Using Kubernetes version: v1.10.0 164 | [init] Using Authorization modes: [Node RBAC] 165 | [preflight] Running pre-flight checks. 166 | [WARNING FileExisting-crictl]: crictl not found in system path 167 | Suggestion: go get github.com/kubernetes-incubator/cri-tools/cmd/crictl 168 | [preflight] Starting the kubelet service 169 | [certificates] Generated ca certificate and key. 170 | [certificates] Generated apiserver certificate and key. 171 | [certificates] apiserver serving cert is signed for DNS names [k8s-master-01 kubernetes kubernetes.default kubernetes.default.svc kubernetes.default.svc.cluster.local] and IPs [10.96.0.1 192.168.1.196] 172 | [certificates] Generated apiserver-kubelet-client certificate and key. 173 | [certificates] Generated etcd/ca certificate and key. 174 | [certificates] Generated etcd/server certificate and key. 175 | [certificates] etcd/server serving cert is signed for DNS names [localhost] and IPs [127.0.0.1] 176 | [certificates] Generated etcd/peer certificate and key. 177 | [certificates] etcd/peer serving cert is signed for DNS names [k8s-master-01] and IPs [192.168.1.196] 178 | [certificates] Generated etcd/healthcheck-client certificate and key. 179 | [certificates] Generated apiserver-etcd-client certificate and key. 180 | [certificates] Generated sa key and public key. 181 | [certificates] Generated front-proxy-ca certificate and key. 182 | [certificates] Generated front-proxy-client certificate and key. 183 | [certificates] Valid certificates and keys now exist in "/etc/kubernetes/pki" 184 | [kubeconfig] Wrote KubeConfig file to disk: "/etc/kubernetes/admin.conf" 185 | [kubeconfig] Wrote KubeConfig file to disk: "/etc/kubernetes/kubelet.conf" 186 | [kubeconfig] Wrote KubeConfig file to disk: "/etc/kubernetes/controller-manager.conf" 187 | [kubeconfig] Wrote KubeConfig file to disk: "/etc/kubernetes/scheduler.conf" 188 | [controlplane] Wrote Static Pod manifest for component kube-apiserver to "/etc/kubernetes/manifests/kube-apiserver.yaml" 189 | [controlplane] Wrote Static Pod manifest for component kube-controller-manager to "/etc/kubernetes/manifests/kube-controller-manager.yaml" 190 | [controlplane] Wrote Static Pod manifest for component kube-scheduler to "/etc/kubernetes/manifests/kube-scheduler.yaml" 191 | [etcd] Wrote Static Pod manifest for a local etcd instance to "/etc/kubernetes/manifests/etcd.yaml" 192 | [init] Waiting for the kubelet to boot up the control plane as Static Pods from directory "/etc/kubernetes/manifests". 193 | [init] This might take a minute or longer if the control plane images have to be pulled. 194 | [apiclient] All control plane components are healthy after 22.520833 seconds 195 | [uploadconfig] Storing the configuration used in ConfigMap "kubeadm-config" in the "kube-system" Namespace 196 | [markmaster] Will mark node k8s-master-01 as master by adding a label and a taint 197 | [markmaster] Master k8s-master-01 tainted and labelled with key/value: node-role.kubernetes.io/master="" 198 | [bootstraptoken] Using token: 7odzio.v63p658llil3cij9 199 | [bootstraptoken] Configured RBAC rules to allow Node Bootstrap tokens to post CSRs in order for nodes to get long term certificate credentials 200 | [bootstraptoken] Configured RBAC rules to allow the csrapprover controller automatically approve CSRs from a Node Bootstrap Token 201 | [bootstraptoken] Configured RBAC rules to allow certificate rotation for all node client certificates in the cluster 202 | [bootstraptoken] Creating the "cluster-info" ConfigMap in the "kube-public" namespace 203 | [addons] Applied essential addon: kube-dns 204 | [addons] Applied essential addon: kube-proxy 205 | 206 | Your Kubernetes master has initialized successfully! 207 | 208 | To start using your cluster, you need to run the following as a regular user: 209 | 210 | mkdir -p $HOME/.kube 211 | sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config 212 | sudo chown $(id -u):$(id -g) $HOME/.kube/config 213 | 214 | You should now deploy a pod network to the cluster. 215 | Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at: 216 | https://kubernetes.io/docs/concepts/cluster-administration/addons/ 217 | 218 | You can now join any number of machines by running the following on each node 219 | as root: 220 | 221 | kubeadm join 192.168.1.196:6443 --token 7odzio.v63p658llil3cij9 --discovery-token-ca-cert-hash sha256:3ea30427d276996f214adba1794af4e37262cdfaa4326dac0c33534fd45a843d 222 | ``` 223 | 224 | - 上面的`kubeadm join xxx`要记住,后面`worker`节点加入集群时需要用到 225 | 226 | - 踩坑记1:各种教程里面,包括`kubernets`官方教程,对`calico`网络方案指定的`--pod-network-cidr`值是`192.168.0.0/16`,但是安装完成后`kube-dns`总是无法正常启动,推测是因为与物理机网卡ip段(`192.168.1.0/24`)重合有关,换成`10.244.0.0/16`后`kube-dns`启动正常 227 | 228 | 2. 按照上一步的提示执行以下命令: 229 | 230 | ``` sh 231 | root@k8s-master-01:/home/zcs# mkdir -p $HOME/.kube 232 | root@k8s-master-01:/home/zcs# sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config 233 | root@k8s-master-01:/home/zcs# sudo chown $(id -u):$(id -g) $HOME/.kube/config 234 | ``` 235 | 236 | - 此时可以执行`kubectl get pods --all-namespaces`命令查看`pod`信息 237 | 238 | ``` sh 239 | root@k8s-master-01:/home/zcs# kubectl get pods --all-namespaces 240 | NAMESPACE NAME READY STATUS RESTARTS AGE 241 | kube-system etcd-k8s-master-01 1/1 Running 0 9m 242 | kube-system kube-apiserver-k8s-master-01 1/1 Running 0 9m 243 | kube-system kube-controller-manager-k8s-master-01 1/1 Running 0 9m 244 | kube-system kube-dns-86f4d74b45-sbbfr 0/3 Pending 0 9m 245 | kube-system kube-proxy-4n7bh 1/1 Running 0 9m 246 | kube-system kube-scheduler-k8s-master-01 1/1 Running 0 8m 247 | ``` 248 | - 可以看到`kube-dns`的`READY`状态为`0/3`,这是因为`kube-dns`默认跑在`worker`节点的,用`kubectl describe`命令查看详细描述可以看到原因 249 | 250 | ``` sh 251 | root@k8s-master-01:/home/zcs# kubectl describe -n kube-system pod kube-dns-86f4d74b45-sbbfr 252 | Name: kube-dns-86f4d74b45-sbbfr 253 | Namespace: kube-system 254 | Node: 255 | Labels: k8s-app=kube-dns 256 | pod-template-hash=4290830601 257 | Annotations: 258 | Status: Pending 259 | IP: 260 | Controlled By: ReplicaSet/kube-dns-86f4d74b45 261 | Containers: 262 | kubedns: 263 | Image: k8s.gcr.io/k8s-dns-kube-dns-amd64:1.14.8 264 | Ports: 10053/UDP, 10053/TCP, 10055/TCP 265 | Host Ports: 0/UDP, 0/TCP, 0/TCP 266 | Args: 267 | --domain=cluster.local. 268 | --dns-port=10053 269 | --config-dir=/kube-dns-config 270 | --v=2 271 | Limits: 272 | memory: 170Mi 273 | Requests: 274 | cpu: 100m 275 | memory: 70Mi 276 | Liveness: http-get http://:10054/healthcheck/kubedns delay=60s timeout=5s period=10s #success=1 #failure=5 277 | Readiness: http-get http://:8081/readiness delay=3s timeout=5s period=10s #success=1 #failure=3 278 | Environment: 279 | PROMETHEUS_PORT: 10055 280 | Mounts: 281 | /kube-dns-config from kube-dns-config (rw) 282 | /var/run/secrets/kubernetes.io/serviceaccount from kube-dns-token-q96xn (ro) 283 | dnsmasq: 284 | Image: k8s.gcr.io/k8s-dns-dnsmasq-nanny-amd64:1.14.8 285 | Ports: 53/UDP, 53/TCP 286 | Host Ports: 0/UDP, 0/TCP 287 | Args: 288 | -v=2 289 | -logtostderr 290 | -configDir=/etc/k8s/dns/dnsmasq-nanny 291 | -restartDnsmasq=true 292 | -- 293 | -k 294 | --cache-size=1000 295 | --no-negcache 296 | --log-facility=- 297 | --server=/cluster.local/127.0.0.1#10053 298 | --server=/in-addr.arpa/127.0.0.1#10053 299 | --server=/ip6.arpa/127.0.0.1#10053 300 | Requests: 301 | cpu: 150m 302 | memory: 20Mi 303 | Liveness: http-get http://:10054/healthcheck/dnsmasq delay=60s timeout=5s period=10s #success=1 #failure=5 304 | Environment: 305 | Mounts: 306 | /etc/k8s/dns/dnsmasq-nanny from kube-dns-config (rw) 307 | /var/run/secrets/kubernetes.io/serviceaccount from kube-dns-token-q96xn (ro) 308 | sidecar: 309 | Image: k8s.gcr.io/k8s-dns-sidecar-amd64:1.14.8 310 | Port: 10054/TCP 311 | Host Port: 0/TCP 312 | Args: 313 | --v=2 314 | --logtostderr 315 | --probe=kubedns,127.0.0.1:10053,kubernetes.default.svc.cluster.local,5,SRV 316 | --probe=dnsmasq,127.0.0.1:53,kubernetes.default.svc.cluster.local,5,SRV 317 | Requests: 318 | cpu: 10m 319 | memory: 20Mi 320 | Liveness: http-get http://:10054/metrics delay=60s timeout=5s period=10s #success=1 #failure=5 321 | Environment: 322 | Mounts: 323 | /var/run/secrets/kubernetes.io/serviceaccount from kube-dns-token-q96xn (ro) 324 | Conditions: 325 | Type Status 326 | PodScheduled False 327 | Volumes: 328 | kube-dns-config: 329 | Type: ConfigMap (a volume populated by a ConfigMap) 330 | Name: kube-dns 331 | Optional: true 332 | kube-dns-token-q96xn: 333 | Type: Secret (a volume populated by a Secret) 334 | SecretName: kube-dns-token-q96xn 335 | Optional: false 336 | QoS Class: Burstable 337 | Node-Selectors: 338 | Tolerations: CriticalAddonsOnly 339 | node-role.kubernetes.io/master:NoSchedule 340 | node.kubernetes.io/not-ready:NoExecute for 300s 341 | node.kubernetes.io/unreachable:NoExecute for 300s 342 | Events: 343 | Type Reason Age From Message 344 | ---- ------ ---- ---- ------- 345 | Warning FailedScheduling 20s (x57 over 15m) default-scheduler 0/1 nodes are available: 1 node(s) were not ready. 346 | ``` 347 | 348 | - 可以看到未成功启动的原因为`FailedScheduling`(调度失败),`Message:0/1 nodes are available: 1 node(s) were not ready.`,大致意思是需要1个可用节点,但是现在0个节点可用,`Age:20s (x57 over 15m)`,大致意思是15分钟内此错误发生了57次 349 | 350 | ## worker节点加入集群 351 | 352 | 1. 在`worker`节点执行`kubeadm join xxx`命令,此命令在初始化`master`节点的时候会给出 353 | 354 | ```sh 355 | root@k8s-worker-01:~# kubeadm join 192.168.1.196:6443 --token 7odzio.v63p658llil3cij9 --discovery-token-ca-cert-hash sha256:3ea30427d276996f214adba1794af4e37262cdfaa4326dac0c33534fd45a843d 356 | [preflight] Running pre-flight checks. 357 | [WARNING FileExisting-crictl]: crictl not found in system path 358 | Suggestion: go get github.com/kubernetes-incubator/cri-tools/cmd/crictl 359 | [preflight] Starting the kubelet service 360 | [discovery] Trying to connect to API Server "192.168.1.196:6443" 361 | [discovery] Created cluster-info discovery client, requesting info from "https://192.168.1.196:6443" 362 | [discovery] Requesting info from "https://192.168.1.196:6443" again to validate TLS against the pinned public key 363 | [discovery] Cluster info signature and contents are valid and TLS certificate validates against pinned roots, will use API Server "192.168.1.196:6443" 364 | [discovery] Successfully established connection with API Server "192.168.1.196:6443" 365 | 366 | This node has joined the cluster: 367 | * Certificate signing request was sent to master and a response 368 | was received. 369 | * The Kubelet was informed of the new secure connection details. 370 | 371 | Run 'kubectl get nodes' on the master to see this node join the cluster. 372 | ``` 373 | 374 | 2. 此时可以用`kubectl get nodes`命令查看`node`信息 375 | 376 | ``` sh 377 | root@k8s-master-01:/home/zcs# kubectl get nodes 378 | NAME STATUS ROLES AGE VERSION 379 | k8s-master-01 NotReady master 37m v1.10.0 380 | k8s-worker-01 NotReady 12m v1.10.0 381 | ``` 382 | 383 | - 可以看到`STATUS`都是`NotReady`,这是因为还未安装`pod network`,官方教程中说明了这一点 384 | [kubernets官方教程](https://kubernetes.io/docs/setup/independent/create-cluster-kubeadm/) 385 | 386 | ``` 387 | You MUST install a pod network add-on so that your pods can communicate with each other. 388 | 389 | The network must be deployed before any applications. Also, kube-dns, an internal helper service, will not start up before a network is installed. kubeadm only supports Container Network Interface (CNI) based networks (and does not support kubenet). 390 | ``` 391 | 392 | - `kubectl get pods --all-namespaces`查看`pod`信息,`kube-dns`仍然是`READY:0/3` 393 | 394 | ## 安装`pod network` 395 | 1. 执行命令 396 | 397 | ``` sh 398 | root@k8s-master-01:/home/zcs# wget https://docs.projectcalico.org/v3.0/getting-started/kubernetes/installation/hosted/kubeadm/1.7/calico.yaml 399 | --2018-04-04 15:42:16-- https://docs.projectcalico.org/v3.0/getting-started/kubernetes/installation/hosted/kubeadm/1.7/calico.yaml 400 | Resolving docs.projectcalico.org (docs.projectcalico.org)... 209.58.185.108 401 | Connecting to docs.projectcalico.org (docs.projectcalico.org)|209.58.185.108|:443... connected. 402 | HTTP request sent, awaiting response... 200 OK 403 | Length: 13711 (13K) [text/yaml] 404 | Saving to: ‘calico.yaml’ 405 | 406 | calico.yaml 100%[====================================================================================================================>] 13.39K --.-KB/s in 0s 407 | 408 | 2018-04-04 15:42:26 (624 MB/s) - ‘calico.yaml’ saved [13711/13711] 409 | 410 | ``` 411 | 412 | 2. 修改`calico.yaml`文件,将`CALICO_IPV4POOL_CIDR`的`value`修改为`10.244.0.0/16` 413 | 414 | ``` 415 | . 416 | . 417 | . 418 | # The default IPv4 pool to create on startup if none exists. Pod IPs will be 419 | # chosen from this range. Changing this value after installation will have 420 | # no effect. This should fall within `--cluster-cidr`. 421 | - name: CALICO_IPV4POOL_CIDR 422 | value: "10.244.0.0/16" 423 | - name: CALICO_IPV4POOL_IPIP 424 | value: "Always" 425 | . 426 | . 427 | . 428 | ``` 429 | - 特别注意`CALICO_IPV4POOL_CIDR`的值必须与初始化`master`节点时的`--pod-network-cidr`值保持一致 430 | 431 | 3. 执行`kubectl apply -f calico.yaml`安装`pod network` 432 | 433 | ``` sh 434 | root@k8s-master-01:/home/zcs# kubectl apply -f calico.yaml 435 | configmap "calico-config" created 436 | daemonset.extensions "calico-etcd" created 437 | service "calico-etcd" created 438 | daemonset.extensions "calico-node" created 439 | deployment.extensions "calico-kube-controllers" created 440 | clusterrolebinding.rbac.authorization.k8s.io "calico-cni-plugin" created 441 | clusterrole.rbac.authorization.k8s.io "calico-cni-plugin" created 442 | serviceaccount "calico-cni-plugin" created 443 | clusterrolebinding.rbac.authorization.k8s.io "calico-kube-controllers" created 444 | clusterrole.rbac.authorization.k8s.io "calico-kube-controllers" created 445 | serviceaccount "calico-kube-controllers" created 446 | ``` 447 | 448 | - `pod network`有很多种:`Calico, Canla, Flannel, Kube-router...`等等,但是一个集群只能安装一个`pod network` 449 | 450 | 4. 此时在`master`节点执行`ifconfig`命令可以看到多了一个`tunl0`网卡,`ip`为`10.244.151.128`,符合`10.244.0.0/16`这个网段,`worker`节点同理 451 | 452 | ``` sh 453 | root@k8s-master-01:/home/zcs# ifconfig 454 | docker0 Link encap:Ethernet HWaddr 02:42:15:08:2f:c3 455 | inet addr:172.17.0.1 Bcast:0.0.0.0 Mask:255.255.0.0 456 | UP BROADCAST MULTICAST MTU:1500 Metric:1 457 | RX packets:0 errors:0 dropped:0 overruns:0 frame:0 458 | TX packets:0 errors:0 dropped:0 overruns:0 carrier:0 459 | collisions:0 txqueuelen:0 460 | RX bytes:0 (0.0 B) TX bytes:0 (0.0 B) 461 | 462 | enp0s3 Link encap:Ethernet HWaddr 08:00:27:3a:12:10 463 | inet addr:192.168.1.196 Bcast:192.168.1.255 Mask:255.255.255.0 464 | inet6 addr: fe80::a00:27ff:fe3a:1210/64 Scope:Link 465 | UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 466 | RX packets:166348 errors:0 dropped:0 overruns:0 frame:0 467 | TX packets:91331 errors:0 dropped:0 overruns:0 carrier:0 468 | collisions:0 txqueuelen:1000 469 | RX bytes:21802344 (21.8 MB) TX bytes:71423851 (71.4 MB) 470 | 471 | lo Link encap:Local Loopback 472 | inet addr:127.0.0.1 Mask:255.0.0.0 473 | inet6 addr: ::1/128 Scope:Host 474 | UP LOOPBACK RUNNING MTU:65536 Metric:1 475 | RX packets:2075906 errors:0 dropped:0 overruns:0 frame:0 476 | TX packets:2075906 errors:0 dropped:0 overruns:0 carrier:0 477 | collisions:0 txqueuelen:1 478 | RX bytes:449818079 (449.8 MB) TX bytes:449818079 (449.8 MB) 479 | 480 | tunl0 Link encap:IPIP Tunnel HWaddr 481 | inet addr:10.244.151.128 Mask:255.255.255.255 482 | UP RUNNING NOARP MTU:1440 Metric:1 483 | RX packets:0 errors:0 dropped:0 overruns:0 frame:0 484 | TX packets:0 errors:0 dropped:0 overruns:0 carrier:0 485 | collisions:0 txqueuelen:1 486 | RX bytes:0 (0.0 B) TX bytes:0 (0.0 B) 487 | ``` 488 | - 踩坑记2:卸载`Calico`再重装,指定不同的`CALICO_IPV4POOL_CIDR`,但是生成的虚拟网卡IP网段仍然是第一次设置的值,猜测是卸载`Calico`时虚拟网卡未删除导致的 489 | 490 | 5. 此时再执行`kubectl get pods --all-namespaces`可以看到`kube-dns`变成了`READY:3/3`,正常启动了 491 | 492 | ```sh 493 | root@k8s-master-01:/home/zcs# kubectl get pods --all-namespaces 494 | NAMESPACE NAME READY STATUS RESTARTS AGE 495 | kube-system calico-etcd-9r6vq 1/1 Running 0 8m 496 | kube-system calico-kube-controllers-5449fdfcd-rc5mb 1/1 Running 0 8m 497 | kube-system calico-node-fs95d 2/2 Running 0 8m 498 | kube-system calico-node-pbxvh 2/2 Running 0 8m 499 | kube-system etcd-k8s-master-01 1/1 Running 0 57m 500 | kube-system kube-apiserver-k8s-master-01 1/1 Running 0 57m 501 | kube-system kube-controller-manager-k8s-master-01 1/1 Running 0 57m 502 | kube-system kube-dns-86f4d74b45-sbbfr 3/3 Running 0 58m 503 | kube-system kube-proxy-4n7bh 1/1 Running 0 58m 504 | kube-system kube-proxy-k8pkv 1/1 Running 0 33m 505 | kube-system kube-scheduler-k8s-master-01 1/1 Running 0 57m 506 | ``` 507 | 508 | 6. 此时再执行`kubectl get nodes`可以看到`master`和`worker`节点的`STATUS`都变成了`Ready` 509 | 510 | ``` sh 511 | root@k8s-master-01:/home/zcs# kubectl get nodes 512 | NAME STATUS ROLES AGE VERSION 513 | k8s-master-01 Ready master 1h v1.10.0 514 | k8s-worker-01 Ready 35m v1.10.0 515 | ``` 516 | 517 | ## 安装`kubernets dashboard` 518 | 1. 编辑`kubernetes-dashboard.yaml`文件,写入以下内容 519 | 520 | ``` yaml 521 | # Copyright 2017 The Kubernetes Authors. 522 | # 523 | # Licensed under the Apache License, Version 2.0 (the "License"); 524 | # you may not use this file except in compliance with the License. 525 | # You may obtain a copy of the License at 526 | # 527 | # http://www.apache.org/licenses/LICENSE-2.0 528 | # 529 | # Unless required by applicable law or agreed to in writing, software 530 | # distributed under the License is distributed on an "AS IS" BASIS, 531 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 532 | # See the License for the specific language governing permissions and 533 | # limitations under the License. 534 | 535 | # Configuration to deploy release version of the Dashboard UI compatible with 536 | # Kubernetes 1.8. 537 | # 538 | # Example usage: kubectl create -f 539 | 540 | # ------------------- Dashboard Secret ------------------- # 541 | 542 | apiVersion: v1 543 | kind: Secret 544 | metadata: 545 | labels: 546 | k8s-app: kubernetes-dashboard 547 | name: kubernetes-dashboard-certs 548 | namespace: kube-system 549 | type: Opaque 550 | 551 | --- 552 | # ------------------- Dashboard Service Account ------------------- # 553 | 554 | apiVersion: v1 555 | kind: ServiceAccount 556 | metadata: 557 | labels: 558 | k8s-app: kubernetes-dashboard 559 | name: kubernetes-dashboard 560 | namespace: kube-system 561 | 562 | --- 563 | # ------------------- Dashboard Role & Role Binding ------------------- # 564 | 565 | kind: Role 566 | apiVersion: rbac.authorization.k8s.io/v1 567 | metadata: 568 | name: kubernetes-dashboard-minimal 569 | namespace: kube-system 570 | rules: 571 | # Allow Dashboard to create 'kubernetes-dashboard-key-holder' secret. 572 | - apiGroups: [""] 573 | resources: ["secrets"] 574 | verbs: ["create"] 575 | # Allow Dashboard to create 'kubernetes-dashboard-settings' config map. 576 | - apiGroups: [""] 577 | resources: ["configmaps"] 578 | verbs: ["create"] 579 | # Allow Dashboard to get, update and delete Dashboard exclusive secrets. 580 | - apiGroups: [""] 581 | resources: ["secrets"] 582 | resourceNames: ["kubernetes-dashboard-key-holder", "kubernetes-dashboard-certs"] 583 | verbs: ["get", "update", "delete"] 584 | # Allow Dashboard to get and update 'kubernetes-dashboard-settings' config map. 585 | - apiGroups: [""] 586 | resources: ["configmaps"] 587 | resourceNames: ["kubernetes-dashboard-settings"] 588 | verbs: ["get", "update"] 589 | # Allow Dashboard to get metrics from heapster. 590 | - apiGroups: [""] 591 | resources: ["services"] 592 | resourceNames: ["heapster"] 593 | verbs: ["proxy"] 594 | - apiGroups: [""] 595 | resources: ["services/proxy"] 596 | resourceNames: ["heapster", "http:heapster:", "https:heapster:"] 597 | verbs: ["get"] 598 | 599 | --- 600 | apiVersion: rbac.authorization.k8s.io/v1 601 | kind: RoleBinding 602 | metadata: 603 | name: kubernetes-dashboard-minimal 604 | namespace: kube-system 605 | roleRef: 606 | apiGroup: rbac.authorization.k8s.io 607 | kind: Role 608 | name: kubernetes-dashboard-minimal 609 | subjects: 610 | - kind: ServiceAccount 611 | name: kubernetes-dashboard 612 | namespace: kube-system 613 | 614 | --- 615 | # ------------------- Dashboard Deployment ------------------- # 616 | 617 | kind: Deployment 618 | apiVersion: apps/v1beta2 619 | metadata: 620 | labels: 621 | k8s-app: kubernetes-dashboard 622 | name: kubernetes-dashboard 623 | namespace: kube-system 624 | spec: 625 | replicas: 1 626 | revisionHistoryLimit: 10 627 | selector: 628 | matchLabels: 629 | k8s-app: kubernetes-dashboard 630 | template: 631 | metadata: 632 | labels: 633 | k8s-app: kubernetes-dashboard 634 | spec: 635 | containers: 636 | - name: kubernetes-dashboard 637 | image: k8s.gcr.io/kubernetes-dashboard-amd64:v1.8.3 638 | ports: 639 | - containerPort: 8443 640 | protocol: TCP 641 | args: 642 | - --auto-generate-certificates 643 | # Uncomment the following line to manually specify Kubernetes API server Host 644 | # If not specified, Dashboard will attempt to auto discover the API server and connect 645 | # to it. Uncomment only if the default does not work. 646 | # - --apiserver-host=http://my-address:port 647 | # - --apiserver-host=http://192.168.1.196:6443 648 | volumeMounts: 649 | - name: kubernetes-dashboard-certs 650 | mountPath: /certs 651 | # Create on-disk volume to store exec logs 652 | - mountPath: /tmp 653 | name: tmp-volume 654 | livenessProbe: 655 | httpGet: 656 | scheme: HTTPS 657 | path: / 658 | port: 8443 659 | initialDelaySeconds: 30 660 | timeoutSeconds: 30 661 | volumes: 662 | - name: kubernetes-dashboard-certs 663 | secret: 664 | secretName: kubernetes-dashboard-certs 665 | - name: tmp-volume 666 | emptyDir: {} 667 | serviceAccountName: kubernetes-dashboard 668 | # Comment the following tolerations if Dashboard must not be deployed on master 669 | tolerations: 670 | - key: node-role.kubernetes.io/master 671 | effect: NoSchedule 672 | 673 | --- 674 | # ------------------- Dashboard Service ------------------- # 675 | 676 | kind: Service 677 | apiVersion: v1 678 | metadata: 679 | labels: 680 | k8s-app: kubernetes-dashboard 681 | name: kubernetes-dashboard 682 | namespace: kube-system 683 | spec: 684 | type: NodePort 685 | ports: 686 | - port: 443 687 | targetPort: 8443 688 | selector: 689 | k8s-app: kubernetes-dashboard 690 | ``` 691 | 692 | 2. 编辑`kubernetes-dashboard-admin.rbac.yaml`,写入以下内容 693 | 694 | ``` yaml 695 | --- 696 | apiVersion: v1 697 | kind: ServiceAccount 698 | metadata: 699 | name: admin-user 700 | namespace: kube-system 701 | --- 702 | apiVersion: rbac.authorization.k8s.io/v1beta1 703 | kind: ClusterRoleBinding 704 | metadata: 705 | name: admin-user 706 | roleRef: 707 | apiGroup: rbac.authorization.k8s.io 708 | kind: ClusterRole 709 | name: cluster-admin 710 | subjects: 711 | - kind: ServiceAccount 712 | name: admin-user 713 | namespace: kube-system 714 | ``` 715 | 716 | 3. 执行`kubectl create -f xxx.yaml`命令安装`dashboard` 717 | 718 | ``` sh 719 | root@k8s-master-01:/home/zcs# kubectl create -f kubernetes-dashboard.yaml 720 | secret "kubernetes-dashboard-certs" created 721 | serviceaccount "kubernetes-dashboard" created 722 | role.rbac.authorization.k8s.io "kubernetes-dashboard-minimal" created 723 | rolebinding.rbac.authorization.k8s.io "kubernetes-dashboard-minimal" created 724 | deployment.apps "kubernetes-dashboard" created 725 | service "kubernetes-dashboard" created 726 | root@k8s-master-01:/home/zcs# kubectl create -f kubernetes-dashboard-admin.rbac.yaml 727 | serviceaccount "admin-user" created 728 | clusterrolebinding.rbac.authorization.k8s.io "admin-user" created 729 | ``` 730 | 731 | 4. 查看`pod`状态,可以看到`kubernetes-dashboard`正常运行了 732 | 733 | ``` sh 734 | root@k8s-master-01:/home/zcs# kubectl get pods --all-namespaces 735 | NAMESPACE NAME READY STATUS RESTARTS AGE 736 | kube-system calico-etcd-9r6vq 1/1 Running 0 43m 737 | kube-system calico-kube-controllers-5449fdfcd-rc5mb 1/1 Running 0 43m 738 | kube-system calico-node-fs95d 2/2 Running 0 43m 739 | kube-system calico-node-pbxvh 2/2 Running 0 43m 740 | kube-system etcd-k8s-master-01 1/1 Running 0 1h 741 | kube-system kube-apiserver-k8s-master-01 1/1 Running 0 1h 742 | kube-system kube-controller-manager-k8s-master-01 1/1 Running 0 1h 743 | kube-system kube-dns-86f4d74b45-sbbfr 3/3 Running 0 1h 744 | kube-system kube-proxy-4n7bh 1/1 Running 0 1h 745 | kube-system kube-proxy-k8pkv 1/1 Running 0 1h 746 | kube-system kube-scheduler-k8s-master-01 1/1 Running 0 1h 747 | kube-system kubernetes-dashboard-7d5dcdb6d9-trj44 1/1 Running 0 3m 748 | ``` 749 | 750 | ## 登录`dashboard` 751 | `kubernets`采用了`rabc`(基于角色的权限访问控制`Role-Based Access Control`),登录过程如下 752 | 1. 获取`dashboard`服务端口为`32315` 753 | 754 | ``` sh 755 | root@k8s-master-01:/home/zcs# kubectl get services kubernetes-dashboard -n kube-system 756 | NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE 757 | kubernetes-dashboard NodePort 10.97.122.226 443:32315/TCP 19m 758 | ``` 759 | 760 | 2. 浏览器访问 https://masterip:32315,本文中的例子应该是 https://192.168.1.196:32315,需注意,由于没有证书,在`Chrome`浏览器中会无法访问,推荐`Firefox`,添加列外后,不出意外出现认证页面,选择令牌登录 761 | 762 | ![avatat](./picture/dashboard_login.png) 763 | 764 | 3. 获取登录令牌(`token`) 765 | - 查看当前集群的`secret` 766 | ``` sh 767 | root@k8s-master-01:/home/zcs# kubectl get secret -n kube-system 768 | NAME TYPE DATA AGE 769 | admin-user-token-sbv24 kubernetes.io/service-account-token 3 27m 770 | attachdetach-controller-token-7lfj6 kubernetes.io/service-account-token 3 1h 771 | bootstrap-signer-token-w48vj kubernetes.io/service-account-token 3 1h 772 | bootstrap-token-7odzio bootstrap.kubernetes.io/token 7 1h 773 | calico-cni-plugin-token-dxlw9 kubernetes.io/service-account-token 3 1h 774 | calico-kube-controllers-token-vt6k7 kubernetes.io/service-account-token 3 1h 775 | certificate-controller-token-9jtj7 kubernetes.io/service-account-token 3 1h 776 | clusterrole-aggregation-controller-token-wfn6r kubernetes.io/service-account-token 3 1h 777 | cronjob-controller-token-thz64 kubernetes.io/service-account-token 3 1h 778 | daemon-set-controller-token-2rn8k kubernetes.io/service-account-token 3 1h 779 | default-token-678zj kubernetes.io/service-account-token 3 1h 780 | deployment-controller-token-69kkf kubernetes.io/service-account-token 3 1h 781 | disruption-controller-token-bnkkm kubernetes.io/service-account-token 3 1h 782 | endpoint-controller-token-78l4k kubernetes.io/service-account-token 3 1h 783 | generic-garbage-collector-token-kb94r kubernetes.io/service-account-token 3 1h 784 | horizontal-pod-autoscaler-token-6txtt kubernetes.io/service-account-token 3 1h 785 | job-controller-token-dpcz7 kubernetes.io/service-account-token 3 1h 786 | kube-dns-token-q96xn kubernetes.io/service-account-token 3 1h 787 | kube-proxy-token-l46s6 kubernetes.io/service-account-token 3 1h 788 | kubernetes-dashboard-certs Opaque 0 27m 789 | kubernetes-dashboard-key-holder Opaque 2 27m 790 | kubernetes-dashboard-token-kd6qc kubernetes.io/service-account-token 3 27m 791 | namespace-controller-token-4hdl4 kubernetes.io/service-account-token 3 1h 792 | node-controller-token-72cf8 kubernetes.io/service-account-token 3 1h 793 | persistent-volume-binder-token-ntwvn kubernetes.io/service-account-token 3 1h 794 | pod-garbage-collector-token-pdgbs kubernetes.io/service-account-token 3 1h 795 | pv-protection-controller-token-84fjx kubernetes.io/service-account-token 3 1h 796 | pvc-protection-controller-token-b48jp kubernetes.io/service-account-token 3 1h 797 | replicaset-controller-token-2dn65 kubernetes.io/service-account-token 3 1h 798 | replication-controller-token-nxr7j kubernetes.io/service-account-token 3 1h 799 | resourcequota-controller-token-l82vw kubernetes.io/service-account-token 3 1h 800 | service-account-controller-token-q7cfj kubernetes.io/service-account-token 3 1h 801 | service-controller-token-d8jc7 kubernetes.io/service-account-token 3 1h 802 | statefulset-controller-token-87ps7 kubernetes.io/service-account-token 3 1h 803 | token-cleaner-token-dpf9c kubernetes.io/service-account-token 3 1h 804 | ttl-controller-token-tklm5 kubernetes.io/service-account-token 3 1h 805 | ``` 806 | 807 | 3. 获取超级用户`admin-user-token-sbv24`的令牌 808 | 809 | ``` sh 810 | root@k8s-master-01:/home/zcs# kubectl describe -n kube-system secret admin-user-token-sbv24 811 | Name: admin-user-token-sbv24 812 | Namespace: kube-system 813 | Labels: 814 | Annotations: kubernetes.io/service-account.name=admin-user 815 | kubernetes.io/service-account.uid=fd35a522-37e1-11e8-a1c3-0800273a1210 816 | 817 | Type: kubernetes.io/service-account-token 818 | 819 | Data 820 | ==== 821 | token: eyJhbGciOiJSUzI1NiIsImtpZCI6IiJ9.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJrdWJlLXN5c3RlbSIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VjcmV0Lm5hbWUiOiJhZG1pbi11c2VyLXRva2VuLXNidjI0Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQubmFtZSI6ImFkbWluLXVzZXIiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC51aWQiOiJmZDM1YTUyMi0zN2UxLTExZTgtYTFjMy0wODAwMjczYTEyMTAiLCJzdWIiOiJzeXN0ZW06c2VydmljZWFjY291bnQ6a3ViZS1zeXN0ZW06YWRtaW4tdXNlciJ9.FOh6fIXsNVJqsnrVbkmjwrO1xbEG-DIhZP0YXyxlCrjqEWHIEsYI_uy6-6arSYmOz2gtEEjU-6ksjndjcSHp5hOIQYVXGriAnmj2NPaqi58hToLgyB5qnLGc2IU2BceyaMrdmNT57TFWtLe8kIYdLKEfJG9GNalghnj9H250cenZjxknvRlK3jYRVdcbui5u6ogq0fe9ETtGnIuw_1vvVigy0nFBH4XK4g79QbJNCeqWYcwsERW3htUNztg8I0IeWcE-RGD1oi0xGWEwllhEOWKnkQV077sp3Tk-QkPA8qUIMLm244Ct8cyoKxyv3QPCc0hIxyHDJQyyCHyU683jAA 822 | ca.crt: 1025 bytes 823 | namespace: 11 bytes 824 | ``` 825 | 826 | 4. 复制获取到的token,粘贴到浏览器,登录,就成功啦 827 | ![avatat](./picture/dashboard.png) 828 | 829 | 830 | ## 一些操作指导,经验 831 | 832 | - `kubectl`命令中`--all-namespaces` 与 `-n kube-system` 是等价的 833 | - 获取`pod`状态 834 | - `kubectl get pods --all-namespaces` 835 | - `kubectl get pods -o wide --all-namespaces` 836 | - 获取`node`状态 837 | - `kubectl get nodes` 838 | - 获取`endpoint`状态 839 | - `kubectl get endpoints --all-namespaces` 840 | - 获取`service`状态 841 | - `kubectl get services kubernetes-dashboard -n kube-system` 842 | - 删除`pod` 843 | - `kubectl delete --namespace=kube-system pod kube-dns-86f4d74b45-d2vh6` 844 | - 查看`pod`日志 845 | - `kubectl logs -n kube-system kube-controller-manager-k8s-manager` 846 | - `kubectl logs -n kube-system kube-dns-86f4d74b45-8f87x kubedns` 847 | - 查看`pod`详细描述 848 | - `kubectl describe -n kube-system pod kube-dns-86f4d74b45-sw7wl` 849 | - `kube-apiserver`配置文件路径 850 | - `/etc/kubernetes/manifests/kube-apiserver.yaml` 851 | - 导出系统中的镜像 852 | 853 | ``` 854 | for images in `docker images|awk '{print $1":"$2}'`;do docker save $images > $(echo $images |sed 's/\//_/g').img; done 855 | ``` 856 | 857 | - 批量加载`docker`镜像 858 | 859 | - `for images in $(ls|grep img);do docker load < $images;done` 860 | 861 | - 执行`kubectl xxx`命令报错,这是因为执行了`kubeadm reset`后再重装集群导致的,解决方法:删除`$HOME/.kube`文件夹 862 | 863 | ```sh 864 | root@k8s-Manager:/home# kubectl get nodes 865 | Unable to connect to the server: x509: certificate signed by unknown authority (possibly because of "crypto/rsa: verification error" while trying to verify candidate authority certificate "kubernetes") 866 | ``` 867 | - 编辑`kube-proxy` 868 | - `kubectl -n kube-system edit ds kube-proxy` 869 | 870 | - 便捷初始化脚本 871 | - `master`节点 872 | ``` sh 873 | hostname k8s-master-01 874 | echo "k8s-master-01" > /etc/hostname 875 | swapoff -a 876 | sed -i 's/^\(.*swap.*$\)/#\1/' /etc/fstab 877 | ufw disable 878 | echo "192.168.1.196 k8s-master-01" >> /etc/hosts 879 | echo "192.168.1.197 k8s-worker-01" >> /etc/hosts 880 | ``` 881 | 882 | - `worker`节点 883 | ``` sh 884 | hostname k8s-worker-01 885 | echo "k8s-worker-01" > /etc/hostname 886 | swapoff -a 887 | sed -i 's/^\(.*swap.*$\)/#\1/' /etc/fstab 888 | ufw disable 889 | echo "192.168.1.196 k8s-master-01" >> /etc/hosts 890 | echo "192.168.1.197 k8s-worker-01" >> /etc/hosts 891 | ``` 892 | 893 | 894 | -------------------------------------------------------------------------------- /学习笔记/K8S/第三天-Kubelet.md: -------------------------------------------------------------------------------- 1 | ## Kubelet 2 | 3 | kubelet组件是K8S集群工作节点中最重要的组件,它负责管理和维护在这台主机上运行着的所有容器(使得pod的运行状态与它的期望值spec一致) 4 | 5 | ### kubelet与cAdvisor交互 6 | 7 | `cAdvisor`是谷歌开发的用于分析运行中容器的资源占用和性能指标的开源工具,它是一个运行时的守护进程,负责收集、聚合、处理和输出运行中容器的信息,通过暴露一个TCP端口对外提供一套REST API 8 | 9 | - **容器信息** 10 | 11 | URL:`/api/{api version}/containers/绝对容器名` 12 | 13 | 如`/api/v1.0/containers/docker/2c4dee605.` 14 | 15 | - **宿主机信息** 16 | 17 | URL:`/api/{api version}/machine` 18 | 19 | ### kubelet的垃圾回收机制 20 | 21 | kubelet的垃圾回收机制分为`容器回收`与`镜像回收` 22 | 23 | #### 容器回收 24 | 25 | docker容器回收策略主要涉及3个因素 26 | 27 | | 名称 | 含义 | 备注 | 28 | | :----------------: | :---------------------: | :-----: | 29 | | MinAge | 回收前距离创建时间的最小值 | =0:没有限制 | 30 | | MaxPerPodContainer | 每个pod最多留有的停止的相同容器名的容器数目 | <0:没有限制 | 31 | | MaxContainers | 每个工作节点上最多拥有的容器数目 | <0:没有限制 | 32 | 33 | **回收步骤** 34 | 35 | 1. 获取所有可以被kubelet垃圾回收的容器(过滤、排序) 36 | 2. 根据垃圾回收策略回收镜像(上面列表的参数) 37 | 38 | #### 镜像回收 39 | 40 | docker镜像回收策略主要涉及3个因素 41 | 42 | | 名称 | 含义 | 43 | | :-------------------: | :------------: | 44 | | HighThreshouldPercent | 触发镜像回收的磁盘使用率上限 | 45 | | LowThresholdPercent | 触发镜像回收的磁盘使用率下限 | 46 | | MinAge | 触发镜像回收时至少存在的时间 | 47 | 48 | **回收步骤** 49 | 50 | 1. 调用`cAdvisor`客户端API获取工作节点的文件系统信息(磁盘设备、挂载点、总容量、使用量等) 51 | 2. 根据垃圾回收策略删除镜像来释放空间 52 | 53 | ### kubelet对工作节点的同步 54 | 55 | 首先,kubelet调用APIServer API向etcd获取包含当前工作节点状态信息的node对象; 56 | 57 | 然后调用`cAdvisor`客户端API获取当前工作节点的宿主机信息(IP、机器信息、磁盘信息、工作节点状态、是否可被调度),更新获取到的node对象; 58 | 59 | 最后kubelet再次调用APIServer API将上述更新持久化到etcd中 60 | -------------------------------------------------------------------------------- /学习笔记/K8S/第二天-kubectl命令.md: -------------------------------------------------------------------------------- 1 | ## kubectl Command 2 | 3 | ### Get 4 | 5 | 以下命令以Pod举例,Service、ReplicaSet、Deployment、...都一样,命令中的pod换为service、replicaset、deployments即可. 6 | 7 | - 查询所有Pod 8 | 9 | ```shell 10 | > kubectl get pods 11 | NAME READY STATUS RESTARTS AGE 12 | eureka-58886df557-txwl9 1/1 Running 0 13d 13 | > kubectl get pods -o wide 14 | NAME READY STATUS RESTARTS AGE IP NODE 15 | eureka-58886df557-txwl9 1/1 Running 0 13d 10.42.88.73 eureka1 16 | ``` 17 | 18 | - 查询某个Pod 19 | 20 | ```shell 21 | > kubectl get pod/eureka-58886df557-txwl9 22 | ``` 23 | 24 | - 根据label查询 25 | 26 | ```shell 27 | > kubectl get pod -l app=eureka 28 | ``` 29 | 30 | - 根据namespace查询 31 | 32 | ```shell 33 | > kubectl get namespaces 34 | NAME STATUS AGE 35 | default Active 17d 36 | istio-system Active 9d 37 | kube-dev Active 9d 38 | kube-public Active 17d 39 | kube-system Active 17d 40 | > kubectl get pod --namespace=default 41 | NAME READY STATUS RESTARTS AGE 42 | eureka-58886df557-txwl9 1/1 Running 0 13d 43 | ``` 44 | 45 | - 以JSON格式输出 46 | 47 | ```shell 48 | > kubectl get -o json pod eureka-58886df557-txwl9 49 | { 50 | "apiVersion": "v1", 51 | "kind": "Pod", 52 | "metadata": { 53 | "creationTimestamp": "2018-06-08T07:01:18Z", 54 | "generateName": "eureka-58886df557-", 55 | "labels": { 56 | "app": "eureka", 57 | "pod-template-hash": "1444289113" 58 | }, 59 | "name": "eureka-58886df557-txwl9", 60 | "namespace": "default", 61 | ... 62 | ``` 63 | 64 | - 查询value值 65 | 66 | ```shell 67 | > kubectl get -o template pod/eureka-58886df557-txwl9 --template={{.status.phase}} 68 | Running 69 | > kubectl get -o template pod/eureka-58886df557-txwl9 --template={{.metadata.name}} 70 | eureka-58886df557-txwl9 71 | > kubectl get -o template pod/eureka-58886df557-txwl9 --template={{.status.podIP}} 72 | 10.42.88.73 73 | ``` 74 | 75 | ### Create 76 | 77 | 创建kubernetes对象 78 | 79 | ```shell 80 | > kubectl create -f xxx.json 81 | ``` 82 | 83 | 参数-f 84 | 85 | ```shell 86 | -f, --filename=[]: Filename, directory, or URL to files to use to create the resource 87 | ``` 88 | 89 | ### Apply 90 | 91 | 在原有资源基础上进行更新 92 | 93 | ```shell 94 | > kubectl apply -f new-xxx.yaml 95 | ``` 96 | 97 | ### Edit 98 | 99 | 与Apply一样都是更新,Edit在执行如下命令后会让你更新对应的yaml文件,相当于修改完yaml文件然后执行replace 100 | 101 | ```shell 102 | > kubectl edit pod/eureka-58886df557-txwl9 103 | ``` 104 | 105 | ### Logs 106 | 107 | 查看日志 108 | 109 | ```shell 110 | > kubectl logs pod/eureka-58886df557-txwl9 111 | ``` 112 | 113 | ### Delete 114 | 115 | 删除 116 | 117 | ```shell 118 | # 根据xxx.json指定的name删除 119 | > kubectl delete -f xxx.json 120 | # 删除指定pod(service、replicaset) 121 | > kubectl delete pod/xxx 122 | # 根据labels删除pods(services、replicasets) 123 | > kubectl delete pods -l app=eureka 124 | ``` 125 | 126 | ### Rollout 127 | 128 | 对deployment失败的资源进行回滚操作 129 | 130 | ```shell 131 | > kubectl rollout --help 132 | Available Commands: 133 | history 展示历史版本 134 | pause 将资源标记为暂停 135 | resume 恢复一个暂停的资源 136 | status 显示rollout的状态 137 | undo 回滚到指定的版本 138 | ``` 139 | --- 140 | 141 | `docker`容器管理的要求: 142 | 143 | |要求|含义| 144 | |---|---| 145 | |调度|我的容器该在哪里运行| 146 | |生命周期管理和健康检查|如何保证容器可以在不同环境下都正常运行| 147 | |服务发现|我的容器现在正在哪里运行?提供哪些服务| 148 | |监控|我的容器发生了什么| 149 | |认证授权|谁可以对我的容器做哪些事情| 150 | |聚合|如何管理由多个容器组成的服务| 151 | |扩展性|动态的调整容器的规模| 152 | 153 | > kubernets提供的功能 154 | 155 | 调度、容器健康、服务发现、监控、认证授权、自动扩展、自愈、持久化接口 156 | -------------------------------------------------------------------------------- /学习笔记/K8S/第四天-K8S架构.md: -------------------------------------------------------------------------------- 1 | ## K8S 架构 2 | 3 | K8S由两种节点组成:`master节点`(管理节点)和`工作节点`(容器运行的节点) 4 | 5 | ### master节点 6 | 7 | master节点主要有3个重要的组件,分别是`APIServer`、`Scheduler`、`Controller Manager` 8 | 9 | #### APIServer 10 | 11 | K8S APIServer负责对外提供Kubernetes API服务,任何对资源增删改查的操作都要交给APIServer处理后才能提交给etcd 12 | 13 | - 对外提供基于RESTFul的管理接口 14 | - 配置K8S的资源对象 15 | - 提供可定制的功能插件 16 | - 系统日志收集功能 17 | - 可视化API 18 | 19 | #### Scheduler 20 | 21 | K8S Scheduler是一个典型的单体调度器,它的作用是根据特定的调度算法将pod调度到指定的工作节点上,这一过程通常称为绑定(bind) 22 | 23 | ![](http://qiniu.itliusir.com/scheduler.png) 24 | 25 | - **数据采集模型** 26 | 27 | K8S没有消息系统帮助用户实现各组件间的高效通信,所以Scheduler专门对感兴趣的资源和数据设置了本地缓存机制(简单的无序cache对象:可用的podLister NodeLister ServiceLister等 、有序数据的先进先出队列:podQueue) 28 | 29 | - **调度算法** 30 | 31 | - default 32 | - 自定义 33 | 34 | - **启动与运行** 35 | 36 | 1. 收集scheduler产生的事件信息并构建事件对象,然后向APIServer发送这些对象,最终由APIServer调用etcd客户端接口将这些事件进行持久化 37 | 2. 创建一个http server,默认绑定到IP地址(default:0.0.0.0)上并监听端口(default:10251) 38 | 3. 根据配置信息创建调度器并启动SchedulerServer 39 | 4. 注册metrics规则,用于检测调度工作的性能 40 | 41 | - **multi-scheduler** 42 | 43 | #### Controller Manager 44 | 45 | K8S Controller Manager是基于Pod API上的一个独立服务,它管理着K8S集群中的各种控制器,如大家熟知的Replication Controller、Node Controller等 46 | 47 | - **启动过程** 48 | 49 | 1. 根据用户传入的参数以及默认参数创建kubeconfig(包含了Controller Manager在工作中需要使用的配置信息)和kubeClient(与APIServer进行交互的客户端) 50 | 2. 创建一个http server,对外暴露`/debug/pprof/`、`/debug/pprof/profile`、`/debug/pprof/symbol`和`/metrics`用于辅助debug和收集metric数据 51 | 3. 按照顺序创建各种控制管理器 52 | 53 | > 其控制pod、工作节点等资源正常运行的本质就是靠各种controller定时对pod、工作节点等资源进行检查,然后判断实际运行状态与期望是否一致,若不一致则通知APIServer进行增删改操作 54 | 55 | - **服务端点控制器(endpoint controller)** 56 | 57 | **当用户在K8S中创建一个包含label selector的service对象时,系统会随之创建一个对应的endpoint对象,该对象即保存了所有匹配service的label selector后端pod的IP地址和端口** 58 | 59 | endpoint controller维护了两个缓存池,其中serviceStore用于存储service,podStore用于存储pod,并且使用controller的reflector机制实现两个缓存与etcd内数据的同步 60 | 61 | endpoint通过多个goroutine来同时处理service队列中的状态更新,goroutine的数量由controller manager的ConcurrentEndpointSyncs参数来指定,默认为5个,不同goroutine相互之间互不干扰 62 | 63 | **goroutine的工作步骤:** 64 | 65 | 1. 从service队列中取出当前处理的service名,在serviceStore中查找该service对象,若该对象不存在,则删除其所对应的所有endpoint 66 | 2. 构建service对应的endpoint的期望状态。根据service.Spec.Selector从podStore中获取该service对应的后端pod对象列表。对于每一个pod将pod.Status.PodIP、pod.Spec.Hostname和service.spec中定义的端口号,版本号这些组成一个EndpointSubset对象,然后将这些对象组成一个slice subset,这就是期望的endpoint状态 67 | 3. 使用service名作为检索键值,调用APIServer的API获取当前系统中存在的endpoint对象列表currentEndpoints(当前实际状态),如果找不到对应的endpoint则将新建一个新的endpoint对象给currentEndpoints,此时ResourceVersion为0,ResourceVersion也是用来判断endpoint是创建还是更新 68 | 69 | > 通过上述分析可以看出,controller的一般处理逻辑是先获取某种资源对象的期望状态,期望状态可能是存储在etcd里的spec字段下的数据,也可能是类似endpoint这种动态构造。然后将之与实际状态对比,最后向APIServer发请求弥补两者之间可能存在的差别 70 | 71 | - **副本管理控制器(replication controller,rm)** 72 | 73 | 负责保证rc管理的pod的**期望副本数**与**实际运行的pod数量**匹配 74 | 75 | 与endpoint controller类似,rm本地也维护了两个缓存池rcStore和podStore,分别同步rc与pod在etcd的数据,同样使用reflector机制实现两个缓存与etcd内数据的同步,rcStore更新时候会将该rc对象加入待更新队列queue中 76 | 77 | rc启用了多个goroutine对其进行同步工作 78 | 79 | **goroutine的工作步骤:** 80 | 81 | 1. 从rc队列中取出当前处理的rc名,通过rcStore获得该rc对象,如果rc不存在则从`expectations`中将该rc删除;如果查询时返回的是其他错误,则重新将该rc入队 82 | 2. 检查该rc的`expectations`是否被满足或者TTL超时,如果是则需要同步 83 | 3. 调整rc中的副本数,将从APIServer获取的pod列表与rc的.spec.replicas字段相减得到diff,如果diff小于0表示还需要更多的副本,设置`expectations`中的add值为|diff|,并且调用APIServer的API发起pod的创建请求,创建完毕add-1。同理如果diff大于0就需要清除一些pod 84 | 4. 最后,调用APISever的API更新rc的status.replicas 85 | 86 | > expectations是rm用于记住每个rc期望看到的pod数的TTL cache,为每个rc维护了原子技术器(add/del),对于创建的会add-1,删除的会del-1,当add或者del小于等于0就代表rc的期望已经被满足啦 87 | 88 | > 本节的rc指的是副本控制器 rm(也叫replication controller)指的是副本管理控制器 89 | 90 | - **垃圾回收控制器(gc controller)** 91 | 92 | gc controller维护了一个缓存池podStore,用于存储终止状态的pod(podPhase非Pending/Running/Unknow三者的pod),使用reflector机制监听APIServer对podStore进行更新 93 | 94 | - **节点控制器(node controller)** 95 | 96 | node controller主要用于检查K8S的工作节点是否可用,它会定期检查所有在运行的工作节点上的kubelet进程来获取这些工作节点的信息,若kubelet在规定时间内没有推送该节点状态则将其NodeCondition为Ready的状态置成Unknow,并写入etcd中 97 | 98 | ### 工作节点 99 | 100 | #### 描述方式 101 | 102 | K8S将工作节点也看作是资源对象的一种,用户可以像创建pod那样,通过资源配置文件或kubectl命令行工具来创建一个node资源对象。创建node资源对象只是为了抽象并维护工作节点的相关信息(spec、status),并对工作节点是否可用进行持续的追踪 103 | 104 | K8S主要维护工作节点的spec和status属性,分别用来描述期望状态和当前状态,期望状态是由一个json资源配置文件构成,描述了一个工作节点的具体信息,当前状态包含如下相关信息: 105 | 106 | - Node Address——工作节点的主机地址信息 107 | - Node Phase——工作节点的生命周期,分为Pending、Running和Terminated 108 | - Node Condition——描述Running状态下工作节点的细分情况 109 | - Node Capacity与Node Allocatable——工作节点上的资源总量和当前可供调度的资源等 110 | - Node Info——如内核信息、runtime版本(docker)、kubelet版本等,这些信息由kubelet收集 111 | - Images——工作节点上存在的容器镜像列表 112 | - Daemon Endpoint——工作节点上运行的kubelet监听的端口 113 | 114 | #### 管理机制 115 | 116 | 工作节点的动态维护过程是依靠node controller来完成的,通过循环来不断检测当前K8S已知的每台工作节点是否正常工作,如果是正常则将其添加为工作节点的一员,反之则会删除 117 | 118 | > node controller主要职责是负责监控有kubelet发送过来的工作节点运行状态,监控间隔是5秒钟,node controller与其他controller不同之处是其实际上的工作节点是由IAAS平台来做,etcd里存放的node资源只是一种说明它是否正常的描述性资源,其信息由kubelet提供 119 | -------------------------------------------------------------------------------- /学习笔记/Linux/面试题.md: -------------------------------------------------------------------------------- 1 | ### 1. 什么是虚拟内存?虚拟内存有什么优势? 2 | ``` 3 | 虚拟内存是计算机系统内存管理的一种技术。它使得应用程序认为它拥有连续的可用的内存(一个连续完整的地址空间). 4 | 而实际上,它通常是被分隔成多个物理内存碎片,还有部分暂时存储在外部磁盘存储器上,在需要时进行数据交换。 5 | 与没有使用虚拟内存技术的系统相比,使用这种技术的系统使得大型程序的编写变得更容易,对真正的物理内存(例如RAM)的使用也更有效率. 6 | 物理内存有限,是一种稀缺资源. 7 | 32位系统中,每个进程独立的占有4G虚拟空间。 8 | ``` 9 | ``` 10 | 虚拟内存优势: 11 | (1)用户程序开发方便 12 | (2)保护内核不受恶意或者无意的破坏 13 | (3)隔离各个用户进程 14 | (4)将逻辑内存和物理内存分开。 15 | (5)虚拟内存允许文件和内存通过共享页而为两个或多个进程所共享。 16 | ``` 17 | ### 2. 进程的有哪几种状态? 18 | ``` 19 | 进程的五种状态模型: 20 | 21 | `新建态`:刚刚创建的进程,操作系统还没有把它加入到可执行进程组中,通常是进程控制块已经创建但是还没有加载到内存中的进程。 22 | 23 | `就绪态`:进程已经做好了准备,只要有机会就开始执行。 24 | 25 | `运行态`:该进程正在执行。 26 | 27 | `阻塞态`(等待态):进程在某些事情发生前不能执行,等待阻塞进程的事件完成。 28 | 29 | `退出态`:操作系统从可执行进程组中释放出的进程,或由于自身或某种原因停止运行。 30 | ``` 31 | 注意:线程也有`4`种状态。`新生状态`、`可运行状态`、`被阻塞状态`、`死亡状态`。 32 | ### 3.线程与进程的区别? 33 | ``` 34 | (1)线程是进程的一部分,所以线程有的时候被称为是轻权进程或者轻量级进程。 35 | (2)一个没有线程的进程是可以被看作单线程的,如果一个进程内拥有多个进程,进程的执行过程不是一条线(线程)的,而是多条线(线程)共同完成的。 36 | (3)系统在运行的时候会为每个进程分配不同的内存区域,但是不会为线程分配内存(线程所使用的资源是它所属的进程的资源),线程组只能共享资源。 37 | 那就是说,除了CPU之外(线程在运行的时候要占用CPU资源),计算机内部的软硬件资源的分配与线程无关,线程只能共享它所属进程的资源。 38 | (4) 与进程的控制表PCB相似,线程也有自己的控制表TCB,但是TCB中所保存的线程状态比PCB表中少多了。 39 | (5) 进程是系统所有资源分配时候的一个基本单位,拥有一个完整的虚拟空间地址,并不依赖线程而独立存在。 40 | ``` 41 | ### 4.进程通信的几种方式? 42 | 进程间通信主要包括`管道`, `系统IPC`(包括`消息队列`,`信号量`,`共享存储`), `SOCKET`. 43 | ``` 44 | 管道包括三种: 45 | (1)普通管道PIPE, 通常有种限制,一是半双工,只能单向传输;二是只能在父子进程间使用. 46 | (2)流管道s_pipe: 去除了第一种限制,可以双向传输. 47 | (3)命名管道:name_pipe,去除了第二种限制,可以在许多并不相关的进程之间进行通讯. 48 | ``` 49 | ``` 50 | (1)管道( pipe ):管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用。 51 | 进程的亲缘关系通常是指父子进程关系。 52 | 53 | (2)有名管道 (namedpipe) : 有名管道也是半双工的通信方式,但是它允许无亲缘关系进程间的通信。 54 | 55 | (3)信号量( semophore) : 信号量是一个计数器,可以用来控制多个进程对共享资源的访问。 56 | 它常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源。 57 | 因此,主要作为进程间以及同一进程内不同线程之间的同步手段。 58 | 59 | (4)消息队列( messagequeue ) : 消息队列是由消息组成的链表,存放在内核中并由消息队列标识符标识。 60 | 消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点。 61 | 62 | (5)信号 ( sinal ) : 信号是一种比较复杂的通信方式,用于通知接收进程某个事件已经发生。 63 | 64 | (6)共享内存( sharedmemory ) :共享内存就是映射一段能被其他进程所访问的内存,这段共享内存由一个进程创建,但多个进程都可以访问。 65 | 共享内存是最快的 IPC 方式,它是针对其他进程间通信方式运行效率低而专门设计的。 66 | 它往往与其他通信机制,如信号量,配合使用,来实现进程间的同步和通信。 67 | 68 | (7)套接字( socket ) : 套解口也是一种进程间通信机制,与其他通信机制不同的是,它可用于不同机器间的进程通信。 69 | ``` 70 | ### 7.进程中线程同步的四种常用方式? 71 | ``` 72 | (1)临界区(CriticalSection) 73 | (2)事件(Event) 74 | (3)互斥量(Mutex) 75 | (4)信号量(Semphore) 76 | ``` 77 | -------------------------------------------------------------------------------- /学习笔记/Lua/linux下如何安装lua.md: -------------------------------------------------------------------------------- 1 | 1.下载`lua`包并解压 2 | ``` 3 | wget -c http://www.lua.org/ftp/lua-5.3.0.tar.gz 4 | tar zxvf lua-5.3.0.tar.gz 5 | ``` 6 | 2、下载`libreadline`相关支持 7 | ``` 8 | sudo apt-get install libreadline5 9 | sudo apt-get install libreadline-gplv2-dev 10 | ``` 11 | 3、编译以及安装 12 | ``` 13 | cd lua-5.3.0 14 | make linux 15 | sudo make install 16 | ``` 17 | 4、测试 18 | ``` 19 | $ lua 20 | Lua 5.1.2 Copyright (C) 1994-2007 Lua.org, PUC-Rio 21 | >print("Hello World!") 22 | ``` 23 | 按下`Ctrl+D`退出。 24 | -------------------------------------------------------------------------------- /学习笔记/MapReduce/tutorial.md: -------------------------------------------------------------------------------- 1 | ### 1. Hadoop Map/Reduce教程 2 | [Hadoop Map/Reduce教程](http://hadoop.apache.org/docs/r1.0.4/cn/mapred_tutorial.html) 3 | -------------------------------------------------------------------------------- /学习笔记/MongoDB/MongoDB的安装.md: -------------------------------------------------------------------------------- 1 | #### 参考文档:https://docs.mongodb.com/master/tutorial/install-mongodb-on-ubuntu/ 2 | *** 3 | ### 虽然Ubuntu本身也提供MongoDB安装包,但往往官网的安装包版本更新。 4 | ``` 5 | hupeng@hupeng-vm:~$ apt-cache show mongodb-clients 6 | Package: mongodb-clients 7 | Priority: optional 8 | Section: universe/database 9 | Installed-Size: 160066 10 | Maintainer: Ubuntu Developers 11 | Original-Maintainer: Laszlo Boszormenyi (GCS) 12 | Architecture: amd64 13 | Source: mongodb 14 | Version: 1:2.6.10-0ubuntu1 # 版本号 15 | ``` 16 | ## 安装步骤: 17 | 18 | #### 1.导入包管理系统使用的公钥 19 | ``` 20 | sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 0C49F3730359A14518585931BC711F9BA15703C6 21 | ``` 22 | #### 2.为MongoDB创建一个列表文件 23 | 根据版本创建`/etc/apt/sources.list.d/mongodb-org-3.4.list `列表文件 24 | 25 | Ubuntu 14.04 26 | ``` 27 | echo "deb [ arch=amd64 ] http://repo.mongodb.org/apt/ubuntu trusty/mongodb-org/3.4 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-3.4.list 28 | ``` 29 | Ubuntu 16.04 30 | ``` 31 | echo "deb [ arch=amd64,arm64 ] http://repo.mongodb.org/apt/ubuntu xenial/mongodb-org/3.4 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-3.4.list 32 | ``` 33 | #### 3.更新本地包数据库 34 | ``` 35 | sudo apt-get update 36 | ``` 37 | #### 4.安装最新版本的MongoDB 38 | ``` 39 | sudo apt-get install -y mongodb-org 40 | ``` 41 | 然后`mongo`启动MongoDB. 42 | 如果发生以下报错: 43 | ``` 44 | connect@src/mongo/shell/mongo.js:240:13 45 | @(connect):1:6 46 | exception: connect failed 47 | ``` 48 | 解决方案: 49 | [connection attempt failed ](https://blog.csdn.net/weixin_40612082/article/details/81568915?utm_source=blogxgwz1) 50 | #### 5.查看配置文件 51 | 52 | 配置文件`mongod.conf`所在路径: 53 | ``` 54 | /etc/mongod.conf 55 | ``` 56 | 内容: 57 | ``` 58 | # mongod.conf 59 | 60 | # for documentation of all options, see: 61 | # http://docs.mongodb.org/manual/reference/configuration-options/ 62 | 63 | # Where and how to store data. 64 | storage: 65 | dbPath: /var/lib/mongodb #数据库存储路径 66 | journal: 67 | enabled: true 68 | # engine: 69 | # mmapv1: 70 | # wiredTiger: 71 | 72 | 73 | # where to write logging data. 74 | systemLog: 75 | destination: file 76 | logAppend: true #以追加的方式写入日志 77 | path: /var/log/mongodb/mongod.log #日志文件路径 78 | 79 | # network interfaces 80 | net: 81 | port: 27017 82 | bindIp: 127.0.0.1 #绑定监听的ip 127.0.0.1只能监听本地的连接,可以改为0.0.0.0 83 | 84 | 85 | #processManagement: 86 | 87 | #security: 88 | 89 | #operationProfiling: 90 | 91 | #replication: 92 | 93 | #sharding: 94 | 95 | ## Enterprise-Only Options: 96 | 97 | #auditLog: 98 | 99 | #snmp: 100 | ``` 101 | #### 6.启动和关闭MongoDB 102 | ``` 103 | sudo service mongod start # 启动 104 | sudo service mongod stop # 关闭 105 | 106 | 107 | ps aux | grep mongod # 查看守护进程mongod的运行状态 108 | root 5997 0.0 0.0 14656 2100 tty1 T 15:45 0:00 sudo mongod 109 | root 5998 1.7 0.2 946052 19916 tty1 Tl 15:45 0:36 mongod 110 | root 6044 0.0 0.0 12892 1112 tty1 S 16:20 0:00 grep --color=auto mongod 111 | ``` 112 | #### 7.卸载 113 | 1.关闭守护进程`mongod` 114 | ``` 115 | sudo service mongod stop 116 | ``` 117 | 2.卸载安装的软件包 118 | ``` 119 | sudo apt-get purge mongodb-org* 120 | ``` 121 | 3.移除数据库和日志文件(数据库和日志文件的路径取决于`/etc/mongod.conf`文件中的配置) 122 | ``` 123 | sudo rm -r /var/log/mongodb 124 | sudo rm -r /var/lib/mongodb 125 | ``` 126 | -------------------------------------------------------------------------------- /学习笔记/NetWorking/TCP建立连接的三次握手.md: -------------------------------------------------------------------------------- 1 | ## TCP协议建立连接的三次握手过程: 2 | ### 假设此时,我们客户机需要与服务器建立连接。那么A就会向B发出连接请求报文段,其首部中的同步位 SYN = 1,并选择序号 seq = x,表明传送数据时的第一个数据字节的序号是 x。这就是第一次握手: 3 | ![xxx](https://github.com/LzyRapx/Notes/blob/master/NetWorking/img/1.png) 4 | 5 | ### 接下来,服务器需要对客户机的连接请求报文段做出回应,这里我们假设服务器同意客户机的连接请求,则B 在确认报文段中应使 SYN = 1,使 ACK = 1,其确认号ack = x + 1,自己选择的序号 seq = y。这就是第二次握手: 6 | ![xxx](https://github.com/LzyRapx/Notes/blob/master/NetWorking/img/2.png) 7 | 8 | ### A 收到此报文段后向 B 给出确认,其 ACK = 1,确认号 ack = y+1。与此同时,A的TCP告诉向上层应用进程,连接已经建立。这就是第三次握手: 9 | ![xxx](https://github.com/LzyRapx/Notes/blob/master/NetWorking/img/3.png) 10 | 11 | ### 而当B收到A的确认报文后,也将向上层应用报告,连接已经建立,此时客户机与服务器之间就可以传输数据了。 12 | ![xxx](https://github.com/LzyRapx/Notes/blob/master/NetWorking/img/4.png) 13 | 14 | ## Tips: 15 | ### 对于客户机和服务器的定义并不是绝对的,我们将主动发起连接的一方叫做客户机,将能够应答的一方称为服务器, 如果TCP连接同时打开,那么双方将既是客户机又是服务器。 16 | ### ACK位和ack位的意义是不一样的,前者只有0/1两个值,1表示这是一个确认报文,后者则表示在此序号之前的数据都已经收到,现在期望收到序号为此值得数据。 17 | ### ack是对对方发来数据的确认号,而seq则是自己发送的数据的序号。 18 | ### SYN(同步位)仅在建立连接的前两个报文段中使用。 19 | ### SYN置1的报文段虽然不携带数据,但也要消耗掉一个序号。 20 | -------------------------------------------------------------------------------- /学习笔记/NetWorking/TCP释放连接的四次挥手.md: -------------------------------------------------------------------------------- 1 | ## TCP释放连接的四次挥手过程 2 | 3 | ### 数据传输结束后,通信的双方都可释放连接。假设现在 A 的应用进程先向其 TCP 发出连接释放报文段,并停止再发送数据,主动关闭 TCP连接。A 把连接释放报文段首部的 FIN = 1,其序号seq = u,等待 B 的确认。这是第一次挥手: 4 | ![xxx](https://github.com/LzyRapx/Notes/blob/master/NetWorking/img/5.png) 5 | 6 | ### B 发出确认,确认号 ack = u+1,而这个报文段自己的序号 seq = v。TCP 服务器进程通知高层应用进程。从 A 到 B 这个方向的连接就释放了,TCP 连接处于半关闭状态。B 若发送数据,A 仍要接收(此段Tips中有详细解释)。这是第二次挥手: 7 | ![xxx](https://github.com/LzyRapx/Notes/blob/master/NetWorking/img/6.png) 8 | 9 | ### 假设到某一时刻B 已经没有要向 A 发送的数据,其应用进程就通知 TCP 释放连接。携带位FIN = 1, ACK = 1, seq = w, ack= u+1。这是第三次挥手: 10 | ![xxx](https://github.com/LzyRapx/Notes/blob/master/NetWorking/img/7.png) 11 | 12 | ### A 收到连接释放报文段后,必须发出确认。ACK = 1, seq = u + 1, ack = w+1。这是第四次挥手: 13 | ![xxx](https://github.com/LzyRapx/Notes/blob/master/NetWorking/img/8.png) 14 | 15 | ## Tips: 16 | ### 客户机与服务器之间,谁有关闭连接的需求,谁就要发送带FIN位的报文段 17 | ### 半关闭状态:数据的传输方向将变为单向,只能由被动关闭方向主动关闭方传输数据 18 | ### TCP连接的真正关闭并不是在第四次挥手之后马上进行,而是要等待时间 2MSL(最大报文段生存周期) 后才真正释放掉。这种机制是为了: 19 | ### 一,为了保证 A 发送的最后一个 ACK 报文段能够到达 B。 20 | ### 二,防止 “已失效的连接请求报文段”出现在本连接中。A 在发送完最后一个 ACK 报文段后,再经过时间 2MSL,就可以使本连接持续的时间内所产生的所有报文段,都从网络中消失。这样就可以使下一个新的连接中不会出现这种旧的连接请求报文段。 21 | -------------------------------------------------------------------------------- /学习笔记/NetWorking/img/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzyrapx/Notes/9d7665195e6ae4807f9b77edb529f3a35e768542/学习笔记/NetWorking/img/1.png -------------------------------------------------------------------------------- /学习笔记/NetWorking/img/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzyrapx/Notes/9d7665195e6ae4807f9b77edb529f3a35e768542/学习笔记/NetWorking/img/2.png -------------------------------------------------------------------------------- /学习笔记/NetWorking/img/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzyrapx/Notes/9d7665195e6ae4807f9b77edb529f3a35e768542/学习笔记/NetWorking/img/3.png -------------------------------------------------------------------------------- /学习笔记/NetWorking/img/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzyrapx/Notes/9d7665195e6ae4807f9b77edb529f3a35e768542/学习笔记/NetWorking/img/4.png -------------------------------------------------------------------------------- /学习笔记/NetWorking/img/5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzyrapx/Notes/9d7665195e6ae4807f9b77edb529f3a35e768542/学习笔记/NetWorking/img/5.png -------------------------------------------------------------------------------- /学习笔记/NetWorking/img/6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzyrapx/Notes/9d7665195e6ae4807f9b77edb529f3a35e768542/学习笔记/NetWorking/img/6.png -------------------------------------------------------------------------------- /学习笔记/NetWorking/img/7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzyrapx/Notes/9d7665195e6ae4807f9b77edb529f3a35e768542/学习笔记/NetWorking/img/7.png -------------------------------------------------------------------------------- /学习笔记/NetWorking/img/8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzyrapx/Notes/9d7665195e6ae4807f9b77edb529f3a35e768542/学习笔记/NetWorking/img/8.png -------------------------------------------------------------------------------- /学习笔记/NetWorking/面试题(1 - 25).md: -------------------------------------------------------------------------------- 1 | ### 1. TCP和UDP能同时使用同一个端口吗? 2 | ``` 3 | 可以。TCP 和 UDP 的端口是不冲突的,各收各的。 而且很多标准服务都是 TCP 和 UDP 在相同的端口提供相同的服务。 4 | UDP是无连接的数据报文接收,没有监听。TCP和UDP端口可以共用,互不影响。 5 | ``` 6 | [TCP和UDP同时监听同一个端口](https://bbs.csdn.net/topics/390809227) (可以同时监听,他们互不影响) 7 | 8 | [Can TCP and UDP sockets use the same port?](https://stackoverflow.com/questions/6437383/can-tcp-and-udp-sockets-use-the-same-port) 9 | 10 | ### 2. 输入网址到页面显示之间发生了什么? 11 | [输入网址到页面显示之间发生了什么](https://www.jianshu.com/p/c2050fa5fb94) 12 | 13 | ### 3.CDN(内容分发网络) 14 | [CDN概念基本介绍](https://www.cnblogs.com/xinxiucan/p/7832368.html) 15 | 16 | ### 4.https怎么实现安全通信的? 17 | [web基础系列(五)---https是如何实现安全通信的](https://www.cnblogs.com/-new/p/7663746.html) 18 | 19 | ### 5.tcp和udp的区别? 20 | ``` 21 | TCP---传输控制协议,提供的是面向连接、可靠的字节流服务。 22 | 当客户和服务器彼此交换数据前,必须先在双方之间建立一个TCP连接,之后才能传输数据。 23 | TCP提供超时重发,丢弃重复数据,检验数据,流量控制等功能,保证数据能从一端传到另一端。 24 | 25 | UDP---用户数据报协议,是一个简单的面向数据报的运输层协议。 26 | UDP不提供可靠性,它只是把应用程序传给IP层的数据报发送出去,但是并不能保证它们能到达目的地。 27 | 由于UDP在传输数据报前不用在客户和服务器之间建立一个连接,且没有超时重发等机制,故而传输速度很快. 28 | 29 | ``` 30 | ``` 31 | 1、TCP面向连接(如打电话要先拨号建立连接);UDP是无连接的,即发送数据之前不需要建立连接 32 | 33 | 2、TCP提供可靠的服务。也就是说,通过TCP连接传送的数据,无差错,不丢失,不重复,且按序到达; 34 | UDP尽最大努力交付,即不保证可靠交付 35 | Tcp通过校验和,重传控制,序号标识,滑动窗口、确认应答实现可靠传输。 36 | 如丢包时的重发控制,还可以对次序乱掉的分包进行顺序控制。 37 | 38 | 3、UDP具有较好的实时性,工作效率比TCP高,适用于对高速传输和实时性有较高的通信或广播通信。 39 | 40 | 4.每一条TCP连接只能是点到点的;UDP支持一对一,一对多,多对一和多对多的交互通信 41 | 42 | 5、TCP对系统资源要求较多,UDP对系统资源要求较少。 43 | ``` 44 | [TCP和UDP的区别和优缺点](https://blog.csdn.net/xiaobangkuaipao/article/details/76793702) 45 | 46 | ### 6.tcp协议如何实现(保证)可靠传输? 47 | ``` 48 | 一. 可靠传输的工作原理————停止等待协议 49 | 1. 使用确认和重传机制,我们就可以在不可靠的传输网络上实现可靠的通信 50 | 2. 这种可靠传输协议常称为自动重传请求ARQ(Automatic Repeat reQuest)。 51 | 3.停止等待协议的优点是简单,缺点是信道利用率太低。 52 | 二.连续 ARQ 协议 53 | 1.可靠的流水线传输需要滑动窗口技术 54 | 2.滑动窗口协议比较复杂,是 TCP 协议的精髓所在。 55 | 3.发送方维持的发送窗口,它的意义是:位于发送窗口内的分组都可连续发送出去,而不需要等待对方的确认。这样,信道利用率就提高了。 56 | 4.连续 ARQ 协议规定,发送方每收到一个确认,就把发送窗口向前滑动一个分组的位置。 57 | ``` 58 | [TCP协议如何实现可靠传输](https://blog.csdn.net/i_am_good_boy/article/details/79599893) 59 | 60 | ### 7. 确认和重传/拥塞控制? 61 | [TCP的超时重传机制与拥塞避免](https://blog.csdn.net/ahafg/article/details/51058467) 62 | 63 | ### 8.确认和重传机制下如果1,2,4,5号的ACK收到了,3号丢失,那么发送端仅重发3还是全部重发3,4,5? 64 | ``` 65 | 仅重发3. 66 | ``` 67 | [快速重传机制与SACK、D-SACK](https://www.cnblogs.com/superpig0501/p/3983464.html) 68 | 69 | ### 9.http状态码? 70 | 71 | [HTTP状态码](https://baike.baidu.com/item/HTTP%E7%8A%B6%E6%80%81%E7%A0%81/5053660?fr=aladdin) 72 | 73 | ### 10.HTTP与HTTPS有什么区别? 74 | ``` 75 | HTTP协议传输的数据都是未加密的,也就是明文的,因此使用HTTP协议传输隐私信息非常不安全,为了保证这些隐私数据能加密传输, 76 | 于是网景公司设计了SSL(Secure Sockets Layer)协议用于对HTTP协议传输的数据进行加密,从而就诞生了HTTPS。 77 | 简单来说,HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,要比http协议安全。 78 |   HTTPS和HTTP的区别主要如下: 79 |   1、https协议需要到ca申请证书,一般免费证书较少,因而需要一定费用。 80 |   2、http是超文本传输协议,信息是明文传输,https则是具有安全性的ssl加密传输协议。 81 |   3、http和https使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443。 82 |   4、http的连接很简单,是无状态的;HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,比http协议安全。 83 | ``` 84 | ### 11.对称密钥? 85 | ``` 86 | 对称密钥(Symmetric-key algorithm)又称为共享密钥加密,对称密钥在加密和解密的过程中使用的密钥是相同的。 87 | 常见的对称加密算法有DES、3DES、AES、RC5、RC6。对称密钥的优点是计算速度快,但是他也有缺点,密钥需要在通讯的两端共享, 88 | 让彼此知道密钥是什么对方才能正确解密,如果所有客户端都共享同一个密钥,那么这个密钥就像万能钥匙一样, 89 | 可以凭借一个密钥破解所有人的密文了,如果每个客户端与服务端单独维护一个密钥, 90 | 那么服务端需要管理的密钥将是成千上万,这会给服务端带来噩梦。 91 | ``` 92 | ### 12.非对称密钥? 93 | ``` 94 | 非对称密钥(public-key cryptography),又称为公开密钥加密,服务端会生成一对密钥,一个私钥保存在服务端,仅自己知道, 95 | 另一个是公钥,公钥可以自由发布供任何人使用。客户端的明文通过公钥加密后的密文需要用私钥解密。 96 | 非对称密钥在加密和解密的过程的使用的密钥是不同的密钥,加密和解密是不对称的,所以称之为非对称加密。 97 | 与对称密钥加密相比,非对称加密无需在客户端和服务端之间共享密钥,只要私钥不发给任何用户, 98 | 即使公钥在网上被截获,也无法被解密,仅有被窃取的公钥是没有任何用处的。 99 | 100 | 常见的非对称加密有RSA。 101 | 102 | 非对称加解密的过程: 103 | 104 | 1.服务端生成配对的公钥和私钥. 105 | 2.私钥保存在服务端,公钥发送给客户端. 106 | 3.客户端使用公钥加密明文传输给服务端. 107 | 4.服务端使用私钥解密密文得到明文. 108 | 109 | ``` 110 | ### 13.数字签名(Digital Signature)? 111 | ``` 112 | 数据在浏览器和服务器之间传输时,有可能在传输过程中被冒充的盗贼把内容替换了, 113 | 那么如何保证数据是真实服务器发送的而不被调包呢,同时如何保证传输的数据没有被人篡改呢, 114 | 要解决这两个问题就必须用到数字签名,数字签名就如同日常生活的中的签名一样,一旦在合同书上落下了你的大名, 115 | 从法律意义上就确定是你本人签的字儿,这是任何人都没法仿造的,因为这是你专有的手迹,任何人是造不出来的。 116 | 那么在计算机中的数字签名怎么回事呢? 117 | 数字签名就是用于验证传输的内容是不是真实服务器发送的数据,发送的数据有没有被篡改过, 118 | 它就干这两件事,是非对称加密的一种应用场景。 119 | 不过他是反过来用私钥来加密,通过与之配对的公钥来解密。 120 | ``` 121 | -------------------------------------------------------------------------------- /学习笔记/Node.js/cluster/Example/process.js: -------------------------------------------------------------------------------- 1 | var cluster= require('cluster') 2 | console.log('start master with ' + process.pid) 3 | 4 | //新建一个worker线程 5 | cluster.fork(); 6 | 7 | /* 8 | 主进程监听SIGHUP事件,如果发生该事件就关闭其他所有worker进程。 9 | 之所以是SIGHUP事件,是因为nginx服务器监听到这个信号,会创造一个新的worker进程,重新加载配置文件。 10 | 另外,关闭worker进程时,主进程发送SIGTERM信号,这是因为Node允许多个worker进程监听同一个端口。 11 | */ 12 | process.on('SIGHUP',function () { 13 | console.log("reloadding......"); 14 | var new_worker = cluster.fork(); 15 | 16 | new_worker.once("listening",function() { 17 | // 关闭所有其他worker的进程 18 | for(var id in cluster.workers) { 19 | if(id === new_worker.id.toString()) continue; 20 | cluster.workers[id].kill('SIGTERM') 21 | } 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /学习笔记/Node.js/cluster/Example/server.js: -------------------------------------------------------------------------------- 1 | var cluster = require('cluster') 2 | 3 | // 如果是主线程 4 | if(cluster.isMaster) { 5 | require('./process.js'); 6 | return; 7 | } 8 | 9 | var express = require('express'); 10 | var http = require('http'); 11 | var app = express(); 12 | 13 | app.get('/',function (req,res) { 14 | res.end('how cruel the world!'); 15 | }); 16 | 17 | http.createServer(app).listen(8080,function () { 18 | console.log('http://localhost:8080'); 19 | }); 20 | -------------------------------------------------------------------------------- /学习笔记/Node.js/cluster/master.js: -------------------------------------------------------------------------------- 1 | 2 | var cluster = require('cluster'); 3 | var http = require('http') 4 | if(cluster.isMaster) { // 判断当前进程是否为主进程 5 | // 如果是,就按照CPU的核数,新建若干个worker进程 6 | var numWorkers = require('os').cpus().length; 7 | console.log('Master cluster setting up ' + numWorkers + ' workers...'); 8 | 9 | for(var i = 0; i < numWorkers; i++) { 10 | cluster.fork(); 11 | } 12 | // 在主进程部署online事件和exit事件的监听函数 13 | cluster.on('online', function(worker) { 14 | console.log('Worker ' + worker.process.pid + ' is online'); 15 | }); 16 | // 主进程一旦监听到worker进程的exit事件,就会重启一个worker进程。 17 | // worker进程一旦启动成功,可以正常运行了,就会发出online事件 18 | cluster.on('exit', function(worker, code, signal) { 19 | console.log('Worker ' + worker.process.pid + ' died with code: ' + code + ', and signal: ' + signal); 20 | console.log('Starting a new worker'); 21 | cluster.fork(); 22 | }); 23 | } 24 | else { 25 | // do something 26 | // 如果不是,说明当前进程是worker进程,则在该进程启动一个服务器程序 27 | http.createServer(function (req,res) { 28 | res.writeHead(200); 29 | res.end('Hello World!!!'); 30 | }).listen(8000); 31 | } 32 | // process.exit(0); 33 | 34 | -------------------------------------------------------------------------------- /学习笔记/Node.js/http/Example/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | How cruel the world!!! 9 | 10 | 11 | -------------------------------------------------------------------------------- /学习笔记/Node.js/http/Example/server.js: -------------------------------------------------------------------------------- 1 | let http = require('http'); 2 | let url = require('url'); 3 | let util = require('util'); 4 | let fs = require('fs'); 5 | 6 | let server = http.createServer((req,res)=>{ 7 | var pathname = url.parse(req.url).pathname; // 获取url的pathname (/index.html) 8 | console.log("file:"+ pathname.substring(1)) // 将‘/’去掉 9 | fs.readFile(pathname.substring(1), function (err,data) { // fs模块加载文件 10 | if(err){ 11 | res.writeHead(404,{ 12 | 'Content-Type':'text/html' 13 | }); 14 | }else{ 15 | res.writeHead(200,{ 16 | 'Content-Type':'text/html' 17 | }); 18 | res.write(data.toString()); 19 | } 20 | res.end(); 21 | }); 22 | 23 | }); 24 | 25 | server.listen(8888,'127.0.0.1', ()=>{ 26 | console.log("服务器已经运行,请打开浏览,输入:http://127.0.0.1:8888/index.html 来进行访问.") 27 | }); 28 | -------------------------------------------------------------------------------- /学习笔记/Node.js/http/app.js: -------------------------------------------------------------------------------- 1 | 2 | var cluster = require('cluster'); 3 | var http = require('http'); // 加载http模块 4 | 5 | 6 | http.createServer(function (request,response) { // 调用http模块的createServer方法,创造一个服务器实例 7 | response.writeHead(200,{'Content-Type':'text/plain'}); 8 | response.write("How cruel the world!!!"); 9 | response.end(); 10 | }).listen(8080,'127.0.0.1'); 11 | /* 12 | ceateServer方法接受一个函数作为参数,该函数的request参数是一个对象,表示客户端的HTTP请求; 13 | response参数也是一个对象,表示服务器端的HTTP回应。 14 | response.writeHead方法用来写入HTTP回应的头信息; 15 | response.end方法用来写入HTTP回应的具体内容,以及回应完成后关闭本次对话。 16 | 最后的listen(8080)表示启动服务器实例,监听本机的8080端口。 17 | */ 18 | console.log("server running on port 8080"); 19 | 20 | // http://127.0.0.1:8080/,网页显示"How cruel the world!!!" 21 | -------------------------------------------------------------------------------- /学习笔记/Online_tmp/README.md: -------------------------------------------------------------------------------- 1 | QwQ 2 | -------------------------------------------------------------------------------- /学习笔记/Online_tmp/largeint_struct.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace std; 6 | 7 | const int MAXN = 30000; 8 | 9 | struct LargeInteger { 10 | public: 11 | // 去除前导零 12 | void cleanLeadZero(); 13 | // 乘以10的n次方 14 | void multiplyTen(int n); 15 | // 除以10的n次方 16 | void divisionTen(int n); 17 | // 将结果转换成字符串 18 | string str() const; 19 | 20 | LargeInteger(); 21 | LargeInteger(int); 22 | LargeInteger(const char *); 23 | // 截取整数的前n位数 24 | LargeInteger getSub(int n) const; 25 | 26 | LargeInteger operator=(const char *); 27 | LargeInteger operator=(int num); 28 | 29 | LargeInteger operator+(const LargeInteger &) const; 30 | LargeInteger operator-(const LargeInteger &) const; 31 | LargeInteger operator*(const LargeInteger &) const; 32 | LargeInteger operator/(const LargeInteger &) const; 33 | LargeInteger operator%(const LargeInteger &) const; 34 | LargeInteger operator-=(const LargeInteger &); 35 | LargeInteger operator+=(const LargeInteger &); 36 | LargeInteger operator*=(const LargeInteger &); 37 | LargeInteger operator/=(const LargeInteger &); 38 | // 重载比较运算符 39 | bool operator<(const LargeInteger &) const; 40 | bool operator>(const LargeInteger &) const; 41 | bool operator<=(const LargeInteger &) const; 42 | bool operator>=(const LargeInteger &) const; 43 | bool operator==(const LargeInteger &) const; 44 | // 重载输入输出流 45 | friend istream &operator>>(istream &, LargeInteger &); 46 | friend ostream &operator<<(ostream &, LargeInteger &); 47 | 48 | private: 49 | int s[MAXN]; 50 | int len; 51 | }; 52 | 53 | void LargeInteger::cleanLeadZero() { 54 | while (len > 1 && !s[len - 1]) len--; 55 | } 56 | 57 | void LargeInteger::divisionTen(int n) { 58 | int i; 59 | if (n > len) { 60 | while (len >= 1) s[len--] = 0; 61 | } else { 62 | for (i = 0; i < len - n; i++) { 63 | s[i] = s[i + n]; 64 | } 65 | len -= n; 66 | } 67 | } 68 | 69 | void LargeInteger::multiplyTen(int n) { 70 | if (n > 0) { 71 | int i; 72 | for (i = len - 1; i >= 0; i--) { 73 | s[i + n] = s[i]; 74 | } 75 | for (i = 0; i < n; i++) { 76 | s[i] = 0; 77 | } 78 | len += n; 79 | } 80 | } 81 | 82 | string LargeInteger::str() const { 83 | string res = ""; 84 | // 每个位的数逆序添加到str末尾。 85 | for (int i = 0; i < len; i++) { 86 | res = (char)(s[i] + '0') + res; 87 | } 88 | if (res == "") res = "0"; 89 | return res; 90 | } 91 | 92 | LargeInteger::LargeInteger() { 93 | memset(s, 0, sizeof(s)); 94 | len = 1; 95 | } 96 | 97 | LargeInteger::LargeInteger(int num) { *this = num; } 98 | 99 | LargeInteger::LargeInteger(const char *num) { *this = num; } 100 | 101 | LargeInteger LargeInteger::getSub(int n) const { 102 | LargeInteger c; 103 | c.len = 0; 104 | for (int i = 0; i < n; i++) { 105 | c.s[c.len++] = s[len - n + i]; 106 | } 107 | return c; 108 | } 109 | 110 | LargeInteger LargeInteger::operator=(const char *num) { 111 | len = strlen(num); 112 | for (int i = 0; i < len; i++) { 113 | s[i] = num[len - i - 1] - '0'; 114 | } 115 | return *this; 116 | } 117 | 118 | LargeInteger LargeInteger::operator=(int num) { 119 | char s[MAXN]; 120 | sprintf(s, "%d", num); 121 | *this = s; 122 | return *this; 123 | } 124 | 125 | LargeInteger LargeInteger::operator+(const LargeInteger &x) const { 126 | LargeInteger r; 127 | r.len = 0; 128 | 129 | int i, up; 130 | int maxLen = max(len, x.len); 131 | for (i = 0, up = 0; up || i < maxLen; i++) { 132 | int temp = up; 133 | if (i < len) temp += s[i]; 134 | if (i < x.len) temp += x.s[i]; 135 | up = temp / 10; 136 | r.s[r.len++] = temp % 10; 137 | } 138 | // 去除前导零 139 | r.cleanLeadZero(); 140 | return r; 141 | } 142 | 143 | 144 | LargeInteger LargeInteger::operator-(const LargeInteger &b) const { 145 | LargeInteger c; 146 | c.len = 0; 147 | int i; 148 | // 保存退位 149 | int down; 150 | for (i = 0, down = 0; i < len; i++) { 151 | int temp = s[i] - down; 152 | if (i < b.len) temp -= b.s[i]; 153 | if (temp >= 0) 154 | down = 0; 155 | else { 156 | down = 1; 157 | temp += 10; 158 | } 159 | c.s[c.len++] = temp; 160 | } 161 | c.cleanLeadZero(); 162 | return c; 163 | } 164 | 165 | LargeInteger LargeInteger::operator*(const LargeInteger &b) const { 166 | int i, j; 167 | LargeInteger c; 168 | c.len = len + b.len; 169 | for (i = 0; i < len; i++) { 170 | for (j = 0; j < b.len; j++) { 171 | c.s[i + j] += s[i] * b.s[j]; 172 | } 173 | } 174 | 175 | for (i = 0; i < c.len - 1; i++) { 176 | c.s[i + 1] += c.s[i] / 10; 177 | c.s[i] %= 10; 178 | } 179 | c.cleanLeadZero(); 180 | return c; 181 | } 182 | 183 | LargeInteger LargeInteger::operator/(const LargeInteger &b) const { 184 | int i, j; 185 | LargeInteger r; 186 | r.len = 0; 187 | // 模拟除法的过程 188 | // 先取blen - 1位 189 | LargeInteger temp = this->getSub(b.len - 1); 190 | for (i = len - b.len; i >= 0; i--) { 191 | temp = temp * 10 + s[i]; 192 | if (temp < b) { 193 | r.s[r.len++] = 0; 194 | } else { 195 | for (j = 1; j <= 10; j++) { 196 | if (b * j > temp) break; 197 | } 198 | r.s[r.len++] = j - 1; 199 | temp = temp - (b * (j - 1)); 200 | } 201 | } 202 | for (i = 0; i < r.len / 2; i++) { 203 | int temp = r.s[i]; 204 | r.s[i] = r.s[r.len - 1 - i]; 205 | r.s[r.len - 1 - i] = temp; 206 | } 207 | r.cleanLeadZero(); 208 | return r; 209 | } 210 | 211 | LargeInteger LargeInteger::operator%(const LargeInteger &b) const { 212 | LargeInteger r; 213 | r = *this / b; 214 | r = *this - r * b; 215 | return r; 216 | } 217 | 218 | LargeInteger LargeInteger::operator+=(const LargeInteger &b) { 219 | *this = *this + b; 220 | return *this; 221 | } 222 | 223 | LargeInteger LargeInteger::operator-=(const LargeInteger &b) { 224 | *this = *this - b; 225 | return *this; 226 | } 227 | 228 | LargeInteger LargeInteger::operator*=(const LargeInteger &b) { 229 | *this = *this * b; 230 | return *this; 231 | } 232 | 233 | LargeInteger LargeInteger::operator/=(const LargeInteger &b) { 234 | *this = *this / b; 235 | return *this; 236 | } 237 | 238 | bool LargeInteger::operator<(const LargeInteger &b) const { 239 | if (len != b.len) 240 | return len < b.len; 241 | else { 242 | for (int i = len - 1; i >= 0; i--) { 243 | if (s[i] != b.s[i]) return s[i] < b.s[i]; 244 | } 245 | } 246 | return false; 247 | } 248 | 249 | bool LargeInteger::operator>(const LargeInteger &b) const { return b < *this; } 250 | 251 | bool LargeInteger::operator<=(const LargeInteger &b) const { return !(b > *this); } 252 | 253 | bool LargeInteger::operator>=(const LargeInteger &b) const { return !(*this < b); } 254 | 255 | bool LargeInteger::operator==(const LargeInteger &b) const { 256 | return !(b < *this) && !(b > *this); 257 | } 258 | 259 | istream &operator>>(istream &in, LargeInteger &x) { 260 | string s; 261 | in >> s; 262 | x = s.c_str(); 263 | return in; 264 | } 265 | 266 | ostream &operator<<(ostream &out, LargeInteger &x) { 267 | out << x.str(); 268 | return out; 269 | } 270 | -------------------------------------------------------------------------------- /学习笔记/Online_tmp/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "largeint_struct.hpp" 5 | 6 | using namespace std; 7 | 8 | // const int MAXN = 30000; 9 | 10 | // 如果采⽤下⾯⽅式来实现,则可能会得到更⾼的分数 11 | 12 | /* 13 | // Declaration 14 | struct LargeInteger { 15 | LargeInteger(const string& val); 16 | LargeInteger operator+(const LargeInteger& rhs); 17 | LargeInteger operator-(const LargeInteger& rhs); 18 | LargeInteger operator*((const LargeInteger& rhs); 19 | LargeInteger operator/(const LargeInteger& rhs); 20 | priavate: 21 | // Underlying data storage 22 | }; 23 | */ 24 | 25 | // 使用了加分项的方法。 若使⽤此⽅法,请包含头⽂件 largeint_struct.hpp 26 | 27 | void print_main_menu() { 28 | cout << "1. add" << endl; 29 | cout << "2. minus" << endl; 30 | cout << "3. multiply" << endl; 31 | cout << "4. divide" << endl; 32 | } 33 | char a[MAXN], b[MAXN]; 34 | char op; 35 | int main(int argc, char const *argv[]) { 36 | // Print the main menu 37 | print_main_menu(); 38 | // Please insert your code here... 39 | 40 | int type; 41 | 42 | printf("Please enter your selection: \n"); 43 | printf("choose a function: 1-4: \n"); 44 | std::cin >> type; 45 | if(type > 4 || type < 1) { 46 | std::cout << "error input!" << '\n'; 47 | return 0; 48 | } 49 | if(type == 1) { 50 | op = '+'; 51 | std::cout << "module: add" << '\n'; 52 | std::cout << "Please enter the left hand side: "; 53 | scanf("%s", a); 54 | std::cout << "Please enter the right hand side: "; 55 | scanf("%s", b); 56 | LargeInteger aa(a); 57 | LargeInteger bb(b); 58 | //去掉前导零 59 | aa.cleanLeadZero(); 60 | bb.cleanLeadZero(); 61 | std::cout << "Result: "; 62 | cout << (aa + bb).str() << endl; 63 | } 64 | if(type == 2) { 65 | op = '-'; 66 | std::cout << "module: minus" << '\n'; 67 | std::cout << "Please enter the left hand side: "; 68 | scanf("%s", a); 69 | std::cout << "Please enter the right hand side: "; 70 | scanf("%s", b); 71 | LargeInteger aa(a); 72 | LargeInteger bb(b); 73 | aa.cleanLeadZero(); 74 | bb.cleanLeadZero(); 75 | std::cout << "Result: "; 76 | cout << (aa - bb).str() << endl; 77 | } 78 | if(type == 3) { 79 | op = '*'; 80 | std::cout << "module: multiply" << '\n'; 81 | std::cout << "Please enter the left hand side: "; 82 | scanf("%s", a); 83 | std::cout << "Please enter the right hand side: "; 84 | scanf("%s", b); 85 | LargeInteger aa(a); 86 | LargeInteger bb(b); 87 | aa.cleanLeadZero(); 88 | bb.cleanLeadZero(); 89 | std::cout << "Result: "; 90 | cout << (aa * bb).str() << endl; 91 | } 92 | if(type == 4) { 93 | op = '/'; 94 | std::cout << "module: divide" << '\n'; 95 | std::cout << "Please enter the left hand side: "; 96 | scanf("%s", a); 97 | std::cout << "Please enter the right hand side: "; 98 | scanf("%s", b); 99 | LargeInteger aa(a); 100 | LargeInteger bb(b); 101 | aa.cleanLeadZero(); 102 | bb.cleanLeadZero(); 103 | std::cout << "Result: "; 104 | cout << (aa / bb).str() << endl; 105 | } 106 | 107 | return 0; 108 | } 109 | -------------------------------------------------------------------------------- /学习笔记/Python/getopt的使用.md: -------------------------------------------------------------------------------- 1 | 在运行程序时,你可能需要根据不同的条件,输入不同的命令行选项来实现不同的功能。 2 | 目前有短选项和长选项两种格式。短选项格式为"-"加上单个字母选项;长选项为"--"加上一个单词。长格式是在Linux下引入的。 3 | 许多Linux程序都支持这两种格式。 4 | 在Python中提供了getopt模块很好的实现了对这两种用法的支持,而且使用简单。 5 | 取得命令行参数 6 | 7 | 在使用之前,首先要取得命令行参数。使用sys模块可以得到命令行参数。 8 | ``` 9 | import sys 10 | print sys.argv 11 | ``` 12 | 然后在命令行下敲入任意的参数,如: 13 | ``` 14 | python get.py -o t --help cmd file1 file2 15 | ``` 16 | 结果为: 17 | ``` 18 | ['get.py', '-o', 't', '--help', 'cmd', 'file1', 'file2'] 19 | ``` 20 | 可见,所有命令行参数以空格为分隔符,都保存在了 sys.argv 列表中。其中第1个为脚本的文件名。 21 | 22 | 选项的写法要求 23 | 24 | 对于短格式,"-"号后面要紧跟一个选项字母。如果还有此选项的附加参数,可以用空格分开,也可以不分开。长度任意,可以用引号。如以下是正确的: 25 | ``` 26 | -o 27 | -oa 28 | -obbbb 29 | -o bbbb 30 | -o "a b" 31 | ``` 32 | 对于长格式,"--"号后面要跟一个单词。如果还有些选项的附加参数,后面要紧跟"=",再加上参数。"="号前后不能有空格。如以下是正确的: 33 | ``` 34 | --help=file1 35 | ``` 36 | 而这些是不正确的: 37 | ``` 38 | -- help=file1 39 | --help =file1 40 | --help = file1 41 | --help= file1 42 | ``` 43 | 如何用getopt进行分析: 44 | 45 | 使用getopt模块分析命令行参数大体上分为三个步骤: 46 | 47 | 1.导入getopt, sys模块 48 | 2.分析命令行参数 49 | 3.处理结果 50 | 51 | 第一步很简单,只要: 52 | ``` 53 | import getopt, sys 54 | ``` 55 | 就行了。 56 | 57 | 第二步有些复杂,拿Python手册上的例子来说明: 58 | ``` 59 | try: 60 | opts, args = getopt.getopt(sys.argv[1:], "ho:", ["help", "output="]) 61 | except getopt.GetoptError: 62 | # print help information and exit: 63 | ``` 64 | 65 | 1. 处理所使用的函数叫getopt(),因为是直接使用import导入的getopt模块,所以要加上限定getopt才可以。 66 | 67 | 2. 使用sys.argv[1:]过滤掉第一个参数(它是执行脚本的名字,不应算作参数的一部分)。 68 | 69 | 3. 使用短格式分析串"ho:"。当一个选项只是表示开关状态时,即后面不带附加参数时,在分析串中写入选项字符。当选项后面是带一个附加参数时,在分析串中写入选项字符同时后面加一个":"号。所以"ho:"就表示"h"是一个开关选项;"o:"则表示后面应该带一个参数。 70 | 71 | 4. 使用长格式分析串列表:["help", "output="]。长格式串也可以有开关状态,即后面不跟"="号。如果跟一个等号则表示后面还应有一个参数。这个长格式表示"help"是一个开关选项;"output="则表示后面应该带一个参数。 72 | 73 | 5. 调用getopt函数。函数返回两个列表:opts和args。opts为分析出的格式信息。args为不属于格式信息的剩余的命令行参数。opts是一个两元组的列表。每个元素为:(选项串,附加参数)。如果没有附加参数则为空串''。 74 | 75 | 6. 整个过程使用异常来包含,这样当分析出错时,就可以打印出使用信息来通知用户如何使用这个程序。 76 | 77 | 解释一下什么是选项,什么是参数。 78 | 79 | 1).单个字符,表示选项, 80 | 81 | 2).单个字符后接一个冒号:表示该选项后必须跟一个参数。参数紧跟在选项后或者以空格隔开。该参数的指针赋给optarg。 82 | 83 | 3).单个字符后跟两个冒号,表示该选项后必须跟一个参数。参数必须紧跟在选项后不能以空格隔开。该参数的指针赋给optarg。(这个特性是GNU的扩张)。 84 | 85 | 86 | 如上面解释的一个命令行例子为: 87 | ``` 88 | '-h -o file --help --output=out file1 file2' 89 | ``` 90 | 在分析完成后,opts应该是: 91 | ``` 92 | [('-h', ''), ('-o', 'file'), ('--help', ''), ('--output', 'out')] 93 | ``` 94 | 而args则为: 95 | ``` 96 | ['file1', 'file2'] 97 | ``` 98 | 第三步也比较简单。在这一步主要是对分析出的参数进行判断是否存在,然后再进一步处理。主要的处理模式为: 99 | ``` 100 | for o, a in opts: 101 | if o in ("-h", "--help"): 102 | usage() 103 | sys.exit() 104 | if o in ("-o", "--output"): 105 | output = a 106 | ``` 107 | 使用一个循环,每次从opts中取出一个两元组,赋给两个变量。o保存选项参数,a为附加参数。接着对取出的选项参数进行处理。 108 | -------------------------------------------------------------------------------- /学习笔记/Redis/Redis各种数据类型的应用场景.md: -------------------------------------------------------------------------------- 1 | |类型|简介|特性|场景| 2 | |------:|---:|------:|---:| 3 | |String(字符串)|二进制安全|可以包含任何数据,比如jpg图片或者序列化的对象,一个键最大能存储512M|---| 4 | |Hash(字典)|键值对集合,即编程语言中的Map类型|适合存储对象,并且可以像数据库中update一个属性一样只修改某一项属性值(Memcached中需要取出整个字符串反序列化成对象修改完再序列化存回去)|存储、读取、修改用户属性| 5 | |List(列表)|链表(双向链表)|增删快,提供了操作某一段元素的API|1,最新消息排行等功能(比如朋友圈的时间线) 2,消息队列| 6 | |Set(集合)|哈希表实现,元素不重复|1,添加、删除,查找的复杂度都是O(1) 2,为集合提供了求交集、并集、差集等操作|1,共同好友 2,利用唯一性,统计访问网站的所有独立ip 3,好友推荐等时,根据tag求交集,大于某个阈值就可以推荐| 7 | |Sorted Set(有序集合)|将Set中的元素增加一个权重参数score,元素按score有序排列|数据插入集合时,已经进行天然排序 |1,排行榜 2,带权重的消息队列| 8 | -------------------------------------------------------------------------------- /学习笔记/Redis/Redis脚本(Lua解释器).md: -------------------------------------------------------------------------------- 1 | #### 1.Redis 脚本使用 Lua 解释器来执行脚本。 2 | ``` 3 | 1. eval: 执行 Lua 脚本。 4 | 2. evalsha : 执行 Lua 脚本。 5 | 3. script exists: 令用于校验指定的脚本是否已经被保存在缓存当中。 6 | 4. script flush: 从脚本缓存中移除所有脚本。 7 | 5. script kill: 杀死当前正在运行的 Lua 脚本。 8 | 6. script load:将脚本 script 添加到脚本缓存中,但并不立即执行这个脚本。 9 | ``` 10 | #### 2.Redis 2.6 版本通过内嵌支持 Lua 环境。执行脚本的常用命令为 `EVAL`。 11 | #### 3.Redis Eval 命令使用 Lua 解释器执行脚本。 12 | 13 | 14 | -------------------------------------------------------------------------------- /学习笔记/RegexExpressions/RegexJS.md: -------------------------------------------------------------------------------- 1 | 2 | ### 用户名正则,4到16位(字母,数字,下划线,减号) 3 | ``` 4 | var uPattern = /^[a-zA-Z0-9_-]{4,16}$/; 5 | ``` 6 | ``` 7 | //输出 true 8 | console.log(uPattern.test("iFat3")); 9 | ``` 10 | 11 | ### 密码强度正则,最少6位,包括至少1个大写字母,1个小写字母,1个数字,1个特殊字符 12 | ``` 13 | var pPattern = /^.*(?=.{6,})(?=.*\d)(?=.*[A-Z])(?=.*[a-z])(?=.*[!@#$%^&*? ]).*$/; 14 | ``` 15 | ``` 16 | // 输出 true 17 | console.log("=="+pPattern.test("iFat3#")); 18 | ``` 19 | ### 正整数正则 20 | ``` 21 | var posPattern = /^\d+$/; 22 | ``` 23 | 24 | ``` 25 | //输出 true 26 | console.log(posPattern.test("42")); 27 | ``` 28 | 29 | ### 负整数正则 30 | ``` 31 | var negPattern = /^-\d+$/; 32 | ``` 33 | ``` 34 | //输出 true 35 | console.log(negPattern.test("-42")); 36 | ``` 37 | ### 整数正则 38 | ``` 39 | var intPattern = /^-?\d+$/; 40 | ``` 41 | ``` 42 | //输出 true 43 | console.log(intPattern.test("-42")); 44 | ``` 45 | 46 | ### 可以是整数也可以是浮点数 47 | ### 正数正则 48 | ``` 49 | var posPattern = /^\d*\.?\d+$/; 50 | ``` 51 | ### 负数正则 52 | ``` 53 | var negPattern = /^-\d*\.?\d+$/; 54 | ``` 55 | ### 数字正则 56 | ``` 57 | var numPattern = /^-?\d*\.?\d+$/; 58 | 59 | console.log(posPattern.test("42.2")); 60 | console.log(negPattern.test("-42.2")); 61 | console.log(numPattern.test("-42.2")); 62 | ``` 63 | ### Email正则 64 | ``` 65 | var ePattern = /^([A-Za-z0-9_\-\.])+\@([A-Za-z0-9_\-\.])+\.([A-Za-z]{2,4})$/; 66 | ``` 67 | ``` 68 | //输出 true 69 | console.log(ePattern.test("65974040@qq.com")); 70 | ``` 71 | ### 手机号正则 72 | ``` 73 | var mPattern = /^[1][3][0-9]{9}$/; 74 | ``` 75 | ``` 76 | //输出 true 77 | console.log(mPattern.test("13900000000")); 78 | ``` 79 | 80 | ### 身份证号(18位)正则 81 | ``` 82 | var cP = /^[1-9]\d{5}(18|19|([23]\d))\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$/; 83 | ``` 84 | ``` 85 | //输出 true 86 | console.log(cP.test("11010519880605371X")); 87 | ``` 88 | ### URL正则 89 | ``` 90 | var urlP= /^((https?|ftp|file):\/\/)?([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w \.-]*)*\/?$/; 91 | ``` 92 | ``` 93 | //输出 true 94 | console.log(urlP.test("http://42du.cn")); 95 | ``` 96 | ### ipv4地址正则 97 | ``` 98 | var ipP = /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/; 99 | ``` 100 | ``` 101 | //输出 true 102 | console.log(ipP.test("115.28.47.26")); 103 | ``` 104 | ### RGB Hex颜色正则 105 | ``` 106 | var cPattern = /^#?([a-fA-F0-9]{6}|[a-fA-F0-9]{3})$/; 107 | ``` 108 | ``` 109 | //输出 true 110 | console.log(cPattern.test("#b8b8b8")); 111 | ``` 112 | ### 日期正则,简单判定,未做月份及日期的判定 113 | ``` 114 | var dP1 = /^\d{4}(\-)\d{1,2}\1\d{1,2}$/; 115 | ``` 116 | ``` 117 | //输出 true 118 | console.log(dP1.test("2017-05-11")); 119 | ``` 120 | ``` 121 | //输出 true 122 | console.log(dP1.test("2017-15-11")); 123 | ``` 124 | ### 日期正则,复杂判定 125 | ``` 126 | var dP2 = /^(?:(?!0000)[0-9]{4}-(?:(?:0[1-9]|1[0-2])-(?:0[1-9]|1[0-9]|2[0-8])|(?:0[13-9]|1[0-2])-(?:29|30)|(?:0[13578]|1[02])-31)|(?:[0-9]{2}(?:0[48]|[2468][048]|[13579][26])|(?:0[48]|[2468][048]|[13579][26])00)-02-29)$/; 127 | ``` 128 | ``` 129 | //输出 true 130 | console.log(dP2.test("2017-02-11")); 131 | ``` 132 | ``` 133 | //输出 false 134 | console.log(dP2.test("2017-15-11")); 135 | ``` 136 | ``` 137 | //输出 false 138 | console.log(dP2.test("2017-02-29")); 139 | ``` 140 | 141 | ### QQ号正则,5至11位 142 | ``` 143 | var qqPattern = /^[1-9][0-9]{4,10}$/; 144 | ``` 145 | ``` 146 | //输出 true 147 | console.log(qqPattern.test("65974040")); 148 | ``` 149 | 150 | ### 微信号正则,6至20位,以字母开头,字母,数字,减号,下划线 151 | ``` 152 | var wxPattern = /^[a-zA-Z]([-_a-zA-Z0-9]{5,19})+$/; 153 | ``` 154 | ``` 155 | //输出 true 156 | console.log(wxPattern.test("RuilongMao")); 157 | ``` 158 | 159 | ### 车牌号正则 160 | ``` 161 | var cPattern = /^[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领A-Z]{1}[A-Z]{1}[A-Z0-9]{4}[A-Z0-9挂学警港澳]{1}$/; 162 | ``` 163 | ``` 164 | //输出 true 165 | console.log(cPattern.test("京K39006")); 166 | ``` 167 | 168 | ### 包含中文正则 169 | ``` 170 | var cnPattern = /[\u4E00-\u9FA5]/; 171 | ``` 172 | ``` 173 | //输出 true 174 | console.log(cnPattern.test("42度")); 175 | ``` 176 | -------------------------------------------------------------------------------- /学习笔记/Tool/MacOS下的ATOM配置.md: -------------------------------------------------------------------------------- 1 | ### Mac OS (OSX)系统下配置 2 | ``` 3 | Mac下操作比较简单,只需要安装相应插件(主要是script)即可运行,其它主要插件如下, 4 | 安装完成后点击command+i就可以调用系统clang编译器编译运行程序。 5 | 6 | autocomplete-clang 在clang下 C/C++/ObjC 语言自动补全插件 7 | build,直接从Atom下编译程序、 8 | linter与其他情况类似,可以在编代码时直接看到错误和其他信息 9 | linter-clang 和linter-gcc类似,是linter的clang插件 10 | script 在Atom下运行代码 11 | ``` 12 | -------------------------------------------------------------------------------- /学习笔记/Tool/Ubuntu 16.04安装Oh-my-zsh.md: -------------------------------------------------------------------------------- 1 | 一、安装zsh 2 | ``` 3 | sudo apt-get update 4 | sudo apt-get install zsh 5 | ``` 6 | 二、修改默认shell 7 | ``` 8 | sudo chsh -s /bin/zsh 9 | ``` 10 | 修改配置文件 11 | ``` 12 | sudo gedit /etc/passwd/ 13 | ``` 14 | 将文件的第一行: 15 | ``` 16 | /bin/bash 17 | ``` 18 | 修改成: 19 | ``` 20 | /bin/zsh 21 | ``` 22 | 将文件的最后一行: 23 | ``` 24 | /home/ubuntu:bin/bash 25 | ``` 26 | 修改为: 27 | ``` 28 | /home/ubuntu:bin/zsh 29 | ``` 30 | 三、安装Oh-my-zsh 31 | 32 | 安装之前,确认安装curl或者wget,可以使用`curl –version`或者`wget –version`查看 33 | ``` 34 | sudo apt-get install curl 35 | sudo apt-get install wget 36 | ``` 37 | 之后,使用以下命令安装Oh-my-zsh 38 | ``` 39 | //via curl 40 | sh -c "$(curl -fsSL https://raw.githubusercontent.com/robbyrussell/oh-my-zsh/master/tools/install.sh)" 41 | ``` 42 | ``` 43 | //via wget 44 | sh -c "$(wget https://raw.githubusercontent.com/robbyrussell/oh-my-zsh/master/tools/install.sh -O -)" 45 | ``` 46 | 重启之后生效 47 | 48 | 四、安装插件 49 | 50 | 1.autojump 51 | ``` 52 | sudo apt-get update 53 | sudo apt-get install autojump 54 | ``` 55 | 说明文件路径在目录 56 | ``` 57 | /usr/share/doc/autojump/README.Debian 58 | ``` 59 | 打开.zshrc文件 60 | ``` 61 | sudo gedit ~/.zshrc 62 | ``` 63 | 在文件最后加上以下 64 | ``` 65 | . /usr/share/autojump/autojump.sh 66 | ``` 67 | 使配置文件生效 68 | ``` 69 | source ~/.zshrc 70 | ``` 71 | -------------------------------------------------------------------------------- /学习笔记/Tool/Ubuntu_Terminator配色.md: -------------------------------------------------------------------------------- 1 | ### terminator的配色: 2 | ``` 3 | sudo vim ~/.config/terminator/config 4 | ``` 5 | 建议第一个: 6 | ``` 7 | [global_config] 8 | handle_size = -3 9 | enabled_plugins = CustomCommandsMenu, LaunchpadCodeURLHandler, APTURLHandler, LaunchpadBugURLHandler 10 | title_transmit_fg_color = "#000000" 11 | suppress_multiple_term_dialog = True 12 | title_transmit_bg_color = "#3e3838" 13 | inactive_color_offset = 1.0 14 | [keybindings] 15 | [profiles] 16 | [[default]] 17 | palette = "#000000:#5a8e1c:#2d5f5f:#cdcd00:#1e90ff:#cd00cd:#00cdcd:#e5e5e5:#4c4c4c:#868e09:#00ff00:#ffff00:#4682b4:#ff00ff:#00ffff:#ffffff" 18 | background_image = "" 19 | background_darkness = 0.90 20 | scrollback_lines = 3000 21 | background_type = transparent 22 | use_system_font = False 23 | scroll_background = False 24 | show_titlebar = False 25 | cursor_shape = ibeam 26 | font = Liberation Mono 12 27 | background_color = "#0e2424" 28 | foreground_color = "#e8e8e8" 29 | [layouts] 30 | [[default]] 31 | [[[child1]]] 32 | type = Terminal 33 | parent = window0 34 | profile = default 35 | [[[window0]]] 36 | type = Window 37 | parent = "" 38 | size = 925, 570 39 | [plugins] 40 | ``` 41 | *** 42 | ``` 43 | [global_config] 44 | title_transmit_bg_color = "#d30102" 45 | focus = system 46 | suppress_multiple_term_dialog = True 47 | [keybindings] 48 | [profiles] 49 | [[default]] 50 | palette = "#2d2d2d:#f2777a:#99cc99:#ffcc66:#6699cc:#cc99cc:#66cccc:#d3d0c8:#747369:#f2777a:#99cc99:#ffcc66:#6699cc:#cc99cc:#66cccc:#f2f0ec" 51 | background_color = "#2D2D2D" # 背景颜色 52 | background_image = None 53 | background_darkness = 0.85 54 | cursor_color = "#2D2D2D" # 光标颜色 55 | cursor_blink = True # 光标是否闪烁 56 | foreground_color = "#EEE9E9" # 文字的颜色 57 | use_system_font = False # 是否启用系统字体 58 | font = Ubuntu Mono 13 # 字体设置,后面的数字表示字体大小 59 | copy_on_selection = True # 选择文本时同时将数据拷贝到剪切板中 60 | show_titlebar = False # 不显示标题栏,也就是 terminator 中那个默认的红色的标题栏 61 | [layouts] 62 | [[default]] 63 | [[[child1]]] 64 | type = Terminal 65 | parent = window0 66 | profile = default 67 | [[[window0]]] 68 | type = Window 69 | parent = "" 70 | [plugins] 71 | ``` 72 | ``` 73 | [global_config] 74 | title_transmit_bg_color = "#d30102" 75 | focus = system 76 | [keybindings] 77 | [profiles] 78 | [[default]] 79 | # solarized-dark 80 | #palette = "#073642:#dc322f:#859900:#b58900:#268bd2:#d33682:#2aa198:#eee8d5:#002b36:#cb4b16:#586e75:#657b83:#839496:#6c71c4:#93a1a1:#fdf6e3" 81 | #foreground_color = "#eee8d5" 82 | #background_color = "#002b36" 83 | #cursor_color = "#eee8d5" 84 | 85 | [[solarized-dark]] 86 | palette = "#073642:#dc322f:#859900:#b58900:#268bd2:#d33682:#2aa198:#eee8d5:#002b36:#cb4b16:#586e75:#657b83:#839496:#6c71c4:#93a1a1:#fdf6e3" 87 | foreground_color = "#eee8d5" 88 | background_color = "#002b36" 89 | cursor_color = "#eee8d5" 90 | 91 | [[solarized-light]] 92 | palette = "#073642:#dc322f:#859900:#b58900:#268bd2:#d33682:#2aa198:#eee8d5:#002b36:#cb4b16:#586e75:#657b83:#839496:#6c71c4:#93a1a1:#fdf6e3" 93 | background_color = "#eee8d5" 94 | foreground_color = "#002b36" 95 | cursor_color = "#002b36" 96 | 97 | [layouts] 98 | [[default]] 99 | [[[child1]]] 100 | type = Terminal 101 | parent = window0 102 | profile = solarized-dark 103 | [[[window0]]] 104 | type = Window 105 | parent = "" 106 | [plugins] 107 | ``` 108 | -------------------------------------------------------------------------------- /学习笔记/Traefik/README.md: -------------------------------------------------------------------------------- 1 | ### Traefik的两个重要特性: 2 | #### 1.自动熔断 3 | 在集群中,当某一个服务大量出现请求错误,或者请求响应时间过久,或者返回`500+`错误状态码时,我们希望可以主动剔除该服务,也就是不在将请求转发到该服务上,而这一个过程是自动完成,不需要人工执行。`Traefik` 通过配置很容易就能帮我们实现,`Traefik`可以通过定义策略来主动熔断服务。 4 | 5 | `NetworkErrorRatio() > 0.5`:监测服务错误率达到`50%`时,熔断。 6 | 7 | `LatencyAtQuantileMS(50.0) > 50`:监测延时大于`50ms`时,熔断。 8 | 9 | `ResponseCodeRatio(500, 600, 0, 600) > 0.5`:监测返回状态码为`[500-600]`在`[0-600]`区间占比超过`50%`时,熔断。 10 | 11 | ### 2.负载均衡策略 12 | 13 | `Traefik` 提供两种负载均衡策略支持。一种是 `wrr`(加权轮询调度算法),一种是 `drr`(动态加权循环调度算法)。 14 | 15 | 从`Traefik`的Web中看到提示 `Load Balancer: wrr`,默认的策略为根据权重轮询调度,从Web中可以看出,新创建的 service 权重都是一样为 1,这样的话,请求会平均分给每个服务,但是这样很多时候会出现资源分配不均衡的问题,比如由于集群中每个机器配置不一样,而且服务消耗不一样,假设 A 资源使用率已经很高,而 B 属于空闲状态,如果还是均摊到每个服务的话,会加重 A 的负荷,这时候因该有一种策略能够主动识别并分担更多流量到 B 才对。 16 | 17 | `drr` 就更加智能,它是一种动态加权轮询调度方式,它会记录一段时间内转发到 A 的请求数,跟转发到 B 的请求数对比,转发数量多,说明处理速度快,响应时间快。如果 A 处理请求速度比 B 快,那么就会调整 A 的权重,接下来的一段时间,就会转发更多请求给 A,相应的 B 的转发就少一些。整个过程都在不断的调整权重,实现请求的合理分配,从而达到资源使用最大化。 18 | 19 | -------------------------------------------------------------------------------- /学习笔记/istio/istio 中文文档.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzyrapx/Notes/9d7665195e6ae4807f9b77edb529f3a35e768542/学习笔记/istio/istio 中文文档.pdf -------------------------------------------------------------------------------- /学习笔记/istio/istio_mesh_for_microservices_r1.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzyrapx/Notes/9d7665195e6ae4807f9b77edb529f3a35e768542/学习笔记/istio/istio_mesh_for_microservices_r1.pdf -------------------------------------------------------------------------------- /学习笔记/istio/istio介绍.md: -------------------------------------------------------------------------------- 1 | #### Istio是用来连接,管理和保护微服务的平台。不改动应用代码,在环境中部署一个sidecar即可实现负载均衡,服务之间认证,监控等功能。Istio有控制面板,可以管理代理,拦截服务间通信。 2 | 3 | #### Istio目前只支持在Kubernets(K8s)部署。 4 | 5 | #### Istio可解决单体应用转型为分布式微服务架构时遇到的问题。Service mesh(服务网格)用于描述构成这些应用程序的微服务网络以及它们之间的交互。随着服务增多,服务越来越难管理,需要有服务发现,负载均衡,故障恢复,指标收集以及监控等需求。 6 | 7 | #### Istio能监测并控制微服务,主要功能有: 8 | 9 | - 流量管理。控制服务间流量和API调用流向,使得服务在网络恶劣情况下稳定。 10 | 11 | - 可观察性。了解服务依赖关系,认清流量流向,快速识别问题。 12 | 13 | - 策略执行。将组织策略应用与服务之间的互动,确保访问策略得以执行,确保资源在消费者间良好分配。策略的修改通过配置网格,而不是修改应用代码。 14 | 15 | - 服务身份和安全。为网各种的服务提供可验证身份,提供保护服务流量的能力,使其可以在不同可信度的网络上流转。 16 | 17 | - 集成和定制。策略执行组建可扩展和定制,以便与ACL,日志,监控,配额,审核等解决方案集成。 18 | 19 | #### 极大减少应用代码和策略的耦合,便于运维和迁移。 20 | -------------------------------------------------------------------------------- /学习笔记/tmp.txt: -------------------------------------------------------------------------------- 1 | https://github.com/abuhabuh/prometheus-test 2 | https://github.com/abuhabuh/prometheus-test/tree/master/client 3 | https://github.com/abuhabuh/prometheus-test/tree/master/server 4 | https://github.com/prometheus/client_python 5 | https://github.com/amitsaha/python-prometheus-demo 6 | https://github.com/amitsaha/python-prometheus-demo/tree/master/flask_app_prometheus 7 | https://github.com/Lispython/prometheus_client_example 8 | https://www.cnblogs.com/lighten/p/6900556.html 9 | https://www.w3cschool.cn/use_docker/use_docker-phr127zf.html 10 | https://github.com/pentium3/2015-ICPC-Regional/blob/f1ed2b08c1a181bf66751792c1cbc314ee2f207e/other/c%E5%A4%A7%E6%95%B0%E6%A8%A1%E6%9D%BF.txt 11 | https://blog.csdn.net/damotiansheng/article/details/51506990 12 | 13 | ------------------ 14 | https://math.stackexchange.com/questions/30638/count-the-number-of-positive-solutions-for-a-linear-diophantine-equation 15 | https://github.com/topics/acm-icpc?o=desc&s=stars 16 | -------------------------------------------------------------------------------- /读书笔记/HBase不睡觉书.md: -------------------------------------------------------------------------------- 1 | #### 1. 2 | -------------------------------------------------------------------------------- /读书笔记/亿级流量网站架构核心技术.md: -------------------------------------------------------------------------------- 1 | ### 1. 2 | -------------------------------------------------------------------------------- /读书笔记/论加班对你的危害.md: -------------------------------------------------------------------------------- 1 | ### 论加班对你的危害 2 | 3 | 1. ***习惯了熬夜:*** 大晚上回到家,洗个澡,因为常年加班,这个时间根本就不困,只能继续熬一会,然后才能睡着。 4 | 5 | 2. ***身体变差:*** 皮肤变差,内分泌失调,导致平时食欲也不好,吃什么都不香,还总容易消化不良。 6 | 7 | 3. ***家庭不和谐:*** 如果你有家庭,总加班,导致自己和家人作息习惯很不协调,平常回到家,家人都睡了。等你早上起床,家人又都出门了,这样的生活真的很累。你跟有没有家人都一样,又有什么区别呢。 8 | 9 | 4. ***没有个人提升时间:*** 每天下班的时间,完全不想干别的,只想放松休息,而且本来下班时间就不多,严重挤压了个人提升的时间。每个人都有自己的兴趣爱好,加班间接就是把这些兴趣爱好完全放弃了。 10 | 11 | 5. ***白天容易犯困:*** 白天工作没精神,爱犯困,反而一到晚上精神抖擞,其实这非常不好。 12 | 13 | 6. ***男性通宵加班易患前列腺癌:*** 通宵上班的女性和男性中,乳腺癌和前列腺癌的发病率高于日常上班人群。 14 | 15 | 7. ***让人变胖:*** 工作时间延长会使人做饭、健身以及睡觉的时间缩短,而这些因素都可能会引起肥胖。 16 | 17 | 8. ***导致脑损伤:*** 《美国流行病学杂志》上的一份报告发现,每周工作55个小时以上的中年人比每周工作不足41个小时的人更容易出现脑功能下降,包括短时记忆能力减退、回忆词语的能力下降等。该研究称,长时间工作会导致长期性的脑损伤或痴呆等病症。 18 | 19 | 9. ***容易引起心脏病:*** 据伦敦大学的一份报告显示,经常加班的人患心脏病的风险会比不加班的人高出67%。 20 | 21 | 10. ***压力大,爱焦虑:*** 正因为加班的上述影响,让你压力特别大,不能好好陪家人,干什么都很焦虑,每天睡觉也都是想到工作。 22 | 23 | 11. ***工作混乱无序:*** 人的精力有限,八小时之内不能有效完成任务,加班只会是低效率,然后就一直恶性循环。该下班时不下班,该吃饭时不吃饭,该上班时不上班 效率越来越低。 24 | 25 | 12. ***加班的产出,质量难保证:*** 加班加得头晕脑胀,工作时长和工作量上来了,但工作质量和效率却下去了,其实这种产出,还不如不要。 26 | -------------------------------------------------------------------------------- /读书笔记/软技能-代码之外的生存之道.md: -------------------------------------------------------------------------------- 1 | #### 1.作为一名(打)雇(工)员(仔)的好处和弊端 2 | | 好处 | 弊端 | 3 | | ------------- |:----------------------:| 4 | | 稳定 | 缺少自由 | 5 | | 从业之路比较轻松 | 收入封顶 | 6 | | 带薪休假 | 薪酬永远不会很高 | 7 | | 公司的各种福利 | ? | 8 | | 可以划水摸鱼 | 做啥由不得你 | 9 | 10 | #### 2.创业的好处和弊端 11 | | 好处 | 弊端 | 12 | | ------------- |:----------------------:| 13 | | 完全自由| 风险很大 | 14 | | 巨大的增(赚)值(钱)潜力 | 完全依靠自己 | 15 | | 做你想做的工作 | 需要很多其他技能 | 16 | | 没有老板 | 可能需要长时间工作 | 17 | 18 | #### 3.一些专业人士和外行的差异 19 | | 专业人士 | 外行 | 20 | | ------------- |:----------------------:| 21 | | 遵守自己的原则 | 让干什么就干什么 | 22 | | 专注于正确完成工作 | 专注于完成工作 | 23 | | 不惧怕承认自己的错,不会文过饰非 | 不懂装懂 | 24 | | 持续稳定 | 无法预测,不可靠 | 25 | | 勇于承担责任 | 回避责任 | 26 | 27 | #### 4.通过社交媒体分享的内容 28 | | 方式 | 内容 | 29 | | ------------- |:----------------------:| 30 | | 博客文章 | 转帖一些博客文章,或者自己的博客 | 31 | | 新闻报道 | 转载一些有趣的文章,尽量与你的细分领域有关,或者与软件开发有关 | 32 | | 励志文章 | 特别是鼓舞人心,积极向上的故事和文章 | 33 | | 技巧,小窍门 | 任何你所了解的特殊技巧或者知识 | 34 | | 吸引人的问题 | 可以吸引你的听众并能和观众互动的问题 | 35 | | 自己推广的一些活动 | 专注于一件事或者一个目的的活动,不要将太多内容混在一起 | 36 | * 尊重知识,转载前请联系原作者,非常建议是原创. 37 | 38 | #### 5. 教育就是当一个人把学校所学的全部忘光之后剩下的东西。 39 | 40 | #### 6. 学习应该有的过程: 学习 -> 实践 -> 初步掌握 -> 深入 -> 完全掌握 -> 教授 41 | 42 | #### 7. 十步学习法 43 | | 步骤 | 过程 | 44 | | ------------- |:----------------------:| 45 | | 第一步 | 了解全局 | 46 | | 第二步 | 确定范围 | 47 | | 第三步 | 定义目标 | 48 | | 第四步 | 寻找资源 | 49 | | 第五步 | 创建学习计划 | 50 | | 第六步 | 筛选资源 | 51 | | 第七步 | 开始学习, 浅尝辄止 | 52 | | 第八步 | 动手操作, 边学边玩 | 53 | | 第九步 | 全面操作, 学以致用 | 54 | | 第十步 | 乐为人师, 融会贯通 | 55 | 56 | --------------------------------------------------------------------------------