沟通杂想

2018-4-22 评论(0) 分类:随记

一个人做一个项目,效率是最高的,各模块间的接口,前后端联调,产品策略,视觉还原,灰度部署方案,运营方案,都在一个人脑里,各块以毫秒级速度进行沟通,瞬间能完成,这里的沟通成本是没有的。

一旦涉及到团队合作做一个项目,沟通成本就上来了,随着项目越来越大,分工越来越细,项目的沟通也细分了很多个层级,同个小团队间的沟通最快,然后是跨团队,跨部门,跨事业群,跨公司。而这里的沟通往往除了项目本身确定性的方案对齐外,更多的是其他额外的不确定因素,像任务排期(优先级不统一)、权力和意愿(不配合,层层批准)、信息不对称(不知道谁负责,不知道为什么这样做)、意见不统一等,导致沟通成本不可控,一个中大型公司很大一部分工作就花在研究如何减少沟通成本上。

技术层面上,接口封装就是减少沟通成本,省去不同模块的的开发者之间沟通细节的成本。全栈也是种减少沟通成本的方式,一个前端页面,是跟其他页面需要沟通协调的内容多,还是跟后端联调接口的沟通多?大部分情况是后者,所以如果前后端一个人做,可以省去这里的沟通成本。产品PRD/运营方案文档/统一的视觉规范等自然也是为了减少沟通而产生的。

非技术层面上,很多组织架构的调整都是在寻找减少沟通成本以提高效率,像腾讯早期各产品的交互和视觉设计由一个部门负责,其他产品团队以提需求的方式跟设计团队合作,好处是专业度高和风格统一,结果每个产品跨部门沟通成本太高,现在都改成各个产品线配自己的设计团队。对于大公司,目前看到的比较好的常见做法是,大型固定的业务成立部门,备齐所有工种人员,包括技术产品设计运营等,需求在部门内完成,减少跨部门沟通成本。各工种仍是独立自己的团队,比如技术团队/产品团队,保持自己的专业度,而做一个个具体项目时,通常需要各团队人员协作完成,可以各团队抽人组成虚拟组,配一号位人员总体负责,减少因为跨团队跨组带来的沟通成本。不过这个虚拟组和一号位人员得有组织上/实际行动保证才能起作用,否则真的是纯虚拟了,变成仍然是跨团队沟通。

一些公司的精英招聘策略也是能有效减少沟通成本,若一个人能力强工作效率高,产出能顶两个人,那实际上加上减少的沟通成本,带来的收益远不止两倍,而若招平庸或差一些的人,跟团队间沟通效率不匹配,带来的沟通成本上升效率下降也不止一个人力的范围内。一个组织大了就一定会有各种人相关的问题需要解决,精英小团队各种好,不好的是招聘困难,以及在铺业务时还是会面临人力不足问题导致扩招,难以控制。

对快应用的看法

2018-3-21 评论(6) 分类:互联网

国内厂商联合起来推出快应用,说说看法。

与小程序相同点

  1. 前端技术栈:毫无疑问所有类似方案都只能是前端技术栈,从社区成熟度,开发者接受程度,开发效率各方面没有对手。
  2. native 能力:都提供了比 web 更多的 native 能力。
  3. 即时/离线:跟 web 一样即点即用,跟 native 一样离线使用,前提是应用不复杂,体积限制在1M以内,当然以后复杂了也可以做分包。

与小程序的不同点

  1. native 渲染:快应用使用前端技术栈开发,native 渲染,性能体验会比较好,看代码挺像是直接拿 RN 改改用了,不过发布会上没提到 RN,而小程序目前是webview渲染。
  2. 自定义框架和规范:与小程序不同的开发框架和规范,快应用更像 vue 的写法,文件结构不一样,样式上因为使用native渲染,只支持 flexbox 布局,CSS 属性的支持程度上不如 webview 渲染的小程序,能力会弱一些。
  3. 系统级能力:目前看起来小程序没有的只有deeplink和push,通过url唤起快应用的deeplink,以及跟原生一样的push能力。

优势

  1. 流量:目前看起来,对开发者来说,使用快应用最大的理由就是厂商的流量扶持,而这是不是个优势还得看各厂商的扶持力度。
  2. 反垄断:小程序腾讯有绝对控制权,开发者把身家性命都放在腾讯的平台里,可能会导致任人宰割,自身对应用的控制力也弱,多一个渠道多一份活路。
  3. 其他:native渲染,deeplink入口,原生桌面入口,push能力这些目前相对小程序算是有一些优势。

劣势

  1. iPhone:联合再多的厂商,也联合不到苹果,中国高端手机市场 iPhone 份额高达85%,做快应用要不就是放弃这部分用户,要不就是针对 iPhone 再做一套,这个成本划不划算只能看能从厂商流量扶持里拿到多少好处,否则为什么不开发小程序。
  2. 跨公司合作:一个大公司内跨部门协作都困难,何况跨N个公司的合作,而且还没有一个站在上一层的领导者,要做成非常困难。
  3. 社交:快应用缺乏微信的社交场景能力和传播手段,推广拉新成本仍不低。

看法

移动开发向前端技术栈倾斜,原因:

  1. 超级APP,业务越来越多,为了减体积和动态发布能力,大部分业务使用前端技术栈开发。
  2. 普通APP,拉新成本高,用户装APP的意愿低,开始尝试转向即开即用的H5/小程序和类似平台拉新。

普通业务开发,按目前趋势越来越倾向前端技术栈,即使是独立APP,展示型业务在 APP 里也会倾向用前端技术栈开发,从开发效率/跨平台/动态性都很有优势,劣势是性能体验稍差,这点长期可以靠机器硬件的提升,短期可以用类似RN方案。

小程序为这样的需求提供了个很好的平台,但缺陷是开发者对应用没有控制力,无法 push 触达唤起用户,入口也一般,生命线掌握在腾讯上,快应用可以弥补这些缺陷,提供了另一个选择,不过不支持 iPhone 仍是个几乎无法解决的致命缺陷,加上上述提到的劣势,总体上不看好。这种事可能得由 google 联合苹果一起做才有戏。

native VS web 这个话题从 08/09 年开始开始到现在都没有结束,因为各有不小优势,即使是现在 web 技术栈占上风,原生 APP 的性能体验,快捷入口,品牌认知这些优势仍是不小,而且技术的发展同时给 native 和 web 两种模式提供了利好,并没有倾向其中一方:对于 web,硬件提升使得体验越来越好。对于 native,运营商无限流量的时代和越来越大的存储空间使得用户装 APP 成本下降,这两个开发模式在很长时间内仍是融合的状态。

北海道杂记

2018-2-25 评论(5) 分类:生活

过年前去日本北海道浪,说了三四年要去日本,这次终于成行了,第一次去日本,写篇体验杂记水文。作为一个从小受日本动漫和游戏熏陶的人,本来想去东京秋叶原这些地方,季节原因还是先去北海道转转。

北海道玩的就是雪和温泉,在登别玩白花花软绵绵厚厚的雪,走在洞爷湖边上纯白的湖畔小道,在札幌白色恋人公园体验大雪纷飞,确实都挺美的。北海道温泉特别多,连札幌市内的酒店都有温泉,不过还是登别的温泉最好,在室外天寒地冻边泡温泉边欣赏旁边雪景是挺不错的体验。不过温泉只能全裸不能穿泳衣导致必须男女分浴这点搞得挺没意思。
(更多…)

移动 APP 网络优化概述

2018-1-9 评论(21) 分类:技术文章

一般开发一个 APP,会直接调用系统提供的网络请求接口去服务端请求数据,再针对返回的数据进行一些处理,或者使用AFNetworking/OKHttp这样的网络库,管理好请求线程和队列,再自动做一些数据解析,就结束了。

但对于一些大型 APP,还会想针对网络的一些问题进行进一步优化,包括:

  1. 速度:网络请求的速度怎样能进一步提升?
  2. 弱网:移动端网络环境随时变化,经常出现网络连接很不稳定可用性差的情况,怎样在这种情况下最大限度最快地成功请求?
  3. 安全:怎样防止被第三方窃听/篡改或冒充,防止运营商劫持,同时又不影响性能?

对基于浏览器的前端开发来说,网络这块能做的事情很少,但对于客户端 APP 来说,整个网络请求过程是自由控制的,可以做很多事情,很多大型 APP 都针对这三个问题做了很多网络层的优化,一些新的网络层协议像 HTTP2 / QUIC 也是在这些方面进行了不少优化,在这里边学习边整理,大致列举一下常见的做法。

速度

正常一条网络请求需要经过的流程是这样:

  1. DNS 解析,请求DNS服务器,获取域名对应的 IP 地址。
  2. 与服务端建立连接,包括 tcp 三次握手,安全协议同步流程。
  3. 连接建立完成,发送和接收数据,解码数据。

这里有明显的三个优化点:

  1. 直接使用 IP 地址,去除 DNS 解析步骤。
  2. 不要每次请求都重新建立连接,复用连接或一直使用同一条连接(长连接)。
  3. 压缩数据,减小传输的数据大小。

逐条来看能做什么。

1.DNS

DNS 完整的解析流程很长,会先从本地系统缓存取,若没有就到最近的 DNS 服务器取,若没有再到主域名服务器取,每一层都有缓存,但为了域名解析的实时性,每一层缓存都有过期时间,这种 DNS 解析机制有几个缺点:

  1. 缓存时间设置得长,域名更新不及时,设置得短,大量 DNS 解析请求影响请求速度。
  2. 域名劫持,容易被中间人攻击,或被运营商劫持,把域名解析到第三方 IP 地址,据统计劫持率会达到7%。
  3. DNS 解析过程不受控制,无法保证解析到最快的IP
  4. 一次请求只能解析一个域名。

为了解决这些问题,就有了 HTTPDNS,原理很简单,就是自己做域名解析的工作,通过 HTTP 请求后台去拿到域名对应的 IP 地址,直接解决上述所有问题:

  1. 域名解析与请求分离,所有请求都直接用IP地址,无需 DNS 解析,APP 定时请求 HTTPDNS 服务器更新IP地址即可。
  2. 通过签名等方式,保证 HTTPDNS 请求的安全,避免被劫持。
  3. DNS 解析由自己控制,可以确保根据用户所在地返回就近的 IP 地址,或根据客户端测速结果使用速度最快的 IP。
  4. 一次请求可以解析多个域名。

其余细节就不多说了,HTTPDNS 优点这么多,几乎成为中大型 APP 的标配。至此解决了第一个问题 — DNS 解析耗时的问题,顺便把一部分安全问题 — DNS 劫持也解决了。

2.连接

第二个问题,连接建立耗时的问题,这里主要的优化思路是复用连接,不用每次请求都重新建立连接,如何更有效率地复用连接,可以说是网络请求速度优化里最主要的点了,并且这里的优化仍在演进过程中,值得了解下。

keep-alive

HTTP 协议里有个 keep-alive,HTTP1.1默认开启,一定程度上缓解了每次请求都要进行TCP三次握手建立连接的耗时。原理是请求完成后不立即释放连接,而是放入连接池中,若这时有另一个请求要发出,请求的域名和端口是一样的,就直接拿出连接池中的连接进行发送和接收数据,少了建立连接的耗时。

实际上现在无论是客户端还是浏览器都默认开启了keep-alive,对同个域名不会再有每发一个请求就进行一次建连的情况,纯短连接已经不存在了。但有个问题,就是这个 keep-alive 的连接一次只能发送接收一个请求,在上一个请求处理完成之前,无法接受新的请求。若同时发起多个请求,就有两种情况:

  1. 若串行发送请求,可以一直复用一个连接,但速度很慢,每个请求都要等待上个请求完成再进行发送。
  2. 若并行发送这些请求,那么首次每个请求都要进行tcp三次握手建立新的连接,虽然第二次可以复用连接池里这堆连接,但若连接池里保持的连接过多,对服务端资源产生较大浪费,若限制了保持的连接数,并行请求里超出的连接仍每次要建连。

对这个问题,新一代协议 HTTP2 提出了多路复用去解决。

多路复用

HTTP2 的多路复用机制一样是复用连接,但它复用的这条连接支持同时处理多条请求,所有请求都可以并发在这条连接上进行,也就解决了上面说的并发请求需要建立多条连接带来的问题,网络上有张图可以较形象地表现这个过程:

duolufuyong

HTTP1.1的协议里,在一个连接里传送数据都是串行顺序传送的,必须等上一个请求全部处理完后,下一个请求才能进行处理,导致这些请求期间这条连接并不是满带宽传输的,即使是HTTP1.1的pipelining可以同时发送多个request,但response仍是按请求的顺序串行返回,只要其中一个请求的response稍微大一点或发生错误,就会阻塞住后面的请求。

HTTP2 这里的多路复用协议解决了这些问题,它把在连接里传输的数据都封装成一个个stream,每个stream都有标识,stream的发送和接收可以是乱序的,不依赖顺序,也就不会有阻塞的问题,接收端可以根据stream的标识去区分属于哪个请求,再进行数据拼接,得到最终数据。

解释下多路复用这个词,多路可以认为是多个连接,多个操作,复用就是字面上的意思,复用一条连接或一个线程。HTTP2这里是连接的多路复用,网络相关的还有一个I/O的多路复用(select/epoll),指通过事件驱动的方式让多个网络请求返回的数据在同一条线程里完成读写。

客户端来说,iOS9 以上 NSURLSession 原生支持 HTTP2,只要服务端也支持就可以直接使用,Android 的 okhttp3 以上也支持了 HTTP2,国内一些大型 APP 会自建网络层,支持 HTTP2 的多路复用,避免系统的限制以及根据自身业务需要增加一些特性,例如微信的开源网络库 mars,做到一条长连接处理微信上的大部分请求,多路复用的特性上基本跟 HTTP2 一致。

TCP队头阻塞

HTTP2 的多路复用看起来是完美的解决方案,但还有个问题,就是队头阻塞,这是受限于 TCP 协议,TCP 协议为了保证数据的可靠性,若传输过程中一个 TCP 包丢失,会等待这个包重传后,才会处理后续的包。HTTP2的多路复用让所有请求都在同一条连接进行,中间有一个包丢失,就会阻塞等待重传,所有请求也就被阻塞了。

对于这个问题不改变 TCP 协议就无法优化,但 TCP 协议依赖操作系统实现以及部分硬件的定制,改进缓慢,于是 GOOGLE 提出 QUIC 协议,相当于在 UDP 协议之上再定义一套可靠传输协议,解决 TCP 的一些缺陷,包括队头阻塞。具体解决原理网上资料较多,可以看看。

QUIC 处于起步阶段,少有客户端接入,QUIC 协议相对于 HTTP2 最大的优势是对TCP队头阻塞的解决,其他的像安全握手 0RTT / 证书压缩等优化 TLS1.3 已跟进,可以用于 HTTP2,并不是独有特性。TCP 队头阻塞在 HTTP2 上对性能的影响有多大,在速度上 QUIC 能带来多大提升待研究。

3.数据

第三个问题,传输数据大小的问题。数据对请求速度的影响分两方面,一是压缩率,二是解压序列化反序列化的速度。目前最流行的两种数据格式是 json 和 protobuf,json 是字符串,protobuf 是二进制,即使用各种压缩算法压缩后,protobuf 仍会比 json 小,数据量上 protobuf 有优势,序列化速度 protobuf 也有一些优势,这两者的对比就不细说了。

压缩算法多种多样,也在不断演进,最新出的 Brotli 和Z-standard实现了更高的压缩率,Z-standard 可以根据业务数据样本训练出适合的字典,进一步提高压缩率,目前压缩率表现最好的算法。

除了传输的 body 数据,每个请求 HTTP 协议头的数据也是不可忽视,HTTP2 里对 HTTP 协议头也进行了压缩,HTTP 头大多是重复数据,固定的字段如 method 可以用静态字典,不固定但多个请求重复的字段例如 cookie 用动态字典,可以达到非常高的压缩率,这里有详细介绍。

通过 HTTPDNS,连接多路复用,更好的数据压缩算法,可以把网络请求的速度优化到较不错的程度了,接下来再看看弱网和安全上可以做的事情。

弱网

手机无线网络环境不稳定,针对弱网的优化,微信有较多实践和分享,包括:

    1. 提升连接成功率
      复合连接,建立连接时,阶梯式并发连接,其中一条连通后其他连接都关闭。这个方案结合串行和并发的优势,提高弱网下的连接成功率,同时又不会增加服务器资源消耗:
      20180109120421
    2. 制定最合适的超时时间
      对总读写超时(从请求到响应的超时)、首包超时、包包超时(两个数据段之间的超时)时间制定不同的计算方案,加快对超时的判断,减少等待时间,尽早重试。这里的超时时间还可以根据网络状态动态设定。
    3. 调优TCP参数,使用TCP优化算法。
      对服务端的TCP协议参数进行调优,以及开启各种优化算法,使得适合业务特性和移动端网络环境,包括RTO初始值,混合慢启动,TLP,F-RTO等。

针对弱网的这些细致优化未成为标准,系统网络库没有内置,不过前两个客户端优化微信的开源网络库 mars 有实现,若有需要可以使用。

安全

标准协议 TLS 保证了网络传输的安全,前身是 SSL,不断在演进,目前最新是 TLS1.3。常见的 HTTPS 就是 HTTP 协议加上 TLS 安全协议。

安全协议概括性地说解决两个问题:1.保证安全 2. 降低加密成本

在保证安全上:

  1. 使用加密算法组合对传输数据加密,避免被窃听和篡改。
  2. 认证对方身份,避免被第三方冒充。
  3. 加密算法保持灵活可更新,防止定死算法被破解后无法更换,禁用已被破解的算法。

降低加密成本上:

  1. 用对称加密算法加密传输数据,解决非对称加密算法的性能低以及长度限制问题。
  2. 缓存安全协议握手后的密钥等数据,加快第二次建连的速度。
  3. 加快握手过程:2RTT-> 0RTT。加快握手的思路,就是原本客户端和服务端需要协商使用什么算法后才能加密发送数据,变成通过内置的公钥和默认的算法,在握手的同时就把数据发出去,也就是不需要等待握手就开始发送数据,达到0RTT。

这些点涉及的细节非常多,对 TLS 的介绍有一篇雄文,说得很详细,在此推荐。

目前基本主流都支持 TLS1.2,iOS 网络库默认使用 TLS1.2,Android4.4 以上支持 1.2。TLS1.3 iOS 还处于测试阶段,Android 未查到消息。对于普通 APP,只要正确配置证书,TLS1.2 已经能保证传输安全,只是在建连速度上会有所损耗,有一些大型 APP 像微信就自行实现了 TLS1.3 的部分协议,早一步全平台支持。

最后

网络优化这个话题非常庞大,本文只是在学习过程中从优化思路上列举了目前业界常见的优化点,还有很多细节很多更深入的优化没涉及到,网络层实践开发经验不足,若有错误欢迎指出。