├── .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 |  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 |  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 |  77 | 78 | > 上图来源:Go 夜读 79 | 80 | 81 | ### 3. Golang Gc 流程 82 | 83 |  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 |  121 | 122 | 123 |  124 | 125 | 126 |  127 | 128 | 129 |  130 | 131 | 132 |  133 | 134 |  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 |  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()**
a = 320 | Python会执行下面三个步骤: 21 | 22 | 1. 创建一个对象来代表值3。 23 | 2. 创建一个变量a,如果它还没有被创建的话。 24 | 3. 将变量与新的对象相连接。 25 | 26 | 如图 27 | 28 |  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 |  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 |  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 |  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 |  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 |  122 | 123 | --- 124 | 125 | ## 3.3 请求异常处理 126 | 127 |  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 |  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 |  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 |  188 | 189 | ## 3.4 自定义Request 190 | 191 |  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 |  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 |  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 |  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 |  31 | 32 | 这个结果其实就是一个base64的简单加密,因此很不安全 33 | 34 |  35 | 36 | 37 | ### 2.OAUTH认证 38 | 39 |  40 | 41 | #### 在GitHub上面设置一个 42 |  43 | #### 从GitHub开发者api上找到认证方式 44 |  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 |  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 |  89 | 90 | 91 | ## 3.2 代理(Proxy) 92 |  93 |  94 | 95 | 96 | ### 安装requests对socksv5支持,cmd下输入: pip install requests[socksv5] 97 |  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 |  118 | 119 | ### 3.3.2 Session 120 |  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 |  29 | 30 | ### 例子演示2 31 | 32 |  33 | 34 | ### 例子演示3 35 | 36 |  37 | 38 | ### 例子演示4 39 | 40 |  41 | 42 | ### 例子演示5 43 | 44 |  45 | 46 | ### 例子演示6 47 | 48 |  49 | 50 | ### 例子演示7 51 | 52 |  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 |  90 | 91 | ## 2.3 事件钩子(Event Hooks) 92 | 93 | 94 |  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 |  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 |  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 |  4 | 5 |  6 | 7 | - 订单补偿不要粗暴地使用消息队列的方式,避免中间件引发的订单丢失 8 | - 关键逻辑也不要使用缓存来进行订单的查询 9 | 10 |  11 | 12 | - 接收消息处理失败时一定要让消息重试,避免丢失 13 | 14 |  15 | 16 | - 尤其注意 return、continue 等关键字 17 | 18 |  19 | 20 | - 写数据库时,数据库事务的粒度不要太大,避免锁表,关注慢SQL 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 | - 结算页:支付完成后,页面调转到 我的服务 57 | 58 | - 提交订单 -> 下单服务 59 | 60 | - 下单服务 61 | - 写 MySQL master,双写缓存 62 | - 通过 binlog 同步 MYSQL slave -> 数据异构 -> 缓存 63 | 64 | 65 |  66 | 67 |  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 |  49 | 5. 浏览器输入:```localhost:9200``` 50 | 51 |  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 |  65 | 7. ①.发现输入:从浏览器访问```localhost:9200```是没问题,但是***elasticsearch-head***就是连不上。 66 | 67 |  68 | 69 | ②.浏览器输入:```localhost:9100```也显示确实未连接。 70 |  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 |  102 | 5. 浏览器输入:```localhost:5601``` 103 | 104 |  105 | 6. 点击Dev Tools: 106 | 107 |  108 | 109 | 7. 接下来,请开始你的表演: 110 | 111 |  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 |  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 | >  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 |  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 |  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 |  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 |  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 |  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 |  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 |  77 | 78 | 1. 最上层 Controller 和 TService 是阿里分层规范里面的第一层:轻业务逻辑,参数校验,异常兜底。 79 | 通常这种接口可以轻易更换接口类型,所以业务逻辑必须要轻,甚至不做具体逻辑。 80 | 81 | 2. Service: 82 | 业务层,复用性较低,这里推荐每一个 Controller 方法都得对应一个 Service, 83 | 不要把业务编排放在 Controller 中去做,为什么呢? 84 | 如果我们把业务编排放在 Controller 层 去做的话, 85 | 如果以后我们要接入 thrift,我们这里又需要把业务编排在做一次, 86 | 这样会导致我们每接入一个入口层这个代码都得重新复制一份如下图所示: 87 | 88 |  89 | 90 | 这样大量的重复工作必定会导致我们开发效率下降,所以我们需要把业务编排逻辑都得放进 Service 中去做: 91 | 92 |  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 |  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 |  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 |
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 |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 |  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 | EurekaHttpResponse180 | 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 |
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 |  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 |  34 | 35 | **②.码云([http://git.oschina.net/](https://github.com/ "码云")):修改资料—>SSH公钥 —>填写相关内容—>确定** 36 | 37 |  38 | 39 | 40 | ### 5.配置PyCharm 41 | 42 | **①.Menu—>VCS—>Checkout from Version Control—>Git—配置Git Repository URL—>点击Test—>成功,即为配置成功—>点击clone** 43 | 44 | 如图 45 | 46 | 47 |  48 | 49 |  50 | 51 |   52 | 53 | ### 6.接下来你就可以修改clone下来的项目了 54 | 55 | ### 7.提交修改 56 | **①.commit(ctrl+k) 弹出如下对话框** 57 | 58 |  59 | 60 | **②.在Pycharm中打开Terminal输入git push然后回车** 61 | 62 |  63 | 64 | **③.输入你的码云或者github用户名及密码(第一次push时需要输入)** 65 | 66 |  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 --------------------------------------------------------------------------------