admin 管理员组文章数量: 887007
文章目录
- 入门篇
- 操作系统入门 Linux
- 编程技能
- 专业基础篇
- 编程语言
- Java 语言
- 学习 Go 语言
- 理论学科
- 数据结构和算法
- 其它理论基础知识
- 系统知识
- C10K 问题
- 实践项目
- 软件设计篇
- 编程范式
- 一些软件设计的相关原则
- 一些软件设计的读物
- 高手成长篇
- Linux 系统、内存和网络(系统底层知识)
- Linux 系统相关
- 内存相关
- 计算机网络
- 网络学习
- 网络调优
- 网络协议
- 异步 I/O 模型和 Lock-Free 编程(系统底层知识)
- 异步 I/O 模型
- Lock-Free 编程相关
- 其它
- 相关论文
- 小结
- Java 底层知识
- Java 字节码相关
- JVM 相关
- 小结
- 数据库
- 关系型数据库
- NoSQL 数据库
- 各种 NoSQL 数据库
- 小结
- 分布式架构入门(分布式架构)
- 分布式架构入门
- 分布式理论
- 小结
- 分布式架构经典图书和论文(分布式架构)
- 经典图书
- 经典论文
- 分布式事务
- Paxos 一致性算法
- Raft 一致性算法
- Gossip 一致性算法
- 分布式存储和数据库
- 分布式消息系统
- 日志和数据
- 分布式监控和跟踪
- 数据分析
- 与编程相关的论文
- 其它的分布式论文阅读列表
- 小结
- 分布式架构工程设计 (分布式架构)
- 设计模式
- 设计与工程实践
- 分布式系统的故障测试
- 弹性伸缩
- 一致性哈希
- 数据库分布式
- 缓存
- 消息队列
- 关于日志方面
- 关于性能方面
- 关于搜索方面
- 各公司的架构实践
- 小结
- 微服务
- 微服务架构
- 微服务和 SOA
- 设计模式和最佳实践
- 相关资源
- 小结
- 容器化和自动化运维
- Docker
- Kubernetes
- 小结
- 机器学习和人工智能
- 基本原理简介
- 相关课程
- 相关图书
- 相关文章
- 相关算法
- 相关资源
- 小结
- 前端基础和底层原理(前端方向)
- HTML 5
- CSS
- JavaScript
- 浏览器原理
- 网络协议
- 小结
- 前端性能优化和框架(前端方向)
- 前端框架
- React.js 框架
- Vue.js 框架
- 小结
- UI/UX 设计(前端方向)
- 图书和文章推荐
- 原子设计(Atomic Design)
- 设计语言和设计系统
- Fluent Design System
- Material Design
- 其它公司
- 动画效果设计
- 相关资源
- 文章资源
- 设计收集
- 小结
- 技术资源集散地
- YouTube 技术频道
入门篇
通过这一系列文章,我主要想回答以下几个问题。
-
理论和现实的差距。你是否觉得自己从学校毕业的时候只做过小玩具一样的程序?走入职场后哪怕没有什么经验也可以把文中提到的这些课外练习走一遍。学校课程总是从理论出发,作业项目都看不出有什么实际作用,到了工作上发现自己什么也不会干。
-
技术能力的瓶颈。你又是否觉得,在工作当中需要的技术只不过是不断地堆业务功能,完全没有什么技术含量。而你工作一段时间后,自己都感觉得非常地迷茫和彷徨,感觉到达了提高的瓶颈,完全不知道怎么提升了。
-
技术太多学不过来。你是否又觉得,要学的技术多得都不行了,完全不知道怎么学?感觉完全跟不上。有没有什么速成的方法?
对此,我有如下的一些解释,以端正一下你的态度。
- 并不是理论和现实的差距大,而是你还没有找到相关的场景,来感受到那些学院派知识的强大威力。算法与数据结构、操作系统原理、编译原理、数据库原理、计算机原理……这些原理上的东西,是你想要成为一个专家必须要学的东西。这就是“工人”和“工程师”的差别,是“建筑工人”和“建筑架构师”的差别。如果你觉得这些理论上的东西无用,那么只能说明,你只不过在从事工人的工作,而不是工程师的工作。
- 技术能力的瓶颈,以及技术太多学不过来,只不过是你为自己的能力不足或是懒惰找的借口罢了。技术的东西都是死的,这些死的知识只要努力就是可以学会的。只不过聪明的人花得时间少,笨点的人花得时间多点罢了。这其中的时间差距主要是由学习方法的不同,基础知识储备的不同决定的。只要你方法得当,多花点时间在基础知识上,会让你未来学习应用知识的时间大大缩短。以绝大多数人努力的程度,和为自己不努力找借口的程度为参考,只要你坚持正常的学习就可以超过大多数人了。
- 这里没有学习技术的速成的方法,真正的牛人不是能够培训出来的,一切都是要靠你自己去努力和持续地付出。如果你觉得自己不是一个能坚持的人,也不是一个想努力的人,而是一个想找捷径的人,那么,这篇文章并不适合你。这篇文章中的成长路径是需要思考、精力和相关的经验的,这都需要时间,而且是不短的时间。你先问问自己有没有花十年磨一剑的决心,如果没有,那这篇文章对你没有任何作用。
学习建议。
- 一定要坚持,要保持长时间学习,甚至终生学习的态度。
- 一定要动手,不管例子多么简单,建议至少自己动手敲一遍看看是否理解了里头的细枝末节。
- 一定要学会思考,思考为什么要这样,而不是那样。还要举一反三地思考。
- 不要乱买书,不要乱追新技术新名词,基础的东西经过很长时间积累,会在未来至少 10 年通用。
- 回顾一下历史,看看历史时间线上技术的发展,你才能明白明天会是什么样的。
操作系统入门 Linux
学习编程你还需要会玩 Linux,虽然 Windows 占据着更多的桌面市场,但是你还是要了解 Linux。这里,你可以看一下,W3CSchool 上的在线教程 Linux 教程。
记得要看官方文档!!!!!
编程技能
在系统地学习编程技能之前,我希望你能先看一下 " The Key To Accelerating Your Coding Skills", 这篇文章会告诉你如何有效地快速提高自己的编程能力。
然后接下来是下面几大块内容,但还只是入门级的。
- 编程技巧方面 - 你可以开始看怎么把程序写好的书了,这里推荐的是**《代码大全》**。这本书好多年没有更新了,其中有一些内容可能有点过时,但还是一本非常好的书,有点厚,你不需要马上就看完。在你的编程路上,这本书可以陪你走很久,因为当你有更多的编程经验时,踩过更多的坑后,再把这本书拿出来看看,你会有更多的体会。好的书和不好的书最大的区别就是,好的书在你不同的阶段来读,你会有不同的收获,而且还会产生更多的深层次的思考! 《代码大全》就是这样的一本书。
- 编程语言方面 - 这个阶段,你可以开始了解一下 Java 语言了,我个人觉得 Java 是世界上目前为止综合排名最好的语言。你一定要学好这门语言。推荐《Java 核心技术(卷 1)》,除了让你了解 Java 的语法,它还会让你了解面向对象编程是个什么概念(如果你觉得这本书有点深,那么,你可以降低难度看更为基础的《Head First Java》)。然后,既然开始学习 Java 了,那就一定要学 Spring,推荐看看《Spring in Action》或是直接从最新的 Spring Boot 开始,推荐看看《Spring Boot 实战》。关于 Spring 的这两本书,里面可能会有很多你从来没有听说过的东西,比如,IoC 和 AOP 之类的东西,能看懂多少就看懂多少,没事儿。——Spring实战
- 操作系统 - 这里你可以看看《鸟哥的 Linux 私房菜》,这本书会让你对计算机和操作系统,以及 Linux 有一个非常全面的了解,并能够管理或是操作好一个 Linux 系统。当然,这本书有很多比较专业的知识,你可能会看不懂,没关系,就暂时略过就好了。这本书的确并不适合初学者,你能看多少就看多少吧。
- 网络协议 - 你需要系统地了解一下 HTTP 协议,请到 MDN 阅读一下其官方的 HTTP 的文档。你需要知道 HTTP 协议的几个关键点:1)HTTP 头,2)HTTP 的请求方法,3)HTTP 的返回码。还有,HTTP 的 Cookie、缓存、会话,以及链接管理,等等,在 MDN 的这个文档中都有了。对于 HTTP 协议,你不需要知道所有的东西,你只需要了解这个协议的最关键的那些东西就好了。
- 数据库设计 - 你需要系统地了解一下数据库设计中的那些东西,这里推荐慕课网的一个在线课程:数据库设计的那些事。每个小课程不过 5-6 分钟,全部不到 2 个小时,我相信你一定能跟下来。你需要搞清楚数据的那几个范式,还有 SQL 语句的一些用法。当然,你还要学习和使用一下数据库,这里推荐学习开源的 MySQL。你可以看官方文档,也可以看一下这本书《MySQL 必知必会》。
- 前端方面 - 前端的东西不算复杂,你需要学习几个东西。一个是和 JavaScript 相关的 jQuery,另一个是和 CSS 相关的 Bootstrap,学习这两个东西都不复杂,直接上其官网看文档就好了。最重要的是,你要学习一下如何使用 JavaScript Ajax 请求后端的 API 接口,而不是再像前面那样用后端来向前端返回 HTML 页面的形式了。这里,你需要学习一下,JavaScript 的 Promise 模式。阮一峰翻译的 ES6 的教程中有相关的内容。当然,你 Google 一下,也可以找到一堆学习资料。
- 字符编码方面 - 在你处理中文时有时会发现有乱码出现,此时需要了解 ASCII 和 Unicode 这样的字符编码。这里推荐一篇文章 - “关于字符编码,你所需要知道的(ASCII,Unicode,Utf-8,GB2312…)” 或是英文文章 “The history of Character Encoding” 以及 Wikipedia - Character encoding。还有 GitHub 上的这两个 Awesome 仓库:Awesome Unicode 和 Awesome Code Points。
专业基础篇
编程语言
Java 语言
学习 Java 语言有以下入门级的书(注意:下面一些书在入门篇中有所提及,但为了完整性,还是要在这里提一下,因为可能有朋友是跳着看的)。
- 《Java 核心技术:卷 1 基础知识》,这本书本来是 Sun 公司的官方用书,是一本 Java 的入门参考书。对于 Java 初学者来说,是一本非常不错的值得时常翻阅的技术手册。书中有较多地方进行 Java 与 C++ 的比较,因为当时 Java 面世的时候,又被叫作 “C++ Killer”。而我在看这本书的时候,发现书中有很多 C++ 的东西,于是又去学习了 C++。学习 C++ 的时候,发现有很多 C 的东西不懂,又顺着去学习了 C。然后,C -> C++ -> Java 整条线融汇贯通,这对我未来的技术成长有非常大的帮助。
- 有了上述的入门后,Java 的 Spring 框架是你玩 Java 所无法回避的东西,所以接下来是两本 Spring 相关的书,《Spring 实战》和《Spring Boot 实战》。前者是传统的 Spring,后者是新式的微服务的 Spring。如果你只想看一本的话,那么就看后者吧。
前面推荐的几本书可以帮你成功入门 Java,但想要进一步成长,就要看下面我推荐的几本进阶级别的书了。
-
接下来,你需要了解了一下如何编写高效的代码,于是必需看一下《Effective Java》(注意,这里我给的引用是第三版的,也是 2017 年末出版的书),这本书是模仿 Scott Meyers 的经典图书《Effective C++》的。Effective 这种书基本上都是各种经验之谈,所以,这是一本非常不错的书,你一定要读。这里需要推荐一下 Google Guava 库 ,这个库不但是 JDK 的升级库,其中有如:集合(collections)、缓存(caching)、原生类型支持(primitives support)、并发库(concurrency libraries)、通用注解(common annotations)、字符串处理(string processing)、I/O 等库,其还是 Effective Java 这本书中的那些经验的实践代表。
-
《Java 并发编程实战》,是一本完美的 Java 并发参考手册。书中从并发性和线程安全性的基本概念出发,介绍了如何使用类库提供的基本并发构建块,用于避免并发危险、构造线程安全的类及验证线程安全的规则,如何将小的线程安全类组合成更大的线程安全类,如何利用线程来提高并发应用程序的吞吐量,如何识别可并行执行的任务,如何提高单线程子系统的响应性,如何确保并发程序执行预期任务,如何提高并发代码的性能和可伸缩性等内容。最后介绍了一些高级主题,如显式锁、原子变量、非阻塞算法以及如何开发自定义的同步工具类。
-
了解如何编写出并发的程序,你还需要了解一下如何优化 Java 的性能。我推荐《Java 性能权威指南》。通过学习这本书,你可以比较大程度地提升性能测试的效果。其中包括:使用 JDK 中自带的工具收集 Java 应用的性能数据,理解 JIT 编译器的优缺点,调优 JVM 垃圾收集器以减少对程序的影响,学习管理堆内存和 JVM 原生内存的方法,了解如何最大程度地优化 Java 线程及同步的性能,等等。看完这本书后,如果你还有余力,想了解更多的底层细节,那么,你有必要去读一下《深入理解 Java 虚拟机》。
-
《Java 编程思想》,真是一本透着编程思想的书。上面的书让你从微观角度了解 Java,而这本书则可以让你从一个宏观角度了解 Java。这本书和 Java 核心技术的厚度差不多,但这本书的信息密度比较大。所以,读起来是非常耗大脑的,因为它会让你不断地思考。对于想学好 Java 的程序员来说,这是一本必读的书。
-
《精通 Spring 4.x》,也是一本很不错的书,就是有点厚,一共有 800 多页,都是干货。我认为其中最不错的是在分析原理,尤其是针对前面提到的 Spring 技术,应用与原理都讲得很透彻,IOC 和 AOP 也分析得很棒,娓娓道来。其对任何一个技术都分析得很细致和全面,不足之处就是内容太多了,所以导致很厚,但这并不影响它是一本不错的工具书。
当然,学 Java 你一定要学面向对象的设计模式,这里就只有一本经典的书《设计模式》。如果你觉得有点儿难度了,那么可以看一下《Head First 设计模式》。学习面向对象的设计模式时,你不要迷失在那 23 个设计模式中,你一定要明白这两个原则:
-
Program to an ‘interface’, not an 'implementation’
- 使用者不需要知道数据类型、结构、算法的细节。
- 使用者不需要知道实现细节,只需要知道提供的接口。
- 利于抽象、封装,动态绑定,多态。符合面向对象的特质和理念。
-
Favor ‘object composition’ over 'class inheritance’
- 继承需要给子类暴露一些父类的设计和实现细节。
- 父类实现的改变会造成子类也需要改变。
- 我们以为继承主要是为了代码重用,但实际上在子类中需要重新实现很多父类的方法。
- 继承更多的应该是为了多态。
至此,如果你把上面的这些知识都融汇贯通的话,那么,你已是一个高级的 Java 程序员了,我保证你已经超过了绝大多数程序员了。基本上来说,你在技术方面是可以进入到一线公司的,而且还不是一般的岗位,至少是高级程序员或是初级架构师的级别了。
学习 Go 语言
C 语言太原始了,C++ 太复杂了,Go 语言是不二之选。有了 C/C++ 的功底,学习 Go 语言非常简单。
首推 Go by Example 作为你的入门教程。然后,Go 101 也是一个很不错的在线电子书。如果你想看纸书的话,The Go Programming Language 一书在豆瓣上有 9.2 分,但是国内没有卖的。(当然,我以前也写过两篇入门的供你参考 “GO 语言简介(上)- 语法” 和 “GO 语言简介(下)- 特性”)。
另外,Go 语言官方的 Effective Go 是必读的,这篇文章告诉你如何更好地使用 Go 语言,以及 Go 语言中的一些原理。
Go 语言最突出之处是并发编程,Unix 老牌黑客罗勃·派克(Rob Pike)在 Google I/O 上的两个分享,可以让你学习到一些并发编程的模式。
- Go Concurrency Patterns( 幻灯片和演讲视频)。
- Advanced Go Concurrency Patterns(幻灯片、演讲视频)。
然后,Go 在 GitHub 的 wiki 上有好多不错的学习资源,你可以从中学习到多。比如:
- Go 精华文章列表。
- Go 相关博客列表。
- Go Talks。
此外,还有个内容丰富的 Go 资源列表 Awesome Go,推荐看看。
理论学科
数据结构和算法
算法是比较难学习的,而且学习“算法”是需要智商的。数组、链表、哈希表、二叉树、排序算法等一些基础知识,对大多数人来说是没什么问题的。但是一旦进入到路径规划、背包问题、字符串匹配、动态规划、递归遍历等一些比较复杂的问题上,就会让很多人跟不上了,不但跟不上,而且还会非常痛苦。是的,解决算法问题的确是可以区分人类智商的一个比较好的方式,这也是为什么好些公司用算法题当面试题来找到智商比较高的程序员。
然而,在很多时候,我们在工作中却发现根本用不到算法,或是一些基本的算法也没有必要实现,只需要使用一下第三方的库就好了。于是,导致社会上出现很多“算法无用论”的声音。
对此,我想说,算法真的很重要。我这 20 年的经历告诉我,无论是做业务还是做底层系统,经常需要使用算法处理各种各样的问题。比如,业务上我需要用算法比较两个数组中差异的布隆过滤器,或是在做监控系统时实时计算过去一分钟的 P99 统计时的蓄水池算法,或是数据库的 B+ 树索引,还有 Linux 内核中的 epoll 的红黑树,还有在做服务调度里的“背包问题”等都会用算法,真的是会本质上帮助到你,也是会让你瞬间会产生成就感的事情。
虽然算法很难,需要智商,但我还是想鼓励你,这其中是有很多的套路是可以学习的,一旦学会这些套路,你会受益无穷的。
这里有几本书着重推荐一下。
- 基础知识。《算法》,是算法领域经典的参考书,不但全面介绍了关于算法和数据结构的必备知识,还给出了每位程序员应知应会的 50 个算法,并提供了实际代码。最不错的是,其深入浅出的算法介绍,让一些比较难的算法也变得容易理解,尤其是书中对红黑树的讲解非常精彩。其中,还有大量的图解,详尽的代码和讲解,也许是最好的数据结构入门图书。不好的是不深,缺乏进一步的算法设计内容,甚至连动态规划都未提及。另外,如果你觉得算法书比较枯燥的话,你可以看看这本有趣的《算法图解》。
- 理论加持。如果说上面这本书偏于实践和工程,而你看完后,对算法和数据结构的兴趣更浓了,那么你可以再看看另一本也是很经典的偏于理论方面的书——《算法导论》。虽然其中的一些理论知识在《算法》那本书中也有提过,但《算法导论》这本书更为专业一些,是美国计算机科学本科生的教科书。
- 思维改善。还有一本叫《编程珠玑》的书,写这本书的人是世界著名计算机科学家乔恩·本特利(Jon Bentley),被誉为影响算法发展的十位大师之一。你可能不认识这个人,但是你知道他的学生有多厉害吗?我例举几个,一个是 Tcl 语言设计者约翰·奥斯德奥特(John Ousterhout),另一个是 Java 语言设计者詹姆斯·高斯林(James Gosling),还有一个是《算法导论》作者之一查尔斯·雷斯尔森(Charles Leiserson),还有好多好多。这本书也是很经典的算法书,其中都是一些非常实际的问题,并以其独有的洞察力和创造力,来引导读者理解并学会解决这些问题的方法,也是一本可以改善你思维方式的书。
然后,你需要去做一些题来训练一下自己的算法能力,这里就要推荐 LeetCode 这个网站了。它是一个很不错的做算法训练的地方。现在也越做越好了。基本上来说,这里会有两类题。
- 基础算法题。其中有大量的算法题,解这些题都是有套路的,不是用递归(深度优先 DFS、广度优先 BFS),就是要用动态规划(Dynamic Programming),或是折半查找(Binary Search),或是回溯(Back tracing),或是分治法(Divide and Conquer),还有大量的对树、数组、链表、字符串和 hash 表的操作。通过做这些题能让你对这些最基础的算法的思路有非常扎实的了解和训练。对我而言,Dynamic Programming 是我的短板,尤其是一些比较复杂的问题,在推导递推公式上总是有思维的缺陷(数学是我的硬伤)。做了这些题后,我能感到我在动态编程的思路上受到了很大的启发。
- 编程题。比如:atoi、strstr、add two nums、括号匹配、字符串乘法、通配符匹配、文件路径简化、Text Justification、反转单词等,这些题的 Edge Case 和 Corner Case 有很多。这些题需要你想清楚了再干,只要你稍有疏忽,就会有几个 case 让你痛不欲生,而且一不小心就会让你的代码写得又臭又长,无法阅读。通过做这些题,可以非常好地训练你对各种情况的考虑,以及你对程序代码组织的掌控(其实就是其中的状态变量)。
我觉得每个程序员都应该花时间和精力做这些题,因为你会从这些题中得到很大的收益。我在 Leetcode 上做的一些题的代码在这——我的 GitHub 上,可以给你一些参考。
如果能够把这些算法能力都掌握了,那么你就有很大的概率可以很容易地通过这世界上最优的公司的面试,比如:Google、Amazon、Facebook 之类的公司。对你来说,如果能够进入到这些公司里工作,那么你未来的想像空间也会大很多。
最后,我们要知道这个世界上的数据结构和算法有很多,下面给出了两个网站。
- List of Algorithms ,这个网站罗列了非常多的算法,完全可以当成一个算法字典,或是用来开阔眼界。
- 还有一个数据结构动画图的网站 Data Structure Visualizations。
其它理论基础知识
下面这些书,基本上是计算机科学系的大学教材。如果你想有科班出身的理论基础,那么这些书是必读的。当然,这些理论基础知识比较枯燥,但我觉得如果你想成为专业的程序员,那么应该要找时间读一下。
- 《数据结构与算法分析》,这本书曾被评为 20 世纪顶尖的 30 部计算机著作之一,作者 Mark Allen Weiss 在数据结构和算法分析方面卓有建树,他在数据结构和算法分析等方面的著作尤其畅销,并广受好评,已被世界 500 余所大学用作教材。
- 《数据库系统概念》,它是数据库系统方面的经典教材之一。国际上许多著名大学包括斯坦福大学、耶鲁大学、德克萨斯大学、康奈尔大学、伊利诺伊大学、印度理工学院等都采用本书作为教科书。这本书全面介绍了数据库系统的各种知识,透彻阐释数据库管理的基本概念。不仅讨论了数据库查询语言、模式设计、数据仓库、数据库应用开发、基于对象的数据库和 XML、数据存储和查询、事务管理、数据挖掘与信息检索以及数据库系统体系结构等方面的内容,而且对性能评测标准、性能调整、标准化以及空间与地理数据、事务处理监控等高级应用主题进行了广泛讨论。
- 《现代操作系统》,这本书是操作系统领域的经典之作,书中集中讨论了操作系统的基本原理,包括进程、线程、存储管理、文件系统、输入 / 输出、死锁等,同时还包含了有关计算机安全、多媒体操作系统、掌上计算机操作系统、微内核、多核处理机上的虚拟机以及操作系统设计等方面的内容。
- 《计算机网络》,这本书采用了独创的自顶向下方法,即从应用层开始沿协议栈向下讲解计算机网络的基本原理,强调应用层范例和应用编程接口,内容深入浅出,注重教学方法,理论与实践相结合。新版中还增加了无线和移动网络一章,并扩充了对等网络、BGP、MPLS、网络安全、广播选路和因特网编址及转发方面的材料。是一本不可多得的教科书。
- 《计算机程序的构造和解释》,这本书也很经典,是 MIT 的计算机科学系的教材。这本书中主要证实了很多程序是怎么构造出来的,以及程序的本质是什么。整本书主要是使用 Scheme/Lisp 语言,从数据抽象、过程抽象、迭代、高阶函数等编程和控制系统复杂性的思想,到数据结构和算法,到编译器 / 解释器、编程语言设计。
- 《编译原理》,这本书又叫 " 龙书 ",其全面、深入地探讨了编译器设计方面的重要主题,包括词法分析、语法分析、语法制导定义和语法制导翻译、运行时刻环境、目标代码生成、代码优化技术、并行性检测以及过程间分析技术,并在相关章节中给出大量的实例。与上一版相比,本书进行了全面的修订,涵盖了编译器开发方面的最新进展。每章中都提供了大量的系统及参考文献。
系统知识
进入专业的编程领域,学习系统知识是非常关键的一部分。
首先推荐的是翻译版图书《深入理解计算机系统》,原书名为《Computer Systems A Programmer’s Perspective》。不过,这本书叫做《程序员所需要了解的计算机知识》更为合适。
本书的最大优点是为程序员描述计算机系统的实现细节,帮助其在大脑中构造一个层次型的计算机系统。从最底层的数据在内存中的表示到流水线指令的构成,到虚拟存储器,到编译系统,到动态加载库,到最后的用户态应用。通过掌握程序是如何映射到系统上,以及程序是如何执行的,你能够更好地理解程序的行为为什么是这样的,以及效率低下是如何造成的。
再强调一下,这本书是程序员必读的一本书!
然后就是美国计算机科学家 理查德·史蒂文斯(Richard Stevens) 的三套巨经典无比的书。(理查德·史蒂文斯于 1999 年 9 月 1 日离世,终年 48 岁。死因不详,有人说是滑雪意外,有人说是攀岩意外,有人说是滑翔机意外。总之,家人没有透露。大师的 个人主页 今天还可以访问。)
- 《Unix 高级环境编程》。
- 《Unix 网络编程》 第 1 卷 套接口 API 、第 2 卷 进程间通信 。
- 《TCP/IP 详解 卷 I 协议》。
这几本书的地位我就不多说了,你可以自己看相关的书评。但是,这三本书可能都不容易读,一方面是比较厚,另一方面是知识的密度太大了,所以,读起来有点枯燥和乏味。但是,这没办法,你得忍住。
这里要重点说一下《TCP/IP 详解》这本书,是一本很奇怪的书。这本书迄今至少被 近五百篇学术论文引用过 。这本写给工程师看的书居然被各种学院派的论文来引用,也是很神奇的一件事了。而且,虽然理查德·史蒂文斯不是 TCP 的发明人,但是这本书中把这个协议深入浅出地讲出来,还画了几百张时序图,也是令人叹为观止了。
如果你觉得上面这几本经典书比较难啃,你可以试试下面这些通俗易懂的(当然,如果读得懂上面那三本的,下面的这些也就不需要读了)。
- 《Linux C 编程一站式学习》。
- 《TCP/IP 网络编程》。
- 《图解 TCP/IP》,这本书其实并不是只讲了 TCP/IP,应该是叫《计算机网络》才对,主要是给想快速入门的人看的。
- 《The TCP/IP Guide》,这本书在豆瓣上的评分 9.2,这里给的链接是这本书的 HTML 英文免费版的,里面的图画得很精彩。
另外,学习网络协议不单只是看书,你最好用个抓包工具看看这些网络包是什么样的。所以,这里推荐一本书《Wireshark 数据包分析实战》。在这本书中,作者结合一些简单易懂的实际网络案例,图文并茂地演示使用 Wireshark 进行数据包分析的技术方法,可以让我们更好地了解和学习网络协议。当然,也拥有了一定的黑客的技能。
看完《Unix 高级环境编程》后,你可以趁热打铁看看《Linux/Unix 系统编程手册》或是罗伯特·拉姆(Robert Love)的 Linux System Programming 英文电子版 。其中文翻译版Linux 系统编程 也值得一读,虽然和《Unix 高级环境编程》很像,不过其主要突出的是 Linux 的一些关键技术和相关的系统调用。
关于 TCP 的东西,你还可以看看下面这一系列的文章。
- Let’s code a TCP/IP stack, 1: Ethernet & ARP
- Let’s code a TCP/IP stack, 2: IPv4 & ICMPv4
- Let’s code a TCP/IP stack, 3: TCP Basics & Handshake
- Let’s code a TCP/IP stack, 4: TCP Data Flow & Socket API
- Let’s code a TCP/IP stack, 5: TCP Retransmission
对于系统知识,我认为主要有以下一些学习要点。
- 用这些系统知识操作一下文件系统,实现一个可以拷贝目录树的小程序。
- 用 fork / wait / waitpid 写一个多进程的程序,用 pthread 写一个多线程带同步或互斥的程序。比如,多进程购票的程序。
- 用 signal / kill / raise / alarm / pause / sigprocmask 实现一个多进程间的信号量通信的程序。
- 学会使用 gcc 和 gdb 来编程和调试程序(参看我的《用 gdb 调试程序》一、二、三、四、五、六、七)。
- 学会使用 makefile 来编译程序(参看我的《跟我一起写 makefile》一、二、三、四、五、六、七、八、九、十、十一、十二、十三、十四)。
- Socket 的进程间通信。用 C 语言写一个 1 对 1 的聊天小程序,或是一个简单的 HTTP 服务器。
C10K 问题
然后,当你读完《Unix 网络编程》后,千万要去读一下 “C10K Problem (中文翻译版)”。提出这个问题的人叫丹·凯格尔(Dan Kegel),目前在 Google 任职。
他从 1978 年起开始接触计算机编程,是 Winetricks 的作者,也是 Wine 1.0 的管理员,同时也是 Crosstool( 一个让 gcc/glibc 编译器更易用的工具套件)的作者。还是 Java JSR 51 规范的提交者并参与编写了 Java 平台的 NIO 和文件锁,同时参与了 RFC 5128 标准中有关 NAT 穿越(P2P 打洞)技术的描述和定义。
C10K 问题本质上是操作系统处理大并发请求的问题。对于 Web 时代的操作系统而言,对于客户端过来的大量的并发请求,需要创建相应的服务进程或线程。这些进程或线程多了,导致数据拷贝频繁(缓存 I/O、内核将数据拷贝到用户进程空间、阻塞), 进程 / 线程上下文切换消耗大,从而导致资源被耗尽而崩溃。这就是 C10K 问题的本质。
了解这个问题,并了解操作系统是如何通过多路复用的技术来解决这个问题的,有助于你了解各种 I/O 和异步模型,这对于你未来的编程和架构能力是相当重要的。
另外,现在,整个世界都在解决 C10M 问题,推荐看看 The Secret To 10 Million Concurrent Connections -The Kernel Is The Problem, Not The Solution 一文。
实践项目
我们已经学习完了编程语言、理论学科和系统知识三部分内容,下面就来做几个实践项目,小试牛刀一下。实现语言可以用 C、C++ 或 Java。
实现一个 telnet 版本的聊天服务器,主要有以下需求。
- 每个客户端可以用使用
telnet ip:port
的方式连接到服务器上。 - 新连接需要用用户名和密码登录,如果没有,则需要注册一个。
- 然后可以选择一个聊天室加入聊天。
- 管理员有权创建或删除聊天室,普通人员只有加入、退出、查询聊天室的权力。
- 聊天室需要有人数限制,每个人发出来的话,其它所有的人都要能看得到。
实现一个简单的 HTTP 服务器,主要有以下需求。
- 解释浏览器传来的 HTTP 协议,只需要处理 URL path。
- 然后把所代理的目录列出来。
- 在浏览器上可以浏览目录里的文件和下级目录。
- 如果点击文件,则把文件打开传给浏览器(浏览器能够自动显示图片、PDF,或 HTML、CSS、JavaScript 以及文本文件)。
- 如果点击子目录,则进入到子目录中,并把子目录中的文件列出来。
实现一个生产者 / 消费者消息队列服务,主要有以下需求。
- 消息队列采用一个 Ring-buffer 的数据结构。
- 可以有多个 topic 供生产者写入消息及消费者取出消息。
- 需要支持多个生产者并发写。
- 需要支持多个消费者消费消息(只要有一个消费者成功处理消息就可以删除消息)。
- 消息队列要做到不丢数据(要把消息持久化下来)。
- 能做到性能很高。
到今天,我们已经学习完了专业编程方面最为重要的三部分内容:编程语言、理论学科和系统知识,我们针对这些内容做个小结。如果想看完我推荐的那些书和知识,并能理解和掌握,我估计怎么也得需要 4-5 年的时间。嗯,是的,就是一个计算机科学系科班出身的程序员需要学习的一些东西。这其中,最重要的是下面这几点。
编程语言。以工业级的 C、C++、Java 这三门语言为主,这三门语言才是真正算得上工业级的编程语言,因为有工业级的标准化组织在控制着这几门语言,而且也有工业级的企业应用。尤其是 Java,还衍生出了大量的企业级架构上的开源生态。你至少需要掌握 C 语言和 Java 语言,这对你以后面对各式各样的编程语言是非常重要的。
此外,还推荐学习 Go 语言,它已成为云计算领域事实上的标准语言,尤其是在 Docker、Kubernetes 等项目中。而且,Go 语言在国内外一些知名公司中有了一定的应用和实践,并且其生态圈也越来越好。
算法和数据结构。这个太重要了,尤其是最基础的算法和数据结构,这是任何一个称职的程序员都需要学习和掌握的。你必需要掌握。
计算机的相关系统。你至少要掌握三个系统的基础知识,一个是操作系统,一个是网络系统,还有一个是数据库系统。它们分别代表着计算机基础构架的三大件——计算、存储、网络。
如果你能够走到这里,把前面的那些知识都了解了(不用精通,因为精通是需要时间和实践来慢慢锤炼出来的,所以,你也不用着急),那么你已经是一个合格的程序员了,而且你的潜力和可能性是非常非常高的。
如果经历过这些比较枯燥的理论知识,而且你还能有热情和成就感,那么我要恭喜你了。因为你已经超过了绝大多数人,而且还是排在上游的比较抢手的程序员了。我相信你至少可以找到年薪 50 万以上的工作了。
但是,你还需要很多的经验或是一些实践,以及一些大系统大项目的实际动手的经验。没关系,我们后面会有教你怎么实操的方法和攻略。
但是,往后面走,你需要开始需要术业有专攻了。下面给一些建议的方向。
- 底层方向:操作系统、文件系统、数据库、网络……
- 架构方向:分布式系统架构、微服务、DevOps、Cloud Native……
- 数据方向:大数据、机器学习、人工智能……
- 前端方向:你对用户体验或是交互更感兴趣,那么你走前端的路吧。
- 其它方向:比如,安全开发、运维开发、嵌入式开发……
这些方向你要仔细选择,因为一旦选好,就要勇往直前地走下去,当然,你要回头转别的方向也没什么问题,因为你有前面的这些基础知识在身,所以,不用害怕。只是不同的方向上会有不同的经验积累,经验积累是看书看不来的,这个是转方向的成本。
下篇文章,我们将进入《软件设计篇》。敬请期待。
软件设计篇
编程范式
编程范式
学习编程范式可以让你明白编程的本质和各种语言的编程方式。因此,我推荐以下一些资料,以帮助你系统化地学习和理解。
-
一个是我在极客时间写的《编程范式游记》系列文章,目录如下。
- 编程范式游记(1)- 起源
- 编程范式游记(2)- 泛型编程
- 编程范式游记(3)- 类型系统和泛型的本质
- 编程范式游记(4)- 函数式编程
- 编程范式游记(5)- 修饰器模式
- 编程范式游记(6)- 面向对象编程
- 编程范式游记(7)- 基于原型的编程范式
- 编程范式游记(8)- Go 语言的委托模式
- 编程范式游记(9)- 编程的本质
- 编程范式游记(10)- 逻辑编程范式
- 编程范式游记(11)- 程序世界里的编程范式
-
Wikipedia: Programming paradigm ,维基百科上有一个编程范式的页面,顺着这个页面看下去,你可以看到很多很多有用的和编程相关的知识。这些东西对你的编程技能的提高会非常非常有帮助。
-
Six programming paradigms that will change how you think about coding,中文翻译版为 六个编程范型将改变你对编程的看法。这篇文章讲了默认支持并发(Concurrent by default)、依赖类型(Dependent types)、连接性语言(Concatenative languages)、声明式编程(Declarative programming)、符号式编程(Symbolic programming)、基于知识的编程(Knowledge-based programming)等六种不太常见的编程范式,并结合了一些你没怎么听说过的语言来分别进行讲述。
比如在讲 Concatenative languages 时,以 Forth、cat 和 joy 三种语言为例讲述这一编程范式背后的思想——语言中的所有内容都是一个函数,用于将数据推送到堆栈或从堆栈弹出数据;程序几乎完全通过功能组合来构建(concatenation is composition)。作者认为,这些编程范式背后的思想十分有魅力,能够改变对编程的思考。我看完此文,对此也深信不疑。虽然这些语言和编程范式不常用到,但确实能在思想层面给予人很大的启发。这也是我推荐此文的目的。
-
Programming Paradigms for Dummies: What Every Programmer Should Know ,这篇文章的作者彼得·范·罗伊(Peter Van Roy)是比利时鲁汶大学的计算机科学教师。他在这篇文章里分析了编程语言在历史上的演进,有哪些典型的、值得研究的案例,里面体现了哪些值得学习的范式。
比如,在分布式编程领域,他提到了 Erlang、E、Distributed Oz 和 Didactic Oz 这四种编程语言。虽然它们都是分布式编程语言,但各有特色,各自解决了不同的问题。通过这篇文章能学到不少在设计编程语言时要考虑的问题,让你重新审视自己所使用的编程语言应该怎样用才能用好,有什么局限性,这些局限性能否被克服等。
-
斯坦福大学公开课:编程范式,这是一门比较基础且很详细的课程,适合学习编程语言的初学者。它通过讲述 C、C++、并发编程、Scheme、Python 这 5 门语言,介绍了它们各自不同的编程范式。以 C 语言为例,它解释了 C 语言的基本要素,如指针、内存分配、堆、C 风格的字符串等,并解释了为什么 C 语言会在泛型编程、多态等方面有局限性。通过学习这门课程,你会对一些常用的编程范式有所了解。
一些软件设计的相关原则
-
Don’t Repeat Yourself (DRY) ,DRY 是一个最简单的法则,也是最容易被理解的。但它也可能是最难被应用的(因为要做到这样,我们需要在泛型设计上做相当的努力,这并不是一件容易的事)。它意味着,当在两个或多个地方发现一些相似代码的时候,我们需要把它们的共性抽象出来形成一个唯一的新方法,并且改变现有地方的代码让它们以一些合适的参数调用这个新的方法。
-
Keep It Simple, Stupid(KISS) ,KISS 原则在设计上可能最被推崇,在家装设计、界面设计和操作设计上,复杂的东西越来越被众人所鄙视了,而简单的东西越来越被人所认可。宜家(IKEA)简约、高效的家居设计和生产思路;微软(Microsoft)“所见即所得”的理念;谷歌(Google)简约、直接的商业风格,无一例外地遵循了“KISS”原则。也正是“KISS”原则,成就了这些看似神奇的商业经典。而苹果公司的 iPhone 和 iPad 将这个原则实践到了极至。
-
Program to an interface, not an implementation,这是设计模式中最根本的哲学,注重接口,而不是实现,依赖接口,而不是实现。接口是抽象是稳定的,实现则是多种多样的。在面向对象的 S.O.L.I.D 原则中会提到我们的依赖倒置原则,就是这个原则的另一种样子。还有一条原则叫 Composition over inheritance(喜欢组合而不是继承),这两条是那 23 个经典设计模式中的设计原则。
-
You Ain’t Gonna Need It (YAGNI) ,这个原则简而言之为——只考虑和设计必须的功能,避免过度设计。只实现目前需要的功能,在以后你需要更多功能时,可以再进行添加。如无必要,勿增复杂性。软件开发是一场 trade-off 的博弈。
-
Law of Demeter,迪米特法则 (Law of Demeter),又称“最少知识原则”(Principle of Least Knowledge),其来源于 1987 年荷兰大学的一个叫做 Demeter 的项目。克雷格·拉尔曼(Craig Larman)把 Law of Demeter 又称作“不要和陌生人说话”。在《程序员修炼之道》中讲 LoD 的那一章将其叫作“解耦合与迪米特法则”。
关于迪米特法则有一些很形象的比喻:1) 如果你想让你的狗跑的话,你会对狗狗说还是对四条狗腿说?2) 如果你去店里买东西,你会把钱交给店员,还是会把钱包交给店员让他自己拿?和狗的四肢说话?让店员自己从钱包里拿钱?这听起来有点儿荒唐,不过在我们的代码里这几乎是见怪不怪的事情了。对于 LoD,正式的表述如下:
对于对象 ‘O’ 中一个方法’M’,M 应该只能够访问以下对象中的方法:
- 对象 O;
- 与 O 直接相关的 Component Object;
- 由方法 M 创建或者实例化的对象;
- 作为方法 M 的参数的对象。
-
[面向对象的 S.O.L.I.D 原则](">http://en.wikipedia/wiki/Solid_(object-oriented_design):
- SRP(Single Responsibility Principle)- 职责单一原则。关于单一职责原则,其核心的思想是:一个类,只做一件事,并把这件事做好,其只有一个引起它变化的原因。单一职责原则可以看作是低耦合、高内聚在面向对象原则上的引申,将职责定义为引起变化的原因,以提高内聚性来减少引起变化的原因。
职责过多,可能引起它变化的原因就越多,这将导致职责依赖,相互之间就产生影响,从而极大地损伤其内聚性和耦合度。单一职责,通常意味着单一的功能,因此不要为一个模块实现过多的功能点,以保证实体只有一个引起它变化的原因。
- OCP(Open/Closed Principle)- 开闭原则。关于开发封闭原则,其核心的思想是:模块是可扩展的,而不可修改的。也就是说,对扩展是开放的,而对修改是封闭的。对扩展开放,意味着有新的需求或变化时,可以对现有代码进行扩展,以适应新的情况。对修改封闭,意味着类一旦设计完成,就可以独立完成其工作,而不要对类进行任何修改。
- LSP(Liskov substitution principle)- 里氏代换原则。软件工程大师罗伯特·马丁(Robert C. Martin)把里氏代换原则最终简化为一句话:“Subtypes must be substitutable for their base types”。也就是,子类必须能够替换成它们的基类。即子类应该可以替换任何基类能够出现的地方,并且经过替换以后,代码还能正常工作。另外,不应该在代码中出现 if/else 之类对子类类型进行判断的条件。里氏替换原则 LSP 是使代码符合开闭原则的一个重要保证。正是由于子类型的可替换性才使得父类型的模块在无需修改的情况下就可以扩展。
- ISP(Interface Segregation Principle )- 接口隔离原则。接口隔离原则的意思是把功能实现在接口中,而不是类中,使用多个专门的接口比使用单一的总接口要好。举个例子,我们对电脑有不同的使用方式,比如:写作、通讯、看电影、打游戏、上网、编程、计算和数据存储等。
如果我们把这些功能都声明在电脑的抽象类里面,那么,我们的上网本、PC 机、服务器和笔记本的实现类都要实现所有的这些接口,这就显得太复杂了。所以,我们可以把这些功能接口隔离开来,如工作学习接口、编程开发接口、上网娱乐接口、计算和数据服务接口,这样,我们的不同功能的电脑就可以有所选择地继承这些接口。
- DIP(Dependency Inversion Principle)- 依赖倒置原则。高层模块不应该依赖于低层模块的实现,而是依赖于高层抽象。举个例子,墙面的开关不应该依赖于电灯的开关实现,而是应该依赖于一个抽象的开关的标准接口。这样,当我们扩展程序的时候,开关同样可以控制其它不同的灯,甚至不同的电器。也就是说,电灯和其它电器继承并实现我们的标准开关接口,而开关厂商就可以不需要关于其要控制什么样的设备,只需要关心那个标准的开关标准。这就是依赖倒置原则。
-
CCP(Common Closure Principle) - 共同封闭原则,一个包中所有的类应该对同一种类型的变化关闭。一个变化影响一个包,便影响了包中所有的类。一个更简短的说法是:一起修改的类,应该组合在一起(同一个包里)。如果必须修改应用程序里的代码,那么我们希望所有的修改都发生在一个包里(修改关闭),而不是遍布在很多包里。
CCP 原则就是把因为某个同样的原因而需要修改的所有类组合进一个包里。如果两个类从物理上或者从概念上联系得非常紧密,它们通常一起发生改变,那么它们应该属于同一个包。CCP 延伸了开闭原则(OCP)的“关闭”概念,当因为某个原因需要修改时,把需要修改的范围限制在一个最小范围内的包里。
-
CRP(Common Reuse Principle)- 共同重用原则 ,包的所有类被一起重用。如果你重用了其中的一个类,就重用全部。换个说法是,没有被一起重用的类不应该组合在一起。CRP 原则帮助我们决定哪些类应该被放到同一个包里。依赖一个包就是依赖这个包所包含的一切。
当一个包发生了改变,并发布新的版本,使用这个包的所有用户都必须在新的包环境下验证他们的工作,即使被他们使用的部分没有发生任何改变。因为如果包中包含未被使用的类,即使用户不关心该类是否改变,但用户还是不得不升级该包并对原来的功能加以重新测试。CCP 则让系统的维护者受益。CCP 让包尽可能大(CCP 原则加入功能相关的类),CRP 则让包尽可能小(CRP 原则剔除不使用的类)。它们的出发点不一样,但不相互冲突。
-
好莱坞原则 - Hollywood Principle ,好莱坞原则就是一句话——“don’t call us, we’ll call you.”。意思是,好莱坞的经纪人不希望你去联系他们,而是他们会在需要的时候来联系你。也就是说,所有的组件都是被动的,所有的组件初始化和调用都由容器负责。
简单来讲,就是由容器控制程序之间的关系,而非传统实现中,由程序代码直接操控。这也就是所谓“控制反转”的概念所在:1) 不创建对象,而是描述创建对象的方式。2)在代码中,对象与服务没有直接联系,而是容器负责将这些联系在一起。控制权由应用代码中转到了外部容器,控制权的转移,是所谓反转。好莱坞原则就是IoC(Inversion of Control) 或DI(Dependency Injection)的基础原则。
-
高内聚, 低耦合 & - High Cohesion & Low/Loose coupling,这个原则是 UNIX 操作系统设计的经典原则,把模块间的耦合降到最低,而努力让一个模块做到精益求精。内聚,指一个模块内各个元素彼此结合的紧密程度;耦合指一个软件结构内不同模块之间互连程度的度量。内聚意味着重用和独立,耦合意味着多米诺效应牵一发动全身。对于面向对象来说,你也可以看看马萨诸塞州戈登学院的面向对象课中的这一节讲义High Cohesion and Low Coupling。
-
CoC(Convention over Configuration)- 惯例优于配置原则 ,简单点说,就是将一些公认的配置方式和信息作为内部缺省的规则来使用。例如,Hibernate 的映射文件,如果约定字段名和类属性一致的话,基本上就可以不要这个配置文件了。你的应用只需要指定不 convention 的信息即可,从而减少了大量 convention 而又不得不花时间和精力啰里啰嗦的东东。
配置文件在很多时候相当影响开发效率。Rails 中很少有配置文件(但不是没有,数据库连接就是一个配置文件)。Rails 的 fans 号称其开发效率是 Java 开发的 10 倍,估计就是这个原因。Maven 也使用了 CoC 原则,当你执行
mvn -compile
命令的时候,不需要指定源文件放在什么地方,而编译以后的 class 文件放置在什么地方也没有指定,这就是 CoC 原则。 -
SoC (Separation of Concerns) - 关注点分离 ,SoC 是计算机科学中最重要的努力目标之一。这个原则,就是在软件开发中,通过各种手段,将问题的各个关注点分开。如果一个问题能分解为独立且较小的问题,就是相对较易解决的。问题太过于复杂,要解决问题需要关注的点太多,而程序员的能力是有限的,不能同时关注于问题的各个方面。
正如程序员的记忆力相对于计算机知识来说那么有限一样,程序员解决问题的能力相对于要解决的问题的复杂性也是一样的非常有限。在我们分析问题的时候,如果我们把所有的东西混在一起讨论,那么就只会有一个结果——乱。实现关注点分离的方法主要有两种,一种是标准化,另一种是抽象与包装。标准化就是制定一套标准,让使用者都遵守它,将人们的行为统一起来,这样使用标准的人就不用担心别人会有很多种不同的实现,使自己的程序不能和别人的配合。
就像是开发镙丝钉的人只专注于开发镙丝钉就行了,而不用关注镙帽是怎么生产的,反正镙帽和镙丝钉按照标准来就一定能合得上。不断地把程序的某些部分抽象并包装起来,也是实现关注点分离的好方法。一旦一个函数被抽象出来并实现了,那么使用函数的人就不用关心这个函数是如何实现的。同样的,一旦一个类被抽象并实现了,类的使用者也不用再关注于这个类的内部是如何实现的。诸如组件、分层、面向服务等这些概念都是在不同的层次上做抽象和包装,以使得使用者不用关心它的内部实现细节。
-
DbC(Design by Contract)- 契约式设计 ,DbC 的核心思想是对软件系统中的元素之间相互合作以及“责任”与“义务”的比喻。这种比喻从商业活动中“客户”与“供应商”达成“契约”而得来。如果在程序设计中一个模块提供了某种功能,那么它要:
- 期望所有调用它的客户模块都保证一定的进入条件:这就是模块的先验条件(客户的义务和供应商的权利,这样它就不用去处理不满足先验条件的情况)。
- 保证退出时给出特定的属性:这就是模块的后验条件(供应商的义务,显然也是客户的权利)。
- 在进入时假定,并在退出时保持一些特定的属性:不变式。
-
ADP(Acyclic Dependencies Principle)- 无环依赖原则 ,包(或服务)之间的依赖结构必须是一个直接的无环图形,也就是说,在依赖结构中不允许出现环(循环依赖)。如果包的依赖形成了环状结构,怎么样打破这种循环依赖呢?
有两种方法可以打破这种循环依赖关系:第一种方法是创建新的包,如果 A、B、C 形成环路依赖,那么把这些共同类抽出来放在一个新的包 D 里。这样就把 C 依赖 A 变成了 C 依赖 D 以及 A 依赖 D,从而打破了循环依赖关系。第二种方法是使用 DIP(依赖倒置原则)和 ISP(接口分隔原则)设计原则。无环依赖原则(ADP)为我们解决包之间的关系耦合问题。在设计模块时,不能有循环依赖。
一些软件设计的读物
- 《领域驱动设计》 ,本书是领域驱动设计方面的经典之作。全书围绕着设计和开发实践,结合若干真实的项目案例,向读者阐述如何在真实的软件开发中应用领域驱动设计。书中给出了领域驱动设计的系统化方法,并将人们普遍接受的一些实践综合到一起,融入了作者的见解和经验,展现了一些可扩展的设计新实践、已验证过的技术以及便于应对复杂领域的软件项目开发的基本原则。
- 《UNIX 编程艺术》 ,这本书主要介绍了 Unix 系统领域中的设计和开发哲学、思想文化体系、原则与经验,由公认的 Unix 编程大师、开源运动领袖人物之一埃里克·雷蒙德(Eric S. Raymond)倾力多年写作而成。包括 Unix 设计者在内的多位领域专家也为本书贡献了宝贵的内容。本书内容涉及社群文化、软件开发设计与实现,覆盖面广、内容深邃,完全展现了作者极其深厚的经验积累和领域智慧。
- 《Clean Architecture》,如果你读过 《Clean Code》 和 《The Clean Coder》这两本书。你就能猜得到这种 Clean 系列一定也是出自“Bob 大叔”之手。没错,就是 Bob 大叔的心血之作。除了这个网站,《Clean Architecture》也是一本书,这是一本很不错的架构类图书。对软件架构的元素、方法等讲得很清楚。示例都比较简单,并带一些软件变化历史的讲述,很开阔视野。
- The Twelve-Factor App ,如今,软件通常会作为一种服务来交付,它们被称为网络应用程序,或软件即服务(SaaS)。12-Factor 为构建 SaaS 应用提供了方法论,这也是架构师必读的文章。(中译版) 这篇文章在业内的影响力很大,必读!
- Avoid Over Engineering ,有时候,我们会过渡设计我们的系统,过度设计会把我们带到另外一个复杂度上,所以,我们需要一些工程上的平衡。这篇文章是一篇非常不错地告诉你什么是过度设计的文章。
- Instagram Engineering’s 3 rules to a scalable cloud application architecture ,Instagram 工程的三个黄金法则:1)使用稳定可靠的技术(迎接新的技术);2)不要重新发明轮子;3)Keep it very simple。我觉得这三条很不错。其实,Amazon 也有两条工程法则,一个是自动化,一个是简化。
- How To Design A Good API and Why it Matters - Joshua Bloch ,Google 的一个分享,关于如何设计好一个 API。
- 关于 Restful API 的设计,你可以学习并借鉴一下下面这些文章。
- Best Practices for Designing a Pragmatic RESTful API
- Ideal REST API design
- HTTP API Design Guide
- Microsoft REST API Guidelines
- IBM Watson REST API Guidelines
- Zalando RESTful API and Event Scheme Guidelines
- The Problem With Logging ,一篇关于程序打日志的短文,可以让你知道一些可能以往不知道的打日志需要注意的问题。
- Concurrent Programming for Scalable Web Architectures ,这是一本在线的免费书,教你如何架构一个可扩展的高性能的网站。其中谈到了一些不错的设计方法和知识。
高手成长篇
Linux 系统、内存和网络(系统底层知识)
这一篇章,是本系列中最长的一篇,其中包括了如下的内容。
- 系统底层相关。 主要是以 Linux 系统为主,其中有大量的文章可以让你学习到 Linux 内核,以及内存、网络、异步 I/O 模型、Lock-free 的无锁编程,还有其它和系统底层相关的东西。注意,系统底层要是深下去是可以完全不见底的。而且内存方面的知识也是比较多的,所以,这里还是主要给出一些非常有价值的基础性的知识和技术。学好这些东西,你会对系统有很深的理解,而且可以把这些知识反哺到架构设计上来。
- 数据库相关。数据库方面主要是 MySQL 和各种开源 NoSQL 的一些相关的有价值的文章和导读,主要是让你对这些数据库的内在有一定的了解,但又不会太深。真正的深入是需要扎入到源代码中的。需要说明的是,这块技术不是我的长项,但又是每个架构师需要知道的,所以,我在这里给的学习资源可能会比较浅,这点还希望你来补充和指正。
- 分布式架构。这一部分是最长最多的。其中有架构入门、分布式理论中各种非常有价值的经典论文,然后是一些分布式工程设计方面的文章,其中包括设计模式和工程应用,最后还有各大公司的架构供参考。
- 微服务。有了分布式架构理论和工程的基础,接下来是对微服务的学习。在这部分内容中,我会罗列几个介绍微服务架构非常系统的文章,然后比较一下微服务和 SOA 的差别,最后则是一些工程实践和最佳实践。
- 容器化和自动化运维。在容器化和自动化运维中,主要是学习 Docker 和 Kubernetes 这两个自动化运维的杀手型技术。而不是 Salt、Puppet、Chef 和 Ansible 这样比较传统的工具。原因很简单,因为自动化部署根本不够,还需要对环境和运行时的管理和运维才够,而只有 Docker 和 Kubernetes 才是未来。所以,这里重点让你学习这两个技术,其中有很多文章需要一些系统底层的知识。
- 机器学习和人工智能。机器学习和人工智能,也不是我的长项,我也只是一个入门者。这里,我主要给了一些基础性的知识,其中包括基本原理、图书、课程、文章和相关的算法。你顺着我画的这路走,不能说能成为一个人工智能专家,但成为一个机器学习的高级工程师甚至准专家还是可能的。
- 前端开发。这里的前端主要是 HTML 5 的前端了,这一节会带你学习一下前端开发所需要知道的基础知识,尤其是对前端开发语言 JavaScript 的学习,我花费了相当的篇幅列出了很多很经典的学习资料,必定会让你成为一个 JavaScript 高手。然后你还需要了解浏览器是怎样工作的,还有相关的网络协议和一些性能优化的技巧。最后则是 JavaScript 框架的学习,这里我只给了 React.js 和 Vue.js,并通过 React.js 带出来函数式编程的学习。我虽然不是一个前端程序员,但是,我相信我这个后端程序员给出来的这组前端开发的学习资料和路径会比前端程序员更靠谱一些。
- 信息源。最后,则是一些信息源,其中包括各大公司的技术 Blog,还有相关的论文集散地。
另外,这里需要说明几点。
- 我假设你在前面已经打下了非常扎实的基础,但是要成为一个高手,基础知识只是一个地基,你还需要很多更为具体的技术。对我来说,就是看各种各样的文章、手册、论文、分享…… 其实,学习到一定程度,就是要从书本中走出去,到社区里和大家一起学习,而且还需要自己找食吃了。所以,对于这里面的文章,有很多都是在罗列各种文章和资源,只是为你梳理信息源,而不是喂你吃饭。
- 老实说,我已经为你梳理并过滤掉了很多的信息,这里只留下了 30% 我觉得最经济也最有价值的信息。虽然对于不同定位和不同需求的人还可以再对这些信息进行删减,但是觉得我这么一做就会对其它人不公平了。所以,这也是我觉得最小数量集的信息和资源吧。你也可以把我这里的东西当成一个索引来对待。
- 这些内容,不能说是隔离开来的,应该说是相辅相成的。也没什么顺序,可以各取所需。虽然看上去内容很多,但你也别害怕,真的不用害怕,你会越学越快,越实践越有感觉,也越有效率。在一开始可能会很慢,但是坚持住,积累一段时间后就会越来越快的。 而且,我要告诉你,绝大多数人是坚持不下来的。只要你能坚持下来,我保证,你一定会成为各个大公司的抢手货,这点你一定要相信我。你不需要特别努力,只需要日进一步,3-5 年后,你就会发现,绝大多数人都在你身后很远的地方了。
今天分享的内容为系统底层知识中的 Linux 系统、内存和网络等方面的相关知识及推荐的学习资料。
Linux 系统相关
学习 Linux 操作系统的原理是通向系统工程师的必经之路。我觉得,Unix/Linux 操作系统里的东西并不难学。你千万不要一下子扎到源代码里去,那样没用——你还是要在上层先通过读一些不错的文档来学习。下面我罗列了一些很不错的站点,其中有很多内容供你去钻研和探索。
我在这里默认你前面已经读过并读懂了我推荐的那些和 Unix/Linux 相关的图书了。所以,我相信你对 Unix/Linux 下的编程已经是有一些基础了,因此,你继续深挖 Linux 下的这些知识应该也不是很难的事了。
- Red Hat Enterprise Linux 文档 。Red Hat Enterprise Linux(RHEL)是老牌 Linux 厂商 Red Hat 出品的面向商业的 Linux 发行版。Red Hat 网站上的这个文档中有很多很有价值的内容,值得一看。
- Linux Insides ,GitHub 上的一个开源电子书,其中讲述了 Linux 内核是怎样启动、初始化以及进行管理的。
- LWN’s kernel page ,上面有很多非常不错的文章来解释 Linux 内核的一些东西。
- Learn Linux Kernel from Android Perspective ,从 Android 的角度来学习 Linux 内核,这个站点上的 Blog 相对于前面的比较简单易读一些。
- Linux Kernel Doc, Linux 的内核文档也可以浏览一下。
- Kernel Planet ,Linux 内核开发者的 Blog,有很多很不错的文章和想法。
- Linux Performance and Tuning Guidelines ,这是 IBM 出的红皮书,虽然有点老了,但还是非常值得一读的。
- TLK: The Linux Kernel ,这是一本相对比较老的书了,Linux 内核版本为 2.0.33,但了解一下前人的思路,也是很有帮助的。
- Linux Performance ,这个网站上提供了和 Linux 系统性能相关的各种工具和文章收集,非常不错。
- Optimizing web servers for high throughput and low latency ,这是一篇非常底层的系统调优的文章,来自 DropBox,从中你可以学到很多底层的性能调优的经验和知识。
内存相关
计算机内存管理是每一个底层程序员需要了解的非常重要的事儿。当然,这里我们重点还是 Linux 操作系统相关的内存管理上的知识。
首先,LWN 上有一系列的 “What every programmer should know about memory” 文章你需要读一下。当然,你可以直接访问一个完整的 PDF 文档。下面是这个系列文章的网页版列表。读完这个列表的内容,你基本上就对内存有了一个比较好的知识体系了。
- Part 1: Introduction ,中译版为 “每个程序员都应该了解的内存知识【第一部分】”
- Part 2: CPU caches
- Part 3 (Virtual memory)
- Part 4 (NUMA systems)
- Part 5 (What programmers can do - cache optimization)
- Part 6 (What programmers can do - multi-threaded optimizations)
- Part 7 (Memory performance tools)
- Part 8 (Future technologies)
- Part 9 (Appendices and bibliography)
然后是几篇和内存相关的论文。下面这三篇论文是我个人觉得能对你非常有帮助的文章,尤其是你要做一些程序的性能优化方面。
- Memory Barriers: a Hardware View for Software Hackers。内存的读写屏障是线程并发访问共享的内存数据时,从程序本身、编译器到 CPU 都必须遵循的一个规范。有了这个规范,才能保证访问共享的内存数据时,一个线程对该数据的更新能被另一个线程以正确的顺序感知到。在 SMP(对称多处理)这种类型的多处理器系统(包括多核系统)上,这种读写屏障还包含了复杂的缓存一致性策略。这篇文章做了详细解释。
- A Tutorial Introduction to the ARM and POWER Relaxed Memory Models,对 ARM 和 POWER 的宽松内存模型的一个教程式的简介。本篇文章的焦点是 ARM 和 POWER 体系结构下多处理器系统内存并发访问一致性的设计思路和使用方法。与支持较强的 TSO 模型的 x86 体系结构不同,ARM 和 POWER 这两种体系结构出于对功耗和性能的考虑,使用了一种更为宽松的内存模型。本文详细讨论了 ARM 和 POWER 的模型。
- x86-TSO: A Rigorous and Usable Programmer’s Model for x86 Multiprocessors,介绍 x86 的多处理器内存并发访问的一致性模型 TSO。
接下来是开发者最关心的内存管理方面的 lib 库。通常来说,我们有三种内存分配管理模块。就目前而言,BSD 的 jemalloc 有很大的影响力。后面我们可以看到不同公司的实践性文章。
- ptmalloc 是 glibc 的内存分配管理。
- tcmalloc 是 Google 的内存分配管理模块,全称是 Thread-Caching malloc,基本上来说比 glibc 的 ptmalloc 快两倍以上。
- jemalloc 是 BSD 提供的内存分配管理。其论文为 A Scalable Concurrent malloc(3) Implementation for FreeBSD,这是一个可以并行处理的内存分配管理器。
关于 C 的这些内存分配器,你可以参看 Wikipedia 的 “C Dynamic Memory Allocation”这个词条。
下面是几篇不错的文章,让你感觉一下上面那三种内存分配器的一些比较和工程实践。
- ptmalloc,tcmalloc 和 jemalloc 内存分配策略研究
- 内存优化总结:ptmalloc、tcmalloc 和 jemalloc
- Scalable memory allocation using jemalloc
- Decreasing RAM Usage by 40% Using jemalloc with Python & Celery
计算机网络
网络学习
首先,推荐一本书——《计算机网络(第五版)》,这本“计算机网络”和前面推荐的那本计算机网络不一样,前面那本偏扫盲,这本中有很多细节。这本书是国内外使用最广泛、最权威的计算机网络经典教材。全书按照网络协议模型自下而上(物理层、数据链路层、介质访问控制层、网络层、传输层和应用层)有系统地介绍了计算机网络的基本原理,并结合 Internet 给出了大量的协议实例。
这本书还与时俱进地引入了最新的网络技术,包括无线网络、3G 蜂窝网络、RFID 与传感器网络、内容分发与 P2P 网络、流媒体传输与 IP 语音,以及延迟容忍网络等。另外,本书针对当前网络应用中日益突出的安全问题,用了一整章的篇幅对计算机网络的安全性进行了深入讨论,而且把相关内容与最新网络技术结合起来阐述。这本书读起来并不枯燥,因为其中有很多小故事和小段子。
然后,有两个网上的教程和讲义也可以让人入门。
- 渥汰华大学的一个课程讲义你也可以一看 Computer Network Design 。
- GeeksforGeeks 上也有一个简单的 Computer Network Tutorials 。
网络调优
接下来,你可能需要一些非常实用的可以操作的技术,下面的几篇文章相信可以帮助到你。
- 《Linux 的高级路由和流量控制 HowTo》(Linux Advanced Routing & Traffic Control HOWTO ),这是一个非常容易上手的关于 iproute2、流量整形和一点 netfilter 的指南。
- 关于网络调优,你可以看一下这个文档 Red Hat Enterprise Linux Network Performance Tuning Guide。
- 还有一些网络工具能够帮上你的大忙,这里有一个网络工具的 Awesome 列表 Awesome Pcap Tools ,其中罗列了各种网络工具,能够让你更从容地调试网络相关的程序。
- Making Linux TCP Fast ,一篇非常不错的 TCP 调优的论文。
- 下面是在 PackageCloud 上的两篇关于 Linux 网络栈相关的底层文章,非常值得一读。
- Monitoring and Tuning the Linux Networking Stack: Receiving Data
- Monitoring and Tuning the Linux Networking Stack: Sending Data
网络协议
接下来,想要学习网络协议最好的方式就是学习通讯相关的 RFC。所以,在这里我会推荐一系列值得读的 RFC 给你。读 RFC 有几个好处,一方面可以学习技术,另一方面,你可以通过 RFC 学习到一个好的技术文档是怎么写的,还能看到各种解决问题的方案和思路。
对于第 2 层链路层,你可能需要了解一下 ARP:
- RFC 826 - An Ethernet Address Resolution Protocol
以及 Tunnel 相关的协议:
- RFC 1853 - IP in IP Tunneling
- RFC 2784 - Generic Routing Encapsulation (GRE)
- RFC 2661 - Layer Two Tunneling Protocol “L2TP”
- RFC 2637 - Point-to-Point Tunneling Protocol (PPTP)
对于第 4 层,你最需要了解的是 TCP/IP 了。和 TCP 相关的 RFC 相当多,这里给一系列经典的 RFC。这些 RFC 我都引用在了我在 CoolShell 上的《TCP 的那些事儿(上)》和《TCP 的那些事儿(下)》两篇文章中。如果你看不懂 RFC,你也可以去看我上述的文章。
- RFC 793 - Transmission Control Protocol - 最初的 TCP 标准定义,但不包括 TCP 相关细节。
- RFC 813 - Window and Acknowledgement Strategy in TCP - TCP 窗口与确认策略,并讨论了在使用该机制时可能遇到的问题及解决方法。
- RFC 879 - The TCP Maximum Segment Size and Related Topics - 讨论 MSS 参数对控制 TCP 分组大小的重要性,以及该参数与 IP 分段大小的关系等。
- RFC 896 - Congestion Control in IP/TCP Internetworks - 讨论拥塞问题和 TCP 如何控制拥塞。
- RFC 2581 - TCP Congestion Control - 描述用于拥塞控制的四种机制:慢启动、拥塞防御、快重传和快恢复。后面这个 RFC 被 RFC 5681 所更新。还有 RFC 6582 - The NewReno Modification to TCP’s Fast Recovery Algorithm 中一个改进的快速恢复算法。
- RFC 2018 - TCP Selective Acknowledgment Options - TCP 的选择确认。
- RFC 2883 - An Extension to the Selective Acknowledgement (SACK) Option for TCP - 对于 RFC 2018 的改进。
- RFC 2988 - Computing TCP’s Retransmission Timer - 讨论与 TCP 重传计时器设置相关的话题,重传计时器控制报文在重传前应等待多长时间。也就是经典的 TCP Karn/Partridge 重传算法。
- RFC 6298 - Computing TCP’s Retransmission Timer - TCP Jacobson/Karels Algorithm 重传算法。
我个人觉得 TCP 最牛的不是不丢包,而是拥塞控制。对此,如果你感兴趣,可以读一下经典论文《Congestion Avoidance and Control》。
关于 Linux 下的 TCP 参数,你需要仔仔细细地读一下TCP 的 man page 。
对于第 7 层协议,HTTP 协议是重点要学习的。
首先推荐的是《HTTP 权威指南 》,这本书有点厚,可以当参考书来看。这本书中没有提到 HTTP/2 的事,但是可以让你了解到 HTTP 协议的绝大多数特性。
HTTP 1.1 的原始 RFC 是 1999 年 6 月的 RFC 2616,但其在 2014 后很快被下面这些 RFC 给取代了。
- RFC 7230 - Hypertext Transfer Protocol (HTTP/1.1): Message Syntax and Routing
- RFC 7231 - Hypertext Transfer Protocol (HTTP/1.1): Semantics and Content
- RFC 7232 - Hypertext Transfer Protocol (HTTP/1.1): Conditional Requests
- RFC 7233 - Hypertext Transfer Protocol (HTTP/1.1): Range Requests
- RFC 7234 - Hypertext Transfer Protocol (HTTP/1.1): Caching
- RFC 7235 - Hypertext Transfer Protocol (HTTP/1.1): Authentication
关于HTTP/2,这是 HTTP 的一个比较新的协议,它于 2015 年被批准通过,现在基本上所有的主流浏览器都默认启用这个协议。所以,你有必要学习一下这个协议。下面是相关的学习资源。
- Gitbook - HTTP/2 详解
- http2 explained(中译版)
- HTTP/2 for a Faster Web
- Nginx HTTP/2 白皮书
- HTTP/2 的两个 RFC:
- RFC 7540 - Hypertext Transfer Protocol Version 2 (HTTP/2) ,HTTP/2 的协议本身
- RFC 7541 - HPACK: Header Compression for HTTP/2 ,HTTP/2 的压缩算法
最后,你可以上 Wikipedia 的 Internet Protocol Suite 上看看,这是一个很不错的网络协议的词条汇集地。顺着这些协议,你可以找到很多有用的东西。
异步 I/O 模型和 Lock-Free 编程(系统底层知识)
异步 I/O 模型
异步 I/O 模型是我个人觉得所有程序员都必需要学习的一门技术或是编程方法,这其中的设计模式或是解决方法可以借鉴到分布式架构上来。再说一遍,学习这些模型,是非常非常重要的,你千万要认真学习。
史蒂文斯(Stevens)在《UNIX 网络编程》一书 6.2 I/O Models 中介绍了五种 I/O 模型。
- 阻塞 I/O
- 非阻塞 I/O
- I/O 的多路复用(select 和 poll)
- 信号驱动的 I/O(SIGIO)
- 异步 I/O(POSIX 的 aio_functions)
然后,在前面我们也阅读过了 - C10K Problem 。相信你对 I/O 模型也有了一定的了解。 这里,我们需要更为深入地学习 I/O 模型,尤其是其中的异步 I/O 模型。
首先,我们看一篇和 Java 相关的 I/O 模型的文章来复习一下之前的内容。Thousands of Threads and Blocking I/O: The Old Way to Write Java Servers Is New Again (and Way Better) ,这个 PPT 中不仅回顾和比较了各种 I/O 模型,而且还有各种比较细节的方案和说明,是一篇非常不错的文章。
然后,你可以看一篇 Java 相关的 PPT - 道格·莱亚(Doug Lea)的 Scalable IO in Java,这样你会对一些概念有个了解。
接下来,我们需要了解一下各种异步 I/O 的实现和设计方式。
- IBM - Boost application performance using asynchronous I/O ,这是一篇关于 AIO 的文章。
- Lazy Asynchronous I/O For Event-Driven Servers ,这篇文章也很不错。
- 另外,异步 I/O 模型中的 Windows I/O Completion Ports , 你也需要了解一下。如果 MSDN 上的这个手册不容易读,你可以看看这篇文章 Inside I/O Completion Ports。另外,关于 Windows,Windows Internals 这本书你可以仔细读一下,非常不错的。其中有一节 I/O Processing 也是很不错的,这里我给一个网上免费的链接I/O Processing 你可以看看 Windows 是怎么玩的。
- 接下来是 Libevent。你可以看一下其主要维护人员尼克·马修森(Nick Mathewson)写的 Libevent 2.0 book。还有一本国人写的电子书 《Libevent 深入浅出》。
- 再接下来是 Libuv。你可以看一下其官网的 Libuv Design Overview 了解一下。
我简单总结一下,基本上来说,异步 I/O 模型的发展技术是: select -> poll -> epoll -> aio -> libevent -> libuv。Unix/Linux 用了好几十年走过这些技术的变迁,然而,都不如 Windows I/O Completion Port 设计得好(免责声明:这个观点纯属个人观点。相信你仔细研究这些 I/O 模型后,你会有自己的判断)。
看过这些各种异步 I/O 模式的实现以后,相信你会看到一个编程模式——Reactor 模式。下面是这个模式的相关文章(读这三篇就够了)。
- Understanding Reactor Pattern: Thread-Based and Event-Driven
- Reactor Pattern
- The reactor pattern and non-blocking IO
然后是几篇有意思的延伸阅读文章。
- The Secret To 10 Million Concurrent Connections -The Kernel Is The Problem, Not The Solution - C10M 问题来了……
- 还有几篇可能有争议的文章,让你从不同的角度思考。
- Select is fundamentally broken
- Epoll is fundamentally broken 1/2
- Epoll is fundamentally broken 2/2
Lock-Free 编程相关
Lock-Free - 无锁技术越来越被开发人员重视,因为锁对于性能的影响实在是太大了,所以如果想开发出一个高性能的程序,你就非常有必要学习 Lock-Free 的编程方式。
关于无锁的数据结构,有几篇教程你可以看一下。
- Dr.Dobb’s: Lock-Free Data Structures
- Andrei Alexandrescu: Lock-Free Data Structures
然后强烈推荐一本免费的电子书:Is Parallel Programming Hard, And, If So, What Can You Do About It? ,这是大牛 保罗·麦肯尼(Paul E. McKenney) 写的书。这本书堪称并行编程的经典书,必看。
此时,Wikipedia 上有三个词条你要看一下,以此了解并发编程中的一些概念:Non-blocking algorithm 、Read-copy-update 和 Seqlock。
接下来,读一下以下两篇论文 。
- Implementing Lock-Free Queues, 这也是一篇很不错的论文,我把它介绍在了我的网站上 ,文章为“无锁队列的实现”。
- Simple, Fast, and Practical Non-Blocking and Blocking Concurrent Queue Algorithms ,这篇论文给出了一个无阻塞和阻塞的并发队列算法。
最后,有几个博客你要订阅一下。
- 1024cores - 德米特里·伐由科夫(Dmitry Vyukov)的和 lock-free 编程相关的网站。
- Paul E. McKenney - 保罗(Paul)的个人网站。
- Concurrency Freaks - 关于并发算法和相关模式的网站。
- Preshing on Programming - 加拿大程序员杰夫·普莱辛(Jeff Preshing)的技术博客,主要关注 C++ 和 Python 两门编程语言。他用 C++11 实现了类的反射机制,用 C++ 编写了 3D 小游戏 Hop Out,还为该游戏编写了一个游戏引擎。他还讨论了很多 C++ 的用法,比如 C++14 推荐的代码写法、新增的某些语言构造等,和 Python 很相似。阅读这个技术博客上的内容能够深深感受到博主对编程世界的崇敬和痴迷。
- Sutter’s Mill - 赫布·萨特(Herb Sutter)是一位杰出的 C++ 专家,曾担任 ISO C++ 标准委员会秘书和召集人超过 10 年。他的博客有关于 C++ 语言标准最新进展的信息,其中也有他的演讲视频。博客中还讨论了其他技术和 C++ 的差异,如 C# 和 JavaScript,它们的性能特点、怎样避免引入性能方面的缺陷等。
- Mechanical Sympathy - 博主是马丁·汤普森(Martin Thompson),他是一名英国的技术极客,探索现代硬件的功能,并提供开发、培训、性能调优和咨询服务。他的博客主题是 Hardware and software working together in harmony,里面探讨了如何设计和编写软件使得它在硬件上能高性能地运行。非常值得一看。
接下来,是一些编程相关的一些 C/C++ 的类库,这样你就不用从头再造轮子了(对于 Java 的,请参看 JDK 里的 Concurrent 开头的一系列的类)。
- Boost.Lockfree - Boost 库中的无锁数据结构。
- ConcurrencyKit - 并发性编程的原语。
- Folly - Facebook 的开源库(它对 MPMC 队列做了一个很好的实现)。
- Junction - C++ 中的并发数据结构。
- MPMCQueue - 一个用 C++11 编写的有边界的“多生产者 - 多消费者”无锁队列。
- SPSCQueue - 一个有边界的“单生产者 - 单消费者”的无等待、无锁的队列。
- Seqlock - 用 C++ 实现的 Seqlock。
- Userspace RCU - liburcu 是一个用户空间的 RCU(Read-copy-update,读 - 拷贝 - 更新)库。
- libcds - 一个并发数据结构的 C++ 库。
- liblfds - 一个用 C 语言编写的可移植、无许可证、无锁的数据结构库。
其它
-
关于 64 位系统编程,只要去一个地方就行了: All about 64-bit programming in one place,这是一个关于 64 位编程相关的收集页面,其中包括相关的文章、28 节课程,还有知识库和相关的 blog。
-
What Scalable Programs Need from Transactional Memory ,事务性内存(TM)一直是许多研究的重点,它在诸如 IBM Blue Gene/Q 和 Intel Haswell 等处理器中得到了支持。许多研究都使用 STAMP 基准测试套件来评估其设计。然而,我们所知的所有 TM 系统上的 STAMP 基准测试所获得的加速比较有限。
例如,在 IBM Blue Gene/Q 上有 64 个线程,我们观察到使用 Blue Gene/Q 硬件事务内存(HTM)的中值加速比为 1.4 倍,使用软件事务内存(STM)的中值加速比为 4.1 倍。什么限制了这些 TM 基准的性能?在本论文中,作者认为问题在于用于编写它们的编程模型和数据结构上,只要使用合适的模型和数据结构,程序的性能可以有 10 多倍的提升。
-
Improving OpenSSL Performance ,这篇文章除了教你如何提高 OpenSSL 的执行性能,还讲了一些底层的性能调优知识。
-
关于压缩的内容。为了避免枯燥,主要推荐下面这两篇实践性很强的文章。
- How eBay’s Shopping Cart used compression techniques to solve network I/O bottlenecks ,这是一篇很好的文章,讲述了 eBay 是如何通过压缩数据来提高整体服务性能的,其中有几个比较好的压缩算法。除了可以让你学到相关的技术知识,还可以让你看到一种比较严谨的工程师文化。
- Linkedin: Boosting Site Speed Using Brotli Compression ,LinkedIn 在 2017 年早些时候开始使用 Brotli 来替换 gzip,以此带来更快的访问,这篇文章讲述了什么是 Brotli 以及与其它压缩程序的比较和所带来的性能提升。
-
这里有两篇关于 SSD 硬盘性能测试的文章。Performance Testing with SSDs, Part 1 和 Performance Testing with SSDs Part 2 ,这两篇文章介绍了测试 SSD 硬盘性能以及相关的操作系统调优方法。
-
Secure Programming HOWTO - Creating Secure Software ,这是一本电子书,其中有繁体中文的翻译,这本电子书讲了 Linux/Unix 下的一些安全编程方面的知识。
相关论文
-
Hints for Computer System Design ,计算机设计的忠告,这是 ACM 图灵奖得主 Butler Lampson 在 Xerox PARC 工作时的一篇论文。这篇论文简明扼要地总结了他在做系统设计时的一些想法,非常值得一读。(用他的话来说,“Studying the design and implementation of a number of computer has led to some general hints for system design. They are described here and illustrated by many examples, ranging from hardware such as the Alto and the Dorado to application programs such as Bravo and Star“。)
-
The 5 minute rule for trading memory for disc accesses and the 5 byte rule for trading memory for CPU time ,根据文章名称也可以看出,5 分钟法则是用来衡量内存与磁盘的,而 5 字节法则则是在内存和 CPU 之间的权衡。这两个法则是 Jim Gray 和 Franco Putzolu 在 1986 年的文章。
在该论文发表 10 年后的 1997 年,Jim Gray 和 Goetz Graefe 又在 The Five-Minute Rule Ten Years Later and Other Computer Storage Rules of Thumb 中对该法则进行了重新审视。2007 年,也就是该论文发表 20 年后,这年的 1 月 28 日,Jim Gray 驾驶一艘 40 英尺长的船从旧金山港出海,目的是航行到附近的费拉隆岛,在那里撒下母亲的骨灰。出海之后,他就同朋友和亲属失去了联系。为了纪念和向大师致敬,时隔 10 多年后的 2009 年 Goetz Graefe 又发表了 The Five-Minute Rule 20 Years Later (and How Falsh Memory Changes the Rules)。
注明一下,Jim Gray 是关系型数据库领域的大师。因在数据库和事务处理研究和实现方面的开创性贡献而获得 1998 年图灵奖。美国科学院、工程院两院院士,ACM 和 IEEE 两会会士。他 25 岁成为加州大学伯克利分校计算机科学学院第一位博士。在 IBM 工作期间参与和主持了 IMS、System R、SQL/DS、DB2 等项目的开发。后任职于微软研究院,主要关注应用数据库技术来处理各学科的海量信息。
小结
好了,总结一下今天的内容。异步 I/O 模型是我个人觉得所有程序员都必需要学习的一门技术或是编程方法,这其中的设计模式或是解决方法可以借鉴到分布式架构上来。而且我认为,学习这些模型非常重要,你千万要认真学习。
接下来是 Lock-Free 方面的内容,由于锁对于性能的影响实在是太大了,所以它越来越被开发人员所重视。如果想开发出一个高性能的程序,你非常有必要学习 Lock-Free 的编程方式。随后,我给出系统底层方面的其它一些重要知识,如 64 位编程、提高 OpenSSL 的执行性能、压缩、SSD 硬盘性能测试等。最后介绍了几篇我认为对学习和巩固这些知识非常有帮助的论文,都很经典,推荐你务必看看。
Java 底层知识
前两篇文章分享的是系统底层方面的内容,今天我们进入高手成长篇的第二部分——Java 底层知识。
Java 字节码相关
首先,Java 最黑科技的玩法就是字节码编程,也就是动态修改或是动态生成 Java 字节码。Java 的字节码相当于汇编,其中的一些细节你可以从下面的这几个教程中学习。
- Java Zone: Introduction to Java Bytecode ,这篇文章图文并茂地向你讲述了 Java 字节码的一些细节,是一篇很不错的入门文章。
- IBM DeveloperWorks: Java bytecode ,虽然这篇文章很老了,但是这篇文章是一篇非常好的讲 Java 字节码的文章。
- Java Bytecode and JVMTI Examples,这是一些使用 JVM Tool Interface 操作字节码的比较实用的例子。包括方法调用统计、静态字节码修改、Heap Taggin 和 Heap Walking。
当然,一般来说,我们不使用 JVMTI 操作字节码,而是用一些更好用的库。这里有三个库可以帮你比较容易地做这个事。
- asmtools - 用于生产环境的 Java .class 文件开发工具。
- Byte Buddy - 代码生成库:运行时创建 Class 文件而不需要编译器帮助。
- Jitescript - 和 BiteScript 类似的字节码生成库。
就我而言,我更喜欢 Byte Buddy,它在 2015 年还获了 Oracle 的 “Duke’s Choice”大奖,其中说 Byte Buddy 极大地发展了 Java 的技术。
使用字节码编程可以玩出很多高级玩法,最高级的还是在 Java 程序运行时进行字节码修改和代码注入。听起来是不是一些很黑客,也很黑科技的事?是的,这个方式使用 Java 这门静态语言在运行时可以进行各种动态的代码修改,而且可以进行无侵入的编程。
比如, 我们不需要在代码中埋点做统计或监控,可以使用这种技术把我们的监控代码直接以字节码的方式注入到别人的代码中,从而实现对实际程序运行情况进行统计和监控。如果你看过我的《编程范式游记》,你就知道这种技术的威力了,其可以很魔法地把业务逻辑和代码控制分离开来。
要做到这个事,你还需要学习一个叫 Java Agent 的技术。Java Agent 使用的是 “Java Instrumentation API”,其主要方法是实现一个叫 premain()
的方法(嗯,一个比 main()
函数还要超前执行的 main 函数),然后把你的代码编译成一个 jar 文件。
在 JVM 启动时,使用这样的命令行来引入你的 jar 文件:java -javaagent:yourAwesomeAgent.jar -jar App.jar
。更为详细的文章你可以参看:“Java Code Geeks: Java Agents”,你还可以看一下这个示例项目:jvm-monitoring-agent 或是 EntryPointKR/Agent.java。如果想用 ByteBuddy 来玩,你可以看看这篇文章 “通过使用 Byte Buddy,便捷地创建 Java Agent”。如果你想学习如何用 Java Agent 做监控,你可以看一下这个项目 Stage Monitor。
JVM 相关
接下来讲讲 Java 底层知识中另一个非常重要的内容——JVM。
说起 JVM,你有必要读一下 JVM 的规格说明书,我在这里放一个 Java 8 的, The Java Virtual Machine Specification Java SE 8 Edition 。对于规格说明书的阅读,我认为是系统了解 JVM 规范的最佳文档,这个文档可以让你对于搞不清楚或是诡异的问题恍然大悟。关于中文翻译,有人在 GitHub 上开了个 Repo - “java-virtual-machine-specification”。
另外,也推荐一下 JVM Anatomy Park JVM 解剖公园,这是一个系列的文章,每篇文章都不长,但是都很精彩,带你一点一点地把 JVM 中的一些技术解开。
学习 Java 底层原理还有 Java 的内存模型,官方文章是 JSR 133。还有马里兰大学的威廉·皮尤(William Pugh)教授收集的和 Java 内存模型相关的文献 - The Java Memory Model ,你可以前往浏览。
对于内存方面,道格·利(Doug Lea)有两篇文章也是很有价值的。
- The JSR-133 Cookbook for Compiler Writers,解释了怎样实现 Java 内存模型,特别是在考虑到多处理器(或多核)系统的情况下,多线程和读写屏障的实现。
- Using JDK 9 Memory Order Modes,讲了怎样通过 VarHandle 来使用 plain、opaque、release/acquire 和 volatile 四种共享内存的访问模式,并剖析了底层的原理。
垃圾回收机制也是需要好好学习的,在这里推荐一本书 《The Garbage Collection Handbook》,在豆瓣上的得分居然是 9.9(当然,评价人数不多)。这本书非常全面地介绍了垃圾收集的原理、设计和算法。但是这本书也是相当难啃的。中文翻译《垃圾回收算法手册》翻译得很一般,有人说翻译得很烂。所以,如果可能,还是读英文版的。如果你对从事垃圾回收相关的工作有兴趣,那么你需要好好看一下这本书。
当然,更多的人可能只需要知道怎么调优垃圾回收, 那么推荐读读 Garbage Collection Tuning Guide ,它是 Hotspot Java 虚拟机的垃圾回收调优指南,对你很有帮助。
Quick Tips for Fast Code on the JVM 也是一篇很不错的文章,里面有写出更快的 Java 代码的几个小提示,值得一读。
小结
好了,总结一下今天学到的内容。Java 最黑科技的玩法就是字节码编程,也就是动态修改或是动态生成 Java 字节码。Java 的字节码相当于汇编,学习其中的细节很有意思,为此我精心挑选了 3 篇文章,供你学习。我们一般不使用 JVMTI 操作字节码,而是用一些更好用的库,如 asmtools、Byte Buddy 和 BiteScript 等。使用字节码编程可以玩出很多高级玩法,其中最高级的玩法是在 Java 程序运行时进行字节码修改和代码注入。同时,我介绍了 Java Agent 技术,帮助你更好地实现这种高级玩法。
JVM 也是学习 Java 过程中非常重要的一部分内容。我推荐阅读一下 JVM 的规格说明书,我认为,它是系统了解 JVM 规范的最佳文档,可以让你对于搞不清楚或是诡异的问题恍然大悟。同时推荐了 JVM Anatomy Park 系列文章,也非常值得一读。
随后介绍的是 Java 的内存模型和垃圾回收机制,尤其给出了如何调优垃圾回收方面的资料。这些内容都很底层,但也都很重要。对于想成为高手的你来说,还是有必要花时间来啃一啃的。
数据库
对于数据库方向,重点就是两种数据库,一种是以 SQL 为代表的关系型数据库,另一种是以非 SQL 为代表的 NoSQL 数据库。关系型数据库主要有三个:Oracle、MySQL 和 Postgres。
在这里,我们只讨论越来越主流的 MySQL 数据库。首先,我们要了解数据库的一些实现原理和内存的一些细节,然后我们要知道数据的高可用和数据复制这些比较重要的话题,了解一下关系型数据库的一些实践和难点。然后,我们会进入到 NoSQL 数据库的学习。
NoSQL 数据库千奇百怪,其主要是解决了关系型数据库中的各种问题。第一个大问题就是数据的 Schema 非常多,用关系型数据库来表示不同的 Data Schema 是非常笨拙的,所以要有不同的数据库(如时序型、键值对型、搜索型、文档型、图结构型等)。另一个大问题是,关系型数据库的 ACID 是一件很讨厌的事,这极大地影响了数据库的性能和扩展性,所以 NoSQL 在这上面做了相应的妥协以解决大规模伸缩的问题。
对于一个程序员,你可能觉得数据库的事都是 DBA 的事,然而我想告诉你你错了,这些事才真正是程序员的事。因为程序是需要和数据打交道的,所以程序员或架构师不仅需要设计数据模型,还要保证整体系统的稳定性和可用性,数据是整个系统中关键中的关键。所以,作为一个架构师或程序员,你必须了解最重要的数据存储——数据库。
关系型数据库
今天,关系型数据库最主要的两个代表是闭源的 Oracle 和开源的 MySQL。当然,还有很多了,比如微软的 SQL Server,IBM 的 DB2 等,还有开源的 PostgreSQL。关系型数据库的世界中有好多好多产品。当然,还是 Oracle 和 MySQL 是比较主流的。所以,这里主要介绍更为开放和主流的 MySQL。
如果你要玩 Oracle,我这里只推荐一本书《Oracle Database 9i/10g/11g 编程艺术》,无论是开发人员还是 DBA,它都是必读的书。这本书的作者是 Oracle 公司的技术副总裁托马斯·凯特(Thomas Kyte),他也是世界顶级的 Oracle 专家。
这本书中深入分析了 Oracle 数据库体系结构,包括文件、内存结构以及构成 Oracle 数据库和实例的底层进程,利用具体示例讨论了一些重要的数据库主题,如锁定、并发控制、事务等。同时分析了数据库中的物理结构,如表、索引和数据类型,并介绍采用哪些技术能最优地使用这些物理结构。
-
学习 MySQL,首先一定是要看MySQL 官方手册。
-
然后,官方还有几个 PPT 也要学习一下。
- How to Analyze and Tune MySQL Queries for Better Performance
- MySQL Performance Tuning 101
- MySQL Performance Schema & Sys Schema
- MySQL Performance: Demystified Tuning & Best Practices
- MySQL Security Best Practices
- MySQL Cluster Deployment Best Practices
- MySQL High Availability with InnoDB Cluster
-
然后推荐《高性能 MySQL》,这本书是 MySQL 领域的经典之作,拥有广泛的影响力。不但适合数据库管理员(DBA)阅读,也适合开发人员参考学习。不管是数据库新手还是专家,都能从本书中有所收获。
-
如果你对 MySQL 的内部原理有兴趣的话,可以看一下这本书《MySQL 技术内幕:InnoDB 存储引擎》。当然,还有官网的MySQL Internals Manual 。
-
数据库的索引设计和优化也是非常关键的,这里还有一本书《数据库的索引设计与优化》也是很不错的。虽然不是讲 MySQL 的,但是原理都是相通的。这也是上面推荐过的《高性能 MySQL》在其索引部分推荐的一本好书。
你千万不要觉得只有做数据库你才需要学习这种索引技术。不是的!在系统架构上,在分布式架构中,索引技术也是非常重要的。这本书对于索引性能进行了非常清楚的估算,不像其它书中只是模糊的描述,你一定会收获很多。
下面还有一些不错的和 MySQL 相关的文章。
- MySQL 索引背后的数据结构及算法原理
- Some study on database storage internals
- Sharding Pinterest: How we scaled our MySQL fleet
- Guide to MySQL High Availability
- Choosing MySQL High Availability Solutions
- High availability with MariaDB TX: The definitive guide
最后,还有一个 MySQL 的资源列表 Awesome MySQL,这个列表中有很多的工具和开发资源,可以帮助你做很多事。
MySQL 有两个比较有名的分支,一个是 Percona,另一个是 MariaDB,其官网上的 Resources 页面中有很多不错的资源和文档,可以经常看看。 Percona Resources、MariaDB Resources ,以及它们的开发博客中也有很多不错的文章,分别为 Percona Blog 和 MariaDB Blog。
然后是关于 MySQL 的一些相关经验型的文章。
- Booking: Evolution of MySQL System Design ,Booking 的 MySQL 数据库使用的演化,其中有很多不错的经验分享,我相信也是很多公司会遇到的的问题。
- Tracking the Money - Scaling Financial Reporting at Airbnb ,Airbnb 的数据库扩展的经验分享。
- Why Uber Engineering Switched from Postgres to MySQL ,无意比较两个数据库谁好谁不好,推荐这篇 Uber 的长文,主要是想让你从中学习到一些经验和技术细节,这是一篇很不错的文章。
关于 MySQL 的集群复制,下面有这些文章供你学习一下,都是很不错的实践性比较强的文章。
- Monitoring Delayed Replication, With A Focus On MySQL
- Mitigating replication lag and reducing read load with freno
- 另外,Booking 给了一系列的文章,你可以看看:
-
Better Parallel Replication for MySQL
-
Evaluating MySQL Parallel Replication Part 2: Slave Group Commit
-
Evaluating MySQL Parallel Replication Part 3: Benchmarks in Production
-
[Evaluating MySQL Parallel Replication Part 4: More Benchmarks in Production
](https://medium/booking-com-infrastructure/evaluating-mysql-parallel-replication-part-4-more-benchmarks-in-production-49ee255043ab)
-
Evaluating MySQL Parallel Replication Part 4, Annex: Under the Hood
-
对于 MySQL 的数据分区来说,还有下面几篇文章你可以看看。
- StackOverflow: MySQL sharding approaches?
- Why you don’t want to shard
- [How to Scale Big Data Applications](https://www.percona/sites/default/files/presentations/How to Scale Big Data Applications.pdf)
- MySQL Sharding with ProxySQL
然后,再看看各个公司做 MySQL Sharding 的一些经验分享。
-
[MailChimp: Using Shards to Accommodate Millions of Users
](https://devs.mailchimp/blog/using-shards-to-accommodate-millions-of-users/)
-
Uber: Code Migration in Production: Rewriting the Sharding Layer of Uber’s Schemaless Datastore
-
Sharding & IDs at Instagram
-
Airbnb: How We Partitioned Airbnb’s Main Database in Two Weeks
NoSQL 数据库
关于 NoSQL 数据库,其最初目的就是解决大数据的问题。然而,也有人把其直接用来替换掉关系型数据库。所以在学习这个技术之前,我们需要对这个技术的一些概念和初衷有一定的了解。下面是一些推荐资料。
- Martin Fowler 在 YouTube 上分享的 NoSQL 介绍 Introduction To NoSQL, 以及他参与编写的 NoSQL Distilled - NoSQL 精粹,这本书才 100 多页,是本难得的关于 NoSQL 的书,很不错,非常易读。
- NoSQL Databases: a Survey and Decision Guidance,这篇文章可以带你自上而下地从 CAP 原理到开始了解 NoSQL 的种种技术,是一篇非常不错的文章。
- Distribution, Data, Deployment: Software Architecture Convergence in Big Data Systems,这是卡内基·梅隆大学的一篇讲分布式大数据系统的论文。其中主要讨论了在大数据时代下的软件工程中的一些关键点,也说到了 NoSQL 数据库。
- No Relation: The Mixed Blessings of Non-Relational Databases,这篇论文虽然有点年代久远。但这篇论文是 HBase 的基础,你花上一点时间来读读,就可以了解到,对各种非关系型数据存储优缺点的一个很好的比较。
- NoSQL Data Modeling Techniques ,NoSQL 建模技术。这篇文章我曾经翻译在了 CoolShell 上,标题为 NoSQL 数据建模技术,供你参考。
- MongoDB - Data Modeling Introduction ,虽然这是 MongoDB 的数据建模介绍,但是其很多观点可以用于其它的 NoSQL 数据库。
- Firebase - Structure Your Database ,Google 的 Firebase 数据库使用 JSON 建模的一些最佳实践。
- 因为 CAP 原理,所以当你需要选择一个 NoSQL 数据库的时候,你应该看看这篇文档 Visual Guide to NoSQL Systems。
选 SQL 还是 NoSQL,这里有两篇文章,值得你看看。
- SQL vs. NoSQL Databases: What’s the Difference?
- Salesforce: SQL or NoSQL
各种 NoSQL 数据库
学习使用 NoSQL 数据库其实并不是一件很难的事,只要你把官方的文档仔细地读一下,是很容易上手的,而且大多数 NoSQL 数据库都是开源的,所以,也可以通过代码自己解决问题。下面我主要给出一些典型的 NoSQL 数据库的一些经验型的文章,供你参考。
列数据库 Column Database
- Cassandra 相关
- 沃尔玛实验室有两篇文章值得一读。
- Avoid Pitfalls in Scaling Cassandra Cluster at Walmart
- Storing Images in Cassandra at Walmart
- Yelp: How We Scaled Our Ad Analytics with Apache Cassandra ,Yelp 的这篇博客也有一些相关的经验和教训。
- Discord: How Discord Stores Billions of Messages ,Discord 公司分享的一个如何存储十亿级消息的技术文章。
- Cassandra at Instagram ,Instagram 的一个 PPT,其中介绍了 Instagram 中是怎么使用 Cassandra 的。
- Netflix: Benchmarking Cassandra Scalability on AWS - Over a million writes per second ,Netflix 公司在 AWS 上给 Cassandra 做的一个 Benchmark。
- 沃尔玛实验室有两篇文章值得一读。
- HBase 相关
- Imgur Notification: From MySQL to HBASE
- Pinterest: Improving HBase Backup Efficiency
- IBM : Tuning HBase performance
- HBase File Locality in HDFS
- Apache Hadoop Goes Realtime at Facebook
- Storage Infrastructure Behind Facebook Messages: Using HBase at Scale
- GitHub: Awesome HBase
针对于 HBase 有两本书你可以考虑一下。
- 首先,先推荐两本书,一本是偏实践的《HBase 实战》,另一本是偏大而全的手册型的《HBase 权威指南》。
- 当然,你也可以看看官方的 The Apache HBase™ Reference Guide
- 另外两个列数据库:
- ClickHouse - Open Source Distributed Column Database at Yandex
- Scaling Redshift without Scaling Costs at GIPHY
文档数据库 Document Database - MongoDB, SimpleDB, CouchDB
- Data Points - What the Heck Are Document Databases?
- eBay: Building Mission-Critical Multi-Data Center Applications with MongoDB
- The AWS and MongoDB Infrastructure of Parse: Lessons Learned
- Migrating Mountains of Mongo Data
- Couchbase Ecosystem at LinkedIn
- SimpleDB at Zendesk
- Github: Awesome MongoDB
数据结构数据库 Data structure Database - Redis
- Learn Redis the hard way (in production) at Trivago
- Twitter: How Twitter Uses Redis To Scale - 105TB RAM, 39MM QPS, 10,000+ Instances
- Slack: Scaling Slack’s Job Queue - Robustly Handling Billions of Tasks in Milliseconds Using Kafka and Redis
- GitHub: Moving persistent data out of Redis at GitHub
- Instagram: Storing Hundreds of Millions of Simple Key-Value Pairs in Redis
- Redis in Chat Architecture of Twitch (from 27:22)
- Deliveroo: Optimizing Session Key Storage in Redis
- Deliveroo: Optimizing Redis Storage
- GitHub: Awesome Redis
时序数据库 Time-Series Database
- What is Time-Series Data & Why We Need a Time-Series Database
- Time Series Data: Why and How to Use a Relational Database instead of NoSQL
- Beringei: High-performance Time Series Storage Engine @Facebook
- Introducing Atlas: Netflix’s Primary Telemetry Platform @Netflix
- Building a Scalable Time Series Database on PostgreSQL
- Scaling Time Series Data Storage - Part I @Netflix
- Design of a Cost Efficient Time Series Store for Big Data
- GitHub: Awesome Time-Series Database
图数据库 - Graph Platform
- 首先是 IBM Devloperworks 上的两个简介性的 PPT。
- Intro to graph databases, Part 1, Graph databases and the CRUD operations
- Intro to graph databases, Part 2, Building a recommendation engine with a graph database
- 然后是一本免费的电子书《Graph Database》。
- 接下来是一些图数据库的介绍文章。
- Handling Billions of Edges in a Graph Database
- Neo4j case studies with Walmart, eBay, AirBnB, NASA, etc
- FlockDB: Distributed Graph Database for Storing Adjacency Lists at Twitter
- JanusGraph: Scalable Graph Database backed by Google, IBM and Hortonworks
- Amazon Neptune
搜索数据库 - ElasticSearch
- Elasticsearch: The Definitive Guide 这是官网方的 ElasticSearch 的学习资料,基本上来说,看这个就够了。
- 接下来是 4 篇和性能调优相关的工程实践。
- Elasticsearch Performance Tuning Practice at eBay
- Elasticsearch at Kickstarter
- 9 tips on ElasticSearch configuration for high performance
- Elasticsearch In Production - Deployment Best Practices
- 最后是 GitHub 上的资源列表 GitHub: Awesome ElasticSearch 。
小结
好了,总结一下今天分享的内容。虽然有人会认为数据库与程序员无关,是 DBA 的事儿。但我坚信,数据库才真正是程序员的事儿。因为程序是需要和数据打交道的,所以程序员或架构师不仅需要设计数据模型,还要保证整体系统的稳定性和可用性,数据是整个系统中关键中的关键。
对于数据库方向,重点就是两种数据库,一种是以 SQL 为代表的关系型数据库,另一种是以非 SQL 为代表的 NoSQL 数据库。因而,在这篇文章中,我给出了 MySQL 和各种开源 NoSQL 的一些相关的有价值的文章和导读,主要是让你对这些数据库的内在有一定的了解,但又不会太深。同时给出了一些知名企业使用数据库的工程实践,这对于了解各种数据库的优劣非常有帮助,值得认真读读。
分布式架构入门(分布式架构)
学习分布式系统跟学习其它技术非常不一样,分布式系统涵盖的面非常广,具体来说涵盖如下几方面:
- 服务调度,涉及服务发现、配置管理、弹性伸缩、故障恢复等。
- 资源调度,涉及对底层资源的调度使用,如计算资源、网络资源和存储资源等。
- 流量调度,涉及路由、负载均衡、流控、熔断等。
- 数据调度,涉及数据复本、数据一致性、分布式事务、分库、分表等。
- 容错处理,涉及隔离、幂等、重试、业务补偿、异步、降级等。
- 自动化运维,涉及持续集成、持续部署、全栈监控、调用链跟踪等。
所有这些形成了分布式架构的整体复杂度,也造就了分布式系统中的很多很多论文、图书以及很多很多的项目。要学好分布式系统及其架构,我们需要大量的时间和实践才能真正掌握这些技术。
这里有几点需要你注意一下。
- 分布式系统之所以复杂,就是因为它太容易出错了。这意味着,你要把处理错误的代码当成正常功能的代码来处理。
- 开发一个健壮的分布式系统的成本是单体系统的几百倍甚至几万倍。这意味着,我们要自己开发一个,需要能力很强的开发人员。
- 非常健壮的开源的分布式系统并不多,或者说基本没有。这意味着,如果你要用开源的,那么你需要 hold 得住其源码。
- 管理或是协调多个服务或机器是非常难的。这意味着,我们要去读很多很多的分布式系统的论文。
- 在分布式环境下,出了问题是很难 debug 的。这意味着,我们需要非常好的监控和跟踪系统,还需要经常做演练和测试。
- 在分布式环境下,你需要更科学地分析和统计。这意味着,我们要用 P90 这样的统计指标,而不是平均值,我们还需要做容量计划和评估。
- 在分布式环境下,需要应用服务化。这意味着,我们需要一个服务开发框架,比如 SOA 或微服务。
- 在分布式环境下,故障不可怕,可怕的是影响面过大,时间过长。这意味着,我们需要花时间来开发我们的自动化运维平台。
总之,在分布式环境下,一切都变得非常复杂。要进入这个领域,你需要有足够多的耐性和足够强的心态来接受各式各样的失败。当拥有丰富的实践和经验后,你才会有所建树。这并不是一日之功,你可能要在这个领域花费数年甚至数十年的时间。
分布式架构入门
学习如何设计可扩展的架构将会有助于你成为一个更好的工程师。系统设计是一个很宽泛的话题。在互联网上,关于架构设计原则的资源也是多如牛毛。所以,你需要知道一些基本概念,对此,这里你先阅读下面两篇文章。
- Scalable Web Architecture and Distributed Systems ,这篇文章会给你一个大概的分布式架构是怎么来解决系统扩展性问题的粗略方法。
- Scalability, Availability & Stability Patterns ,这个 PPT 能在扩展性、可用性、稳定性等方面给你一个非常大的架构设计视野和思想,可以让你感受一下大概的全景图。
然后,我更强烈推荐 GitHub 上的一篇文档 - System Design Primer ,这个仓库主要组织收集分布式系统的一些与扩展性相关的资源,它可以帮助你学习如何构建可扩展的架构。
目前这个仓库收集到了好些系统架构和设计的基本方法。其中包括:CAP 理论、一致性模型、可用性模式、DNS、CDN、负载均衡、反向代理、应用层的微服务和服务发现、关系型数据库和 NoSQL、缓存、异步通讯、安全等。
我认为,上面这几篇文章基本足够可以让你入门了,因为其中基本涵盖了所有与系统架构相关的技术。这些技术,足够这世上 90% 以上的公司用了,只有超级巨型的公司才有可能使用更高层次的技术。
分布式理论
下面,我们来学习一下分布式方面的理论知识。
首先,你需要看一下 An introduction to distributed systems。 这只是某个教学课程的提纲,我觉得还是很不错的,几乎涵盖了分布式系统方面的所有知识点,而且辅以简洁并切中要害的说明文字,非常适合初学者提纲挈领地了解知识全貌,快速与现有知识结合,形成知识体系。这也是一个分布式系统的知识图谱,可以让你看到分布式系统的整体全貌。你可以根据这个知识图 Google 下去,然后你会学会所有的东西。
然后,你需要了解一下拜占庭将军问题(Byzantine Generals Problem)。这个问题是莱斯利·兰波特(Leslie Lamport)于 1982 年提出用来解释一致性问题的一个虚构模型(论文地址)。拜占庭是古代东罗马帝国的首都,由于地域宽广,守卫边境的多个将军(系统中的多个节点)需要通过信使来传递消息,达成某些一致的决定。但由于将军中可能存在叛徒(系统中节点出错),这些叛徒将努力向不同的将军发送不同的消息,试图会干扰一致性的达成。拜占庭问题即为在此情况下,如何让忠诚的将军们能达成行动的一致。
对于拜占庭问题来说,假如节点总数为 N
,叛变将军数为 F
,则当 N >= 3F + 1
时,问题才有解,即拜占庭容错(Byzantine Fault Tolerant,BFT)算法。拜占庭容错算法解决的是,网络通信可靠但节点可能故障情况下一致性该如何达成的问题。
最早由卡斯特罗(Castro)和利斯科夫(Liskov)在 1999 年提出的实用拜占庭容错(Practical Byzantine Fault Tolerant,PBFT)算法,是第一个得到广泛应用的 BFT 算法。只要系统中有 2/3 的节点是正常工作的,则可以保证一致性。PBFT 算法包括三个阶段来达成共识:预准备(Pre-Prepare)、准备(Prepare)和提交(Commit)。
这里有几篇和这个问题相关的文章,推荐阅读。
- Dr.Dobb’s - The Byzantine Generals Problem
- The Byzantine Generals Problem
- Practicle Byzantine Fault Tolerance
拜占庭容错系统研究中有三个重要理论:CAP、FLP 和 DLS。
-
CAP 定理,CAP 理论相信你应该听说过不下 N 次了。CAP 定理是分布式系统设计中最基础也是最为关键的理论。CAP 定理指出,分布式数据存储不可能同时满足以下三个条件:一致性(Consistency)、可用性(Availability)和 分区容忍(Partition tolerance)。 “在网络发生阻断(partition)时,你只能选择数据的一致性(consistency)或可用性(availability),无法两者兼得”。
论点比较直观:如果网络因阻断而分隔为二,在其中一边我送出一笔交易:“将我的十元给 A”;在另一半我送出另一笔交易:“将我的十元给 B”。此时系统要不是,a)无可用性,即这两笔交易至少会有一笔交易不会被接受;要不就是,b)无一致性,一半看到的是 A 多了十元而另一半则看到 B 多了十元。要注意的是,CAP 理论和扩展性(scalability)是无关的,在分片(sharded)或非分片的系统皆适用。
-
FLP impossibility,在异步环境中,如果节点间的网络延迟没有上限,只要有一个恶意的节点存在,就没有算法能在有限的时间内达成共识。但值得注意的是, “Las Vegas” algorithms(这个算法又叫撞大运算法,其保证结果正确,只是在运算时所用资源上进行赌博,一个简单的例子是随机快速排序,它的 pivot 是随机选的,但排序结果永远一致)在每一轮皆有一定机率达成共识,随着时间增加,机率会越趋近于 1。而这也是许多成功的共识算法会采用的解决问题的办法。
-
容错的上限,从DLS 论文 中我们可以得到以下结论:
- 在部分同步(partially synchronous)的网络环境中(即网络延迟有一定的上限,但我们无法事先知道上限是多少),协议可以容忍最多 1/3 的拜占庭故障(Byzantine fault)。
- 在异步(asynchronous)的网络环境中,具有确定性质的协议无法容忍任何错误,但这篇论文并没有提及 randomized algorithms,在这种情况下可以容忍最多 1/3 的拜占庭故障。
- 在同步(synchronous)网络环境中(即网络延迟有上限且上限是已知的),协议可以容忍 100% 的拜占庭故障,但当超过 1/2 的节点为恶意节点时,会有一些限制条件。要注意的是,我们考虑的是"具有认证特性的拜占庭模型(authenticated Byzantine)“,而不是"一般的拜占庭模型”;具有认证特性指的是将如今已经过大量研究且成本低廉的公私钥加密机制应用在我们的算法中。
当然,还有一个著名的“8 条荒谬的分布式假设(Fallacies of Distributed Computing)”。
- 网络是稳定的。
- 网络传输的延迟是零。
- 网络的带宽是无穷大。
- 网络是安全的。
- 网络的拓扑不会改变。
- 只有一个系统管理员。
- 传输数据的成本为零。
- 整个网络是同构的。
阿尔农·罗特姆 - 盖尔 - 奥兹(Arnon Rotem-Gal-Oz)写了一篇长文 Fallacies of Distributed Computing Explained 来解释为什么这些观点是错误的。另外,加勒思·威尔逊(Gareth Wilson)的文章 则用日常生活中的例子,对这些点做了通俗的解释。为什么我们深刻地认识到这 8 个错误?是因为,这要我们清楚地认识到——在分布式系统中错误是不可能避免的,我们在分布式系统中,能做的不是避免错误,而是要把错误的处理当成功能写在代码中。
下面分享几篇一致性方面的论文。
-
当然,关于经典的 CAP 理论,也存在一些误导的地方,这个问题在 2012 年有一篇论文 CAP Twelve Years Later: How the Rules Have Changed (中译版)中做了一些讨论,主要是说,在 CAP 中最大的问题就是分区,也就是 P,在 P 发生的情况下,非常难以保证 C 和 A。然而,这是强一致性的情况。
其实,在很多时候,我们并不需要强一致性的系统,所以后来,人们争论关于数据一致性和可用性时,主要是集中在强一致性的 ACID 或最终一致性的 BASE。当时,BASE 还不怎么为世人所接受,主要是大家都觉得 ACID 是最完美的模型,大家很难接受不完美的 BASE。在 CAP 理论中,大家总是觉得需要“三选二”,也就是说,P 是必选项,那“三选二”的选择题不就变成数据一致性 (consistency)、服务可用性 (availability) 间的“二选一”?
然而,现实却是,P 很少遇到,而 C 和 A 这两个事,工程实践中一致性有不同程度,可用性也有不同等级,在保证分区容错性的前提下,放宽约束后可以兼顾一致性和可用性,两者不是非此即彼。其实,在一个时间可能允许的范围内是可以取舍并交替选择的。
-
Harvest, Yield, and Scalable Tolerant Systems ,这篇论文是基于上面那篇“CAP 12 年后”的论文写的,它主要提出了 Harvest 和 Yield 概念,并把上面那篇论文中所讨论的东西讲得更为仔细了一些。
-
Base: An Acid Alternative (中译版),本文是 eBay 的架构师在 2008 年发表给 ACM 的文章,是一篇解释 BASE 原则,或者说最终一致性的经典文章。文中讨论了 BASE 与 ACID 原则的基本差异, 以及如何设计大型网站以满足不断增长的可伸缩性需求,其中有如何对业务做调整和折中,以及一些具体的折中技术的介绍。一个比较经典的话是——“在对数据库进行分区后, 为了可用性(Availability)牺牲部分一致性(Consistency)可以显著地提升系统的可伸缩性 (Scalability)”。
-
Eventually Consistent ,这篇文章是 AWS 的 CTO 维尔纳·沃格尔(Werner Vogels)在 2008 年发布在 ACM Queue 上的一篇数据库方面的重要文章,阐述了 NoSQL 数据库的理论基石——最终一致性,对传统的关系型数据库(ACID,Transaction)做了较好的补充。
小结
好了,总结一下今天分享的内容。文章的开头,我给出了学习分布式架构需要注意的几个关键点,然后列出了入门学习的资源,基本涵盖了所有与系统架构相关的技术。随后讲述了拜占庭容错系统研究中有三个重要理论:CAP、FLP 和 DLS,以及 8 条荒谬的分布式假设,从理论和认知等角度让你更为清楚地理解分布式系统。最后分享了几篇一致性相关的论文,很实用很经典,推荐阅读。
分布式架构经典图书和论文(分布式架构)
经典图书
首先,我推荐几本分布式架构方面的经典图书。
-
Distributed Systems for fun and profit,这是一本免费的电子书。作者撰写此书的目的是希望以一种更易于理解的方式,讲述以亚马逊的 Dynamo、谷歌的 Bigtable 和 MapReduce 等为代表的分布式系统背后的核心思想。
-
Designing Data Intensive Applications,这本书是一本非常好的书,我们知道,在分布式的世界里,数据结点的扩展是一件非常麻烦的事。这本书深入浅出地用很多的工程案例讲解了如何让数据结点做扩展。作者马丁·科勒普曼(Martin Kleppmann)在分布式数据系统领域有着很深的功底,并在这本书中完整地梳理各类纷繁复杂设计背后的技术逻辑,不同架构之间的妥协与超越,很值得开发人员与架构设计者阅读。
这本书深入到 B-Tree、SSTables、LSM 这类数据存储结构中,并且从外部的视角来审视这些数据结构对 NoSQL 和关系型数据库的影响。这本书可以让你很清楚地了解到真正世界的大数据架构中的数据分区、数据复制的一些坑,并提供了很好的解决方案。最赞的是,作者将各种各样技术的本质非常好地关联在一起,令你触类旁通。
而且,这本书完全就是抽丝剥茧,循循善诱,从“提出问题”到“解决问题”、“解决方案”、“优化方案”和“对比不同的方案”,一点一点地把非常晦涩的技术和知识展开。本书的引用相当多,每章后面都有几百个 Reference,通过这些 Reference 你可以看到更为广阔、更为精彩的世界。
-
[Distributed Systems: Principles and Paradigms](http://barbie.uta.edu/~jli/Resources/MapReduce&Hadoop/Distributed Systems Principles and Paradigms.pdf) ,本书是由计算机科学家安德鲁·斯图尔特·塔能鲍姆(Andrew S. Tanenbaum)和其同事马丁·范·斯蒂恩(Martin van Steen)合力撰写的,是分布式系统方面的经典教材。
语言简洁,内容通俗易懂,介绍了分布式系统的七大核心原理,并给出了大量的例子;系统讲述了分布式系统的概念和技术,包括通信、进程、命名、同步化、一致性和复制、容错以及安全等;讨论了分布式应用的开发方法(即范型)。但本书不是一本指导“如何做”的手册,仅适合系统性地学习基础知识,了解编写分布式系统的基本原则和逻辑。中文翻译版为《分布式系统原理与范型》(第二版)。
-
Scalable Web Architecture and Distributed Systems,
这是一本免费的在线小册子,其中文翻译版 可扩展的 Web 架构和分布式系统。本书主要针对面向互联网(公网)的分布式系统,但其中的原理或许也可以应用于其他分布式系统的设计中。作者的观点是,通过了解大型网站的分布式架构原理,小型网站的构建也能从中受益。本书从大型互联网系统的常见特性,如高可用、高性能、高可靠、易管理等出发,引出了一个类似于 Flickr 的典型的大型图片网站的例子。 -
Principles of Distributed Systems ,本书是苏黎世联邦理工学院的教材。它讲述了多种分布式系统中会用到的算法。虽然分布式系统的不同场景会用到不同算法,但并不表示这些算法都会被用到。不过,作为学生来说,掌握了算法设计的精髓也就能举一反三地设计出解决其他问题的算法,从而得到分布式系统架构设计中所需的算法。
经典论文
分布式事务
想了解分布式模型中最难的“分布式事务”,你需要看看 Google App Engine 联合创始人瑞恩·巴雷特(Ryan Barrett)在 2009 年的 Google I/O 大会上的演讲《Transaction Across DataCenter》(YouTube 视频)。
在这个演讲中,巴雷特讲述了各种经典的解决方案如何在一致性、事务、性能和错误上做平衡。而最后得到为什么分布式系统的事务只有 Paxos 算法是最好的。
下面这个图是这个算法中的结论。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Kxc6l59o-1666747390244)(data:image/jpeg;base64,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)]
你也可以移步看一下我在 Coolshell 上写的这篇文章《分布式系统的事务处理》。
Paxos 一致性算法
Paxos 算法,是莱斯利·兰伯特(Lesile Lamport)于 1990 年提出来的一种基于消息传递且具有高度容错特性的一致性算法。但是这个算法太过于晦涩,所以一直以来都属于理论上的论文性质的东西。其真正进入工程圈,主要是来源于 Google 的 Chubby lock——一个分布式的锁服务,用在了 Bigtable 中。直到 Google 发布了下面这两篇论文,Paxos 才进入到工程界的视野中来。
- Bigtable: A Distributed Storage System for Structured Data
- The Chubby lock service for loosely-coupled distributed systems
Google 与 Bigtable 相齐名的还有另外两篇论文。
- The Google File System
- MapReduce: Simplified Data Processing on Large Clusters
不过,这几篇文章中并没有讲太多的 Paxos 算法上的细节,反而是在Paxos Made Live - An Engineering Perspective 这篇论文中提到了很多工程实现的细节。这篇论文详细解释了 Google 实现 Paxos 时遇到的各种问题和解决方案,讲述了从理论到实际应用二者之间巨大的鸿沟。
Paxos 算法的原版论文比较晦涩,也不易懂。这里推荐一篇比较容易读的—— Neat Algorithms - Paxos 。这篇文章中还有一些小动画帮助你读懂。还有一篇可以帮你理解的文章是 Paxos by Examples。
Raft 一致性算法
因为 Paxos 算法太过于晦涩,而且在实际的实现上有太多的坑,并不太容易写对。所以,有人搞出了另外一个一致性的算法,叫 Raft。其原始论文是 In search of an Understandable Consensus Algorithm (Extended Version) ,寻找一种易于理解的 Raft 算法。这篇论文的译文在 InfoQ 上,题为《Raft 一致性算法论文译文》,推荐你读一读。
这里推荐几个不错的 Raft 算法的动画演示。
- Raft - The Secret Lives of Data
- Raft Consensus Algorithm
- Raft Distributed Consensus Algorithm Visualization
Gossip 一致性算法
后面,业内又搞出来一些工程上的东西,比如 Amazon 的 DynamoDB,其论文Dynamo: Amazon’s Highly Available Key Value Store 的影响力非常大。这篇论文中讲述了 Amazon 的 DynamoDB 是如何满足系统的高可用、高扩展和高可靠的。其中展示了系统架构是如何做到数据分布以及数据一致性的。GFS 采用的是查表式的数据分布,而 DynamoDB 采用的是计算式的,也是一个改进版的通过虚拟结点减少增加结点带来数据迁移的一致性哈希。
这篇文章中有几个关键的概念,一个是 Vector Clock,另一个是 Gossip 协议。
- Time, Clocks and the Ordering of Events in a Distributed System ,这篇文章是莱斯利·兰伯特(Leslie Lamport)于 1978 年发表的,并在 2007 年被选入 SOSP 的名人堂,被誉为第一篇真正的“分布式系统”论文,该论文曾一度成为计算机科学史上被引用最多的文章。分布式系统中的时钟同步是一个非常难的问题,因为分布式系统中是使用消息进行通信的,若使用物理时钟来进行同步,一方面是不同的 process 的时钟有差异,另一方面是时间的计算也有一定的误差,这样若有两个时间相同的事件,则无法区分它们谁前谁后了。这篇文章主要解决分布式系统中的时钟同步问题。
- 马萨诸塞大学课程 Distributed Operating System 中第 10 节 Clock Synchronization,这篇讲义讲述了时钟同步的问题。
- 关于 Vector Clock,你可以看一下 Why Vector Clocks are Easy 和 Why Vector Clocks are Hard 这两篇文章。
用来做数据同步的 Gossip 协议的原始论文是 Efficient Reconciliation and Flow Control for Anti-Entropy Protocols。Gossip 算法也是 Cassandra 使用的数据复制协议。这个协议就像八卦和谣言传播一样,可以“一传十、十传百”传播开来。但是这个协议看似简单,细节上却非常麻烦。
Gossip 协议也是 NoSQL 数据库 Cassandra 中使用到的数据协议,你可以上 YouTube 上看一下这个视频介绍: Understanding Gossip (Cassandra Internals)。
关于 Gossip 的一些图示化的东西,你可以看一下动画 Gossip Visualization。
分布式存储和数据库
除了前面的 Google 的 BigTable 和 Google File System 那两篇论文,还有 Amazon 的 DynamoDB 的论文,下面也有几篇也是要读一下的。
- 一篇是 AWS Aurora 的论文 Amazon Aurora: Design Considerations for High Throughput Cloud -Native Relation Databases。
- 另一篇是比较有代表的论文是 Google 的 Spanner: Google’s Globally-Distributed Database。 其 2017 年的新版论文:Spanner, TrueTime & The CAP Theorem。
- F1 - The Fault-Tolerant Distributed RDBMS Supporting Google’s Ad Business 。
- Cassandra: A Decentralized Structured Storage System 。
- CRUSH: Controlled, Scalable, Decentralized Placement of Replicated Data, 这里提到的算法被应用在了 Ceph 分布式文件系统中,其架构可以读一下 RADOS - A Scalable, Reliable Storage Service for Petabyte-scale
Storage Clusters 以及 Ceph 的架构文档。
分布式消息系统
- 分布式消息系统,你一定要读一下 Kafka 的这篇论文 Kafka: a Distributed Messaging System for Log Processing。
- Wormhole: Reliable Pub-Sub to Support Geo-replicated Internet Services ,Wormhole 是 Facebook 内部使用的一个 Pub-Sub 系统,目前还没有开源。它和 Kafka 之类的消息中间件很类似。但是它又不像其它的 Pub-Sub 系统,Wormhole 没有自己的存储来保存消息,它也不需要数据源在原有的更新路径上去插入一个操作来发送消息,是非侵入式的。其直接部署在数据源的机器上并直接扫描数据源的 transaction logs,这样还带来一个好处,Wormhole 本身不需要做任何地域复制(geo-replication)策略,只需要依赖于数据源的 geo-replication 策略即可。
- All Aboard the Databus! LinkedIn’s Scalable Consistent Change Data Capture Platform , 在 LinkedIn 投稿 SOCC 2012 的这篇论文中,指出支持对不同数据源的抽取,允许不同数据源抽取器的开发和接入,只需该抽取器遵循设计规范即可。该规范的一个重要方面就是每个数据变化都必须被一个单调递增的数字标注(SCN),用于同步。这其中的一些方法完全可以用做异地双活的系统架构中。(和这篇论文相关的几个链接如下:PDF 论文 、 PPT 分享。)
日志和数据
-
The Log: What every software engineer should know about real-time data’s unifying abstraction ,这篇文章好长,不过这是一篇非常好非常好的文章,这是每个工程师都应用知道的事,必看啊。你可以看中译版《日志:每个软件工程师都应该知道的有关实时数据的统一概念》。
-
The Log-Structured Merge-Tree (LSM-Tree) ,N 多年前,谷歌发表了 Bigtable 的论文,论文中很多很酷的方面,其一就是它所使用的文件组织方式,这个方法更一般的名字叫 Log Structured-Merge Tree。LSM 是当前被用在许多产品的文件结构策略:HBase、Cassandra、LevelDB、SQLite,甚至在 MongoDB 3.0 中也带了一个可选的 LSM 引擎(Wired Tiger 实现的)。LSM 有趣的地方是它抛弃了大多数数据库所使用的传统文件组织方法。实际上,当你第一次看它时是违反直觉的。这篇论文可以让你明白这个技术。(如果读起来有些费解的话,你可以看看中文社区里的这几篇文章:文章一、文章二。)
-
Immutability Changes Everything ,这篇论文是现任 Salesforce 软件架构师帕特·赫兰德(Pat Helland)在 CIDR 2015 大会上发表的(相关视频演讲)。
-
Tango: Distributed Data Structures over a Shared Log)。这个论文非常经典,其中说明了不可变性(immutability)架构设计的优点。随着为海量数据集存储和计算而设计的以数据为中心的新型抽象技术的出现,分布式系统比以往任何时候都更容易构建。但是,对于元数据的存储和访问不存在类似的抽象。
为了填补这一空白,Tango 为开发人员提供了一个由共享日志支持的内存复制数据结构(例如地图或树)的抽象。Tango 对象易于构建和使用,通过共享日志上简单的追加和读取操作来复制状态,而不是复杂的分布式协议。在这个过程中,它们从共享日志中获得诸如线性化、持久性和高可用性等属性。Tango 还利用共享日志支持跨不同对象的快速事务处理,允许应用程序跨机器进行状态划分,并在不牺牲一致性的情况下扩展到底层日志的上限。
分布式监控和跟踪
- Google 的分布式跟踪监控论文 - Dapper, a Large-Scale Distributed Systems Tracing Infrastructure, 其开源实现有三个 Zipkin、Pinpoint 和 HTrace。我个人更喜欢 Zipkin。
数据分析
- The Unified Logging Infrastructure for Data Analytics at Twitter ,Twitter 公司的一篇关于日志架构和数据分析的论文。
- [Scaling Big Data Mining Infrastructure: The Twitter Experience](http://www.datascienceassn/sites/default/files/Scaling Big Data Mining Infrastructure - The Twitter Experience.pdf) ,讲 Twitter 公司的数据分析平台在数据量越来越大,架构越来越复杂,业务需求越来越多的情况下,数据分析从头到底是怎么做的。
- Dremel: Interactive Analysis of Web-Scale Datasets,Google 公司的 Dremel,是一个针对临时查询提供服务的系统,它处理的是只读的多层数据。本篇文章介绍了它的架构与实现,以及它与 MapReduce 是如何互补的。
- Resident Distributed Datasets: a Fault-Tolerant Abstraction for In-Memory Cluster Computing,这篇论文提出了弹性分布式数据集(Resilient Distributed Dataset,RDD)的概念,它是一个分布式存储抽象,使得程序员可以在大型集群上以容错的方式执行内存计算;解释了其出现原因:解决之前计算框架在迭代算法和交互式数据挖掘工具两种应用场景下处理效率低下的问题,并指出将数据保存在内存中,可以将性能提高一个数量级;同时阐述了其实现原理及应用场景等多方面内容。很有趣儿,推荐阅读。
与编程相关的论文
- Distributed Programming Model
- PSync: a partially synchronous language for fault-tolerant distributed algorithms
- Programming Models for Distributed Computing
- Logic and Lattices for Distributed Programming
其它的分布式论文阅读列表
除了上面上的那些我觉得不错的论文,下面还有三个我觉得不错的分布式系统论文的阅读列表,你可以浏览一下。
- Services Engineering Reading List
- Readings in Distributed Systems
- Google Research - Distributed Systems and Parallel Computing
小结
今天分享的内容是分布式架构方面的经典图书和论文,并给出了导读文字,几乎涵盖了分布式系统架构方面的所有关键的理论知识。这些内容非常重要,是学好分布式架构的基石,请一定要认真学习。
分布式架构工程设计 (分布式架构)
要学好分布式架构,你首先需要学习一些架构指导性的文章和方法论,即分布式架构设计原则。下面是几篇很不错的文章,值得一读。
- Designs, Lessons and Advice from Building Large Distributed Systems,Google 杰夫·迪恩(Jeff Dean)2009 年一次演讲的 PPT。2010 年,斯坦福大学请杰夫·迪恩到大学里给他们讲了一节课,你可以在 YouTube 上看一下,Building Software Systems At Google and Lessons Learned ,其回顾了 Google 发展的历史。
- The Twelve-Factor App ,如今,软件通常会作为一种服务来交付,它们被称为网络应用程序,或软件即服务(SaaS)。12-Factor 为构建 SaaS 应用提供了方法论,是架构师必读的文章。(中译版)这篇文章在业内的影响力很大,必读!
- Notes on Distributed Systems for Young Bloods ,给准备进入分布式系统领域的人的一些忠告。
- On Designing and Deploying Internet-Scale Services(中译版),微软 Windows Live 服务平台的一些经验性的总结文章,很值得一读。
- 4 Things to Keep in Mind When Building a Platform for the Enterprise ,Box 平台 VP 海蒂·威廉姆斯(Heidi Williams)撰写的一篇文章,阐述了为企业构建平台时需要牢记的四件关于软件设计方面的事:1. Design Broadly, Build Narrowly; 2. Platforms Are Powerful and Flexible. Choose wisely what to expose when!;3. Build Incrementally, Get Feedback, and Iterate;4. Create a Platform-first Mentality。文章中有详细的解读,推荐看看。
- Principles of Chaos Engineering ,我们知道,Netflix 公司有一个叫 Chaos Monkey 的东西,这个东西会到分布式系统里“瞎搞”,以此来测试系统的健壮和稳定性。这个视频中,Netflix 分享了一些软件架构的经验和原则,值得一看。
- Building Fast & Resilient Web Applications ,伊利亚·格里高利克(Ilya Grigorik)在 Google I/O 2016 上的一次关于如何通过弹力设计来实现快速和可容错的网站架构的演讲,其中有好些经验分享。
- Design for Resiliency ,这篇文章带我们全面认识“弹力(Resiliency)”,以及弹力对于系统的重要性,并详细阐述了如何设计和实现系统的弹力。
- 微软的 Azure 网站上有一系列的 Design Principle 的文章,你可以看看这几篇: Design for Self-healing 、Design for Scaling Out 和 Design for Evolution 。
- Eventually Consistent ,AWS CTO 维尔纳·沃格尔斯(Werner Vogels)发布在自己 Blog 上的一篇关于最终一致性的好文。
- Writing Code that Scales ,Rackspace 的一篇很不错的博文,告诉我们一些很不错的写出高扩展和高性能代码的工程原则。
- Automate and Abstract: Lessons from Facebook on Engineering for Scale ,软件自动化和软件抽象,这是软件工程中最重要的两件事了。通过这篇文章,我们可以看到 Facebook 的关于这方面的一些经验教训。
设计模式
有了方法论后,你还需要学习一些比较细节的落地的技术。最好的方式就是学习被前人总结出来的设计模式,虽然设计模式也要分场景,但是设计模式可以让你知道一些套路,这些套路对于我们设计的分布式系统有非常大的帮助,不但可以让我们少走一些弯路,而且还能让我们更为系统和健壮地设计我们的架构。
下面是一些分布式架构设计模式的网站。
首先,需要重点推荐的是微软云平台 Azure 上的设计模式。 Cloud Design Patterns ,这个网站上罗列了分布式设计的各种设计模式,可以说是非常全面和完整。对于每一个模式都有详细的说明,并有对其优缺点的讨论,以及适用场景和不适用场景的说明,实在是一个非常不错的学习分布式设计模式的地方。其中有如下分类。
- 设计模式:可用性;
- 设计模式:数据管理;
- 设计模式:设计和实现;
- 设计模式:消息;
- 设计模式:管理和监控;
- 设计模式:性能和扩展;
- 设计模式:系统弹力;
- 设计模式:安全。
除此之外,还有其它的一些关于分布式系统设计模式的网站和相关资料。
- AWS Cloud Pattern ,这里收集了 AWS 云平台的一些设计模式。
- Design patterns for container-based distributed systems ,这是 Google 给的一篇论文,其中描述了容器化下的分布式架构的设计模式。
- Patterns for distributed systems ,这是一个 PPT,其中讲了一些分布式系统的架构模式,你可以顺着到 Google 里去搜索。
我个人觉得微服务也好,SOA 也好,都是分布式系统的一部分,这里有两个网站罗列了各种各样的服务架构模式。
- A Pattern Language for Micro-Services ;
- SOA Patterns。
当然,还有我在极客时间上写的那些分布式的设计模式的总结。
- 弹力设计篇,内容包括:认识故障和弹力设计、隔离设计、异步通讯设计、幂等性设计、服务的状态、补偿事务、重试设计、熔断设计、限流设计、降级设计、弹力设计总结。
- 管理设计篇,内容包括:分布式锁、配置中心、边车模式、服务网格、网关模式、部署升级策略等。
- 性能设计篇,内容包括:缓存、异步处理、数据库扩展、秒杀、边缘计算等。
设计与工程实践
分布式系统的故障测试
- FIT: Failure Injection Testing ,Netflix 公司的一篇关于做故障注入测试的文章。
- Automated Failure Testing ,同样来自 Netflix 公司的自动化故障测试的一篇博文。
- Automating Failure Testing Research at Internet Scale ,Netflix 公司伙同圣克鲁斯加利福尼亚大学和 Gremlin 游戏公司一同撰写的一篇论文。
弹性伸缩
- 4 Architecture Issues When Scaling Web Applications: Bottlenecks, Database, CPU, IO ,本文讲解了后端程序的主要性能指标,即响应时间和可伸缩性这两者如何能提高的解决方案,讨论了包括纵向和横向扩展,可伸缩架构、负载均衡、数据库的伸缩、CPU 密集型和 I/O 密集型程序的考量等。
- Scaling Stateful Objects ,这是一本叫《Development&Deployment of Multiplayer Online Games》书中一章内容的节选,讨论了有状态和无状态的节点如何伸缩的问题。虽然还没有写完,但是可以给你一些很不错的基本概念和想法。
- Scale Up vs Scale Out: Hidden Costs ,Coding Horror 上的一篇有趣的文章,详细分析了可伸缩性架构的不同扩展方案(横向扩展或纵向扩展)所带来的成本差异,帮助你更好地选择合理的扩展方案,可以看看。
- Best Practices for Scaling Out ,OpenShift 的一篇讨论 Scale out 最佳实践的文章。
- Scalability Worst Practices ,这篇文章讨论了一些最差实践,你需要小心避免。
- Reddit: Lessons Learned From Mistakes Made Scaling To 1 Billion Pageviews A Month ,Reddit 分享的一些关于系统扩展的经验教训。
- 下面是几篇关于自动化弹性伸缩的文章。
- Autoscaling Pinterest;
- Square: Autoscaling Based on Request Queuing;
- PayPal: Autoscaling Applications;
- Trivago: Your Definite Guide For Autoscaling Jenkins;
- Scryer: Netflix’s Predictive Auto Scaling Engine。
一致性哈希
- Consistent Hashing ,这是一个一致性哈希的简单教程,其中还有代码示例。
- Consistent Hashing: Algorithmic Tradeoffs ,这篇文章讲述了一致性哈希的一些缺陷和坑,以及各种哈希算法的性能比较,最后还给了一组代码仓库,其中有各种哈希算法的实现。
- Distributing Content to Open Connect ,Netflix 的一个对一致性哈希的实践,提出了 Uniform Consistent Hashing,是挺有意思的一篇文章。
- Consistent Hashing in Cassandra ,这是 Cassandra 中使用到的一致性哈希的相关设计。
数据库分布式
-
Life Beyond Distributed Transactions ,该文是 Salesforce 的软件架构师帕特·赫兰德(Pat Helland)于 2016 年 12 月发表的针对其在 2007 年 CIDR(创新数据库研究会议)上首次发表的同名文章的更新和缩写版本。业界谈到分布式事务通常指两段提交 2PC 事务(Spring/JEE 中 JTA 等) 或者 Paxos 与 Raft,这些事务都有明显缺点和局限性。
而赫兰德在本文讨论的是另外一种基于本地事务情况下的事务机制,它是基于实体和活动(Activity)的概念,其实类似 DDD 聚合根和领域事件的概念,这种工作流类型事务虽然需要程序员介入,依靠消息系统实现,但可以实现接近无限扩展的大型系统。赫兰德文中提出了重要的观点:“如果你不能使用分布式事务,那么你就只能使用工作流。”
-
How Sharding Works ,这是一篇很不错的探讨数据 Sharding 的文章。基本上来说,数据 Sharding 可能的问题都在这篇文章里谈到了。
-
Why you don’t want to shard ,这是 Percona 的一篇文章,其中表达了,不到万不得已不要做数据库分片。是的,最好还是先按业务来拆分,先把做成微服务的架构,然后把数据集变简单,然后再做 Sharding 会更好。
-
[How to Scale Big Data Applications](https://www.percona/sites/default/files/presentations/How to Scale Big Data Applications.pdf) ,这也是 Percona 给出的一篇关于怎样给大数据应用做架构扩展的文章。值得一读。
-
MySQL Sharding with ProxySQL ,用 ProxySQL 来支撑 MySQL 数据分片的一篇实践文章。
缓存
- 缓存更新的套路,这是我在 CoolShell 上写的缓存更新的几个设计模式,包括 Cache Aside、Read/Write Through、Write Behind Caching。
- Design Of A Modern Cache ,设计一个现代化的缓存系统需要注意到的东西。
- Netflix: Caching for a Global Netflix ,Netflix 公司的全局缓存架构实践。
- Facebook: An analysis of Facebook photo caching ,Facebook 公司的图片缓存使用分析,这篇文章挺有意思的,用数据来调优不同的缓存大小和算法。
- How trivago Reduced Memcached Memory Usage by 50% ,Trivago 公司一篇分享自己是如何把 Memcached 的内存使用率降了一半的实践性文章。很有意思,可以让你学到很多东西。
- Caching Internal Service Calls at Yelp ,Yelp 公司的缓存系统架构。
消息队列
- Understanding When to use RabbitMQ or Apache Kafka ,什么时候使用 RabbitMQ,什么时候使用 Kafka,通过这篇文章可以让你明白如何做技术决策。
- Trello: Why We Chose Kafka For The Trello Socket Architecture ,Trello 的 Kafka 架构分享。
- LinkedIn: Running Kafka At Scale ,LinkedIn 公司的 Kafka 架构扩展实践。
- Should You Put Several Event Types in the Same Kafka Topic? ,这个问题可能经常困扰你,这篇文章可以为你找到答案。
- Billions of Messages a Day - Yelp’s Real-time Data Pipeline ,Yelp 公司每天十亿级实时消息的架构。
- Uber: Building Reliable Reprocessing and Dead Letter Queues with Kafka ,Uber 公司的 Kafka 应用。
- Uber: Introducing Chaperone: How Uber Engineering Audits Kafka End-to-End ,Uber 公司对 Kafka 消息的端到端审计。
- Publishing with Apache Kafka at The New York Times ,纽约时报的 Kafka 工程实践。
- Kafka Streams on Heroku ,Heroku 公司的 Kafka Streams 实践。
- Salesforce: How Apache Kafka Inspired Our Platform Events Architecture ,Salesforce 的 Kafka 工程实践。
- Exactly-once Semantics are Possible: Here’s How Kafka Does it ,怎样用 Kafka 让只发送一次的语义变为可能。这是业界中一个很难的工程问题。
- Delivering billions of messages exactly once 同上,这也是一篇挑战消息只发送一次这个技术难题的文章。
- Benchmarking Streaming Computation Engines at Yahoo!。Yahoo! 的 Storm 团队在为他们的流式计算做技术选型时,发现市面上缺乏针对不同计算平台的性能基准测试。于是,他们研究并设计了一种方案来做基准测试,测试了 Apache Flink、Apache Storm 和 Apache Spark 这三种平台。文中给出了结论和具体的测试方案。(如果原文链接不可用,请尝试搜索引擎对该网页的快照。)
关于日志方面
- Using Logs to Build a Solid Data Infrastructure - Martin Kleppmann ,设计基于 log 结构应用架构的一篇不错的文章。
- Building DistributedLog: High-performance replicated log service ,Distributed 是 Twitter 2016 年 5 月份开源的一个分布式日志系统。在 Twitter 内部已经使用 2 年多。其主页在 distributedlog.io。这篇文章讲述了这个高性能日志系统的一些技术细节。另外,其技术负责人是个中国人,其在微信公众号中也分享过这个系统 Twitter 高性能分布式日志系统架构解析。
- LogDevice: a distributed data store for logs ,Facebook 分布式日志系统方面的一些工程分享。
关于性能方面
- Understand Latency ,这篇文章收集并整理了一些和系统响应时间相关的文章,可以让你全面了解和 Latency 有关的系统架构和设计经验方面的知识。
- Common Bottlenecks ,文中讲述了 20 个常见的系统瓶颈。
- Performance is a Feature ,Coding Horror 上的一篇让你关注性能的文章。
- Make Performance Part of Your Workflow ,这篇文章是图书《Designing for Performance》中的节选(国内没有卖的),其中给出来了一些和性能有关的设计上的平衡和美学。
- CloudFlare: How we built rate limiting capable of scaling to millions of domains,讲述了 CloudFlare 公司是怎样实现他们的限流功能的。从最简单的每客户 IP 限流开始分析,进一步讲到 anycast,在这种情况下 PoP 的分布式限流是怎样实现的,并详细解释了具体的算法。
关于搜索方面
- Instagram: Search Architecture
- eBay: The Architecture of eBay Search
- eBay: Improving Search Engine Efficiency by over 25%
- LinkedIn: Introducing LinkedIn’s new search architecture
- LinkedIn: Search Federation Architecture at LinkedIn
- Slack: Search at Slack
- DoorDash: Search and Recommendations at DoorDash
- Twitter: Search Service at Twitter (2014)
- Pinterest: Manas: High Performing Customized Search System
- Sherlock: Near Real Time Search Indexing at Flipkart
- Airbnb: Nebula: Storage Platform to Build Search Backends
各公司的架构实践
High Scalability ,这个网站会定期分享一些大规模系统架构是怎样构建的,下面是迄今为止各个公司的架构说明。
- YouTube Architecture
- Scaling Pinterest
- Google Architecture
- Scaling Twitter
- The WhatsApp Architecture
- Flickr Architecture
- Amazon Architecture
- Stack Overflow Architecture
- Pinterest Architecture
- Tumblr Architecture
- Instagram Architecture
- TripAdvisor Architecture
- Scaling Mailbox
- Salesforce Architecture
- ESPN Architecture
- Uber Architecture
- DropBox Design
- Splunk Architecture
小结
今天我们分享的内容是高手成长篇分布式架构部分的最后一篇——分布式架构工程设计,讲述了设计原则、设计模式等方面的内容,尤其整理和推荐了国内外知名企业的设计思路和工程实践,十分具有借鉴意义。
微服务
微服务是分布式系统中最近比较流行的架构模型,也是 SOA 架构的一个进化。微服务架构并不是银弹,所以,也不要寄希望于微服务架构能够解决所有的问题。微服务架构主要解决的是如何快速地开发和部署我们的服务,这对于一个能够适应快速开发和成长的公司是非常必要的。同时我也觉得,微服务中有很多很不错的想法和理念,所以学习微服务是每一个技术人员迈向卓越的架构师的必经之路。
首先,你需要看一下,Martin Fowler 的这篇关于微服务架构的文档 - Microservice Architecture (中译版),这篇文章说明了微服务的架构与传统架构的不同之处在于,微服务的每个服务与其数据库都是独立的,可以无依赖地进行部署。你也可以看看 Martin Fowler 老人家现身说法的视频。
另外,你还可以简单地浏览一下,各家对微服务的理解。
- AWS 的理解 - What are Microservices?。
- Microsoft 的理解 - Microservices architecture style。
- Pivotal 的理解 - Microservices。
微服务架构
接下来,你可以看一下 IBM 红皮书:Microservices Best Practices for Java ,这本书非常好,不但有通过把 Spring Boot 和 Dropwizard 来架建 Java 的微服务,而且还谈到了一些标准的架构模型,如服务注册、服务发现、API 网关、服务通讯、数据处理、应用安全、测试、部署、运维等,是相当不错的一本书。
当然,有一本书你也可以读一下—— 微服务设计。这本书全面介绍了微服务的建模、集成、测试、部署和监控,通过一个虚构的公司讲解了如何建立微服务架构。主要内容包括认识微服务在保证系统设计与组织目标统一上的重要性,学会把服务集成到已有系统中,采用递增手段拆分单块大型应用,通过持续集成部署微服务,等等。
与此相似的,也有其它的一系列文章,值得一读。
下面是 Nginx 上的一组微服务架构的系列文章。
- Introduction to Microservices
- Building Microservices: Using an API Gateway
- Building Microservices: Inter-Process Communication in a Microservices Architecture
- Service Discovery in a Microservices Architecture
- Event-Driven Data Management for Microservices
- Choosing a Microservices Deployment Strategy
- Refactoring a Monolith into Microservices
下面这是 Auto0 Blog 上一系列的微服务的介绍,有代码演示。
- An Introduction to Microservices, Part 1
- API Gateway. An Introduction to Microservices, Part 2
- An Introduction to Microservices, Part 3: The Service Registry
- Intro to Microservices, Part 4: Dependencies and Data Sharing
- API Gateway: the Microservices Superglue
还有 Dzone 的这个 Spring Boot 的教程。
- Microservices With Spring Boot - Part 1 - Getting Started
- Microservices With Spring Boot - Part 2 - Creating a Forex Microservice
- Microservices With Spring Boot - Part 3 - Creating Currency Conversion Microservice
- Microservices With Spring Boot - Part 4 - Using Ribbon for Load Balancing
- Microservices With Spring Boot - Part 5 - Using Eureka Naming Server
当然,如果你要玩得时髦一些的话,我推荐你使用下面的这套架构。
- 前端:React.js 或 Vue.js。
- 后端:Go 语言 + 微服务工具集 Go kit ,因为是微服务了,所以,每个服务的代码就简单了。既然简单了,也就可以用任何语言了,所以,我推荐 Go 语言。
- 通讯:gRPC,这是 Google 远程调用的一个框架,它比 Restful 的调用要快 20 倍到 50 倍的样子。
- API:Swagger ,Swagger 是一种 Restful API 的简单但强大的表示方式,标准的,语言无关,这种表示方式不但人可读,而且机器可读。可以作为 Restful API 的交互式文档,也可以作为 Restful API 形式化的接口描述,生成客户端和服务端的代码。今天,所有的 API 应该都通过 Swagger 来完成。
- 网关:Envoy 其包含了服务发现、负载均衡和熔断等这些特性,也是一个很有潜力的网关。当然,Kubernetes 也是很好的,而且它也是高扩展的,所以,完全可以把 Envoy 通过 Ingress 集成进 Kubernetes。这里有一个开源项目就是干这个事的 - contour。
- 日志监控:fluentd + ELK 。
- 指标监控:Prometheus 。
- 调用跟踪:Jaeger 或是 Zipkin,当然,后者比较传统一些,前者比较时髦,最重要的是,其可以和 Prometheus 和 Envory 集成。
- 自动化运维:Docker + Kubernetes 。
微服务和 SOA
在对微服务有了一定的认识以后,一定有很多同学分不清楚微服务和 SOA 架构,对此,你可以看一下这本电子书 - 《Microservices vs. Service-Oriented Architecture》。通过这本书,你可以学到,服务化架构的一些事实,还有基础的 SOA 和微服务的架构知识,以及两种架构的不同。这本书的作者马克·理查兹(Mark Richards)同学拥有十年以上的 SOA 和微服务架构的设计和实现的经验。
另外,还有几篇其它对比 SOA 和微服务的文章你也可以看看。
- DZone: Microservices vs. SOA
- DZone: Microservices vs. SOA - Is There Any Difference at All?
- Microservices, SOA, and APIs: Friends or enemies?
除此之外,我们还需要知道微服务和其它架构的一些不同和比较,这样我们就可以了解微服务架构的优缺点。下面几篇文章将帮助获得这些知识。
- PaaS vs. IaaS for Microservices Architectures: Top 6 Differences
- Microservices vs. Monolithic Architectures: Pros, Cons, and How Cloud Foundry (PaaS) Can Help
- Microservices - Not A Free Lunch!
- The Hidden Costs Of Microservices
设计模式和最佳实践
然后,你可以看一下微服务的一些设计模式。
- Microservice Patterns,微服务架构的设计模式和最佳实践。
- Microservice Antipatterns and Pitfalls,微服务架构的一些已知的反模式和陷阱。
- Microservice Architecture: All The Best Practices You Need To Know,这是一篇长文,里面讲述了什么是微服务、微服务架构的优缺点、微服务最大的挑战和解决方案是什么、如何避免出错,以及构建微服务架构的最佳实践等多方面的内容。推荐阅读。
- Best Practices for Building a Microservice Architecture ,这篇文章分享了构建微服务架构的最佳实践。
- Simplicity by Distributing Complexity,这是一篇讲如何使用事件驱动构建微服务架构的文章,其中有很多不错的设计上的基本原则。
相关资源
- Microservices Resource Guide ,这个网页上是 Martin Fowler 为我们挑选的和微服务相关的文章、视频、书或是 podcast。
- Awesome Microservices ,一个各种微服务资源和相关项目的集中地。
小结
好了,总结一下今天的内容。我认为,微服务中有很多很不错的想法和理念,所以学习微服务是每一个技术人员迈向卓越的架构师的必经之路。在这篇文章中,我先给出了 AWS、Microsoft 和 Pivotal 对微服务的理解;然后给出了好几个系列的教程,帮你全面学习和理解微服务架构;然后通过一系列文章帮你来区分何为微服务,何为 SOA;最后给出了微服务架构的设计模式和最佳实践,以及相关资源。相信通过这一系列内容的学习,你一定会对微服务有全面、透彻的理解。
容器化和自动化运维
这篇文章我们来重点学习 Docker 和 Kubernetes,它们已经是分布式架构和自动化运维的必备工具了。对于这两个东西,你千万不要害怕,因为技术方面都不算复杂,只是它们的玩法和传统运维不一样,所以你不用担心,只要你花上一点时间,一定可以学好的。
Docker
- 你可以先看一下 Docker 的官方介绍 Docker Overview 。
- 然后再去一个 Web 在线的 Playground 上体验一下, Katacoda Docker Playground 或者是 Play With Docker 。
- 接下来,跟着 Learn Docker 这个文档中的教程自己安装一个 Docker 的环境,实操一把。
- 然后跟着 Docker Curriculum 这个超详细的教程玩一下 Docker。
有了上述的一些感性体会之后,你就可以阅读 Docker 官方文档 Docker Documentation 了,这是学习 Docker 最好的方式。
如果你想了解一下 Docker 的底层技术细节,你可以参看我的文章。
- Docker 基础技术:Linux Namespace(上)
- Docker 基础技术:Linux Namespace(下)
- Docker 基础技术:Cgroup
- Docker 基础技术:AUFS
- Docker 基础技术:DeviceMapper
还有一些不错的与 Docker 网络有关的文章你需要阅读及实践一下。
- A container networking overview
- Docker networking 101 - User defined networks
- Understanding CNI (Container Networking Interface)
- Using CNI with Docker
Docker 有下面几种网络解决方案:Calico 、Flannel 和 Weave ,你需要学习一下。另外,还需要学习一下 netshoot ,这是一个很不错的用来诊断 Docker 网络问题的工具集。
关于这几个容器网络解决方案的性能对比,你可以看一下下面这几篇文章或报告。
- Battlefield: Calico, Flannel, Weave and Docker Overlay Network
- Comparison of Networking Solutions for Kubernetes
- Docker Overlay Networks: Performance analysis in high-latency enviroments
如果你对 Docker 的性能有什么问题的话,你可以看一下下面这些文章。
- IBM Research Report: An Updated Performance Comparison of Virtual Machines and Linux Containers
- An Introduction to Docker and Analysis of its Performance
下面是一些和存储相关的文章。
- Storage Concepts in Docker: Network and Cloud Storage
- Storage Concepts in Docker: Persistent Storage
- Storage Concepts in Docker: Shared Storage and the VOLUME directive
然后是跟运维相关的文章。
- Docker Monitoring with the ELK Stack: A Step-by-Step Guide
最后,推荐看看 Valuable Docker Links ,其中收集并罗列了一系列非常不错的 Docker 文章。
最佳实践
下面分享一些与 Docker 相关的最佳实践。
- Best Practices for Dockerfile ,Docker 官方文档里的 Dockerfile 的最佳实践。
- Docker Best Practices ,这里收集汇总了存在于各个地方的使用 Docker 的建议和实践。
- Container Best Practices ,来自 Atomic 项目,是一个介绍容器化应用程序的架构、创建和管理的协作型文档项目。
- Eight Docker Development Patterns ,八个 Docker 的开发模式:共享基础容器、共享同一个卷的多个开发容器、开发工具专用容器、测试环境容器、编译构建容器、防手误的安装容器、默认服务容器、胶黏容器。
Kubernetes
Kubernetes 是 Google 开源的容器集群管理系统,是 Google 多年大规模容器管理技术 Borg 的开源版本,也是 CNCF 最重要的项目之一,主要功能包括:
- 基于容器的应用部署、维护和滚动升级;
- 负载均衡和服务发现;
- 跨机器和跨地区的集群调度;
- 自动伸缩;
- 无状态服务和有状态服务;
- 广泛的 Volume 支持;
- 插件机制保证扩展性。
Kubernetes 发展非常迅速,已经成为容器编排领域的领导者。
首先,我推荐你阅读 Kubernetes 前世今生的一篇论文。
- Borg, Omega, and Kubernetes ,看看 Google 这十几年来从这三个容器管理系统中得到的经验教训。
学习 Kubernetes,有两个免费的开源电子书。
- 《Kubernetes Handbook》,这本书记录了作者从零开始学习和使用 Kubernetes 的心路历程,着重于经验分享和总结,同时也会有相关的概念解析。希望能够帮助你少踩坑,少走弯路,还会指引你关注 kubernetes 生态周边,如微服务构建、DevOps、大数据应用、Service Mesh、Cloud Native 等领域。
- 《Kubernetes 指南》,这本书旨在整理平时在开发和使用 Kubernetes 时的参考指南和实践总结,形成一个系统化的参考指南以方便查阅。
这两本电子书都不错,前者更像是一本学习教程,而且面明显广一些,还包括 Cloud Natvie、Service Mesh 以及微服务相关的东西。而后者聚焦于 Kubernetes 本身,更像一本参考书。
另外,我这两天也读完了《Kubernetes in Action》一书,感觉写的非常好,一本很完美的教科书,抽丝剥茧,图文并茂。如果你只想读一本有关 Kubernetes 的书来学习 Kubernetes,那么我推荐你就选这本。
但是也别忘了 Kubernetes 的官方网站:Kubernetes.io,上面不但有全面的文档 ,也包括一个很不错的 官方教程 。
此外,还有一些交互式教程,帮助你理解掌握,以及一些很不错的文章推荐你阅读。
一些交互式教程
- Katacoda
- Kubernetes Bootcamp
一些文章
这里还有一些不错的文档,你应该去读一下。
- Kubernetes tips & tricks
- Achieving CI/CD with Kubernetes
- How to Set Up Scalable Jenkins on Top of a Kubernetes Cluster
- 10 Most Common Reasons Kubernetes Deployments Fail Part I 和 Part II
- How to Monitor Kubernetes ,一共有 4 个篇章
- Logging in Kubernetes with Fluentd and Elasticsearch
- Kubernetes Monitoring: Best Practices, Methods, and Existing Solutions
网络相关的文章
要学习 Kubernetes,你只需要读一下,下面这个 Kubernetes 101 系列的文章。
- Kubernetes 101 - Networking
- Kubernetes networking 101 - Pods
- Kubernetes networking 101 - Services
- Kubernetes networking 101 - (Basic) External access into the cluster
- Kubernetes Networking 101 - Ingress resources
- Getting started with Calico on Kubernetes
CI/CD 相关的文章
- Automated Image Builds with Jenkins, Packer, and Kubernetes
- Jenkins setups for Kubernetes and Docker Workflow
- Lab: Build a Continuous Deployment Pipeline with Jenkins and Kubernetes
最佳实践
- Kubernetes Best Practices by Sachin Arote ,AWS 工程师总结的最佳实践。
- Kubernetes Best Practices by Sandeep Dinesh ,Google 云平台工程师总结的最佳实践。
Docker 和 Kubernetes 资源汇总
下面是 GitHub 上和 Docker & Kubernetes 相关的 Awesome 系列。
- Awesome Docker。
- Awesome Kubernetes。
虽然上面的这些系列非常全的罗列了很多资源,但是我觉得很不系统。对于系统的说明 Docker 和 Kubernetes 生态圈,我非常推荐大家看一下 The New Stack 为 Kubernetes 出的一系列的电子书或报告。
- The New Stack eBook Series ,非常完整和详实的 Docker 和 Kubernetes 生态圈的所有东西。
- Book 01: The Docker Container Ecosystem
- Book 02: Applications & Microservices with Docker & Containers
- Book 03: Automation & Orchestration with Docker & Containers
- Book 04: Network, Security & Storage with Docker & Containers
- Book 05: Monitoring & Management with Docker & Containers
- Book 06: Use Cases for Kubernetes
- Book 07: State of the Kubernetes Ecosystem
- Book 08: Kubernetes Deployment & Security Patterns
- Book 09: CI/CD with Kubernetes
- Book 10: Kubernetes solutions Directory
- Book 11: Guid to Cloud-Native Microservices
小结
总结一下今天的内容。Docker 和 Kubernetes 已经成为分布式架构和自动化运维方面的不可或缺的两大基本构成,是你必需要学习的。虽然它们的玩法跟传统运维不一样,但技术方面并不算复杂,只要你花上一点时间,一定会学好的。
在这篇文章中,我推荐了 Docker 和 Kubernetes 基础技术方面的学习资料,并给出了存储、运维、网络、CI/CD 等多方面的资料,同时列出了与之相关的最佳实践。相信认真学习和消化这些知识,你一定可以掌握 Docker 和 Kubernetes 两大利器。
机器学习和人工智能
我之前写过一篇机器学习的入门文章,因为我也是在入门和在学习的人,所以,那篇文章和这篇机器学习和人工智能方向的文章可能都会有点太肤浅。如果你有更好的学习方式或资料,欢迎补充。
基本原理简介
我们先来介绍一下机器学习的基本原理。
机器学习主要有两种方式,一种是监督式学习(Supervised Learning),另一种是非监督式学习(Unsupervised Learning)。下面简单地说一下这两者的不同。
-
监督式学习(Supervised Learning)。所谓监督式学习,也就是说,我们需要提供一组学习样本,包括相关的特征数据和相应的标签。我们的程序可以通过这组样本来学习相关的规律或是模式,然后通过得到的规律或模式来判断没有被打过标签的数据是什么样的数据。
举个例子,假设需要识别一些手写的数字,我们要找到尽可能多的手写体数字的图像样本,然后人工或是通过某种算法来明确地标注上什么是这些手写体的图片,谁是 1,谁是 2,谁是 3…… 这组数据叫样本数据,又叫训练数据(training data)。然后通过机器学习的算法,找到每个数字在不同手写体下的特征,找到规律和模式。通过得到的规律或模式来识别那些没有被打过标签的手写数据,以此完成识别手写体数字的目的。
-
非监督式学习(Unsupervised Learning)。对于非监督式学习,也就是说,数据是没有被标注过的,所以相关的机器学习算法需要找到这些数据中的共性。因为大量的数据是没被被标识过的,所以这种学习方式可以让大量的未标识的数据能够更有价值。而且,非监督式学习,可以为我们找到人类很难发现的数据里的规律或模型,所以也有人称这种学习为“特征点学习”,其可以让我们自动地为数据进行分类,并找到分类的模型。
一般来说,非监督式学习会应用在一些交易型的数据中。比如,你有一堆堆的用户购买数据,但是对于人类来说,我们很难找到用户属性和购买商品类型之间的关系。所以,非监督式学习算法可以帮助我们找到它们之间的关系。比如,一个在某年龄段的女性购买了某种肥皂,有可能说明这个女性在怀孕期,或是某人购买儿童用品,有可能说明这个人的关系链中有孩子,等等。于是,这些信息会被用作一些所谓的精准市场营销活动,从而可以增加商品销量。
我们这么来说吧,监督式学习是在被告诉过了正确的答案后的学习,而非监督式学习是在没有被告诉正确答案时的学习。所以,非监督式学习是在大量的非常乱的数据中找寻一些潜在的关系,这个成本也比较高。非监督式学习经常被用来检测一些不正常的事情发生,比如信用卡的诈骗或是盗刷。也被用在推荐系统,比如买了这个商品的人又买了别的什么商品,或是如果某个人喜欢某篇文章、某个音乐、某个餐馆,那么他可能会喜欢某个车、某个明星或某个地方。
在监督式学习算法下,我们可以用一组“狗”的照片来确定某个照片中的物体是不是狗。而在非监督式学习算法下,我们可以通过一个照片来找到其中有与其相似的事物的照片。这两种学习方式都有些有用的场景。
关于机器学习,你可以读一读 Machine Learning is Fun! ,这篇文章(中文翻译版)恐怕是全世界最简单的入门资料了。
- Data Science Simplified Part 1: Principles and Process
- Data Science Simplified Part 2: Key Concepts of Statistical Learning
- Data Science Simplified Part 3: Hypothesis Testing
- Data Science Simplified Part 4: Simple Linear Regression Models
- Data Science Simplified Part 5: Multivariate Regression Models
- Data Science Simplified Part 6: Model Selection Methods
- Data Science Simplified Part 7: Log-Log Regression Models
- Data Science Simplified Part 8: Qualitative Variables in Regression Models
- Data Science Simplified Part 9: Interactions and Limitations of Regression Models
- Data Science Simplified Part 10: An Introduction to Classification Models
- Data Science Simplified Part 11: Logistic Regression
相关课程
接下来,我们需要比较专业地学习一下机器学习了。
在学习机器学习之前,我们需要学习数据分析,所以,我们得先学一些大数据相关的东西,也就是 Data Science 相关的内容。下面是两个不错的和数据科学相关的教程以及一个资源列表。
- UC Berkeley’s Data 8: The Foundations of Data Science 和电子书 Computational and Inferential Thinking 会讲述数据科学方面非常关键的概念,会教你在数据中找到数据的关联、预测和相关的推断。
- Learn Data Science ,这是 GitHub 上的一本电子书,主要是一些数据挖掘的算法,比如线性回归、逻辑回归、随机森林、K-Means 聚类的数据分析。然后,donnemartin/data-science-ipython-notebooks 这个代码仓库中用 TensorFlow、scikit-learn、Pandas、NumPy、Spark 等把这些经典的例子实现了个遍。
- Data Science Resources List ,这个网站上有一个非常长的和数据科学相关的资源列表,你可以从中得到很多你想要的东西。
之后,有下面几门不错的在线机器学习的课程供你入门,也是非常不错。
- 吴恩达教授(Andrew Ng)在 Coursera 上的免费机器学习课程 非常棒。我强烈建议从此入手。对于任何拥有计算机或科学学位的人,或是还能记住一点点数学知识的人来说,都应该非常容易入门。这个斯坦福大学的课程请尽量拿满分。可以在 网易公开课 中找到这一课程。除此之外,吴恩达教授还有一组新的和深度学习相关的课程,现在可以在网易公开课上免费学习——Deep Learning Specialization。
- Deep Learning by Google ,Google 的一个关于深度学习的在线免费课程,其支持中英文。这门课会教授你如何训练和优化基本神经网络、卷积神经网络和长短期记忆网络。你将通过项目和任务接触完整的机器学习系统 TensorFlow。
- 卡内基梅隆大学汤姆·米切尔(Tom Mitchell)的机器学习 英文原版视频与课件 PDF 。
- 2013 年加利福尼亚理工学院亚瑟·阿布 - 穆斯塔法(Yaser Abu-Mostafa)的 Learning from Data 课程视频及课件 PDF,内容更适合进阶。
- 关于神经网络方面,YouTube 上有一个非常火的课程视频,由宾夕法尼亚大学的雨果·拉罗歇尔(Hugo Larochelle)出品的教学课程 - Neural networks class - Université de Sherbrooke 。
除此之外,还有很多的在线大学课程可以供你学习。比如:
- 斯坦福大学的《统计学学习》、《机器学习》、《卷积神经网络》、《深度学习之自然语言处理》等。
- 麻省理工大学的《神经网络介绍 》、《机器学习》、《预测》等。
更多的列表,请参看——Awesome Machine Learning Courses。
相关图书
-
《Pattern Recognition and Machine Learning》,这本书是机器学习领域的圣经之作。该书也是众多高校机器学习研究生课程的教科书,Google 上有[PDF 版的下载](http://users.isr.ist.utl.pt/~wurmd/Livros/school/Bishop - Pattern Recognition And Machine Learning - Springer 2006.pdf)。这本书很经典,但并不适合入门来看。GitHub 上有这本中的 Matlab 实现。
-
下面这两本电子书也是比较经典的,其中讲了很多机器学习的知识,可以当做手册或字典。
- 《Understanding Machine Learning: From Theory to Algorithms》。
- 《The Elements of Statistical Learning - Second Edition》。
-
《Deep Learning: Adaptive Computation and Machine Learning series》 中文翻译为《深度学习》。这本书由全球知名的三位专家伊恩·古德费洛(Ian Goodfellow)、友华·本吉奥(Yoshua Bengio)和亚伦·考维尔(Aaron Courville)撰写,是深度学习领域奠基性的经典教材。
全书内容包括 3 部分:第 1 部分介绍基本的数学工具和机器学习的概念,它们是深度学习的预备知识;第 2 部分系统深入地讲解现今已成熟的深度学习方法和技术;第 3 部分讨论某些具有前瞻性的方向和想法,它们被公认为是深度学习未来的研究重点。这本书的官网为 “deeplearningbook”,在 GitHub 上也有中文翻译 - 《Deep Learning 中文翻译》。
-
《Neural Networks and Deep Learning》(中文翻译版),这是一本非常不错的神经网络的入门书,在豆瓣上评分 9.5 分,从理论讲到了代码。虽然有很多数学公式,但是有代码相助,就不难理解了。其中讲了很多如激活函数、代价函数、随机梯度下降、反向传播、过度拟合和规范化、权重初始化、超参数优化、卷积网络的局部感受野、混合层、特征映射的东西。
-
《Introduction to Machine Learning with Python》,算是本不错的入门书,也是本比较易读的英文书。其是以 Scikit-Learn 框架来讲述的。如果你用过 Scikit 这个框架,那么你学这本书还是很不错的。
-
《Hands-On Machine Learning with Scikit-Learn and TensorFlow 》,这是一门以 TensorFlow 为工具的入门书,其用丰富的例子从实站的角度来让你学习。这本书对于无基础的人也是适合的,对于小白来说虽然略难但是受益匪浅。
相关文章
除了上述的那些课程和图书外,下面这些文章也很不错。
- YouTube 上的 Google Developers 的 Machine Learning Recipes with Josh Gordon ,这 9 集视频,每集不到 10 分钟,从 Hello World 讲到如何使用 TensorFlow,非常值得一看。
- 还有 Practical Machine Learning Tutorial with Python Introduction 上面一系列的用 Python 带着你玩 Machine Learning 的教程。
- Medium 上的 Machine Learning - 101 ,讲述了好些我们上面提到过的经典算法。
- Medium 上的 Marchine Learning for Humans。
- Dr. Jason Brownlee 的博客 ,也非常值得一读,其中好多的 “How-To”,会让你有很多的收获。
- Rules of Machine Learning: Best Practices for ML Engineering ,一些机器学习相关的最佳实践。
- i am trask ,也是一个很不错的博客。
- 关于 Deep Learning 中的神经网络,YouTube 上有介绍视频 Neural Networks。
- 麻省理工学院的电子书 Deep Learning。
- 用 Python 做自然语言处理Natural Language Processing with Python。
- 最后一个是 Machine Learning 和 Deep Learning 的相关教程列表,Machine Learning & Deep Learning Tutorials。
下面是一些和神经网络相关的不错的文章。
- The Unreasonable Effectiveness of Recurrent Neural Networks ,这是一篇必读的文章 ,告诉你为什么要学 RNN,以及展示了最简单的 NLP 形式。
- Neural Networks, Manifolds, and Topology ,这篇文章可以帮助你理解神经网络的一些概念。
- Understanding LSTM Networks ,解释了什么是 LSTM 的内在工作原理。
- Attention and Augmented Recurrent Neural Networks ,用了好多图来说明了 RNN 的 attention 机制。
- Recommending music on Spotify with deep learning ,一个在 Spotify 的实习生分享的音乐聚类的文章。
相关算法
下面是 10 个非常经典的机器学习的算法。
- 对于监督式学习,有如下经典算法。
- 决策树(Decision Tree),比如自动化放贷、风控。
- 朴素贝叶斯分类器(Naive Bayesian classifier),可以用于判断垃圾邮件、对新闻的类别进行分类,比如科技、政治、运动、判断文本表达的感情是积极的还是消极的、人脸识别等。
- 最小二乘法(Ordinary Least Squares Regression),是一种线性回归。
- 逻辑回归(Logisitic Regression),一种强大的统计学方法,可以用一个或多个变量来表示一个二项式结果。可以用于信用评分,计算营销活动的成功率,预测某个产品的收入。
- 支持向量机(Support Vector Machine,SVM),可以用于基于图像的性别检测、图像分类等。
- 集成方法(Ensemble methods),通过构建一组分类器,然后通过它们的预测结果进行加权投票来对新的数据点进行分类。原始的集成方法是贝叶斯平均,但最近的算法包括纠错输出编码、Bagging 和 Boosting。
- 对于无监督式的学习,有如下经典算法。
- 聚类算法(Clustering Algorithms)。聚类算法有很多,目标是给数据分类。有 5 个比较著名的聚类算法你必需要知道:K-Means、Mean-Shift、DBSCAN、EM/GMM、和 Agglomerative Hierarchical。
- 主成分分析(Principal Component Analysis,PCA)。PCA 的一些应用包括压缩、简化数据便于学习、可视化等。
- 奇异值分解(Singular Value Decomposition,SVD)。实际上,PCA 是 SVD 的一个简单应用。在计算机视觉中,第一个人脸识别算法使用 PCA 和 SVD 来将面部表示为"特征面"的线性组合,进行降维,然后通过简单的方法将面部匹配到身份。虽然现代方法更复杂,但很多方面仍然依赖于类似的技术。
- 独立成分分析(Independent Component Analysis,ICA)。ICA 是一种统计技术,主要用于揭示随机变量、测量值或信号集中的隐藏因素。
如果你想了解更全的机器学习的算法列表,你可以看一下 Wikipedia 上的 List of Machine Learning Algorithms。
在 A Tour of Machine Learning Algorithms ,这篇文章带你概览了一些机器学习算法,其中还有一个"脑图"可以下载,并还有一些 How-To 的文章供你参考。
对于这些算法,SciKit-Learn有一些文档供你学习。
- 1. Supervised learning
- 2.3 Clustering
- 2.5. Decomposing signals in components (matrix factorization problems)
- 3. Model selection and evaluation
- 4.3. Preprocessing data
相关资源
- 对于初学者来说,动手是非常非常重要的,不然,你会在理论的知识里迷失掉自己,这里有篇文章"8 Fun Machine Learning Projects for Beginners",其中为初学者准备了 8 个很有趣的项目,你可以跟着练练。
- 学习机器学习或是人工智能你需要数据,这里有一个非常足的列表给你足够多的公共数据 – 《Awesome Public Datasets》,其中包括农业、生物、天气、计算机网络、地球科学、经济、教育、金融、能源、政府、健康、自然语言、体育等。
- GitHub 上的一些 Awesome 资源列表。
- Awesome Deep Learning
- Awesome - Most Cited Deep Learning Papers
- Awesome Deep learning papers and other resources
小结
总结一下今天的内容。我首先介绍了机器学习的基本原理:监督式学习和非监督式学习,然后给出了全世界最简单的入门资料 Machine Learning is Fun!。随后给出了与机器学习密切相关的数据分析方面的内容和资料,然后推荐了深入学习机器学习知识的在线课程、图书和文章等,尤其列举了神经网络方面的学习资料。最后描述了机器学习的十大经典算法及相关的学习资料。
在机器学习和人工智能领域,我也在学习,也处于入门阶段,所以本文中推荐的内容,可能在你看来会有些浅。如果你有更好的信息和资料,欢迎补充。目前文章中给出来的是,我在学习过程中认为很不错的内容,我从中受益良多,所以希望它们也能为你的学习提供帮助。
前端基础和底层原理(前端方向)
对于前端的学习和提高,我的基本思路是这样的。首先,前端的三个最基本的东西 HTML 5、CSS 3 和 JavaScript(ES6)是必须要学好的。这其中有很多很多的技术,比如,CSS 3 引申出来的 Canvas(位图)、SVG(矢量图) 和 WebGL(3D 图),以及 CSS 的各种图形变换可以让你做出非常丰富的渲染效果和动画效果。
ES6 简直就是把 JavaScript 带到了一个新的台阶,JavaScript 语言的强大,大大释放了前端开发人员的生产力,让前端得以开发更为复杂的代码和程序,于是像 React 和 Vue 这样的框架开始成为前端编程的不二之选。
我一直认为学习任何知识都要从基础出发,所以这篇文章我会着重介绍基础知识和基本原理,尤其是如下的这些知识,都是前端程序员需要花力气啃下来的硬骨头。
- JavaScript 的核心原理。这里我会给出好些网上很不错的讲 JavaScript 的原理的文章或图书,你一定要学好语言的特性,并且详细了解其中的各种坑。
- 浏览器的工作原理。这也是一块硬骨头,我觉得这是前端程序员需要了解和明白的关键知识点,不然,你将无法深入下去。
- 网络协议 HTTP。也是要着重了解的,尤其是 HTTP/2,还有 HTTP 的几种请求方式:短连接、长连接、Stream 连接、WebSocket 连接。
- 前端性能调优。有了以上的这些基础后,你就可以进入前端性能调优的主题了,我相信你可以很容易上手各种性能调优技术的。
- 框架学习。我只给了 React 和 Vue 两个框架。就这两个框架来说,Virtual DOM 技术是其底层技术,组件化是其思想,管理组件的状态是其重点。而对于 React 来说,函数式编程又是其编程思想,所以,这些基础技术都是你需要好好研究和学习的。
- UI 设计。设计也是前端需要做的一个事,比如像 Google 的 Material UI,或是比较流行的 Atomic Design 等应该是前端工程师需要学习的。
而对于工具类的东西,这里我基本没怎么涉及,因为本文主要还是从原理和基础入手。那些工具我觉得都很简单,就像学习 Java 我没有让你去学习 Maven 一样,因为只要你去动手了,这种知识你自然就会获得,我们还是把精力重点放在更重要的地方。
下面我们从前端基础和底层原理开始讲起。先来讲讲 HTML5 相关的内容。
HTML 5
HTML 5 主要有以下几本书推荐。
- HTML 5 权威指南 ,本书面向初学者和中等水平 Web 开发人员,是牢固掌握 HTML 5、CSS 3 和 JavaScript 的必读之作。书看起来比较厚,是因为里面的代码很多。
- HTML 5 Canvas 核心技术 ,如果你要做 HTML 5 游戏的话,这本书必读。
对于 SVG、Canvas 和 WebGL 这三个对应于矢量图、位图和 3D 图的渲染来说,给前端开发带来了重武器,很多 HTML5 小游戏也因此蓬勃发展。所以,你可以学习一下。
学习这三个技术,我个人觉得最好的地方是 MDN。
- SVG: Scalable Vector Graphics
- Canvas API
- The WebGL API: 2D and 3D graphics for the web
最后是几个资源列表。
- Awesome HTML5 。GitHub 上的 Awesome HTML5,其中有大量的资源和技术文章。
- Awesome SVG
- Awesome Canvas
- Awesome WebGL
CSS
在《程序员练级攻略》系列文章最开始,我们就推荐过 CSS 的在线学习文档,这里再推荐一下 MDN Web Doc - CSS 。我个人觉得只要你仔细读一下文档,CSS 并不难学。绝大多数觉得难的,一方面是文档没读透,另一方面是浏览器支持的标准不一致。所以,学好 CSS 最关键的还是要仔细地读文档。
之后,在写 CSS 的时候,你会发现,你的 CSS 中有很多看起来相似的东西。你的 DRY - Don’t Repeat Yourself 洁癖告诉你,这是不对的。所以,你需要学会使用 LESS 和 SaSS 这两个 CSS 预处理工具,其可以帮你提高很多效率。
然后,你需要学习一下 CSS 的书写规范,前面的《程序员修养》一文中提到过一些,这里再补充几个。
- Principles of writing consistent, idiomatic CSS
- Opinionated CSS styleguide for scalable applications
- Google HTML/CSS Style Guide
如果你需要更有效率,那么你还需要使用一些 CSS Framework,其中最著名的就是 Twitter 公司的 Bootstrap,其有很多不错的 UI 组件,页面布局方案,可以让你非常方便也非常快速地开发页面。除此之外,还有,主打清新 UI 的 Semantic UI 、主打响应式界面的 Foundation 和基于 Flexbox 的 Bulma。
当然,在使用 CSS 之前,你需要把你浏览器中的一些 HTML 标签给标准化掉。所以,推荐几个 Reset 或标准化的 CSS 库:Normalize、MiniRest.css、sanitize.css 和 unstyle.css。
关于更多的 CSS 框架,你可以参看Awesome CSS Frameworks 上的列表。
接下来,是几个公司的 CSS 相关实践,供你参考。
- CodePen’s CSS
- Github 的 CSS
- Medium’s CSS is actually pretty f***ing good
- CSS at BBC Sport
- Refining The Way We Structure Our CSS At Trello
最后是一个可以写出可扩展的 CSS 的阅读列表 A Scalable CSS Reading List 。
JavaScript
下面是学习 JavaScript 的一些图书和文章。
- JavaScript: The Good Parts ,中文翻译版为《JavaScript 语言精粹》。这是一本介绍 JavaScript 语言本质的权威图书,值得任何正在或准备从事 JavaScript 开发的人阅读,并且需要反复阅读。学习、理解、实践大师的思想,我们才可能站在巨人的肩上,才有机会超越大师,这本书就是开始。
- Secrets of the JavaScript Ninja ,中文翻译版为《JavaScript 忍者秘籍》,本书是 jQuery 库创始人编写的一本深入剖析 JavaScript 语言的书。适合具备一定 JavaScript 基础知识的读者阅读,也适合从事程序设计工作并想要深入探索 JavaScript 语言的读者阅读。这本书有很多晦涩难懂的地方,需要仔细阅读,反复琢磨。
- Effective JavaScript ,Ecma 的 JavaScript 标准化委员会著名专家撰写,作者凭借多年标准化委员会工作和实践经验,深刻辨析 JavaScript 的内部运作机制、特性、陷阱和编程最佳实践,将它们高度浓缩为极具实践指导意义的 68 条精华建议。
- 接下来是 ES6 的学习,这里给三个学习手册源。
- ES6 in Depth,InfoQ 上有相关的中文版 - ES6 深入浅出。还可以看看 A simple interactive ES6 Feature list ,或是看一下 阮一峰翻译的 ES6 的教程 。
- ECMAScript 6 Tools ,这是一堆 ES6 工具的列表,可以帮助你提高开发效率。
- Modern JS Cheatsheet ,这个 Cheatsheet 在 GitHub 上有 1 万 6 千颗星,你就可见其影响力了。
- 然后,还有一组很不错的《You Don’t Know JS 系列》 的书。
- [You Don’t Know JS: “Up & Going”](https://github/getify/You-Dont-Know-JS/blob/master/up & going/README.md#you-dont-know-js-up–going)
- [You Don’t Know JS: “Scope & Closures”](https://github/getify/You-Dont-Know-JS/blob/master/scope & closures/README.md#you-dont-know-js-scope–closures)
- [You Don’t Know JS: “this & Object Prototypes”](https://github/getify/You-Dont-Know-JS/blob/master/this & object prototypes/README.md#you-dont-know-js-this–object-prototypes)
- [You Don’t Know JS: “Types & Grammar”](https://github/getify/You-Dont-Know-JS/blob/master/types & grammar/README.md#you-dont-know-js-types–grammar)
- [You Don’t Know JS: “Async & Performance”](https://github/getify/You-Dont-Know-JS/blob/master/async & performance/README.md#you-dont-know-js-async–performance)
- [You Don’t Know JS: “ES6 & Beyond”](https://github/getify/You-Dont-Know-JS/blob/master/es6 & beyond/README.md#you-dont-know-js-es6–beyond)
- 接下来是一些和编程范式相关的文章。
- Glossary of Modern JavaScript Concepts: Part 1 ,首先推荐这篇文章,其中收集了一些编程范式方面的内容,比如纯函数、状态、可变性和不可变性、指令型语言和声明式语言、函数式编程、响应式编程、函数式响应编程。
- Glossary of Modern JavaScript Concepts: Part 2 ,在第二部分中主要讨论了作用域和闭包,数据流,变更检测,组件化……
- 下面三篇文章是德米特里·索什尼科夫(Dmitry Soshnikov)个人网站上三篇讲 JavaScript 内在的文章。
- JavaScript. The Core: 2nd Edition
- JavaScript. The Core (older ES3 version)
- JS scope: static, dynamic, and runtime-augmented
- “How JavaScript Works” 是一组非常不错的文章(可能还没有写完),强烈推荐。这一系列的文章是 SessionStake 的 CEO 写的,现在有 13 篇,我感觉可能还没有写完。这个叫 亚历山大·兹拉特科夫(Alexander Zlatkov) 的 CEO 太猛了。
- An overview of the engine, the runtime, and the call stack
- Inside the V8 engine + 5 tips on how to write optimized code ,了解 V8 引擎。这里,也推荐 Understanding V8’s Bytecode 这篇文章可以让你了解 V8 引擎的底层字节码。
- Memory management + how to handle 4 common memory leaks ,内存管理和 4 种常见的内存泄露问题。
- Event loop and the rise of Async programming + 5 ways to better coding with async/await ,Event Loop 和异步编程。
- Deep dive into WebSockets and HTTP/2 with SSE + how to pick the right path ,WebSocket 和 HTTP/2。
- A comparison with WebAssembly + why in certain cases it’s better to use it over JavaScript ,JavaScript 内在原理。
- The building blocks of Web Workers + 5 cases when you should use them ,Web Workers 技术。
- Service Workers, their lifecycle and use cases ,Service Worker 技术。
- The mechanics of Web Push Notifications ,Web 端 Push 通知技术。
- Tracking changes in the DOM using MutationObserver ,Mutation Observer 技术。
- The rendering engine and tips to optimize its performance ,渲染引擎和性能优化。
- Inside the Networking Layer + How to Optimize Its Performance and Security ,网络性能和安全相关。
- Under the hood of CSS and JS animations + how to optimize their performance ,CSS 和 JavaScript 动画性能优化。
- 接下来是 Google Chrome 工程经理 阿迪·奥斯马尼(Addy Osmani) 的几篇 JavaScript 性能相关的文章,也是非常好的。
- The Cost Of JavaScript
- JavaScript Start-up Performance
- 其它与 JavaScript 相关的资源。
- JavScript has Unicode Problem ,这是一篇很有价值的 JavaScript 处理 Unicode 的文章。
- JavaScript Algorithms ,用 JavaScript 实现的各种基础算法库。
- JavaScript 30 秒代码 ,一堆你可以在 30 秒内看懂各种有用的 JavaScript 的代码,在 GitHub 上有 2 万颗星了。
- What the f*ck JavaScript ,一堆 JavaScript 搞笑和比较 tricky 的样例。
- Airbnb JavaScript Style Guide ,Airbnb 的 JavaScript 的代码规范,GitHub 上有 7 万多颗星。
- JavaScript Patterns for 2017 ,YouTube 上的一个 JavaScript 模式分享,值得一看。
浏览器原理
你需要了解一下浏览器是怎么工作的,所以,你必需要看《How browsers work》。这篇文章受众之大,后来被人重新整理并发布为《How Browsers Work: Behind the scenes of modern web browsers》,其中还包括中文版。这篇文章非常非常长,所以,你要有耐心看完。如果你想看个精简版的,可以看我在 Coolshell 上发的《浏览器的渲染原理简介》或是看一下这个幻灯片。
然后,是对 Virtual DOM 的学习。Virtual DOM 是 React 的一个非常核心的技术细节,它也是前端渲染和性能的关键技术。所以,你有必要要好好学习一下这个技术的实现原理和算法。当然,前提条件是你需要学习过前面我所推荐过的浏览器的工作原理。下面是一些不错的文章可以帮你学习这一技术。
- How to write your own Virtual DOM
- Write your Virtual DOM 2: Props & Events
- How Virtual-DOM and diffing works in React
- The Inner Workings Of Virtual DOM
- 深度剖析:如何实现一个 Virtual DOM 算法
- 以及两个 Vitual-DOM 实现供你参考:
- Matt-Esch/Virtual-DOM
- Maquette
网络协议
-
High Performance Browser Networking ,本书是谷歌公司高性能团队核心成员的权威之作,堪称实战经验与规范解读完美结合的产物。本书目标是涵盖 Web 开发者技术体系中应该掌握的所有网络及性能优化知识。
全书以性能优化为主线,从 TCP、UDP 和 TLS 协议讲起,解释了如何针对这几种协议和基础设施来优化应用。然后深入探讨了无线和移动网络的工作机制。最后,揭示了 HTTP 协议的底层细节,同时详细介绍了 HTTP 2.0、 XHR、SSE、WebSocket、WebRTC 和 DataChannel 等现代浏览器新增的能力。
-
另外,HTTP/2也是 HTTP 的一个新的协议,于 2015 年被批准通过,现在基本上所有的主流浏览器都默认启用这个协议。所以,你有必要学习一下这个协议。下面相关的学习资源。
- Gitbook - HTTP/2 详解
- http2 explained(中译版)
- HTTP/2 for a Faster Web
- Nginx HTTP/2 白皮书
- HTTP/2 的两个 RFC:
- RFC 7540 - Hypertext Transfer Protocol Version 2 (HTTP/2) ,HTTP/2 的协议本身。
- RFC 7541 - HPACK: Header Compression for HTTP/2 ,HTTP/2 的压缩算法。
-
新的 HTML5 支持 WebSocket,所以,这也是你要学的一个重要协议。
- HTML5 WebSocket: A Quantum Leap in Scalability for the Web ,这篇文章比较了 HTTP 的几种链接方式,Polling、Long Polling 和 Streaming,并引入了终级解决方案 WebSocket。你知道的,了解一个技术的缘由是非常重要的。
- StackOverflow: My Understanding of HTTP Polling, Long Polling, HTTP Streaming and WebSockets ,这是 StackOverflow 上的一个 HTTP 各种链接方式的比较,也可以让你有所认识。
- An introduction to Websockets ,一个 WebSocket 的简单教程。
- Awesome Websockets ,GitHub 的 Awesome 资源列表。
- 一些和 WebSocket 相关的想法,可以开阔你的思路:
- Introducing WebSockets: Bringing Sockets to the Web
- Websockets 101
- Real-Time Web by Paul Banks
- Are WebSockets the future?
小结
总结一下今天的内容。我一直认为学习任何知识都要从基础出发,所以今天我主要讲述了 HTML 5、CSS 3 和 JavaScript(ES6)这三大基础核心,给出了大量的图书、文章以及其他一些相关的学习资源。之后,我建议你学习浏览器的工作原理和网络协议相关的内容。我认为,掌握这些原理也是学好前端知识的前提和基础。值得花时间,好好学习消化。
前端性能优化和框架(前端方向)
首先是推荐几本前端性能优化方面的图书。
-
Web Performance in Action ,这本书目前国内没有卖的。你可以看电子版本,我觉得是一本很不错的书,其中有 CSS、图片、字体、JavaScript 性能调优等。
-
Designing for Performance ,这本在线的电子书很不错,其中讲了很多网页优化的技术和相关的工具,可以让你对整体网页性能优化有所了解。
-
High Performance JavaScript ,这本书在国内可以买到,能让你了解如何提升各方面的性能,包括代码的加载、运行、DOM 交互、页面生存周期等。雅虎的前端工程师尼古拉斯·扎卡斯(Nicholas C. Zakas)和其他五位 JavaScript 专家介绍了页面代码加载的最佳方法和编程技巧,来帮助你编写更为高效和快速的代码。你还会了解到构建和部署文件到生产环境的最佳实践,以及有助于定位线上问题的工具。
-
High Performance Web Sites: Essential Knowledge for Front-End Engineers ,这本书国内也有卖,翻译版为《高性能网站建设指南:前端工程师技能精髓》。作者给出了 14 条具体的优化原则,每一条原则都配以范例佐证,并提供了在线支持。
全书内容丰富,主要包括减少 HTTP 请求、Edge Computing 技术、Expires Header 技术、gzip 组件、CSS 和 JavaScript 最佳实践、主页内联、Domain 最小化、JavaScript 优化、避免重定向的技巧、删除重复 JavaScript 的技巧、关闭 ETags 的技巧、Ajax 缓存技术和最小化技术等。
-
除了上面这几本书之外,Google 的 Web Fundamentals 里的 Performance 这一章节也有很多非常不错的知识和经验。
接下来是一些最佳实践性的文档。
- Browser Diet ,前端权威性能指南(中文版)。这是一群为大型站点工作的专家们建立的一份前端性能的工作指南。
- PageSpeed Insights Rules ,谷歌给的一份性能指南和最佳实践。
- Best Practices for Speeding Up Your Web Site ,雅虎公司给的一份 7 个分类共 35 个最佳实践的文档。
接下来,重点推荐一个性能优化的案例学习网站 WPO Stats 。WPO 是 Web Performance Optimization 的缩写,这个网站上有很多很不错的性能优化的案例分享,一定可以帮助你很多。
然后是一些文章和案例。
- A Simple Performance Comparison of HTTPS, SPDY and HTTP/2 ,这是一篇比较浏览器的 HTTPS、SPDY 和 HTTP/2 性能的文章,除了比较之外,还可以让你了解一些技术细节。
- 7 Tips for Faster HTTP/2 Performance ,对于 HTTP/2 来说,Nginx 公司给出的 7 个增加其性能的小提示。
- Reducing Slack’s memory footprint ,Slack 团队减少内存使用量的实践。
- Pinterest: Driving user growth with performance improvements ,Pinterest 关于性能调优的一些分享,其中包括了前后端的一些性能调优实践。其实也是一些比较通用的玩法,这篇文章主要是想让前端的同学了解一下如何做整体的性能调优。
- 10 JavaScript Performance Boosting Tips ,10 个提高 JavaScript 运行效率的小提示,挺有用的。
- 17 Statistics to Sell Web Performance Optimization ,这个网页上收集了好些公司的 Web 性能优化的工程分享,都是非常有价值的。
- Getting started with the Picture Element ,这篇文章讲述了 Responsive 布局所带来的一些负面的问题。主要是图像适配的问题,其中引出了一篇文章"Native Responsive Images" ,值得一读。
- Improve Page Load Times With DNS Prefetching ,这篇文章教了你一个如何降低 DNS 解析时间的小技术——DNS prefetching。
- Jank Busting for Better Rendering Performance ,这是一篇 Google I/O 上的分享,关于前端动画渲染性能提升。
- JavaScript Memory Profiling ,这是一篇谷歌官方教你如何使用 Chrome 的开发工具来分析 JavaScript 内存问题的文章。
接下来是一些性能工具。在线性能测试分析工具太多,这里只推荐比较权威的。
- PageSpeed ,谷歌有一组 PageSpeed 工具来帮助你分析和优化网站的性能。Google 出品的,质量相当有保证。
- YSlow ,雅虎的一个网页分析工具。
- GTmetrix ,是一个将 PageSpeed 和 YSlow 合并起来的一个网页分析工具,并且加上一些 Page load 或是其它的一些分析。也是一个很不错的分析工具。
- Awesome WPO ,在 GitHub 上的这个 Awesome 中,你可以找到更多的性能优化工具和资源。
另外,中国的网络有各种问题(你懂的),所以,你不能使用 Google 共享的 JavaScript 链接来提速,你得用中国自己的。你可以到这里看看中国的共享库资源,Forget Google and Use These Hosted JavaScript Libraries in China 。
前端框架
接下来,要学习的是 Web 前端的几大框架。目前而言,前端社区有三大框架 Angular.js、React.js 和 Vue.js。我认为,React 和 Vue 更为强劲一些,所以,我这里只写和 React 和 Vue 相关的攻略。关于两者的比较,网上有好多文章。我这里推荐几篇我觉得还不错的,供你参考。
- Angular vs. React vs. Vue: A 2017 comparison
- React or Vue: Which JavaScript UI Library Should You Be Using?
- ReactJS vs Angular5 vs Vue.js - What to choose in 2018?
其实,比较这些框架的优缺点还有利弊并不是要比出个输赢,而是让你了解一下不同框架的优缺点。我觉得,这些框架都是可以学习的。而在我们生活工作中具体要用哪个框架,最好还是要有一些出发点,比如,你是为了找份好的工作,为了快速地搭一个网站,为了改造一个大规模的前端系统,还是纯粹地为了学习……
不同的目的会导致不同的决定。我并不希望上述的这些比较会让你进入“二选一”或是“三选一”的境地。我只是想通过这些文章让你知道这些框架的设计思路和实现原理,这些才是让你受益一辈子的事。
React.js 框架
下面先来学习一下 React.js 框架。
入门
React 学起来并不复杂,就看 React 官方教程 和其文档就好了( React 的中文教程 )。
然后,下面的文章会带你了解一下 React.js 的基本原理。
- All the fundamental React.js concepts ,这篇文章讲了所有的 React.js 的基本原理。
- Learn React Fundamentals and Advanced Patterns ,这篇文章中有几个短视频,每个视频不超过 5 分钟,是学习 React 的一个很不错的地方。
- Thinking in React,这篇文章将引导你完成使用 React 构建可搜索产品数据表的思考过程。
提高
学习一个技术最重要的是要学到其中的思想和方法。下面是一些我觉得学习 React 中最重要的东西。
-
状态,对于富客户端来说是非常麻烦也是坑最多的地方,这里有几篇文章你可以一读。
- Common React.js mistakes: Unneeded state ,React.js 编程的常见错误——不必要的状态。
- State is an Anti-Pattern ,关于如何做一个不错的组件的思考,很有帮助。
- Why Local Component State is a Trap ,一些关于 “Single state tree” 的想法。
- Thinking Statefully ,几个很不错的例子让你对声明式有状态的技术有更好的理解。
- 传统上,解决 React 的状态问题一般用 Redux。在这里推荐 Tips to learn React + Redux in 2018 。Redux 是一个状态粘合组件,一般来说,我们会用 Redux 来做一些数据状态和其上层 Component 上的同步。这篇教程很不错。
- 最后是 "State Architecture Patterns in React " 系列文章,非常值得一读。
- Part 1: A Review
- Part 2: The Top-Heavy Architecture, Flux and Performance
- Part 3: Articulation Points, zine and An Overall Strategy
- Part 4: Purity, Flux-duality and Dataflow
-
函数式编程。从 jQuery 过来的同学一定非常不习惯 React,而从 Java 等后端过来的程序员就会很习惯了。所以,我觉得 React 就是后端人员开发的,或者说是做函数式编程的人开发的。对此,你需要学习一下 JavaScript 函数式编程的东西。
这里推荐一本免费的电子书 《Professor Frisby’s Mostly Adequate Guide to Functional Programming》,其中译版为《JS 函数式编程指南中文版》。
下面有几篇文章非常不错。前两篇和函数式编程有关的文章非常值得一读。后三篇是一些比较实用的函数式编程和 React 结合的文章。
- Master the JavaScript Interview: What is Functional Programming?
- The Rise and Fall and Rise of Functional Programming (Composing Software)
- Functional UI and Components as Higher Order Functions
- Functional JavaScript: Reverse-Engineering the Hype
- Some Thoughts on Function Components in React
-
设计相关。接下来是学习一些 React 的设计模式。React Pattern 是一个不错的学习 React 模式的地方。除此之外,还有如下的一些不错的文章也会对你很有帮助的。
- React Higher Order Components in depth
- Presentational and Container Components
- Controlled and uncontrolled form inputs in React don’t have to be complicated
- Function as Child Components
- Writing Scalable React Apps with the Component Folder Pattern
- Reusable Web Application Strategies
- Characteristics of an Ideal React Architecture
-
实践和经验
还有一些不错的实践和经验。
- 9 things every React.js beginner should know
- Best practices for building large React applications
- Clean Code vs. Dirty Code: React Best Practices
- How to become a more productive React Developer
- 8 Key React Component Decisions
资源列表
最后就是 React 的资源列表。
- Awesome React ,这是一些 React 相关资源的列表,很大很全。
- React/Redux Links ,这也是 React 相关的资源列表,与上面不一样的是,这个列表主要收集了大量的文章,其中讲述了很多 React 知识和技术,比上面的列表好很多。
- React Rocks ,这个网站主要收集各种 React 的组件示例,可以让你大开眼界。
Vue.js 框架
Vue 可能是一个更符合前端工程师习惯的框架。不像 React.js 那样使用函数式编程方式,是后端程序员的思路。
- 通过文章 “Why 43% of Front-End Developers want to learn Vue.js” ,你可以看出其编程方式和 React 是大相径庭的,符合传统的前端开发的思维方式。
- 通过文章 Replacing jQuery With Vue.js: No Build Step Necessary ,我们可以看到,从 jQuery 是可以平滑过渡到 Vue 的。
- 另外,我们可以通过 “10 things I love about Vue” ,了解 Vue 的一些比较优秀的特性。
最令人高兴的是,Vue 的作者是我的好朋友尤雨溪(Evan You),最近一次对他的采访 “Vue on 2018 - Interview with Evan You” 当中有很多故事以及对 Vue 的展望。(注意:Vue 是完全由其支持者和用户资助的,这意味着它更接近社区而不受大公司的控制。)
要学习 Vue 并不难,我认为上官网看文档( Vue 官方文档(中文版)),照着搞一搞就可以很快上手了。Vue.js screencasts 是一个很不错的英文视频教程。
另外,推荐 新手向:Vue 2.0 的建议学习顺序 ,这是 Vue 作者写的,所以有特殊意义。
Vue 的确比较简单,有 Web 开发经验的人上手也比较快,所以这里也不会像 React 那样给出很多的资料。下面是一些我觉得还不错的内容,推荐给你。
- How not to Vue ,任何技术都有坑,了解 Vue 的短板,你就能扬长避短,就能用得更好。
- Vue.js Component Communication Patterns
- 4 AJAX Patterns For Vue.js Apps
- How To (Safely) Use A jQuery Plugin With Vue.js
- 7 Ways To Define A Component Template in Vue.js
- Use Any Javascript Library With Vue.js
- Dynamic and async components made easy with Vue.js
当然,最后一定还有 Awesome Vue ,Vue.js 里最为巨大最为优秀的资源列表。
小结
总结一下今天的内容。我先介绍的是前端性能优化方面的内容,推荐了图书、最佳实践性的文档、案例,以及一些在线性能测试分析工具。随后重点讲述了 React 和 Vue 两大前端框架,给出了大量的文章、教程和相关资源列表。我认为,React.js 使用函数式编程方式,更加符合后端程序员的思路,而 Vue 是更符合前端工程师习惯的框架。因此,两者比较起来,Vue 会更容易上手一些。
UI/UX 设计(前端方向)
上面的技术都讲完了,前端还有一个很重要的事就是设计。作为前端人员,我们有必要了解现在的一些知名且流行的设计语言或是一些设计规范或是设计方法,学习它们的设计思想和方法,有助于我们拓宽眼界、与时俱进。我并不觉得这些内容是设计师要学习的,如果你要成为一个前端程序员,那么学习这些设计上的东西可以让你有更好的成长空间。
对于学习设计的新手来说,推荐看看 7 steps to become a UI/UX designer ,这是一篇很不错的让新手入门的文章,非常具有指导性。首先,你得开始学习设计的一些原则和套路,如配色、平衡、排版、一致性等。还有用户体验的 4D 步骤——Discover、Define、Develop 和 Delivery。然后,开始到一些网站上找灵感。接下来,是到不同的网站上读各种文章和资源,开始学习使用设计工具,最后是找人拜师。此外,其中还链接了其它一些不错的文章、网站、博客和工具。我认为,这篇文章是一篇很不错的设计师从入门到精通的练级攻略。
虽然有这么一个速成的教程,但我觉得还是应该系统地学习一下,所以有了下面这些推荐。
图书和文章推荐
先推荐几本书。
- Don’t Make Me Think ,这是我看的第一本和设计相关的书。这本书对我的影响也比较深远。这本书践行了自己的理论,整本书短小精悍,语言轻松诙谐,书中穿插大量色彩丰富的屏幕截图、趣味丛生的卡通插图以及包含大量信息的图表,使枯燥的设计原理变得平易近人。
- Simple and Usable Web,Mobile,and Interaction Design ,中文版译名为《简约至上》。本书作者贾尔斯(Giles)有 20 多年交互式设计的探索与实践。提出了合理删除、分层组织、适时隐藏和巧妙转移这四个达成简约至上的终极策略,讲述了为什么应该站在主流用户一边,以及如何从他们的真实需求和期望出发,简化设计,提升易用性。
- Designing with the Mind in Mind: Simple Guide to Understanding User Interface Design Rules ,中文版译名为《认知与设计:理解 UI 设计准则》。这本书语言清晰明了,将设计准则与其核心的认知学和感知科学高度统一起来,使得设计准则更容易在具体环境中得到应用。涵盖了交互计算机系统设计的方方面面,为交互系统设计提供了支持工程方法。不仅如此,这也是一本人类行为原理的入门书。
- Designing Interfaces: Patterns for Effective Interaction Design ,中文版译名为《界面设计模式》。这本书开篇即总结了“与人有关”的各类问题,为读者提供了界面设计总体思路上的指引,帮助读者举一反三。然后,收集并分析了很多常用的界面设计模式,帮助读者理解在实现级别的各种常用解决方案,将它们灵活地运用到自己的设计中。
除了上面的这几本书,还有下面的这几篇文章也是很不错的,推荐一读。
- The Psychology Principles Every UI/UX Designer Needs to Know ,这篇文章讲述了 6 大用户界面用户体验设计的心理学原则。
- 18 designers predict UI/UX trends for 2018, 我倒不觉得这篇文章中所说的 UI/UX 是在 2018 年的趋势,我反而觉得,这 18 条原则是指导性的思想。
- The Evolution of UI/UX Designers Into Product Designers ,这篇文章是 Adobe 公司的一篇博客,其在回顾整个产品设计的演化过程中有一些不错的思考和想法,并提供了一些方法论。
原子设计(Atomic Design)
在 2013 年网页设计师布拉德·弗罗斯特(Brad Frost)从化学中受到启发:原子(Atoms)结合在一起,形成分子(Molecules),进一步结合形成生物体(Organisms)。布拉德将这个概念应用在界面设计中,我们的界面就是由一些基本的元素组成的。
乔希·杜克(Josh Duck)的“HTML 元素周期表”完美阐述了我们所有的网站、App、企业内部网、hoobadyboops 等是如何由相同的 HTML 元素组成的。通过在大层面(页)和小层面(原子)同时思考界面,布拉德认为,可以利用原子设计建立一个适应组件的动态系统。
为什么要玩原子设计,我认为,这对程序员来说是非常好理解的,因为这就是代码模块化重用化的体现。于是,你就是要像搭积木一样开发和设计网页,当你把其模块化组件化了,也更容易规范整体的风格,而且容易维护……这些都意味着你可以更容易地维护你的代码。所以,这个方法论导致了 Web 组件化的玩法。这是设计中非常重要的方法论。
关于这个设计方法论,你可以阅读一下下面这几篇文章。
- Atomic Design 原子设计┃构建科学规范的设计系统
- 网页设计:Atomic Design 简介及工作实例
但是,真正权威的地方还是布拉德·弗罗斯特的电子书、博客和实验室,可以从中获取更多的信息。
- 电子书:Atomic Design by Brad Frost 是布拉德·弗罗斯特写的一本书。
- 博 客:Atomic Design 是布拉德·弗罗斯特的博客。
- 实验室:Pattern lab 是布拉德·弗罗斯特依照这个设计系统所建立的一套工具,可以前往 Pattern Lab 的 GitHub 来试试 Atomic design。
接下来是关于这个设计方法和 React.js 框架的几篇文章。
- Atomic Design with React
- Atomic Components: Managing Dynamic React Components using Atomic Design
设计语言和设计系统
下面来介绍一下设计语言和设计系统。
Fluent Design System
Fluent Design System 中文翻译为流畅设计体系,是微软于 2017 年开发的设计语言。流畅设计是 Microsoft Design Language 2 的改版,其中包含为所有面向 Windows 10 设备和平台设计的软件中的设计和交互的指导原则。
该体系基于五个关键元素:光感、深度、动效、材质和缩放。新的设计语言包括更多对动效、深度及半透明效果的使用。过渡到流畅设计体系是一个长期项目,没有具体的完成目标,但是从创作者更新以来,新设计语言的元素已被融入到个别应用程序中。它将在未来的 Windows 10 秋季创作者更新中更广泛地使用,但微软也表示,该设计体系不会在秋季创作者更新内完成。
微软于 2017 年 5 月 11 日的 Microsoft Build 2017 开发者大会上公开了该设计体系。
- What’s new and coming for Windows UI: XAML and composition ,从概念上讲了一下 Fluent Design System 的各个部分。
- Introducing Fluent Design ,介绍了 Fluent Design System 的各个部分。
还有 Build 2018 上的一些微软的 YouTube 分享。
- Fluent Design: Evolving our Design System : Build 2018
- Microsoft Build 2018 - Fluent Design System Demo
- Microsoft Build 2018 - Fluent Design System Evolution
- Fluent Design System inside of Microsoft: Office : Build 2018
Material Design
Material Design 中文翻译为质感设计,或是材质设计、材料设计。这是由 Google 开发的设计语言。扩展于 Google Now 的“卡片”设计,Material Design 基于网格的布局、响应动画与过渡、填充、深度效果(如光线和阴影)。设计师马蒂亚斯·杜阿尔特(Matías Duarte)解释说:“与真正的纸张不同,我们的数字材质可以智能地扩大和变形。材质具有实体的表面和边缘。接缝和阴影表明组件的含义。”Google 指出他们的新设计语言基于纸张和油墨。
Material Design 于 2014 年的 Google I/O 大会上发布(参看 Google I/O 2014 - Material witness: How Android material applications work)。其可借助 v7 appcompat 库用于 Android 2.1 及以上版本,几乎支持所有 2009 年以后制造的 Android 设备。随后,Material Design 扩展到 Google 的网络和移动产品阵列,提供一致的跨平台和应用程序体验。Google 还为第三方开发人员发布了 API,开发人员可将质感设计应用到他们的应用程序中。
除了到 官网 学习 Material Design,你还可以访问 Material Design 中文版 来学习。
另外,Wikipedia 上有一张 Material Design 实现的比较表,供你参考。
下面是几个可供你使用的 Material UI 的工程实现。
- Material Design Lite ,这是 Google 官方的框架,简单易用。
- Materialize ,一组类似于 Bootstrap 的前端 UI 框架。
- Material-UI 是基于 Google Material Design 的 React 组件实现。
- MUI 是一个轻量级的 CSS 框架,遵循 Google 的 Material Design 设计方针。
其它公司
接下来再来推荐其它几家公司的设计语言。
- 苹果公司的设计指南,在这个网站有苹果的各种设备的设计规范和指导,一方面可以让你的 App 能和苹果的 UI 融合在一起,另一方面,你也可以从中看到苹果的审美和思维方式。
- IBM 公司的设计语言 ,我们总觉得 IBM 公司是一家比较传统的没有新意的公司,但是并不是这样的。IBM 公司的这个设计语言的确比较出众。所以,在这里推荐一下。
- Salesforce 公司的 Lightning Design System ,是在 Salesforce 生态系统中用于创建统一 UI 的设计模式、组件和指南的集合,是一个企业级的产品。
- Facebook Design - What’s on our mind? ,Facebook 的设计师们收集的一系列的文章、视频和资源。很不错哦。
动画效果设计
我认为,要了解 Web 动画效果设计的第一步,最好的地方是 CodePen。这个网站不只是让人分享 HTML、CSS 和 JavaScript 代码的网站。其中也有很多分享样例都和动画效果有关。这个网站可以让你对动画效果有一些感性认识,当然还有代码供你参考。
接下来,我们要了解动画效果设计的一些方法。基本上来说,动画设计都会受 “动画的 12 项基本法则 ”的影响,这个方法论源自于迪士尼动画师奥利·约翰斯顿(Ollie Johnston)和弗兰克·托马斯(Frank Thomas)在 1981 年所出的《The Illusion of Life: Disney Animation》一书。这些法则已被普遍采用,至今仍与制作 3D 动画法则有关联。这里还有一篇文章 “Understand the 12 principles of animation” 是对这个法则的解读和理解。
除此之外,还有几个动画设计指南和相关文章供你参考和学习。
- 6 Animation Guidelines for UX Design。这是 Prototypr 公司的一个指南,其中主要指出,动画效果不是为了炫配,而是能让你的 UI/UX 能活起来,自然,不消耗时间,并且是生动故事型的动画效果。其中还推荐了如下几篇很不错的文章。
- Transitional Interfaces
- UI Animation and UX: A Not-So-Secret Friendship
- Invisible animation
- Creating Usability with Motion: The UX in Motion Manifesto
- Designing Interface Animation ,这篇文章同样说明,任何一个小动画都是要讲一个微故事的,而且这些微故事会和你的品牌和产品理念相融合。动画会给人更深的印象,让人们更容易记住你。这篇文章主要是讲品牌动画。
- Animation principles in motion design ,这篇文章有点像设计模式,给了一些动画效果的套路和演示。
- Creating Usability with Motion: The UX in Motion Manifesto
- Integrating Animation into a Design System
- Great UI/UX Animations 是设计师丹尼尔(Daniel)收集的一些很不错的动画,可以给你一些灵感。
- Great UI/UX Animations 第一组
- Great UI/UX Animations 第二组
相关资源
下面分享一下 UI/UX 设计的相关资源。文章资源主要有以下这些。
文章资源
- Web Designer News ,一个文章聚合的网站。除此之外,还有两个文章聚合网站,你也可以订阅。一个是Designer News ,另一个是 Reddit Web Design。
- Marvel Blog ,Marvel 团队的博客。
- The Next Web ,内容主要涵盖国际技术新闻、商业和文化等多个方面。
- Medium - Design ,Medium 现在已经成为一个好文章的集散地了,这个地方必去。
- Smashing Magazine ,这个地方是给专业的 Web 设计师和程序员的。不但有设计还有 HTML、CSS 和 JavaScript 等各种资源。
- Sitepoint ,这个网站上也有很多不错的给 Web 前端程序员和设计师看的文章(当然,给程序员看的有点简单了,我觉得更像是让设计师来学写程序的网站)。
设计收集
接下来推荐一些优秀设计的聚集地。
- Awwwards ,这个网站给一些设计得不错网站的评分,在这里你可以看到很多设计不错的网站。
- One Page Love ,就是一个单页的网页设计的收集。
- Inspired UI ,移动 App 的设计模式。
- Behance,这个地言有很不错的很有创意的作品。
- Dribbble ,这应该是设计师都知道也都爱去的网站。除了你可以看到一些很不错的作品外,你还可以在这里看到很多不错的设计师。
- UI Movement ,也是个设计的收集网站,上面有很多很不错的 UI 设计,大量的动画。虽说会像抖音一样,让你不知不觉就看了好几小时,但是它比抖音让你的收获大多了。
小结
总结一下今天的内容。我并不认为 UI/UX 设计这些内容只是设计师要学习的,如果你要成为一个前端程序员,那么学习这些设计上的东西可以让你有更好的成长空间。首先,我推荐了一些图书和文章,让你更好地了解经典的设计原则和指导思想。
然后介绍了原子设计,以及深入学习和理解这一设计方法论的图书、文章和其他相关资源。最后分享了当下主流和知名公司中在用的设计语言和设计系统,并给出了大量的学习资源,推荐了一些优秀设计的聚集地。相信通过学习这些内容,你在 UI/UX 设计方面不仅能收获方法,还能获得非常多的灵感。
技术资源集散地
首先,我先推荐一些不错的个人技术博客。
- Coding Horror ,这是杰夫·阿特伍德(Jeff Atwood)于 2004 年创办的博客,记录其在软件开发经历中的所思所想、点点滴滴。时至今日,该博客每天都有近 10 万人次的访问量,读者纷纷参与评论,各种观点与智慧在这里不断地激情碰撞。其博文选集在中国被翻译成《高效能程序员的修练》,在豆瓣上有 8.3 的高分。2008 年,他和 Joel Spolsky 联合创办了 StackOverflow 问答网站,为程序员在开发软件时节省了非常多的时间,并开启了“StackOverflow Copy + Paste 式编程”。
- Joel on Software ,Joel Spolsky 的这个博客在全世界都有很多的读者和粉丝,其博文选集在中国被翻译成《软件随想录》在豆瓣上有 8.7 的高分。这是一本关于软件技术、人才、创业和企业管理的随想文集,作者以诙谐幽默的笔触将自己在软件行业的亲身感悟娓娓道来,观点新颖独特,简洁实用。
- Clean Coder Blog ,这是编程大师“Bob 大叔”的博客,其真名叫 Robert C. Martin,世界级软件开发大师,设计模式和敏捷开发先驱,敏捷联盟首任主席,C++ Report 前主编,被后辈程序员尊称为“Bob 大叔”。其博文选集在中国被翻译成《程序员的职业素养》,在豆瓣上有 8.8 的高分。
- Martin Fowler ,这是另外一个程序员大师,Martin 主要专注于面向对象分析与设计、统一建模语言、领域建模,以及敏捷软件开发方法,包括极限编程。他的《重构》、《分析模式》、《企业应用架构模式》、《领域特定语言》和《NoSQL 精粹》都是非常不错的书。在他的博客上有很多很多的编程和架构模式方法可以学习。
- Paul Graham Essays ,美国著名程序员、风险投资家、博客和技术作家。《黑客与画家》是他的著作之一。2005 年他与人共同创建了科技创业孵化器 Y Combinator,孵化了 Airbnb、Dropbox、Stripe 等知名互联网公司。他有几篇创业方面的文章都很经典,如果你想创业,可以读一读这几篇:《How to Get Startup Ideas》、《Do Things that Don’t Scale》、《Startup = Growth》。Paul Graham 的文章以清新自然,思想深刻见长。不仅可以跟 Paul Graham 学创业,学思考,学技术,更可以学习写作。
- Steve Yegge ,Steve Yegge 这个人算是一个知名的程序员了,在 Amazon 呆过,现在在 Google,他的文章都是长篇大论,最知名的文章就是对 Amazon 和 Google 平台的吐槽,这篇文章引发了大家的讨论和议论。
- Bruce Eckel’s Programming Blog ,《Thinking in Java》作者的博客,他之前的博客在 artima - Computing Thoughts 。
- Herb Sutter ,C++ 大拿,C++ 标准委员会专家,微软软件架构师。《Exceptional C++ 》、《More Exceptional C++》、《Exceptional C++ Style》作者。
- Eli Bendersky’s website ,这位老哥从 2003 年就一直写博客到今天,其中的文章都非常不错,原理型的,主要是 C、C++ 和 Python 相关的。里面有很多干货。
- Peter Krumins’ blog ,这位老哥从 2007 年开始写博客,他博客里好玩的东西太多了。
- Brendan D. Gregg ,Brendan 是 Netflix 的工程师,他的博客里有大量的非常不错的文章,基本上都是和 Linux 性能分析相关的,这是一个如果你要玩底层性能分析一定不能错过的博客。
- Evan Klitzke ,主要讨论 Linux 和 C++ 相关的内容。
- Julia Evans ,主要讨论 Linux debug 工具和网络相关的内容。
- null program ,和 C/C++ 相关的一个博客。其中关于 Linux 系统调用、GPU、无锁编程、JIT 编译的一些文章非常不错。
- Fluent {C++} ,博主是 Murex 的首席工程师,主要玩 C++,在这个博客里有很多很不错的 C++ 相关的文章。
- Preshing on Programming ,这也是一个和 C/C++ 相关的博客,其中有很多的干货。
- Programming is Terrible ,这个博客有很多强观点的文章,主要是软件开发中的一些教训。
- Accidentally Quadratic ,姑且翻译成事故二次方,这里有好些非常有趣的文章。
- Hacker Noon ,这是一个一堆人在写的博客,里面有很多质量很高的文章。
其实还有很多不错的博客,不过,现在国外不错的博客都在一个叫 Medium 的网站,我也发现我 Google 很多东西时都会到这个网站上。这个网站上的内容不只有技术的,还有很多很多其他方面的内容,比如文化、艺术、科学等等。这个网站就是一个博客发布系统,其是由 Twitter 联合创始人埃文·克拉克·威廉姆斯(Evan Clark Williams)和克里斯多福·艾萨克·比兹·斯通(Christopher Isaac Biz Stone)创办的,这两个人觉得 Twitter 上全是垃圾没有营养的信息。所以,创办了 Medium,这个平台上有专业和非专业的贡献者,亦有受雇的编者。
我已经感觉到,未来高质量的文章都会在 Medium 这个平台上出现,因为有一些公司的技术博客也在这个平台上发布了,比如 Netflix 的。所以,你有必要上到这个平台上 follow 一些作者、专栏和主题。
YouTube 技术频道
下面是我订阅的一些我认为还不错的和编程相关的频道,推荐给你。
- Devoxx ,Devoxx 的频道,其中有各种很不错的技术分享。
- Coding Tech ,也是个非常不错的编程频道,涵盖各种技术。
- [Amazon Web Services](https://www.youtube/channel/UC
版权声明:本文标题:左耳听风——笔记二:程序员练级攻略 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.freenas.com.cn/jishu/1729032521h1309332.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论