├── .gitignore ├── README.md ├── README_backup.md ├── basic ├── golang │ ├── gc.md │ ├── images │ │ ├── gc_1.png │ │ ├── gc_2.png │ │ ├── gc_3.png │ │ ├── gc_4.png │ │ ├── gc_6_1.png │ │ ├── gc_6_2.png │ │ ├── gc_6_3.png │ │ ├── gc_6_4.png │ │ ├── gc_6_5.png │ │ ├── gc_6_6.png │ │ └── mm_1.png │ ├── memory_management.md │ ├── source_code │ │ ├── channel.md │ │ └── images │ │ │ ├── channel_2_1_1.png │ │ │ ├── channel_3_1_1.png │ │ │ ├── channel_4.png │ │ │ ├── channel_5.png │ │ │ ├── channel_6.png │ │ │ ├── channel_7.png │ │ │ ├── channel_select_1.png │ │ │ └── channel_select_2.png │ └── 用go实现nginx反向代理及负载均衡.md └── python │ ├── basic │ ├── Python中的作用域及global用法.md │ ├── Python学习之Queue.md │ ├── images │ │ ├── 1.png │ │ ├── 2.png │ │ └── 3.png │ └── 变量对象和引用.md │ ├── concurrency │ ├── Python_多进程_进程池.md │ ├── Python之路_异步IO_队列_缓存.md │ └── Python之路_进程_线程.md │ └── requests │ ├── Python学习之Requests模块学习之一-发送请求.md │ ├── Python学习之Requests模块学习之三-进阶话题.md │ ├── Python学习之Requests模块学习之二-处理响应.md │ └── images │ ├── 23-1.png │ ├── 23-2.png │ ├── 23-3.png │ ├── 32-1.png │ ├── 32-10.png │ ├── 32-11.png │ ├── 32-12.png │ ├── 32-2.png │ ├── 32-3.png │ ├── 32-4.png │ ├── 32-5.png │ ├── 32-6.png │ ├── 32-7.png │ ├── 32-8.png │ ├── 32-9.png │ ├── 41-1.png │ ├── 41-2.png │ ├── 41-3.png │ ├── 41-4.png │ ├── 41-5.png │ ├── 41-6.png │ ├── 41-7.png │ ├── 51-1.png │ ├── 51-2.png │ ├── 51-3.png │ ├── 51-4.png │ ├── 51-5.png │ ├── 51-6.png │ ├── 51-7.png │ ├── 51-8.png │ ├── 52-1.png │ ├── 52-2.png │ └── 52-3.png ├── chinese ├── chinese_300_tang_poems │ └── 五言古诗_三十三首 │ │ └── 张九龄 │ │ └── 感遇_二首.md └── chinese_idiom.md ├── contents ├── algorithm.md ├── basic.md ├── chinese.md ├── design.md ├── framework.md ├── misc.md ├── reflection_and_summary.md └── tools.md ├── design ├── golang_analysis │ └── golang_analysis.md ├── golang_crawler │ └── golang_crawler.md ├── golang_crontab │ ├── golang_crontab.md │ └── images │ │ └── architecture.png ├── golang_pipeline │ └── golang_pipeline.md ├── order │ ├── how_xx_order_system.md │ └── images │ │ ├── order_1.png │ │ ├── order_10.png │ │ ├── order_11.png │ │ ├── order_12.png │ │ ├── order_13.png │ │ ├── order_14.png │ │ ├── order_15.png │ │ ├── order_16.png │ │ ├── order_17.png │ │ ├── order_2.png │ │ ├── order_3.png │ │ ├── order_4.png │ │ ├── order_5.png │ │ ├── order_6.png │ │ ├── order_7.png │ │ ├── order_8.png │ │ └── order_9.png └── red_envelope │ └── red_envelope.md ├── framework ├── elasticsearch │ ├── Elasticsearch环境搭建.md │ ├── images │ │ ├── ElasticSearc环境搭建-1.png │ │ ├── ElasticSearc环境搭建-2.png │ │ ├── ElasticSearc环境搭建-3.png │ │ ├── ElasticSearc环境搭建-4.png │ │ ├── ElasticSearc环境搭建-5.png │ │ ├── ElasticSearc环境搭建-6.png │ │ ├── ElasticSearc环境搭建-7.png │ │ └── ElasticSearc环境搭建-8.png │ └── 搜索引擎_Elasticsearch_pending.md └── scrapy │ ├── images │ ├── scrapy_architecture_01.png │ └── scrapy_architecture_02.png │ └── 第一步Scrapy框架原理.md ├── reflection_and_summary ├── interview │ ├── Python面试题精选.md │ ├── hw_OD.md │ ├── images │ │ ├── amino_jd.png │ │ ├── huawei_od_jd.png │ │ ├── liao_jd.png │ │ ├── liulishuo_jd.png │ │ └── shihuo_jd.png │ ├── interview.md │ ├── liulishuo.md │ ├── shihuo.md │ ├── 某不知名小厂面经.md │ ├── 某不知名小厂面经_2.md │ └── 面试-复习.md ├── misc │ └── 给学弟学妹们总的方向及建议.md └── tech │ └── cpu.md ├── tech ├── architecture │ ├── fanout_and_fanin.md │ ├── git_workflow.md │ ├── how_should_your_project_be_stratified.md │ ├── images │ │ ├── git_workflow_1.png │ │ ├── how_should_your_project_be_stratified_1.png │ │ ├── how_should_your_project_be_stratified_2.png │ │ ├── how_should_your_project_be_stratified_3.png │ │ └── how_should_your_project_be_stratified_4.png │ └── style │ │ ├── code_13.md │ │ └── images │ │ └── code_13_1.jpeg ├── distributed │ ├── algo │ │ ├── images │ │ │ └── snowflake-64bit.jpg │ │ └── 分布式id生成算法SnowFlake.md │ ├── celery │ │ ├── celery_opens_correct_way.md │ │ └── celery_source_code.md │ ├── etcd │ │ ├── etcd_function_and_principle.md │ │ ├── etcd_study_1_what_is_etcd.md │ │ ├── etcd_study_1_what_is_etcd_back.md │ │ ├── etcd_usage_golang_1.md │ │ └── etcd_usage_golang_2.md │ └── raft │ │ ├── images │ │ ├── raft_consensus_algorithm_1.png │ │ ├── raft_log_replication_1.png │ │ ├── raft_log_replication_2.png │ │ └── server_status.png │ │ ├── raft_consensus_algorithm.md │ │ ├── raft_leader_election.md │ │ └── raft_log_replication.md ├── kafka │ └── kafka.md ├── linux │ ├── Linux.md │ ├── images │ │ └── 文件传输到网络的公共数据路径演变.png │ ├── kernel_or_user_mode.md │ ├── select_poll_epoll.md │ └── 零拷贝_NIO.md ├── mysql │ ├── Mysql大表处理_pending.md │ ├── images │ │ ├── 2_索引管理_3_3_1.png │ │ ├── 3_锁管理_MySQL部分源码_4_3_2.png │ │ ├── 3_锁管理_RR_RC级别下的InnoDB的非阻塞读实现_4_3_1.png │ │ ├── 3_锁管理_对主键索引或者唯一索引是否会用Gap锁_5_2_1.png │ │ ├── 3_锁管理_对主键索引或者唯一索引是否会用Gap锁_5_2_2.png │ │ ├── 3_锁管理_对主键索引或者唯一索引是否会用Gap锁_不走索引_5_2_3.png │ │ ├── 3_锁管理_对主键索引或者唯一索引是否会用Gap锁_插入失败_5_2_5.png │ │ ├── 3_锁管理_对主键索引或者唯一索引是否会用Gap锁_插入成功_5_2_4.png │ │ └── 3_锁管理_当前读和快照读_4_2_1.png │ ├── 数据库——1_数据库架构.md │ ├── 数据库——2_索引管理.md │ ├── 数据库——3_锁管理.md │ └── 数据库优化——索引优化.md ├── network │ ├── https.md │ ├── http与https.md │ ├── images │ │ └── HTTPS数据传输过程.png │ └── tcp.md ├── nginx │ ├── nginx使用之总体简介.md │ ├── nginx使用之配置文件的组成及主配置段的指令之一.md │ └── nginx使用之配置文件的组成及主配置段的指令之二.md ├── redis │ ├── Redis的正确打开方式.md │ ├── images │ │ └── redis_pipeline_and_sync_master_slaver_1.png │ ├── redis_pipeline_and_sync_master_slaver.md │ ├── redis_so_fast.md │ └── 高并发情况下Redis做缓存的一系列问题_pending.md └── springcloud │ ├── Eureka_Server_和_Client_之间的信息维护(注册和续约).md │ ├── Eureka介绍.md │ ├── Zuul介绍.md │ └── images │ ├── eureka_intrd_1.jpg │ ├── eureka_intrd_2.jpg │ ├── zuul_intrd_1.jpg │ └── zuul_intrd_2.jpg └── tools ├── Pycharm上传到码云或者GitHub.md ├── images ├── 1.png ├── 10.png ├── 2.png ├── 3.png ├── 4.png ├── 5.png ├── 6.png ├── 7.png ├── 8.png └── 9.png └── 欢迎使用CSDN-markdown编辑器.md /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .idea/ 3 | .vscode 4 | 5 | *.prof 6 | *.pid 7 | *.pid.lock 8 | *_port 9 | .coverage.out 10 | 11 | reflection_and_summary/gignore/* -------------------------------------------------------------------------------- /basic/golang/gc.md: -------------------------------------------------------------------------------- 1 | ## Go gc 2 | 3 | 4 | ### 1. 三色标记 5 | 6 | 1. 有黑白灰三个集合,初始时所有对象都是白色 7 | 2. 从 Root 对象开始标记,将所有可达对象标记为灰色 8 | 3. 从灰色对象集合取出对象,将其引用的对象标记为灰色,放入灰色集合,并将自己标记黑色 9 | 4. 重复第三步,直到灰色集合为空,即所有可达对象都被标记 10 | 5. 标记结束后,不可达的白色对象即为垃圾,对内存进行迭代清扫,回收白色对象 11 | 6. 重置 GC 状态 12 | 13 | 14 | go 和 java 不同,go 的对象在内存中并没有 header 15 | 16 | 1. 标记和程序并发,会漏标记对象吗?如何解决的? 17 | 2. 哪里记录了对象的三色标记状态? 18 | 3. 标记时,拿到一个指针,怎么知道它是哪个对象?也许是某个对象的内部指针? 19 | 这个对象的内存哪些地方代表了它引用的对象呢? 20 | 21 | ### 2. 三色标记实现的一点细节 22 | 23 | #### 2.1 写屏障 24 | 25 | ![Alt text](./images/gc_1.png) 26 | 27 | > 上图来源:Go 夜读 28 | 29 | - 三色标记需要维护(弱)不变形条件;黑色对象不能引用无法被灰色对象可达的白色对象 30 | 31 | - 并发标记时,如果没有做正确性的保障措施,可能会导致漏标记对象,导致实际上可达的对象被请扫掉 32 | 33 | 为了解决这个问题,go 使用了写屏障(和内存写屏障不是同一个概念)。写屏障是在写入指针前执行的一小段代码,用以防止并发标记时指针丢失, 34 | 这一小段代码,Go 是在编译时加入的。 35 | 36 | Golang 写屏障在 mark 和 marktermination 阶段处于开启状态 37 | 38 | 图中,当第三步,A.obj = C 时,会将 C 进行标记。加入写屏障 bug,最终会 flush 到待扫描队列,这样就不会丢失 C 及 C引用对象。 39 | 40 | 栈中指针 slot 的操作没有写屏障 41 | 42 | - Dijkstra 写屏障是对被写入的指针进行 grey 操作,不能防止指针从 heap 被隐藏到黑色的栈中,需要 STW 重新扫描栈。 43 | - Yuasa 写屏障是对将被覆盖的指针进行 grey 操作,不能防止指针从栈被隐藏到黑色的 heap 对象中,需要在 GC 开始时保存栈的快照。 44 | 45 | go 1.8写屏障混合了两者,既不需要 GC 开始时保存栈快照,也不需要 STW 重新扫描栈,原型如下: 46 | 47 | ```go 48 | writePointer(slot, ptr): 49 | shade(*slot) 50 | if current statck is grey: 51 | shade(ptr) 52 | *slot = ptr 53 | ``` 54 | 55 | #### 2.2 三色状态 56 | 57 | ![Alt text](./images/gc_2.png) 58 | 59 | > 上图来源:Go 夜读 60 | 61 | 并没有真正的三个集合类分别装三色对象。 62 | 63 | 前面分析内存的时候,介绍了 go 的对象是分配在 span 中,spna 里还有一个字段是 gcmarkBits,mark 阶段 64 | 里面每个 bit 代表一个 slot 已被标记。 65 | 66 | 白色对象该 bit 为 0,灰色或黑色为 1 (runtime.markBits) 67 | 68 | 每个 p 中都有 wbBuff 和 gcw gcWork,以及全局的 workbuf 标记队列,实现 生产者-消费者模型, 69 | 在这些队列中的指针为灰色对象,表示已标记,待扫描 70 | 71 | 从队列中出来并把其引用对象入队的为黑色对象,表示已标记,已扫描(runtime.scanobject) 72 | 73 | 74 | #### 2.3 扫描与元信息 75 | 76 | ![Alt text](./images/gc_3.png) 77 | 78 | > 上图来源:Go 夜读 79 | 80 | 81 | ### 3. Golang Gc 流程 82 | 83 | ![Alt text](./images/gc_4.png) 84 | 85 | > 上图来源:Go 夜读 86 | 87 | 88 | ### 4. 未涉及的点 89 | 90 | - 栈分配 91 | - fixalloc, tinyalloc 92 | - 逃逸分析 93 | - 内存归还 94 | - 清扫与辅助清扫 95 | - go gc mark 任务分配 96 | - 辅助标记 97 | - revise 98 | - mark termination 流程 99 | - GC pacer, trigger 计算,goal 计算 100 | 101 | 102 | 103 | ### 5. 实践 104 | 105 | 通过 godoc 来开启一个 go 进程,用 ab 来调用,加上 debug trace 观察其状态 106 | 107 | GOMAXPROCS=8 GODEBUG=schedtrace=500 godoc -http=:6060 (加上 scheddetail=1观察更详细信息) 108 | 109 | ab -c 1000 -n 100000 'http://localhost:6060/' 110 | 111 | 这是一个服务通过调用 debug.SetGCPercent 设置 GOGC,分别是 100,500,1650 时的表现 112 | GOGC 越大,GC频次月底。但是触发GC的堆内存也越大 113 | 114 | 115 | 116 | ### 6. 一些优化 117 | 118 | > 图来源:Go 夜读 119 | 120 | ![Alt text](./images/gc_6_1.png) 121 | 122 | 123 | ![Alt text](./images/gc_6_2.png) 124 | 125 | 126 | ![Alt text](./images/gc_6_3.png) 127 | 128 | 129 | ![Alt text](./images/gc_6_4.png) 130 | 131 | 132 | ![Alt text](./images/gc_6_5.png) 133 | 134 | ![Alt text](./images/gc_6_6.png) 135 | 136 | 137 | ### 感谢 138 | 139 | - [Go 夜读](https://github.com/talkgo/night) 140 | 141 | 142 | 143 | -------------------------------------------------------------------------------- /basic/golang/images/gc_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/basic/golang/images/gc_1.png -------------------------------------------------------------------------------- /basic/golang/images/gc_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/basic/golang/images/gc_2.png -------------------------------------------------------------------------------- /basic/golang/images/gc_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/basic/golang/images/gc_3.png -------------------------------------------------------------------------------- /basic/golang/images/gc_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/basic/golang/images/gc_4.png -------------------------------------------------------------------------------- /basic/golang/images/gc_6_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/basic/golang/images/gc_6_1.png -------------------------------------------------------------------------------- /basic/golang/images/gc_6_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/basic/golang/images/gc_6_2.png -------------------------------------------------------------------------------- /basic/golang/images/gc_6_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/basic/golang/images/gc_6_3.png -------------------------------------------------------------------------------- /basic/golang/images/gc_6_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/basic/golang/images/gc_6_4.png -------------------------------------------------------------------------------- /basic/golang/images/gc_6_5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/basic/golang/images/gc_6_5.png -------------------------------------------------------------------------------- /basic/golang/images/gc_6_6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/basic/golang/images/gc_6_6.png -------------------------------------------------------------------------------- /basic/golang/images/mm_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/basic/golang/images/mm_1.png -------------------------------------------------------------------------------- /basic/golang/memory_management.md: -------------------------------------------------------------------------------- 1 | ## Go 内存管理 2 | 3 | Go 内存局域 TcMalloc,使用连续虚拟地址,以页(8k)为单位、多级缓存进行管理;在分配内存时, 4 | 需要对size 进行对齐处理,根据 best-fit 找到合适的 mspan,对未用完的内存还会拆分成其他大小的 mspan 继续使用。 5 | 6 | 7 | 在 new 一个 object 时(忽略逃逸分析),根据 object 的 size 做不同的分配策略: 8 | 9 | - 极小对象(size < 16 byte)直接在当前 P 的 mcache 上的 tiny 缓存上分配; 10 | 11 | - 小对象(16 byte <= size <= 32 k)在当前 P 的 mcache 上对应 slot 的空闲列表中分配, 12 | 无空闲列表则会继续向 mcentral 申请(还是没有则向 mheap 申请); 13 | 14 | - 大对象(size > 32k) 直接通过 mheap 申请 15 | 16 | 17 | 内存分配关键点 18 | 19 | * 分配速度问题 20 | * 先本地cache,后全局 21 | * 碎片率问题 22 | * mspan go里一个 page(8KB) 23 | 24 | 25 | #### 分配策略 26 | 27 | 28 | ![Alt text](./images/mm_1.png) 29 | 30 | 31 | > 上图来源:Go 夜读 32 | 33 | 1. new, make 最终调用 mallocgc 34 | 2. 大于 32KB 对象,直接从 mheap 中分配,构成一个 span 35 | 3. 小于 16byte 且无指针(noscan),使用 tiny分配器,合并分配 36 | 4. 小于 16byte 有指针或16byte-32KB,如果 mcache 中有对应 class 的空闲 mspan,则直接从该 mspan 中分配一个 slot. 37 | 5. (mcentral.cacheSpan) mcache 没有对应的空余 span,则从对应 mcentral 中申请一个有空余 slot 的 span 到 mcache 中,再进行分配 38 | 6. (mcentral.grow) 对应 mcentral 没有空余 span,则向 mheap(mheap_.alloc)中申请一个 span,能 sweep 出 span 则返回。否则看 mheap 的 free mTreap 能否分配 39 | 大于该 size 的连续页,能则分配,多的页放回。 40 | 7. mheap 的 free mTreap 无可用,则调用 sysAlloc(mmap)向系统申请 41 | 8. 6、7步中获得的内存构建成 span,返回给 mcache,分配对象。 42 | 43 | #### 1. 内存分配知识 44 | 45 | #### 2. 动态存储分配器 46 | 47 | #### 3. mmap 函数 48 | 49 | Unix 进程可以使用 mmap 函数来创建新的虚拟存储区域并将对象映射到这些区域中。 50 | 51 | mmap 函数要求内核创建一个新的虚拟存储区域,最好是从起始地址 start 开始的一个区域,并将文件描述符 52 | fd指定的对象的一个连续的片(chunk)映射到新的区域。 53 | 54 | #### 4. 数据频繁分配与回收 55 | 56 | 对于有效地进行数据频繁分配与回收,减少碎片,一般有两种手段: 57 | 58 | - 空闲链表:提供直接可供使用,已分配的结构块,缺点是不能全局控制 59 | - slab:linux 提供的,可以把不同的对象划分为所谓高速缓存组 60 | 61 | #### 5. Go的内存分配 62 | 63 | Go的内存分配器是采用google自家的tcmalloc,tcmalloc是一个带内存池的分配器,底层直接调用mmap函数,并使用bestfit进行动态分配。 64 | 65 | Go为每个系统线程分配了一个本地MCache,少量的地址分配就是从MCache分配的,并且定期进行垃圾回收,所以可见go的分配器包含了显式与隐式的调用。 66 | 67 | Go定义的小块内存,大小上是指32K或以下的对象,go底层会把这些小块内存按照指定规格(大约100种)进行切割:为了避免随意切割,申请任意字节内存时会向上取整到接近的块,将整块分配(从空闲链表)给到申请者。 68 | 69 | Go内存分配主要组件: 70 | 71 | 72 | - MCache:层次与MHeap类似,对于每个尺寸的类别都有一个空闲链表。每个M都有自己的局部Mcache(小对象从它取,无需加锁),这就是Go能够在多线程中高效内存管理的重要原因. 73 | 74 | - MCentral:在无空闲内存的时候,向Mheap申请一个span,而不是多个,申请的span包含多少个page由central的sizeclass来确定(跨进程复用) 75 | 76 | - MHeap:负责将MSpan组织和管理起来。 77 | 78 | (1). 分配过程:从free[]中分配,如果发生切割则将剩余的部分放回到free[]中. 79 | 80 | (2). 回收过程:回收一个Mspan时,首选查找它相邻的地址,再通过map映射得到对应的Mspan,如果Mspan的state是未使用,则可以将 两者进行合并。最后将这页或者合并后的页归还到free[]分配池或者large中。 81 | 82 | #### 6. Go的内存模型 83 | 84 | Go 的内存模型可以视为两级的内存模型: 85 | 86 | - 第一级:Mheap 为主要组件:分配的单位是页,但管理的单位是 MSpan,回收是采用位图的方式。 87 | 88 | - 第二级:Mcache 为主要组件:相当于一个内存池,回收采用引用计数器 89 | 90 | 分配场景: 91 | 92 | 为对象分配内存须区分是在栈上分配,还是在堆上分配。通常情况下,编译器有责任尽可能使用寄存器和栈来存储对象, 93 | 这有助于提升性能, 减少垃圾回收器的压力。 94 | 95 | 96 | 内存分配流程: 97 | 98 | 1、将小对象的大小向上取整到一个对应的尺寸类别(大约 100种),查找相应的 MCache 的空闲链表,如果链表不空, 99 | 直接从上面分配一个对象,这个过程不加锁 100 | 101 | 2、如果 Mcache 自由链表是空的,通过 Mcentral 的自由链表取一些对象进行补充 102 | 103 | 3、如果 Mcentral 的自由链表是空的,则往 MHeap 中取用一些页对 Mcentral 进行补充,然后将这些内存截断成特定规格 104 | 105 | 4、如果 MHeap 空或者没有足够大的页的情况下,从操作系统分配一组新的页面,一般在 1MB以上 106 | 107 | Go也有happens-before ,go happens-before常用的三原则是: 108 | 109 | - 对于不带缓冲区的channel,对其写happens-before对其读. 110 | - 对于带缓冲区的channel,对其读happens-before对其写. 111 | - 对于不带缓冲的channel的接收操作 happens-before 相应channel的发送操作完成. 112 | 113 | ### 感谢 114 | 115 | - [Go 内存管理](https://github.com/KeKe-Li/data-structures-questions/blob/master/src/chapter09/golang.01.md) 116 | 117 | -------------------------------------------------------------------------------- /basic/golang/source_code/images/channel_2_1_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/basic/golang/source_code/images/channel_2_1_1.png -------------------------------------------------------------------------------- /basic/golang/source_code/images/channel_3_1_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/basic/golang/source_code/images/channel_3_1_1.png -------------------------------------------------------------------------------- /basic/golang/source_code/images/channel_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/basic/golang/source_code/images/channel_4.png -------------------------------------------------------------------------------- /basic/golang/source_code/images/channel_5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/basic/golang/source_code/images/channel_5.png -------------------------------------------------------------------------------- /basic/golang/source_code/images/channel_6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/basic/golang/source_code/images/channel_6.png -------------------------------------------------------------------------------- /basic/golang/source_code/images/channel_7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/basic/golang/source_code/images/channel_7.png -------------------------------------------------------------------------------- /basic/golang/source_code/images/channel_select_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/basic/golang/source_code/images/channel_select_1.png -------------------------------------------------------------------------------- /basic/golang/source_code/images/channel_select_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/basic/golang/source_code/images/channel_select_2.png -------------------------------------------------------------------------------- /basic/golang/用go实现nginx反向代理及负载均衡.md: -------------------------------------------------------------------------------- 1 | # 用go实现nginx反向代理及负载均衡 2 | 3 | ## 1.介绍 4 | 5 | ### 1.1 正向代理与反向代理: 6 | 7 | [Forward-Proxy-vs-Reverse-Proxy](https://www.jscape.com/blog/bid/87783/Forward-Proxy-vs-Reverse-Proxy) / [正向代理与反向代理的区别](http://blog.csdn.net/m13666368773/article/details/8060481) 8 | 9 | ### 1.2 负载均衡: 10 | [维基百科](https://en.wikipedia.org/wiki/Load_balancing_(computing)) / [百度百科](https://baike.baidu.com/item/%E8%B4%9F%E8%BD%BD%E5%9D%87%E8%A1%A1/932451?fr=aladdin) 11 | 12 | ## 2.实现 13 | 14 | ### 2.1 负载均衡算法 15 | 16 | #### 2.1.1 数据结构: 17 |
18 | type Convert struct {
19 | 	Req_type   string   // (host / location)
20 | 	Backends string
21 | 	Address string
22 | 	Protocol string
23 | 	Weight float32
24 | 	Cur_weight float32
25 | }
26 | 
27 | 28 | #### 2.1.2 负载均衡实现: 29 | 1. 我在globalvar里面定义了两个全局变量:```globalvar.go``` 30 | 31 |
32 | 	var Cache map[string][]models.Convert
33 | 	var L_Lock *sync.RWMutex
34 | 	
35 | 36 | 2. 轮询算法实现```polling.go``` 37 | 38 |
39 | 	func GetNextServerConvert(host string) (convert models.Convert, err error){
40 | 		globalvar.L_Lock.Lock()
41 | 		defer globalvar.L_Lock.Unlock()
42 | 	
43 | 		var converts []models.Convert
44 | 		converts = globalvar.Cache[host]
45 | 		if converts == nil || len(converts) == 0 {
46 | 			converts = GetConvertsByHost(host)
47 | 			if converts == nil || len(converts) == 0 {
48 | 				return convert, errors.New("not found convert can handle request from host:" + host)
49 | 			}
50 | 		}
51 | 		globalvar.Cache[host] = converts
52 | 		convert = getNextServerConvert(converts, len(converts))
53 | 		globalvar.Cache[host] = converts
54 | 		return convert, nil
55 | 	}
56 | 	
57 | 58 | 剩下的回头在写...... 59 | -------------------------------------------------------------------------------- /basic/python/basic/Python中的作用域及global用法.md: -------------------------------------------------------------------------------- 1 | ## Python中的作用域及global用法 2 | 3 | #### 1.作用域 4 | 5 | > Python中,一个变量的作用域总是由代码中被赋值的地方所决定的 6 |
 7 | 函数定义了本地作用域,而模块定义的是全局作用域。
 8 | 如果想要在函数内定义全局作用域,需要加上global修饰符。
 9 | 
10 | 变量名解析:LEGB原则
11 | 当在函数中使用未认证的变量名时,Python搜索4个作用域
12 | [本地作用域(L)(函数内部声明但没有使用global的变量),
13 |   之后是上一层结构中def或者lambda的本地作用域(E),
14 |    之后是全局作用域(G)(函数中使用global声明的变量或在模块层声明的变量),
15 |     最后是内置作用域(B)(即python的内置类和函数等)]
16 | 并且在第一处能够找到这个变量名的地方停下来。如果变量名在整个的搜索过程中都没有找到,Python就会报错。
17 | 
18 | 补:
19 | 上面的变量规则只适用于简单对象,当出现引用对象的属性时,则有另一套搜索规则:
20 | 属性引用搜索一个或多个对象,而不是作用域,并且有可能涉及到所谓的"继承"。
21 | 
22 | 23 | #### 2.globle用法 24 | 25 | > Python在模块层定义的变量(无需global修饰),如果在函数中没有再定义同名变量,可以在函数中当做全局变量使用,如下例子: 26 | 27 |
28 | hackfun = 11
29 | 
30 | def test_global():
31 |     print('in_fun: ', hackfun)
32 | 
33 | test_global()
34 | print('out_fun: ', hackfun)
35 | 
36 | 
37 | 结果
38 | in_fun:  11
39 | out_fun:  11
40 | 
41 | 42 | > 但如果在函数中使用此变量之后,再赋值/定义(因为Python是弱类型语言,赋值语句和其定义变量的语句一样),则会产生引用为定义变量的错误。如下例子: 43 |
44 | hackfun = 11
45 | 
46 | def test_global():
47 |     print('in_fun: ', hackfun)
48 |     hackfun = 2
49 | 
50 | test_global()
51 | print('out_fun: ', hackfun)
52 | 
53 | 
54 | 结果
55 | UnboundLocalError: local variable 'hackfun' referenced before assignment
56 | 
57 | 58 | > 而如果在函数中的的再赋值/定义,在使用之前,则会正常运行,但需要注意的是,函数中的变量和模块中定义的全局变量不为同一个。如下例子: 59 |
60 | hackfun = 11
61 | def test_global():
62 |     hackfun = 2
63 |     print('in_fun: ', hackfun)
64 | 
65 | test_global()
66 | print('out_fun: ', hackfun)
67 | 
68 | 
69 | 结果
70 | in_fun:  2
71 | out_fun:  11
72 | 
73 | 74 | > 那么如果,我可能在函数使用某一变量后又对其进行修改(即再赋值),怎么让函数里面的变量是模块层定义的那个全局变量而不是函数内部的局部变量呢?这时候global修饰符就派上用场了。如下例子: 75 |
76 | hackfun = 11
77 | def test_global():
78 |     global hackfun
79 |     print('in_fun: ', hackfun)
80 |     hackfun = 2
81 | 
82 | test_global()
83 | print('out_fun: ', hackfun)
84 | 
85 | 
86 | 结果
87 | in_fun:  11
88 | out_fun:  2
89 | 
90 | 91 | 在用global修饰符声明hackfun后(注:global语句不允许同时进行赋值,如global hackfun = 2是不允许的)上述的到11 和 2,得到了我们想要的效果。 92 | 93 | ### 参考 94 | [Python中的作用域及global用法](http://www.cnblogs.com/summer-cool/p/3884595.html) 95 | 96 | [ Python容易混淆的地方](http://blog.csdn.net/carolzhang8406/article/details/6855525 " Python容易混淆的地方") -------------------------------------------------------------------------------- /basic/python/basic/Python学习之Queue.md: -------------------------------------------------------------------------------- 1 | 2 | ## Python3 queue 3 | >Python2 中为 Queue 4 | 5 | ##### 1.Python queue 模块有三种队列: 6 |
 7 | 1.python queue模块得FIFO队列先进先出。
 8 | 2.LIFO类似于堆,即先进后出。
 9 | 3.还有一种是优先级队列级别越低越先出来。
10 | 
11 | 12 | ##### 2.针对这三种队列分别有三个构造函数: 13 |
14 | 1.class queue.Queue(maxsize) FIFO
15 | 2.class queue.LifoQueue(maxsize) LIFO
16 | 3.class queue.PriorityQueue(maxsize) 优先级队列
17 | 
18 | ##### 3.介绍一下此包中的常用方法 19 |
20 | queue.qsize() 返回队列的大小
21 | queue.empty() 如果队列为空,返回True,反之False
22 | queue.full() 如果队列满了,返回True,反之False
23 | queue.full 与 maxsize 大小对应
24 | queue.get([block[, timeout]]) 获取队列,timeout等待时间
25 | queue.get_nowait() 相当Queue.get(False)非阻塞 
26 | queue.put(item) 写入队列,timeout等待时间
27 | queue.put_nowait(item) 相当Queue.put(item, False) 
28 | queue.task_done() 在完成一项工作之后,queue.task_done() 函数向任务已经完成的队列发送一个信号
29 | queue.join() 实际上意味着等到队列为空,再执行别的操作
30 | 
31 | 32 | **task_done()**
33 | 意味着之前入队的一个任务已经完成。由队列的消费者线程调用。每一个```get()```调用得到一个任务,接下来的```task_done()```调用告诉队列该任务已经处理完毕。 34 | 如果当前一个join()正在阻塞,它将在队列中的所有任务都处理完时恢复执行(即每一个由```put()```调用入队的任务都有一个对应的```task_done()```调用)。 35 | 36 | **join()**
37 | 阻塞调用线程,直到队列中的所有任务被处理掉。 38 | 只要有数据被加入队列,未完成的任务数就会增加。当消费者线程调用```task_done()```(意味着有消费者取得任务并完成任务),未完成的任务数就会减少。当未完成的任务数降到0,```join()```解除阻塞。 39 | 40 | **put(item[, block[, timeout]])**
41 | 将item放入队列中。
42 | 1. 如果可选的参数block为True且timeout为空对象(默认的情况,阻塞调用,无超时)。
43 | 2. 如果timeout是个正整数,阻塞调用进程最多timeout秒,如果一直无空空间可用,抛出Full异常(带超时的阻塞调用)。
44 | 3. 如果block为False,如果有空闲空间可用将数据放入队列,否则立即抛出Full异常其非阻塞版本为```put_nowait```等同于```put(item, False)``` 45 | 46 | **get([block[, timeout]])**
47 | 从队列中移除并返回一个数据。block跟timeout参数同put方法 48 | 其非阻塞方法为```get_nowait()```相当与```get(False)``` 49 | 50 | **empty()**
51 | 如果队列为空,返回```True```,反之返回```False``` 52 | 53 | 54 | -------------------------------------------------------------------------------- /basic/python/basic/images/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/basic/python/basic/images/1.png -------------------------------------------------------------------------------- /basic/python/basic/images/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/basic/python/basic/images/2.png -------------------------------------------------------------------------------- /basic/python/basic/images/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/basic/python/basic/images/3.png -------------------------------------------------------------------------------- /basic/python/basic/变量对象和引用.md: -------------------------------------------------------------------------------- 1 | ## 变量、对象和引用 2 | 3 | 1.变量 4 | 5 | 6 | **变量创建** 7 | 8 | > 一个变量(也就是变量名),就想a,当代码第一次给他赋值是就创建了它。之后的赋值也会改变自己创建的变量名的值。从技术上来讲,Python在代码运行之前先检测变量名,可以当成是最初的赋值创建变量。 9 | 10 | **变量类型** 11 | 12 | > 变量永远不会有任何的和它关联的类型信息或约束。类型的概念是存在与对象中而不是变量名中。变量原本是通用的,它只是在一个特定的时间点,简单地引用了一个特定的对象而已。 13 | 14 | **变量使用** 15 | 16 | > 当变量出现在表达式中时,它会马上被当前引用的对象所代替,无论这个对象时什么类型。此外,所有的变量必须在其使用前明确地赋值,使用未赋值的变量会产生错误。 17 | 18 | 对于 19 |
a = 3
20 | Python会执行下面三个步骤: 21 | 22 | 1. 创建一个对象来代表值3。 23 | 2. 创建一个变量a,如果它还没有被创建的话。 24 | 3. 将变量与新的对象相连接。 25 | 26 | 如图 27 | 28 | ![Alt text](images/1.png) 29 | 30 | 31 | ### 参考 32 | 33 | [Python学习手册](https://www.baidu.com/s?wd=Python%E5%AD%A6%E4%B9%A0%E6%89%8B%E5%86%8C&rsv_spt=1&rsv_iqid=0xb3a048c900038a73&issp=1&f=8&rsv_bp=0&rsv_idx=2&ie=utf-8&tn=baiduhome_pg&rsv_enter=1&rsv_sug3=19&rsv_sug1=16&rsv_sug7=100&rsv_sug2=0&inputT=6601&rsv_sug4=6612 "Python学习手册") 34 | 35 | [跟老齐学Python之深入变量和引用对象](http://www.jb51.net/article/55576.htm "跟老齐学Python之深入变量和引用对象") -------------------------------------------------------------------------------- /basic/python/concurrency/Python之路_异步IO_队列_缓存.md: -------------------------------------------------------------------------------- 1 | ## 协程 2 | 3 | 协程,又称微线程,纤程。英文名Coroutine。一句话说明什么是线程:协程是一种用户态的轻量级线程。 4 | 5 | 协程拥有自己的寄存器上下文和栈。协程调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器上下文和栈。因此: 6 | 7 | 协程能保留上一次调用时的状态(即所有局部状态的一个特定组合),每次过程重入时,就相当于进入上一次调用的状态,换种说法:进入上一次离开时所处逻辑流的位置。 8 | 9 | 10 | 11 | ### 1.协程的好处: 12 | 13 | 无需线程上下文切换的开销 14 | 无需原子操作锁定及同步的开销 15 |   "原子操作(atomic operation)是不需要synchronized",所谓原子操作是指不会被线程调度机制打断的操作;这种操作一旦开始,就一直运行到结束,中间不会有任何 context switch (切换到另一个线程)。原子操作可以是一个步骤,也可以是多个操作步骤,但是其顺序是不可以被打乱,或者切割掉只执行部分。视作整体是原子性的核心。 16 | 方便切换控制流,简化编程模型 17 | 高并发+高扩展性+低成本:一个CPU支持上万的协程都不是问题。所以很适合用于高并发处理。 18 | 19 | 20 | ### 2.缺点: 21 | 22 | 无法利用多核资源:协程的本质是个单线程,它不能同时将 单个CPU 的多个核用上,协程需要和进程配合才能运行在多CPU上.当然我们日常所编写的绝大部分应用都没有这个必要,除非是cpu密集型应用。 23 | 进行阻塞(Blocking)操作(如IO时)会阻塞掉整个程序 24 | 25 | #### 3.yield实现简单的协程 26 |
 27 | 
 28 | def consumer(name):
 29 |     print("--->starting eating baozi...")
 30 |     while True:
 31 |         new_baozi = yield
 32 |         print("[%s] is eating baozi %s" % (name, new_baozi))
 33 |         # time.sleep(1)
 34 | 
 35 | 
 36 | def producer():
 37 |     r = con.next()  # python3下是__next__()
 38 |     r = con2.next()
 39 |     n = 0
 40 |     while n < 5:
 41 |         n += 1
 42 |         con.send(n)  # 
 43 |         con2.send(n)
 44 |         print("\033[32;1m[producer]\033[0m is making baozi %s" % n)
 45 | 
 46 | if __name__ == '__main__':
 47 |     con = consumer("c1")
 48 |     con2 = consumer("c2")
 49 |     p = producer()
 50 | 
 51 | 结果
 52 | >>>
 53 | --->starting eating baozi...
 54 | --->starting eating baozi...
 55 | [c1] is eating baozi 1
 56 | [c2] is eating baozi 1
 57 | [producer] is making baozi 1
 58 | [c1] is eating baozi 2
 59 | [c2] is eating baozi 2
 60 | [producer] is making baozi 2
 61 | [c1] is eating baozi 3
 62 | [c2] is eating baozi 3
 63 | [producer] is making baozi 3
 64 | [c1] is eating baozi 4
 65 | [c2] is eating baozi 4
 66 | [producer] is making baozi 4
 67 | [c1] is eating baozi 5
 68 | [c2] is eating baozi 5
 69 | [producer] is making baozi 5
 70 | 
71 | 72 | 看楼上的例子,我问你这算不算做是协程呢?你说,我他妈哪知道呀,你前面说了一堆废话,但是并没告诉我协程的标准形态呀,我腚眼一想,觉得你说也对,那好,我们先给协程一个标准定义,即符合什么条件就能称之为协程: 73 | 74 | 1. 必须在只有一个单线程里实现并发 75 | 2. 修改共享数据不需加锁 76 | 3. 用户程序里自己保存多个控制流的上下文栈 77 | 4. 一个协程遇到IO操作自动切换到其它协程 78 | 79 | 基于上面这4点定义,我们刚才用yield实现的程并不能算是合格的线程,因为它有一点功能没实现,哪一点呢? 80 | 81 | 82 | ### 4.Greenlet 83 | 84 | pip install gevent 85 | 86 | greenlet是一个用C实现的协程模块,相比与python自带的yield,它可以使你在任意函数之间随意切换,而不需把这个函数先声明为generator 87 | 88 |
 89 | # greenlet(手动切换)
 90 | from greenlet import greenlet
 91 | 
 92 | 
 93 | def xiecheng_test():
 94 |     print(12)
 95 |     gr2.switch()
 96 |     print(34)
 97 |     gr2.switch()
 98 | 
 99 | 
100 | def xiecheng_test2():
101 |     print(56)
102 |     gr1.switch()
103 |     print(78)
104 | 
105 | 
106 | gr1 = greenlet(xiecheng_test)
107 | gr2 = greenlet(xiecheng_test2)
108 | gr1.switch()
109 | 
110 | 结果
111 | >>>
112 | 12
113 | 56
114 | 34
115 | 78
116 | 
117 | 118 | ### Gevent 119 | 120 | Gevent 是一个第三方库,可以轻松通过gevent实现并发同步或异步编程,在gevent中用到的主要模式是Greenlet, 它是以C扩展模块形式接入Python的轻量级协程。 Greenlet全部运行在主程序操作系统进程的内部,但它们被协作式地调度。 121 | 122 |
123 | import gevent
124 | 
125 | def foo():
126 |     print('Running in foo')
127 |     gevent.sleep(2)
128 |     print('Explicit context switch to foo again')
129 | 
130 | 
131 | def bar():
132 |     print('Explicit context to bar')
133 |     gevent.sleep(1)
134 |     print('Implicit context switch back to bar')
135 | 
136 | gevent.joinall([
137 |     gevent.spawn(foo),  # spawn:产生
138 |     gevent.spawn(bar),
139 | ])
140 | 
141 | 结果
142 | >>>
143 | Running in foo
144 | Explicit context to bar
145 | Implicit context switch back to bar
146 | Explicit context switch to foo again
147 | 
148 | 149 |
150 | import gevent
151 | 
152 | 
153 | def foo():
154 |     print('Running in foo')
155 |     gevent.sleep(2)
156 |     print('Explicit context switch to foo again')
157 | 
158 | 
159 | def bar():
160 |     print('Explicit context to bar')
161 |     gevent.sleep(1)
162 |     print('Implicit context switch back to bar')
163 | 
164 | 
165 | def func3():
166 |     print('running func3')
167 |     gevent.sleep(0)
168 |     print('running func3 again')
169 | 
170 | 
171 | gevent.joinall([
172 |     gevent.spawn(foo),  # spawn:产生
173 |     gevent.spawn(bar),
174 |     gevent.spawn(func3),
175 | ])
176 | 
177 | 结果
178 | >>>
179 | Running in foo
180 | Explicit context to bar
181 | running func3
182 | running func3 again
183 | Implicit context switch back to bar
184 | Explicit context switch to foo again
185 | 
186 | 187 | ## 参考 188 | [Python之路,Day9 - 异步IO\数据库\队列\缓存](http://www.cnblogs.com/alex3714/articles/5248247.html) 189 | 190 | [Python之路,Day9, 进程、线程、协程篇](http://www.cnblogs.com/alex3714/articles/5230609.html) -------------------------------------------------------------------------------- /basic/python/concurrency/Python之路_进程_线程.md: -------------------------------------------------------------------------------- 1 | ## Python threading 模块 2 | 线程有2种调用方法,如下: 3 | #### 直接调用 4 |
5 | 
6 | 
7 |
8 | 
9 | 
-------------------------------------------------------------------------------- /basic/python/requests/Python学习之Requests模块学习之一-发送请求.md: -------------------------------------------------------------------------------- 1 | # Requests模块学习之一发送请求 2 | 3 |
  4 | GitHub API
  5 | URL:https://developer.github.com/
  6 | 
7 | 8 | 9 | ## 1.1 请求方法 10 | - GET: 查看资源 11 | - POST: 增加资源 12 | - PUT: 修改资源 13 | - DELETE: 删除资源 14 | - HEAD: 查看响应头 15 | - OPTIONS: 查看可用请求方法 16 | 17 | **requests.\[method\](url)** 18 | 19 |
 20 | #!/usr/bin/env python
 21 | # -*- coding:utf-8 -*-
 22 | 
 23 | __Author__ = "HackFun"
 24 | __Date__ = '2017/9/28 23:15'
 25 | 
 26 | import requests
 27 | import json
 28 | 
 29 | URL = 'https://api.github.com'
 30 | 
 31 | 
 32 | def build_uri(endpoint):
 33 |     return '/'.join([URL, endpoint])
 34 | 
 35 | 
 36 | def better_print(json_str):
 37 |     return json.dumps(json.loads(json_str), indent=4)
 38 | 
 39 | 
 40 | def request_method():
 41 |     response = requests.get(build_uri('user/emails'), auth=('hackfeng624@gmail.com', 'qqq@123456'))
 42 |     print better_print(response.text)
 43 |     
 44 | if __name__ == '__main__':
 45 |     request_method()
 46 | 
47 | 48 | ## 1.2 带参数的请求 49 | 50 | 1.URL Parameters:URL参数 51 | 52 | - https://list.tmall.com/search_product.htm?cat=50514037&... 53 | 54 | - params:requests.get(url,params={'key1': 'value1'}) 55 | 56 | 2.表单参数提交: 57 | 58 | - Content-Type: application/x-www-form-urlencoded 59 | - 内容: key1=value1&key2=value2 60 | - request.post(url, data={'key1': 'value1', 'key2': 'value2'}) 61 | 62 | 3.json参数提交 63 | 64 | - Content-Type:application/json 65 | - 内容: '{"key1": "value1", "key2": "value2"}' 66 | - requests.post(url, json={'key1': 'value1', 'key2': 'value2'}) 67 | 68 | 69 | --- 70 | ### 例子1: 71 | [https://developer.github.com/v3/users/#parameters-1](https://developer.github.com/v3/users/#parameters-1) 72 | 73 | ![Alt text](images/32-1.png) 74 |
 75 | def params_request():
 76 |     response = requests.get(build_uri('users'), params={'since': 11})
 77 |     print better_print(response.text)
 78 |     print response.request.headers
 79 |     print response.url
 80 | 
81 | ### 结果1 82 | ![Alt text](images/32-2.png) 83 | 84 | --- 85 | 86 | ### 例子2: 87 | 88 | [https://developer.github.com/v3/users/#update-the-authenticated-user](https://developer.github.com/v3/users/#update-the-authenticated-user) 89 | 90 | ![Alt text](images/32-3.png) 91 | 92 |
 93 | def json_request():
 94 |     response = requests.patch(build_uri('user'), auth=('hackfeng624@gmail.com', 'xxxx'), json={"name": 'hackfun', "email": "xxx@xxx.com"})
 95 |     print better_print(response.text)
 96 |     print response.request.headers
 97 |     print response.request.body
 98 |     print response.status_code
 99 | 
100 | ### 结果2 101 | ![Alt text](images/32-4.png) 102 | 103 | --- 104 | 105 | ### 例子3: 106 | 107 | 代码添加email 108 | 109 |
110 | def json_request():
111 |     response = requests.patch(build_uri('user/emails'), auth=('hackfeng624@gmail.com', 'xxxx'), json=["xxxx@xxx.com"])
112 | 
113 |     print better_print(response.text)
114 |     print response.request.headers
115 |     print response.request.body
116 |     print response.status_code
117 | 
118 | 119 | ### 结果3 120 | 121 | ![Alt text](images/32-5.png) 122 | 123 | --- 124 | 125 | ## 3.3 请求异常处理 126 | 127 | ![Alt text](images/32-6.png) 128 | 129 | 130 |
131 | 异常类型:
132 | BaseHTTPError
133 | ChunkedEncodingError
134 | ConnectionTimeout
135 | ConnectionError
136 | ContentDecodingError
137 | HTTPError
138 | InvalidSchema
139 | InvalidURL
140 | MissingSchema
141 | ProxyError
142 | ReadTimeout
143 | RequestException
144 | RetryError
145 | SSLError
146 | StreamConsumedError
147 | Timeout
148 | TooManyRedirects
149 | URLRequired
150 | 
151 | 152 | ![Alt text](images/32-7.png) 153 | 154 | ### 处理异常代码 155 |
156 | def timeout_request():
157 |     try:
158 |         response = requests.get(build_uri('user/emails'), timeout=0,1)
159 |     except exceptions.Timeout as e:
160 |         print e.message
161 |     else:
162 |         print response.text
163 | 
164 | 165 | ### 结果 166 | ![Alt text](images/32-8.png) 167 | 168 | --- 169 | 170 | ### status_code 异常 171 | 172 |
173 | def timeout_request():
174 |     try:
175 |         response = requests.get(build_uri('user/emails'), timeout=0.1)
176 |         response.raise_for_status()
177 |     except exceptions.Timeout as e:
178 |         print e.message
179 |     except exceptions.HTTPError as e:
180 |         print e.message
181 |     else:
182 |         print response.text
183 |         print response.status_code.code
184 | 
185 | 186 | ### 结果 187 | ![Alt text](images/32-9.png) 188 | 189 | ## 3.4 自定义Request 190 | 191 | ![Alt text](images/32-10.png) 192 | 193 |
194 | class Request:的构造函数
195 | __init__(self,
196 |             method=None, url=None, headers=None, files=None, data=None,
197 |             params=None, auth=None, cookies=None, hooks=None, json=None):
198 | 
199 | ### 代码1 200 |
201 | def hard_requests():
202 |     from requests import Session, Request
203 |     s = Session()
204 |     headers = {'User-Agent': 'fake1.3.4'}
205 |     req = Request('GET', build_uri('user/emails'), auth=('hackfeng624@gmail.com', 'xxxx'), headers=headers)
206 |     prepped = req.prepare()
207 |     print prepped.body
208 |     print prepped.headers
209 | 
210 | ### 结果1 211 | ![Alt text](images/32-11.png) 212 | 213 | ### 代码2 214 |
215 | def hard_requests():
216 |     from requests import Session, Request
217 |     s = Session()
218 |     headers = {'User-Agent': 'fake1.3.4'}
219 |     req = Request('GET', build_uri('user/emails'), auth=('hackfeng624@gmail.com', 'xxxx'), headers=headers)
220 |     prepped = req.prepare()
221 |     print prepped.body
222 |     print prepped.headers
223 | 
224 |     resp = s.send(prepped, timeout=5)
225 |     print resp.status_code
226 |     print resp.request.headers
227 |     print resp.text
228 | 
229 | ### 结果2 230 | ![Alt text](images/32-12.png) 231 | 232 | 233 | ## 参考 234 | 235 | [慕课网-Python-走进Requests库](http://www.imooc.com/learn/736) -------------------------------------------------------------------------------- /basic/python/requests/Python学习之Requests模块学习之三-进阶话题.md: -------------------------------------------------------------------------------- 1 | # Requests模块学习之三进阶话题 2 | 3 |
  4 | GitHub API
  5 | URL:https://developer.github.com/
  6 | 
7 | 8 | 9 | ## 3.1 HTTP认证 10 | 11 | ![Alt text](images/51-1.png) 12 | 13 | ### 1.基本认证 14 |
 15 | def base_auth():
 16 |     """基本认证
 17 |     """
 18 |     response = requests.get(construct_url('user'), auth=('hackfeng624@gmail.com', 'xxxxxx'))
 19 |     print response.text
 20 |     print response.request.headers
 21 | 
 22 | >>>
 23 | Authorization': 'Basic xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', 'Connection': 'keep-alive', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'User-Agent': 'python-requests/2.18.4'}
 24 | 200
 25 | 
 26 | 
27 | 28 | ### 结果1 29 | 30 | ![Alt text](images/51-2.png) 31 | 32 | 这个结果其实就是一个base64的简单加密,因此很不安全 33 | 34 | ![Alt text](images/51-3.png) 35 | 36 | 37 | ### 2.OAUTH认证 38 | 39 | ![Alt text](images/51-4.png) 40 | 41 | #### 在GitHub上面设置一个 42 | ![Alt text](images/51-5.png) 43 | #### 从GitHub开发者api上找到认证方式 44 | ![Alt text](images/51-6.png) 45 |
 46 | def base_oauth():
 47 |     headers = {'Authorization': 'token xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'}
 48 |     # user/emails
 49 |     response = requests.get(construct_url('user/emails'), headers=headers)
 50 |     # response = requests.get(construct_url('user/emails'),
 51 |     # params={"access_token": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"})
 52 | 
 53 |     print response.request.headers
 54 |     # print response.text
 55 |     print response.status_code
 56 | 
57 | 58 | ### 3.通过继承requests.auth.AuthBase进行OAUTH认证 59 | 60 | ![Alt text](images/51-7.png) 61 |
 62 | from requests.auth import AuthBase
 63 | 
 64 | class GithubAuth(AuthBase):
 65 | 
 66 |     def __init__(self, token):
 67 |         self.token = token
 68 | 
 69 |     def __call__(self, r):
 70 |         # requests 加 headers
 71 |         r.headers['Authorization'] = ' '.join(['token', self.token])
 72 | 
 73 |         return r
 74 | 
 75 | 
 76 | def oauth_advanced():
 77 |     auth = GithubAuth('xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx')
 78 |     print auth
 79 |     response = requests.get(construct_url('user/emails'), auth=auth)
 80 |     print response.text
 81 | 
 82 | >>>
 83 | <__main__.GithubAuth object at 0x0000000002E7DAC8>
 84 | [{"email":"hackfeng624@gmail.com","primary":true,"verified":true,"visibility":"public"}]
 85 | 
 86 | 
87 | ### 结果2 88 | ![Alt text](images/51-8.png) 89 | 90 | 91 | ## 3.2 代理(Proxy) 92 | ![Alt text](images/52-1.png) 93 | ![Alt text](images/52-2.png) 94 | 95 | 96 | ### 安装requests对socksv5支持,cmd下输入: pip install requests[socksv5] 97 | ![Alt text](images/52-3.png) 98 | 99 | ### 代码实现 100 |
101 | #!/usr/bin/env python
102 | # -*- coding:utf-8 -*-
103 | 
104 | __Author__ = "HackFun"
105 | __Date__ = '2017/9/28 11:28'
106 | 
107 | import requests
108 | 
109 | proxies = {'http': 'socks5://127.0.0.1:1080', 'https': 'socks5://127.0.0.1:1080'}
110 | url = 'https://www.facebook.com'
111 | response = requests.get(url, proxies=proxies, timeout=10)
112 | 
113 | 114 | ## 3.3 Requests库-Session和Cookies 115 | 116 | ### 3.3.1 Cookies 117 | ![Alt text](./images/53-1.png) 118 | 119 | ### 3.3.2 Session 120 | ![Alt text](./images/53-2.png) 121 | 122 | 123 | 124 | 125 | 126 | ## 参考 127 | 128 | [慕课网-Python-走进Requests库](http://www.imooc.com/learn/736) -------------------------------------------------------------------------------- /basic/python/requests/Python学习之Requests模块学习之二-处理响应.md: -------------------------------------------------------------------------------- 1 | # Requests模块学习二处理响应 2 | 3 |
  4 | GitHub API
  5 | URL:https://developer.github.com/
  6 | 
7 | 8 | ## 2.1 响应基本API 9 |
 10 | status_code
 11 | reason:'OK','Forbidden'之类的
 12 | headers
 13 | url
 14 | history :历史信息,比如3xx重定向的一些跳转信息
 15 | elapsed : 耗费的时间
 16 | request :找到请求的对象
 17 | 
 18 | 响应主体api:
 19 | encoding:是什么编码
 20 | raw:相当于读文件一样
 21 | content: byte (str格式)
 22 | text:unicode(经过解析过的)
 23 | json:json格式
 24 | 
25 | 26 | ### 例子演示1 27 | 28 | ![Alt text](images/41-1.png) 29 | 30 | ### 例子演示2 31 | 32 | ![Alt text](images/41-2.png) 33 | 34 | ### 例子演示3 35 | 36 | ![Alt text](images/41-3.png) 37 | 38 | ### 例子演示4 39 | 40 | ![Alt text](images/41-4.png) 41 | 42 | ### 例子演示5 43 | 44 | ![Alt text](images/41-5.png) 45 | 46 | ### 例子演示6 47 | 48 | ![Alt text](images/41-6.png) 49 | 50 | ### 例子演示7 51 | 52 | ![Alt text](images/41-7.png) 53 | 54 | 55 | ## 2.2 下载图片/文件 56 | 57 |
 58 | def download_request():
 59 |     """demo下载图片
 60 |     """
 61 |     url = "http://img.sootuu.com/vector/2006-4/2006420114643989.jpg"
 62 |     response = requests.get(url, stream=True)
 63 | 
 64 |     print response.status_code, response.reason
 65 |     print response.headers
 66 |     with open('image.jpg', 'wb') as f:
 67 |         f.write(response.content)
 68 | 对于较大的图片上面代码是比较耗费资源的
 69 | 
70 | 71 | ### 优化后代码 72 |
 73 | def download_request():
 74 |     """demo下载图片
 75 |     """
 76 |     url = "http://img.sootuu.com/vector/2006-4/2006420114643989.jpg"
 77 | 
 78 |     from contextlib import closing
 79 |     with closing(requests.get(url, stream=True)) as response:
 80 |         with open('demo.jpg', 'wb') as fd:
 81 |             for chunk in response.iter_content(128):
 82 |                 fd.write(chunk)
 83 | 
 84 |     print response.status_code, response.reason
 85 |     print response.headers
 86 | 
 87 | 
88 | 89 | ![Alt text](images/23-1.png) 90 | 91 | ## 2.3 事件钩子(Event Hooks) 92 | 93 | 94 | ![Alt text](images/23-2.png) 95 | 96 |
 97 | #!/usr/bin/env python
 98 | # -*- coding:utf-8 -*-
 99 | 
100 | __Author__ = "HackFun"
101 | __Date__ = '2017/9/28 10:25'
102 | 
103 | import requests
104 | 
105 | 
106 | def get_key_info(response, *args, **kwargs):
107 |     """回调函数
108 |     """
109 |     print response.headers['Content-Type']
110 |     print dir(response)
111 | 
112 | 
113 | def main():
114 |     """主程序
115 |     """
116 |     requests.get('https://www.baidu.com', hooks=dict(response=get_key_info))
117 | 
118 | if __name__ == '__main__':
119 |     main()
120 | 
121 | 
122 | >>>
123 | text/html
124 | ['__attrs__', '__bool__', '__class__', '__delattr__', '__dict__', '__doc__', '__enter__', '__exit__', '__format__', '__getattribute__', '__getstate__', '__hash__', '__init__', '__iter__', '__module__', '__new__', '__nonzero__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setstate__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_content', '_content_consumed', '_next', 'apparent_encoding', 'close', 'connection', 'content', 'cookies', 'elapsed', 'encoding', 'headers', 'history', 'is_permanent_redirect', 'is_redirect', 'iter_content', 'iter_lines', 'json', 'links', 'next', 'ok', 'raise_for_status', 'raw', 'reason', 'request', 'status_code', 'text', 'url']
125 | 
126 | 127 | ![Alt text](images/23-3.png) 128 | 129 | 130 | ## 参考 131 | 132 | [慕课网-Python-走进Requests库](http://www.imooc.com/learn/736) -------------------------------------------------------------------------------- /basic/python/requests/images/23-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/basic/python/requests/images/23-1.png -------------------------------------------------------------------------------- /basic/python/requests/images/23-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/basic/python/requests/images/23-2.png -------------------------------------------------------------------------------- /basic/python/requests/images/23-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/basic/python/requests/images/23-3.png -------------------------------------------------------------------------------- /basic/python/requests/images/32-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/basic/python/requests/images/32-1.png -------------------------------------------------------------------------------- /basic/python/requests/images/32-10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/basic/python/requests/images/32-10.png -------------------------------------------------------------------------------- /basic/python/requests/images/32-11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/basic/python/requests/images/32-11.png -------------------------------------------------------------------------------- /basic/python/requests/images/32-12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/basic/python/requests/images/32-12.png -------------------------------------------------------------------------------- /basic/python/requests/images/32-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/basic/python/requests/images/32-2.png -------------------------------------------------------------------------------- /basic/python/requests/images/32-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/basic/python/requests/images/32-3.png -------------------------------------------------------------------------------- /basic/python/requests/images/32-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/basic/python/requests/images/32-4.png -------------------------------------------------------------------------------- /basic/python/requests/images/32-5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/basic/python/requests/images/32-5.png -------------------------------------------------------------------------------- /basic/python/requests/images/32-6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/basic/python/requests/images/32-6.png -------------------------------------------------------------------------------- /basic/python/requests/images/32-7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/basic/python/requests/images/32-7.png -------------------------------------------------------------------------------- /basic/python/requests/images/32-8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/basic/python/requests/images/32-8.png -------------------------------------------------------------------------------- /basic/python/requests/images/32-9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/basic/python/requests/images/32-9.png -------------------------------------------------------------------------------- /basic/python/requests/images/41-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/basic/python/requests/images/41-1.png -------------------------------------------------------------------------------- /basic/python/requests/images/41-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/basic/python/requests/images/41-2.png -------------------------------------------------------------------------------- /basic/python/requests/images/41-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/basic/python/requests/images/41-3.png -------------------------------------------------------------------------------- /basic/python/requests/images/41-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/basic/python/requests/images/41-4.png -------------------------------------------------------------------------------- /basic/python/requests/images/41-5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/basic/python/requests/images/41-5.png -------------------------------------------------------------------------------- /basic/python/requests/images/41-6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/basic/python/requests/images/41-6.png -------------------------------------------------------------------------------- /basic/python/requests/images/41-7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/basic/python/requests/images/41-7.png -------------------------------------------------------------------------------- /basic/python/requests/images/51-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/basic/python/requests/images/51-1.png -------------------------------------------------------------------------------- /basic/python/requests/images/51-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/basic/python/requests/images/51-2.png -------------------------------------------------------------------------------- /basic/python/requests/images/51-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/basic/python/requests/images/51-3.png -------------------------------------------------------------------------------- /basic/python/requests/images/51-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/basic/python/requests/images/51-4.png -------------------------------------------------------------------------------- /basic/python/requests/images/51-5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/basic/python/requests/images/51-5.png -------------------------------------------------------------------------------- /basic/python/requests/images/51-6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/basic/python/requests/images/51-6.png -------------------------------------------------------------------------------- /basic/python/requests/images/51-7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/basic/python/requests/images/51-7.png -------------------------------------------------------------------------------- /basic/python/requests/images/51-8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/basic/python/requests/images/51-8.png -------------------------------------------------------------------------------- /basic/python/requests/images/52-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/basic/python/requests/images/52-1.png -------------------------------------------------------------------------------- /basic/python/requests/images/52-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/basic/python/requests/images/52-2.png -------------------------------------------------------------------------------- /basic/python/requests/images/52-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/basic/python/requests/images/52-3.png -------------------------------------------------------------------------------- /chinese/chinese_300_tang_poems/五言古诗_三十三首/张九龄/感遇_二首.md: -------------------------------------------------------------------------------- 1 | ## 张九龄 2 | 3 | 张九龄(678-740) : 唐开元尚书丞相,诗人。字子寿,一名博物,汉族,韶州曲江(今广东韶关市)人。长安年间进士。官至中书侍郎同中书门下平章事。后罢相,为荆州长史。诗风清淡。有《曲江集》。他是一位有胆识、有远见的著名政治家、文学家、诗人、名相。他忠耿尽职,秉公守则,直言敢谏,选贤任能,不徇私枉法,不趋炎附势,敢与恶势力作斗争,为“开元之治”作出了积极贡献。他的五言古诗,以素练质朴的语言,寄托深远的人生慨望,对扫除唐初所沿习的六朝绮靡诗风,贡献尤大。誉为“岭南第一人”。 4 | 5 | ---- 6 | 7 | ## 感遇十二首·其一 8 | 9 | **蓝 叶 春 葳 蕤,桂 华 秋 皎 洁。** 10 | 11 | **欣 欣 此 生 意,自 尔 为 佳 节。** 12 | 13 | **谁 知 林 栖 者,闻 风 坐 相 悦。** 14 | 15 | **草 木 有 本 心,何 求 美 人 折!** 16 | 17 | ### 其一·译文 18 | 19 |
20 | 春 天 里 的 幽 兰 翠 叶 纷 披,秋 天 里 的 桂 花 交 接 清 新。
21 | 
22 | 世 间 的 草 木 勃 勃 的 生 机,自 然 顺 应 了 美 好 的 季 节。
23 | 
24 | 谁 想 到 山 林 隐 逸 的 高 人,闻 到 芬 芳 因 而 满 怀 喜 悦。
25 | 
26 | 草 木 散 发 香 气 源 于 天 性,怎 么 会 求 观 赏 者 攀 折 呢!
27 | 
28 | 29 | 30 | 31 | ## 感遇十二首·其二 32 | 33 | **江 南 有 丹 橘,经 冬 犹 绿 林。** 34 | 35 | **岂 伊 地 气 暖?自 有 岁 寒 心。** 36 | 37 | **可 以 荐 嘉 客,奈 何 阻 重 生。** 38 | 39 | **运 命 惟 所 遇,循 环 不 可 寻。** 40 | 41 | **徒 言 树 桃 李,此 木 岂 无 阴?** 42 | 43 | ### 其二·译文 44 | 45 |
46 | 江 南 丹 桔 叶 茂 枝 繁,经 冬 不 凋 四 季 常 青。
47 | 岂 止 南 国 地 气 和 暖,而 是 具 有 松 柏 品 性。
48 | 荐 之 嘉 宾 必 受 称 赞,山 重 水 阻 如 何 进 献?
49 | 命 运 遭 遇 往 往 不 一,因 果 循 环 奥 秘 难 寻。
50 | 只 说 桃 李 有 果 有 林,难 道 丹 桔 就 不 成 阴?
51 | 
52 | 53 | 54 | ## 感谢 55 | 56 | [唐诗三百首](https://zh.wikipedia.org/wiki/%E5%94%90%E8%AF%97%E4%B8%89%E7%99%BE%E9%A6%96) 57 | 58 | [感遇·兰叶春葳蕤](https://so.gushiwen.org/shiwenv_d5419292d268.aspx) 59 | 60 | [感遇·江南有丹橘](https://so.gushiwen.org/shiwenv_02ba8d3eabab.aspx) -------------------------------------------------------------------------------- /chinese/chinese_idiom.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/chinese/chinese_idiom.md -------------------------------------------------------------------------------- /contents/algorithm.md: -------------------------------------------------------------------------------- 1 | # 个人博客 2 | 3 | 本仓库下存放个人博客的源文件。持续更新,欢迎 `star`。 4 | 5 | 如果大家觉得那里写的不合适的可以给我提 `Issue` 6 | 7 | --- 8 | 9 | [回到目录简介](../README.md#目录简介) 10 | 11 | 12 | #### 【数据结构与算法】 13 | 14 | - ##### 我的专题仓库「HelloAlgorithm」有介绍:[点击这里](https://github.com/hackfengJam/HelloAlgorithm) 15 | -------------------------------------------------------------------------------- /contents/basic.md: -------------------------------------------------------------------------------- 1 | # 个人博客 2 | 3 | 本仓库下存放个人博客的源文件。持续更新,欢迎 `star`。 4 | 5 | 如果大家觉得那里写的不合适的可以给我提 `Issue` 6 | 7 | --- 8 | 9 | [回到目录简介](../README.md#目录简介) 10 | 11 | 12 | #### 【语言基础】 13 | 14 | - ##### Python 15 | - 基础知识 16 | - [变量对象和引用](../basic/python/basic/变量对象和引用.md) 17 | - [Python学习之Queue](../basic/python/basic/Python学习之Queue.md) 18 | - [Python中的作用域及global用法](../basic/python/basic/Python中的作用域及global用法.md) 19 | - Requests 库 20 | - [Requests模块学习之一-发送请求](../basic/python/requests/Python学习之Requests模块学习之一-发送请求.md) 21 | - [Requests模块学习之二-处理响应](../basic/python/requests/Python学习之Requests模块学习之二-处理响应.md) 22 | - [Requests模块学习之三-进阶话题](../basic/python/requests/Python学习之Requests模块学习之三-进阶话题.md) 23 | - 并发 24 | - [Python_多进程_进程池](../basic/python/concurrency/Python_多进程_进程池.md) 25 | - [Python之路_异步IO_队列_缓存](../basic/python/concurrency/Python_多进程_进程池.md) 26 | - [Python之路_进程_线程](../basic/python/concurrency/Python_多进程_进程池.md) 27 | 28 | - ##### Golang 29 | - [用 golang 实现 nginx 反向代理及负载均衡](../basic/golang/用go实现nginx反向代理及负载均衡.md) 30 | - [channel & select](../basic/golang/source_code/channel.md) 31 | 32 | - ##### Java 33 | - Pending 34 | -------------------------------------------------------------------------------- /contents/chinese.md: -------------------------------------------------------------------------------- 1 | # 个人博客 2 | 3 | 本仓库下存放个人博客的源文件。持续更新,欢迎 `star`。 4 | 5 | 如果大家觉得那里写的不合适的可以给我提 `Issue` 6 | 7 | --- 8 | 9 | [回到目录简介](../README.md#目录简介) 10 | 11 | 12 | #### 【chinese】 13 | 14 | - ##### chinese_300_tang_poems 15 | - 五言古诗_三十三首 16 | - [张九龄 - 感遇_二首](../chinese/chinese_300_tang_poems/五言古诗_三十三首/张九龄/感遇_二首.md) 17 | -------------------------------------------------------------------------------- /contents/design.md: -------------------------------------------------------------------------------- 1 | # 个人博客 2 | 3 | 本仓库下存放个人博客的源文件。持续更新,欢迎 `star`。 4 | 5 | 如果大家觉得那里写的不合适的可以给我提 `Issue` 6 | 7 | --- 8 | 9 | [回到目录简介](../README.md#目录简介) 10 | 11 | 12 | #### 【设计与实战】 13 | 14 | - ##### [搭建并行处理管道 - Golang](../design/golang_pipeline/golang_pipeline.md) 15 | - ##### [原生爬虫 - Golang](../design/golang_crawler/golang_crawler.md) 16 | - ##### [流量统计系统 - Golang](../design/golang_analysis/golang_analysis.md) 17 | - ##### [开发分布式任务调度 - Golang](../design/golang_crontab/golang_crontab.md) 18 | - ##### [微信抢红包功能设计 - Golang](../design/red_envelope/red_envelope.md) 19 | - ##### [如何设计并实现一个高可用订单系统](../design/order/how_xx_order_system.md) 20 | 21 | -------------------------------------------------------------------------------- /contents/framework.md: -------------------------------------------------------------------------------- 1 | # 个人博客 2 | 3 | 本仓库下存放个人博客的源文件。持续更新,欢迎 `star`。 4 | 5 | 如果大家觉得那里写的不合适的可以给我提 `Issue` 6 | 7 | --- 8 | 9 | [回到目录简介](../README.md#目录简介) 10 | 11 | 12 | #### 【框架技术】 13 | 14 | - ##### Scrapy 15 | - [Scrapy - 第一步框架原理](../framework/scrapy/第一步Scrapy框架原理.md) 16 | - ##### Elasticsearch 17 | - [Elasticsearch - 介绍及开发环境搭建](../framework/elasticsearch/Elasticsearch环境搭建.md) 18 | - [Elasticsearch - 搜索引擎_pending](../framework/elasticsearch/搜索引擎_Elasticsearch_pending.md) 19 | - ##### SpringCloud 20 | - [Eureka 的介绍](../tech/springcloud/Eureka介绍.md) 21 | - [Eureka Server 和 Client 之间的信息维护(注册和续约)](../tech/springcloud/Eureka_Server_和_Client_之间的信息维护(注册和续约).md) 22 | - [Zuul 的介绍](../tech/springcloud/Zuul介绍.md) 23 | -------------------------------------------------------------------------------- /contents/misc.md: -------------------------------------------------------------------------------- 1 | # 个人博客 2 | 3 | 本仓库下存放个人博客的源文件。持续更新,欢迎 `star`。 4 | 5 | 如果大家觉得那里写的不合适的可以给我提 `Issue` 6 | 7 | --- 8 | 9 | [回到目录简介](../README.md#目录简介) 10 | 11 | 12 | #### 【各种技术】 13 | 14 | - ##### Redis 15 | - [Redis的正确打开方式](../tech/redis/Redis的正确打开方式.md) 16 | - [高并发情况下Redis做缓存的一系列问题_pending](../tech/redis/高并发情况下Redis做缓存的一系列问题_pending.md) 17 | - [Redis Pipeline 及 主从同步](../tech/redis/redis_pipeline_and_sync_master_slaver.md) 18 | - ##### Kafka 19 | - [kafka](../tech/kafka/kafka.md) 20 | - ##### MySQL 21 | - [数据库优化 - 索引优化](../tech/mysql/数据库优化——索引优化.md) 22 | - [Mysql大表处理_pending](../tech/mysql/Mysql大表处理_pending.md) 23 | - [数据库 - 如何设计一个关系型数据库](../tech/mysql/数据库——1_数据库架构.md) 24 | - [数据库 - 索引管理](../tech/mysql/数据库——2_索引管理.md) 25 | - [数据库 - 锁管理](../tech/mysql/数据库——3_锁管理.md) 26 | - ##### Nginx 27 | - [nginx - 使用之总体简介](../tech/nginx/nginx使用之总体简介.md) 28 | - [nginx - 使用之配置文件的组成及主配置段的指令之一](../tech/nginx/nginx使用之配置文件的组成及主配置段的指令之一.md) 29 | - [nginx - 使用之配置文件的组成及主配置段的指令之二](../tech/nginx/nginx使用之配置文件的组成及主配置段的指令之二.md) 30 | - ##### 分布式 31 | - [分布式id生成算法 - SnowFlake](../tech/distributed/algo/分布式id生成算法SnowFlake.md) 32 | - Raft 33 | - [Raft 领导选举](../tech/distributed/raft/raft_leader_election.md) 34 | - [Raft 一致性算法](../tech/distributed/raft/raft_consensus_algorithm.md) 35 | - [Raft 日志复制](../tech/distributed/raft/raft_log_replication.md) 36 | - Celery 37 | - [Celery 的正确打开方式 - 结合「官方文档」及「实际用例」了解 Celery](../tech/distributed/celery/celery_opens_correct_way.md)「**关键词:分布式任务队列;Celery**」 38 | - [[Draft]Celery 源码阅读](../tech/distributed/celery/celery_source_code.md) 39 | - etcd 40 | - [什么是 etcd?](../tech/distributed/etcd/etcd_study_1_what_is_etcd.md) 41 | - [etcd 功能与原理](../tech/distributed/etcd/etcd_function_and_principle.md) 42 | - [Golang 操作 etcd(上)](../tech/distributed/etcd/etcd_usage_golang_1.md) 43 | - [Golang 操作 etcd(下)](../tech/distributed/etcd/etcd_usage_golang_2.md) 44 | - ##### Linux 45 | - [Linux - find、grep、awk、sed 常用命令](../tech/linux/Linux.md) 46 | - [select、poll、epoll](../tech/linux/select_poll_epoll.md) 47 | - [零拷贝 - NIO](../tech/linux/零拷贝_NIO.md) 48 | - [用户态与内核态](../tech/linux/kernel_or_user_mode.md) 49 | - ##### 网络 50 | - [TCP 三次握手、四次挥手详解](../tech/network/tcp.md) 51 | - [HTTP 与 HTTPS 详解与区别](../tech/network/http与https.md) 52 | - [HTTPS 如何做到安全](../tech/network/https.md) 53 | - ##### 架构 54 | - [Git workflow](../tech/architecture/git_workflow.md) 55 | - [你的项目应该如何分层?](../tech/architecture/how_should_your_project_be_stratified.md) 56 | - [什么是扇入和扇出?](../tech/architecture/fanout_and_fanin.md) 57 | -------------------------------------------------------------------------------- /contents/reflection_and_summary.md: -------------------------------------------------------------------------------- 1 | # 个人博客 2 | 3 | 本仓库下存放个人博客的源文件。持续更新,欢迎 `star`。 4 | 5 | 如果大家觉得那里写的不合适的可以给我提 `Issue` 6 | 7 | --- 8 | 9 | [回到目录简介](../README.md#目录简介) 10 | 11 | 12 | #### 【反省与总结】 13 | 14 | - ##### 面试 15 | - [Python面试题精选](../reflection_and_summary/interview/Python面试题精选.md) 16 | - [面试-复习](../reflection_and_summary/interview/面试-复习.md) 17 | - [某不知名小厂面经系列 - 第一家 - 2019.05.28](../reflection_and_summary/interview/某不知名小厂面经.md) 18 | - [某不知名小厂面经系列 - 第二家 - 2019.07.11](../reflection_and_summary/interview/某不知名小厂面经_2.md) 19 | - [这段时间六家公司面经 - 2019年 - 07.11-07.22](../reflection_and_summary/interview/interview.md) 20 | - [识货 —— 面经](../reflection_and_summary/interview/shihuo.md) 21 | - [华为OD —— 面经](../reflection_and_summary/interview/hw_OD.md) 22 | - [英语流利说 —— 面经](../reflection_and_summary/interview/liulishuo.md) 23 | 24 | - ##### 其他 25 | - [给学弟学妹们总的方向及建议](../reflection_and_summary/misc/给学弟学妹们总的方向及建议.md) 26 | -------------------------------------------------------------------------------- /contents/tools.md: -------------------------------------------------------------------------------- 1 | # 个人博客 2 | 3 | 本仓库下存放个人博客的源文件。持续更新,欢迎 `star`。 4 | 5 | 如果大家觉得那里写的不合适的可以给我提 `Issue` 6 | 7 | --- 8 | 9 | [回到目录简介](../README.md#目录简介) 10 | 11 | 12 | #### 【工具】 13 | 14 | - ##### [Pycharm上传到码云或者GitHub](../tools/Pycharm上传到码云或者GitHub.md) 15 | - ##### [欢迎使用CSDN-markdown编辑器](../tools/欢迎使用CSDN-markdown编辑器.md) 16 | -------------------------------------------------------------------------------- /design/golang_analysis/golang_analysis.md: -------------------------------------------------------------------------------- 1 | # 流量统计系统 2 | 3 | 源码仓库:[这里](https://github.com/hackfengJam/golearn/tree/master/project/analysis) 4 | 5 | --- 6 | 7 | 8 | - 【run】 9 | - [run.go - 生成大量日志](./run/run.go) 10 | - 【analysis】 11 | - channel + redis 12 | - [analysis.go - 基于日志流量统计](./analysis.go) 13 | 14 | #### 流量统计系统架构 15 | ``` 16 | +--------------------------+ +---------------------+ 17 | | | | | 18 | | read log line by line | Channel(logChannel) | logConsumer | 19 | | +----------------------->+ | 20 | +--------------------------+ +---------+-----------+ 21 | | 22 | | 23 | | Channel(pvChannel uvChannel ...) 24 | | 25 | | 26 | v 27 | +------------------+-----------------------+ 28 | | | 29 | | Counter(pvCounter uvCounter ...) | 30 | | | 31 | +------------------+-----------------------+ 32 | | 33 | | 34 | | Channel(storageChannel ...) 35 | | 36 | | 37 | v 38 | +-------------------+--------------------------+ 39 | | | 40 | | dataSorage(into Redis/Hbase ...) | 41 | | | 42 | +----------------------------------------------+ 43 | 44 | ``` 45 | 46 | #### 感谢 47 | 48 | -------------------------------------------------------------------------------- /design/golang_crontab/golang_crontab.md: -------------------------------------------------------------------------------- 1 | ## Golang 开发分布式任务调度 2 | 3 | --- 4 | 5 | ### 目录 6 | 7 | [1. 架构图](#1-架构图) 8 | 9 | [2. 项目主体结构](#2-项目主体结构) 10 | 11 | [3. 其他 Golang 项目](#3-其他-Golang-项目) 12 | 13 | 14 | ### 1. 架构图 15 | 16 | ![Alt text](./images/architecture.png) 17 | 18 | 19 | ### 2. 项目主体结构 20 | 21 | - ##### Master 22 | - [ApiServer](./crontab/master/ApiServer.go) 管理后台(提供 HTTP 接口 及 前端界面,提升服务使用友好度) 23 | - [Config](./crontab/master/Config.go) 配置管理(加载服务必须配置) 24 | - [JobMgr](./crontab/master/JobMgr.go) 任务管理(任务 CRUD 至 etcd,GET/PUT/DELETE:/cron/jobs/目录下的所有任务) 25 | - [LogMgr](./crontab/master/LogMgr.go) 日志管理(日志查询,从 MongoDB 查询执行日志) 26 | - [WorkerMgr](./crontab/master/WorkerMgr.go) 服务发现(健康节点监控,GET 目录 /cron/workers/{IP地址}) 27 | - ##### Worker 28 | - [Config](./crontab/worker/Config.go) 配置管理(加载服务必须配置) 29 | - [Executor](./crontab/worker/Executor.go) 任务执行(执行一个任务) 30 | - [JobLock](./crontab/worker/JobLock.go) 分布式锁(etcd 授予租约机制,实现 分布式锁) 31 | - [JobMgr](./crontab/worker/JobMgr.go) 任务管理(etcd watch 机制,监听 /cron/jobs/目录下的所有任务 revision 向后监听变化事件) 32 | - [LogSink](./crontab/worker/LogSink.go) 日志转存(channel + 定时器 定时 buffer,批量写入执行日志 至 MongoDB) 33 | - [Register](./crontab/worker/Register.go) 服务注册 (获取服务器网卡IP地址,并通过 租约机制,注册到目录:/cron/workers/{IP地址}) 34 | - [Scheduler](./crontab/worker/Scheduler.go) 任务调度 (任务事件channel + 任务调度计划表 + 任务执行表 + 任务执行结果channel,实现调度) 35 | - ##### TODO 36 | - master 选主 37 | - 抢占 etcd 乐观锁 /cron/master 38 | - 抢到锁的成为 leader 并持续续租 39 | 40 | - 任务超时控制 41 | - web 增加任务超时配置项 42 | - worker 支持超时检查 43 | - 任务超时在日志中得到体现 44 | 45 | - 任务失败告警 46 | - etcd 写入每秒 1000次 47 | - 任务失败告警,不适宜使用 etcd,使用消息队列 48 | 49 | ### 3. 其他 Golang 项目 50 | 51 | - [原生爬虫](https://github.com/hackfengJam/golearn/tree/master/project/crawler) 52 | - [流量统计系统](https://github.com/hackfengJam/golearn/tree/master/project/analysis) 53 | - [搭建并行处理管道 - 外部排序](https://github.com/hackfengJam/golearn/tree/master/project/gointro) 54 | 55 | 56 | ### 感谢 57 | 58 | - [owenliang](https://github.com/owenliang) 59 | 60 | - [etcd 官网](https://etcd.io/) 61 | 62 | - [etcd 官方文档](https://etcd.io/docs/v3.3.12/) 63 | 64 | - [Raft 英文 paper pdf](https://ramcloud.atlassian.net/wiki/download/attachments/6586375/raft.pdf) 65 | 66 | - [Raft 作者油管讲解视频](https://www.youtube.com/watch?v=YbZ3zDzDnrw&feature=youtu.be) 67 | -------------------------------------------------------------------------------- /design/golang_crontab/images/architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/design/golang_crontab/images/architecture.png -------------------------------------------------------------------------------- /design/golang_pipeline/golang_pipeline.md: -------------------------------------------------------------------------------- 1 | # 搭建并行处理管道 2 | 3 | 4 | 源码仓库:[这里](https://github.com/hackfengJam/golearn/tree/master/project/gointro) 5 | 6 | --- 7 | 8 | - 外部排序 9 | 10 | #### 外部排序架构 11 | ``` 12 | External Sorting 13 | 14 | 15 | +--------+ +-------------------+ 16 | +--------->+ read +-------->+ internal sorting | 17 | | +--------+ +-------------------+ +-----------+ 18 | | +-------->+ merge | 19 | | +-------->+ | 20 | +----------+ | +-----------+ 21 | | | +--------+ +--------------------+ | 22 | | +--------->+ read +-------->+ internal sorting | | +------------+ +------------+ 23 | | | +--------+ +--------------------+ +-------->+ | | | 24 | | | + merge +---->+ retData | 25 | |sourceData| +-------->+ + + | 26 | | | | +------------+ +------------+ 27 | | | +--------+ +---------------------+ | 28 | | +--------->+ read +-------->+ internal sorting | | 29 | | | +--------+ +---------------------+ +-----------+ 30 | +----------+ +------->+ merge | 31 | | |------->+ | 32 | | +---------+ +---------------------+ +-----------+ 33 | +--------->+ read +------->+ internal sorting | 34 | +---------+ +---------------------+ 35 | 36 | ``` -------------------------------------------------------------------------------- /design/order/how_xx_order_system.md: -------------------------------------------------------------------------------- 1 | ## 如何设计并实现一个高可用订单系统 2 | 3 | ![Alt Text](images/order_1.png) 4 | 5 | ![Alt Text](images/order_2.png) 6 | 7 | - 订单补偿不要粗暴地使用消息队列的方式,避免中间件引发的订单丢失 8 | - 关键逻辑也不要使用缓存来进行订单的查询 9 | 10 | ![Alt Text](images/order_3.png) 11 | 12 | - 接收消息处理失败时一定要让消息重试,避免丢失 13 | 14 | ![Alt Text](images/order_4.png) 15 | 16 | - 尤其注意 return、continue 等关键字 17 | 18 | ![Alt Text](images/order_5.png) 19 | 20 | - 写数据库时,数据库事务的粒度不要太大,避免锁表,关注慢SQL 21 | 22 | - 关注数据易购的性能和稳定性,尤其在网络抖动的情况下,可能会影响用户体验 23 | 24 | - 要关注订单系统的幂等性,避免出现计费等锁雾,影响后续操作等流程 25 | 26 | 27 | ![Alt Text](images/order_6.png) 28 | 29 | ![Alt Text](images/order_7.png) 30 | 31 | ![Alt Text](images/order_8.png) 32 | 33 | 34 | - 下单服务处理接单慢 35 | 36 | - 数据库压力大 37 | 38 | - 数据异构延迟高 39 | 40 | - 缓存数据质量差 41 | 42 | ![Alt Text](images/order_9.png) 43 | 44 | ![Alt Text](images/order_10.png) 45 | 46 | - 下单服务:接单服务 -> 订单引擎 -> 订单管道 47 | 48 | ![Alt Text](images/order_11.png) 49 | 50 | ![Alt Text](images/order_12.png) 51 | 52 | ![Alt Text](images/order_13.png) 53 | 54 | ![Alt Text](images/order_14.png) 55 | 56 | - 结算页:支付完成后,页面调转到 我的服务 57 | 58 | - 提交订单 -> 下单服务 59 | 60 | - 下单服务 61 | - 写 MySQL master,双写缓存 62 | - 通过 binlog 同步 MYSQL slave -> 数据异构 -> 缓存 63 | 64 | 65 | ![Alt Text](images/order_15.png) 66 | 67 | ![Alt Text](images/order_16.png) 68 | 69 | 70 | ### DB 使用云产品 71 | 72 | order_17.png 73 | 74 | ### 感谢 75 | 76 | - [极客时间](https://time.geekbang.org/) -------------------------------------------------------------------------------- /design/order/images/order_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/design/order/images/order_1.png -------------------------------------------------------------------------------- /design/order/images/order_10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/design/order/images/order_10.png -------------------------------------------------------------------------------- /design/order/images/order_11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/design/order/images/order_11.png -------------------------------------------------------------------------------- /design/order/images/order_12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/design/order/images/order_12.png -------------------------------------------------------------------------------- /design/order/images/order_13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/design/order/images/order_13.png -------------------------------------------------------------------------------- /design/order/images/order_14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/design/order/images/order_14.png -------------------------------------------------------------------------------- /design/order/images/order_15.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/design/order/images/order_15.png -------------------------------------------------------------------------------- /design/order/images/order_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/design/order/images/order_16.png -------------------------------------------------------------------------------- /design/order/images/order_17.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/design/order/images/order_17.png -------------------------------------------------------------------------------- /design/order/images/order_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/design/order/images/order_2.png -------------------------------------------------------------------------------- /design/order/images/order_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/design/order/images/order_3.png -------------------------------------------------------------------------------- /design/order/images/order_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/design/order/images/order_4.png -------------------------------------------------------------------------------- /design/order/images/order_5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/design/order/images/order_5.png -------------------------------------------------------------------------------- /design/order/images/order_6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/design/order/images/order_6.png -------------------------------------------------------------------------------- /design/order/images/order_7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/design/order/images/order_7.png -------------------------------------------------------------------------------- /design/order/images/order_8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/design/order/images/order_8.png -------------------------------------------------------------------------------- /design/order/images/order_9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/design/order/images/order_9.png -------------------------------------------------------------------------------- /design/red_envelope/red_envelope.md: -------------------------------------------------------------------------------- 1 | # Golang 实现红包 2 | 3 | 4 | ## 红包业务为背景按照软件研发的流程 5 | ``` 6 | +-------------+ +-------------+ +--------------+ +---------------+ 7 | | | | | | | | | 8 | | 需 求 分 析 +------>+ 概 要 设 计 +----->+ 详 细 设 计 +----->+ 开 发 | 9 | | | | | | | | | 10 | +-------------+ +-------------+ +--------------+ +------+--------+ 11 | | 12 | | 13 | v 14 | +------+--------+ 15 | | | 16 | | 测 试 | 17 | | | 18 | +---------------+ 19 | 20 | ``` 21 | 22 | ## 流程简介 23 | 24 | - 需求分析方法和用例定义方法 25 | 26 | - 四色建模法和核心模型设计 27 | 28 | - 系统架构设计 29 | 30 | - 数据库物理模型设计 31 | 32 | - 数据库物理模型设计 33 | 34 | - Golang 编程实践 35 | 36 | 37 | ## 探讨问题 38 | 39 | - 资金交易安全问题探讨 40 | 41 | - 超卖问题的解决方案 42 | 43 | - 表结构设计中的性能优化考虑 44 | 45 | - 红包拆解和红包算法 46 | 47 | - 系统设计和算法的选择 48 | 49 | ## 红包秒杀系统架构概览 50 | 51 | todo 52 | 53 | ## 红包系统演进之路 54 | 55 | - 满足红包业务需求,快速迭代上线 56 | 57 | - 出现超卖现象,事务锁来帮忙 58 | 59 | - 流量增加,收红包出现性能瓶颈,改为乐观锁,性能提高3倍 60 | 61 | - 流量继续增加,乐观锁也扛不住了,那就上缓存吧 62 | 63 | - 缓存还没跑溜呢,服务器挂了,数据丢失了? 64 | 65 | - 分布式消息队列来解决异步写 66 | 67 | - 数据分片来解决数据库横向扩展? 68 | 69 | - Golang 编码 0到1 构建红包秒杀系统 70 | 71 | ## 学到什么? 72 | 73 | 1. 红包业务系统的需求分析方法和用例定义方法 74 | 75 | 2. 学习四色建模法的基本知识,并结合红包业务场景把需求转化为业务模型来深入学习四色建模法 76 | 77 | 3. 学习在四色建模法过程中如何绘制时间轴事件模型图? 78 | 79 | 4. 通过业务模型如何来拆分业务系统模块?然后通过业务模型学习如何定义业务边界? 80 | 81 | 5. 从业务模型和架构目标和愿景来学习架构设计过程、设计方法? 82 | 83 | 6. 学习如何从业务模型推导物理模型? 84 | 85 | 7. 如何从数据库物理模型设计上和系统架构设计上来优化性能? 86 | 87 | 8. 如何解决资金交易安全(超卖)问题和资金交易上的性能优化?并结合超卖方案来学习使用 Golang 编程语言做基准测试。 88 | 89 | 9. 如何在不同的场景和时机中设计和应用红包算法? 90 | 91 | 10. 学习 Golang 项目如何构建? 92 | 93 | 11. 在 Golang 中如何设计和解决基础公共资源的访问问题? 94 | 95 | 12. 学习使用 Golang 接口来设计基础资源加载和启动的基础设置组件,学习对基础资源组件生命周期的管理的设计? 96 | 97 | ## 感谢 98 | 99 | [3小时极简春节抢红包之Go的实战](https://www.imooc.com/learn/1101) 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | -------------------------------------------------------------------------------- /framework/elasticsearch/Elasticsearch环境搭建.md: -------------------------------------------------------------------------------- 1 | # Elasticsearch基础环境搭建 2 | 3 | ## 1.Elasticsearch介绍 4 | 5 | ### 1.1 Elasticsearch - Wikipedia 6 | 7 | 译自[Elasticsearch - 维基百科](https://en.wikipedia.org/wiki/Elasticsearch): 8 | 9 | Elasticsearch是基于Lucene的搜索引擎。它提供了一个分布式、多租户可全文搜索引擎通过HTTP Web界面和无模式JSON文件。Elasticsearch java开发的,作为Apache许可证条款下的开源发布。官方客户端的java,是可用的。NET(C #),PHP,Python,Apache的Groovy和许多其他语言。Elasticsearch是最受欢迎的企业搜索引擎,其次是Apache Solr,也基于Lucene。 10 | 11 | Elasticsearch是一起开发数据采集和日志分析引擎叫Logstash,以及分析和可视化平台“Kibana。这三种产品被设计成作为一个集成解决方案使用,称为“弹性堆栈”(以前是“ELK 堆”)。 12 | 13 | ### 1.2 我们搭建一个网站或者程序,希望添加搜索功能,发现搜索工作很难: 14 | 15 | 1. 我们希望搜索解决方案要高效 16 | 2. 我们希望零配置和完全免费的搜索方案 17 | 3. 我们希望能够简单的通过json和http与搜索引擎交互 18 | 4. 我们希望我们的搜索服务器稳定 19 | 5. 我们希望能够简单的将一台服务器扩展到上百台 20 | 21 | ## 2.Elasticsearch安装 22 | 23 | 1. 安装elasticsearch-rtf 24 | 2. head插件 25 | 3. kibana的安装 26 | 27 | --- 28 | 29 | ### 2.1 安装 jdk 30 | 自行 [百度](https://www.baidu.com/) / [谷歌](https://www.google.com)。 31 | 32 | ### 2.2 安装 elasticsearch-rtf 33 | 34 | 前言:什么是Elasticsearch-RTF? RTF是Ready To Fly的缩写,在航模里面,表示无需自己组装零件即可直接上手即飞的航空模型,Elasticsearch-RTF是针对中文的一个发行版,即使用最新稳定的elasticsearch版本,并且帮你下载测试好对应的插件,如中文分词插件等,目的是让你可以下载下来就可以直接的使用(虽然es已经很简单了,但是很多新手还是需要去花时间去找配置,中间的过程其实很痛苦),当然等你对这些都熟悉了之后,你完全可以自己去diy了,跟linux的众多发行版是一个意思。 35 | 36 | 引自:[https://github.com/medcl/elasticsearch-rtf](https://github.com/medcl/elasticsearch-rtf) 37 | 38 | --- 39 | 40 | 1. 从[Github](https://github.com)下载:[elasticsearch-rtf](https://github.com/medcl/elasticsearch-rtf) 41 | 2. 解压 42 | 3. 运行,切换到```bin```目录下 43 | - ***Windows***下运行```elasticsearch.bat``` 44 | - ***Mac/Linux***下运行```./elasticsearch``` 45 | - 切记不要用***root***用户去运行,否则会报错,具体自行 [百度](https://www.baidu.com/) / [谷歌](https://www.google.com) 46 | 4. 效果: 47 | 48 | ![Alt text](images/ElasticSearc环境搭建-1.png "结果") 49 | 5. 浏览器输入:```localhost:9200``` 50 | 51 | ![Alt text](images/ElasticSearc环境搭建-2.png "结果") 52 | 53 | 54 | 55 | ### 2.3 安装 elasticsearch-head 56 | 57 | 1. 从[Github](https://github.com)下载:[elasticsearch-head](https://github.com/mobz/elasticsearch-head) 58 | 2. 解压 59 | 3. 安装cnpm:[安装npm及cnpm](https://www.cnblogs.com/yominhi/p/7039795.html) 60 | 4. Install:切换到 ```elasticsearch-head``` 目录下,运行```cnpm install``` 61 | 5. 运行:直接 ```cpnm run start``` 62 | 6. 效果: 63 | 64 | ![Alt text](images/ElasticSearc环境搭建-3.png "结果") 65 | 7. ①.发现输入:从浏览器访问```localhost:9200```是没问题,但是***elasticsearch-head***就是连不上。 66 | 67 | ![Alt text](images/ElasticSearc环境搭建-2.png "结果") 68 | 69 | ②.浏览器输入:```localhost:9100```也显示确实未连接。 70 | ![Alt text](images/ElasticSearc环境搭建-4.png "结果") 71 | 72 | ***注:这是由于elasticsearch的安全策略,默认不允许使用第三方服务(版本5之前elasticsearch-head是属于elasticsearch 的,但现在是单独的服务了,所以为出现这种情况)*** 73 | 74 | 8. 设置安全策略 75 |
 76 | 	http.cors.enabled: true
 77 | 	http.cors.allow-origin: "*"
 78 | 	http.cors.allow-methods: OPTIONS, HEAD, GET, POST, PUT, DELETE
 79 | 	http.cors.allow-headers: "X-Requested-With, Content-Type, Content-Length, X-User"
 80 | 
81 | 82 | 将以上内容复制到```config/elasticsearch.yaml```最后,然后重启```es```和```head```即可 83 | 84 | ### 2.4 安装 kibana 85 | 86 | 前言:Kibana是一个开放源代码的分析和可视化平台的设计与Elasticsearch。你用Kibana搜索,查看,并与存储在Elasticsearch指标数据进行交互。您可以轻松地执行高级数据分析,并在各种图表、表格和地图中可视化您的数据。 87 | 88 | Kibana可以很容易理解大量数据。简单的,基于浏览器的界面,使您可以快速创建和共享的动态仪表盘显示变化到Elasticsearch实时查询。你可以在几分钟之内安装和开始探索你的Elasticsearch索引数据,不需要写任何代码,没有其他基础软件依赖 89 | 90 | 引自:[https://www.elastic.co/guide/en/kibana/master/introduction.html](https://www.elastic.co/guide/en/kibana/master/introduction.html) 91 | 92 | --- 93 | 94 | 1. kibana官网下载:[Kibana](https://www.elastic.co/downloads/kibana),我用的是 [Kibana 5.1.2](https://www.elastic.co/downloads/past-releases/kibana-5-1-2) 95 | 2. 解压 96 | 3. 运行,切换到```bin```目录下 97 | - ***Windows***下运行```kibana ``` 98 | - ***Mac/Linux***下运行```./kibana``` 99 | 4. 效果: 100 | 101 | ![Alt text](images/ElasticSearc环境搭建-5.png "结果") 102 | 5. 浏览器输入:```localhost:5601``` 103 | 104 | ![Alt text](images/ElasticSearc环境搭建-6.png "结果") 105 | 6. 点击Dev Tools: 106 | 107 | ![Alt text](images/ElasticSearc环境搭建-7.png "结果") 108 | 109 | 7. 接下来,请开始你的表演: 110 | 111 | ![Alt text](images/ElasticSearc环境搭建-8.png "结果") 112 | 113 | 114 | 115 | -------------------------------------------------------------------------------- /framework/elasticsearch/images/ElasticSearc环境搭建-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/framework/elasticsearch/images/ElasticSearc环境搭建-1.png -------------------------------------------------------------------------------- /framework/elasticsearch/images/ElasticSearc环境搭建-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/framework/elasticsearch/images/ElasticSearc环境搭建-2.png -------------------------------------------------------------------------------- /framework/elasticsearch/images/ElasticSearc环境搭建-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/framework/elasticsearch/images/ElasticSearc环境搭建-3.png -------------------------------------------------------------------------------- /framework/elasticsearch/images/ElasticSearc环境搭建-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/framework/elasticsearch/images/ElasticSearc环境搭建-4.png -------------------------------------------------------------------------------- /framework/elasticsearch/images/ElasticSearc环境搭建-5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/framework/elasticsearch/images/ElasticSearc环境搭建-5.png -------------------------------------------------------------------------------- /framework/elasticsearch/images/ElasticSearc环境搭建-6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/framework/elasticsearch/images/ElasticSearc环境搭建-6.png -------------------------------------------------------------------------------- /framework/elasticsearch/images/ElasticSearc环境搭建-7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/framework/elasticsearch/images/ElasticSearc环境搭建-7.png -------------------------------------------------------------------------------- /framework/elasticsearch/images/ElasticSearc环境搭建-8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/framework/elasticsearch/images/ElasticSearc环境搭建-8.png -------------------------------------------------------------------------------- /framework/elasticsearch/搜索引擎_Elasticsearch_pending.md: -------------------------------------------------------------------------------- 1 | # Elasticsearch - 搜索引擎 2 | 3 | elasticsearch mysql 4 | index(索引) 数据库 5 | type(类型) 表 6 | document(文档) 行 7 | fields 列 8 | 9 | 10 | 方法 11 | GET 12 | POST 13 | PUT 14 | DELETE 15 | 16 | 17 | 倒排索引 18 | 倒排索引源于实际应用中需要根据属性的值来查找记录,这种索引表中的每一项都包括一个属性值和具有该属性值的各记录的地址。由于不是由记录来确定属性值,而是由属性值来确定记录的位置,因而称为倒排索引(inverted index)。带有倒排索引的文件我们称为倒排索引文件,简称倒排文件(inverted file)。 19 | 20 | 例子 21 | 文件A: 通过python django搭建网站 22 | 23 | 24 | 映射(mapping) 25 | 当我们创建索引的时候,可以预先定义字段的类型以及相关属性 26 | 27 | elasticsearch会根据JSON源数据的基础类型猜测你想要的字段映射。将输入的数据转变成可搜索的索引项。Mapping就是我们自己定义的字段的数据类型,同时告诉elasticsearch如何索引数据以及是否可以被搜索。 28 | 29 | 作用:会让索引建立的更加细致和完善 30 | 31 | 类型:静态映射和动态映射 32 | 33 | 内置类型 34 | string类型:text,keyword(string类型在es5开始已经废弃) 35 | 数字类型:long,integer,short,byte,double,float 36 | 日期类型:date 37 | bool类型:boolean 38 | binary类型:binary 39 | 复杂类型:object(对象),nested(对象集) 40 | geo类型:geo-point,geo-shape 41 | 专业类型:ip,competition 42 | 43 | 属性 描述 适合类型 44 | store 值为yes表示存储,为no表示不存储,默认为no all 45 | 46 | index yes表示分析,no表示不分析,默认值为true string 47 | 48 | null_value 如果字段为空,可以设置一个默认值,比如"NA" all 49 | 50 | analyzer 可以设置索引和索引时用的分析器,默认使用的是standard分析器,还可以使用 whitespace、simple、english all 51 | 52 | include_in_all 默认es为每个文档定义一个特殊域_all,它的作用是让每个字段被搜索到,如果不想某个字段被搜索到,可以设置为false all 53 | 54 | format 时间格式字符串的模式 date 55 | 56 | 57 | 查询 58 | elasticsearch是功能非常强大的搜索引擎,使用它的目的就是为了快速的查询到需要的数据。 59 | 60 | 查询分类: 61 | - 基本查询:使用elasticsearch内置查询条件进行查询 62 | - 组合查询:把多个查询组合在一起进行复合查询 63 | - 过滤:查询同时,通过filter条件下在不影响打分的情况下筛选数据 64 | 65 | analyzer:"ik_max_word" 66 | 67 | 68 | -------------------------------------------------------------------------------- /framework/scrapy/images/scrapy_architecture_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/framework/scrapy/images/scrapy_architecture_01.png -------------------------------------------------------------------------------- /framework/scrapy/images/scrapy_architecture_02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/framework/scrapy/images/scrapy_architecture_02.png -------------------------------------------------------------------------------- /framework/scrapy/第一步Scrapy框架原理.md: -------------------------------------------------------------------------------- 1 | ## Scrapy架构原理初探 2 | 3 | ### 1.Scrapy架构图 4 | ![Alt text](images/scrapy_architecture_01.png) 5 | #### 1. Scrapy Engine(Scrapy引擎) 6 | 引擎负责控制数据流在系统中所有组件中流动,并在相应动作发生时触发事件。 7 | 8 | #### 2. Scheduler(调度器) 9 | 调度器从引擎接受request并将他们入队,以便以后引擎请求他们时提供给引擎 10 | 11 | #### 3.Downloader(下载器) 12 | 下载器负责获取页面数据并提供给引擎 13 | 14 | #### 4.Spiders 15 | Spider是Scrapy用户编写用于分析response并提取item(即获取到item)或额外跟进的URL的类。每个spider负责处理一个特定(或一些)网站。更多内容请看[Spider](http://scrapy-chs.readthedocs.io/zh_CN/latest/topics/spiders.html#topics-spiders) 16 | 17 | #### 5.Item Pipeline 18 | Item Pipeline负责处理被spider提取出来的item。典型的处理有清理、验证及持久化(例如存储到数据库中)。更多内容请看[Item Pipeline](http://scrapy-chs.readthedocs.io/zh_CN/latest/topics/item-pipeline.html#topics-item-pipeline) 19 | 20 | #### 6.下载器中间件(Downloader middlewares) 21 | 下载器中间件是在引擎及下载器之间的特定钩子(specific hook),处理Downloader传递给引擎的response。其提供了一个简单的机制,通过插入自定义代码来扩展Scrapy功能。更多内容请看[下载器中间件(Downloader middlewares)](http://scrapy-chs.readthedocs.io/zh_CN/latest/topics/downloader-middleware.html#topics-downloader-middleware) 22 | 23 | #### 7.Spider中间件(Spider middlewares) 24 | Spider中间件是在引擎及Spider之间的特定钩子(specific hook),处理spider的输入(response)和输出(items及requests)。 其提供了一个简便的机制,通过插入自定义代码来扩展Scrapy功能。更多内容请看 [Spider中间件(Middleware)](http://scrapy-chs.readthedocs.io/zh_CN/latest/topics/spider-middleware.html#topics-spider-middleware) 。 25 | 26 | 27 | 28 | 29 | > ### 2.来自[官方文档][guanfang-doc]的架构浏览 30 | 31 | 32 | > ![Alt text](images/scrapy_architecture_02.png) 33 | 34 | > #### 数据流(Data flow) 35 | > Scrapy中的数据流由执行引擎控制,其过程如下: 36 | 37 | > 1. 引擎打开一个网站(open a domain),找到处理该网站的Spider并向该spider请求第一个要爬取的URL(s)。 38 | 2. 引擎从Spider中获取到第一个要爬取的URL并在调度器(Scheduler)以Request调度。 39 | 3. 引擎向调度器请求下一个要爬取的URL。 40 | 4. 调度器返回下一个要爬取的URL给引擎,引擎将URL通过下载中间件(请求(request)方向)转发给下载器(Downloader)。 41 | 5. 一旦页面下载完毕,下载器生成一个该页面的Response,并将其通过下载中间件(返回(response)方向)发送给引擎。 42 | 6. 引擎从下载器中接收到Response并通过Spider中间件(输入方向)发送给Spider处理。 43 | 7. Spider处理Response并返回爬取到的Item及(跟进的)新的Request给引擎。 44 | 8. 引擎将(Spider返回的)爬取到的Item给Item Pipeline,将(Spider返回的)Request给调度器。 45 | 9. (从第二步)重复直到调度器中没有更多地request,引擎关闭该网站。 46 | 47 | > #### 事件驱动网络(Event-driven networking) 48 | Scrapy基于事件驱动网络框架 [Twisted](http://twistedmatrix.com/trac/) 编写。因此,Scrapy基于并发性考虑由非阻塞(即异步)的实现。 49 | 50 | > 关于异步编程及Twisted更多的内容请查看下列链接: 51 | 52 | > [Introduction to Deferreds in Twisted](http://twistedmatrix.com/documents/current/core/howto/defer-intro.html) 53 | 54 | > [Twisted - hello, asynchronous programming](http://jessenoller.com/2009/02/11/twisted-hello-asynchronous-programming/) 55 | 56 | 57 | 58 | 59 | 60 | [guanfang-doc]:https://docs.scrapy.org/en/latest/topics/architecture.html -------------------------------------------------------------------------------- /reflection_and_summary/interview/hw_OD.md: -------------------------------------------------------------------------------- 1 | ## 华为OD —— 面经 2 | 3 | #### 2020年xx月xx日 4 | 5 | #### 目录 6 | 7 | - [1. 先看一下 jd](#1-先看一下-jd) 8 | - [2. 本人大致情况](#2-本人大致情况) 9 | - [3. 此次流程](#3此次流程) 10 | - [3.1 笔试](#31-笔试) 11 | - [3.2 一轮技术面](#32-一轮技术面) 12 | - [3.3 二轮技术面](#33-二轮技术面) 13 | 14 | - [4. 结果](#4-结果) 15 | 16 | - [5. 总结](#5总结) 17 | 18 | 19 | ### 1. 先看一下 jd 20 | 21 | ![Alt Text](./images/huawei_od_jd.png) 22 | 23 | ### 2. 本人大致情况 24 | 25 | - 18年毕业,17年11月份实习 26 | - 2017.11 - 2019.08 某C轮小厂 - Python开发工程师 27 | - 2019.08 - 至今 上海突进科技有限公司 - Golang开发工程师 28 | 29 | ### 3. 此次流程 30 | 31 | #### 3.1 笔试 32 | 33 | - [华为机试](https://github.com/hackfengJam/LeetCode/commit/04305863ea1cd24c03b9cc7dc0f8a17f7e586a1b) 34 | 35 | #### 3.2 一轮技术面 36 | 37 | - 描述下现在做的事情 38 | - 有点忘记了... 39 | 40 | - coding 41 | - 输入:n 42 | - 输出:小于它的所有质数的个数。 43 | 44 | #### 3.3 二轮技术面 45 | 46 | - 描述下现在做的事情 47 | 48 | - 描述下,下单流程 49 | - 订单这边涉及多少表 50 | - 订单量级多少? 51 | - 数据库压力是否会很大? 52 | - 是否需要冷热储备? 53 | - 怎么分库的? 54 | 55 | - 接口是存在权限控制?有单独认证服务吗? 56 | 57 | - 平时如何排查问题? 58 | - pprof? 59 | - 用过什么 debug 工具,gdb 有用过吗? 60 | - 怎么控制添加和取消断点? 61 | 62 | - 你们服务是怎么打包的? 63 | - 对 makefile 是否了解? 64 | - 服务有没有调用过 c代码? 65 | - 服务都是部署在云上吗? 66 | 67 | - 是否用过排序算法?常用的排序算法?通用的排序算法,怎么设计接口? 68 | 69 | - map 70 | - map key 是否是有序的? 71 | - 多次 json.Marshal 结果是否相同? 72 | - key 是否可以为 指针? 73 | - channel 是否可以当 key? 74 | - 结构体是否可以当 key? 75 | 76 | - 序列化 77 | - chan 是否可以序列化? 78 | - 用过哪些序列化工具? 79 | - 一个结构体 成员变量 是一个指向自己的指针,是否可以 序列化? 80 | - 如果自己做应该怎么做? 81 | 82 | - 说下开闭原则、依赖倒转?用过哪些设计模式 83 | 84 | - coding 85 | - 判断二叉树是否为平衡二叉树 86 | 87 | 88 | ### 4. 结果 89 | 90 | - continuing 91 | 92 | ### 5. 总结 93 | 94 | - 加油吧⛽️ 95 | 96 | 97 | #### TODO 98 | 99 | - 面试答案未及时整理,后续补充,感谢持续关注:) 100 | 101 | #### 感谢 102 | 103 | - 感谢面试官 -------------------------------------------------------------------------------- /reflection_and_summary/interview/images/amino_jd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/reflection_and_summary/interview/images/amino_jd.png -------------------------------------------------------------------------------- /reflection_and_summary/interview/images/huawei_od_jd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/reflection_and_summary/interview/images/huawei_od_jd.png -------------------------------------------------------------------------------- /reflection_and_summary/interview/images/liao_jd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/reflection_and_summary/interview/images/liao_jd.png -------------------------------------------------------------------------------- /reflection_and_summary/interview/images/liulishuo_jd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/reflection_and_summary/interview/images/liulishuo_jd.png -------------------------------------------------------------------------------- /reflection_and_summary/interview/images/shihuo_jd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/reflection_and_summary/interview/images/shihuo_jd.png -------------------------------------------------------------------------------- /reflection_and_summary/interview/liulishuo.md: -------------------------------------------------------------------------------- 1 | ## 英语流利说 —— 面经 2 | 3 | #### 2020年xx月xx日 4 | 5 | #### 目录 6 | 7 | - [1. 先看一下 jd](#1-先看一下-jd) 8 | - [2. 本人大致情况](#2-本人大致情况) 9 | - [3. 此次流程](#3-此次流程) 10 | - [3.1 一轮技术面](#31-一轮技术面) 11 | - [3.2 二轮技术面](#32-二轮技术面) 12 | - [3.3 三轮技术面](#33-三轮技术面) 13 | - [3.4 四轮技术面](#34-四轮技术面) 14 | - [3.5 五轮技术面](#35-五轮技术面) 15 | - [3.6 HR 面](#36-HR-面) 16 | 17 | - [4. 结果](#4-结果) 18 | 19 | - [5. 总结](#5总结) 20 | 21 | 22 | ### 1. 先看一下 jd 23 | 24 | 注:[链接](https://www.zhipin.com/job_detail/ae4b42c8e320b3483nBz39u0EFY~.html?ka=hot-job-1) 25 | 26 | ![Alt Text](./images/liulishuo_jd.png) 27 | 28 | 29 | ### 2. 本人大致情况 30 | 31 | - 18年毕业,17年11月份实习 32 | - 2017.11 - 2019.08 某C轮小厂 - Python开发工程师 33 | - 2019.08 - 至今 上海突进科技有限公司 - Golang开发工程师 34 | 35 | ### 3. 此次流程 36 | 37 | #### 3.1 一轮技术面 38 | 39 | 第一轮是:电面 40 | 41 | - go 的并发怎么做的 42 | - goroutine 和 其他语言常见的多线程 有什么区别 43 | - 介绍 goroutine 44 | - go routine 如何同步 45 | - go channel 底层 46 | - gmp 47 | - 介绍 context 48 | - 自己实现 timeout 怎么做 49 | - 实现有序 map 50 | - kafka 存储机制 51 | - consul 平时用来做什么 52 | - 说一下 raft 53 | - redis zset 底层实现 54 | - 一主、多主 55 | 56 | #### 3.2 二轮技术面 57 | 58 | - 自我介绍 59 | 60 | - git rebase、merge 61 | 62 | - 看你有了解过安全,问下这方面吧 63 | - 中间人攻击、重放攻击和嗅探? 64 | - 防重放攻击怎么实现的? 65 | - 幂等怎么处理? 66 | - sql 注入,怎么预防的? 67 | - 描述下 https 68 | - https 用的加密协议,与之前 RSA 有什么不同 。 xxxK(没了解过) ? 69 | 70 | - 说一下你参与 71 | - 密钥服务项目 72 | - 参与的支付重构项目 73 | 74 | - 集群内部微服务之间负载均衡用的什么,在哪端做的 75 | 76 | - 平时服务监控怎么做的 77 | - 介绍了平时都会关注哪些监控,包括制定的一些业务监控 78 | - 顺带提了一下最近做的,支付渠道业务降级 79 | 80 | - 聊了聊 ACM 81 | 82 | - 做题 83 | - 灯泡开关问题 84 | 85 | #### 3.3 三轮技术面 86 | 87 | 88 | - 说一下你参与的会员签约项目 89 | - 会员续约怎么做的 90 | 91 | - 服务用的是否是物理机 92 | 93 | - 30 亿的数据表,你觉得该怎么优化 94 | - 分库分表,双写不一致问题处理 95 | 96 | - 说一下你的参与的基建工作 97 | - 简单介绍了下我们当前的 workflow ,平时发布流程 98 | - 然后讨论了下 service mesh(所谓的) 99 | 100 | - 设计:用户学习打卡,功能点:打卡、补打卡、查看连续打卡天数、总打卡天数、查看一段时间打卡日历 101 | 102 | - 扯了点其他的,有点忘记了 103 | 104 | - 做题 105 | - go defer 106 | - 连续子数组的最大和 107 | - 删除一次得到子数组最大和(上一题进阶) 108 | 109 | #### 3.4 四轮技术面 110 | 111 | 112 | - goroutine 和 通常的线程 区别 113 | - channel 同步 114 | - goroutine 有遇到什么坑 115 | - 聊了经历的一些事故 116 | 117 | - kafka 118 | - 对比一下 kafka 和其他 MQ 119 | - kafka 的 topic,partition 120 | - kafka 如何保证不丢消息 121 | - kafka 如何保证精确一次投放消息 122 | - 说一下 consumer group 123 | - consumer 是不是越多越好 124 | - partition 是不是越多越好 125 | - 业务方如何保证消费幂等 126 | - 业务如何处理 消息处理失败 127 | - 非法消息处理 128 | - 涉及到多个 rpc 调用,某一个 rpc 出错 129 | - kafka 底层用的通信协议 130 | - 没答出来。面试官:用的 MQTT。我:记得之前了解 IM 服务好像用的这个协议 131 | - 平时 kafka 监控这么做的 132 | - 就说平时没有 kafka 权限,只能在业务这边自己定制 metrics,自己打点 133 | - 然后介绍了下,去年刚来时经历的一次事故,导致 kafka 消息的堆积 134 | 135 | - 聊一些工作时遇到的问题 136 | - 假如 有产品/Leader 告诉你,帮忙加个小功能点;但是你知道实现会使代码非常恶心。你会怎么办? 137 | - 其他的有点忘记 138 | 139 | - 做题 140 | - 判断链表存在环 141 | 142 | #### 3.5 五轮技术面 143 | 144 | - 自我介绍 145 | 146 | - 设计 147 | - 实现功能:手机号发验证码、校验验证码:五分钟内所有验证码都可以用、验证码频控 148 | 149 | - 流控 150 | - 并发控制,用 go 怎么实现 151 | - go 的 waitGroup,errorGroup 152 | - 随便聊了聊技术 153 | 154 | - 未来岗位会做的事情 155 | - 聊了聊我的 github 156 | - 关于业务和技术的看法 157 | - 为什么要来流利说,上海这边去 头条、PDD 如何 158 | 159 | #### 3.6 HR 面 160 | 161 | 162 | - 我 163 | - Q:当前业务如何 164 | - A:说了很多 165 | - Q:后续工作的部门 166 | - A:后续会根据评估安排岗位 167 | 168 | - HR 169 | - Q:面试体验如何,对面试技术官感觉如何 170 | - A:略 171 | - Q:为什么选择流利说 172 | - A:略 173 | - Q:为什么要从上家离开 174 | - A:略 175 | - Q:选公司的时候,考虑哪些因素 176 | - A:略 177 | - Q:下个岗位有什么期待 178 | - A:略 179 | - Q:当前是否还有别的面试 180 | - A:略 181 | - Q:薪资问题 182 | - A:暂时没想好。 183 | 184 | 185 | ### 4. 结果 186 | 187 | - continuing 188 | 189 | ### 5. 总结 190 | 191 | - 应该是过了。因为薪资问题,我这边还没有给确定的数她们说需要商量下(周五晚上面的,说是下周给我同步) 192 | - 体验还是不错的,面试官人都挺不错;不是说一问一答,还是交流过程中把讨论的问题解决 193 | - 电面 + 现场五轮;效率很高,但是对候选人不太友好,后面有点面不动了 194 | - 还是有一些问到的 实际问题 值得自己后续,将细节考虑清楚 195 | 196 | #### TODO 197 | 198 | - 面试答案未及时整理,后续补充,感谢持续关注:) 199 | 200 | #### 感谢 201 | 202 | - 感谢面试官 203 | - 感谢 HR -------------------------------------------------------------------------------- /reflection_and_summary/interview/shihuo.md: -------------------------------------------------------------------------------- 1 | ## 识货 —— 面经 2 | 3 | #### 2020年xx月xx日 4 | 5 | #### 目录 6 | 7 | - [1. 先看一下 jd](#1-先看一下-jd) 8 | - [2. 本人大致情况](#2-本人大致情况) 9 | - [3. 此次流程](#3此次流程) 10 | - [3.1 一轮技术面](#31-一轮技术面) 11 | 12 | - [4. 结果](#4-结果) 13 | 14 | - [5. 总结](#5总结) 15 | 16 | 17 | ### 1. 先看一下 jd 18 | 19 | ![Alt Text](./images/shihuo_jd.png) 20 | 21 | ### 2. 本人大致情况 22 | 23 | - 18年毕业,17年11月份实习 24 | - 2017.11 - 2019.08 某C轮小厂 - Python开发工程师 25 | - 2019.08 - 至今 上海突进科技有限公司 - Golang开发工程师 26 | 27 | ### 3. 此次流程 28 | 29 | #### 3.1 一轮技术面 30 | 31 | 先给了几道题 32 | - golang 里面 channel 是什么?原理是什么? 33 | - golang 里面 map 是怎么实现的?为什么并发不安全?有没有 不加锁并发安全的 map 34 | - go 里面可读锁和互斥锁?怎么实现的,它们区别是是什么? 35 | - 平时怎么排查问题的? 36 | - http1、http2 和 grpc 的关系与区别 37 | - redis zeset、hashmap 底层是什么 38 | - 描述自己平时使用较多的两个mq,并对比它们差异 39 | - golang里面逃逸分析是怎么样的?如何避免内存逃逸 40 | - mysql 如何主动加锁和被动加锁 41 | 42 | 开始面试 43 | 44 | - 聊一下项目 45 | 46 | - 看过 go 的源码吗? 47 | 48 | - 实现一个迭代器用 channel 49 | 50 | - map 怎么实现的? 51 | 52 | - 内存对齐 53 | 54 | - sync 包下都有那些东西 55 | - sync pool 一般什么时候用 56 | - 并发和互斥锁怎么实现 57 | - Map 实现 58 | - 原子操作底层原理 59 | 60 | - 说一下 https 61 | 62 | - 说一下 mysql 的 MVCC 63 | 64 | - redis 为什么这么快 65 | - redis 用过哪些数据结构? list、set 一般什么场景使用 66 | - epoll? 红黑树说一下 67 | 68 | ### 4. 结果 69 | 70 | __挂了__ 71 | 72 | ### 5. 总结 73 | 74 | - 面试官评价:我觉得你基础非常好,但是业务描述能力不行,让人觉得你做的业务过于简单;甚至会对你业务理解与处理能力没有信心。 75 | 76 | - 反思 77 | - 这次面试完,需要准备下做的业务 78 | - 最好能做到有信心,向一个完全不了解该业务的技术,描述清楚 79 | 80 | #### TODO 81 | 82 | - 面试答案未及时整理,后续补充,感谢持续关注:) 83 | 84 | #### 感谢 85 | 86 | - 感谢猎头推荐 87 | - 感谢此轮面试官时间成本,给予宝贵建议 88 | -------------------------------------------------------------------------------- /reflection_and_summary/interview/某不知名小厂面经.md: -------------------------------------------------------------------------------- 1 | ## 某不知名小厂面经 - 第一家 2 | 3 | #### 2019年5月28日 4 | 5 | #### 目录 6 | 7 | - [1. 先看一下 jd](#1-先看一下-jd) 8 | - [2. 本人大致情况](#2-本人大致情况) 9 | - [3. 和猎头说的期望](#3-和猎头说的期望) 10 | - [4. 此次流程](#4此次流程) 11 | - [4.1 初筛](#41-初筛) 12 | - [4.1.1 给了一道题目,以附件形式提交](#411-给了一道题目然后以附件形式提交) 13 | - [4.1.2 结果](#412-结果) 14 | - [4.1.3 接下来流程](#413-接下来流程) 15 | - [4.2 两轮技术面](#42-两轮技术面) 16 | - [4.2.1 一面](#421-一面) 17 | - [4.2.1.1 聊自己写的项目](#4211-所写的项目哪些有对你帮助很多有什么挑战如何克服的学到了什么) 18 | - [4.2.1.2 MySQL 了解多少?](#4212-mysql-了解多少) 19 | - [4.2.1.3 设计一个点赞系统](#4213-设计一个-微博帖子post的-点赞系统) 20 | - [4.2.1.4 一面总结](#4214-一面总结) 21 | - [4.2.2 二面](#42-两轮技术面) 22 | - [4.2.2.1 简单的算法](#4221-一个数组长度为-n有个数出现次数大于n2找出这个数) 23 | - [4.2.2.2 网络](#4222-你网络还不错吧这部分直接爆炸我嗯自信满满是最骚的) 24 | - [4.2.2.3 二面总结](#4223-二面总结) 25 | 26 | - [5. 结果](#5-结果) 27 | 28 | - [6. 总结](#6总结) 29 | 30 | 31 | ### 1. 先看一下 jd 32 | 33 | ![Alt Text](./images/amino_jd.png) 34 | 35 | ### 2. 本人大致情况 36 | 37 | - 18年毕业,17年11月份出去实习+转正至今(马马虎虎算一年经验了吧=。=)。 38 | 39 | - 某C轮小厂,做 Python开发工程师。(工作制:965,算时薪比的话还是相当可观的,手动滑稽: )) 40 | 41 | - 目前薪资:正常价格,你懂得! 42 | 43 | 44 | ### 3. 和猎头说的期望 45 | 46 | - 对方规模不能太小,起码不能比我司还低吧 47 | 48 | - 这里指的是管理层对公司定位及产品方向还是有的,千万别是连自己做什么都不知道,那就没法玩了 49 | 50 | - 薪资:package 25w(按 base * 12 算的,说白了就是 20k左右/月,这是猎头提议的:低了没必要跳槽) 51 | 52 | - 其他,貌似除了薪资其他的也没啥好说的? 53 | 54 | 题外话: 这个是直接告知到对方公司的,作为参考 55 | 56 | ### 4. 此次流程 57 | 58 | #### 4.1 初筛 59 | 60 | ##### 4.1.1 给了一道题目,然后以附件形式提交 61 | 62 | 我提交的附件,在另外一个仓库里:[MyBlog-py3/parse](https://github.com/hackfengJam/MyBlog-py3/tree/master/parse) 63 | 包括问题描述(PS:除了 README 里面的问题描述部分,其他都是自己写的)。 64 | 65 | ##### 4.1.2 结果 66 | 67 | 通过。猎头说推了四个,我一个人过了(我也是奇怪,题目本身貌似没难度;是我文档写的太好了么=。=) 68 | 69 | ##### 4.1.3 接下来流程 70 | 71 | 现场面试:2轮技术面+HR面(2019年5月27日下午兩點开始) 72 | 73 | 74 | #### 4.2 两轮技术面 75 | 76 | ##### 4.2.1 一面 77 | 78 | ###### 4.2.1.1 所写的项目:哪些有对你帮助很多,有什么挑战,如何克服的,学到了什么。 79 | 80 | - 我重点说的 【[ScanEngine](https://github.com/hackfengJam/ScanEngine)】 ,这个从设计到实现基本我一个人搞定的,除了脚本部分编写。 81 | 82 | - 解释一下整个项目,画一下了架构图 83 | - 脚本什么写的(python),扩展性如何,目前(由公司某大佬接盘,600+脚本) 84 | - Crontab 怎么实现的?(后续写文章聊一下(环形队列)) 85 | - 模板模式定义脚本的输入输出,怎么保证脚本执行安全性(内部架构师团队人员review以及,容器部署) 86 | - 脚本异常捕捉、重试机制(聊了一堆) 87 | - 任务生命周期以及所有任务监控情况(聊了一堆,自己实现的简易监控,后续打算优化) 88 | - 其他的我也记不清问了啥了(聊得挺久的) 89 | 90 | - 题外话 91 | 92 | 这个项目是我公司项目,仓库里面放的是终极精简版本(连README都没有,不是我风格呀 :-)),后续有机会完善一下。 93 | 94 | ###### 4.2.1.2 MySQL 了解多少? 95 | 96 | - MyISAM 与 InnoDB 关于锁方面的区别 97 | 98 | - 索引管理 99 | - 索引好处 100 | - B+树、为什么不用B-树 101 | - 锁管理 102 | - 四种隔离机制 103 | - InnoDB 下 RR如何避免幻读(当前读和快照读、next-keys(行锁+gap锁)) 104 | - 其他没印象了 105 | 106 | 题外话: 107 | 108 | - 关于索引管理和锁管理之前博客有谈过链接如下 109 | - [数据库 - 如何设计一个关系型数据库](../../tech/mysql/数据库——1_数据库架构.md) 110 | - [数据库 - 索引管理](../../tech/mysql/数据库——2_索引管理.md) 111 | - [数据库 - 锁管理](../../tech/mysql/数据库——3_锁管理.md) 112 | 113 | ###### 4.2.1.3 设计一个 微博帖子(post)的 点赞系统 114 | 115 | - like count by postIds 116 | - user like staus about post 117 | - like / unlike 118 | - like users list by timeline 119 | 120 | 设计: 121 | 122 | - 数据库,索引如何建立、 123 | - 幂等、缓存 124 | - 描述每个请求流程,最好简单画一下时序图 125 | - count优化(count ++, count表) 126 | - 我:用redis HyperLogLog + 定期数据对齐; 127 | - 面试官:给了一种自愈方案,不需要定期数据对齐(或者说非冷数据基本不会用到);算是学到了(后续待我总结一下,看看网上有没有相关讨论,系统写个笔记) 128 | 129 | ###### 4.2.1.4 一面总结 130 | 131 | - 基本答得可以,就问了三个问题,聊的时间蛮长的。 132 | 133 | - 可能主要是自己项目占用时间比较多,才会让后面直接进入主题的吧。 134 | 135 | - 前两个问题基本是我再说,聊得算是不错;最后一个问题,我给了个思路,然后面试官问一下细节,不是最优方案,但还凑合,大部分设计算是合理。 136 | 137 | - 总体来说,这一面感觉就是,如果能让面试官对你的项目感兴趣,那么你基本这轮面试就成功了,因为大部分都在谈你熟悉的东西,让你很容易发挥。 138 | 139 | 140 | 141 | ##### 4.2.2 二面 142 | 143 | ###### 4.2.2.1 一个数组,长度为 n,有个数出现次数大于(n/2),找出这个数 144 | 145 | - 第一次尝试 146 | 147 | - 思考阶段 148 | - 不可能用 Map 做统计,空间太耗费了 149 | - 咦?三路快排思想好像不错。 150 | 151 | - 交流过程 152 | - 我:三路快排思想,每次看 等于部分的长度是否大于 n/2,如不是则丢弃这部分,并且把两边长度小于 n/2 的部分去掉。 153 | - 面试官:时间复杂度 154 | - 我:n+n/2+...+1 < 2n,所以总体 O(n)。 155 | - 面试官:最坏情况呢? 156 | - 我思考了一下。。。:额。。。终极退化。 157 | 158 | - 第二次尝试 159 | 160 | - 思考阶段 161 | - 括号匹配思想貌似可以 162 | 163 | - 交流过程 164 | - 我:栈为空则入栈,否则对比栈顶元素,如果相等入栈,不相等则出栈,最后栈里剩的是大于 n/2 的元素。(栈是基于原数组基础上加了 index+size 实现的,不需要额外空间,并且出入栈时间O(1)) 165 | - 虽然空间O(1),时间O(n),时间空间复杂度确实是最优了,但是好像并不是很满意 166 | 167 | - 第三次尝试 168 | 169 | - 思考阶段 170 | - 我去,摩尔投票法 171 | 172 | - 没有机会说了 173 | 174 | ###### 4.2.2.2 你网络还不错吧(这部分直接爆炸=。=)?我:嗯(自信满满是最“骚”的。) 175 | 176 | - 了解 Proxy 机制吗?它的包与普通的包有什么区别? 177 | 178 | - 只说了表面的问题,扯了正向代理、反向代理,然后从网络分区相关点去回答,但是他貌似希望让我细聊整个 HTTP 协议细节相关,这个后续需要总结了 179 | 180 | - 简单查了一下:HTTP 1.1 以后相关 181 | 182 | - HTTP 与 HTTPS 的 区别? 183 | - HTTPS 如何做到保密的? 184 | - 整个流程说一下? 185 | - 如何信任 CA 什么的等等 186 | 187 | 确实 HTTPS 问的非常细节。我只说了大致流程,细节部分基本答得不好(有点胡说的意味),并且被发现明显是来面试前随便看了一下,没仔细钻研的(挂的导火索=。=) 188 | 189 | ###### 4.2.2.3 二面总结 190 | 191 | - 二面总的来说,答得不满意。 192 | 193 | - 一个简单的算法问题,也答得不好;而后面几个问题问的 HTTP/HTTPS 相关的知识(然而我确实只是来前随便看了两眼),之前没有琢磨。 194 | 195 | - 老实说:下层协议个人真心挺自信的(来自看完 《TCP/IP 详解 卷一》的自信),基本很多都 真的动手操作过(之前在学校网络安全玩的)。 196 | 197 | - 不多说了,下一步直接把 RFC文档 翻出来,常用协议全部再看一遍,再用一下许久不用的 wireshark。 198 | 199 | ### 5. 结果 200 | 201 | __挂了__ 202 | 203 | ### 6. 总结 204 | 205 | 两点面到四点半,还是有所收获的。 206 | 207 | - 总的来说,问的东西并不深奥,基本都是需要掌握的。 208 | 209 | - 几乎没有问任何语言相关基础;本次是毕业后的第一次面试,体验还算行,这种面试节奏是我喜欢的,这次准备不够充分,以后继续努力。 210 | 211 | 本次关键: 212 | 213 | - 心里因素,多少有一些,以后多面试,继续调整就好了。 214 | 215 | - 二面面试官,连续三个问题答的都有瑕疵。最后问题更是直接暴露,对问题本身回答的不上心,没自己动手过的,然后用看到的表面理论乱说。(本人自己都看不下去) 216 | 217 | - 不会直接过就好了,记住似懂非懂等于不懂(当然可能面试官有可能就是想考察这个点,直接过也有可能存在挂的风险,看情况吧)。 218 | 219 | - 自己太菜呀,继续加油:-) 220 | 221 | #### 感谢 222 | 223 | - 感谢两个面试官,也感谢猎头大哥给的帮助。 -------------------------------------------------------------------------------- /reflection_and_summary/interview/某不知名小厂面经_2.md: -------------------------------------------------------------------------------- 1 | ## 某不知名小厂面经 - 第二家 2 | 3 | #### 2019年07月11日 4 | 5 | ### 前言 6 | 7 | 有很多基本和上次([某不知名小厂面经 - 第一家](https://github.com/hackfengJam/blog/blob/master/reflection_and_summary/interview/某不知名小厂面经.md)) 8 | 描述的一致,比如[本人大致情况](#2-本人大致情况)可以直接跳过。 9 | 10 | ### 目录 11 | 12 | - [1. 先看一下 jd](#1-先看一下-jd) 13 | - [2. 本人大致情况](#2-本人大致情况) 14 | - [3. 公司大致情况](#3-公司大致情况) 15 | - [4. 此次流程](4-此次流程) 16 | - [4.1 面试题](#41-面试题) 17 | - [4.2 两轮技术面 + HR 面](#42-两轮技术面--hr-面) 18 | - [4.2.1 一面](#421-一面) 19 | - [4.2.1.1 介绍自己写的项目](#4211-介绍自己写的项目) 20 | - [4.2.1.2 MySQL](#4212-mysql) 21 | - [4.2.1.3 Redis](#4213-redis) 22 | - [4.2.1.4 Golang](#4214-golang) 23 | - [4.2.1.5 杂项](#4215-杂项) 24 | - [4.2.1.6 一面总结](#4216-一面总结) 25 | - [4.2.2 二面](#422-二面) 26 | - [4.2.2.1 Golang](#4221-golang) 27 | - [4.2.2.2 杂项](#4222-杂项) 28 | - [4.2.2.3 二面总结](#4223-二面总结) 29 | - [4.2.3 HR 面](#423-hr-面) 30 | - [4.2.3.1 薪资](#4231-薪资) 31 | - [4.2.3.2 问答阶段](#4232-问答阶段) 32 | - [4.2.3.3 HR面 总结](#4233-hr-面总结) 33 | - [5. 结果](#5-结果) 34 | 35 | - [6. 总结](#6-总结) 36 | 37 | 38 | ### 1. 先看一下 jd 39 | 40 | ![Alt Text](./images/liao_jd.png) 41 | 42 | ### 2. 本人大致情况 43 | 44 | - 18年毕业,17年11月份出去实习+转正至今(马马虎虎算一年经验了吧=。=)。 45 | 46 | - 某C轮小厂,做 Python开发工程师。(工作制:965,算时薪比的话还是相当可观的,手动滑稽: )) 47 | 48 | - 目前薪资:正常价格,你懂得! 49 | 50 | 51 | ### 3. 公司大致情况 52 | 53 | BOSS 上介绍的比较简单:一家做 IM 的公司,A轮,20-99 人,没啥说了。 54 | 55 | ### 4. 此次流程 56 | 57 | #### 4.1 面试题 58 | 59 | __现场给了一道题:__ 60 | 61 | 全英文 两页,大致是给了一个协议(可能是他们公司自己定的吧或者是 IM 相关的协议); 62 | 给了一些包结构,介绍了一堆,给了消息体 encode 和 decode 算法介绍,用自己常用语言实现 decode 方法。 63 | 64 | #### 4.2 两轮技术面 + HR 面 65 | 66 | ##### 4.2.1 一面 67 | 68 | ###### 4.2.1.1 介绍自己写的项目 69 | 70 | 介绍ScanEngine 和上次差不多([某不知名小厂面经系列 - 1](https://github.com/hackfengJam/blog/blob/master/reflection_and_summary/interview/%E6%9F%90%E4%B8%8D%E7%9F%A5%E5%90%8D%E5%B0%8F%E5%8E%82%E9%9D%A2%E7%BB%8F.md#4211-%E6%89%80%E5%86%99%E7%9A%84%E9%A1%B9%E7%9B%AE%E5%93%AA%E4%BA%9B%E6%9C%89%E5%AF%B9%E4%BD%A0%E5%B8%AE%E5%8A%A9%E5%BE%88%E5%A4%9A%E6%9C%89%E4%BB%80%E4%B9%88%E6%8C%91%E6%88%98%E5%A6%82%E4%BD%95%E5%85%8B%E6%9C%8D%E7%9A%84%E5%AD%A6%E5%88%B0%E4%BA%86%E4%BB%80%E4%B9%88)) 71 | 72 | ###### 4.2.1.2 MySQL 73 | 74 | - 建索引有什么要注意的? 75 | 76 | - 实际工作中,怎么排查 sql 相关问题 77 | 78 | - 写了几个 sql,怎么建索引、sql是否有问题如何修改 79 | 80 | 题外话: 81 | 82 | - 关于索引管理和锁管理之前博客有谈过链接如下 83 | - [数据库 - 如何设计一个关系型数据库](../../tech/mysql/数据库——1_数据库架构.md) 84 | - [数据库 - 索引管理](../../tech/mysql/数据库——2_索引管理.md) 85 | - [数据库 - 锁管理](../../tech/mysql/数据库——3_锁管理.md) 86 | 87 | ###### 4.2.1.3 Redis 88 | 89 | - 用 redis 做过什么 90 | - 最近用了 zset 做延时队列说了一下,以及用延时 buffer 做 merge 91 | 92 | - 你用 redis 消息队列怎么做到可靠消费? 面试官又提了一嘴:Kafka 这方面怎么做的? 93 | 94 | ###### 4.2.1.4 Golang 95 | 96 | - 自己工作一直用 python 为什么学 golang 97 | 98 | - golang 和 python 你的视角对比一下他们 99 | 100 | ###### 4.2.1.5 杂项 101 | 102 | - 有没有遇到什么并发问题?描述了一个最近遇到的问题(后续有空写blog,感觉 TODO list 已经排满了:-)。。) 103 | 104 | - 一个人有 100 积分,买一个 100 积分的商品,同时发三个请求,做到返回一个成功,两个失败。 105 | 106 | - 一个商品,库存 100,整点秒杀,如何设计 107 | 108 | ###### 4.2.1.6 一面总结 109 | 110 | - 一面花了大约接近两个小时,一个小时四五十分钟吧,从面试官反应来说,基本算答得可以。 111 | 112 | - 问题看上去比较少,实际基于问题交流以及细节沟通都花费了一些时间。 113 | 114 | - 能让面试官对你的项目感兴趣还是比较重要的,自己项目说了很久,参考上次[一面总结](https://github.com/hackfengJam/blog/blob/master/reflection_and_summary/interview/%E6%9F%90%E4%B8%8D%E7%9F%A5%E5%90%8D%E5%B0%8F%E5%8E%82%E9%9D%A2%E7%BB%8F.md#4214-%E4%B8%80%E9%9D%A2%E6%80%BB%E7%BB%93) 115 | 116 | ##### 4.2.2 二面 117 | 118 | ###### 4.2.2.1 Golang 119 | 120 | - 问了我为什么用 golang,用下来感觉如何? 121 | 122 | ###### 4.2.2.2 杂项 123 | 124 | - HTTP 协议了解多少? 125 | 126 | - 觉得这个算法(面试题中的 decode)有什么优缺点? 127 | 128 | - 为什么一个月才能到岗 129 | 130 | 131 | ###### 4.2.2.3 二面总结 132 | 133 | - 感觉 CTO来就过了个场,随便聊几句,好像还挺满意的 134 | 135 | ##### 4.2.3 HR 面 136 | 137 | ###### 4.2.3.1 薪资 138 | 139 | - 你期望薪资上面填写的是 16-20k(期望薪资填写心路历程:上次不是猎头给找的 20k 岗位凉了嘛;这回考虑薪资先猥琐点填) 140 | 141 | - 我们这边如果给到 17-18k 的 offer,你觉得可以吗?(本人内心独白,大概率是不会来,也就不太想去争取了吧) 142 | 143 | ###### 4.2.3.2 问答阶段 144 | 145 | - 我 146 | - Q:什么工作制,是否有年终? 147 | - A:965,13薪 148 | - Q:那加班怎么算 149 | - A:平时弹性工作,周末我们目前没加过班,如果要加的话给调休 150 | - Q:咱 CEO 经常在公司么 151 | - A:(朝外面指了一下,CEO刚好路过)这个就是 152 | - D:我这边,没问题了 153 | - 她 154 | - Q:你这边写的一个月到岗,为什么? 155 | - A:不是裸辞,过来人都告诉我不要裸辞,我觉得非常有道理,所以你懂的 156 | - Q:是否可以给个最快时间 157 | - A:我现在提离职最快也要一个月,顶多到时候提前一周休年假过来,然后到时间去办离职手续 158 | - Q:你为什么现在想要换工作 159 | - A:想看看有没有新的锻炼机会 160 | 161 | ... 162 | 163 | __她:那最近会给你发 offer,也希望你能加入我们团队。那么,今天就到这里。(然后送我出门)__ 164 | 165 | ###### 4.2.3.3 HR 面总结 166 | 167 | - 随便扯点,没啥好总结的 168 | 169 | ### 5. 结果 170 | 171 | __暂时口头 offer(文章发布当天的面试),算是过了吧__ 172 | 173 | ### 6. 总结 174 | 175 | - 下午两点开始面试,总共花了不到两个半小时。 176 | 177 | - 没怎么问语言基础,没问数据结构与算法,直接问项目,然后聊实际工作问题和解决思路。 178 | 179 | - 这次感觉不像之前那次(见:[某不知名小厂面经 - 第一家](https://github.com/hackfengJam/blog/blob/master/reflection_and_summary/interview/某不知名小厂面经.md)), 180 | 感觉没学到啥东西,不过总的来说还是可以的,起码还是给过了 :)。 181 | 182 | - 目前能想起来的就这些,那些问题都是临场随意发挥的,现在想有点费神,明天还有两家面试,等后续一并总结一下自己的回答吧,休息了: )。 183 | 184 | - 继续加油:-) 185 | 186 | - 感谢该公司给予宝贵的面试机会 187 | 188 | 189 | #### 感谢 190 | 191 | - 感谢三个技术面试官 192 | -------------------------------------------------------------------------------- /reflection_and_summary/interview/面试-复习.md: -------------------------------------------------------------------------------- 1 | ## 复习-知识点总结 2 | *2019.02.17* 3 | 4 | ### 数据库 5 | - 数据库-索引优化 6 | 7 | - MySQL视图优缺点 8 | 优点: 9 | 10 | 1,数据库视图允许简化复杂查询:数据库视图由与许多基础表相关联的SQL语句定义。 您可以使用数据库视图来隐藏最终用户和外部应用程序的基础表的复杂性。 通过数据库视图,您只需使用简单的SQL语句,而不是使用具有多个连接的复杂的SQL语句。 11 | 2,数据库视图有助于限制对特定用户的数据访问。 您可能不希望所有用户都可以查询敏感数据的子集。可以使用数据库视图将非敏感数据仅显示给特定用户组。 12 | 数据库视图提供额外的安全层。 安全是任何关系数据库管理系统的重要组成部分。 数据库视图为数据库管理系统提供了额外的安全性。 数据库视图允许您创建只读视图,以将只读数据公开给特定用户。 用户只能以只读视图检索数据,但无法更新。 13 | 3,数据库视图启用计算列。 数据库表不应该具有计算列,但数据库视图可以这样。 假设在orderDetails表中有quantityOrder(产品的数量)和priceEach(产品的价格)列。 但是,orderDetails表没有一个列用来存储订单的每个订单项的总销售额。如果有,数据库模式不是一个好的设计。 在这种情况下,您可以创建一个名为total的计算列,该列是quantityOrder和priceEach的乘积,以表示计算结果。当您从数据库视图中查询数据时,计算列的数据将随机计算产生。 14 | 4,数据库视图实现向后兼容。 假设你有一个中央数据库,许多应用程序正在使用它。 有一天,您决定重新设计数据库以适应新的业务需求。删除一些表并创建新的表,并且不希望更改影响其他应用程序。在这种情况下,可以创建与将要删除的旧表相同的模式的数据库视图。 15 | 缺点: 16 | 17 | 1,性能:从数据库视图查询数据可能会很慢,特别是如果视图是基于其他视图创建的。 18 | 2,表依赖关系:将根据数据库的基础表创建一个视图。每当更改与其相关联的表的结构时,都必须更改视图。 19 | 20 | - MySQL删除大批量数据 21 | - MySQL修改大表 22 | 23 | ### 操作系统 24 | 25 | 进程是系统分配资源的基本单位,线程是CPU调度的基本单位。 26 | 27 | select、poll、epoll 28 | 29 | 分布式:二阶段提交;分布式锁;etcd/zk、raft;领域驱动;github; 30 | TCP/IP、HTTP 协议; 31 | 操作系统:进程与线程; 32 | 数据库:索引优化; 33 | 维护:routeloaderpy 34 | 设计模式 35 | 数据结构与算法 36 | 37 | linux 命令 38 | 并发安全 39 | 40 | 系统消息设计与实现 41 | 42 | 有空看一下 Kafka等消息中间件 43 | 简历:填充分布式相关 44 | -------------------------------------------------------------------------------- /reflection_and_summary/misc/给学弟学妹们总的方向及建议.md: -------------------------------------------------------------------------------- 1 | # 给大一学弟学妹们总的方向和建议 2 | 3 | ## 1.跟你们聊一下方向 4 | 前端开发: HTML5,CSS,javascript,后台也要会,因为你要调试,交互(PHP,java等) 5 | 6 | 后端开发: Java后台开发,PHP后台开发,Python后台开发,C,C#(.net),Ruby等等(各是一个方向,学好其中一门就很棒了,建议学考前的语言) 7 | 8 | 移动开发: 安卓开发(学java),IOS开发(Object-C,swiftt等) 9 | 10 | 大数据&云计算: 要学python,hadoop(java的框架)等等 11 | 12 | 运维: Linux必学 13 | 14 | UI设计: 跟我们几乎关系很小,除非你美工不错,又想跟IT挂钩 15 | 16 | ## 2.咱们学校开的课:Java(几乎任何框架都不学) 17 | 18 | 19 | 20 | 21 | 1. JavaWeb,C#,ASP/ASPX(.NET) 22 | 23 | 2. 要想拿来找工作,吃饭。学任何语言都不简单。 24 | 25 | 3. 以上的方向所需要学的,是必须要学的,也就是至少要学的东西。就是你学前端开发,你肯定也要会后台,你学后台,前端也得知道。 26 | 27 | 4. 以上方向只是我了解的。还有对方向有不懂的,可以私聊我。 28 | 29 | 30 | 31 | 32 | 补充,还有安全这个方向:我现在学的,感觉很棒!但是自学能力,实践能力真的要强! 33 | 34 | 35 | 咱们这个专业要学好,必须得自学;是必须,必须,须。 36 | 37 | 重要的是坚持不懈,毅力,耐心。 38 | 39 | 祝你们能选个合适自己的方向! 40 | 41 | 42 | ## 3.不是老师能力不够,而是照顾大众,所以得多问 43 | 既然上了大学里了,没人跟你后面催着你学,所以,一切学习都得靠自己。 44 | 45 | -------------------------------------------------------------------------------- /reflection_and_summary/tech/cpu.md: -------------------------------------------------------------------------------- 1 | ### CPU飙升 可能情况 2 | 1. 高并发 3 | 2. 定时任务跑批 4 | 3. 分布式锁(重试机制) 5 | - CAS 机制 6 | 4. 端口暴露(被注入异常程序,当肉机) 7 | 8 | ### 避免 上述情况 9 | 1. 对接口实现限流、熔断、降级 10 | 2. 接口比较耗时的代码不要写成同步,改成 MQ 11 | 3. 定时任务与业务分开部署 12 | 1. 降低业务逻辑项目 CPU 消耗资源 13 | 2. 更好实现定时分片执行 14 | 4. 自旋锁重试次数控制 15 | 5. 避免端口暴露 16 | 17 | -------------------------------------------------------------------------------- /tech/architecture/fanout_and_fanin.md: -------------------------------------------------------------------------------- 1 | ## 什么是扇入和扇出? 2 | 3 | ### 前言 4 | 5 | 转载自 [什么是扇入和扇出?](https://blog.csdn.net/cuixinminsuijie/article/details/3497442) 6 | 7 | ### 目录 8 | 9 | [1. 在软件设计中定义](#1-在软件设计中定义) 10 | 11 | [2. 其他回答](#2-其他回答) 12 | 13 | 14 | ### 1. 在软件设计中定义 15 | 16 | 在软件设计中,扇入和扇出的概念是指应用程序模块之间的层次调用情况。按照结构化设计方法,一个应用程序是由多个功能相对独立的模块所组成。 17 | 18 | 扇入:是指直接调用该模块的上级模块的个数。扇入大表示模块的复用程序高。 19 | 20 | 扇出:是指该模块直接调用的下级模块的个数。扇出大表示模块的复杂度高,需要控制和协调过多的下级模块;但扇出过小(例如总是1)也不好。扇出过 大一般是因为缺乏中间层次,应该适当增加中间层次的模块。扇出太小时可以把下级模块进一步分解成若干个子功能模块,或者合并到它的上级模块中去。 21 | 22 | 设计良好的软件结构,通常顶层扇出比较大,中间扇出小,底层模块则有大扇入。 23 | 24 | ### 2. 其他回答 25 | 26 | 扇入:一个门的输入定义为门的输入的数目。 27 | 扇出:用于描述驱动能力的一个词 28 | 更加恰当的说法是:描述负载状况的一种描述方式 29 | 30 | ### 感谢 31 | 32 | - [什么是扇入和扇出?](https://blog.csdn.net/cuixinminsuijie/article/details/3497442) -------------------------------------------------------------------------------- /tech/architecture/how_should_your_project_be_stratified.md: -------------------------------------------------------------------------------- 1 | ## 你的项目应该如何分层? 2 | 3 | ### 前言 4 | 5 | 大半年前在某脉上看到 一个蚂蚁金服大佬 发的这篇文章,前两天突然回想到,特此记录一下。 6 | 7 | 本文可以说是一篇转载文章(图是本人自己画的)。 8 | 9 | ### 目录 10 | 11 | [1. 背景](#1-背景) 12 | 13 | [2. 如何进行分层](#2-如何进行分层) 14 | 15 | [3. 分层领域模型的转换](#3-分层领域模型的转换) 16 | 17 | [4. 总结](#4-总结) 18 | 19 | ### 1. 背景 20 | 21 | 说起应用分层,大部分人都会认为这个不是很简单嘛 就 controller,service,mapper 三层。 22 | 看起来简单,很多人其实并没有把他们职责划分开,在很多代码中,controller 做的逻辑比 service 还多,service 往往当成透传了, 23 | 这其实是很多人开发代码都没有注意到的地方,反正功能也能用,至于放哪无所谓呗。 24 | 这样往往造成后面代码无法复用,层级关系混乱,对后续代码的维护非常麻烦。 25 | 26 | 的确在这些人眼中分层只是一个形式,前辈们的代码这么写的,其他项目代码这么写的,那么我也这么跟着写。 27 | 但是在真正的团队开发中每个人的习惯都不同,写出来的代码必然带着自己的标签,有的人习惯 controller 写大量的业务逻辑, 28 | 有的人习惯在service中之间调用远程服务,这样就导致了每个人的开发代码风格完全不同,后续其他人修改的时候, 29 | 一看,我靠这个人写的代码和我平常的习惯完全不同,修改的时候到底是按着自己以前的习惯改,还是跟着前辈们走, 30 | 这又是个艰难的选择,选择一旦有偏差,你的后辈又维护你的代码的时候,恐怕就要骂人了。 31 | 32 | 所以一个好的应用分层需要具备以下几点: 33 | 34 | - 方便后续代码进行维护扩展 35 | 36 | - 分层的效果需要让整个团队都接受 37 | 38 | - 各个层职责边界清晰 39 | 40 | ### 2. 如何进行分层 41 | 42 | #### 2.1 阿里规范 43 | 44 | 在阿里的编码规范中约束的分层如下: 45 | 46 | ![Alt Text](./images/how_should_your_project_be_stratified_1.png) 47 | 48 | - 开放接口层:可直接封装 Service 方法包括成 RPC 接口;通过 Web 封装成 HTTP 接口;进行 网关安全控制、流量控制等。 49 | 50 | - 终端显示层:各个端的模板渲染并执行显示的层。当前主要是 velocity 渲染,JS 渲染,JSP 渲染,移动端展示等。 51 | 52 | - Web 层:主要是对访问控制进行转发,各类基本参数校验,或者不复用的业务简单处理等。 53 | 54 | - Service 层:相对具体的业务逻辑服务层。 55 | 56 | - Manager 层:通用业务处理层,它有如下特征: 57 | 1. 对第三方平台封装的层,预处理返回结果及转化异常信息; 58 | 2. 对 Service 层 通用能力的下沉,如缓存方案、中间件通用处理; 59 | 3. 与 DAO 层 交互,对多个 DAO 的组合复用。 60 | 61 | - DAO 层:数据访问层,与底层 MySQL、Oracle、HBase 进行数据交互。 62 | 63 | - 外部接口或第三方平台:包括其它部门 RPC 开放接口,基础平台,其它公司的 HTTP 接口。 64 | 65 | - 阿里巴巴规约中的分层比较清晰简单明了,但是描述得还是过于简单了, 66 | 以及 Service 层 和 Manager 层 有很多同学还是有点分不清楚之间的关系, 67 | 就导致了很多项目中根本没有 Manager 层 的存在。下面介绍一下具体业务中应该如何实现分层 68 | 69 | 70 | #### 2.2 优化分层 71 | 72 | 从我们的业务开发中总结了一个较为的理想模型, 73 | 这里要先说明一下由于我们的 rpc框架 选用的是 thrift 可能会比其他的一些 Rpc框架 例如 Dubbo 会多出一层, 74 | 作用和 controller 层 类似 75 | 76 | ![Alt Text](./images/how_should_your_project_be_stratified_2.png) 77 | 78 | 1. 最上层 Controller 和 TService 是阿里分层规范里面的第一层:轻业务逻辑,参数校验,异常兜底。 79 | 通常这种接口可以轻易更换接口类型,所以业务逻辑必须要轻,甚至不做具体逻辑。 80 | 81 | 2. Service: 82 | 业务层,复用性较低,这里推荐每一个 Controller 方法都得对应一个 Service, 83 | 不要把业务编排放在 Controller 中去做,为什么呢? 84 | 如果我们把业务编排放在 Controller 层 去做的话, 85 | 如果以后我们要接入 thrift,我们这里又需要把业务编排在做一次, 86 | 这样会导致我们每接入一个入口层这个代码都得重新复制一份如下图所示: 87 | 88 | ![Alt Text](images/how_should_your_project_be_stratified_3.png) 89 | 90 | 这样大量的重复工作必定会导致我们开发效率下降,所以我们需要把业务编排逻辑都得放进 Service 中去做: 91 | 92 | ![Alt Text](images/how_should_your_project_be_stratified_4.png) 93 | 94 | 3.Manager:可复用逻辑层。这里的 Manager 可以是单个服务的,比如我们的 Cache,MQ 等等, 95 | 当然也可以是复合的,当你需要调用多个 Manager 的时候,这个可以合为一个 Manager, 96 | 比如逻辑上的连表查询等。如果是 httpManager 或 rpcManager 需要在这一层做一些数据转换 97 | 98 | 4.DAO:数据库访问层。主要负责“操作数据库的某张表,映射到某个 java对象”, 99 | Dao 应该只允许自己的 Service 访问,其他 Service 要访问我的数据必须通过对应的 Service。 100 | 101 | ### 3. 分层领域模型的转换 102 | 103 | 在阿里巴巴编码规约中列举了下面几个领域模型规约: 104 | 105 | - DO(Data Object):此对象与数据库表结构一一对应,通过 DAO 层向上传输数据源对象。 106 | - DTO(Data Transfer Object):数据传输对象, Service 或 Manager 向外传输的对象。 107 | - BO(Business Object):业务对象,由 Service 层输出的封装业务逻辑的对象。 108 | - AO(Application Object):应用对象,在 Web 层 与 Service 层 之间抽象的复用对象模型,极为贴近展示层,复用度不高。 109 | - VO(View Object) :显示层对象,通常是 Web 向模板渲染引擎层传输的对象。 110 | - Query :数据查询对象,各层接收上层的查询请求。注意超过 2 个参数的查询封装,禁止使用 Map 类来传输。 111 | 112 | | 层次 | 领域模型 | 113 | |------------|-------------| 114 | | Controller/TService | VO/DTO | 115 | | Service/Manager | AO/BO | 116 | 117 | 每一个层基本都自己对应的领域模型,这样就导致了有些人过于追求每一层都是用自己的领域模型, 118 | 这样就导致了一个对象可能会出现 3次 甚至 4次 转换在一次请求中,当返回的时候同样也会出现 3-4次 转换, 119 | 这样有可能一次完整的请求-返回会出现很多次对象转换。如果在开发中真的按照这么来,恐怕就别写其他的了, 120 | 一天就光写这个重复无用的逻辑算了吧。 121 | 所以我们得采取一个折中的方案: 122 | 123 | 1. 允许 Service/Manager 可以操作数据领域模型,对于这个层级来说,本来自己做的工作也是做的是业务逻辑处理和数据组装。 124 | 125 | 2. Controller/TService 层 的领域模型不允许传入 DAO 层,这样就不符合职责划分了。 126 | 127 | 3. 同理,不允许DAO层的数据传入到 Controller/TService. 128 | 129 | ### 4. 总结 130 | 131 | 总的来说业务分层对于代码规范是比较重要,决定着以后的代码是否可复用, 132 | 是否职责清晰,边界清晰,所以搞清楚这一块也比较重要。 133 | 当然这种分层其实见仁见智,团队中的所有人的分层习惯也不同,所以很难权衡出一个标准的准则, 134 | 总的来说只要满足职责逻辑清晰,后续维护容易,就是好的分层。 135 | 136 | ### 感谢 137 | 138 | [多研究些架构,少谈些框架(4)-- 架构师是技术的使用者而不是信徒](https://github.com/JoeCao/JoeCao.github.io/issues/6) 139 | 140 | [你的项目应该如何分层?](https://maimai.cn/article/detail?fid=1163981324&efid=pKbwc4vk_CiJIy0sRr1UBQ) 141 | -------------------------------------------------------------------------------- /tech/architecture/images/git_workflow_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/tech/architecture/images/git_workflow_1.png -------------------------------------------------------------------------------- /tech/architecture/images/how_should_your_project_be_stratified_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/tech/architecture/images/how_should_your_project_be_stratified_1.png -------------------------------------------------------------------------------- /tech/architecture/images/how_should_your_project_be_stratified_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/tech/architecture/images/how_should_your_project_be_stratified_2.png -------------------------------------------------------------------------------- /tech/architecture/images/how_should_your_project_be_stratified_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/tech/architecture/images/how_should_your_project_be_stratified_3.png -------------------------------------------------------------------------------- /tech/architecture/images/how_should_your_project_be_stratified_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/tech/architecture/images/how_should_your_project_be_stratified_4.png -------------------------------------------------------------------------------- /tech/architecture/style/code_13.md: -------------------------------------------------------------------------------- 1 | ## 13 Code Review Standards Inspired by Google 2 | 3 | > 作者 | Rafiullah Hamedy 4 | 来源 | https://medium.com/better-programming/13-code-review-standards-inspired-by-google-6b8f99f7fd67 5 | 6 | ## 以下为译文: 7 | 8 | 在本文中,我们将简要介绍13条代码审查标准,希望能够通过这些标准极大地帮助改善软件的质量,同时让开发人员保持心情愉悦。 9 | 10 | 代码审查是开发过程中的一个环节,顾名思义,代码审查需要一位或多位开发人员审查另一位开发人员(即代码的作者)编写的代码,以确保: 11 | 12 | * 代码没有任何错误,没有bug,也没有问题; 13 | * 代码符合质量与样式指南的要求和标准; 14 | * 代码完成了所有预期功能; 15 | * 合并代码后,代码库仍然能够正常运行,且达到更好的状态。 16 | 17 | 这就是为什么代码审查是软件开发的重要环节的原因。代码审查者担当着把关者的职责,负责决定这些代码是否能够成为代码库的一部分并进入生产环境。 18 | 19 | Google以其卓越的技术而闻名世界,他们拥有高效的代码审查标准,这些标准突出了审查代码时需要牢记的一些重点。关注公众号Java技术栈回复:GG规范,还能获取一份完整的 Google 开发规范。 20 | 在Google, 21 | 22 | >“代码审查的主要目的是确保Google代码库内整体的代码运行状况能够不断提升。” —— [Google工程实践文档](https://google.github.io/eng-practices/review/reviewer/standard.html#:~:text=The%20primary%20purpose%20of%20code,base%20is%20improving%20over%20time.&text=They%20want%20to%20ensure%20that,for%20in%20a%20code%20review.%E2%80%9D) 23 | 24 | 以下是审查代码时你需要牢记的一些重点。 25 | 26 | 27 | ### 代码审查标准: 28 | 29 | #### 1. 这些代码能够提升系统整体的运行状况 30 | 31 | 每次代码变更(拉取请求)都能够提升系统整体的运行状况。重点在于,即便是很小的改进,合并代码后都会提升软件或代码库的运行状况。 32 | 33 | #### 2. 快速审查代码,并给出积极地响应和反馈 34 | 35 | 首先也是最重要的一点,不可延误代码的合并。世上没有完美的代码。如果代码可以提升系统的整体运行状况,则应该立即交付这些代码。 36 | “关键在于,世上没有完美的代码,只有更好的代码。” —— Google工程实践文档 37 | 如果手头没有紧急任务,那么请在代码提交上来后立即进行审查。响应拉取请求的时间最长不得超过一个工作日。一天之内,应针对一次拉取请求完成多轮的部分或完整的代码审查。 38 | 39 | #### 3. 在代码审查的过程中开展教育和启发 40 | 41 | 在代码审查的过程中,应尽可能通过共享知识和经验提供指导。 42 | 43 | #### 4. 审查代码应遵循标准 44 | 45 | 请始终牢记,样式指南、编程标准以及相关的文档应该作为代码审查的绝对权威。例如,制表符与空格的使用应保持一致,此时你可以引用编程约定。 46 | 如果你选用的是Java,那么以下文章可能会有所帮助,文中总结了大型科技公司Java编程的最佳实践:[《Java编程最佳实践摘要》](https://rhamedy.medium.com/a-short-summary-of-java-coding-best-practices-31283d0167d3) 47 | 48 | #### 5. 解决代码审查冲突 49 | 50 | 解决代码审查冲突时,应遵循样式指南以及编程标准中商定的最佳实践,并征求其他拥有更多产品领域知识和经验的人的建议。 51 | 52 | ![Alt text](images/code_13_1.jpeg) 53 | 54 | 如果你的意见是可选或不怎么重要的,请在注释中说明,然后由作者来决定是解决还是略过。 55 | 作为代码审查者,在没有样式指南或编程标准的情况下,你至少可以建议此次代码变更与其余代码库保持一致。 56 | 57 | #### 6. 演示UI变更是代码审查的一部分 58 | 59 | 如果代码变更涉及用户界面变化,则除了代码审查外,还需要提供演示,确保界面符合预期且与界面设计一致。 60 | 对于前端代码变更,你需要进行演示,或确保代码变更包括必要的UI自动化测试,以验证添加或更新的功能。 61 | 62 | #### 7. 确保代码审查中包含了所有测试 63 | 64 | 除非遇到紧急情况,否则拉取请求应包含所有必要的测试,例如单元测试、集成测试以及端到端测试等。 65 | 这里所说的紧急情况指的是,某个需要尽快修复的bug或安全漏洞,而测试可以等到以后再添加。在这种情况下,请确保创建了适当的票证/问题,并确保有人负责在完成热修复或部署后立即完成测试。 66 | 67 | 我们绝对不可以跳过测试。如果时间有限,某些目标有无法实现的风险,那么解决方案不是跳过测试,而是限定可交付成果的范围。 68 | 69 | #### 8. 不要为了代码审查打断手头的工作 70 | 71 | 如果你正在专心致志地工作,那么请不要打断自己,因为你需要花费很长时间才能重新投入工作。换句话说,打断专心工作的开发人员所付出的代价远远超过了让开发人员等待代码审查。你可以在休息(午餐或咖啡等)过后,进行代码审查。 72 | 73 | 大多数时候,整个代码审查以及代码的合并无法在一天内完成。重要的是迅速给作者一些反馈。例如,虽然可能无法完成完整的审查,但你可以快速指出一些有待探讨的地方。这可以极大地降低代码审查期间的挫败感。 74 | 75 | #### 9. 审查所有代码,不要做任何假设 76 | 77 | 你需要审查提交上来的每一行代码。不要对人工编写的类和方法做任何假设,而且应该确保你理解代码在做什么。 78 | 79 | 确保你理解正在审核的代码。如果不理解,则请作者澄清或提供代码演示和解释。如果你不具备审核部分代码的资格,则请其他有资格的开发人员代为审查。关注公众号Java技术栈回复:GG规范,还能获取一份完整的 Google 开发规范。 80 | 81 | #### 10. 审查代码时需要保持大局观 82 | 83 | 从更广阔的视野来看待代码变更会更有帮助。例如,某个文件被修改,并添加了4行新代码。请不要只看这4行代码,你应该考虑审查整个文件,并检查新添加的内容。它们是否会降低现有代码的质量?它们是否会导致现有功能成为重构的候选对象? 84 | 如果不在函数/方法或类的背景下审查添加的代码,则随着时间的流逝,你将会得到一个面临无法维护、纠缠不清、不易于测试等问题的类,而且这个类很难扩展或重构。 85 | 请记住,即便是微不足道的改进,随着时间的推移,也可能导致产品出现缺陷,同样,即便是轻微的代码降级或技术负债也可能在日积月累下导致产品难以维护和扩展。 86 | 87 | #### 11. 在代码审查期间认同和鼓励出色的工作 88 | 89 | 如果看到出色的代码变更,请别忘了大力表扬和鼓励作者。代码审查的目的不仅仅是发现错误,而且还应该鼓励和指导开发人员出色的工作。 90 | 91 | #### 12. 在代码审查期间应保持谨慎、尊重、友善和思路清晰 92 | 93 | 在代码审查期间,你应该保持友善、思路清晰、有礼貌和尊重别人,这一点至关重要,同时也要给予作者清晰的反馈和积极的帮助。在审查代码时,你需要做到对事不对人,即对代码做出评论,而非开发人员。 94 | 95 | #### 13. 详细解释代码审查的意见,并注意尺度 96 | 97 | 每当代码审查意见提出替代方案或指出某些问题时,重要的是你需要解释其中的原因,并根据个人的知识和经验提供示例,以帮助开发人员理解为何你的建议能够提升代码质量。在建议修改或变更代码时,你需要在如何指导作者修改代码方面找到适当的平衡。例如,我更喜欢指导、解释、提示或建议,而不是整个解决方案。 98 | -------------------------------------------------------------------------------- /tech/architecture/style/images/code_13_1.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/tech/architecture/style/images/code_13_1.jpeg -------------------------------------------------------------------------------- /tech/distributed/algo/images/snowflake-64bit.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/tech/distributed/algo/images/snowflake-64bit.jpg -------------------------------------------------------------------------------- /tech/distributed/algo/分布式id生成算法SnowFlake.md: -------------------------------------------------------------------------------- 1 | # 分布式id生成算法 - SnowFlake 2 | 3 | 4 | #### 概述 5 | 6 | 分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的, 7 | 由于采用的是无意义的字符串,推测会在数据量增大时造成访问过慢,在基础互联网的系统设计中都不推荐采用。 8 | 有些时候我们希望能使用一种简单一些的ID,并且希望ID能够按照时间有序生成。 9 | 10 | 而twitter的snowflake解决了这种需求,最初Twitter把存储系统从MySQL迁移到Cassandra,因为Cassandra没有顺序ID生成机制,所以开发了这样一套全局唯一ID生成服务。 11 | 12 | 自增ID的方法虽然比较适合大数据量的场景,当时由于自增ID是按照顺序增加的,数据记录都是可以根据ID号进行推测出来,对于一些数据敏感的场景,不建议采用。 13 | 14 | 15 | #### Snowflake 算法核心 16 | 把 **时间戳** ,**工作机器id** ,**序列号** 组合在一起。 17 | 18 | snowflake的结构如下(每部分用-分开): 19 | 20 | ![Alt text](images/snowflake-64bit.jpg) 21 | 22 | 23 | - `1位`,不用。二进制中最高位为1的都是负数,但是我们生成的id一般都使用整数,所以这个最高位固定是0 24 | 25 | - `41位`,用来记录时间戳(毫秒)。 26 | - `41位`可以表示$2^{41}-1$个数字, 27 | 28 | - 如果只用来表示正整数(计算机中正数包含0),可以表示的数值范围是:0 至 $2^{41}-1$,减1是因为可表示的数值范围是从0开始算的,而不是1。 29 | 30 | - 也就是说41位可以表示$2^{41}-1$个毫秒的值,转化成单位年则是$(2^{41}-1) / (1000 * 60 * 60 * 24 * 365) = 69$年 31 | 32 | - `10位`,用来记录工作机器id。 33 | - 可以部署在$2^{10} = 1024$个节点,包括5位datacenterId和5位workerId 34 | 35 | - `5位(bit)`可以表示的最大正整数是$2^{5}-1 = 31$,即可以用0、1、2、3、....31这32个数字,来表示不同的datecenterId或workerId 36 | 37 | - `12位`,序列号,用来记录同毫秒内产生的不同id。 38 | - `12位(bit)`可以表示的最大正整数是$2^{12}-1 = 4095$,即可以用0、1、2、3、....4094这4095个数字,来表示同一机器同一时间截(毫秒)内产生的4095个ID序号 39 | 40 | #### 感谢 41 | 42 | [twitter开源项目 - Scala版](https://github.com/twitter/snowflake) 43 | 44 | [pysnowflake - Python版](https://github.com/erans/pysnowflake) 45 | 46 | [理解分布式id生成算法SnowFlake](https://segmentfault.com/a/1190000011282426) 47 | 48 | [64位自增ID算法详解](https://www.lanindex.com/twitter-snowflake%EF%BC%8C64%E4%BD%8D%E8%87%AA%E5%A2%9Eid%E7%AE%97%E6%B3%95%E8%AF%A6%E8%A7%A3/) 49 | -------------------------------------------------------------------------------- /tech/distributed/celery/celery_source_code.md: -------------------------------------------------------------------------------- 1 | [Draft]Celery 源码阅读 2 | 3 | - @task 构造类 4 | 5 | [@task](https://github.com/hackfengJam/celery/blob/21baef53c39bc1909fd6eee9a2a20e6ce851e88c/celery/app/base.py#L362) 6 | 7 | 8 | - 自动重试 9 | autoretry_for celery/app/base.py _task_from_fun 10 | 11 | [_task_from_fun](https://github.com/hackfengJam/celery/blob/21baef53c39bc1909fd6eee9a2a20e6ce851e88c/celery/app/base.py#L430) 12 | 13 | 14 | 15 | 16 | * 自动重试 autoretry_for celery/app/base.py _task_from_fun 17 | * task类 celery/app/base.py _task_from_fun 18 | * 重试 celery/app/task.py retry(self 19 | * 任务执行 celery/app/trace.py build_tracer.trace_task 20 | * on_error 21 | * 发送 22 | * celery/app/consumer.py connect 23 | * celery/app/base.py connection_for_read 24 | * Request 25 | * celery/celery/worker/request.py 26 | * 持久化 27 | * 持久化 celery/backends/base.py mark_as_done 28 | * Worker 29 | * celery/worker/worker.py 30 | * self._conninfo = self.app.connection_for_read() 31 | * TaskId 生成策略 32 | * uuid 33 | -------------------------------------------------------------------------------- /tech/distributed/etcd/etcd_study_1_what_is_etcd.md: -------------------------------------------------------------------------------- 1 | # What is etcd ? 2 | 3 | ### What is etcd ? 4 | 5 | 以下内容,译自 [etcd 官网](https://etcd.io/) 6 | 7 | --- 8 | 9 | #### 目录 10 | 11 | - [1. Project](#1-Project) 12 | - [2. Technical overview](#2-Technical-overview) 13 | - [3. Adopters](#3-Adopters) 14 | 15 | 16 | #### 1. Project 17 | 18 | 1.1 etcd 是一个强一致的的分布式 键-值 存储,它提供了一种可靠的方式来存储需要由分布式系统机器或集群访问的数据 19 | 它优雅地处理网络分区期间的领导者选举,并且可以容忍机器故障,即使在领导者节点中也是如此。 20 | 21 |
22 | 原文 23 | 24 | etcd is a strongly consistent, distributed key-value store 25 | that provides a reliable way to store data 26 | that needs to be accessed by a distributed system or cluster of machines. 27 | It gracefully handles leader elections during network partitions and can tolerate machine failure, even in the leader node. 28 | 29 |
30 | 31 | 32 | 1.2 从简单的 Web应用程序 到 Kubernetes,任何复杂的应用程序都可以读取数据并将数据写入 etcd 。 33 | 34 | 35 |
36 | 原文 37 | 38 | Applications of any complexity, from a simple web app to [Kubernetes](https://kubernetes.io/), can read data from and write data into etcd. 39 | 40 |
41 | 42 | 1.3 您的应用程序可以读取和写入 etcd 中的数据。 43 | 一个简单的用例是将 etcd 中的数据库连接详细信息或功能标记存储为键值对。可以监视这些值,允许您的应用在更改时重新配置。 44 | 高级用法利用 etcd 的一致性保证来实现数据库领导者选举或跨工作集群执行分布式锁定。 45 | 46 | 47 |
48 | 原文 49 | 50 | Your applications can read from and write data into etcd . 51 | A simple use case is storing database connection details or feature flags in etcd as key-value pairs. 52 | These values can be watched, allowing your app to reconfigure itself when they change. 53 | Advanced uses take advantage of etcd ’s consistency guarantees 54 | to implement database leader elections or perform distributed locking across a cluster of workers. 55 | 56 |
57 | 58 | 1.4 etcd 是开源的,可以在 GitHub 上获得,并由 Cloud Native Computing Foundation 支持。 59 | 60 |
61 | 原文 62 | 63 | etcd is open source, available [on GitHub](https://github.com/etcd-io/etcd), and backed by the [Cloud Native Computing Foundation](https://www.cncf.io/). 64 | 65 |
66 | 67 | #### 2. Technical overview 68 | 69 | 2.1 etcd 是用 Go 编写的,它具有出色的跨平台支持,小型二进制文件和背后的优秀社区。 70 | etcd 机器之间的通信通过 Raft 一致性算法处理。 71 | 72 |
73 | 原文 74 | 75 | etcd is written in [Go](https://golang.org/), which has excellent cross-platform support, small binaries and a great community behind it. 76 | Communication between etcd machines is handled via the Raft consensus algorithm. 77 | 78 |
79 | 80 | 2.2 来自 etcd 领导者的延迟是最重要的跟踪指标,内置仪表板具有专用于此的视图。 81 | 在我们的测试中,严重的延迟会在集群内引入不稳定性,因为 Raft 的速度与大多数机器中的最慢机器一样快(/因为Raft只有大多数机器中最慢的机器速度)。 82 | 您可以通过正确调整集群来缓解此问题。etcd 已经在具有高度可变网络的云提供商上进行了预调整。 83 | 84 |
85 | 原文 86 | 87 | Latency from the etcd leader is the most important metric 88 | to track and the built-in dashboard has a view dedicated to this. 89 | In our testing, severe latency will introduce instability within the cluster 90 | because Raft is only as fast as the slowest machine in the majority. 91 | You can mitigate this issue by properly tuning the cluster. 92 | etcd has been pre-tuned on cloud providers with highly variable networks. 93 | 94 |
95 | 96 | #### 3. Adopters 97 | 98 |
99 | Adopters List 100 | 101 | 3.1 [Kubernetes (K8s)](https://kubernetes.io/) 102 | 103 | etcd 是服务发现的后端,存储集群状态和配置 104 | 105 |
106 | 原文 107 | 108 | etcd is the backend for service discovery and stores cluster state and configuration 109 | 110 |
111 | 112 | 3.2 [Rook](https://rook.io/) 113 | 114 | etcd 作为 Rook 的编排引擎 115 | 116 |
117 | 原文 118 | 119 | etcd serves as the orchestration engine for Rook 120 | 121 |
122 | 123 | 3.3 [CoreDNS](https://coredns.io/) 124 | 125 | CoreDNS 使用 etcd 作为可选后端 126 | 127 |
128 | 原文 129 | 130 | CoreDNS uses etcd as an optional backend 131 | 132 |
133 | 134 | 135 | 3.4 [M3](https://eng.uber.com/m3/) 136 | 137 | M3 是 Uber 创建的 Prometheus 大型指标平台,使用 etcd 进行规则存储和其他功能 138 | 139 |
140 | 原文 141 | 142 | M3, a large-scale metrics platform for Prometheus created by Uber, uses etcd for rule storage and other functions 143 | 144 |
145 | 146 | 3.5 [OpenStack](https://www.openstack.org/) 147 | 148 | OpenStack 支持 etcd 作为配置存储,分布式密钥锁定等的可选提供者 149 | 150 |
151 | 原文 152 | 153 | OpenStack supports etcd as an optional provider of configuration storage, distributed key locking, and more 154 | 155 |
156 | 157 | 3.6 [Patroni](https://github.com/zalando/patroni) 158 | 159 | 带有ZooKeeper,etcd 或 Consul 的 PostgreSQL HA模板 160 | 161 |
162 | 原文 163 | 164 | A template for PostgreSQL HA with ZooKeeper, etcd, or Consul 165 | 166 |
167 | 168 | 3.7 [Trillian](https://github.com/google/trillian/) 169 | 170 | 由 Google 创建的透明,高度可扩展且可加密验证的数据存储 171 | 172 |
173 | 原文 174 | 175 | A transparent, highly scalable and cryptographically verifiable data store, created by Google 176 | 177 |
178 |
179 | 180 | ## 感谢 181 | 182 | [etcd 官网](https://etcd.io/) 183 | 184 | [etcd 官方文档](https://etcd.io/docs/v3.3.12/) 185 | -------------------------------------------------------------------------------- /tech/distributed/etcd/etcd_study_1_what_is_etcd_back.md: -------------------------------------------------------------------------------- 1 | # What is etcd ? 2 | 3 | ### What is etcd ? 4 | 5 | 以下内容,译自 [etcd 官网](https://etcd.io/) 6 | 7 | --- 8 | 9 | #### 目录 10 | 11 | - [1. Project](#1-Project) 12 | - [2. Technical overview](#2-Technical-overview) 13 | - [3. Adopters](#3-Adopters) 14 | 15 | 16 | #### 1. Project 17 | 18 | 1.1 etcd is a strongly consistent, distributed key-value store 19 | that provides a reliable way to store data 20 | that needs to be accessed by a distributed system or cluster of machines. 21 | It gracefully handles leader elections during network partitions and can tolerate machine failure, even in the leader node. 22 | 23 |
24 | 译文 25 | 26 | etcd 是一个强一致的的分布式 键-值 存储,它提供了一种可靠的方式来存储需要由分布式系统机器或集群访问的数据 27 | 它优雅地处理网络分区期间的领导者选举,并且可以容忍机器故障,即使在领导者节点中也是如此。 28 | 29 |
30 | 31 | 32 | 1.2 Applications of any complexity, from a simple web app to [Kubernetes](https://kubernetes.io/), can read data from and write data into etcd . 33 | 34 |
35 | 译文 36 | 37 | 从简单的 Web应用程序 到 Kubernetes,任何复杂的应用程序都可以读取数据并将数据写入 etcd 。 38 | 39 |
40 | 41 | 1.3 Your applications can read from and write data into etcd . 42 | A simple use case is storing database connection details or feature flags in etcd as key-value pairs. 43 | These values can be watched, allowing your app to reconfigure itself when they change. 44 | Advanced uses take advantage of etcd ’s consistency guarantees 45 | to implement database leader elections or perform distributed locking across a cluster of workers. 46 | 47 |
48 | 译文 49 | 50 | 您的应用程序可以读取和写入 etcd 中的数据。 51 | 一个简单的用例是将 etcd 中的数据库连接详细信息或功能标记存储为键值对。可以监视这些值,允许您的应用在更改时重新配置。 52 | 高级用法利用 etcd 的一致性保证来实现数据库领导者选举或跨工作集群执行分布式锁定。 53 | 54 |
55 | 56 | 1.4 etcd is open source, available [on GitHub](https://github.com/etcd-io/etcd), and backed by the [Cloud Native Computing Foundation](https://www.cncf.io/). 57 | 58 |
59 | 译文 60 | 61 | etcd 是开源的,可以在 GitHub 上获得,并由 Cloud Native Computing Foundation 支持。 62 | 63 |
64 | 65 | #### 2. Technical overview 66 | 67 | 2.1 etcd is written in [Go](https://golang.org/), which has excellent cross-platform support, small binaries and a great community behind it. 68 | Communication between etcd machines is handled via the Raft consensus algorithm. 69 | 70 |
71 | 译文 72 | 73 | etcd 是用 Go 编写的,它具有出色的跨平台支持,小型二进制文件和背后的优秀社区。 74 | etcd 机器之间的通信通过 Raft 一致性算法处理。 75 | 76 |
77 | 78 | 2.2 Latency from the etcd leader is the most important metric 79 | to track and the built-in dashboard has a view dedicated to this. 80 | In our testing, severe latency will introduce instability within the cluster 81 | because Raft is only as fast as the slowest machine in the majority. 82 | You can mitigate this issue by properly tuning the cluster. 83 | etcd has been pre-tuned on cloud providers with highly variable networks. 84 | 85 |
86 | 译文 87 | 88 | 来自 etcd 领导者的延迟是最重要的跟踪指标,内置仪表板具有专用于此的视图。 89 | 在我们的测试中,严重的延迟会在集群内引入不稳定性,因为 Raft 的速度与大多数机器中的最慢机器一样快(/因为Raft只有大多数机器中最慢的机器速度)。 90 | 您可以通过正确调整集群来缓解此问题。etcd 已经在具有高度可变网络的云提供商上进行了预调整。 91 | 92 |
93 | 94 | #### 3. Adopters 95 | 96 | 3.1 [Kubernetes (K8s)](https://kubernetes.io/) 97 | 98 | etcd is the backend for service discovery and stores cluster state and configuration 99 | 100 |
101 | 译文 102 | 103 | etcd 是服务发现的后端,存储集群状态和配置 104 | 105 |
106 | 107 | 3.2 [Rook](https://rook.io/) 108 | 109 | etcd serves as the orchestration engine for Rook 110 | 111 |
112 | 译文 113 | 114 | etcd 作为 Rook 的编排引擎 115 | 116 |
117 | 118 | 3.3 [CoreDNS](https://coredns.io/) 119 | 120 | CoreDNS uses etcd as an optional backend 121 | 122 |
123 | 译文 124 | 125 | CoreDNS 使用 etcd 作为可选后端 126 | 127 |
128 | 129 | 130 | 3.4 [M3](https://eng.uber.com/m3/) 131 | 132 | M3, a large-scale metrics platform for Prometheus created by Uber, uses etcd for rule storage and other functions 133 | 134 |
135 | 译文 136 | 137 | M3 是 Uber 创建的 Prometheus 大型指标平台,使用 etcd 进行规则存储和其他功能 138 | 139 |
140 | 141 | 3.5 [OpenStack](https://www.openstack.org/) 142 | 143 | OpenStack supports etcd as an optional provider of configuration storage, distributed key locking, and more 144 | 145 |
146 | 译文 147 | 148 | OpenStack 支持 etcd 作为配置存储,分布式密钥锁定等的可选提供者 149 | 150 |
151 | 152 | 3.6 [Patroni](https://github.com/zalando/patroni) 153 | 154 | A template for PostgreSQL HA with ZooKeeper, etcd, or Consul 155 | 156 |
157 | 译文 158 | 159 | 带有ZooKeeper,etcd 或 Consul 的 PostgreSQL HA模板 160 | 161 |
162 | 163 | 3.7 [Trillian](https://github.com/google/trillian/) 164 | 165 | A transparent, highly scalable and cryptographically verifiable data store, created by Google 166 | 167 |
168 | 译文 169 | 170 | 由 Google 创建的透明,高度可扩展且可加密验证的数据存储 171 | 172 |
173 | 174 | ## 感谢 175 | 176 | [etcd 官网](https://etcd.io/) 177 | 178 | [etcd 官方文档](https://etcd.io/docs/v3.3.12/) 179 | -------------------------------------------------------------------------------- /tech/distributed/etcd/etcd_usage_golang_1.md: -------------------------------------------------------------------------------- 1 | ## Golang 操作 etcd(上) 2 | 3 | ### 目录 4 | 5 | [1. 连接 etcd](#1-连接-etcd) 6 | 7 | [2. Put 写入 KV](#2-put-写入-kv) 8 | 9 | [3. Get 读取 KV](#3-get-读取-kv) 10 | 11 | [4. Get 读取目录下所有 KV](#4-get-读取目录下所有-kv) 12 | 13 | [5. Delete 删除 KV](#5-delete-删除-kv) 14 | 15 | --- 16 | 17 | [相关博文](#相关博文) 18 | 19 | 20 | #### 1. 连接 etcd 21 | 22 |
23 | 查看源代码 24 | 25 | ```golang 26 | package main 27 | 28 | import ( 29 | "fmt" 30 | "go.etcd.io/etcd/clientv3" 31 | "time" 32 | ) 33 | 34 | func main() { 35 | 36 | var ( 37 | config clientv3.Config 38 | client *clientv3.Client 39 | err error 40 | ) 41 | 42 | // 客户端配置 43 | config = clientv3.Config{ 44 | Endpoints: []string{"127.0.0.1:2379"}, // 集群列表 45 | DialTimeout: 5 * time.Second, 46 | } 47 | 48 | // 建立连接 49 | if client, err = clientv3.New(config); err != nil { 50 | fmt.Println(err) 51 | return 52 | } 53 | 54 | // 仅测试是否连接 55 | client = client 56 | 57 | } 58 | 59 | ``` 60 | 61 |
62 | 63 | 64 | #### 2. Put 写入 KV 65 | 66 |
67 | 查看源代码 68 | 69 | ```golang 70 | package main 71 | 72 | import ( 73 | "context" 74 | "fmt" 75 | "go.etcd.io/etcd/clientv3" 76 | "time" 77 | ) 78 | 79 | func main() { 80 | var ( 81 | config clientv3.Config 82 | client *clientv3.Client 83 | err error 84 | kv clientv3.KV 85 | putResp *clientv3.PutResponse 86 | ) 87 | 88 | // 客户端配置 89 | config = clientv3.Config{ 90 | Endpoints: []string{"127.0.0.1:2379"}, // 集群列表 91 | DialTimeout: 5 * time.Second, 92 | } 93 | 94 | // 建立一个客户端 95 | if client, err = clientv3.New(config); err != nil { 96 | fmt.Println(err) 97 | return 98 | } 99 | 100 | // 用于读写etcd的键值对 101 | kv = clientv3.NewKV(client) 102 | 103 | if putResp, err = kv.Put(context.TODO(), "/cron/jobs/job1", "bye", clientv3.WithPrevKV()); err != nil { 104 | fmt.Println(err) 105 | } else { 106 | fmt.Println("Revision", putResp.Header.Revision) 107 | fmt.Println("RaftTerm", putResp.Header.RaftTerm) 108 | if &putResp.PrevKv != nil { 109 | fmt.Println("PrevValue", string(putResp.PrevKv.Value)) 110 | } 111 | 112 | } 113 | 114 | } 115 | 116 | ``` 117 | 118 |
119 | 120 | 121 | #### 3. Get 读取 KV 122 | 123 |
124 | 查看源代码 125 | 126 | ```golang 127 | 128 | package main 129 | 130 | import ( 131 | "context" 132 | "fmt" 133 | "go.etcd.io/etcd/clientv3" 134 | "time" 135 | ) 136 | 137 | func main() { 138 | var ( 139 | config clientv3.Config 140 | client *clientv3.Client 141 | err error 142 | kv clientv3.KV 143 | getResp *clientv3.GetResponse 144 | ) 145 | 146 | // 客户端配置 147 | config = clientv3.Config{ 148 | Endpoints: []string{"127.0.0.1:2379"}, // 集群列表 149 | DialTimeout: 5 * time.Second, 150 | } 151 | 152 | // 建立一个客户端 153 | if client, err = clientv3.New(config); err != nil { 154 | fmt.Println(err) 155 | return 156 | } 157 | 158 | // 用于读写etcd的键值对 159 | kv = clientv3.NewKV(client) 160 | 161 | if getResp, err = kv.Get(context.TODO(), "/cron/jobs/job1", /*clientv3.WithCountOnly()*/); err != nil { 162 | fmt.Println(err) 163 | } else { 164 | fmt.Println(getResp.Kvs, getResp.Count) 165 | } 166 | 167 | } 168 | 169 | ``` 170 | 171 |
172 | 173 | 174 | #### 4. Get 读取目录下所有 KV 175 | 176 |
177 | 查看源代码 178 | 179 | ```golang 180 | 181 | package main 182 | 183 | import ( 184 | "context" 185 | "fmt" 186 | "go.etcd.io/etcd/clientv3" 187 | "time" 188 | ) 189 | 190 | func main() { 191 | var ( 192 | config clientv3.Config 193 | client *clientv3.Client 194 | err error 195 | kv clientv3.KV 196 | getResp *clientv3.GetResponse 197 | ) 198 | 199 | // 客户端配置 200 | config = clientv3.Config{ 201 | Endpoints: []string{"127.0.0.1:2379"}, // 集群列表 202 | DialTimeout: 5 * time.Second, 203 | } 204 | 205 | // 建立一个客户端 206 | if client, err = clientv3.New(config); err != nil { 207 | fmt.Println(err) 208 | return 209 | } 210 | 211 | // 用于读写etcd的键值对 212 | kv = clientv3.NewKV(client) 213 | 214 | // 写入另外一个Job 215 | kv.Put(context.TODO(), "/cron/jobs/job2", "{...}") 216 | 217 | // 读取 /corn/jobs/ 为前缀的所有key 218 | if getResp, err = kv.Get(context.TODO(), "/cron/jobs", clientv3.WithPrefix()); err != nil { 219 | fmt.Println(err) 220 | } else { // 获取成功,遍历所有kvs 221 | fmt.Println(getResp.Kvs) 222 | } 223 | 224 | } 225 | 226 | ``` 227 | 228 |
229 | 230 | 231 | #### 5. Delete 删除 KV 232 | 233 |
234 | 查看源代码 235 | 236 | ```golang 237 | 238 | package main 239 | 240 | import ( 241 | "context" 242 | "fmt" 243 | "go.etcd.io/etcd/clientv3" 244 | "go.etcd.io/etcd/mvcc/mvccpb" 245 | "time" 246 | ) 247 | 248 | func main() { 249 | var ( 250 | config clientv3.Config 251 | client *clientv3.Client 252 | err error 253 | kv clientv3.KV 254 | delResp *clientv3.DeleteResponse 255 | kvpair *mvccpb.KeyValue 256 | ) 257 | 258 | config = clientv3.Config{ 259 | Endpoints: []string{"127.0.0.1:2379"}, // 集群列表 260 | DialTimeout: 5 * time.Second, 261 | } 262 | 263 | // 建立一个客户端 264 | if client, err = clientv3.New(config); err != nil { 265 | fmt.Println(err) 266 | return 267 | } 268 | 269 | // 用于读写etcd的键值对 270 | kv = clientv3.NewKV(client) 271 | 272 | // 删除KV 273 | if delResp, err = kv.Delete(context.TODO(), "/cron/jobs/job1", clientv3.WithFromKey(), clientv3.WithLimit(2)); err != nil { 274 | fmt.Println(err) 275 | return 276 | } 277 | 278 | // 被删除之前的value是什么 279 | if len(delResp.PrevKvs) != 0 { 280 | for _, kvpair = range delResp.PrevKvs { 281 | fmt.Println("删除了:", string(kvpair.Key), string(kvpair.Value)) 282 | } 283 | } 284 | } 285 | 286 | 287 | ``` 288 | 289 |
290 | 291 | ### 相关博文 292 | 293 | - [什么是 etcd?](/tech/distributed/etcd/etcd_study_1_what_is_etcd.md) 294 | 295 | - [etcd 功能与原理](/tech/distributed/etcd/etcd_function_and_principle.md) 296 | 297 | - [Golang 操作 etcd(下)](/tech/distributed/etcd/etcd_usage_golang_2.md) 298 | 299 | 300 | #### 感谢 301 | 302 | [etcd 官网](https://etcd.io/) 303 | 304 | [Golang - 开发分布式任务调度](/design/golang_crontab/golang_crontab.md) 305 | 306 | -------------------------------------------------------------------------------- /tech/distributed/raft/images/raft_consensus_algorithm_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/tech/distributed/raft/images/raft_consensus_algorithm_1.png -------------------------------------------------------------------------------- /tech/distributed/raft/images/raft_log_replication_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/tech/distributed/raft/images/raft_log_replication_1.png -------------------------------------------------------------------------------- /tech/distributed/raft/images/raft_log_replication_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/tech/distributed/raft/images/raft_log_replication_2.png -------------------------------------------------------------------------------- /tech/distributed/raft/images/server_status.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/tech/distributed/raft/images/server_status.png -------------------------------------------------------------------------------- /tech/distributed/raft/raft_consensus_algorithm.md: -------------------------------------------------------------------------------- 1 | ## Raft 一致性算法 2 | 3 | ### 前言 4 | 5 | 本文内容几乎全部摘自 6 | 7 | - [Raft 英文 paper pdf](https://ramcloud.atlassian.net/wiki/download/attachments/6586375/raft.pdf) 8 | 9 | - [Raft 论文译文](https://github.com/maemual/raft-zh_cn/blob/master/raft-zh_cn.md) 10 | 11 | paper 写的比较完备,无可挑剔 : ) 12 | 13 | ### 目录 14 | 15 | [1. Raft 复制状态机](#1-Raft-复制状态机) 16 | 17 | [2. 关于 Raft 一致性算法的浓缩总结](#2-关于-Raft-一致性算法的浓缩总结) 18 | 19 | [3. Raft 在任何时候都保证以下的各个特性](#3-Raft-在任何时候都保证以下的各个特性) 20 | 21 | 22 | ### 1. Raft 复制状态机 23 | 24 | ![图 1 ](./images/raft_consensus_algorithm_1.png) 25 | 26 | > 图 1 :复制状态机的结构。一致性算法管理着来自客户端指令的复制日志。状态机从日志中处理相同顺序的相同指令,所以产生的结果也是相同的。 27 | 28 | 复制状态机通常都是基于复制日志实现的,如图 1。每一个服务器存储一个包含一系列指令的日志,并且按照日志的顺序进行执行。 29 | 每一个日志都按照相同的顺序包含相同的指令,所以每一个服务器都执行相同的指令序列。 30 | 因为每个状态机都是确定的,每一次执行操作都产生相同的状态和同样的序列。 31 | 32 | 保证复制日志相同就是一致性算法的工作了。 33 | 在一台服务器上,一致性模块接收客户端发送来的指令然后增加到自己的日志中去。 34 | 它和其他服务器上的一致性模块进行通信来保证每一个服务器上的日志最终都以相同的顺序包含相同的请求,尽管有些服务器会宕机。 35 | 一旦指令被正确的复制,每一个服务器的状态机按照日志顺序处理他们,然后输出结果被返回给客户端。 36 | 因此,服务器集群看起来形成一个高可靠的状态机。 37 | 38 | 实际系统中使用的一致性算法通常含有以下特性: 39 | 40 | * 安全性保证(绝对不会返回一个错误的结果):在非拜占庭错误情况下,包括网络延迟、分区、丢包、冗余和乱序等错误都可以保证正确。 41 | * 可用性:集群中只要有大多数的机器可运行并且能够相互通信、和客户端通信,就可以保证可用。因此,一个典型的包含 5 个节点的集群可以容忍两个节点的失败。服务器被停止就认为是失败。他们当有稳定的存储的时候可以从状态中恢复回来并重新加入集群。 42 | * 不依赖时序来保证一致性:物理时钟错误或者极端的消息延迟只有在最坏情况下才会导致可用性问题。 43 | * 通常情况下,一条指令可以尽可能快的在集群中大多数节点响应一轮远程过程调用时完成。小部分比较慢的节点不会影响系统整体的性能。 44 | 45 | ### 2. 关于 Raft 一致性算法的浓缩总结(不包括成员变换和日志压缩) 46 | 47 | > Raft 是一种用来管理[Raft 复制状态机](#1-Raft-复制状态机)中描述的复制日志的算法。 48 | 49 | ### 2.1 状态 50 | 51 | |状态|所有服务器上持久存在的| 52 | |-------|------| 53 | |currentTerm | 服务器最后一次知道的任期号(初始化为 0,持续递增)| 54 | |votedFor | 在当前获得选票的候选人的 Id| 55 | | log[] | 日志条目集;每一个条目包含一个用户状态机执行的指令,和收到时的任期号 | 56 | 57 | |状态|所有服务器上经常变的| 58 | |-------|------| 59 | | commitIndex| 已知的最大的已经被提交的日志条目的索引值| 60 | | lastApplied| 最后被应用到状态机的日志条目索引值(初始化为 0,持续递增)| 61 | 62 | | 状态 | 在领导人里经常改变的 (选举后重新初始化)| 63 | |----|--------| 64 | | nextIndex[] | 对于每一个服务器,需要发送给他的下一个日志条目的索引值(初始化为领导人最后索引值加一)| 65 | | matchIndex[] | 对于每一个服务器,已经复制给他的日志的最高索引值| 66 | 67 | 68 | ### 2.2 附加日志 RPC 69 | 70 | 由领导人负责调用来复制日志指令;也会用作 heartbeat 71 | 72 | | 参数 | 解释 | 73 | |----|----| 74 | |term| 领导人的任期号| 75 | |leaderId| 领导人的 Id,以便于跟随者重定向请求| 76 | |prevLogIndex|新的日志条目紧随之前的索引值| 77 | |prevLogTerm|prevLogIndex 条目的任期号| 78 | |entries[]|准备存储的日志条目(表示心跳时为空;一次性发送多个是为了提高效率)| 79 | |leaderCommit|领导人已经提交的日志的索引值| 80 | 81 | | 返回值| 解释| 82 | |---|---| 83 | |term|当前的任期号,用于领导人去更新自己| 84 | |success|跟随者包含了匹配上 prevLogIndex 和 prevLogTerm 的日志时为真| 85 | 86 | 接收者实现: 87 | 88 | 1. 如果 `term < currentTerm` 就返回 false 89 | 2. 如果日志在 prevLogIndex 位置处的日志条目的任期号和 prevLogTerm 不匹配,则返回 false 90 | 3. 如果已经存在的日志条目和新的产生冲突(索引值相同但是任期号不同),删除这一条和之后所有的 91 | 4. 附加日志中尚未存在的任何新条目 92 | 5. 如果 `leaderCommit > commitIndex`,令 commitIndex 等于 leaderCommit 和 新日志条目索引值中较小的一个 93 | 94 | ### 2.3 请求投票 RPC 95 | 96 | 由候选人负责调用用来征集选票 97 | 98 | | 参数 | 解释| 99 | |---|---| 100 | |term| 候选人的任期号| 101 | |candidateId| 请求选票的候选人的 Id | 102 | |lastLogIndex| 候选人的最后日志条目的索引值| 103 | |lastLogTerm| 候选人最后日志条目的任期号| 104 | 105 | | 返回值| 解释| 106 | |---|---| 107 | |term| 当前任期号,以便于候选人去更新自己的任期号| 108 | |voteGranted| 候选人赢得了此张选票时为真| 109 | 110 | 接收者实现: 111 | 112 | 1. 如果`term < currentTerm`返回 false 113 | 2. 如果 votedFor 为空或者为 candidateId,并且候选人的日志至少和自己一样新,那么就投票给他 114 | 115 | ### 2.4 所有服务器需遵守的规则 116 | 117 | 所有服务器: 118 | 119 | * 如果`commitIndex > lastApplied`,那么就 lastApplied 加一,并把`log[lastApplied]`应用到状态机中 120 | * 如果接收到的 RPC 请求或响应中,任期号`T > currentTerm`,那么就令 currentTerm 等于 T,并切换状态为跟随者 121 | 122 | 跟随者: 123 | 124 | * 响应来自候选人和领导者的请求 125 | * 如果在超过选举超时时间的情况之前都没有收到领导人的心跳,或者是候选人请求投票的,就自己变成候选人 126 | 127 | 候选人: 128 | 129 | * 在转变成候选人后就立即开始选举过程 130 | * 自增当前的任期号(currentTerm) 131 | * 给自己投票 132 | * 重置选举超时计时器 133 | * 发送请求投票的 RPC 给其他所有服务器 134 | * 如果接收到大多数服务器的选票,那么就变成领导人 135 | * 如果接收到来自新的领导人的附加日志 RPC,转变成跟随者 136 | * 如果选举过程超时,再次发起一轮选举 137 | 138 | 领导人: 139 | 140 | * 一旦成为领导人:发送空的附加日志 RPC(心跳)给其他所有的服务器;在一定的空余时间之后不停的重复发送,以阻止跟随者超时 141 | * 如果接收到来自客户端的请求:附加条目到本地日志中,在条目被应用到状态机后响应客户端 142 | * 如果对于一个跟随者,最后日志条目的索引值大于等于 nextIndex,那么:发送从 nextIndex 开始的所有日志条目: 143 | * 如果成功:更新相应跟随者的 nextIndex 和 matchIndex 144 | * 如果因为日志不一致而失败,减少 nextIndex 重试 145 | * 如果存在一个满足`N > commitIndex`的 N,并且大多数的`matchIndex[i] ≥ N`成立,并且`log[N].term == currentTerm`成立,那么令 commitIndex 等于这个 N 146 | 147 | ### 3. Raft 在任何时候都保证以下的各个特性 148 | 149 | | 特性| 解释| 150 | |---|---| 151 | |选举安全特性| 对于一个给定的任期号,最多只会有一个领导人被选举出来| 152 | |领导人只附加原则| 领导人绝对不会删除或者覆盖自己的日志,只会增加| 153 | |日志匹配原则| 如果两个日志在相同的索引位置的日志条目的任期号相同,那么我们就认为这个日志从头到这个索引位置之间全部完全相同| 154 | |领导人完全特性|如果某个日志条目在某个任期号中已经被提交,那么这个条目必然出现在更大任期号的所有领导人中| 155 | |状态机安全特性| 如果一个领导人已经在给定的索引值位置的日志条目应用到状态机中,那么其他任何的服务器在这个索引位置不会提交一个不同的日志| 156 | 157 | 158 | ### 相关博文 159 | 160 | - [Raft 日志复制](/tech/distributed/raft/raft_log_replication.md) 161 | 162 | - [Raft 领导选举](/tech/distributed/raft/raft_leader_election.md) 163 | 164 | - [Golang 操作 etcd(上)](/tech/distributed/etcd/etcd_usage_golang_1.md) 165 | 166 | - [Golang 操作 etcd(下)](/tech/distributed/etcd/etcd_usage_golang_2.md) 167 | 168 | 169 | #### 感谢 170 | 171 | - [Raft 英文 paper pdf](https://ramcloud.atlassian.net/wiki/download/attachments/6586375/raft.pdf) 172 | 173 | - [Raft 作者讲解视频](https://www.youtube.com/watch?v=YbZ3zDzDnrw&feature=youtu.be) 174 | 175 | - [Raft 作者讲解视频对应的 PPT](https://ramcloud.atlassian.net/wiki/download/attachments/6586375/raft.pdf) 176 | 177 | - [Raft 论文译文](https://github.com/maemual/raft-zh_cn/blob/master/raft-zh_cn.md) 178 | 179 | - [Raft 动画](http://thesecretlivesofdata.com/raft/) 180 | 181 | 182 | -------------------------------------------------------------------------------- /tech/distributed/raft/raft_leader_election.md: -------------------------------------------------------------------------------- 1 | ## Raft 领导选举 2 | 3 | ### 目录 4 | 5 | [1. 心跳机制来触发领导人选举](#1-心跳机制来触发领导人选举) 6 | 7 | [2. 选举过程](#2-选举过程) 8 | 9 | [3. 候选人获胜(选举)规则](#3-候选人获胜选举规则) 10 | 11 | [4. 注意](#4-注意) 12 | 13 | [5. 总结](#5-总结) 14 | 15 | --- 16 | 17 | [相关博文](#相关博文) 18 | 19 | 服务器角色转换图 20 | 21 | ![Alt text](./images/server_status.png) 22 | 23 | ### 1. 心跳机制来触发领导人选举 24 | 25 | 1.1 跟随者当服务器程序启动时,他们都是跟随者身份。 26 | 27 | 1.2 一个跟随者服务器节点只要他从领导人或者候选者处接收到有效的 RPCs,就将继续保持着跟随者状态。 28 | 29 | 1.3 领导者周期性的向所有跟随者发送心跳包(即不包含日志项内容的附加日志项 RPCs)来维持自己的权威。 30 | 31 | 1.4 如果一个跟随者在一段时间里没有接收到任何消息,也就是选举超时,那么他就会认为系统中没有可用的领导者,并发起选举以选出新的领导者。 32 | 33 | ### 2. 选举过程 34 | 35 | 2.1 要开始一次选举过程,跟随者先要增加自己的当前任期号并且转换到候选人状态。 36 | 37 | 2.2 然后他会并行的向集群中的其他服务器节点发送请求投票的 RPCs 来给自己投票。候选人会继续保持着当前状态直到以下三件事情之一发生: 38 | 39 | (a) 他自己赢得了这次的选举 40 | 41 | (b) 其他的服务器成为领导者 42 | 43 | (c) 一段时间之后没有任何一个获胜的人。 44 | 45 | ### 3. 候选人获胜(选举)规则 46 | 47 | 3.1 当一个候选人从整个集群的大多数服务器节点获得了针对同一个任期号的选票,那么他就赢得了这次选举并成为领导人 48 | 49 | 3.2 每一个服务器最多会对一个任期号投出一张选票,按照先来先服务的原则。 50 | 51 | 3.3 要求大多数选票的规则确保了最多只会有一个候选人赢得此次选举。 52 | 一旦候选人赢得选举,他就立即成为领导人。然后他会向其他的服务器发送心跳消息来建立自己的权威并且阻止新的领导人的产生 53 | 54 | ### 4. 注意 55 | 56 | 4.1 在等待投票的时候,候选人可能会从其他的服务器接收到声明它是领导人的附加日志项 RPC。 57 | 58 | - 如果这个领导人的任期号(包含在此次的 RPC中)不小于候选人当前的任期号,那么候选人会承认领导人合法并回到跟随者状态。 59 | 60 | - 如果此次 RPC 中的任期号比自己小,那么候选人就会拒绝这次的 RPC 并且继续保持候选人状态。 61 | 62 | 4.2 候选人第三种可能的结果是既没有赢得选举也没有输: 63 | 64 | - 如果有多个跟随者同时成为候选人,那么选票可能会被瓜分以至于没有候选人可以赢得大多数人的支持。 65 | 66 | - 当这种情况发生的时候,每一个候选人都会超时,然后通过增加当前任期号来开始一轮新的选举。 67 | 68 | - 然而,没有其他机制的话,选票可能会被无限的重复瓜分。 69 | 为了解决这个问题,Raft 增加了一个“时间随机选择机制”,选举超时时间是从一个固定的区间(例如 150-300 毫秒)随机选择,这样就使得每个节点发送 RPC 请求的时间错开。 70 | 71 | 4.3 选举限制。请求投票 RPC 实现了这样的限制:RPC 中包含了候选人的日志信息,然后投票人会拒绝掉那些日志没有自己新的投票请求。 72 | 73 |
74 | 查看选举限制(论文译文) 75 | 76 | 在任何基于领导人的一致性算法中,领导人都必须存储所有已经提交的日志条目。 77 | 在某些一致性算法中,例如 Viewstamped Replication,某个节点即使是一开始并没有包含所有已经提交的日志条目,它也能被选为领导者。 78 | 这些算法都包含一些额外的机制来识别丢失的日志条目并把他们传送给新的领导人,要么是在选举阶段要么在之后很快进行。 79 | 不幸的是,这种方法会导致相当大的额外的机制和复杂性。 80 | Raft 使用了一种更加简单的方法,它可以保证所有之前的任期号中已经提交的日志条目在选举的时候都会出现在新的领导人中,不需要传送这些日志条目给领导人。 81 | 这意味着日志条目的传送是单向的,只从领导人传给跟随者,并且领导人从不会覆盖自身本地日志中已经存在的条目。 82 | 83 | Raft 使用投票的方式来阻止一个候选人赢得选举除非这个候选人包含了所有已经提交的日志条目。 84 | 候选人为了赢得选举必须联系集群中的大部分节点,这意味着每一个已经提交的日志条目在这些服务器节点中肯定存在于至少一个节点上。 85 | 如果候选人的日志至少和大多数的服务器节点一样新(这个新的定义会在下面讨论),那么他一定持有了所有已经提交的日志条目。 86 | 请求投票 RPC 实现了这样的限制:RPC 中包含了候选人的日志信息,然后投票人会拒绝掉那些日志没有自己新的投票请求。 87 | 88 |
89 | 90 | ### 5. 总结 91 | 92 | 5.1 心跳机制和超时机制触发领导者选举 93 | 94 | 5.2 选举的两个过程:跟随者增加任期号,转换状态至候选者状态;维持当前状态,并发送请求投票的 RPCs,直至出现三种情况(事件),可能(没有获胜者)触发“时间随机选择机制”。 95 | 96 | ### 相关博文 97 | 98 | - [Raft 日志复制](/tech/distributed/raft/raft_log_replication.md) 99 | 100 | - [Raft 一致性算法](/tech/distributed/raft/raft_consensus_algorithm.md) 101 | 102 | - [什么是 etcd?](/tech/distributed/etcd/etcd_study_1_what_is_etcd.md) 103 | 104 | - [etcd 功能与原理](/tech/distributed/etcd/etcd_function_and_principle.md) 105 | 106 | - [Golang 操作 etcd(上)](/tech/distributed/etcd/etcd_usage_golang_1.md) 107 | 108 | - [Golang 操作 etcd(下)](/tech/distributed/etcd/etcd_usage_golang_2.md) 109 | 110 | 111 | #### 感谢 112 | 113 | - [Raft 英文 paper pdf](https://ramcloud.atlassian.net/wiki/download/attachments/6586375/raft.pdf) 114 | 115 | - [Raft 作者讲解视频](https://www.youtube.com/watch?v=YbZ3zDzDnrw&feature=youtu.be) 116 | 117 | - [Raft 作者讲解视频对应的 PPT](https://ramcloud.atlassian.net/wiki/download/attachments/6586375/raft.pdf) 118 | 119 | - [Raft 论文译文](https://github.com/maemual/raft-zh_cn/blob/master/raft-zh_cn.md) 120 | 121 | - [Raft 动画](http://thesecretlivesofdata.com/raft/) 122 | 123 | 124 | -------------------------------------------------------------------------------- /tech/distributed/raft/raft_log_replication.md: -------------------------------------------------------------------------------- 1 | ## Raft 日志复制 2 | 3 | ### 目录 4 | 5 | [1. 日志结构](#1-日志结构) 6 | 7 | [2. 主从日志的一致性](#2-主从日志的一致性) 8 | 9 | [3. 日志特性](#3-日志特性) 10 | 11 | [4. 领导人一致性检查](#4-领导人一致性检查) 12 | 13 | [5. 总结](#5-总结) 14 | 15 | 16 | ### 1. 日志结构 17 | 18 | 19 | **附加日志 RPC**: 20 | 21 | 由领导人负责调用来复制日志指令;也会用作 heartbeat 22 | 23 | | 参数 | 解释 | 24 | |----|----| 25 | |term| 领导人的任期号| 26 | |leaderId| 领导人的 Id,以便于跟随者重定向请求| 27 | |prevLogIndex|新的日志条目紧随之前的索引值| 28 | |prevLogTerm|prevLogIndex 条目的任期号| 29 | |entries[]|准备存储的日志条目(表示心跳时为空;一次性发送多个是为了提高效率)| 30 | |leaderCommit|领导人已经提交的日志的索引值| 31 | 32 | | 返回值| 解释| 33 | |---|---| 34 | |term|当前的任期号,用于领导人去更新自己| 35 | |success|跟随者包含了匹配上 prevLogIndex 和 prevLogTerm 的日志时为真| 36 | 37 | 接收者实现: 38 | 39 | 1. 如果 `term < currentTerm` 就返回 false 40 | 2. 如果日志在 prevLogIndex 位置处的日志条目的任期号和 prevLogTerm 不匹配,则返回 false 41 | 3. 如果已经存在的日志条目和新的产生冲突(索引值相同但是任期号不同),删除这一条和之后所有的 42 | 4. 附加日志中尚未存在的任何新条目 43 | 5. 如果 `leaderCommit > commitIndex`,令 commitIndex 等于 leaderCommit 和 新日志条目索引值中较小的一个 44 | 45 | ### 2. 主从日志的一致性 46 | 47 | ![图 1 ](./images/raft_log_replication_1.png) 48 | 49 | > 图 1 :日志由有序序号标记的条目组成。 50 | 每个条目都包含创建时的任期号(图中框中的数字),和一个状态机需要执行的指令。 51 | 一个条目当可以安全的被应用到状态机中去的时候,就认为是可以提交了。 52 | 53 | **Raft 为了保证主从日志的一致性,有以下保证**: 54 | 55 | 1. 领导人 来决定什么时候把日志条目应用到状态机中是安全的;这种日志条目被称为已提交。 56 | Raft 算法保证所有已提交的日志条目都是持久化的并且最终会被所有可用的状态机执行。 57 | 58 | 2. 领导人 把指令作为一条新的日志添加到日志中后(此时还未 committed,即未应用到至 复制状态机),将并行的发送 **附加日志 RPC** 给 跟随者,希望他们复制这条日志。 59 | 60 | 3. 当 领导人 收到大多数 追随者 返回正确响应,将会更新本地最大的且即将被提交的日志条目的索引 61 | 62 | 4. 领导人 会追踪发送 3中提到的索引,并且这个索引会被包含在未来的所有附加日志 **附加日志 RPC** 请求中,这样就能保证其他的服务器知道 领导人 的索引提交位置。 63 | 64 | 5. 追随者 知道一条日志已经被提交,那么他也会将这条日志应用到自己的状态机中(按照日志索引的顺序)。 65 | 66 | ### 3. 日志特性 67 | 68 | - 如果在不同的日志中的两个条目拥有相同的 索引 和 任期号,那么他们存储了相同的指令。([Raft 在任何时候都保证的特性 —— 状态机安全特性](https://github.com/hackfengJam/blog/blob/master/tech/distributed/raft/raft_consensus_algorithm.md#3-Raft-%E5%9C%A8%E4%BB%BB%E4%BD%95%E6%97%B6%E5%80%99%E9%83%BD%E4%BF%9D%E8%AF%81%E4%BB%A5%E4%B8%8B%E7%9A%84%E5%90%84%E4%B8%AA%E7%89%B9%E6%80%A7)) 69 | 70 | - 如果在不同的日志中的两个条目拥有相同的 索引 和 任期号,那么他们之前的所有日志条目也全部相同。([领导人一致性检查](#4-领导人一致性检查)) 71 | 72 | ### 4. 领导人一致性检查 73 | 74 | ![图 2 ](./images/raft_log_replication_2.png) 75 | 76 | > 图 2:当一个领导人成功当选时,跟随者可能是任何情况(a-f)。 77 | 每一个盒子表示是一个日志条目;里面的数字表示任期号。 78 | 跟随者可能会缺少一些日志条目(a-b),可能会有一些未被提交的日志条目(c-d),或者两种情况都存在(e-f)。 79 | 例如,场景 f 可能会这样发生,某服务器在任期 2 的时候是领导人,已附加了一些日志条目到自己的日志中,但在提交之前就崩溃了; 80 | 很快这个机器就被重启了,在任期 3 重新被选为领导人,并且又增加了一些日志条目到自己的日志中; 81 | 在任期 2 和任期 3 的日志被提交之前,这个服务器又宕机了,并且在接下来的几个任期里一直处于宕机状态。 82 | 83 | 在每个服务器会保存以下状态 84 | 85 | | 状态 | 在领导人里经常改变的 (选举后重新初始化)| 86 | |----|--------| 87 | | nextIndex[] | 对于每一个服务器,需要发送给他的下一个日志条目的索引值(初始化为领导人最后索引值加一)| 88 | | matchIndex[] | 对于每一个服务器,已经复制给他的日志的最高索引值| 89 | 90 | 对于领导人: 91 | 92 | * 一旦成为领导人:发送空的附加日志 RPC(心跳)给其他所有的服务器;在一定的空余时间之后不停的重复发送,以阻止跟随者超时 93 | * 如果接收到来自客户端的请求:附加条目到本地日志中,在条目被应用到状态机后响应客户端 94 | * 如果对于一个跟随者,最后日志条目的索引值大于等于 nextIndex,那么:发送从 nextIndex 开始的所有日志条目: 95 | * 如果成功:更新相应跟随者的 nextIndex 和 matchIndex 96 | * 如果因为日志不一致而失败,减少 nextIndex 重试 97 | * 如果存在一个满足`N > commitIndex`的 N,并且大多数的`matchIndex[i] ≥ N`成立,并且`log[N].term == currentTerm`成立,那么令 commitIndex 等于这个 N 98 | 99 | ### 5. 总结 100 | 101 | - 保证复制日志相同是一致性算法的主要工作也是其核心 102 | 103 | - 日志特性 104 | - 如果在不同的日志中的两个条目拥有相同的 索引 和 任期号,那么他们存储了相同的指令 105 | - 如果在不同的日志中的两个条目拥有相同的 索引 和 任期号,那么他们之前的所有日志条目也全部相同 106 | 107 | - 状态机安全特性:如果一个领导人已经在给定的索引值位置的日志条目应用到状态机中,那么其他任何的服务器在这个索引位置不会提交一个不同的日志 108 | 109 | - 领导人的一致性检查 110 | 111 | ### 相关博文 112 | 113 | - [Raft 一致性算法](/tech/distributed/raft/raft_consensus_algorithm.md) 114 | 115 | - [Raft 领导选举](/tech/distributed/raft/raft_leader_election.md) 116 | 117 | - [Golang 操作 etcd(上)](/tech/distributed/etcd/etcd_usage_golang_1.md) 118 | 119 | - [Golang 操作 etcd(下)](/tech/distributed/etcd/etcd_usage_golang_2.md) 120 | 121 | #### 感谢 122 | 123 | - [Raft 英文 paper pdf](https://ramcloud.atlassian.net/wiki/download/attachments/6586375/raft.pdf) 124 | 125 | - [Raft 作者讲解视频](https://www.youtube.com/watch?v=YbZ3zDzDnrw&feature=youtu.be) 126 | 127 | - [Raft 作者讲解视频对应的 PPT](https://ramcloud.atlassian.net/wiki/download/attachments/6586375/raft.pdf) 128 | 129 | - [Raft 论文译文](https://github.com/maemual/raft-zh_cn/blob/master/raft-zh_cn.md) 130 | 131 | - [Raft 动画](http://thesecretlivesofdata.com/raft/) 132 | 133 | 134 | -------------------------------------------------------------------------------- /tech/linux/images/文件传输到网络的公共数据路径演变.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/tech/linux/images/文件传输到网络的公共数据路径演变.png -------------------------------------------------------------------------------- /tech/linux/kernel_or_user_mode.md: -------------------------------------------------------------------------------- 1 | ## 用户态与内核态 2 | 3 | ### 1. 用户态切换到内核态方式 4 | 5 | 用户态切换到的触发条件:申请外部资源 6 | 7 | #### 1.1 用户态切换到内核态的3种方式 8 | 9 | 1、系统调用 10 | 11 | 这是用户进程主动要求切换到内核态的一种方式,用户进程通过系统调用申请操作系统提供的服务程序完成工作。 12 | 而系统调用的机制其核心还是使用了操作系统为用户特别开放的一个中断来实现,例如Linux的ine 80h中断。 13 | 14 | 15 | 例: 16 | 17 | - 读写文件 open/read/write 18 | - 申请内存(堆内存) malloc 19 | - brk (<128k) 20 | - mmap(申请虚拟内存空间) 21 | 22 | 注意: 23 | 24 | 这里 mmap 申请的是虚拟内存空间,并不是主存上的物理内存空间, 25 | 想要拿到真正的物理内存空间,还要在第一次访问时,会发现虚拟内存地址没有映射到物理内存地址, 26 | 于是触发 缺页中断(缺页异常) 27 | 28 | 29 | 2、异常 30 | 31 | 当CPU在执行运行在用户态的程序时,发现了某些事件不可知的异常,这是会触发由当前运行进程切换到处理此。 32 | 异常的内核相关程序中,也就到了内核态,比如缺页异常。 33 | 34 | 3、外围设备的中断 35 | 36 | 当外围设备完成用户请求的操作之后,会向CPU发出相应的中断信号,这时CPU会暂停执行下一条将要执行的指令,转而去执行中断信号的处理程序, 37 | 如果先执行的指令是用户态下的程序,那么这个转换的过程自然也就发生了有用户态到内核态的切换。 38 | 比如硬盘读写操作完成,系统会切换到硬盘读写的中断处理程序中执行后续操作等。 39 | 40 | 41 | #### 1.2 系统调用 42 | 43 | > man syscalls 44 | 45 | ① 进程 46 | 47 | - exit 48 | - fork 49 | 50 | ② 文件 51 | 52 | - chmod 53 | - chown 54 | 55 | ③ 设备 56 | 57 | - read 58 | - write 59 | - io ctrl 60 | - mmap(磁盘) 61 | 62 | ④ 信息 63 | 64 | - getcpu 65 | - get xxx 66 | 67 | 68 | ⑤ 通信 69 | 70 | - 管道(pipe) 71 | - mmap(文件和内存的映射) 72 | 73 | ### 2. 切换操作 74 | 75 | 从触发方式看,可以在认为存在前述3种不同的类型,但是从最终实际完成由用户态到内核态的切换操作上来说,涉及的关键步骤是完全一样的,没有任何区别,都相当于执行了一个中断响应的过程,因为系统调用实际上最终是中断机制实现的,而异常和中断处理机制基本上是一样的,用户态切换到内核态的步骤主要包括: 76 | 77 | 1、从当前进程的描述符中提取其内核栈的ss0及esp0信息。 78 | 79 | 2、使用ss0和esp0指向的内核栈将当前进程的cs,eip,eflags,ss,esp信息保存起来,这个过程也完成了由用户栈找到内核栈的切换过程,同时保存了被暂停执行的程序的下一条指令。 80 | 81 | 3、将先前由中断向量检索得到的中断处理程序的cs,eip信息装入相应的寄存器,开始执行中断处理程序,这时就转到了内核态的程序执行了。 82 | 83 | ### 3. 用户态和内核态区别 84 | 85 | #### 3.1 系统态和用户态 86 | 87 | 在计算机系统中,通常运行着两类程序:系统程序和应用程序,为了保证系统程序不被应用程序有意或无意地破坏,为计算机设置了两种状态: 88 | 89 | - 系统态(也称为管态或核心态),操作系统在系统态运行——运行操作系统程序 90 | - 用户态(也称为目态),应用程序只能在用户态运行——运行用户程序 91 | 92 | #### 3.2 特权指令和非特权指令 93 | 94 | 在实际运行过程中,处理机会在系统态和用户态间切换。相应地,现代多数操作系统将 CPU 的指令集分为特权指令和非特权指令两类。 95 | 96 | 1) 特权指令——在系统态时运行的指令 97 | 98 | 对内存空间的访问范围基本不受限制,不仅能访问用户存储空间,也能访问系统存储空间, 99 | 特权指令只允许操作系统使用,不允许应用程序使用,否则会引起系统混乱。 100 | 101 | 102 | 2) 非特权指令——在用户态时运行的指令 103 | 104 | 一般应用程序所使用的都是非特权指令,它只能完成一般性的操作和任务,不能对系统中的硬件和软件直接进行访问,其对内存的访问范围也局限于用户空间。 105 | 106 | #### 3.3 UNIX 系统中用户态与核心态 107 | 108 | UNIX 系统把进程的执行状态分为两种: 109 | 110 | - 一种是用户态执行,表示进程正处于用户状态中执行; 111 | 112 | - 另一种是核心态执行,表示一个应用进程执行系统调用后,或 I/O 中断、时钟中断后,进程便处于核心态执行。 113 | 114 | 115 | 这两种状态的主要差别在于: 116 | 117 | - 处于用户态执行时,进程所能访问的内存空间和对象受到限制,其所占有的处理机是可被抢占的; 118 | 119 | - 而处于核心态执行中的进程,则能访问所有的内存空间和对象,且所占用的处理机是不允许被抢占的。 120 | 121 | 122 | 注: 123 | 124 | - 用户态切换到内核态的唯一途径——>中断/异常/陷入 125 | 126 | - 内核态切换到用户态的途径——>设置程序状态字 127 | 128 | 129 | 注意一条特殊的指令——陷入指令(又称为访管指令,因为内核态也被称为管理态,访管就是访问管理态)。该指令给用户提供接口,用于调用操作系统的服务。 130 | 131 | ### 感谢 132 | 133 | TODO 134 | -------------------------------------------------------------------------------- /tech/linux/select_poll_epoll.md: -------------------------------------------------------------------------------- 1 | ## select、poll、epoll 2 | 3 | ### 简介 4 | 5 | select , poll , epoll 都是 IO多路复用 的机制。I/O多路复用 就是通过一种机制,一个进程可以 6 | 监视多个描述符,一旦某个描述符就绪(一般是读就绪或者写就绪),能够通知程序进行相应的读写操作。 7 | 但 select , poll , epoll 本质上都是 同步I/O,因为它们都需要在读写事件就绪后自己负责进行读写, 8 | 也就是说这个读写过程都是阻塞的,而 异步I/O 无需自己负责进行读写,异步I/O 的实现会负责把数据从 9 | 内核拷贝到用户空间。 10 | 11 | 12 | 13 | ### 提纲 14 | 15 | #### 1. select 16 | 17 | select 函数监视的文件描述符分 3类,分别是 writefds、readfds 和 exceptfds。调用后 select函数 18 | 会阻塞,直到有描述符就绪(有数据 可读、可写、或者有 except),或者超时(timeout 指定等待时间,如果 19 | 立即返回设为 null 即可),函数返回。当 select 函数返回后,可以通过遍历 fdset,来找到就绪的描述符。 20 | 21 | select 目前几乎在所有的平台上支持,其良好跨平台支持也是它的一个有点。select 的一个缺点在于单个进程 22 | 能够监视的文件描述符存在最大限制,在 Linux 上一般为1024,可以通过修改宏定义甚至重新编译内核的方式, 23 | 提升这一限制,但是这一也会造成效率的降低。 24 | 25 | #### 2. poll 26 | 27 | 不同于 select 使用三个位图来表示三个 fdset 的方式,poll 使用一个 pollfd 的指针实现。 28 | 29 | pollfd 结构包含了要监视的 event 和发生的 event,不要再使用 “参数-值” 传递的方式。同时, 30 | pollfd 并没有最大数量限制(但是数量过大后性能也是会下降)。和 select 函数一样,poll 返回后, 31 | 需要轮询 pollfd 来获取就绪的描述符。 32 | 33 | 从上面看,select 和 poll 都需要在返回后,通过遍历文件描述符来获取已经就绪的 socket。事实上, 34 | 同时连接的大量客户端在一时刻可能只有很少的处于就绪状态,因此随着监视的描述符数量的增长,其效率 35 | 也会线性下降。 36 | 37 | #### 3. epoll 38 | 39 | epoll 是在 2.6 内核中提出的,是之前的 select 和 poll 的增强版本。相对于 select 和 poll 来说, 40 | epoll 更加灵活,没有描述符限制。epoll 使用一个文件描述符管理多个描述符,将用户关系的文件描述符的 41 | 事件存放到内核的一个事件表中,这样在用户空间和内核空间的 copy 只需一次。 42 | 43 | 题外话,由上面特性,我们可以看出: 44 | 45 | - epoll 适用于 web服务器(一旦建立连接,活跃度低) 46 | - select 适用于 游戏服务器(一旦建立连接,活跃度高) 47 | 48 | 49 | ### epoll 详细工作原理 50 | 51 | epoll是一种IO多路复用技术,可以非常高效的处理数以百万计的socket句柄,比起以前的select和poll效率高大发了。 52 | 它到底为什么可以高速处理这么多并发连接呢? 53 | 54 | C库封装的3个epoll系统调用。 55 | 56 | ```cpp 57 | int epoll_create(int size); 58 | int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event); 59 | int epoll_wait(int epfd, struct epoll_event *events,int maxevents, int timeout); 60 | ``` 61 | 62 | 使用起来很清晰,首先要调用 epoll_create 建立一个 epoll 对象,参数 size 是内核保证能够正确处理的 63 | 最大句柄数,多于这个最大树时内核可不保证效果。 64 | 65 | epoll_ctl 可以操作上面建立 epoll,例如,将刚建立的 socket 加入到 epoll 中让其监控,或者把 epoll 66 | 正在 监控的某个 socket 句柄移出 epoll,不再监控它等等。 67 | 68 | epoll_wait 在调用时,在给定的 timeout 时间内,当在监控的所有句柄中有事件发生时,就返回用户态的进程。 69 | 70 | 71 | 从上面的调用方式就可以看到 epoll 比 select/poll 的优越之处:因为后者每次调用时都要传递你所要监控的 72 | 所有 socket 给 select/poll 系统调用,这意味着需要将用户态的 socket 列表 copy 到内核态,如果以万计 73 | 的句柄会导致每次都要 copy 几十几百KB的内存到内核态,非常低效。而我们调用 epoll_wait 时就相当于以往调用 select/poll, 74 | 但是这时却不用传递 socket 句柄给内核,因为内核已经在 epoll_ctl 中拿到了要监控的句柄列表。 75 | 76 | 所以,实际上在调用 epoll_create 后,内核就已经在内核态开始准备帮你存储要监控的句柄了,每次调用 epoll_ctl 只是 77 | 在往内核的数据结构里塞入新的 socket 句柄。 78 | 79 | 在内核里,一切皆文件。所以,epoll 向内核注册了一个文件系统,用于存储上述的被监控 socket。当你调用 epoll_create时, 80 | 就会在这个虚拟的 epoll 文件系统里创建一个 file 节点。当然这个 file 不是普通文件,它只服务与 epoll。 81 | 82 | epoll 在被内核初始化时(操作系统启动),同时会开辟出 epoll 自己的内核高速 cache 区,用于安置每一个我们想 83 | 监控的 socket,这些 socket 会以红黑树的形式保存在内核 cache 里,以支持快速的查找、插入、删除。这个内核高速 84 | cache 区,就是建立连续的物理内存页,然后在之上建立 slab 层,简单地说,就是物理上分配好你想要的 size 的内存对象, 85 | 每次使用时都是使用空闲的已分配好的对象。 86 | 87 | 88 | ```cpp 89 | static int __init eventpoll_init(void) 90 | { 91 | ... ... 92 | 93 | /* Allocates slab cache used to allocate "struct epitem" items */ 94 | epi_cache = kmem_cache_create("eventpoll_epi", sizeof(struct epitem), 95 | 0, SLAB_HWCACHE_ALIGN|EPI_SLAB_DEBUG|SLAB_PANIC, 96 | NULL, NULL); 97 | 98 | /* Allocates slab cache used to allocate "struct eppoll_entry" */ 99 | pwq_cache = kmem_cache_create("eventpoll_pwq", 100 | sizeof(struct eppoll_entry), 0, 101 | EPI_SLAB_DEBUG|SLAB_PANIC, NULL, NULL); 102 | 103 | ... ... 104 | ``` 105 | 106 | epoll的高效就在于,当我们调用 epoll_ctl 往里塞入百万个句柄时,epoll_wait 仍然可以飞快的返回,并有效的将发生事件 107 | 的句柄给我们用户。这是由于我们在调用 epoll_create 时,内核除了帮我们在 epoll 文件系统里建了个 file 结点,在内核 cache 108 | 里建了个红黑树用于存储以后 epoll_ctl 传来的 socket 外,还会再建立一个 list链表,用于存储准备就绪的事件,当 epoll_wait 调用时, 109 | 仅仅观察这个 list链表 里有没有数据即可。有数据就返回,没有数据就 sleep ,等到 timeout 时间到后即使链表没数据也返回。所以, 110 | epoll_wait 非常高效。 111 | 112 | 113 | 而且,通常情况下即使我们要监控百万计的句柄,大多一次也只返回很少量的准备就绪句柄而已,所以,epoll_wait 仅需要从内核态 114 | copy 少量的句柄到用户态而已,因此相当高效。 115 | 116 | 那么,这个准备就绪 list链表 是怎么维护的呢?当我们执行 epoll_ctl 时,除了把 socket 放到 epoll文件系统 里 file 对象对应的红黑树上之外, 117 | 还会给内核中断处理程序注册一个回调函数,告诉内核,如果这个句柄的中断到了,就把它放到准备就绪 list链表 里。 118 | 所以,当一个 socket 上有数据到了,内核在把网卡上的数据 copy 到内核中后,就来把 socket 插入到准备就绪链表里了。 119 | 120 | 如此,一颗红黑树,一张准备就绪句柄链表,少量的内核 cache,就帮我们解决了大并发下的 socket 处理问题。 121 | 执行 epoll_create 时,创建了红黑树和就绪链表,执行 epoll_ctl 时,如果增加 socket 句柄,则检查在红黑树中是否存在, 122 | 存在立即返回,不存在则添加到树干上,然后向内核注册回调函数,用于当中断事件来临时向准备就绪链表中插入数据。 123 | 执行 epoll_wait 时立刻返回准备就绪链表里的数据即可。 124 | 125 | 最后看看 epoll 独有的两种模式 LT 和 ET 。无论是 LT 和 ET 模式,都适用于以上所说的流程。区别是,LT模式下, 126 | 只要一个句柄上的事件一次没有处理完,会在以后调用 epoll_wait 时次次返回这个句柄,而ET模式仅在第一次返回。 127 | 128 | 这件事怎么做到的呢?当一个 socket 句柄上有事件时,内核会把该句柄插入上面所说的准备就绪 list链表,这时我们调用 epoll_wait, 129 | 会把准备就绪的 socket 拷贝到用户态内存,然后清空准备就绪 list链表,最后,epoll_wait 干了件事,就是检查这些 socket, 130 | 如果不是ET模式(就是LT模式的句柄了),并且这些 socket 上确实有未处理的事件时,又把该句柄放回到刚刚清空的准备就绪链表了。 131 | 所以,非ET的句柄,只要它上面还有事件,epoll_wait 每次都会返回。而ET模式的句柄,除非有新中断到,即使 socket 上的事件没有处理完, 132 | 也是不会次次从 epoll_wait 返回的。 133 | 134 | 题外话: 135 | 136 | - LT(level triggered) 是缺省的工作方式,并且同时支持 block 和 no-block socket.在这种做法中,内核告诉你一个文件描述符是否就绪了, 137 | 然后你可以对这个就绪的fd进行IO操作。如果你不作任何操作,内核还是会继续通知你的,所以,这种模式编程出错误可能性要小一点。 138 | 传统的 select/poll 都是这种模型的代表。 139 | 140 | - ET (edge-triggered) 是高速工作方式,只支持 no-block socket。在这种模式下,当描述符从未就绪变为就绪时,内核通过 epoll 告诉你。 141 | 然后它会假设你知道文件描述符已经就绪,并且不会再为那个文件描述符发送更多的就绪通知,直到你做了某些操作导致那个文件描述符不再为就绪状态了, 142 | 但是请注意,如果一直不对这个 fd作IO操作(从而导致它再次变成未就绪),内核不会发送更多的通知(only once)。 143 | 144 | 145 | ## 感谢 146 | 147 | [epoll和select区别](https://blog.csdn.net/ysu108/article/details/7570571) 148 | 149 | [epoll 详细工作原理](https://blog.csdn.net/hdutigerkin/article/details/7517390) 150 | 151 | [linux 内核poll/select/epoll实现剖析](https://blog.csdn.net/lishenglong666/article/details/45536611) 152 | -------------------------------------------------------------------------------- /tech/linux/零拷贝_NIO.md: -------------------------------------------------------------------------------- 1 | ## 零拷贝 2 | 3 | ### 零拷贝简介 4 | 5 | #### 1. 简介 6 | 7 | - 网络传输持久性日志块 8 | 9 | - Java Nio channel.transforTo() 方法 10 | 11 | - Linux sendfile 系统调用 12 | 13 | #### 2. 文件传输到网络的公共数据路径 14 | 15 | - 操作系统将数据从磁盘读入到内核空间的页缓存 16 | 17 | - 应用程序将数据从内核空间读入到用户空间页缓存中 18 | 19 | - 应用程序将数据写回到内核空间到 socket 缓存中 20 | 21 | - 操作系统将数据从 socket缓冲区 复制到 网卡缓冲区,以便将数据经网络发出 22 | 23 | #### 3. 零拷贝过程 24 | 25 | - 操作系统将数据从磁盘读入到内核空间的页缓存 26 | 27 | - 将数据的位置和长度的信息的描述符增加至内核空间(socket 缓冲区) 28 | 29 | - 操作系统将数据从内核拷贝到网卡缓冲区,以便将数据经网络发出 30 | 31 | ![Alt Text](./images/文件传输到网络的公共数据路径演变.png) 32 | 33 | ## 感谢 34 | 35 | ... -------------------------------------------------------------------------------- /tech/mysql/Mysql大表处理_pending.md: -------------------------------------------------------------------------------- 1 | # 数据库索引优化 2 | 3 | ## MySQL支持的索引类型 4 | 5 | 1. [BTree索引](#1B-tree索引) 6 | 2. [Hash索引](#2Hash索引) 7 | 8 | 9 | ### 1.B-tree索引 10 | 11 | #### 1.1 B-tree索引的特点(顺序存储) 12 | 13 | - B-tree 索引能够加快数据的查询速度 14 | - B-tree 索引更适合进行范围查找(顺序存储) 15 | 16 | #### 1.2 在什么情况下可以用到B树索引 17 | 18 | - 全职匹配的查询 19 | - order_sn = '9876432119900' 20 | - 匹配最左前缀的查询 21 | - 匹配列前缀查询 22 | - order_sn like '9876%' 23 | - 匹配范围值的查询 24 | - order_sn > '9876432119900' and order_sn < '9876432119999' 25 | - 精确匹配左前列并范围匹配另外一列 26 | - 只访问索引的查询 27 | 28 | #### 1.3 Btree索引的使用限制 29 | 30 | - 如果不是按照索引最左烈开始查找,则无法使用索引 31 | - 使用索引时不能跳过索引中的列 32 | - not in 和 <> 操作无法使用索引 33 | - 如果查询中有某个列的范围查询,则其右边所有列都无法使用索引 34 | 35 | ### 2.Hash索引 36 | 37 | #### 2.1 Hash索引的特点 38 | - Hash索引时基于Hash表实现的,只有查询条件精确匹配Hash索引中的所有列时,在能够使用到hash索引。 39 | - 对于Hash索引中的所有列,存储引擎都会为每一行计算一个Hash码,Hash索引中存储的就是Hash码。 40 | 41 | #### 2.2 Hash索引的限制 42 | - Hash索引必须进行二次查找 43 | - Hash索引无法用于排序 44 | - Hash索引不支持部分索引查找,也不支持范围查找 45 | - Hash索引中Hash码的计算可能存在Hash冲突 46 | 47 | ### 3.为什么要使用索引 48 | 49 | - 索引大大减少了存储引擎需要扫描的数据量 50 | - 索引可以帮助我们进行排序以避免使用临时表(避免自排临时表) 51 | - 索引可以把随机I/O变为顺序I/O 52 | - 注:innodb索引最大767字节,myisam索引最大1000字节 53 | 54 | ### 4. 索引是不是越多越好 55 | 56 | - 索引会增加写操作的成本 57 | - 太多的索引会增加查询优化器的选择时间 58 | 59 | ### 5. 查询优化策略 60 | 61 | #### 5.1 索引列上不能使用表达式或函数 62 | 63 | select ... from product where to_days(out_date)-to_days(current_date)<=30 64 | 优化后 65 | select ... from product where out_date <= date_add(current_date,interval 30 day) 66 | 67 | #### 5.2 前缀索引和索引列的选择性 68 | create index index_name on table(col_name(n)); 69 | 索引的选择性是不重复的所有制和表的记录的比值 70 | mysql5.0之前,每一个查询只能使用到一个列上的索引。 71 | 72 | 73 | #### 5.3 联合索引 74 | 如何选择索引列的顺序(优先级从上往下递减) 75 | (1)经常会被使用到的列优先 76 | (2)选择性高的列优先 77 | (3)宽度小的列优先 78 | 79 | #### 5.4 覆盖索引 80 | (1)优点 81 | ①.可以优化缓存,减少磁盘IO操作 82 | ②.可以减少随机IO,变随机IO操作为顺序IO操作 83 | ③.可以避免对Innodb主键索引的二次查询 84 | ④.可以避免MyISAM表进行系统调用 85 | (2)无法使用覆盖索引的情况 86 | ①.存储引擎不支持覆盖索引 87 | ②.查询使用了太多的列 88 | ③.使用了双%号的like查询 89 | 90 | ### 6.使用索引来优化查询 91 | (1)使用索引扫描来优化排序 92 | ①.索引的列顺序和Order by子句的顺序完全一致 93 | ②.索引中索引列的方向(升序,降序)和Order By 子句完全一致 94 | ③.Order By中的字段全部在关联表中的第一张表中 95 | (2)模拟Hash索引优化查询 96 | ①.只能处理键值的全值匹配查找 97 | ③.所使用的Hash函数决定着索引键的大小 98 | (3)利用索引优化锁 99 | ①.索引可以减少锁定的行数 100 | ③.索引可以加快处理速度,同时也加快了所的释放 101 | 102 | ### 7.索引的维护和优化 103 | (1)删除重复和冗余的索引 104 | ①.primary key(id), unique_id key(id), index(id) 主键和唯一主键都会建立索引不需要再建立额外索引 105 | ②.index(a), index(a,b) 联合索引:index(a,b)实则也是与index(a)冗余 106 | ③.primary key(id), index(a,b) 同② 107 | 注:当然,当联合索引很大时,可以建立一个冗余索引。比如:index(a,b,c,d,..) 此时我们可以适当建立 index(a) 108 | ③. pt-duplicate-key-checker h=127.0.0.1,使用工具查看重复和冗余索引(pt-duplicate-key-checker这款工具也是percona-toolkit中一款非常适用的工具) 109 | (2)查找未被使用过的索引 110 | select object_schema,object_name,index_name,b.`TABLE_ROWS` FROM performance_schema.table_io_waits_summary_by_index_usage a JOIN information_schema.tables b ON a.`OBJECT_SCHEMA`=b.`TABLE_SCHEMA` AND a.`OBJECT_NAME`=b.`TABLE_NAME` WHERE index_name IS NOT NULL and count_star=0 ORDER BY object_schema,object_name; 111 | (3)更新索引统计信息及减少索引碎片 112 | analyze table table_name 113 | innodb是随机,并不是全盘扫描,只做评估,效率高,但不准确 114 | myisam是全盘扫描,准确,但锁表时间长,效率低 115 | 116 | 定期维护索引碎片 117 | 定期维护表碎片 optimize table table_name (注:使用不当会导致锁表) 118 | -------------------------------------------------------------------------------- /tech/mysql/images/2_索引管理_3_3_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/tech/mysql/images/2_索引管理_3_3_1.png -------------------------------------------------------------------------------- /tech/mysql/images/3_锁管理_MySQL部分源码_4_3_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/tech/mysql/images/3_锁管理_MySQL部分源码_4_3_2.png -------------------------------------------------------------------------------- /tech/mysql/images/3_锁管理_RR_RC级别下的InnoDB的非阻塞读实现_4_3_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/tech/mysql/images/3_锁管理_RR_RC级别下的InnoDB的非阻塞读实现_4_3_1.png -------------------------------------------------------------------------------- /tech/mysql/images/3_锁管理_对主键索引或者唯一索引是否会用Gap锁_5_2_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/tech/mysql/images/3_锁管理_对主键索引或者唯一索引是否会用Gap锁_5_2_1.png -------------------------------------------------------------------------------- /tech/mysql/images/3_锁管理_对主键索引或者唯一索引是否会用Gap锁_5_2_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/tech/mysql/images/3_锁管理_对主键索引或者唯一索引是否会用Gap锁_5_2_2.png -------------------------------------------------------------------------------- /tech/mysql/images/3_锁管理_对主键索引或者唯一索引是否会用Gap锁_不走索引_5_2_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/tech/mysql/images/3_锁管理_对主键索引或者唯一索引是否会用Gap锁_不走索引_5_2_3.png -------------------------------------------------------------------------------- /tech/mysql/images/3_锁管理_对主键索引或者唯一索引是否会用Gap锁_插入失败_5_2_5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/tech/mysql/images/3_锁管理_对主键索引或者唯一索引是否会用Gap锁_插入失败_5_2_5.png -------------------------------------------------------------------------------- /tech/mysql/images/3_锁管理_对主键索引或者唯一索引是否会用Gap锁_插入成功_5_2_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/tech/mysql/images/3_锁管理_对主键索引或者唯一索引是否会用Gap锁_插入成功_5_2_4.png -------------------------------------------------------------------------------- /tech/mysql/images/3_锁管理_当前读和快照读_4_2_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/tech/mysql/images/3_锁管理_当前读和快照读_4_2_1.png -------------------------------------------------------------------------------- /tech/mysql/数据库——1_数据库架构.md: -------------------------------------------------------------------------------- 1 | # 一、数据库架构 2 | 3 | ## 一个面试题引发的"血案",如何设计一个关系型数据库? 4 | 5 | ----- 6 | 7 | ### 开始设计我们的 RDBMS 8 | 9 | #### 1. RDBMS 即关系数据库管理系统(Relational Database Management System) 10 | 11 | 1.1 RDBMS 应当包括 **程序实例** 和 **存储系统(文件系统)** 12 | 13 | ``` 14 | RDBMS 15 | +----------------------------------+ 16 | | 程 序 实 例 | 17 | | | 18 | | | 19 | +----------------------------------+ 20 | | 存 储 ( 文 件 系 统 ) | 21 | | | 22 | | | 23 | +----------------------------------+ 24 | ``` 25 | 26 | 27 | #### 2. **程序实例** 和 **存储系统(文件系统)** 28 | 29 | 2.1 **存储系统(文件系统)** 应当存储在 HDD / SSD / ...,如下图 30 | 31 | ``` 32 | RDBMS 33 | +----------------------------------+ 34 | | 程 序 实 例 | 35 | | | 36 | | | 37 | +----------------------------------+ 38 | | 存 储 ( 文 件 系 统 ) | 39 | | HDD / SSD / ... | 40 | | | 41 | +----------------------------------+ 42 | ``` 43 | 44 | 45 | 2.2 **程序实例** 应当包括:存储管理、缓存机制、SQL解析、日志管理、权限划分、容灾机制、索引管理、锁管理,如下图 46 | 47 | 48 | ``` 49 | RDBMS 50 | +---------------------------------------------------+ 51 | | 程 序 实 例 | 52 | | | 53 | | 存 储 管 理 缓 存 机 制 SQL 解 析 日 志 管 理 | 54 | | | 55 | | 权 限 划 分 容 灾 机 制 索 引 管 理 锁 管 理 | 56 | | | 57 | +---------------------------------------------------+ 58 | | 存 储 ( 文 件 系 统 ) | 59 | | | 60 | | | 61 | | HDD / SSD / ... | 62 | | | 63 | +---------------------------------------------------+ 64 | ``` 65 | 66 | #### 3. **程序实例** 67 | 68 | 3.1 作为开发者,我们将重点研究,其中两个模块: 69 | - 索引管理 70 | 71 | - 锁管理 72 | 73 | 3.2 索引管理 74 | 75 | 1. 在研究索引管理之前,我们先提出几个问题 76 | - 为什么要使用索引? 77 | - 什么样的信息能成为索引? 78 | - 索引的数据结构? 79 | - 密集索引和稀疏索引的区别? 80 | 2. 衍生出来的问题,以mysql为例 81 | - 如何定位并优化慢查询 Sql? 82 | - 联合索引的最左匹配原则的成因? 83 | - 索引是建立的越多越好吗? 84 | 85 | 3.3 锁管理 86 | 87 | 1. 在研究索引管理之前,我们当然也先提出几个问题 88 | - MyISAM 与 InnoDB 关于锁方面的区别是什么? 89 | - 数据库的四大特性? 90 | - 事务隔离级别以及各级别下的并发访问问题? 91 | - InnoDB可重复读隔离级别下如何避免幻读? 92 | - RC、RR级别下的InnoDB的非阻塞度如何实现? 93 | 94 | 3.4 传送门 95 | 96 | 1. 带着以上问题,我们开启数据库探索之旅,进入我的另外两篇文章:)。 97 | 98 | - [数据库 —— 索引管理](./数据库——2_索引管理.md) 99 | 100 | - [数据库 —— 锁管理](./数据库——3_锁管理.md) 101 | 102 | 103 | 104 | ## 感谢 105 | 106 | [xiangzepro](https://www.imooc.com/t/4264265) 107 | 108 | [MySQL 官方文档](https://dev.mysql.com/doc/refman/8.0/en/innodb-locking.html) 109 | -------------------------------------------------------------------------------- /tech/mysql/数据库——2_索引管理.md: -------------------------------------------------------------------------------- 1 | # 2. 索引管理 2 | 3 | ### 索引管理 4 | 5 | 6 | #### 1.提出问题。 7 | 8 | 1.1 问题回顾与总结 9 | - 为什么要使用索引? 10 | - 什么样的信息能成为索引? 11 | - 索引的数据结构? 12 | - 密集索引和稀疏索引的区别? 13 | 14 | 1.2 衍生出来的问题,以mysql为例 15 | - 如何定位并优化慢查询 Sql? 16 | - 联合索引的最左匹配原则的成因? 17 | - 索引是建立的越多越好吗? 18 | 19 | #### 2. 寻找答案 20 | 21 | 2.1 问题回顾与总结 22 | - 为什么要使用索引? 23 | - 快速查询数据 24 | - 什么样的信息能成为索引? 25 | - 主键、唯一键以及普通键等 26 | - 索引的数据结构? 27 | - 生成索引,建立 二叉查找树 进行二分查找 28 | - 生成索引,建立 B-Tree 结构进行查找 29 | - 生成索引,建立 B+-Tree 结构进行查找 30 | - 生成索引,建立 Hash 结构进行查找 31 | - 密集索引和稀疏索引的区别? 32 | - 密集索引文件中的每个搜索码值都对应一个索引值 33 | - 稀疏索引文件只为索引码的某些值建立索引项 34 | 35 | 2.2 衍生出来的问题,以mysql为例 36 | - 如何定位并优化慢查询 Sql? 37 | 1. 根据日志定位慢查询 sql 38 | 2. 使用 explain 等工具分析 sql 39 | 3. 修改 sql 或者尽量让 sql 走索引 40 | 41 | 42 | #### 3. 实际操作 43 | 44 | 3.1 mysql 日志 45 | 46 | 3.1.1 查看慢查询相关变量 47 | 48 | ```sql 49 | show variables like '%query%'; 50 | ``` 51 | 52 | 结果如下(其余行暂时忽略): 53 | 54 | | Variable_name | Value | 55 | |-------------------|--------------------------------| 56 | |long_query_time | 10.000000 | 57 | |slow_query_log | OFF | 58 | |slow_query_log_file|/usr/local/xxx/mysql/...slow.log| 59 | 60 | 需要关注的参数有:**long_query_time** 、**slow_query_log** 、 **slow_query_log_file** 61 | 62 | 63 | 3.1.2 查看当前慢查询数 64 | 65 | ```sql 66 | show status like '%slow_queries%'; 67 | ``` 68 | 69 | 将会出现 slow_queries 字段,表示当前存在的慢查询个数。 70 | 71 | 3.1.3 打开慢查询日志 72 | 73 | ```sql 74 | set global slow_query_log = on; 75 | ``` 76 | 77 | 3.1.4 设置慢查询最长时间(默认:10 s) 78 | 79 | 我们修改为 1s 80 | ```sql 81 | set global long_query_time = 1; 82 | ``` 83 | 84 | 再次查看,我们将发现各个参数已被修改 85 | 86 | ```sql 87 | show variables like '%query%'; 88 | ``` 89 | 90 | 91 | 结果如下(其余行暂时忽略): 92 | 93 | | Variable_name | Value | 94 | |-------------------|--------------------------------| 95 | |long_query_time | 1.000000 | 96 | |slow_query_log | ON | 97 | |slow_query_log_file|/usr/local/xxx/mysql/...slow.log| 98 | 99 | 100 | **注意**: 101 | 102 | - 以上所有设置,都是在本次会话有效,当退出重连时,参数设置将失效,可以通过修改 MySQL 配置文件,保证改动重启后依然有效。 103 | 104 | - DDL 数据库定义语句,不会进入慢查询 105 | 106 | - DML 数据库修改语句,才会进入慢查询 107 | 108 | 3.2 使用 explain 等工具分析 sql 109 | 110 | - 通过 **slow_query_log_file** 文件,查看慢查询日志,找到慢sql。 111 | 112 | - 使用 explain 关键字段 对 sql分析。 113 | - type 字段 114 | 115 | 连接类型。有多种类型,**重要且困难**。 116 | 117 | 性能由高到低依次为:system > const > eq_ref > ref > fulltext > ref_or_null_index_merge > unique_subquery > index_subquery > range > **index** > **all** 118 | 119 | 其中 index 和 all 都是扫描全表 120 | 121 | | type 项 | 说明 | 122 | |-------------------|--------------------------------| 123 | | id | 理解为,SQL执行的顺序的标识,SQL从大到小的执行 | 124 | | all | 对于每个来自于先前的表的行组合,进行完整的表扫描。如果表是第一个没标记const的表,这通常不好,并且通常在它情况下很差。通常可以增加更多的索引而不要使用ALL,使得行能基于前面的表中的常数值或列值被检索出。 | 125 | | index | 该联接类型与ALL相同,除了只有索引树被扫描。这通常比ALL快,因为索引文件通常比数据文件小。(也就是说虽然all和Index都是读全表,但index是从索引中读取的,而all是从硬盘中读的) | 126 | 127 | - extra 字段 128 | 129 | 该列包含MySQL解决查询的详细信息。 130 | 131 | | extra 项 | 说明 | 132 | |-------------------|--------------------------------| 133 | |Using filesort | 表示 MySQL 会对结果使用一个外部索引排序,而不是从表里按索引次序读到相关内容。可能在内存或者磁盘上进行排序。MySQL 中无法利用索引完成的排序操作称为"文件排序" | 134 | |Using temporary | 表示 MySQL 在对查询结果排序时使用临时表。常见于 order by 和 分组查询 group by。 | 135 | 136 | 3.3 联合索引的最左匹配原则的成因 137 | 138 | - 最左前缀匹配原则,非常重要的原则,mysql 会一直向右匹配直到遇到范围查询(>、<、between、like)就停止匹配 139 | 140 | 比如 ```a = 3 and b = 4 and c > 5 and d = 6``` 如果建立 (a,b,c,d) 顺序的索引,d 是用不到索引的,如果建立 (a,b,d,c) 的索引则都可以用到 a,b,d 的顺序可以任意调整 141 | 142 | - = 和 in 可以乱序,比如 ```a = 1 and b = 2 and c = 3``` 建立 (a,b,c) 索引可以任意顺序, mysql 的查询优化器会帮你优化成索引可以是别的形式 143 | 144 | - 下图是大致描述了,联合索引的最左匹配原则的成因 145 | 146 | ![Alt text](./images/2_索引管理_3_3_1.png) 147 | 148 | 149 | 3.4 索引是建立得越多越好吗 150 | 151 | - 数据量小的表不需要建立索引,建立会增加额外的索引开销 152 | 153 | - 数据变更需要维护索引,因此更多的索引意味着更多的维护成本 154 | 155 | - 更多的索引意味着要需要更多的空间 156 | 157 | ## 感谢 158 | 159 | [xiangzepro](https://www.imooc.com/t/4264265) 160 | 161 | [MySQL 官方文档](https://dev.mysql.com/doc/refman/8.0/en/innodb-locking.html) 162 | -------------------------------------------------------------------------------- /tech/mysql/数据库优化——索引优化.md: -------------------------------------------------------------------------------- 1 | # 数据库索引优化 2 | 3 | ## MySQL支持的索引类型 4 | 5 | 1. [BTree索引](#1B-tree索引) 6 | 2. [Hash索引](#2Hash索引) 7 | 8 | 9 | ### 1.B-tree索引 10 | 11 | #### 1.1 B-tree索引的特点(顺序存储) 12 | 13 | - B-tree 索引能够加快数据的查询速度 14 | - B-tree 索引更适合进行范围查找(顺序存储) 15 | 16 | #### 1.2 在什么情况下可以用到B树索引 17 | 18 | - 全职匹配的查询 19 | - order_sn = '9876432119900' 20 | - 匹配最左前缀的查询 21 | - 匹配列前缀查询 22 | - order_sn like '9876%' 23 | - 匹配范围值的查询 24 | - order_sn > '9876432119900' and order_sn < '9876432119999' 25 | - 精确匹配左前列并范围匹配另外一列 26 | - 只访问索引的查询 27 | 28 | #### 1.3 Btree索引的使用限制 29 | 30 | - 如果不是按照索引最左烈开始查找,则无法使用索引 31 | - 使用索引时不能跳过索引中的列 32 | - not in 和 <> 操作无法使用索引 33 | - 如果查询中有某个列的范围查询,则其右边所有列都无法使用索引 34 | 35 | ### 2.Hash索引 36 | 37 | #### 2.1 Hash索引的特点 38 | - Hash索引时基于Hash表实现的,只有查询条件精确匹配Hash索引中的所有列时,在能够使用到hash索引。 39 | - 对于Hash索引中的所有列,存储引擎都会为每一行计算一个Hash码,Hash索引中存储的就是Hash码。 40 | 41 | #### 2.2 Hash索引的限制 42 | - Hash索引必须进行二次查找 43 | - Hash索引无法用于排序 44 | - Hash索引不支持部分索引查找,也不支持范围查找 45 | - Hash索引中Hash码的计算可能存在Hash冲突 46 | 47 | ### 3.为什么要使用索引 48 | 49 | - 索引大大减少了存储引擎需要扫描的数据量 50 | - 索引可以帮助我们进行排序以避免使用临时表(避免自排临时表) 51 | - 索引可以把随机I/O变为顺序I/O 52 | - 注:innodb索引最大767字节,myisam索引最大1000字节 53 | 54 | ### 4. 索引是不是越多越好 55 | 56 | - 索引会增加写操作的成本 57 | - 太多的索引会增加查询优化器的选择时间 58 | 59 | ### 5. 查询优化策略 60 | 61 | #### 5.1 索引列上不能使用表达式或函数 62 | 63 | select ... from product where to_days(out_date)-to_days(current_date)<=30 64 | 优化后 65 | select ... from product where out_date <= date_add(current_date,interval 30 day) 66 | 67 | #### 5.2 前缀索引和索引列的选择性 68 | create index index_name on table(col_name(n)); 69 | 索引的选择性是不重复的所有制和表的记录的比值 70 | mysql5.0之前,每一个查询只能使用到一个列上的索引。 71 | 72 | 73 | #### 5.3 联合索引 74 | 如何选择索引列的顺序(优先级从上往下递减) 75 | (1)经常会被使用到的列优先 76 | (2)选择性高的列优先 77 | (3)宽度小的列优先 78 | 79 | #### 5.4 覆盖索引 80 | (1)优点 81 | ①.可以优化缓存,减少磁盘IO操作 82 | ②.可以减少随机IO,变随机IO操作为顺序IO操作 83 | ③.可以避免对Innodb主键索引的二次查询 84 | ④.可以避免MyISAM表进行系统调用 85 | (2)无法使用覆盖索引的情况 86 | ①.存储引擎不支持覆盖索引 87 | ②.查询使用了太多的列 88 | ③.使用了双%号的like查询 89 | 90 | ### 6.使用索引来优化查询 91 | (1)使用索引扫描来优化排序 92 | ①.索引的列顺序和Order by子句的顺序完全一致 93 | ②.索引中索引列的方向(升序,降序)和Order By 子句完全一致 94 | ③.Order By中的字段全部在关联表中的第一张表中 95 | (2)模拟Hash索引优化查询 96 | ①.只能处理键值的全值匹配查找 97 | ③.所使用的Hash函数决定着索引键的大小 98 | (3)利用索引优化锁 99 | ①.索引可以减少锁定的行数 100 | ③.索引可以加快处理速度,同时也加快了所的释放 101 | 102 | ### 7.索引的维护和优化 103 | (1)删除重复和冗余的索引 104 | ①.primary key(id), unique_id key(id), index(id) 主键和唯一主键都会建立索引不需要再建立额外索引 105 | ②.index(a), index(a,b) 联合索引:index(a,b)实则也是与index(a)冗余 106 | ③.primary key(id), index(a,b) 同② 107 | 注:当然,当联合索引很大时,可以建立一个冗余索引。比如:index(a,b,c,d,..) 此时我们可以适当建立 index(a) 108 | ③. pt-duplicate-key-checker h=127.0.0.1,使用工具查看重复和冗余索引(pt-duplicate-key-checker这款工具也是percona-toolkit中一款非常适用的工具) 109 | (2)查找未被使用过的索引 110 | select object_schema,object_name,index_name,b.`TABLE_ROWS` FROM performance_schema.table_io_waits_summary_by_index_usage a JOIN information_schema.tables b ON a.`OBJECT_SCHEMA`=b.`TABLE_SCHEMA` AND a.`OBJECT_NAME`=b.`TABLE_NAME` WHERE index_name IS NOT NULL and count_star=0 ORDER BY object_schema,object_name; 111 | (3)更新索引统计信息及减少索引碎片 112 | analyze table table_name 113 | innodb是随机,并不是全盘扫描,只做评估,效率高,但不准确 114 | myisam是全盘扫描,准确,但锁表时间长,效率低 115 | 116 | 定期维护索引碎片 117 | 定期维护表碎片 optimize table table_name (注:使用不当会导致锁表) 118 | -------------------------------------------------------------------------------- /tech/network/http与https.md: -------------------------------------------------------------------------------- 1 | ## HTTP 2 | 3 | ### 1. HTTP 协议发展历史 4 | 5 | #### 1.1 HTTP/0.9 6 | 7 | - 只有一个命令 GET 8 | 9 | - 没有 HEADER 等描述数据的信息 10 | 11 | - 服务器发送完毕,就关闭 TCP 连接 12 | 13 | #### 1.2 HTTP/1.0 14 | 15 | - 增加了很多命令 16 | 17 | - 增加 status code 和 header 18 | 19 | - 多字符集支持、多部分发送、权限、缓存等 20 | 21 | 22 | #### 1.4 HTTP/1.1 23 | 24 | - 持久连接 25 | 26 | - pipeline 27 | 28 | - 增加 host 和 其他一些命令 29 | 30 | 31 | #### 1.5 HTTP/2.0 32 | 33 | - 所有数据以二进制传输 34 | 35 | - 同一个连接里面发送多个请求不再需要按照顺序来 36 | 37 | - 头信息压缩以及推送等提高效率的功能 38 | 39 | #### 2. HTTP 相关知识 40 | 41 | #### 2.1 GET 请求 和 POST 请求的区别 42 | 43 | | 三个层面 | GET | POST | 44 | |---|---|---| 45 | |HTTP报文层面| GET 将请求信息放在URL | POST 将请求信息放在报文体中 | 46 | |数据层面| GET 符合幂等性和安全性| POST 不符合| 47 | |其他层面| GET 可以被缓存、被存储| POST 不行| 48 | 49 | #### 2.2 Cookie 和 Session 的介绍及其区别 50 | 51 | 2.2.1 Cookie 简介 52 | 53 | - 是否服务器发给客户端的特殊信息,以文本的形式存放在客户端 54 | 55 | - 客户端再次请求的时候,会把 Cookie 回发 56 | 57 | - 服务器收到后,会解析 Cookie 生成与客户端相对应的内容 58 | 59 | 2.2.2 Cookie 的设置以及发送过程 60 | 61 | - 客户端 -> 服务端:HTTP Request 62 | 63 | - 客户端 <- 服务端:HTTP Response + Set-Cookie 64 | 65 | - 客户端 -> 服务端:HTTP Request + Cookie 66 | 67 | - 客户端 <- 服务端:HTTP Response 68 | 69 | 2.2.3 Session 简介 70 | 71 | - 服务端的机制,在服务器上保存的信息 72 | 73 | - 解析客户端请求并操作 session id,按需保存状态信息 74 | 75 | 2.2.4 Session 的实现方式 76 | 77 | - 使用 Cookie 来实现 78 | 79 | - 使用 URL 回写来实现 80 | 81 | Cookie 实现,如下: 82 | 83 | - 客户端 -> 服务端:HTTP Request 84 | 85 | - 客户端 <- 服务端:HTTP Response + Set-Cookie: JSESSIONID=xxxxx 86 | 87 | - 客户端 -> 服务端:HTTP Request + Cookie: JSESSIONID=xxxxx 88 | 89 | - 客户端 <- 服务端:HTTP Response 90 | 91 | 2.2.5 Cookie 和 Session 的区别 92 | 93 | - Cookie 数据存放在客户的浏览器上,Session 数据放在服务器上 94 | 95 | - Session 相对于 Cookie 更安全 96 | 97 | - 若考虑减轻服务器负担,应当使用 Cookie 98 | 99 | 100 | 101 | ### 3. URI、URL 和 URN 102 | 103 | #### 3.1 URI 104 | 105 | - Uniform Resource Identifier / 统一资源标识符 106 | 107 | - 用来唯一标识互联网上的信息资源 108 | 109 | - 包括 URL 和 URN 110 | 111 | 112 | #### 3.2 URL 113 | 114 | - Uniform Resource Locator / 统一资源定位器 115 | 116 | - http://user:pass@host.com:80/path?query=string#hash 117 | 118 | - 此类格式都叫做 URL,比如 ftp协议 119 | 120 | 121 | 122 | #### 3.3 URN 123 | 124 | - 永久统一资源定位符 125 | 126 | - 在资源移动之后还能被找到 127 | 128 | - 目前还没有非常成熟的使用方案 129 | 130 | 131 | 132 | ### 4. HTTP 和 HTTPS 的区别 133 | 134 | #### 4.1 HTTPS 简介 135 | ``` 136 | HTTP HTTPS 137 | 138 | +------------+ +-----------+ 139 | | | | HTTP | 140 | | HTTP | | | 141 | | | +-----------+ 142 | +------------+ |SSL or TLS | 143 | | | | | 144 | | TCP | +-----------+ 145 | | | | TCP | 146 | +------------+ | | 147 | | | +-----------+ 148 | | IP | | IP | 149 | | | | | 150 | +------------+ +-----------+ 151 | 152 | ``` 153 | 154 | 4.1.1 SSL(Security Sockets Layer,安全套接层) 155 | 156 | - 为网络通信提高安全及数据完整性的一种安全协议 157 | 158 | - 是操作系统对外的API, SSL 3.0 后更名为 TLS 159 | 160 | - 采用身份验证和数据加密保证 网络通信的安全 和 数据的完整性 161 | 162 | 4.1.2 加密的方式 163 | 164 | - 对称加密:加密和解密都使用同一个密钥 165 | 166 | - 非对称加密:加密使用的密钥和解密使用的密钥是不相同的 167 | 168 | - 哈希算法:将任意长度的信息转换为固定长度的值,算法不可逆 169 | 170 | - 数字签名:证明某个消息或者文件是某人 发出 / 认同的 171 | 172 | 4.1.3 HTTPS 数据传输流程 173 | 174 | - 浏览器将支持的加密算法信息发送诶服务器 175 | 176 | - 服务器选择一套浏览器支持的加密算法,以证书的形式回发浏览器 177 | 178 | - 浏览器验证证书合法性,并结合证书公钥加密信息发送给服务器 179 | 180 | - 服务器使用私钥解密信息,验证哈希,加密响应消息回发浏览器 181 | 182 | - 浏览器解密响应消息,并对消息进行验证,之后进行加密交互数据 183 | 184 | ![Alt Text](./images/HTTPS数据传输过程.png) 185 | 186 | #### 4.2 HTTP 和 HTTPS 的区别 187 | 188 | 4.2.1 对比 HTTP 189 | 190 | - HTTPS 需要到 CA 申请证书,HTTP 不需要 191 | 192 | - HTTPS 密文传输,HTTP 明文传输 193 | 194 | - 连接方式不同,HTTPS 默认使用 443 端口,HTTP 使用 80 端口 195 | 196 | - HTTPS = HTTP + 加密 + 认证 + 完整性保护,较 HTTP 安全 197 | 198 | #### 4.3 HTTPS 是否真的很安全 199 | 200 | 4.3.1 未必 201 | 202 | - 浏览器默认填充 http://,请求需要进行跳转,有被劫持的风险 203 | 204 | - 可以使用 HSTS(HTTP Strict Transport Security)优化 205 | 206 | ## 感谢 207 | 208 | ... -------------------------------------------------------------------------------- /tech/network/images/HTTPS数据传输过程.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/tech/network/images/HTTPS数据传输过程.png -------------------------------------------------------------------------------- /tech/nginx/nginx使用之总体简介.md: -------------------------------------------------------------------------------- 1 | ## Nginx介绍 2 | 3 | #### Nginx 4 | 5 | - [http://nginx.org/](http://nginx.org/) ,C10k 6 | - Igor Sysoev,Rambler Media; 7 | - engine X:nginx 8 | - tengine,OpenResty 9 | 10 | 11 | ### 1.Nginx的特性 12 | 13 | - 模块化设计、较好扩展性 14 | - 高可靠性 15 | - master/worker 16 | - 支持热部署 17 | - 不停机-更新配置文件、更换日志、更新服务器程序版本;(平滑升级/迁移) 18 | - 低内存消耗 19 | - 10000个keep-alive连接模式下的非活动连接仅要好2.5M内存;event-driven,aio,mmap; 20 | 21 | ### 2.功能 22 | 23 | - 基本功能 24 | - 静态资源的web服务器; 25 | - http协议的反响代理服务; 26 | - pop3,smpt,imap4等邮件协议的反向代理; 27 | - 能缓存打开的文件(元数据)、支持FastCGI(php-fpm),uWSGI(Python Web Framwork)等协议 28 | - 模块化(非DSO机制),过滤器zip,SSI,SSL; 29 | - Web服务相关的功能 30 | - 虚拟主机(server)、keepalive、访问日志(支持基于日志缓存提高其性能)、url rewrite、路径别名、基于IP及用户的访问控制、支持速率限制及并发数限制…… 31 | 32 | ### 3.Nginx的基本架构: 33 | 34 | master/worker: 35 | 36 | - 一个master进程,可生成一个或多个进程; 37 | - 事件驱动:epoll(Linux),kqueue(FreeBSD),/dev/poll(Solarls) 38 | - 消息通知:select,poll,rt signals 39 | - 支持sendfile,sendfile64 40 | - 支持AIO,mmap 41 | - master:加载配置文件,管理worker进程、平滑升级,... 42 | - worker:http服务、http代理,fastcgi代理,... 43 | 44 | ### 4.模块类型: 45 | 46 | - 核心模块:core module 47 | - Standard HTTP modules 48 | - Optional HTTP modules 49 | - 3rd party modules 50 | 51 | ### 5.用来做什么? 52 | 53 | - 静态资源的web服务器; 54 | - http服务器的反向代理; 55 | - 等等 56 | 57 | -------------------------------------------------------------------------------- /tech/nginx/nginx使用之配置文件的组成及主配置段的指令之一.md: -------------------------------------------------------------------------------- 1 | # Nginx使用之配置文件解析 2 | --- 3 | > 配置文件的组成、主配置段的指令 4 | 5 | 6 | 7 | 1. [配置文件的组成部分](#1配置文件的组成部分) 8 | - 1.1.[主配置文件](#11-主配置文件nginxconf) 9 | - 1.2.[fastcgi的配置文件](#12-fastcgi的配置文件) 10 | 2. [配置命令](#2配置指令必须以分号结尾) 11 | - 2.1 [指令格式](#21-指令格式) 12 | - 2.2 [支持使用变量](#22-支持使用变量) 13 | 3. [.配置文件组织结构](#3配置文件组织结构) 14 | - 3.1[http配置段](#31-http配置段) 15 | - 3.2[main配置段](#32-main配置段) 16 | 17 | --- 18 | 19 | ## 1.配置文件的组成部分 20 | - nginx.conf 21 | - mine.type 22 | - fastcgi_params 23 | - proxy.conf 24 | - site.conf 25 | 26 | --- 27 | 28 | ### 1.1 主配置文件:nginx.conf 29 | 30 | - conf.d/\*.conf 31 | - include conf.d/\*.conf (include host/\*.conf) 32 | - /etc/nginx/conf.d/\*.conf 33 | 34 | ### 1.2 fastcgi的配置文件 35 | 36 | - fastcgi_params 37 | - uwsgi_params 38 | 39 | --- 40 | 41 | ## 2.配置指令(必须以分号结尾) 42 | 43 | ### 2.1 指令格式 44 | 45 | directive value1 (value2...); 46 | 47 | ### 2.2 支持使用变量 48 | - 内置变量:由模块引入; 49 | - 自定义变量: set variable value; 50 | - 引用变量: $variable 51 | 52 | ## 3.配置文件组织结构 53 | 54 | 55 |
 56 | #main block
 57 | 	event{
 58 | 	  …               
 59 | 	}
 60 | 	http{
 61 | 	  … 
 62 | 	}
 63 | 
64 | 65 | --- 66 | 67 | ### 3.1 http配置段 68 |
 69 | 	http{
 70 | 	    …
 71 | 	   (upstream{
 72 | 	      …  
 73 | 	   }) #(定义一个负载均衡器的容器的,反向代理,可不写)
 74 | 	   server{
 75 | 	      server_name    
 76 | 	         root
 77 | 	         alias
 78 | 	         location /uri/{
 79 | 				
 80 | 	         }(location可以出现多个,映射机制不同于alias)…
 81 | 	
 82 | 	    }
 83 | 	    server{
 84 | 	          …
 85 | 	    }
 86 | 	}
 87 | 
88 | ### 3.2 main配置段 89 |
 90 | 类别:
 91 |  1.正常运行必备的配置;
 92 |  2.优化性能相关的配置;
 93 |  3.用于调试,定位问题的配置;
 94 | 
 95 | I.正常运行必备的配置
 96 |  1.user USERNAME [GROUPNAME];
 97 |     指定用于运行worker进程的用户和组
 98 |     例:  user nginx nginx
 99 |  2.pid /PATH/TO/PID_FILE;
100 |     指定nginx进程的pid文件路径
101 |     例:  pid /var/run/nginx.pid
102 |  3.worker_rlimit_nofile #; (number of files)
103 |     指定一个(/单个)worker进程所能够打开的最大文件描述符数量
104 |  4.worker_rlimit_sigpending #;
105 |     指定每个用户能够发往worker进程的信号的数量;  
106 | 
107 | II.优化性能相关的配置
108 |  1.worker_processes #;
109 |     worker进程的个数;
110 |     通常应该为物理CPU核心数量减1(或减2,比较好);
111 |     可以为"auto",实现自动设定;
112 |  2、worker_cpu_affinity CPUMASK CPUMASK ...;
113 |     (affinity--英译-->密切关系)
114 |     CPUMASK:
115 | 	    0001
116 | 	    0010
117 | 	    0100
118 | 	    1000
119 |     例: worker_cpu_affinity 00000001 00000010 00000100;
120 |          (这样绑定cpu,并不能隔离cpu,隔离CPU后面会讲)
121 |  3.worker_priority nice(默认为0);
122 |     [-20,19]  大->小    
123 | 
124 | III.用于调试,定位问题的配置
125 |  1.daemon  on|off
126 |     是否已守护方式启动nginx;
127 |  2.master_process on|off
128 |     是否以master/worker模型运行nginx;     
129 |  3.error_log /PATH/TO/ERROR_LOG level;
130 |     错误日志文件及其级别;
131 |     出于调试需要,可以设定为debug;
132 |     但debug仅在编译时使用了"--with-debug"选项是才有效;
133 | 
134 | 注:整个nginx接受最大并发连接数 = 
135 | worker_processes(worker进程数) * worker_connections(单个worker能最多接受多少个并发请求)
136 | 
137 | 
138 | -------------------------------------------------------------------------------- /tech/nginx/nginx使用之配置文件的组成及主配置段的指令之二.md: -------------------------------------------------------------------------------- 1 | # nginx.conf 配置 2 | 3 | --- 4 | ## nginx.conf 5 |
  6 | 
  7 | main配置段
  8 | 
  9 | event{
 10 |   ...
 11 | }
 12 | 
 13 | http{
 14 |     ...
 15 |    server{
 16 |        server_name
 17 |            root
 18 |            location /uri/ {
 19 |                ... 
 20 |            }
 21 |     }
 22 |     server{
 23 |         ... 
 24 |     }
 25 | }
 26 | 
 27 | 
28 | ### 1.main配置段 29 | 30 | ### 2.event 31 |
 32 | event{
 33 |   ...
 34 | }
 35 | 
36 |
 37 | 1.worker_connections #;
 38 |     没个worker进程能够响应的最大并发请求数量;
 39 | 
 40 | 整个nginx接受最大并发连接数 = 
 41 | worker_processes(worker进程数) * worker_connections(单个worker能最多接受多少个并发请求)
 42 | 
 43 | 2.use[epoll| rgs| select| poll];
 44 |     定义使用的事件模型;建议让nginx自动选择;
 45 | 
 46 | 3.accept_mutex [on| off];  (mutex--英译-->互斥)
 47 |     (使序列化的响应新请求)
 48 |     各worker接受用户的请求的负载均衡器;启用时,表示用于让多个worker轮流地、序列化的响应新请求;
 49 | 
 50 | 4.lock_file /PATH/TO/LOCK_FILE;
 51 | 
 52 | 
53 | 54 | ### 3.http配置段 55 |
 56 | http{
 57 |     ...
 58 | }
 59 | 
60 | 61 | #### 3.1 套接字或主机相关的指令 62 |
 63 | 1.server(){
 64 |      list PORT;
 65 |      server_name NAME;
 66 |      root /PATH/TO/DOCUMENTROOT;
 67 |  }
 68 |     需要多个虚拟主机,只需要多个server即可;
 69 |     例:server(){
 70 |             ...
 71 |             listen 8080;
 72 |             server_name nodel.hackfun.com;
 73 |             root /data/www/vhost2;
 74 |         }
 75 |        ...
 76 |     注意:
 77 |         (1)基于port:
 78 |                  listen 指令监听在不同的端口;
 79 |         (2)基于hostname:
 80 |                  server_name指令指向不同主机名;
 81 | 
 82 | 2.listen
 83 |     listen address [:port] [default_server] [ssl] [http2| spdy]
 84 |     listen port [default_server] [ssl] [http2: spdy]
 85 | 
 86 |     例:
 87 |     server{
 88 |         listen 80 default_server;
 89 |         server_name www.c.org;
 90 |         root /data/www/vhost2;
 91 |     }
 92 |     default_server: 设置默认虚拟主机;用基于IP地址,或使用了任意不能对应于任何一个server的name时返回站点;
 93 |     ssl: 用于限制只能通过ssl连接提供服务(即只服务https)
 94 |     spdy: SPDY protocol(speedy),在编译时,编译了spdy模块的情况下,用于支持SPDY协议;
 95 |     http2: http version 2;
 96 | 
 97 | 3.server_name NAME [...];(可以多个)
 98 |     后可跟一个或多个主机名;名称还可以使用通配符和正则表达式(二者一定要分开使用);
 99 |     (1)首先做精确匹配,例如:www.hackfun.cn
100 |     (2)左侧通配符
101 |     (3)右侧通配符
102 |     (4)正则表达式:例如:-^.*\.hackfun\.cn$;
103 |     (5)default_server
104 | 
105 | 4.tcp_nodelay on| off;
106 |     对keepalive模式下的连接是否使用TCP_NODELAY选项;(ligoals算法合并多个小报文,等待多个报文);
107 | 
108 | 5.tcp_nopush on| off;
109 |     是否启用TCP_NOPUSH(FREEBSE)或TCP_CORK(Linux)选项;仅在sendfile为on时有用;
110 | 
111 | 6.sendfile on| off;
112 |     是否启用sendfile功能;
113 | 
114 | 7.root
115 |     设置web资源的路径映射;用于指明请求的URL所对应的文档的目录路径;
116 | 
117 |     例:
118 |     server{
119 |         root /data/www/vhost2;
120 |     }
121 |     http://www.hackfun.cn/images/logo.jpg--> /data/www/vhost/images/logo.jpg
122 | 
123 |     server{
124 |         server_name www.hackfun.cn;
125 |         location /images/ {
126 |             root /data/imgs/;
127 |             ...
128 |         }
129 |     }
130 |     http://www.hackfun.cn/images/logo.jpg--> /data/imgs/images/logo.jpg
131 | 
132 | 8.location [=| ~| ~*| ^~] uri{...}
133 |   location @name{...}
134 |     功能:允许根据用户请求的URI来匹配定义的个location,匹配到时,
135 |     此请求将被相应的location快中的配置所处理;简言之,即用于为需要用到专用的配置uri提供特定配置;
136 | 
137 | 	例:
138 |     server{
139 |         ...
140 |         server_name www.hackfun.cn;
141 |         root /data/www;
142 |         (location /{
143 |              ...
144 |         })
145 |         location /admin{
146 |             ...
147 |         }
148 |     }
149 |     注:
150 |     =:URI的精确匹配;
151 |     ~:做正则表达式匹配,区分字符大小写;
152 |     ~*:做正则表达式匹配,不区分字符大小写;
153 |     ^~:URI的左半部分匹配,不区分字符大小写;
154 | 
155 |     匹配优先级:精确匹配=、^-、~或~*、不带符号的URL;
156 | 
157 | 9.ailas
158 |     只能用于location配置段,定义路径别名;
159 |     
160 |     例:
161 |     location /images/{
162 |         ...
163 |         root /data/imgs/;
164 |     }
165 |     location /images/{
166 |         ...
167 |         alias /data/imgs/;
168 |     }
169 |     注意:
170 |         root指令:路径为对应的location的"/"这个URL;
171 |                  /images/test.jpg--> /data/imgs/images/test.jpg;
172 |         alias指令:路径对应的location的"/url"这个URL;
173 |                  /images/test.jpg-> /data/imgs/test.jpg;
174 | 10.index
175 |     index file...;
176 |     默认主页
177 | 
178 | 11.error_page
179 | 
180 |     Syntax: error_page code... [=[response]] uri;
181 |     Default: ---
182 |     Context: http, server, location, if in location
183 | 
184 | 根据http状态码重定向至页面 185 | 例: 186 | error_page 404 /404.html 187 | error_page 500 502 503 /50x.html 188 | error_page 404 =200 /empty.jpg 189 | 190 | error_page 500 502 503 504 /50x.html; 191 | location = /50x.html{ 192 | root htm; 193 | } 194 | 195 | 12.try_files 196 |
197 |     Syntax: try_files file... uri;
198 |             try_files file... =code;
199 |     Default: ---
200 |     Context: server, location
201 | 
202 | 尝试查找第1至第N-1个文件,第一个即为返回给请求者的资源;若1~N-1个资源均不存在,则跳转至最后一个URI(由其他location定义,而应该匹配至其它location,否则会导致死循环); 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 |
218 | -------------------------------------------------------------------------------- /tech/redis/Redis的正确打开方式.md: -------------------------------------------------------------------------------- 1 | ## Redis的正确打开方式 2 | 3 | ### 提纲 4 | 5 | - 引入:后端开发中最常遇到的问题————共享数据 6 | - 多线程下共享数据————共享变量即可 7 | - 多进程/多进程服务器共享数据————外部共享存储 8 | - MySQL:适合存储关系型数据,一般用于存储业务数据 9 | - Redis:适合存储离散,简单的数据,操作丰富,速度更快 10 | 11 | - 简单、快速、好用的外部共享存储————Redis 12 | - 认证令牌、验证码、密码输错次数等————基本GET、SET、INCR操作 13 | - SETEX实现自动过期的登录令牌、验证码 14 | - INCR、EXPIRE操作实现限制密码输错次数 15 | 16 | - 缓存MySQL数据库记录 17 | - 方式1:SET、GET保存完整JSON字符串 (参考:http://redis.cn/commands/set.html) 18 | - 方式2:HSET、HMSET、HGET、HMGET、HGETALL拆分保存数据 (参考:http://redis.cn/commands/hset.html) 19 | 20 | - 简单队列/栈、全局轮询————LIST操作 (参考:http://redis.cn/commands/lpush.html 、 http://redis.cn/commands/rpoplpush.html) 21 | - LPUSH、RPOP作为队列使用 22 | - LPUSH、BRPOP实现生产者-消费者模型 23 | - LPUSH、LPOP作为栈使用 24 | - RPOPLPUSH作为循环列表使用 25 | - RPOPLPUSH实现可靠队列 (参考:https://www.zhihu.com/question/32318171/answer/98280219) 26 | - 消息订阅、发布————PUBSUB操作 27 | - Node.js中PUBSUB的正确使用方式(参考:https://www.npmjs.com/package/redis#publish--subscribe) 28 | - Python中PUBSUB的正确使用方式(参考:https://github.com/andymccurdy/redis-py#api-reference) 29 | - 使用PSUBSCRIBE批量订阅,减少监听客户端(参考:http://redis.cn/commands/psubscribe.html) 30 | 31 | - 题外话:Redis的Key设计/命名规则 32 | - 冒号「:」分隔,方便使用「keys *」通配 33 | - 添加「#」、「@」分隔应⽤用名称、键⽤用途,增加可读性。 *articlespider#cache@:user:1:* or *hfonline#cache@:user:1:* 34 | 35 | - 全局自增长————INCR 36 | - Redis事务 (参考:http://redis.cn/topics/transactions.html) 37 | - 使用WATCH、MULTI、EXEC实现Check-And-Set(乐观锁) 38 | 39 | - 优先级/延迟队列————ZSET操作 40 | - SCORE作为启动时间/优先级的有序集合 41 | - 利用Redis事务实现ZPOP 42 | 43 | - 使用HyperLogLog算法————PFADD、PFCOUNT (参考:http://www.runoob.com/redis/redis-hyperloglog.html) 44 | - 文章阅读量统计 45 | 46 | - 缓存常见套路 (参考:https://coolshell.cn/articles/17416.html) 47 | - Cache Aside————最常用,需要增加失效时间 48 | - Read/Write Through————对应用层透明 49 | - Write Behind Caching (Write Back)————速度飞快、非强一致性 50 | 51 | - 完整Redis操作介绍————文档多么齐全! 52 | - 注意 「可⽤用版本」 53 | - 注意 「时间复杂度」 54 | 55 | 先把理论梳理一遍,例子后面加,持续更新中。。。。。 56 | 57 | ## 感谢 58 | [Redis 官方文档](https://redis.io/commands) 59 | 60 | [周逸灵](https://www.zhihu.com/people/zhou-yi-ling-31/activities) 61 | -------------------------------------------------------------------------------- /tech/redis/images/redis_pipeline_and_sync_master_slaver_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/tech/redis/images/redis_pipeline_and_sync_master_slaver_1.png -------------------------------------------------------------------------------- /tech/redis/redis_pipeline_and_sync_master_slaver.md: -------------------------------------------------------------------------------- 1 | ## Redis Pipeline 及 主从同步 2 | 3 | ### 目录 4 | 5 | [1. Pipeline](#1-pipeline) 6 | - [1.1 使用 Pipeline 的好处](#11-使用-pipeline-的好处) 7 | - [1.2 批量生成 redis 测试数据](#12-批量生成-redis-测试数据) 8 | 9 | [2. Redis 的同步机制](#2-redis-的同步机制) 10 | - [2.1 同步过程](#21-同步过程) 11 | - [2.2 全同步过程](#22-全同步过程) 12 | - [2.3 增量同步过程](#23-增量同步过程) 13 | 14 | [3. Redis 哨兵](#3-redis-哨兵) 15 | 16 | [4. 流言协议 Gossip](#3-流言协议-gossip) 17 | 18 | ### 1. Pipeline 19 | 20 | #### 1.1 使用 Pipeline 的好处 21 | 22 | - Pipeline 和 Linux 的管道类似 23 | 24 | - Redis 基于 请求/响应 模型,单个请求处理需要一一应答 25 | 26 | - Pipeline 批量执行指令,节省多次 IO 往返的时间 27 | 28 | - 有顺序依赖的指令建议分批发送 29 | 30 | #### 1.2 批量生成 redis 测试数据 31 | 32 | 1. **Linux Bash 下面执行** 33 | 34 | for((i=1;1<=20000000;i++)); do echo "set k$i v$i" >> /tmp/redisTest.txt ;done; 35 | 生成 2千万 条 redis 批量设置 kv 的语句 (key=kn,value=vn) 写入到 /tmp 目录下的 redisTest.txt 文件中 36 | 37 | 2. **用 vim 去掉行尾的 ^M 符号,使用方式如下:** 38 | 39 | vim /tmp/redisTest.txt 40 | 41 | :set fileformat=dos # 设置文件的格式,通过这句话去掉每行结尾的 ^M 符号 42 | ::wq # 保存退出 43 | 44 | 3. **通过 redis 提供的管道--pile 形式,跑redis,传入文件的指令批量灌入数据,需要花费10分钟左右** 45 | 46 | cat /tmp/redisText.txt | 路径/redis-5.0.0/src/redis-cli -h 主机ip -p 端口号 --pipe 47 | 48 | 49 | 50 | ### 2. Redis 的同步机制 51 | 52 | ![图 1 ](./images/redis_pipeline_and_sync_master_slaver_1.png) 53 | 54 | > 图1:主节点通过 BGSAVE 记录到内存 buffer 中,待完成将 RDB 文件全量同步到从节点,从节点接受完成后, 55 | 将 RDB 镜像加载到内存中,加载完成后再通知主节点,将期间 修改的操作记录 及 增量数据 同步到 从节点(获得某个时间点之后的数据)进行重放。 56 | 57 | 58 | #### 2.1 同步过程 59 | 60 | 主节点通过 BGSAVE 记录到内存 buffer 中,待完成将 RDB 文件全量同步到从节点,从节点接受完成后, 61 | 将 RDB 镜像加载到内存中,加载完成后再通知主节点,将期间 修改的操作记录 及 增量数据 同步到 从节点(获得某个时间点之后的数据)进行重放。 62 | 63 | #### 2.2 全同步过程 64 | 65 | - Slaver 发送 sync 命令道 Master 66 | 67 | - Master 启动一个后台进程,将 Redis 中的数据快照保存到文件中 68 | 69 | - Master 将保存数据快照期间接收到的写命令缓存起来 70 | 71 | - Master 完成写文件操作后,将该文件发送给 Slaver 72 | 73 | - 使用新的 AOF 文件替换掉旧的 AOF 文件 74 | 75 | - Master 将这期间收集的增量写命令发送给 Slave 端 76 | 77 | #### 2.3 增量同步过程 78 | 79 | - Master 接收到用户的操作指令,判断是否需要传播到 Slaver 80 | 81 | - 将操作记录追加到 AOF 文件 82 | 83 | - 将操作传播到其他 Slaver:1、对齐主从库;2、往响应缓存写入指令 84 | 85 | - 将缓存中的数据发送给 Slaver 86 | 87 | ### 3. Redis 哨兵 88 | 89 | #### 解决主从同步 Master 宕机后的主从切换问题 90 | 91 | - 监控: 检查主从服务器是否运行正常 92 | 93 | - 提醒:通过 API 向管理员或者其他应用程序发送故障通知 94 | 95 | - 自动故障迁移:主从切换 96 | 97 | ### 4. 流言协议 Gossip 98 | 99 | #### 在杂乱无章中寻求一直 100 | 101 | - 每个节点随机地与对方通信,最终所有节点的状态达成一致 102 | 103 | - 种子节点定期随机向其他节点发送节点列表以及需要传播的消息 104 | 105 | - 不保证信息一定会传递给所有节点,但是最终会趋于一致 106 | 107 | ### 感谢 108 | 109 | - [Redis 官方文档](http://www.redis.cn/) 110 | 111 | - [xiangzepro](https://gitee.com/xiangze) 112 | 113 | - [深入剖析 redis 主从复制](http://daoluan.net/linux/%E5%AD%A6%E4%B9%A0%E6%80%BB%E7%BB%93/%E7%BD%91%E7%BB%9C%E7%BC%96%E7%A8%8B/2014/04/22/decode-redis-replication.html) 114 | 115 | -------------------------------------------------------------------------------- /tech/redis/redis_so_fast.md: -------------------------------------------------------------------------------- 1 | ## Redis 为什么这么快? 2 | 3 | 4 | ### 1. 纯内存操作,肯定快 5 | 6 | 数据存储在内存中,读取的时候不需要进行磁盘的 IO 7 | 8 | ### 2. 单线程,无锁竞争损耗 9 | 10 | 单线程保证了系统没有线程的上下文切换 11 | 12 | 使用单线程,可以避免不必要的上下文切换和竞争条件,没有多进程或多线程引起的切换和 CPU 的消耗,不必考虑各种锁的问题,没有锁释放或锁定操作,不会因死锁而降低性能; 13 | 14 | ### 3. C 语言实现,更接近底层操作 15 | 16 | Redis 是用 C 语言开发完成的 17 | 18 | ### 4. 多路 I/O 复用模型,非阻塞 IO 19 | 20 | 采用多路 I/O 复用技术可以让单个线程高效的处理多个网络连接请求(尽量减少网络 IO 的时间消耗) 21 | 22 | 非阻塞 IO 内部实现采用 epoll,采用了 epoll+自己实现的简单的事件框架。epoll 中的读、写、关闭、连接都转化成了事件,然后利用 epoll 的多路复用特性,绝不在 io 上浪费一点时间。 23 | 24 | ### 5. 数据结构简单,底层又做了优化 25 | 26 | 数据结构简单,对数据操作也简单,Redis 中的数据结构是专门进行设计的; 27 | 28 | ### 6. 源码精湛、简短 29 | 30 | 扩展: 31 | 在 Redis 中,常用的 5 种数据结构和应用场景 32 | String: 缓存、计数器、分布式锁等。 33 | List: 链表、队列、微博关注人时间轴列表等。 34 | Hash: 用户信息、Hash 表等。 35 | Set: 去重、赞、踩、共同好友等。 36 | Zset: 访问量排行榜、点击量排行榜等。 37 | 多路 I/O 复用模型 38 | 多路 I/O 复用模型是利用 select、poll、epoll 可以同时监察多个流的 I/O 事件的能力,在空闲的时候,会把当前线程阻塞掉,当有一个或多个流有 I/O 事件时,就从阻塞态中唤醒,于是程序就会轮询一遍所有的流(epoll 是只轮询那些真正发出了事件的流),并且只依次顺序的处理就绪的流,这种做法就避免了大量的无用操作。 39 | 40 | 这里“多路”指的是多个网络连接,“复用”指的是复用同一个线程。 41 | 42 | 采用多路 I/O 复用技术可以让单个线程高效的处理多个连接请求(尽量减少网络 IO 的时间消耗),且 Redis 在内存中操作数据的速度非常快,也就是说内存内的操作不会成为影响 Redis 性能的瓶颈,主要由以上几点造就了 Redis 具有很高的吞吐量。 43 | 44 | 45 | ### 感谢 46 | 47 | - [Redis 为什么这么快?](https://blog.csdn.net/qq_22871083/article/details/104511778) 48 | 49 | -------------------------------------------------------------------------------- /tech/redis/高并发情况下Redis做缓存的一系列问题_pending.md: -------------------------------------------------------------------------------- 1 | # 高并发情况下Redis做缓存的一系列问题 2 | 3 | 4 | ## Redis 缓存雪崩、缓存穿透、缓存预热、缓存更新、缓存降级 5 | 6 | 1. [缓存雪崩](#1缓存雪崩) 7 | 2. [缓存穿透](#2缓存穿透) 8 | 3. [缓存预热](#3缓存预热) 9 | 4. [缓存更新](#4缓存更新) 10 | 5. [缓存降级](#5缓存降级) 11 | 12 | ### 1.缓存雪崩 13 | 14 | #### 1.1 描述 15 | 16 | 缓存雪崩我们可以简单的理解为:由于原有缓存失效,新缓存未到期间(例如:我们设置缓存时采用了相同的过期时间,在同一时刻出现大面积的缓存过期),所有原本应该访问缓存的请求都去查询数据库了,而对数据库CPU和内存造成巨大压力,严重的会造成数据库宕机。从而形成一系列连锁反应,造成整个系统崩溃。 17 | 18 | #### 1.2 方案 19 | 20 | ### 2. 缓存穿透 21 | 22 | #### 2.1 描述 23 | 24 | - 缓存雪崩我们可以简单的理解为:由于原有缓存失效,新缓存未到期间(例如:我们设置缓存时采用了相同的过期时间,在同一时刻出现大面积的缓存过期),所有原本应该访问缓存的请求都去查询数据库了,而对数据库CPU和内存造成巨大压力,严重的会造成数据库宕机。从而形成一系列连锁反应,造成整个系统崩溃。 25 | 26 | - 缓存失效时的雪崩效应对底层系统的冲击非常可怕!大多数系统设计者考虑用加锁或者队列的方式保证来保证不会有大量的线程对数据库一次性进行读写,从而避免失效时大量的并发请求落到底层存储系统上。还有一个简单方案就时讲缓存失效时间分散开,比如我们可以在原有的失效时间基础上增加一个随机值,比如1-5分钟随机,这样每一个缓存的过期时间的重复率就会降低,就很难引发集体失效的事件。 27 | 28 | #### 2.2 方案 29 | 30 | ##### 2.1.1 加锁排队 31 | - 一般并发量不是特别多的时候,使用最多的解决方案是加锁排队。加锁排队只是为了减轻数据库的压力,并没有提高系统吞吐量。假设在高并发下,缓存重建期间key是锁着的,这是过来1000个请求999个都在阻塞的。同样会导致用户等待超时,这是个治标不治本的方法! 32 | 注意:加锁排队的解决方式分布式环境的并发问题,有可能还要解决分布式锁的问题;线程还会被阻塞,用户体验很差!因此,在真正的高并发场景下很少使用! 33 | 34 | ##### 2.1.2 缓存标记 35 | - 给每一个缓存数据增加相应的缓存标记,记录缓存的是否失效,如果缓存标记失效,则更新数据缓存。 36 | 37 | #### 2.3 解释说明 38 | - 缓存标记:记录缓存数据是否过期,如果过期会触发通知另外的线程在后台去更新实际key的缓存; 39 | 40 | - 缓存数据:它的过期时间比缓存标记的时间延长1倍,例:标记缓存时间30分钟,数据缓存设置为60分钟。 这样,当缓存标记key过期后,实际缓存还能把旧数据返回给调用端,直到另外的线程在后台更新完成后,才会返回新缓存。 41 | 42 | 关于缓存崩溃的解决方法,这里提出了三种方案:使用锁或队列、设置过期标志更新缓存、为key设置不同的缓存失效时间,还有一各被称为“二级缓存”的解决方法,有兴趣的读者可以自行研究。 43 | 44 | 45 | ### 3. 缓存预热 46 | 47 | #### 3.1 描述 48 | 49 | - 缓存雪崩我们可以简单的理解为:由于原有缓存失效,新缓存未到期间(例如:我们设置缓存时采用了相同的过期时间,在同一时刻出现大面积的缓存过期),所有原本应该访问缓存的请求都去查询数据库了,而对数据库CPU和内存造成巨大压力,严重的会造成数据库宕机。从而形成一系列连锁反应,造成整个系统崩溃。 50 | 51 | - 缓存失效时的雪崩效应对底层系统的冲击非常可怕!大多数系统设计者考虑用加锁或者队列的方式保证来保证不会有大量的线程对数据库一次性进行读写,从而避免失效时大量的并发请求落到底层存储系统上。还有一个简单方案就时讲缓存失效时间分散开,比如我们可以在原有的失效时间基础上增加一个随机值,比如1-5分钟随机,这样每一个缓存的过期时间的重复率就会降低,就很难引发集体失效的事件。 52 | 53 | 加锁排队只是为了减轻数据库的压力,并没有提高系统吞吐量。假设在高并发下,缓存重建期间key是锁着的,这是过来1000个请求999个都在阻塞的。同样会导致用户等待超时,这是个治标不治本的方法! 54 | 注意:加锁排队的解决方式分布式环境的并发问题,有可能还要解决分布式锁的问题;线程还会被阻塞,用户体验很差!因此,在真正的高并发场景下很少使用! 55 | 56 | 57 | 58 | #### 3.2 方案 59 | 60 | ### 4. 缓存更新 61 | 62 | #### 4.1 描述 63 | 64 | 缓存雪崩我们可以简单的理解为:由于原有缓存失效,新缓存未到期间(例如:我们设置缓存时采用了相同的过期时间,在同一时刻出现大面积的缓存过期),所有原本应该访问缓存的请求都去查询数据库了,而对数据库CPU和内存造成巨大压力,严重的会造成数据库宕机。从而形成一系列连锁反应,造成整个系统崩溃。 65 | 66 | #### 4.2 方案 67 | 68 | ### 5. 缓存降级 69 | 70 | #### 5.1 描述 71 | 72 | 缓存雪崩我们可以简单的理解为:由于原有缓存失效,新缓存未到期间(例如:我们设置缓存时采用了相同的过期时间,在同一时刻出现大面积的缓存过期),所有原本应该访问缓存的请求都去查询数据库了,而对数据库CPU和内存造成巨大压力,严重的会造成数据库宕机。从而形成一系列连锁反应,造成整个系统崩溃。 73 | 74 | #### 5.2 方案 75 | 76 | ## 感谢 77 | 78 | [高可用架构](https://mp.weixin.qq.com/s/TBCEwLVAXdsTszRVpXhVug) 79 | 80 | [Redis的缓存雪崩](https://www.sunjs.com/article/detail/7cdee1d735cf43f9a2e051d62a400aa9.html) 81 | -------------------------------------------------------------------------------- /tech/springcloud/Eureka_Server_和_Client_之间的信息维护(注册和续约).md: -------------------------------------------------------------------------------- 1 | # Eureka Server 和 Client 之间的信息维护(注册和续约) 2 | 3 | 4 | ### Eureka Server 维护了系统中服务的元信息,这些元信息包含什么你知道吗 ? 5 | 6 | #### Eureka Server 维护了 Client 的哪些信息呢? 7 | 8 | 如果我们启动 Client (简单认为就是一个微服务)的时候,如果此时配置了错误的 Eureka Server 发现地址或 Eureka Server 没有启动,那么会发现,Client 可以正常启动,但不能完成注册,会抛出如下异常信息。 9 | 10 | ``` 11 | com.netflix.discovery.shared.transport.TransportException: Cannot execute request on any known server 12 | ...... 13 | at com.netflix.discovery.DiscoveryClient.register(DiscoveryClient.java:829) ~[eureka-client-1.9.2.jar:1.9.2] 14 | ...... 15 | ``` 16 | 17 | 这里的异常信息,其实就告诉了我们,Client 向 Eureka Server 发起注册的过程。我们来看一看 DiscoveryClient.register 里面做了什么(eureka-client-1.9.2-sources.jar!/com/netflix/discovery/DiscoveryClient.java): 18 | 19 | ```java 20 | /** 21 | * 通过 HTTP (eurekaTransport) 请求将 Eureka Client 注册到 Eureka Server 上 22 | */ 23 | boolean register() throws Throwable { 24 | logger.info(PREFIX + "{}: registering service...", appPathIdentifier); 25 | EurekaHttpResponse httpResponse; 26 | try { 27 | // 很显然,这里的 instanceInfo 就是 Client 的元数据 28 | httpResponse = eurekaTransport.registrationClient.register(instanceInfo); 29 | } catch (Exception e) { 30 | logger.warn(PREFIX + "{} - registration failed {}", appPathIdentifier, e.getMessage(), e); 31 | throw e; 32 | } 33 | if (logger.isInfoEnabled()) { 34 | logger.info(PREFIX + "{} - registration status: {}", appPathIdentifier, httpResponse.getStatusCode()); 35 | } 36 | return httpResponse.getStatusCode() == 204; 37 | } 38 | ``` 39 | 40 | instanceInfo 就是 com.netflix.appinfo.InstanceInfo 的对象实例,它被称作是"应用实例信息"。 41 | 所以,这个对象中包含的属性,最终会投递到 Eureka Server 中,也就是说,Eureka Server 维护的元信息就是 InstanceInfo(各位可以看一看 InstanceInfo 中包含了什么,同时,还可以继续跟踪源代码,看一看 InstanceInfo 的初始化过程)。 42 | 43 | 44 | ### 元信息又是怎么存储的呢 ? 45 | 46 | #### 猜想,Eureka Server 和 Client 之间的信息维护(注册和续约) 47 | 48 | 元信息的保存,可能是Eureka Server内部维护着一张表来记录这些元信息,Eureka服务器没有后端存储,但注册表中的服务实例必须发送心跳信号以保持其注册是最新的,所以这可能使内存中完成。客户端可能还拥有一个eureka注册的内存缓存,这样,client不必为每个服务请求都去注册表。 49 | 50 | #### Eureka Server 是怎么存储 Client 的元信息的呢 ? 51 | 52 | 这个问题与第一个问题是有关联性的,因为 Client 向 Server 发起注册(HTTP 请求),那么 Server 必须对外提供了这个接口才可以。 53 | 54 | 经过追踪 Server 端的源码(eureka-core-1.9.2-sources.jar),很容易可以找到 com/netflix/eureka/resources/ApplicationResource.java, 55 | 其中 addInstance 方法即实现了服务注册的功能(Server 端)。源码如下: 56 | 57 | ```java 58 | @POST 59 | @Consumes({"application/json", "application/xml"}) 60 | public Response addInstance(InstanceInfo info, 61 | @HeaderParam(PeerEurekaNode.HEADER_REPLICATION) String isReplication) { 62 | // 校验 instanceinfo 中是否包含必须的属性 63 | if (isBlank(info.getId())) { 64 | return Response.status(400).entity("Missing instanceId").build(); 65 | } else if (isBlank(info.getHostName())) { 66 | return Response.status(400).entity("Missing hostname").build(); 67 | } 68 | ...... 69 | 70 | // 注册信息校验 71 | ...... 72 | 73 | // 通过 PeerAwareInstanceRegistry 的 register 方法完成 Client 的注册 74 | registry.register(info, "true".equals(isReplication)); 75 | return Response.status(204).build(); 76 | } 77 | ``` 78 | 79 | 我们再去看 PeerAwareInstanceRegistry 的实现类:org.springframework.cloud.netflix.eureka.server.InstanceRegistry 的 register 方法的实现: 80 | 81 | ```java 82 | public void register(InstanceInfo registrant, int leaseDuration, boolean isReplication) { 83 | try { 84 | read.lock(); 85 | // registry 存储了注册信息, 它是一个两层的 Map 结构 86 | // ConcurrentHashMap>> registry 87 | Map> gMap = registry.get(registrant.getAppName()); 88 | REGISTER.increment(isReplication); 89 | if (gMap == null) { 90 | final ConcurrentHashMap> gNewMap = new ConcurrentHashMap>(); 91 | gMap = registry.putIfAbsent(registrant.getAppName(), gNewMap); 92 | if (gMap == null) { 93 | gMap = gNewMap; 94 | } 95 | } 96 | Lease existingLease = gMap.get(registrant.getId()); 97 | ...... 98 | Lease lease = new Lease(registrant, leaseDuration); 99 | if (existingLease != null) { 100 | lease.setServiceUpTimestamp(existingLease.getServiceUpTimestamp()); 101 | } 102 | gMap.put(registrant.getId(), lease); 103 | ...... 104 | } finally { 105 | read.unlock(); 106 | } 107 | } 108 | ``` 109 | 110 | InstanceInfo 中的元数据信息存储在一个 ConcurrentHashMap 对象中。Eureka Server 使用了两层 Map 结构做存储,第一层的 key 存储服务名: 111 | InstanceInfo 中的 appName 属性,第二层 key 存储实例名:InstanceInfo 中的 instanceId 属性。 112 | 113 | 114 | ## 感谢 115 | 116 | [张勤一 - 百度 · 高级Java工程师](https://www.zhihu.com/people/zhang-qin-yi-51-72/activities) 117 | 118 | -------------------------------------------------------------------------------- /tech/springcloud/Eureka介绍.md: -------------------------------------------------------------------------------- 1 | # Eureka 2 | 3 | ## Eureka 的介绍 4 | 5 | ### 核心功能 6 | 7 | - Service Registry(服务注册) 8 | 9 | - Service Discovery(服务发现) 10 | 11 | ### 基本架构 12 | 13 | #### Erueka 由三个角色组成: 14 | 15 | - Eureka Server,提供服务注册与发现 16 | 17 | - Service Provider,服务提供方,将自身服务注册到 Eureka Server 上,从而让 Eureka Server 持有服务的元信息,让其他的服务消费方能够找到当前服务 18 | 19 | - Service Consumer,服务消费方,从 Eureka Server 上获取注册服务列表,从而能够消费服务 20 | 21 | - Service Provider/Consumer,相对于 Server,都叫做 Eureka Client 22 | 23 | #### Erueka 的基本架构如下图所示 24 | 25 | ![Alt text](./images/eureka_intrd_1.jpg) 26 | 27 | 28 | ## Eureka Server 的高可用 29 | 30 | ### 问题说明 31 | 32 | 单节点的 **Eureka Server** 虽然能够实现基础功能,但是存在单点故障的问题,不能实现高可用。因为 **Eureka Server** 中存储了整个系统中所有的微服务的元数据信息,单节点一旦挂了,所有的服务信息都会丢失,造成整个系统的瘫痪。 33 | 34 | ### 解决办法 35 | 36 | 搭建 **Eureka Server** 集群,让各个 **Server** 节点之间互相注册,从而实现微服务元数据的复制/备份,即使单个节点失效,其他的 **Server** 仍可以继续提供服务 37 | 38 | ### Eureka Server 集群架构如下图所示 39 | 40 | ![Alt text](./images/eureka_intrd_2.jpg) 41 | 42 | 43 | ## 构造应用的 pom.xml 文件及注释信息 44 | ```xml 45 | 46 | 49 | 50 | 51 | 52 | hackfun-ad 53 | com.hackfun.ad 54 | 1.0-SNAPSHOT 55 | 56 | 57 | 4.0.0 58 | 59 | 60 | ad-eureka 61 | 1.0-SNAPSHOT 62 | jar 63 | 64 | 65 | ad-eureka 66 | Spring Cloud Eureka 67 | 68 | 69 | 70 | 71 | org.springframework.cloud 72 | spring-cloud-starter-netflix-eureka-server 73 | 74 | 75 | 76 | 80 | 81 | 82 | 83 | org.springframework.boot 84 | spring-boot-maven-plugin 85 | 86 | 87 | 88 | 89 | 90 | ``` 91 | 92 | ## 结尾 93 | 94 | - Eureka Server 维护了系统中服务的元信息,这些元信息包含什么你知道吗 ? 95 | 96 | - 元信息又是怎么存储的呢 ? 97 | 98 | 以上两个问题,各位可以先考虑一下,关于问题解答,参考下一篇博文 [Eureka Server 和 Client 之间的信息维护(注册和续约)](Eureka_Server_和_Client_之间的信息维护(注册和续约).md) 99 | 100 | - [Eureka 官方 wiki](https://github.com/Netflix/eureka/wiki) 提到 101 | 102 | Eureka 2.0 (Discontinued) 103 | 104 | The existing open source work on eureka 2.0 is discontinued. The code base and artifacts that were released as part of the existing repository of work on the 2.x branch is considered use at your own risk. 105 | 106 | Eureka 1.x is a core part of Netflix's service discovery system and is still an active project. 107 | 108 | 关于Eureka 2.0 开源工作已经停止,网络上还是有一些讨论的,小弟就不在此发表意见了,有兴趣可以自己了解一下。 109 | 110 | 对于使用 Eureka 1.x 的,可以看一下这篇文章 [Eureka 2.0 开源流产,真的对你影响很大吗?](http://blog.didispace.com/Eureka-2-0-discontinued/) 111 | 112 | ## 感谢 113 | 114 | [张勤一 - 百度 · 高级Java工程师](https://www.zhihu.com/people/zhang-qin-yi-51-72/activities) 115 | -------------------------------------------------------------------------------- /tech/springcloud/Zuul介绍.md: -------------------------------------------------------------------------------- 1 | # Zuul 2 | 3 | ## Zuul 的介绍 4 | 5 | 在介绍 **Zuul** 可以提供的功能之前,请各位先考虑一个问题: 6 | 微服务系统中往往包含很多个功能不同的子系统或微服务,那么,外部应用怎样去访问各种各样的微服务呢?这也是 **Zuul** 所要解决的一个主要问题。 7 | 8 | 在微服务架构中,后端服务往往不直接开放给调用端,而是通过一个服务网关根据请求的 **url**,路由到相应的服务,即实现请求转发,效果如下图所示。 9 | 10 | ![Alt text](./images/zuul_intrd_1.jpg) 11 | 12 | **Zuul** 提供了服务网关的功能,可以实现负载均衡、反向代理、动态路由、请求转发等功能。**Zuul** 大部分功能都是通过过滤器实现的,**Zuul** 中定义了四种标准的过滤器类型,同时,还支持自定义过滤器(例如,用来记录访问延迟)。 13 | 这些过滤器的类型也对应于请求的典型生命周期,如下图所示。 14 | 15 | ![Alt text](./images/zuul_intrd_2.jpg) 16 | 17 | - Pre:在被请求路由之前调用 18 | - Route:在请求路由时调用 19 | - Post:在请求路由最后(Route 和 Error 过滤器之后)调用 20 | - Error:处理请求,发生错误时被调用 21 | 22 | 23 | ## 构造应用的 pom.xml 文件及注释信息 24 | ```xml 25 | 26 | 29 | 30 | 31 | 32 | hackfun-ad 33 | com.hackfun.ad 34 | 1.0-SNAPSHOT 35 | 36 | 37 | 4.0.0 38 | 39 | 40 | ad-gateway 41 | 1.0-SNAPSHOT 42 | jar 43 | 44 | 45 | ad-gateway 46 | ad-gateway 47 | 48 | 49 | 53 | 54 | org.springframework.cloud 55 | spring-cloud-starter-netflix-eureka-client 56 | 57 | 58 | 59 | org.springframework.cloud 60 | spring-cloud-starter-netflix-zuul 61 | 62 | 63 | 64 | 68 | 69 | 70 | 71 | org.springframework.boot 72 | spring-boot-maven-plugin 73 | 74 | 75 | 76 | 77 | 78 | ``` 79 | 80 | ## 结尾 81 | 82 | - Zuul 的功能大部分都是由过滤器实现的,你还可以定义怎样的过滤器实现你想要的功能呢 ? 83 | 84 | - 如果要给我们的系统接入用户模块(用户和权限),放在网关里面做合适吗 ? 85 | 86 | 以上两个问题,各位可以先考虑一下,关于问题解答,参考下一篇博文 Pending 87 | 88 | 89 | ## 感谢 90 | 91 | [张勤一 - 百度 · 高级Java工程师](https://www.zhihu.com/people/zhang-qin-yi-51-72/activities) 92 | -------------------------------------------------------------------------------- /tech/springcloud/images/eureka_intrd_1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/tech/springcloud/images/eureka_intrd_1.jpg -------------------------------------------------------------------------------- /tech/springcloud/images/eureka_intrd_2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/tech/springcloud/images/eureka_intrd_2.jpg -------------------------------------------------------------------------------- /tech/springcloud/images/zuul_intrd_1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/tech/springcloud/images/zuul_intrd_1.jpg -------------------------------------------------------------------------------- /tech/springcloud/images/zuul_intrd_2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/tech/springcloud/images/zuul_intrd_2.jpg -------------------------------------------------------------------------------- /tools/Pycharm上传到码云或者GitHub.md: -------------------------------------------------------------------------------- 1 | ## Windows下使用Pycharm上传到码云或者GitHub 2 | 3 | ### 1.安装Git 4 | 5 | 去Git官网下载:https://git-scm.com/downloads 6 | 7 | 点击下一步就行了,不多说。 8 | 9 | ### 2.设置Git的user name 和 email 10 | 11 | 打开Git bash 输入如下两行 12 |
13 | $ git config --global user.name "xxx(用户名)"
14 | $ git config --global user.email "xxxxxx@xxx.com(邮箱)"
15 | 
16 | 17 | ### 3.生成密钥 18 | 19 | 输入 20 | 21 |
ssh-keygen -t rsa -C "xxxxx@xxx.com(邮箱)" 
22 | 23 | **会生成```id_rsa```和```id_rsa.pub```(windows默认会生成在 C:\Users\xxxx\.ssh ,linux默认在我的home目录底下的 .ssh/),后面要添加的是"id_rsa.pub"里面的公钥。** 24 | 25 | 如图 26 | 27 | ![Alt text](./images/1.png) 28 | 29 | ### 4.配置github(或者码云) 30 | 31 | **①.GitHub([https://github.com/](https://github.com/ "GitHub")):Settings—> SSH keys and GPG keys—>New SHH key —>填写相关内容—>Add SSH key** 32 | 33 | ![Alt text](./images/2.png) 34 | 35 | **②.码云([http://git.oschina.net/](https://github.com/ "码云")):修改资料—>SSH公钥 —>填写相关内容—>确定** 36 | 37 | ![Alt text](./images/3.png) 38 | 39 | 40 | ### 5.配置PyCharm 41 | 42 | **①.Menu—>VCS—>Checkout from Version Control—>Git—配置Git Repository URL—>点击Test—>成功,即为配置成功—>点击clone** 43 | 44 | 如图 45 | 46 | 47 | ![Alt text](./images/4.png "第一步") 48 | 49 | ![Alt text](./images/5.png "第二步") 50 | 51 | ![Alt text](./images/6.png "第三步") ![Alt text](./images/7.png "第四步") 52 | 53 | ### 6.接下来你就可以修改clone下来的项目了 54 | 55 | ### 7.提交修改 56 | **①.commit(ctrl+k) 弹出如下对话框** 57 | 58 | ![Alt text](./images/8.png "第一步") 59 | 60 | **②.在Pycharm中打开Terminal输入git push然后回车** 61 | 62 | ![Alt text](./images/9.png "第一步") 63 | 64 | **③.输入你的码云或者github用户名及密码(第一次push时需要输入)** 65 | 66 | ![Alt text](./images/10.png "第一步") 67 | 68 | 69 | ### 8.在码云或者GitHub查看项目 70 | 71 | 接下来你就可以在你的「git.oschina.net/xxxx/xx.git」中看见你提交修改的代码了 72 | -------------------------------------------------------------------------------- /tools/images/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/tools/images/1.png -------------------------------------------------------------------------------- /tools/images/10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/tools/images/10.png -------------------------------------------------------------------------------- /tools/images/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/tools/images/2.png -------------------------------------------------------------------------------- /tools/images/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/tools/images/3.png -------------------------------------------------------------------------------- /tools/images/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/tools/images/4.png -------------------------------------------------------------------------------- /tools/images/5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/tools/images/5.png -------------------------------------------------------------------------------- /tools/images/6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/tools/images/6.png -------------------------------------------------------------------------------- /tools/images/7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/tools/images/7.png -------------------------------------------------------------------------------- /tools/images/8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/tools/images/8.png -------------------------------------------------------------------------------- /tools/images/9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackfengJam/blog/02afeb3031c3b168de031a97dce7787fd33dae4a/tools/images/9.png -------------------------------------------------------------------------------- /tools/欢迎使用CSDN-markdown编辑器.md: -------------------------------------------------------------------------------- 1 | # 欢迎使用Markdown编辑器写博客 2 | 3 | 本Markdown编辑器使用[StackEdit][6]修改而来,用它写博客,将会带来全新的体验哦: 4 | 5 | - **Markdown和扩展Markdown简洁的语法** 6 | - **代码块高亮** 7 | - **图片链接和图片上传** 8 | - ***LaTex*数学公式** 9 | - **UML序列图和流程图** 10 | - **离线写博客** 11 | - **导入导出Markdown文件** 12 | - **丰富的快捷键** 13 | 14 | ------------------- 15 | 16 | ## 快捷键 17 | 18 | - 加粗 `Ctrl + B` 19 | - 斜体 `Ctrl + I` 20 | - 引用 `Ctrl + Q` 21 | - 插入链接 `Ctrl + L` 22 | - 插入代码 `Ctrl + K` 23 | - 插入图片 `Ctrl + G` 24 | - 提升标题 `Ctrl + H` 25 | - 有序列表 `Ctrl + O` 26 | - 无序列表 `Ctrl + U` 27 | - 横线 `Ctrl + R` 28 | - 撤销 `Ctrl + Z` 29 | - 重做 `Ctrl + Y` 30 | 31 | ## Markdown及扩展 32 | 33 | > Markdown 是一种轻量级标记语言,它允许人们使用易读易写的纯文本格式编写文档,然后转换成格式丰富的HTML页面。 —— [ 维基百科 ] 34 | 35 | 使用简单的符号标识不同的标题,将某些文字标记为**粗体**或者*斜体*,创建一个[链接](http://www.csdn.net)等,详细语法参考帮助?。 36 | 37 | 本编辑器支持 **Markdown Extra** ,  扩展了很多好用的功能。具体请参考[Github][2]. 38 | 39 | ### 表格 40 | 41 | **Markdown Extra** 表格语法: 42 | 43 | 项目 | 价格 44 | -------- | --- 45 | Computer | $1600 46 | Phone | $12 47 | Pipe | $1 48 | 49 | 可以使用冒号来定义对齐方式: 50 | 51 | | 项目 | 价格 | 数量 | 52 | | :-------- | --------:| :--: | 53 | | Computer | 1600 元 | 5 | 54 | | Phone | 12 元 | 12 | 55 | | Pipe | 1 元 | 234 | 56 | 57 | ###定义列表 58 | 59 | **Markdown Extra** 定义列表语法: 60 | 项目1 61 | 项目2 62 | : 定义 A 63 | : 定义 B 64 | 65 | 项目3 66 | : 定义 C 67 | 68 | : 定义 D 69 | 70 | > 定义D内容 71 | 72 | ### 代码块 73 | 代码块语法遵循标准markdown代码,例如: 74 | ``` python 75 | @requires_authorization 76 | def somefunc(param1='', param2=0): 77 | '''A docstring''' 78 | if param1 > param2: # interesting 79 | print 'Greater' 80 | return (param2 - param1 + 1) or None 81 | class SomeClass: 82 | pass 83 | >>> message = '''interpreter 84 | ... prompt''' 85 | ``` 86 | 87 | ###脚注 88 | 生成一个脚注[^footnote]. 89 | [^footnote]: 这里是 **脚注** 的 *内容*. 90 | 91 | ### 目录 92 | 用 `[TOC]`来生成目录: 93 | 94 | [TOC] 95 | 96 | ### 数学公式 97 | 使用MathJax渲染*LaTex* 数学公式,详见[math.stackexchange.com][1]. 98 | 99 | - 行内公式,数学公式为:$\Gamma(n) = (n-1)!\quad\forall n\in\mathbb N$。 100 | - 块级公式: 101 | 102 | $$ x = \dfrac{-b \pm \sqrt{b^2 - 4ac}}{2a} $$ 103 | 104 | 更多LaTex语法请参考 [这儿][3]. 105 | 106 | ### UML 图: 107 | 108 | 可以渲染序列图: 109 | 110 | ```sequence 111 | 张三->李四: 嘿,小四儿, 写博客了没? 112 | Note right of 李四: 李四愣了一下,说: 113 | 李四-->张三: 忙得吐血,哪有时间写。 114 | ``` 115 | 116 | 或者流程图: 117 | 118 | ```flow 119 | st=>start: 开始 120 | e=>end: 结束 121 | op=>operation: 我的操作 122 | cond=>condition: 确认? 123 | 124 | st->op->cond 125 | cond(yes)->e 126 | cond(no)->op 127 | ``` 128 | 129 | - 关于 **序列图** 语法,参考 [这儿][4], 130 | - 关于 **流程图** 语法,参考 [这儿][5]. 131 | 132 | ## 离线写博客 133 | 134 | 即使用户在没有网络的情况下,也可以通过本编辑器离线写博客(直接在曾经使用过的浏览器中输入[write.blog.csdn.net/mdeditor](http://write.blog.csdn.net/mdeditor)即可。**Markdown编辑器**使用浏览器离线存储将内容保存在本地。 135 | 136 | 用户写博客的过程中,内容实时保存在浏览器缓存中,在用户关闭浏览器或者其它异常情况下,内容不会丢失。用户再次打开浏览器时,会显示上次用户正在编辑的没有发表的内容。 137 | 138 | 博客发表后,本地缓存将被删除。  139 | 140 | 用户可以选择 把正在写的博客保存到服务器草稿箱,即使换浏览器或者清除缓存,内容也不会丢失。 141 | 142 | > **注意:**虽然浏览器存储大部分时候都比较可靠,但为了您的数据安全,在联网后,**请务必及时发表或者保存到服务器草稿箱**。 143 | 144 | ##浏览器兼容 145 | 146 | 1. 目前,本编辑器对Chrome浏览器支持最为完整。建议大家使用较新版本的Chrome。 147 | 3. IE9以下不支持 148 | 4. IE9,10,11存在以下问题 149 | 1. 不支持离线功能 150 | 1. IE9不支持文件导入导出 151 | 1. IE10不支持拖拽文件导入 152 | 153 | --------- 154 | 155 | [1]: http://math.stackexchange.com/ 156 | [2]: https://github.com/jmcmanus/pagedown-extra "Pagedown Extra" 157 | [3]: http://meta.math.stackexchange.com/questions/5020/mathjax-basic-tutorial-and-quick-reference 158 | [4]: http://bramp.github.io/js-sequence-diagrams/ 159 | [5]: http://adrai.github.io/flowchart.js/ 160 | [6]: https://github.com/benweet/stackedit --------------------------------------------------------------------------------