江边闲话集

12/23/2018

深入浅出:HTTP/2

Filed under: I.T — 张太国 @ 18:07

上篇文章深入浅出:5G和HTTP里给自己挖了一根深坑,说是要写一篇关于HTTP/2的文章,今天来还账了。

本文分为以下几个部分:

  1. HTTP/2的背景
  2. HTTP/2的特点
  3. HTTP/2的协议分析
  4. HTTP/2的支持

HTTP/2简介

HTTP/2主要是为了解决现HTTP 1.1性能不好的问题才出现的。当初Google为了提高HTTP性能,做出了SPDY,它就是HTTP/2的前身,后来也发展成为HTTP/2的标准。

HTTP/2兼容HTTP 1.1,例如HTTP Method,Status code,URI以及大部分Header Fields。

HTTP/2通过以下方法减少latency,用来改进页面加载的速度,

  1. HTTP Header的压缩,采用的是HPack算法。
  2. HTTP/2的Server Push,非常重要的一个特性。
  3. 请求的pipeline。
  4. 修复在HTTP 1.x的队头阻塞问题。
  5. 在单个TCP连接里多工复用请求。

HTTP/2支持HTTP 1.1里的大部分use case,例如桌面浏览器、移动浏览器、Web API、Web Server、代理服务器、反向代理服务器、防火墙和CDN等。

HTTP/2 头部压缩(HPack)

HPack是HTTP/2 里HTTP头压缩的算法,具体可以参看https://tools.ietf.org/html/rfc7541。下面简单介绍一下HPack是如何工作的。

见下图,该图来自Google 的性能专家 Ilya Grigorik 的文章HTTP/2 is here, let’s optimize!,它非常直观地描述了 HTTP/2 中头部压缩的原理:

简单说,HTTP头压缩需要在HTTP/2 Client和服务端之间:

  • 维护一份相同的静态表(Static Table),包含常见的头部名称,以及特别常见的头部名称与值的组合;
  • 维护一份相同的动态表(Dynamic Table),可以动态地添加内容;
  • 基于静态哈夫曼码表的哈夫曼编码(Huffman Coding);

在HTTP头里,有些key:value是固定,例如:

 :method: GET
 :scheme: http

在编码时,它们直接用一个index编号代替,例如:method:GET是2,这些在一个静态表定义。静态表的定义如下,总共61个Header Name,点击URLhttps://tools.ietf.org/html/rfc7541#appendix-A查看所有静态表的定义。

 

Index Header Name Header Value
1 :authority
2 :method GET
3 :method POST
4 :path /
5 :path /index.html
6 :scheme http
7 :scheme https
8 :status 200
32 cookie
60 via
61 www-authenticate

 

使用静态表、动态表、以及Huffman编码可以极大地提升压缩效果。对于静态表里的字段,原来需要N个字符表示的,现在只需要一个索引即可,对于静态、动态表中不存在的内容,还可以使用哈夫曼编码来减小体积。HTTP/2 标准里也给出了一份详细的静态哈夫曼码表(https://tools.ietf.org/html/rfc7541#appendix-B),它们需要内置在客户端和服务端之中。

关于HPack的算法和实现,后面专门抽一篇文章来写。

HTTP/2 ALPN

HTTP/2协议里有个negotiation的机制,让客户端和服务器选择使用HTTP 1.1还是2.0,这个是由ALPN来实现,关于ALPN,可以参看

ALPN(Transport Layer Security (TLS) Application-Layer Protocol Negotiation Extension,https://tools.ietf.org/html/rfc7301

下面是抓包截图,在TLS里的Client Hello的包里,我们可以看到ALPN里由H2和HTTP/1.1,这就是说客户端支持HTTP2以及HTTP 1.1.

当Server收到后,会识别Client发过来的协议列表,如果不认识就忽略掉。如果认识多个,则选择一个最合适的协议发布给Client。也是在Server Hello里的ALPN返回,见下图。

HTTP/2 Server Push机制

Server Push是HTTP 2最重要的一个特性。

在HTTP 1.1里,在同一个 TCP 连接里面,上一个回应(response)发送完了,服务器才能发送下一个,但在HTTP/2里,可以将多个回应一起发送。

下图是PUSH模式,当请求一个HTML时,如果HTML里有CSS文件,server会一并推给client,而不像在HTTP 1.1下,还需要再发一个CSS的请求。

 

根据上图,从理论上PUSH模式下性能会好很多。

举个例子解释一下。下面是一个简单的HTML页面,假说是index.html 。

复制代码
<html>
<head>
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <p>This is a sample to illustrate how HTTP/2 works</p>
  <img src="example.png">
</body>
</html>
复制代码

这里有三个文件需要处理:该HTML页面、CSS文件style.css以及图片example.png。在HTTP 1.1里为了处理这三个文件,Client需要发三个请求给Server。

首先,发送一个请求index.html,

GET /index.html HTTP/1.1

Client解析该HTML文件,继而知道有2个style.css和example.png资源文件下载。

Client继续发送2个请求下载他们。

GET /style.css  HTTP/1.1

以及

GET /example.png  HTTP/1.1

一般为了解决这两个问题,像CSS文件,可以把CSS code直接放在HTML里,也可以把example.png转化为base64 code嵌入在HTML里,以上只是把外部资源文件合并到HTML里。

除了上述方法,还有一个优化的方法,就是Preload(预加载),可以参看这里,https://w3c.github.io/preload/

所以我们可以把HTML代码改成如下:

<link rel="preload" href="/styles.css" as="style">
<link rel="preload" href="/example.png" as="image">

那Preload是什么意思呢?就是说下载前一个页面时,可以把相关的资源文件预先加载好,这样感觉起来会快一些。但是有一个关键问题需要注意,即便是预加载的情况下,也不能减少HTTP请求次数

针对上面的问题,我们引出服务器推送(server push)。根据上面的图,我们可以看出,Server还没有收到Client的请求,就把各种资源推送给Client。

拿上面例子继续举例,当Client只请求index.html,但是Server把index.htmlstyle.cssexample.png全部发送给浏览器。这样只需要一轮 HTTP 通信,Client就得到了全部资源。

 

HTTP/2的支持

现在主流的软件都支持HTTP/2.

浏览器

基本上大部分浏览器在2015年底都支持HTTP/2了,包括Chrome、Opera、Firefox、IE 11、Safari,Edge。

在Chrome上,可以下载插件HTTP Indicator,判断访问的网站是否支持HTTP/2.

也可以打开Chrome的开发者工具,打开Network tab,可以看到Protocol为h2的就是HTTP/2请求。如果Initiator为push的,说明开启了Server Push模式。

常用Server软件

  1. Apache HTTPd,从版本2.4.12开始支持,通过模块mod_h2来支撑。
  2. Apache Tomcat,从版本8.5开始支持。
  3. Jetty从9.3开始支持。
  4. Netty从4.1开始。
  5. IIS在Win10和WIndows Server 2016支持。
  6. Ngnix从1.9.5开始支持HTTP2,但Server Push功能则在1.13.9才开始。

硬件

  1. Ctrix NetScaler从11.x开始支持
  2. F5 BIG-IP从11.6开始。

CDN/Cloud

  1. Akamai
  2. AWS
  3. Azure
  4. Aliyun
  5. Tecent Cloud

缓存问题

如果开启了Server Push模式,我们很容易意识到一个问题,那就是缓存问题。Server见到HTML页面就把外部资源push给Client,如果没有缓存,其实很浪费。为了解决这个问题,可以在第一次请求时push,后面的请求都不push了。

服务器推送有一个很麻烦的问题。所要推送的资源文件,如果浏览器已经有缓存,推送就是浪费带宽。即使推送的文件版本更新,浏览器也会优先使用本地缓存。下面是 Nginx 官方给出的示例,根据 Cookie 判断是否为第一次访问(https://www.nginx.com/blog/nginx-1-13-9-http2-server-push/)。

复制代码
server {
    listen 443 ssl http2 default_server;

    ssl_certificate ssl/certificate.pem;
    ssl_certificate_key ssl/key.pem;

    root /var/www/html;
    http2_push_preload on;

    location = /demo.html {
        add_header Set-Cookie "session=1";
        add_header Link $resources;
    }
}

map $http_cookie $resources {
    "~*session=1" "";
    default "</style.css>; as=style; rel=preload, </image1.jpg>; as=image; rel=preload, </image2.jpg>; as=image; rel=preload";
复制代码

HTTP/2的性能

有人专门做过测试,https://www.smashingmagazine.com/2017/04/guide-http2-server-push/#measuring-server-push-performance,借用该文的一张图片,

可以看出,启用HTTP/2后性能并未大幅度提升,所以在使用HTTP/2还是谨慎一些,如果使用不当,反而会使性能下降。

另外,Ngnix专门撰文描述7个提高HTTP/2的技巧https://www.nginx.com/blog/7-tips-for-faster-http2-performance/ 。

参考文章:

  1. https://en.wikipedia.org/wiki/HTTP/2
  2. https://tools.ietf.org/html/rfc7301
  3. https://tools.ietf.org/html/rfc7541 (HPack)
  4. http://www.ruanyifeng.com/blog/2018/03/http2_server_push.html
  5. https://www.nginx.com/blog/nginx-1-13-9-http2-server-push/
  6. https://www.smashingmagazine.com/2017/04/guide-http2-server-push/#measuring-server-push-performance
  7. https://www.nginx.com/blog/7-tips-for-faster-http2-performance/
  8. https://w3c.github.io/preload/
  9. http://velocityconf.com/devops-web-performance-2015/public/schedule/detail/42385

12/17/2018

深入浅出:5G和HTTP

Filed under: I.T — 张太国 @ 12:48

本文将会讲到5G和HTTP。曾经在深入浅出经典面试题:从浏览器中输入URL到页面加载发生了什么 – Part 3 提到为什么有些RPC框架不选用HTTP,而5G会采用HTTP。

您可以从本文里获取到一些概念:5G用HTTP作为reference point interface的实现,HTTP/2,RESTful API/HATEOAS/OpenAPI等最佳实践和标准,这些都是一些常见但是又容易忽略的知识点。

本文参考了一些文章,见文章末尾的链接列表。

HTTP的优点和缺点

我们大家知道HTTP协议包含的信息太多,太繁重,导致消息体会很大,但是其中有一些消息根本用不上,这也是为什么HTTP/1.1消息效率不高的原因,所以一些RPC框架舍弃它,例如dubbo定义自己的协议等,如果大家定义过协议,例如类似TCP协议,就能明白协议定义的重要性。如果要效率高,消息短,那就会太底层,如TCP,如果要想易于理解,例如HTTP,那就得长一些。

5G和HTTP

5G明年试商用,在5G里采用HTTP协议,确实有意思。可以参看TS 29.501协议 5G System;Principles and Guidelines for Services Definition,Stage 3。先看看下图:

在通信领域,由原来的Diameter,AAA等转变为HTTP,的确是一个大变化,但是开发的效率将会大大提高。

那么5G将会应用到什么HTTP相关技术呢?

  1. HTTP/2/0 (协议下载https://http2.github.io/http2-spec/)
  2. JSON
  3. HATEOAS
  4. RESTful
  5. OpenAPI

HTTP/2.0

还是先看看HTTP/2吧。谈到HTTP/2,最先想到Google的SPDY,它是HTTP/2的前身。为什么Google要做SPDY呢?原因很简单,HTTP的效率不高。自从有了SPDY后,加载时间减少64%(http://dev.chromium.org/spdy/spdy-whitepaper),原话这么说的, In lab tests, we have compared the performance of these applications over HTTP and SPDY, and have observed up to 64% reductions in page load times in SPDY.

SPDY并不用于取代HTTP,它只是修改了HTTP的请求与应答在网络上传输的方式;这意味着只需增加一个SPDY传输层,现有的所有服务端应用均不用做任何修改。 当使用SPDY的方式传输,HTTP请求会被处理、标记简化和压缩。比如,每一个SPDY端点会持续跟踪每一个在之前的请求中已经发送的HTTP报文头部,从而避免重复发送还未改变的头部。而还未发送的报文的数据部分将在被压缩后被发送。

HTTP/2主要特性包括:

 

二进制协议

HTTP/1.1 版的头信息肯定是文本(ASCII编码),数据体可以是文本,也可以是二进制。HTTP/2 则是一个彻底的二进制协议,头信息和数据体都是二进制,并且统称为”帧”(frame):头信息帧和数据帧。

二进制协议的一个好处是,可以定义额外的帧。HTTP/2 定义了近十种帧,为将来的高级应用打好了基础。如果使用文本实现这种功能,解析数据将会变得非常麻烦,二进制解析则方便得多。

 

多工

HTTP/2 复用TCP连接,在一个连接里,客户端和浏览器都可以同时发送多个请求或回应,而且不用按照顺序一一对应,这样就避免了”队头堵塞”。

举例来说,在一个TCP连接里面,服务器同时收到了A请求和B请求,于是先回应A请求,结果发现处理过程非常耗时,于是就发送A请求已经处理好的部分, 接着回应B请求,完成后,再发送A请求剩下的部分。

这样双向的、实时的通信,就叫做多工(Multiplexing)。

 

数据流

因为 HTTP/2 的数据包是不按顺序发送的,同一个连接里面连续的数据包,可能属于不同的回应。因此,必须要对数据包做标记,指出它属于哪个回应。

HTTP/2 将每个请求或回应的所有数据包,称为一个数据流(stream)。每个数据流都有一个独一无二的编号。数据包发送的时候,都必须标记数据流ID,用来区分它属于哪个数据流。另外还规定,客户端发出的数据流,ID一律为奇数,服务器发出的,ID为偶数。

数据流发送到一半的时候,客户端和服务器都可以发送信号(RST_STREAM帧),取消这个数据流。1.1版取消数据流的唯一方法,就是关闭TCP连接。这就是说,HTTP/2 可以取消某一次请求,同时保证TCP连接还打开着,可以被其他请求使用。

客户端还可以指定数据流的优先级。优先级越高,服务器就会越早回应。

 

头信息压缩

HTTP 协议不带有状态,每次请求都必须附上所有信息。所以,请求的很多字段都是重复的,比如CookieUser Agent,一模一样的内容,每次请求都必须附带,这会浪费很多带宽,也影响速度。

HTTP/2 对这一点做了优化,引入了头信息压缩机制(header compression)。一方面,头信息使用gzipcompress压缩后再发送;另一方面,客户端和服务器同时维护一张头信息表,所有字段都会存入这个表,生成一个索引号,以后就不发送同样字段了,只发送索引号,这样就提高速度了。

 

服务器推送

HTTP/2 允许服务器未经请求,主动向客户端发送资源,这叫做服务器推送(server push)。

常见场景是客户端请求一个网页,这个网页里面包含很多静态资源。正常情况下,客户端必须收到网页后,解析HTML源码,发现有静态资源,再发出静态资源请求。其实,服务器可以预期到客户端请求网页后,很可能会再请求静态资源,所以就主动把这些静态资源随着网页一起发给客户端了。

我给自己挖个坑,后面专门出一篇文章写HTTP/2.

HATEOAS 约束

HATEOAS(Hypermedia as the engine of application state)是 REST 架构风格中最复杂的约束,也是构建成熟 REST 服务的核心。它的重要性在于打破了客户端和服务器之间严格的契约,使得客户端可以更加智能和自适应,而 REST 服务本身的演化和更新也变得更加容易。

在介绍 HATEOAS 之前,先介绍一下 Richardson 提出的 REST 成熟度模型。该模型把 REST 服务按照成熟度划分成 4 个层次:(这个可以参考Richardson的成熟度模型,见后文链接)

  • 第一个层次(Level 0)的 Web 服务只是使用 HTTP 作为传输方式,实际上只是远程方法调用(RPC)的一种具体形式。SOAP 和 XML-RPC 都属于此类。
  • 第二个层次(Level 1)的 Web 服务引入了资源的概念。每个资源有对应的标识符和表达。
  • 第三个层次(Level 2)的 Web 服务使用不同的 HTTP 方法来进行不同的操作,并且使用 HTTP 状态码来表示不同的结果。如 HTTP GET 方法来获取资源,HTTP DELETE 方法来删除资源。
  • 第四个层次(Level 3)的 Web 服务使用 HATEOAS。在资源的表达中包含了链接信息。客户端可以根据链接来发现可以执行的动作。

从上述 REST 成熟度模型中可以看到,使用 HATEOAS 的 REST 服务是成熟度最高的,也是推荐的做法。对于不使用 HATEOAS 的 REST 服务,客户端和服务器的实现之间是紧密耦合的。客户端需要根据服务器提供的相关文档来了解所暴露的资源和对应的操作。当服务器发生了变化时,如修改了资源的 URI,客户端也需要进行相应的修改。而使用 HATEOAS 的 REST 服务中,客户端可以通过服务器提供的资源的表达来智能地发现可以执行的操作。当服务器发生了变化时,客户端并不需要做出修改,因为资源的 URI 和其他信息都是动态发现的。

所以我们可以看到HATEOAS可以降低客户端和服务器之间的耦合。

我们看看在Spring官网上的例子。

下面是一个类 Customer.

class Customer {
    String name;
}

一个传统的例子是:

{ 
    "name" : "Alice"
}

如果变成HATEOAS风格的,可以是下面这样:

{
    "name": "Alice",
    "links": [ {
        "rel": "self",
        "href": "http://localhost:8080/customer/1"
    } ]
}

我们可以看到,不仅有了name,还多了一个links. links下的rel的值是self,意思就是说指向当前资源的链接。

关于ref的值,可以参考下表:

rel 属性值 描述
self 指向当前资源本身的链接的 rel 属性。每个资源的表达中都应该包含此关系的链接。
edit 指向一个可以编辑当前资源的链接。
item 如果当前资源表示的是一个集合,则用来指向该集合中的单个资源。
collection 如果当前资源包含在某个集合中,则用来指向包含该资源的集合。
related 指向一个与当前资源相关的资源。
search 指向一个可以搜索当前资源及其相关资源的链接。
first、last、previous、next 这几个 rel 属性值都有集合中的遍历相关,分别用来指向集合中的第一个、最后一个、上一个和下一个资源。

根据以上,我们可以清楚的看出根据rel不同的类型有不同的用处,这样客户端可以智能的进行不同的操作,达到解耦的目的。

OpenAPI

其实RESTful API都是和OpenAPI相关的,为什么会把OpenAPI单独拿出来说?原理很简单,那是因为现在很多API的定义,包括一些大厂的,都做的不是很好。RESTful API设计的最佳实践文档就在这里,但是大部分人还是没有去遵守。关于RESTful API文档,建议去参考微软的文章(  https://docs.microsoft.com/en-us/azure/architecture/best-practices/api-design)。那么OpenAPI是干什么的?说白了就是为了RESTful API,定义了一个标准,让我们和机器不用再去查看源代码、文档,甚至不用像我前面文件里抓包那样,去了解API的定义。

最典型的例子还是Swagger。Swagger的Editor等产品是支持OpenAPI的,总的来说,Open API的那些标准不是太难,因为现成的例子供参考。关键是如果利用这些将自己的产品变得更加标准,这是很重要的策略和思路。我原来在这个上面花了很多时间引入到项目里,我觉得是值的,一个是让产品规范了,有质的保证,二是让自己和同事的思维提高了。

 

总的来说,这篇文章简单介绍了5G和HTTP的关系,以及HTTP里用到RESTful API,HTTP/2等技术,这和以前通信领域是不一样的。

参考文章:

12/14/2018

深入浅出:远离法律风险,必须了解开源项目许可证

Filed under: I.T — 张太国 @ 09:56

本文讲开源项目的许可证(License)。

现在FOSS(Free Open Souce Software)的项目逐步增多,而且项目引进FOSS项目也越来越多,以提高我们开发的效率,避免重复造轮子。那么在我们开心享用这些FOSS项目时,感叹世界真美好,但我们有没有认真去研读过它们的许可证呢?

引进FOSS项目需要注意什么?

那么在引进FOSS的项目时,我们需要注意什么呢?对此不同的人有不同的答案。对此,我的看法是:

  1. 需要了解FOSS项目许可。
  2. FOSS项目是否符合自己的需求。
  3. FOSS项目是否有人维护。
  4. FOSS项目的成熟度,社区的热度。
  5. FOSS项目的质量。
  6. FOSS项目的继承难度系数,以及是否能提高开发效率。

本文只关注这里的第一步:FOSS项目许可证。为什么把许可证放在第一条呢?因为我觉得如果许可证都不合适,下面其他要素不用考虑了。

License的重要性

无论作为个体还是公司,我们引进FOSS项目时,首先必须要考虑License的问题,如果不注意License的问题,自己的项目有可能会侵权,可能会把自己或者公司陷入法律风险的境地,如果真的这种事情发生,解决起来很麻烦。

一般怎么处理呢?首先如果是个体,我们必须把常见的License类型了解清楚,如果是公司,需要有法务部门来审核,但是一般公司可能没有法务部门,那需要开发人员自己去把握。我清楚的记得,在前东家里,我配合公司的法务部门核查每个项目使用FOSS项目的情况,就是为了让项目和公司不处于被动地位。(其实我也亲身碰到过专利侵权问题,不过不在本文之内)。

所以,我们在引进FOSS项目时,一定要仔细项目的许可证,我们自己得有法律意识,这根弦必须得绷住

License类型

现在开源项目的类型实在太多了,参看这里http://www.gnu.org/licenses/license-list.html, 估计有百种左右。但是,我们常见的许可证类型有以下几种

我们常见的软件是什么类型呢?我们看看:

  • Apache HTTPd ,许可证是Apache.
  • Apache Tomcat, 也是Apache,似乎Apache Foundation都采用Apache许可。Dubbo也是,可以参看https://github.com/apache/incubator-dubbo/blob/master/LICENSE 。
  • Spring Boot,也是Apache,https://github.com/spring-projects/spring-boot/blob/master/LICENSE.txt
  • React,用的是MIT,https://github.com/facebook/react/blob/master/LICENSE
  • Linux常用命令wget,用的是GPL,https://www.gnu.org/software/wget/
  • Linux操作系统, 用的也是GPL,https://www.kernel.org/category/faq.html
  • QT,不同用途有不同的许可,包括LGPL,参看http://doc.qt.io/qt-5/licensing.html
  • VI,用的就是BSD,https://www.freebsd.org/cgi/man.cgi?query=vi&sektion=1

License介绍

光去阅读许可证的描述太抽象了,我借用阮一峰老师的文章:http://www.ruanyifeng.com/blog/2011/05/how_to_choose_free_software_licenses.html,以图胜千言。

12/07/2018

从浏览器中输入URL到页面加载发生了什么 – Part 3

Filed under: I.T — 张太国 @ 10:38

HTTP/HTTPS请求和响应

前面TCP连接已经建立好了,意味着桥已经搭好了,下一步就该传输HTTP消息了。因为HTTP我们都很熟悉,很常见,也不是那么底层,理解起来轻松不少。
还是抓包来分析,不过这次不用Wireshark来抓,因为不太直观,这次直接用Chrome自带的Developer Tools。

HTTP 请求

下图展示了HTTP请求Header
Request URL:就是请求的URL
Request Method: GET, POST, PUT,DELETE, OPTIONS, HEAD
接下来就是其他报文头,常见的请求报头有: Accept, Accept-Charset, Accept-Encoding, Accept-Language, Content-Type, Authorization, Cookie, User-Agent等。

HTTP 响应

下图展示了HTTP响应Header

最常见的就是Status Code( 200, 302, 307, 404, 500),server等。

HTTP 10问

HTTP问题简单,那就直接列举几个问题,有些问题我给出详细答案。
1. HTTP METHOD有哪几种,分别是什么?
常见问题,不多解释。
2. HTTP的PUT/DELETE/等使用时需要注意什么?
有一点需要特别注意,有的浏览器是不支持的,所以在使用和实现时需要仔细评估好自己客户端的能力。
3. HTTP的OPTIONS用来做什么?
OPTIONS一般用来获取目标资源的通信选项,例如确认允许的HTTP Method.下面的这个例子来在Mozilla官网https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/OPTIONS
请求
curl -X OPTIONS http://example.org -i
响应
HTTP/1.1 200 OK
Allow: OPTIONS, GET, HEAD, POST
Cache-Control: max-age=604800
Date: Thu, 13 Oct 2016 11:45:00 GMT
Expires: Thu, 20 Oct 2016 11:45:00 GMT
Server: EOS (lax004/2813)
x-ec-custom-error: 1
Content-Length: 0
看红色的返回部分,意思是说该URL允许的HTTP Method 为OPTIONS、GET、HEAD以及POST。
那么OPTIONS一般用在哪里呢?是的,CORS。如果您开发过SPA,或者您的前端的逻辑和交互完全用JavaScript来实现的,肯定会碰到此问题。所谓JavaScript实现,目前比交流行的有VueJS,AngularJS,React等流行框架。如何解决这个问题?最常用的方法是是前端和后端在同一个域名下。如果不在同一个域名下,需要在后端实现支持CORS的功能,目前Spring/Spring Boot已经有类似功能支持CORS,实现起来蛮简单的,具体可以参看https://spring.io/blog/2015/06/08/cors-support-in-spring-framework,不在赘述。
关于CORS,最难的不是这里,在我遇到的Case里,比这个更复杂,如果前端是SPA,而且在某种情况下,访问任何前端页面都会进行跳转,这是需求。但是因为是SPA的架构,会出现OPTIONS(这是浏览器关于CORS支持的流程),这会使整个HTTP 流程变得紊乱,也是一个很棘手的问题。
不管怎么说,CORS属于安全性这一块,后面在软件安全(包括Web)方面专门写吧。在过去几年里,因为公司和客户在产品安全和数据安全放在了一个很高的位置,而我又是去负责这一块,所以自己在安全方面积累了大量的实战经验,非常宝贵。
4. 上述访问qq的HTTP response里的server哪里不合适,需要注意什么?
server的值是squid/3.5.24,不合适之处在哪里?也许部分人是不清楚的。其实很简单,不应该把squid的版本信息放在这里。为什么?
如果web server软件是自己公司开发的,私有的,不开源的,这也罢了,没人知道你的web server是怎么实现的,但这并不代表web  server没有漏洞,不代表别人发现不了漏洞。
但如果用的是开源的,例如Apache HTTPd,Apache Tomcat,Ngnix等,就需要注意了,每个版本都有安全漏洞,而且这些安全漏洞都有专门的记录,看看隔三差五报告的CVE,就知道漏洞多少了。所以,如果使用开源软件,很容易将自己的web server处于一个具有潜在风险的位置,所以不要加上版本号。
腾讯作为全球顶级的大公司,这方面不注意,实在是有点说不过去。如果有腾讯的朋友看到这里,还是改过来吧。
和上面一样,这也是属于安全性问题,有时间我再写吧。
5. Status Code 302与307的区别是什么?
都属于跳转,但是区别在哪里呢?
我们看看307在协议里是怎么定义的?参看rfc2616第10章节
10.3.8 307 Temporary Redirect
The requested resource resides temporarily under a different URI. Since the redirection MAY be altered on occasion, the client SHOULD continue to use the Request-URI for future requests. This response is only cacheable if indicated by a Cache-Control or Expires header field.
The temporary URI SHOULD be given by the Location field in the response. Unless the request method was HEAD, the entity of the response SHOULD contain a short hypertext note with a hyperlink to the new URI(s) , since many pre-HTTP/1.1 user agents do not understand the 307 status. Therefore, the note SHOULD contain the information necessary for a user to repeat the original request on the new URI.
If the 307 status code is received in response to a request other than GET or HEAD, the user agent MUST NOT automatically redirect the request unless it can be confirmed by the user, since this might change the conditions under which the request was issued.
在 GET、HEAD 这些幂等的请求方式上,302、307 没区别,但对于 POST 就不同了,大部分浏览器 都会 302 会将 POST 请求转为 GET,而 307则不一样,规范要求浏览器继续向 Location 的地址 POST 内容。
举个例子解释一下,假设正在POST一个消息,里面的Body有1M内容,在307的情况下,这1M的内容会继续发过去,但在302的情况下,则不会。
6. 在HTTP Response里Connection的用法需要注意什么?
不解释过多,keep-alive,closed用法不一样,根据实际情况而定,在优化网络时经常用到。
需要注意的是,Connection在通信领域会一些场景下会造成一些麻烦,尤其是在监控某个HTTP Session的flow时。
7.  在HTTP Response里Strict-Transport-Security(HSTS)怎么用?
HSTS一般大公司都会用,在我实际的项目涉及到HTTPS,为了实现某个功能,HSTS成了一个跨不过去的坎,遇到过很大问题。大家自己多看看吧。
8. 可以抓HTTPS的包了解HTTP请求和响应吗?有什么方法?
不多解释,但提供2个软件名字,Fiddler,HTTP Analyzer。
9. 为什么对性能要求高的场景下不使用HTTP作为协议?例如在商用里,RPC开源项目一般不使用HTTP作为传输协议?而在5G下使用HTTP协议呢?
有一点是需要注意的,HTTP的消息头太多了,会造成消息体特别大,影响性能,而且有些场景下这些消息头大部分都是无用的。
但是在5G里,为什么3GPP组织会采用HTTP协议作为各个reference point的interface的实现呢?大家体会一下。
10.  HTTP协议(包括HTTP/2.0)有了解吗?
不多解释,但是HTTP/2.0还是需要了解一下,优势和缺点。

浏览器解析和渲染页面

现在浏览器接收到了server的返回内容,接下来浏览器该把内容呈现给用户了。
Server返回的内容有哪些呢?这里只以HTML页面为例(API返回的JSON数据或XML数据不在讨论范围内)。
一个页面一般包含HTML、CSS、 JS、 图片等文件,那么浏览器收到这些文件后该如何渲染(render)他们呢?
以下部分很多参考下面2篇文章:
下面是浏览器的组成
 
首先我们先了解一下浏览器的组件构成,以及每个组件的功能,下图是浏览器包括的几个部分:
  1. User Interface: UI组件包括地址栏,前进/后退按钮,书签菜单等。
  2. Browser Engine: 在UI组件和渲染引擎间采取一些action.
  3. Rendering engine : 负责显示请求的内容。例如,如果是HTML页面,它将解析HTML,CSS,并将解析的内容显示在屏幕上.
        不同的浏览器使用不同的渲染引擎:
  • IE使用Trident
  • Firefox使用Gecko
  • Safari使用WebKit
  • Chrome和Opera(版本15开始)使用Blink。它是基于Webkit开发的。

4. Networking: 负责网络调用,例如HTTP请求。在不同的平台有不同的实

 5. UI backend: 主要用来绘画基本的UI元素,例如下拉框,Windows等。这个UI后台暴露一些通用的接口,并不依赖平台的。

6. JavaScript interpreter. 用来解析和运行JavaScript code。

7.  Data storage. 数据持久化的那一层。浏览器可能需要存储各种各样的数据,例如Cookie。浏览器也得支持我们常用的LocalStorage, IndexedDB,WebSQL以及FileSystem。

 

渲染页面的主要流程

下面是浏览器的渲染引擎的主要步骤。

渲染引擎解析HTML文档,并将HTML包含的元素转化为一个个DOM,并构建为一个DOM树。然后引擎开始解析来自CSS文件或直接嵌在HTML页面的CSS样式数据,这些样式信息又会构建另外一个树:渲染树
渲染树包含了多个矩形,这些矩形包含了颜色,大小,位置等属性,而且会按照对应的顺序显示在屏幕上。
当渲染树构造完毕后,接下来进入布局的程序,在这个程序里,渲染引擎会给每个DOM元素安排精确的坐标,并根据坐标在屏幕上显示。
接下来是遍历渲染树,UI Backend层会将一个个DOM元素绘画在屏幕上绘画出来。
需要注意的是,上面是一个渐进的过程,理解这一点非常重要。但是为了得到更好的用户体验,浏览器会边解析边渲染,它并不会等到所有HTML解析完了才开始构造和布局渲染树。当部分内容正在解析渲染时,另外一部分正从网络那边下载下来呢。
下面2个图是WebKit和Gecko的渲染引擎的流程,我们发现他们大致相同的。

下面是DOM树,渲染树的树形结构。

渲染引擎是单线程工作的,除了网络操作,其他所有的都是单线程的。在Firefox和Safari,它们自己就是主线程,而Chrome就是每个tab处理主线程。
网络操作则由多个并列线程去执行,但数量也是受限的,一般在2-6个。
浏览器的主线程是一个无限的事件循环,而且一直保持进程alive,一直等着各种事件(例如绘画事件,布局事件),并处理他们。
浏览器渲染10问
1.   浏览器的组成部分是什么?
2.  各个主流浏览器的渲染引起是什么?
3.  浏览器显示页面的主要流程是什么?
4.  您在做开发和测试时,有哪些浏览器(包括手机)存在兼容性问题较多?
       遇见最多的是Samsung手机和Huawei手机,有时一个兼容性需要花费大量时间去调研和修复,可能是Samsung和Huawei定制的太厉害了,不兼容一些特性吧。
5.  渲染引擎是单线程还是多线程?
6.  浏览器的网络操作一般由几个线程去执行?
7.  DOM树,渲染树是什么?
8.  为了获得更好的用户体验,我们应该在页面做些什么改进?
9.  浏览器是如何打开PDF,Word等文档的?
10. 如果让你开发一个浏览器,设计思路有哪些?

Web优化

我们知道,人的耐心是有限的,一个页面如果超过8s,人基本上不会等了,这会对业务产生巨大影响。我们该如何去优化页面呢?
思路很简单,就是按照我们前面介绍的几大步骤去优化。我们先回顾一下几大步骤:
1.     DNS查询
2.    TCP连接
3.    发送HTTP请求
4.    Server处理HTTP请求并返回HTTP报文
5.    浏览器解析并render页面
6.    HTTP连接断开
当我想总结一下的时候,雅虎在10多年就总结出来一些经验,参看这里(https://developer.yahoo.com/performance/rules.html)。
这是10多年前的经验,随着科技的发展,一些新的经验又出现了,可以容易想到的是:
1.  尽量将server离用户近一些,例如人处在中国访问Apple,应该是Apple中国站提供服务,GSLB很重要。
2. 不要把layout嵌入一层又一层,简单说就是嵌套别太深,不然影响解析和渲染性能。
3. 有些数据可以在后台处理的,就不要在前端通过JavaScript处理了。
4. 如果请求过大,Load Balance这些手段还是要上的。
5. 保持HTTP连接,合理设置Connection。
6. 后台事件性能要高,能够及时将结果返回给用户。
当然涉及到高可用,高性能等那是另外一个话题。

总结

这道面试题非常经典,考察的知识非常丰富,跨度较大,如果没有几年的经验,是很难完全掌握的,所以想答好其实不容易的。对这个问题,基本上可以根据我的经验回答,也算是对这些年来在这方面的知识的一个总结。但同时,我也参考了一些资料,感谢他们。在参考的地方,我都把URL列出来了。
写这篇文章耗费了大量时间,我觉得挺有意义,但是也不能保证里面的内容全都是正确或准确的,如果您有任何问题可以通过以下方式联系我,以便我进一步改正并更新。

下载

写到这里,三部分已经写完,在这里放上全文的PDF文档供大家参考,可能后面会更改,如果有新的文档,我将保持更新。

下载 2018/12/04版本

从浏览器中输入URL到页面加载发生了什么 – Part 2

Filed under: I.T — 张太国 @ 10:36

TCP连接

DNS解析返回域名的IP之后,接下来就是浏览器要和该IP建立TCP连接了。为什么是TCP而不是UDP?那是因为HTTP是基于TCP上的。这里涉及到另外一个话题:TCP/IP 模型。这个已经在大学的课本上学过了,我们再复习一下。

TCP/IP模型

TCP/IP模型一般分为4层,下面是我用PPT画的。
在这里不得不说OSI七层参考模型,它和TCP/IP模型的区别和联系,继续用PPT画,见下图:

不多解释,OSI的7/6/5层和TCP/TP的应用层对应,2/1层和链路层对应。在实际的应用中,主要还是TCP/IP概念模型,后面的内容主要讲它。

这些都是课本上的,也许忘了(毕竟不是天天用到这些嘛),没关系,我们以最简单的方式来讲解。为了便于理解每层的含义和作用,先看每层有哪些协议,看看有没有自己熟悉的协议。有熟悉的协议,先体会一下。

应用层
我们可以看到,有常用的HTTP/HTTPS/IMAP/SSH/Telnet等都在应用层上(题外话,这一层你用的协议越多,说明你知识越开阔)。相信每个人都用过HTTP/HTTPS,所以我上面说HTTP/HTTP是基于TCP上的。
Wikipedia 这么解释:
The application layer is the scope within which applications create user data and communicate this data to other applications on another or the same host. The applications, or processes, make use of the services provided by the underlying, lower layers, especially the Transport Layer which provides reliable or unreliable pipesto other processes. The communications partners are characterized by the application architecture, such as the client-server model and peer-to-peer networking. This is the layer in which all higher level protocols, such as SMTP, FTP, SSH, HTTP, operate. Processes are addressed via ports which essentially represent services.
传输层
没错,最常见的TCP和UDP就在这里,TCP三次握手也在这里。
Wikipedia 这么解释:
The transport layer performs host-to-host communications on either the same or different hosts and on either the local network or remote networks separated by routers.[22] It provides a channel for the communication needs of applications. UDP is the basic transport layer protocol, providing an unreliable datagram service. The Transmission Control Protocol provides flow-control, connection establishment, and reliable transmission of data.
IP层
IP层非常重要,可能这么说还不太懂,看看其他协议。大家知道ICMP吗?估计很多人还是说不上来ICMP是什么东西。大家肯定用过ping命令吧,它就是用的ICMP。说到这里,应该有感性的认识了吧。
Wikipedia 这么解释:
The internet layer exchanges datagrams across network boundaries. It provides a uniform networking interface that hides the actual topology (layout) of the underlying network connections. It is therefore also referred to as the layer that establishes internetworking. Indeed, it defines and establishes the Internet. This layer defines the addressing and routing structures used for the TCP/IP protocol suite. The primary protocol in this scope is the Internet Protocol, which defines IP addresses. Its function in routing is to transport datagrams to the next IP router that has the connectivity to a network closer to the final data destination.
链路层
这个非常底层了,ARP,NDP,Ethernet都很常见,如果认真看过HTTP抓包,熟悉LVS,Ngnix等提供的负载均衡,应该对ARP不陌生,是的ARP用来查找设备的MAC地址,在LVS做负载均衡时会用到,因为进来的stream的包MAC地址要和出去的Stream包的MAC地址保持一致,因为做负载均衡,有可能会变化,如何解决这个问题,则不在本文的讨论范围内,如有兴趣可以参看LVS的文档。
Wikipedia 这么解释:
The link layer defines the networking methods within the scope of the local network link on which hosts communicate without intervening routers. This layer includes the protocols used to describe the local network topology and the interfaces needed to effect transmission of Internet layer datagrams to next-neighbor hosts.

 

TCP/IP抓包分析

看了前面的内容,还是觉得抽象吗?如果是,不要紧,也在预期内。让我们抓个包,分析认识一下就清楚了。
先访问www.qq.com 这个主页,抓到的包如下:
看到这里,应该开始有感觉了吧。
HTTP,即应用层,正在访问js.aq.qq.com.
TCP层,src port是62957, dst port是80端口,因为js.aq.qq.com的端口是80。
IP层,用的是IPV4,我的计算机IP地址是192.168.1.2,目标IP是180.153.105.248.
链路层, 我使用的是Apple电脑,我的MAC地址我隐藏了,对端是ZTE设备。
再截几个图大家仔细看一下。
链路层
 
IP层
TCP层
应用层(HTTP)

在这里不加以详解,后面会对TCP以及HTTP层详详细说明。

TCP三次握手与四次挥手

TCP三次握手
所谓三次握手(Three-way Handshake),是指建立一个 TCP 连接时,需要客户端和服务器总共发送3个包。
三次握手的目的是连接服务器指定端口,建立 TCP 连接,并同步连接双方的序列号和确认号,交换 TCP 窗口大小信息。在 socket 编程中,客户端执行 connect() 时。将触发三次握手。
·       第一次握手(SYN=1, seq=x):
客户端发送一个 TCP 的 SYN 标志位置1的包,指明客户端打算连接的服务器的端口,以及初始序号 X,保存在包头的序列号(Sequence Number)字段里。
发送完毕后,客户端进入 SYN_SEND 状态。
·       第二次握手(SYN=1, ACK=1, seq=y, ACKnum=x+1):
服务器发回确认包(ACK)应答。即 SYN 标志位和 ACK 标志位均为1。服务器端选择自己 ISN 序列号,放到 Seq 域里,同时将确认序号(Acknowledgement Number)设置为客户的 ISN 加1,即X+1。 发送完毕后,服务器端进入 SYN_RCVD 状态。
·       第三次握手(ACK=1,ACKnum=y+1)
客户端再次发送确认包(ACK),SYN 标志位为0,ACK 标志位为1,并且把服务器发来 ACK 的序号字段+1,放在确定字段中发送给对方,并且在数据段放写ISN的+1
发送完毕后,客户端进入 ESTABLISHED 状态,当服务器端接收到这个包时,也进入 ESTABLISHED状态,TCP 握手结束。
三次握手的过程的示意图如下:
确实比较抽象,让我们继续通过抓包来分析(访问baidu.com)

这里有三个包。
192.168.1.2是我机器的IP,115.239.211.112是baidu的IP,是不是和上图一致。
具体看270包,192.168.1.2 发送SYN到115.239.211.112,seq=0;
如下图:
274包图,115.239.211.112返回SYN 和ACK给192.168.1.2, seq =0, 但是ACK等于SYN里的seq(为0)+1,所以为1
275包图,192.168.1.2收到ACK包后,给115.239.211.112再回一个ACK,ACK#为1:
对于协议的理解,还是多观察,多比对,就知道是怎么回事了。

 

TCP四次挥手
TCP 连接的拆除需要发送四个包,因此称为四次挥手(Four-way handshake),也叫做改进的三次握手。客户端或服务器均可主动发起挥手动作,在 socket 编程中,任何一方执行 close() 操作即可产生挥手操作。
·       第一次挥手(FIN=1,seq=x)
假设客户端想要关闭连接,客户端发送一个 FIN 标志位置为1的包,表示自己已经没有数据可以发送了,但是仍然可以接受数据。
发送完毕后,客户端进入 FIN_WAIT_1 状态。
·       第二次挥手(ACK=1,ACKnum=x+1)
服务器端确认客户端的 FIN 包,发送一个确认包,表明自己接受到了客户端关闭连接的请求,但还没有准备好关闭连接。
发送完毕后,服务器端进入 CLOSE_WAIT 状态,客户端接收到这个确认包之后,进入 FIN_WAIT_2 状态,等待服务器端关闭连接。
·       第三次挥手(FIN=1,seq=y)
服务器端准备好关闭连接时,向客户端发送结束连接请求,FIN 置为1。
发送完毕后,服务器端进入 LAST_ACK 状态,等待来自客户端的最后一个ACK。
·       第四次挥手(ACK=1,ACKnum=y+1)
客户端接收到来自服务器端的关闭请求,发送一个确认包,并进入 TIME_WAIT状态,等待可能出现的要求重传的 ACK 包。
服务器端接收到这个确认包之后,关闭连接,进入 CLOSED 状态。
客户端等待了某个固定时间(两个最大段生命周期,2MSL,2 Maximum Segment Lifetime)之后,没有收到服务器端的 ACK ,认为服务器端已经正常关闭连接,于是自己也关闭连接,进入 CLOSED 状态。
四次挥手的示意图如下:
这里就不抓包了,可以自行抓包对比看看。

HTTPS证书

越来越多的网站开始使用HTTPS(Apple要求App都须用HTTPS)。对于HTTPS,需要有一个SSL/TLS的鉴权/认证,才能建立TCP链接。
下图描述了HTTP和HTTPS的区别。
关于SSL/TLS如何交互等,可以参看阮一峰老师的文章http://www.ruanyifeng.com/blog/2014/02/ssl_tls.html 和http://www.ruanyifeng.com/blog/2014/09/illustration-ssl.html,写非常清楚的。
借用一张阮一峰老师的图:

 

我们还是抓包体会一下。
对着阮一峰老师图片的流程看:
273包: Client 发送Client Hello给Server。
278包: Server回Server Hello给Client。
283包: Server继续回Server Certificate给Client,要交换证书。
294包:Server继续回Server Key Exchange,交换key。
295包:Server返回Server Hello Done。
截止这里,Server已经做了不少事,接下来轮到Client了。
298包:Client Key Exchange,Change Cipher Spec,Encrypted Handshake Message。到这里就结束了。
我们再仔细看看Client Hello的273包,注意标记部分.
接下来再看看Extension,有很多对不对。这里专门说一下 SNI(Server Name Indication), server_name, 我们可以看见它的值是www.baidu.com. 也就是说浏览器发送过来的证书是给baidu这个域名签发的。SNI用来校验该证书是不是为server name提供的域名签发的。如果不是,就会报错。
有一种情况特别需要注意,在早期版本的浏览器或者HTTP客户端,SNI可能不包含在该包里的,那么怎么处理呢?如果Server端只有一个证书部署,那简单,就是按照部署的那个证书去判断。如果有多个证书部署呢?比如部署了aaa.com bbb.com ccc.com 三个域名的证书,那么就会按照缺省的去匹配,取决于软件(Apache,Tomcat等)和硬件(F5,Netscaler)怎么配置了。
但是如果已经商用,去改默认配置,会对商用服务有影响,那么可不可以在Client有一些改进呢?如果您正在使用某个HTTP library,可以考虑升级版本是否支持。

 

278包的Server Hello
继续看看Server Certificate,即283包
我们看看baidu的证书,打开Chrome就可以看到了,对比一下两图的基本信息,这时是不是觉得更容易理解?我相信答案是肯定的。
294包,Server key Exchange
 
295包,Server Hello Done。
298包,Client Key Exchange/Change Cipher Spec/Encrypted Handshake Message。

TCP/IP其他

上面都是最基本的东西,在实际的过程中还有包重试,包拼装等,太底层了,大家有兴趣可以找资料看看。

TCP/IP 10问

以下几个问题大部分都可以找到答案。
  1. TCP/IP的4层模型了解吗?每层有哪些常见协议?
  2. TCP/IP的三次握手了解吗?四次挥手是什么,了解多少?
  3. HTTP和HTTPS在TCP握手上有什么不同?SSL/TLS握手流程了解吗?
  4. SSL/TLS的版本有哪些?当前浏览器支持哪些版本?
  5. SNI了解多少?如果SNI没有,该如何校验证书?
  6. TCP与UDP区别在哪里?
  7. 为什么TCP经常会组装包?如何保证包的完整性?
  8. TCP滑动窗口原理是什么?TCP有哪些状态?
  9. MAC地址的是如何定义的?(这个问题太Edge了)
  10. SSL/TLS证书和端口有关系吗?为什么?

今天把TCP/IP, SSL/TLS介绍完了,下一部分是最后一部份了,左右介绍HTTP和Broswer的机制。

从浏览器中输入URL到页面加载发生了什么 – Part 1

Filed under: I.T — 张太国 @ 10:34

背景

“从浏览器中输入URL到页面加载的发生了什么“,这是一道经典的面试题,涉及到的知识面非常多,但作为一个自认为对网络知识掌握的比较好的老码农来说,回答这个问题自然不在话下。如果这道题目如果在面试出现,对我来说就是送分题啊。尽管如此,我还是愿意花一些时间根据我自己的理解回答一下这个题目,看我自己到底掌握的有多深,同时也把自己的知识梳理一下。

这让我想起另外一件往事,这道题有点类似于“在手机上浏览器上输入一个URL,手机做了一些什么”,我当时学习通信里的核心网时就给自己提出过这个问题。

我非常愿意将这个面试题的答案共享出来,一是希望得到大家的意见,二是也希望对那些不是特别熟的人起到一些帮助。

因为文章较长,我将它们分为三大部份,后面会提供该文章的完整PDF版本,供大家下载。

从本文里学到什么?

正如前面所说,这篇文章涉及到的知识面非常丰富,我相信您绝对可以从本文里学到很多基础知识,还有一些高级话题。

  1. DNS的解析原理,常用命令,端口等
  2. TCP/IP模型,三次握手,四次挥手。
  3. HTTP/HTTPS的原理和解析。
  4. 浏览器render一个页面
  5. Web安全性问题
  6. 抓包,分析TCP模型,三次握手,SSL/TLS,让学起来不再枯燥。
  7. 其他一些高级话题。

自认为是目前写的最详细的一篇文章了,因为里面有理论,有实战,应该会起到一个比较好的效果。

总概: 几大步骤

总的来说,当你输入在浏览器里输入一个URL到页面加载,发生的顺序如下:

  1. DNS查询
  2. TCP连接
  3. 发送HTTP请求
  4. Server处理HTTP请求并返回HTTP报文
  5. 浏览器解析并render页面
  6. HTTP连接断开
后面将对以上步骤详细介绍。

DNS查询

DNS解析流程

假设输入的URL是包含域名的,那肯定会涉及到DNS解析。当然,如果URL仅仅是IP,那就不会涉及到DNS的。域名的出现是为了方便记忆,因为域名比IP好记。我们这里假设URL包含域名。

解析的步骤大致如下图:

首先,在本地域名服务器中根据域名查询IP地址,如果没有找到的情况下,本地域名服务器会向根域名服务器发送一个请求。
如果根域名服务器也不存在该域名时,本地域名会向com顶级域名服务器(TLD)发送一个请求,依次类推下去。
直到最后本地域名服务器得到google的IP地址并把它缓存到本地,供下次查询使用。
可以参考页面https://www.verisign.com/en_US/website-presence/online/how-dns-works/index.xhtml ,该页面诠释了DNS的过程。
需要说明的是Root DNS Server一般有13个,后面有个点(.),别忘了。
a.root-servers.net.
c.root-servers.net.
j.root-servers.net.
b.root-servers.net.
i.root-servers.net.
d.root-servers.net.
k.root-servers.net.
f.root-servers.net.
l.root-servers.net.
h.root-servers.net.
m.root-servers.net.
g.root-servers.net.
e.root-servers.net.

DNS的优化

我们发现,一个DNS查询在没有缓存的情况下会有6步,这将是一个耗时的过程,如果DNS 查询时间过长,甚至会影响到用户体验。
那么现阶段是怎么优化的呢?缓存。DNS是存在着多级缓存,从离浏览器的距离排序的话,有以下几种: 浏览器缓存,系统缓存,路由器缓存,IPS服务器缓存,根域名服务器缓存,顶级域名服务器缓存,主域名服务器缓存。
我们以Chrome为例子,输入chrome://net-internals/#dns,我们会看到如下界面:
这里的Capacity: 1000,代表缓存1K条,那么每条记录缓存多久呢?参看
timeout 1
这里的1代表1分钟。
如果是系统缓存,一般分2种情况:
Linux 操作系统
见下图,一般在/etc/hosts下。
Windows操作系统
一般在C:\Windows\System32\Drivers\etc\hosts
谈到这里,我给大家分享一个特别有用的技巧
我们在做开发和测试时,会有一种情况,经常会去访问某个(测试)URL,例如http://192.168.1.8:8080/admin/login, 如果这样的话,我们极有可能存在一个问题,觉得每次输入ip真的很麻烦。怎么解决?那么我们可以这么做,利用DNS的原理,将某个伪hostname(abc-test)加入到hosts里,只需加入一条记录:
192.168.1.8. abc-test
这样就可以用http://abc-test:8080/admin/login去访问了,简单易用,对吧。

DNS负载均衡

不知道大家有没有注意或思考过一个问题,Google在全球都有服务器,不同的国家或区域访Google,是不是都很快,这就是Google GSLB的作用。也就是说不同的区域访问Google返回的IP是不一样的,甚至在同一个办公室访问Google,返回回来的IP也有可能是不一样的。
为什么呢?这里用的就是DNS负载均衡,不然Google怎么去支持全球几十亿客户的请求呢。总之,DNS会根据你的位置或IP返回一个合适的IP给你用。除了Google,一些CDN的SP例如Akamai、AWS、Azure、阿里云都有类似的服务。

DNS Record(记录)

DNS记录是一个非常重好的概念。DNS记录类型如下表。
记录类型
含义简介
A(Address)
指定域名对应的IPv4地址
AAAA
指定域名对应的IPv6地址
NS(Name Server)
指定该域名由哪个DNS服务器来进行解析
MX(Mail Exchanger)
邮件交换记录,用于电子邮件系统发邮件时根据收信人的地址后缀来定位邮件服务器
CNAME
别名记录,多个域名映射到同一台计算机(如同一主机提供mail和www服务)
TXT
主机名或域名的说明
TTL(Time-To-Live)
DNS服务器中保存的时间
PTR
将一个主机地址映射到对应的域名
HINFO
说明映射到特定 DNS 主机名的 CPU 类型和操作系统类型
在这里只介绍常用的A Record, CNAME,MX,NS。
A记录
A记录是用的最多的一种类型。
A (Address) 记录是用来指定主机名(或域名)对应的IP地址记录。用户可以将该域名下的网站服务器指向到自己的Web Server上。
同时也可以设置该域名的子域名。通俗来说A记录就是服务器的IP,域名绑定A记录就是告诉DNS,当你输入域名的时候给你引导向设置在DNS的A记录所对应的服务器。
后面的抓包分析会对A记录进行分析,让您有直观认识。
CNAME记录
CNAME记录是另一种用的比较多的记录,可以将一个域名或者子域名指向另外一个主机名。
最常用的使用场景是什么呢?没错,CDN就是这种方式。举个例子,例如公司A想把自己的图片放在Akamai的CDN上,A的子域名是img.abc.com, 而 Akamai的CDN服务域名是img.akaimacdn.com. 但是A公司期望用自己的域名吗,而不是Akamai的域名。为了实现这个目标,怎么办?是的,使用CNAME,只需要将子域名img.abc.com指向到img.akaimacdn.com。问题又来了,在哪里设置呢?肯定是在公司A这边的DNS server上,而不是Akamai那边。
后面的抓包分析会对MX进行分析,让您有直观认识。
MX记录
MX(Mail Exchanger)记录,字面意思很直观,知道它用来做邮件路由,用户可以将域名下的邮件服务器指向到自己的邮件服务器上,然后可以自己操控所有的邮箱设置。所以只需在线填写服务器的IP地址,即可以将域名下的邮件全部转到您自己设定相应的邮件服务器上。
NS记录 
NS记录用来解析服务器记录,表明由哪台服务器对该域名进行解析,这里的NS记录只对子域名生效。
例如用户希望由12.34.56.78这台服务器解析sub1.mydomain.com,则需要设置 sub1.mydomain.com的NS记录。
这里涉及到一个问题,细心的我们会发现A记录也有该功能,这里就涉及到优先级的问题了。NS记录优先于A记录。如果一个主机地址同时存在NS记录和A记录,则A记录不生效。

DNS常用命令和工具

只介绍2个常用的命令dig和nslookup。
dig
dig是一个DNS查询工具。
[warren]$ dig
; <<>> DiG 9.9.5-3ubuntu0.16-Ubuntu <<>>
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 57775
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 13, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;.                              IN      NS
;; ANSWER SECTION:
.                       16265   IN      NS      a.root-servers.net.
.                       16265   IN      NS      c.root-servers.net.
.                       16265   IN      NS      j.root-servers.net.
.                       16265   IN      NS      b.root-servers.net.
.                       16265   IN      NS      i.root-servers.net.
.                       16265   IN      NS      d.root-servers.net.
.                       16265   IN      NS      k.root-servers.net.
.                       16265   IN      NS      f.root-servers.net.
.                       16265   IN      NS      l.root-servers.net.
.                       16265   IN      NS      h.root-servers.net.
.                       16265   IN      NS      m.root-servers.net.
.                       16265   IN      NS      g.root-servers.net.
.                       16265   IN      NS      e.root-servers.net.
;; Query time: 0 msec
;; SERVER: 208.113.157.202#53(208.113.157.202)
;; WHEN: Thu Nov 29 18:04:06 PST 2018
;; MSG SIZE  rcvd: 239
再看看dig 京东的域名www.jd.com 会有什么效果。
; <<>> DiG 9.10.6 <<>> www.jd.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 2675
;; flags: qr rd ra; QUERY: 1, ANSWER: 3, AUTHORITY: 0, ADDITIONAL: 0
;; QUESTION SECTION:
;www.jd.com.                   IN    A
;; ANSWER SECTION:
www.jd.com.            300  IN    CNAME    www.jd.com.gslb.qianxun.com.
www.jd.com.gslb.qianxun.com. 300 IN CNAME    www.jdcdn.com.
www.jdcdn.com.        300  IN    A     61.174.55.1
;; Query time: 3 msec
;; SERVER: 192.168.1.1#53(192.168.1.1)
;; WHEN: Fri Nov 30 10:07:37 CST 2018
;; MSG SIZE  rcvd: 106
红色部分为有CNAME记录和A记录。
nslookup
nslookup适用于Windows,Linux,macOS等操作系统。
nslookup www.jd.com
Server:            192.168.1.1
Address:   192.168.1.1#53
Non-authoritative answer:
www.jd.com      canonical name = www.jd.com.gslb.qianxun.com.
www.jd.com.gslb.qianxun.com    canonical name = www.jdcdn.com.
Name:      www.jdcdn.com
Address: 61.174.55.1

 

DNS抓包分析

说了这么多,有些同学可能还是觉得只有概念,没法完全理解。所以,我们还是来点实战更为实际,这也是我更进一步了解DNS的工作方式,因为在我看来想了解根本,最有效的方法是抓包,然后深入查探DNS的packet。
本文都会使用Wireshark,相信大家都用过这个工具吧。如果没用过,可以下载一个,入门很简单的,别担心。
A记录
下面是抓包图,过滤条件是dns,即protocol为DNS。
请参看第89和90包,这是查询www.jd.com 的request和response。
第89包细节图如下:
我们可以看到上图,Name是www.jd.com, Type是A记录。
另外,我们可以看到其他信息,DNS是通过UDP传送。其实,有时候也是通过TCP来传送。那么什么时候用TCP,什么时候用UDP?很简单,当response的packet大于512字节时,就用TCP,反之,则用UDP。再回头看着89包,长度为70,所以用UDP了。那多问一个问题,什么情况下DNS查询包超过512?CNAME就有可能。可以参考下面的CNAME抓包。
端口是多少呢?53,是的,DNS用的是53端口,非常重要,一般防火墙要打开,否则DNS解析不了,也意味着无法访问域名的website。
那么返回什么呢?继续看第90包。
我们可以看到www.jd.com 的DNS A记录,IP地址是61.174.55.1。
CNAME
下图是查询www.taobao.com 的抓包。
同时我们也可以看到www.taobao.com.danuoyi.tbcache.com 有多条A记录,这里就是传说的DNS 负载均衡。

DNS标准和协议

DNS是有标准和协议的,就跟HTTP类似的。DNS标准和协议在IETF里。大家可以参考https://en.wikipedia.org/wiki/Domain_Name_System 的 RFC documents部分。
我认为学习协议,框架,或技术,最佳的方法就是阅读官方资料。例如,这里学习DNS可以直接看RFC文档,学习Angular,可以访问其官网

DNS 10问

如果面试,下面10问基本可以覆盖全了,答案在上面已经说过了:
  1. 为什么要用域名?
  2. DNS解析的基本流程?
  3. DNS的根域名是什么,有几个Server?TLD DNS是什么?
  4. DNS的优化策略是什么?在各个环节怎么做的?Chrome和各个操作系统怎么做的?
  5. DNS负载均衡是什么,为什么要用?
  6. DNS的记录类型有哪些?CNAME一般用在哪些场合?举例子说明一下。
  7. DNS的常用工具和命令有哪些?
  8. DNS查询是用TCP还是UDP?一般用哪个端口?
  9. DNS抓包抓过吗?Wireshark有用过吗?
  10. 请说明一下www.google.com 和google.com的区别,如何设置它们的DNS?
本章介绍完DNS,下一章节介绍TCP/IP,三次握手,四次挥手,以及SSL/TLS,内容绝对不能错过。

09/29/2018

iPhone到底贵不贵?

Filed under: I.T — 张太国 @ 15:58

自从新iPhone 出来后,最大的话题莫过于它的价格,太贵了。那中国大陆这边来说,起步价比前些年高了不少。拿最受欢迎的iPhone Xs Max 256G来说,高达10,999元,估计好多人看到这个价格后,心都碎了。而且按照消费心理,1W可是一大门槛。9999和10001的效果是不是一样的。

今天,在雷锋网的公众账号上看到一则新闻,说“64GB 版苹果 iPhone XS Max 物料成本为 390 美元”,然后在Forbes上也看到类似的文章The iPhone XS Max Could Be A Profit Machine。在这篇文章里,数据来源说是IHS Markit,这家机构的数据还是挺权威的,毕竟IHS就是干这事的。

iPhone  Xs Max 64G在大陆卖9,599RMB,390美金折合人民币2,678(按6.87的汇率),估计好多人一看到这个数字就觉得苹果太过份了,不到3K块的东西你Apple凭什么卖到接近1万块。

OK,如果我们是Apple,站在Apple的角度上,如何去思考这个问题呢?

Apple作为一个商业公司,利润是它追求的。所以,每次新的iPhone出来,我估计Apple在定价方面都是绞尽脑汁。如果是你Apple,你怎么去定价?如果定价便宜了,不挣钱,定价贵了,势必影响销量。为了利润,为了股价稳定,Apple必须拿出一个合理的价格来。定得太高或者太低,都会引起股价的不稳定或下跌。

那么Apple是如何定价的?一般来说,iPhone的定价可以从以下几个方面去考虑:

  • BoM,Billing of Materials,也就是物料费,制造一台手机的费用。
  • COGS,Cost of Goods Sold,即销售iPhone的成本。当Apple造手机时,Apple也需要成本给所有在iPhone上的开发人员,产品人员等,这个费用也包含了产品立项,产品线,物流,仓库,以及其他费用。这个上面有优化的余地,凭Tim Cook以前做运营的,应该是把这方面优化到极致了吧. 另,COGS是包含BOM的。
  • Profit。很简单,Apple想要的利润。
  • Distributor。Apple想把iPhone卖出去,靠几个Apple Store是不可能的。在各个国家或地区需要一些分发商,有了这些分发商,Apple才有可能高效率的把自己家的产品卖给消费者。
  • Retailer。即零售商。需要注意一点的是,Apple Store这样的零售商的成本应该是要比传统的零售商或者分发商成本要高很多。当然,很多时候,Apple Store除了卖机器,还承担一部分Customer Care的功能。

所以一台iPhone的零售价(MSRP)等于COGS + Profit + Distributor + Retailer。

可以简单用这张图表示:

再回到iPhone的零售价上。Forbes的网站上贴了下面这张图,看了这张图,最大的感受什么?我们发现,BOM在MSRP里所在百分比和这几年差不多,当然和2017年的iPhone X 和 iPhone 8 Plus,确实低了1-2个百分点。

那么其他费用是否增加了呢?这个Apple没有公示,我们也无法判断。但是从Apple的招聘,以及Apple Store的店面来看,肯定是增加了。从Apple发布的财务报表看(https://www.apple.com/newsroom/pdfs/Q3FY18ConsolidatedFinancialStatements.pdf ), 3个月和9个月的研发成本是增加的。3个月的增长16%,9个月的增长14.85%。而且研发支出占Apple总支出的一半(49.95%),同时我们也能看到销售成本也有接近20%的增长,这部分费用应该反映在零售商和分发商的费用上。我们可以看看Apple Store最近几年开了多少。以前也就上海北京有,现在再看看(https://www.apple.com/cn/retail/storelist/),广西,云南这些地区都有了,相信后面开店的节奏会越来越快。

更复杂的一点是,iPhone不仅仅是iPhone,iPhone附加了其他产品,例如Watch,XCode,Office套件,macOS,MacBook等其他产品,这些费用是是可以share的,但是每个产品之间如何共享支出和收入,恐怕只有Apple高层的人才知道。但是,一旦这些数字定好后,iPhone的价格就比较容易定出来了。

1W的手机贵不贵,但是架不住有那么多人买?为什么,就凭Apple这个品牌,这也是品牌溢价。你让其他厂商定个高价试试看,估计没几天就降价了,品牌不支撑。这也是定价的一个原因吧。

我不是替Apple辩解什么,但是我想说的是,iPhone的定价其实蛮复杂的,我们应该理性的去看待这个定价。

09/21/2018

对顺丰删库事件的思考

Filed under: I.T — 张太国 @ 16:39

这几天,每次在各个新闻app和圈子里出现该事情,我是感到很诧异和遗憾。

顺丰作为国内快递行业上市公司的第一名,市值约1800亿人民币。作为这样一个量级的公司,出现这种情事情,的确是不应该的。总体来说,我对这件事情的印象是:

  1. 顺丰IT水平可能不好。
  2. 顺丰IT管理肯定是存在很大的漏洞。
  3. 该工程师技能应该是比较弱的。
  4. 顺丰最应该考虑的是如何避免这种事情再次发生。

一直以来,在软件工程里,前期开发很重要,到了后期,运维又变得重要了。所以,任何一个公司,绝对不可以小觑运维的重要性。一个规范化的公司,在软件运维上必须有自己的制度和规范。

在我看来,当一个公司发展到了一定规模后,制度是要比人的主观能力要重要。说回这次事故,该如何去避免?或者说一个正常的运维是什么样的?

首先,对于不同角色,严格控制其权限和职责,例如研发有研发的权限,运维工程师有运维工程师的权限,DBA有DBA的权限。每个角色的权限是相对的。

其次,如果做一项升级,前期工作必须做好。一般来说,先申请一个时间窗口去升级,这个申请,必须按照相关的流程去审批。其次,如果申请通过,需要准备好升级的步骤(至于是手动还是自动,后面再讲),形成文档。接下来,将该文档提交给相关team去审核,审核通过后到了维护的时间窗口根据文档去做升级即可。那么该文档怎么写:

  1. 包含每个模块升级的每一步骤。
  2. 必须准备好升级失败后如何rollback的步骤。
  3. 能用脚本执行则用脚本执行,避免人工执行每一个步骤。
  4. 涉及到删除数据,更改数据,增加数据等操作,务必谨慎,有必要在lab环境里跑一次。要条件的化,QA可以介入其中。
  5. 升级文档要经过几个team的审核,尤其是对那些复杂的升级。

接下来,就开始干活了。至于是手动还是自动升级,都非常关键。在我看来,越是自动化,说明公司运维水平越高,反之,越是手动,公司运维水平就越低。例如,假设现在去升级某个web app,但是这个web app部署在不同pop(假说m个),不同pop又有n个实例,那么最后要升级m*n个实例,试想一下,如果2*2=4,手动还可以。如果是2*10=20,手动还可以接受吗?

为什么要强调自动化呢?很简单,我们要尽量降低认为错误。毕竟,人犯错误的可能性是非常大的,因为升级的时间窗口往往都是大半夜,这个时候,人处于疲惫状态,很容易出现认为的错误,而且很多时候不可预测。例如,计划删除数据库里的某些数据,通过执行SQL语句DELETE FROM table1 WHERE id=12可以达到该墓地。因为网络错误,或者id=12输入到1时,手抖,按了enter,这样就会误删,想想是不是很可怕。除了这些,还有rm 命令等。如果我们前期在准备升级文档时,把这些SQL放到脚本里去执行,那么人为错误的概率就会大大降低。

在这件事情上,运维工程师犯错了,一点不冤,需要惩罚,但是务必达到教育的效果。同时,这件事情也需要引起运维部门的高层的注意,例如Director,VP甚至COO级别的,否则,这种事情还会不断出现。我觉得,在本次事件中最大的隐患还是制度的缺失和升级方法导致的,所以在流程上改进改进再改进,方法上优化优化再优化。

最后,运维是一个非常有技术含量的活儿,同时也是靠制度撑起它的。别小看它,必须重视,否则出现什么问题,大晚上被叫起来的概率就会增加。

09/18/2018

一个微信群的现状

Filed under: 管理之道 — 张太国 @ 11:36

最近,加入了一个微信群,这个微信群的群体基本上都是IT行业人士,而且各个地方的人都有。不出一天时间,我发现这个群里讨论的话题无非包括:

  • 一些IT大公司的五花八门
  • 如何进入这些大公司
  • 买房
  • 保险
  • 30岁的焦虑

参与这个群的都有哪些人呢?

  • 在读的学生
  • 大部分是参加工作5以下的在职人员
  • 卖保险的
  • 某些公司的HR

从大家谈论的话题,我意识到现在人的焦虑该有多严重啊?

  • 一个大学还没毕业的学生,就开始考虑以后工作,买不起房。
  • 一个刚毕业工作没几年的人,考虑的是如何进入一些大公司,抱怨现在房价多高。
  • 一些卖保险的人,拼命并含蓄推销自己的产品。
  • 一些卖理财的人,因为直接推销自己的产品,和群里的人闹起来。

我也在思考是什么造成了这样的浮躁的气氛呢?应该和最近几年经济环境变化有关。我认为最主要的是社会财富积累的变化,表现在:

  • 前几年股市的变化,15年的大牛市让多少人富了,但是很少人注意到那些赔钱的人。
  • 币圈。还是有人富了。我的一个朋友还是挣了不少的,但是有多少人被割韭菜。
  • 楼市的变化。从15年起到今年上半年,从一线到三四线城市,资产价格飙升,导致一些人群的资产急升。我今年上半年去了一趟西安,和同事聊天,明显觉得一个最重要的变化是大家现在都谈房子,原来去出差,大家都是谈工作,谈技术等。我最担心的是西安房市过后一地鸡毛,毕竟我在西安待过几年,了解一些西安的情况。
  • IT行业工资。这几年工资被大公司,互联网等带起来了。因为工资高,导致我们当时招人很困难,迟迟不到位。连合作的猎头都说工资没有竞争力,即便这几年有所好转,但是招人还是困难。我们是属于通信行业,尽管公司是行业的#1,但是工资水平是他们还是差一截的。
  • 市公司造富能力。例如阿里上市造福了一批,小米上市又造福了一批,今日头条也是,大家心里羡慕嫉妒恨。
  • 舆论和媒体的作用。舆论和媒体往往有选择性的报道导致社会对以上几种情况有了一个大概印象。当然,这也符合媒体气质和策略,不然怎么有流量。

因为浮躁,大家都希望改变自己,去追求最好的生活。怎么办?所以像知识星球,逻辑思维,极客时间,知乎上的Live等这样的圈子出来了?这也是为什么知识经济出现的一个最重要的原因吧。从侧面看,这也是知乎火的一个重要原因。我不能说这些圈子不好,但是有一点一定要注意,从这些圈子里获得的知识凑效吗?我发现很多人在知乎上停留的时间很长,期待获取一些知识,包括我当时也是,但是后来我发现基本上是浪费时间,最后连知乎都不装了。

同时,也让我想起知乎上某个大V,没工作过几年,但因在腾讯等公司工作过,以这些公司作为背书,后辞职做咨询和培训。我在想一个问题,你自己在以前公司都没做过高管,你怎么知道高管是怎么回事,你培训出来的哪些鸡汤真的对员工有收益吗,那些鸡汤是自己想出来的把?讽刺的是,有不少大公司去请他培训,这我是可以理解的,作为一个利益集团,有时高管不在乎员工学到多少,但是在文化build以及情怀上还是要作出一些关怀的,正好这个大V符合这种预期。

也许我是落伍了,在过去9年,我在工作上把精力放在了产品上,导致我没有时间去和外面沟通和了解,甚至有时候都没时间换工作,有猎头打电话给我,我一直推辞,因为喜欢自己的工作。正因为这样,我发现不理解现在的人了。现在的学生和没工作几年的人的浮躁超出我想象。

说到这个微信圈,从早到晚基本上没停过,各种事情都谈,好不热闹。这样的群真的有意义吗?对于各种人士,与其在这里吐槽,聊天,还不如自己真正去学习一点事情。例如,你想做架构,为什么不考虑学习一些关于架构的知识?例如高并发,高可用等知识。具体一点就是LVS/F5/NetScaler/Ngnix(基于L4~L7实现)等,Redis/MySQL分布式/集群等,应用/HTTP/多级缓存等,队列,以及扩容(例如数据库),Docker/K8S等。有了这些知识,找个不错的工作还是比较容易的。

说到房市,现在IT行业的工资还算可以,在一线城市买房真的不能够买房吗?未必。就比如说上海,3-5万的房子还是蛮多的,别动不动看新闻说1000多万的房子一出来就没了,说实话,这些房子对大多数人是买不起的。但要说买房,还得自己亲自花一点时间去了解市场。比如说,比如说房子5W一平,买个60~90平米,对IT行业者来说还是有可能的,别被网上1000W房子的舆论吓到自己,还是自己去中介了解以下。我这里有个公式,如果您的收入(税前即可)可以买您所在城市的一平米(均价),那买房就没问题了

我一直认为,IT行业是一个相对公平的行业,不需要太多背景和资源,单凭自己的努力,是可以混的不错的,投身于这个行业,应该觉得幸运。

最后,说个大家听的,也是说给自己的。与其在那里追求一些所谓的知识,还不如沉下心来,发现自己的目标,查漏补缺,多花一点时间在上面。我知道,这需要自律,自我管理的。做得到吗?

焦虑代表了什么?代表的是想多了,但做少了。

话说回来,经过最近几个月的了解,发现自己原来不接地气啊,还好,现在已经明白很多了。

09/13/2018

我的智能手机之路

Filed under: 闲情逸致 — 张太国 @ 16:30

北京时间,2018/9/13的凌晨1点,Apple在此刻会召开一年一度的新品发布会,那时候全世界的目光集中于此。由于之前网上对新的iPhone爆的完无体肤,所以发布会上也没什么新鲜事儿了。iPhone Xs,iPhone Xs Max和iPhone XR发布了。

在看发布会时,我也回忆起自己使用SmartPhone的历史,干脆在这里记录一下。

第一次接触到智能手机是Blackberry,大概是在2005初,我应该是国内接触Blackberry最早的一批人吧。当时我老板从美国带回来2支Blackberry让我研究着,因为后面要在上面做开发。因为此,我研究了很多,加上后来开发,所以成为了国内最早的开发人员吧,后来因为资料匮乏,所以干脆把Blackberry官方文档翻译了一遍,给同行一点帮助。当然这是后话,不过这次因为Blackberry设备的把玩,我对智能手机有了最初的认识,上网,发邮件,安装app在当时多高级,多新鲜。尤其是Blackberry的全键盘QWERTY,令自己无限着迷。因为这,我从那个时候到现在一直使用全键盘。

2005年11月,换过一次工作,公司里有一台Samsung的Windows Mobile手机,也是全键盘的,内置Windows Mobile for Pocket PC。主要是来用开发,但是其键盘太难用,到让我想起Blackberry的全键盘了。但是当时出于我自己经济能力问题,我不可能花6k去买一台智能机(2005年的6K块还是挺值钱的),所以退而求其次,买了一台多普达(也就是现在的HTC)的SmartPhone(内置Windows Mobile 2003 for Smartphone)。在未来一年里,因为是不是在Windows Mobile上做开发,使用Windows Mobile手机太多,因为他们的用户体验不是太好,产生了一下疲倦心理。一旦自己有这种心思,换手机势在必行。

那换什么手机呢?很明显,Blackberry手机成为首选。所以在2006年,我买了一个Blackberry 7290(看了以下家里的旧手机,应该是7100系列)。用起来非常舒服,全键盘太好用了,右边的滑轮用户体验真好,打英文联想等。当然,不太好的是中文输入有问题。

2007年,因为看见Blackberry Pearl系列,太惊艳,所以毫不犹豫在某个周末,去浦东某个淘宝店家买了一台。其实体验完之后,感觉没有想象中的好。用完一段时间后,又想起换手机了。今年,发生了一件改变世界的事情,那就是第一代iPhone发布。

2008年,换手机的想法老早就有了,一直在心里盘算呢。换什么手机好呢?看中了Blackberry 8320,属于Curve系列,这是一款我用起来真是舒服的手机。输入法,中文输入,上网(当时用的网络是EDGE),可以轻易刷系统(把玩程度高),像素增加不少,色彩度也很饱和。也是从那个时候起,Blackberry的社交用途多起来,比如邮件,上网等。当时,属Blackberry的BBM,和PUSH Mail最有名了。这个时候,因为Push Mail没有在大陆落地,有一家叫尚邮的公司出现解决这个问题。我也安装了他们的软件,从此发邮件不是问题了,但BBM的确是个问题。此刻中国移动已经引入了Blackberry业务,BIS/BES其实是可以用的,但对于个人来说,还是比较遥远。因为接触到中国移动的人,我时常可以体会到这些服务,可怕的是一体验,发现自己就中毒了,太好的体验了。

2008年底去了北京,2009元旦加入我前东家Aicent/Syniverse(加入也是因为Blackberry接下来的机缘)。很可惜的是,我最满意的8320在一次挤地铁的时候被偷了,心疼啊。不得已,买一支呗,这时候买的是Bold系列,似乎看起来精进不少。

在2010年时,因为iPhone的大热,触摸屏已经开始成为主流,Blackberry推出第一款触摸屏的手机系列Blackberry Storm,遗憾的是,因为用户体验太差,并不是很畅销,而且这个时候Blackberry开始走下铺路了。我当时的Blackberry Storm是集成了中国电信的BES和BIS,服务用起来很好,但就是手机体验太差了。

2011年,iPhone 4已经发布,而且在国内基本上没货。直到3月开始才有所缓解吧。4月份和老板出差回来,在机场等飞机的时候,我们在聊iPhone,等我回到家,立即去营业厅买了一支。从此走上了不归路。

2011年我们其实就开始做Mobile Apps,这个我后期用到各种手机创造了条件。

2013年, HTC One一发布,以在当时来说惊艳的外表和特性吸引了不少人。我当然也是其中之一。那时候,我使用iPhone也蛮久了,想换个手机玩玩,看到HTC One发布,直接下单了。凭着当时HTC系统的优化和造型,真的不错。可惜,用到后来,系统镜头泛红了。这是2015年的事情了。

2014年,因为自己想尝试一下Windows Phone,买了一台华为的Windows Phone手机,用了几个月,就此作罢了。

2015年,因为HTC镜头泛红,加上这时国产手机大行其道,我买了一支魅族4,用了大半年,感觉系统有点卡。但话说魅族手机还真是漂亮,而且耐用,这支手机至今老人还用着呢。因为iPhone 6S的发布,我在第一时间全款预定,并于9月29拿到手机,应该是第一批最早拿到的。

2016年,都在说小米手机厉害,我买了一台Note,遗憾的是,我并未体会到里面的优势。

从2017年开始,感觉iPhone OS用起来太单调,一颗不安分的心开始了,于2018年买了一台HTC UU,在HTC如此不堪的情况再买一台,这也算是情怀了吧。遗憾的是,这台手机在前几天下岗了,主板坏了。

下一台手机是什么呢?必须是新款iPhone手机。

总结

  1. 在这经历里,我一直对国产手机抱有希望,可惜每次都是失望。直至几天,我仍认为国产手机有一段路要走,但不可否认,这个差距已经不大了。
  2. 在手机系统方面,我喜欢Blackberry和iOS,同时Android在国内生态群还是差了一些。
  3. 我对新鲜事物感兴趣,尤其是手机相关的,所以每次出来一个东西,我都会去尝试,也是“浪费”了不少钱。
  4. 关于系统的演进,例如Blackberry,从早起的3.x,到Blackberry 7.1,又到后来的Blackberry10(QNX),那是另外一个话题了,有空可以单独讲讲所有Windows Mobile,Blackberry, iOS,Android, Palm等系统的演进。我没做过Symbian的开发,所以不多讲。
  5. 用过这么多手机,我认为性价比最高的是iPhone,做工最好的还是iPhone,例如我的iPhone 4还在用着呢,这都7年了。
  6. 这几年,手机想玩出新花样比原来难了。如果想出现当时iPhone或者Mac Air的创新性和颠覆性,那基本上遥不可及,包括Apple。Apple想革命自己,现在来看,难!
Older Posts »

Powered by WordPress