boys & girls,我们的中场休息结束了哈,赶紧搬板凳继续听老王扯技术的淡~
(悄悄的广播一下:如果没有看过上一篇的同学,请关注老王的微信simplemain,或者拉到本文末尾扫描/识别二维码)
上一篇,我们谈到了互联网服务端技术的整体蓝图。同时顺着这个蓝图中,介绍了语言、算法和数据结构、框架具体有哪些要求以及怎么样去学习他们。接下来,老王准备介绍另外几个比较基础,又在工程中大量使用的技术。具体是什么呢?我们接着往下看。首先我们还是把那幅蓝图摆出来(开始装B啦~)。
聪明的同学一定已经发现,这一篇要介绍的:操作系统、数据库和网络,在我们的蓝图中都占了两层。这两层代表什么呢?老王是这么来看的:一层是体系本身,一层是基于体系的应用。比如,操作系统就涵盖了操作系统本身以及基于操作系统的使用。那这两层分别有什么要求,以及如何来学习呢?
·操作系统(operating system)
大家听到操作系统,第一反应是什么?
十年前,我的第一反应是:win98(是不是很古老的记忆了,哈哈哈~);
如今,我的第一反应是:安卓还是iOS?
你呢?
我们是码工,天生的使命就是繁育后代(生物使命)和创造程序(社会使命)。我们的后代生长在这个地球,而我们的程序则是运行在操作系统之上。因此,要想我们的程序跑的快、运行的好,就需要像了解我们生成的环境一样,去了解操作系统。
我们对于操作系统的学习大致上可以分为两个方面来学习:一是某个具体的操作系统(比如: windows、 linux等);另一个则是操作系统原理。根据不同的能力级别,对应的要求也是不一样的。
[初级能力]
要让程序跑起来,我们就需要熟练使用一个操作系统。大家想想,我们对于windows的操作是否已经很熟练?常用的操作有哪些?为了运行一个程序我们要做哪些操作?
我相信99.99%的程序员们,对上述这个问题的回答:你的这个问题简直是在侮辱我的智商(老王已经准备好被打了~)
好吧,老王来回答上面的这些问题。我们要熟练使用windows,实际上就是会常见的操作、明白他的文件管理方式、知道cpu和内存的运转状态等等。常见的操作有:
1、目录和文件的创建、打开、处理和关闭(还记得桌面左上角那个“我的电脑”么?);
2、下载、安装、运行一个程序(“下一步”、“下一步”……“完成”、“双击打开”);
3、观察cpu、内存、磁盘、网络的情况(任务栏右键,点击“任务管理器”)。
如果你使用的是windows作为服务器,基本上对于操作系统的要求就是这样的。但是,很不幸的是,如今互联网绝大部分服务器使用的是linux作为服务器,那码工们就需要学会上述操作对应的linux命令(老王最近正在教家里领导使用linux,准备写一篇linux入门手册……),具体的就是:
1、mkdir、cd、vim……
2、make&& make install、yum install、apt-get install、./run……
3、ps、top、free、df、netstat、vmstat、iostat……
如果没有linux基础,是不是觉得好难?!
其实,你把linux看成文字版的windows,这个事情就简单了。先把windows操作翻译成英语,再缩写,就是高大上的黑屏+命令(特别是在妹子跟前玩儿黑屏,简直是极限装B)。比如:
a、新建目录 ->make
directory -> mkdir;
b、双击打开某个目录 ->change directory-> cd;
c、磁盘剩余 ->disk free ->df。
所以,对于这个能力级别的要求,就是像使用windows一样,去使用linux就可以了。学习的时候也不用那么枯燥的去记住命令,而是用windows操作的方式去类比,这能涵盖80%左右的操作。有一些特殊的,需要特别去记一下。
另外,linux命令有一个很麻烦的事情,就是参数有点儿多,咋办呢?linux的命令一般提供两种帮助:
1、命令 --help(比如:cd --help),会提供给你简要的参数提示
2、man 命令(比如:man cd),这里的man不是男人的意思,而是手册的缩写。帮助你全面的了解这个命令。
只要有这两个神器,大部分问题还是能搞定。如果还搞不定,就用另外一个神器:
3、浏览器输入:www.baidu.com回车,搜索框输入:linux 命令……
除了基本命令以外,还有几个东东要学习一下:管道(|)、输入重定向(<)、输出重定向(>)。大体就这些,怎么样,是不是轻松了些?
[中级能力]
我面试别的程序员的时候,经常喜欢问一个问题:当你远程登录你的linux服务器,发现执行命令很卡顿,请问你如何来分析出了什么问题?以及怎么样来解决?(这个问题其实也扩展到windows等其他的服务器操作系统)
问这个问题,其实就是想考察面试者对操作系统是否熟悉,有些原理性的东西是怎么样来看的,以及如何去解决他。
当你担当一部分或者全部服务器运维任务的时候,或者需要在操作系统上做相关开发的时候。这个时候,就不光要会基本的命令,基本的操作,还要会以下的一些能力:
1、写脚本:我们除了要了解常用的操作命令以外,还需要用熟一些高级的命令,比如:awk、sed、chown、chmod、find、sort等。同时,还要了解一些shell的关键字,比如:if、for、while、read等,把这些命令组合起来,写一些稍微有逻辑的脚本,方便对机器和程序进行管理;
2、懂原理:我们对于操作系统除了知其然,还要知其所以然。懂得操作系统一些原理性的东西。比如,进程是如何创建的、什么是僵死进程、文件是如何创建的、什么是inode、数据是怎么存储到磁盘的、什么是寻道、内存是怎么分配的,等等。这样可以方便我们维护服务器的正常运转,分析和解决操作系统出现的一些问题。
3、会编程:了解操作系统提供的API,能将原理性的东东对应到程序上,编写出我们想要的功能代码,并进行编译、链接等操作。比如,我们监控一个机器的运转,就需要编写对应的监控程序,对cpu、内存、磁盘等进行实时分析,如果出现问题,就提醒管理人员。(现在很多高级程序语言已经提供了虚拟机,从而使得程序具有了很好的跨平台的能力。这一点其实帮助不少程序员脱离了苦海。不过如果要编写高性能的服务器程序,有可能还是需要对c/c++,甚至汇编语言有所了解,同时了解操作系统提供的api)。
会以上的这些,基本上就基本上是半个专家了,足以应对大多数情况。
那怎么学呢?
对于命令和脚本,老王以前喜欢ls /sbin和ls /bin,看看都有哪些命令,然后一个个的去网上查,看看他们都是干嘛的。对于比较知名的几个命令,就用man,看看他们详细的用法,并写脚本实际去用一用。
对于原理性的东东,老王建议大家看看操作系统原理相关的书籍,上面都有比较详细的讲解:cpu管理、内存管理、文件管理等等。
对于编程,如果是linux的服务器,推荐大家一本宝典:APUE,《Advanced Programming in the UNIXEnvironment》,中文名:《UNIX环境高级编程》。老王大概读过2-3遍,每一次读都受益匪浅。不过光读是不行的,最好是按照例子写写,才能理解。只看书的意义不大;如果是windows的服务器,老王在10多年前写过一些windows的程序,当时还在念本科1-2年级,那个时候还是用的vc6(那是多么古老的记忆),看过一大半《windows程序设计》,觉得还不错。不知道现在怎么样了,所以老王就不做推荐了。
[高级能力]
如果你是运维方面的专家,或者是操作系统的研发者。就需要对操作系统本身有深入的了解了。这包含两个层面的东东:
1、对操作系统原理有比较深入的了解:处理器管理、存储器管理、文件管理、设备管理等等,具象化以后,涵盖进程、分页分段、文件存储等等内容,让你从抽象的角度去看待操作系统。
2、精深某一个操作系统:能把操作系统原理的东东落地到某一种操作系统中。比如:实现linux的文件管理。或是根据业务需求,定制和重新编译一个操作系统。
因为老王只是学过操作系统原理,对常规的原理有一定的了解,做底层开发的时候涉及过某些东东,但大部分没有去做过深入实践,所以这一部分确实也给不出太好的建议,只能是建议大家读读相关的书籍。如果有这方面的专家,也欢迎给出意见,大家一起学习和进步~
操作系统是我们码工必须依赖的生存环境,每天都会面对。所以如果要从事互联网服务端的研发,最好能非常熟练使用至少windows和linux两种系统。一个给你很好的桌面办公环境,一个给你很好的程序运行环境。
·数据库(database)
在谈论数据库技能之前,想问大家一个问题:为什么要有数据库?或者也可以换一个问法:没有数据库有什么影响?
在回答这个问题前,老王讲一个故事。当我刚刚进入百度的时候(大约是07-08年),百度(至少我所在的大部门)还基本上没有使用数据库,所有的系统用c/c++来开发,除了要考虑逻辑层面的东东,还要考虑如何将每个系统产生的逻辑数据写成结构体存储到磁盘文件(序列化写入),以及如何从磁盘文件中读取结构体数据(序列化读入)。为了开发一个功能模块,需要以月为单位,这在移动互联的今天,简直就是无法忍受的慢。而我们现在怎么做呢?用java/ruby等高级语言写逻辑,将数据存入到数据库中,开发一个完整功能的系统也就几周(如果功能不大,可能就几天)。
不错,数据库就是帮我们解决数据存储的问题,他提供了通用的数据存储和读取的方案。能帮我们解决大部分数据存储问题(有些系统数据库也可能搞不定,或者说搞定成本比较高,以后讲到的时候,再跟大家分享),极大的提升我们开发的速度。
我们常用的关系型数据库,比如mysql、 sqlserver、 db2、 oracle、 postgresql等等,都包含了:sql操作、事务管理、文件存储、索引管理等功能(不同数据库在实现上会有功能差异,但大面儿上是一致的)。他们提供的这些功能足够满足我们日常开发的需求(完全是码工们的救星,如果没有数据库,估计码工们都被产品经理打死完了,哈哈哈~)。后来,几年前又开始流行非关系型数据库,比如mongodb、redis等等,这些NoSql的数据库以轻量化设计,快速的查询效率,在如今的互联网研发中也起到了很重要的作用(比如,对于需求快速更迭的实验性产品,mongodb就用文档存储方式来应对,避免了传统关系数据库的行列限制;redis提供更多的数据结构支持等等)。
一般我们在中大型的数据访问和存储方案上,采用NoSql和RDBS相结合的方式。常常会把访问速度快,轻量化的非关系型数据库当做临时性数据访问介质,比如,memcache、redis常常被当做cache,用于应对大量重复的请求。而关系型数据库则用来当做一致性要求较高的持久化存储。
所以,针对不同的应用场景,我们对于数据库的要求也是不一样的。
[初级能力]
这个层级的能力要求,就是满足日常业务开发需求,直白一点就是:能用!所以:
1、要么用熟一种非关系型数据库:会用程序访问常用的set、get、delete、modify等接口;
2、要么用熟一种关系型数据库:会常用的sql来做查插删改;会用程序访问数据库。
当然,以上的前提是:学会安装和配置某种数据库。这些要求都是码工解决基本温饱最基础的
[中级能力]
如果你是一个公司的服务端技术负责人,就需要对数据库有比较深入的了解,以应对数据量、数据一致性、查询和提交的并发请求量等的问题。除了会基本的操作以外,你还需要对数据库原理和某一种数据库有一个比较深入的了解。可能非关系型和关系型都需要有一定的涉及。
1、非关系型数据库:他是如何实现的?提供哪些特殊的功能以帮助我们实现不同的需求?有哪些瓶颈和问题?数据量大了以后,如何来保证数据的一致性和可用性?等等;
2、关系型数据库:需要了解sql操作、事务管理、文件存储、索引管理等几大部分的基本原理;基本能回答以下这些问题:每一个sql请求是如何做查询优化的?索引是如何设计的?以及索引的种类和工作原理?事务是如何管理的(比如mvcc)?数据是如何存储到磁盘的?等等。
那么如何来学习呢?对于实现不复杂的数据库,最好的方式就是阅读源代码;对于原理性的东东,需要看算法数据结构、操作系统原理的知识来补充(比如:b树和b+树、hash算法;read、write这些io调用等)。还有一点,计算机科学是一门实践性的科学,光看书是不行的,还需要写代码练习。所以,如果有机会,可以自己用文件的方式来实现存储。等写完以后,很多问题就会有更深入的认识(比如:fwrite是否有缓存?write是否有缓存?什么是字节对齐?什么是mmap、DirectIO等等)。
另外,可能还要详细研究不同数据库的配置说明。配置参数不一样,数据库性能表现会有很大差异。比如:内存调多大?读取超时配置多少?数据刷回磁盘的频率是多少?等等
[高级能力]
这个就是专家级的要求了。对数据库原理非常精通,精深一个数据库系统。除了会满足开发需求外,还可以对数据库进行代码修改打patch、对数据库进行功能完善等。
老王自认达不到这个能力要求,所以这个方面建议不多。不过当年在百度的同居蜜友,现在已经是mysql的大犇,去年请他来百词斩做过技术分享。
互联网服务端的最大技术难点,就是数据的存储(老王当年选择百度的很重要的一个原因,就是自己在拉活儿的时候,解决不了访问量大了以后,数据读取和写入慢的问题)。而数据存储又分成特殊数据存储和通用数据存储。其中通用数据存储,目前最好的解决方案就是数据库。所以,学好数据库技术是学好互联网服务端技术的重中之重。
·网络(network)
所谓互联网互联网,最重要的当然就是这个网络了。大家对tcp/ip、http这些名词,估计都听的耳朵都发茧了。
对于互联网server的开发来说,我们一般会比较看重三个方面:网络协议、网络服务模型和网络安全。网络协议是我们所有工作的基础,是计算机网络的基础理论;网络服务模型可以让我们能有更高效的服务能力;而网络安全,则是保障我们服务安全的基础。
针对不同的特点,不同能力级别的要求自然也有不一样。
[初级能力]
1、协议知识:知道网络分层的原理,懂得常用的网络协议,以及对他们的熟练应用。需要了解常见的协议:
a、HTTP协议。http协议是搞互联网的基础,所以是一个必须要了解的。什么是header、什么是cookie、常见的返回码(2xx、3xx、4xx、5xx)、什么是post、get等等。会用工具发送http请求,或者用程序发送http调用等。
b、TCP/IP协议。这个也自然不用说,作为一个码工,肯定应该知道什么是ip地址?什么是端口?怎么样建立连接?等等(如果这个不懂,怎么帮女生修电脑呢,对不对?)
2、服务模型:如果是常见的web服务,就需要了解常见的web服务器,会搭建、会配置、会使用。保证我们的用户能成功的接入服务。比如:现在流行的nginx(或者以前流行过的apache、lighttp等)。如果是socket服务,就可能需要关注一些其他的服务器或者组件(比如java的mina、netty等等),会配置,会使用。
3、网络安全:了解常见的安全威胁,比如:DoS、DDoS、xss、sql注入等。写代码的时候,能去主动规避常见的编码漏洞(比如html转义、sql转义等)。
[中级能力]
对于这个能力级别的要求,主要是对网络有一个全面的了解,会编写高效率网络程序,能防范一些常见的网络攻击。因此就需要充分了解以下知识:
1、协议知识:对于互联网服务端的开发,重点要关注的就是TCP/IP和HTTP协议,具体的知识涵盖如下:
a、网络协议栈是如何分层的,以及每一层的职责和工作原理;每一层常见协议的包格式以及应用场景;
b、TCP、IP协议:IP报文的格式、协议的路由规则、 IP地址的相关内容(网关地址、广播地址、子网掩码、A-D类地址等);TCP的三次握手、优雅关闭、滑动窗口、超时重传等。
c、Http、Https协议:这两个协议的工作原理(https可以参见老王之前写的一篇文章《Https到底是个啥玩意儿?》),以及一些深入的用法,比如keep alive、range等;
d、其他的一些技术,比如:网络地址转换(NAT)等等。
2、服务模型:
a、会写基本的client-server代码;
b、了解常见的网络模型,最好能写出相关的模型代码。比如:select、epoll;
c、常见setsockopt选项的作用: SO_RCVTIMEO、SO_SNDTIMEO、SO_REUSERADDR、SO_LINGER等。
d、了解常见webserver架构和工作原理,比如nginx、apache;
3、网络安全:
a、了解常见攻击的原理,以及如何预防和处理。比如:syn半连接攻击的产生原因和如今的解决方案。
b、会使用常见的网络工具和方法去规避网络风险。比如:iptables的配置和使用、数据库授权管理和安全配置等等。
为了比较全面的了解网络这一部分,推荐大家阅读经典的《TCP/IP详解》三部曲;以及阅读常见网络服务器的源代码;同时可以关注wooyun.org上面的相关知识。
[高级能力]
到这个阶段,基本上就是某个方面的专家。要么对网络协议十分精通、要么对网络服务模型十分了解,或者是网络安全的专家。具体的:
1、充分了解网络协议,并能编写协议代码;
2、或者编写高效的大规模网络服务器;
3、或者对网络安全攻防了如指掌。
老王当年读书那会儿,没事儿干就写了写ICMP协议,本来想用UDP模拟实现TCP,但是没有落地。后来工作以后,抽时间看过部分apache代码、java的mina、thrift的代码,改过tomcat的一些代码,自己用java实现了reactor模型代码,但是没有机会去应用到大规模网络访问中。不过,对于网络攻防做的比较少,没有什么经验。
老王得出的一个经验就是,有机会就多看书,多看源代码,多思考,多折腾~ 生命不息,折腾不止。
=== 休息的分割线 ===
好了,老王今天的故事讲完了,觉得怎么样?接下来的下篇相比上篇和中篇,更偏重实际工程中遇到的问题,因此实际操作性更强,内容更加贴地,请关注老王下一场的扯淡吧~
话外音:老王现在基本上每周出一篇文章,有盆友问老王为什么不能天天出呢?原因是这样的。可能很多盆友都发现了,老王的文章一般很长(似乎大概可能也许是4000-8000字,所以感谢大家有耐心读完这么冗长的文字),纯码字大概要弄几个小时。同时工作日还要加班创业,所以一般只有周末有时间来码字。而且老王本着对大家负责,对心负责的态度,会反复的review和修改(这篇文章已经修改过至少4遍了)。所以老王尽力保证一周出一篇老王自己觉得还不错的文章,希望大家理解哈~
还没关注老王?赶紧加微信吧:simplemain
或者扫码/长按识别二维码:
来,看美图了。这是2012年老王去满洲里-呼伦贝尔-根河-额尔古纳拍的美景。老王走过大约20个省,这是可以排到Top3的地方。