分类目录归档:WEB服务

fredzneg与你一起对apache,nginx,squid,trafficserver学习相关知识及探讨!

互联网视频的实际工业标准RTMP: 有多少个坑?

最简单的PC流媒体应用,可以使用Flash采集摄像头和麦克风后,以RTMP协议推送给流媒体服务器,然后在浏览器中用Flash播放器播放这个RTMP流。总共需要多少行代码?可以100行as代码就可以实现,脏累烦的事情都是flash搞定了。

视频点播,从来就不是RTMP的事情,那是HTTP文件的世界,一个HTTP-MP4文件,可以在所有平台观看。直播呢也不仅仅是PC了,移动互联网、h.265和mpeg-dash,这些视频的新技术,发展的速度非常快。而HLS这个和RTMP一样古老的Apple的流媒体技术,在Android3支持了HLS后,HLS成了移动互联网应用最广泛的技术。

RTMP还是那个RTMP,从视频的编码采集到服务器,还是RTMP;分发到PC,可以RTMP,也可以HLS了;分发到移动互联网,自己的app可以RTMP,浏览器只能HLS了。

而流媒体服务器的角色,也从分发RTMP直播流,变成了分发RTMP和HLS流。RTMP对于直播流媒体服务器,还是扰不过去的大坑。让我们一起数一数RTMP这个坑里有多少个球吧。

第一个球,变更过的加密握手协议。RTMP协议Adobe公开了吗?是的,可以在Adobe官网上下载。按照协议实现一个RTMP服务器时,发现里面的握手是变更过了的;这就是为何SRS需要编译openssl库,需要从客户端的握手信息中获取客户端的公钥,然后按照指定算法交换密钥。如果按照RTMP标准文档握手会怎样?Flash播放器只能播放vp6编码的流,无法播放h.264的流,呵呵。

第二个球,变更过的扩展时间戳传输方法。RTMP的时间戳是24位的,如果超过这个4.5小时连续推流,就需要用到高8位的扩展时间戳。标准中说,chunked的X3包,是不能包含扩展时间戳的;可惜Adobe的所有产品都用了,从flash到FMLE到FMS。而ffmpeg中也有注释抱怨说Adobe太坑爹了,没事改它干啥。而SRS中对于这种处理,是采用猜测,即X3的chunked包先读4字节出来,如果和消息的时间戳吻合那么就是Adobe系统,也有些开源的产品遵守规范的,SRS会自动适配。

第三个球,RTMP的时间戳是32位还是31位?在flv标准中,明确讲了是31位(SI32)即24.8天左,而按照RTMP的49.7天回绕的说法应该是32位。一般没有问题,谁会看一个直播24.8天呢?额,这个不是很严谨的做法,对于服务器来讲。SRS使用31位。

第四个球,不能变更ChunkSize。有些服务器不能变更ChunkSize,所以SRS在Edge模式时,回源某些服务器会有问题。这个球只能配置SRS的默认ChunkSize,配置为128即原始值。

第五个球,溢出的ChunkSize。RTMP标准说ChunkSize最大不超过65535,有个什么球服务器,就喜欢设置一个比这个大得多的ChunkSize,泥马!这个该怎么处理?忽略标准就好,实际上没有这个上限。

RTMP的扩展时间戳传输,请参考:http://blog.csdn.net/win_lin/article/details/13363699

RTMP的复杂握手协议,请参考:https://github.com/winlinvip/simple-rtmp-server/wiki/v1_CN_RTMPHandshake

RTMP的更多信息,请参考:https://github.com/winlinvip/simple-rtmp-server/wiki/v1_CN_DeliveryRTMP

用nginx-rtmp的63%代码,增加80%的功能,SRS用到的ST是个什么球?

这次我要讲的是:ST(state-threads)是个什么球?

趁着吃完饭休息会儿,给大家讲讲ST(state-threads),一个四两拨千斤的想法。基于ST的SRS1只用了4.3万行(63%)代码,比nginx-rtmp多了83%的功能,周期缩短100%;而SRS2只用了6.5万行(95%)代码,比nginx-rtmp多了230%功能。开发周期SRS1用了1年,SRS2用了1年;nginx-rtmp发布1.0用了2年。啥都不说了,SRS3就不再和nginx-rtmp比了,SRS3和SRS2比吧~

如果说代码行数不能说明问题,那再爆料一组数据,SRS1的注释率是22.1%,而SRS2的注释率是23.7,nginx-rtmp注释率是3%。可见SRS用ST简化了多少逻辑。nginx-rtmp的6.8万行代码,是去掉了其他模块,只有core和rtmp等必要模块,总共nginx-rtmp有16万行代码。

ST解决的是服务器的最根本问题:如何以最高效率服务多个客户端连接?答案就是nginx的架构,即单线程异步非阻塞socket(没错还有多进程,我们先只考虑如何一个进程最高效);在linux中,就是epoll+send(MSG_DONTWAIT),具体的可以翻翻书柜,epoll早就不是什么新鲜事了。

这个架构可以打个比方,一个快递员在送快递时,假设有4个客户分别在四个完全不同的方向,东家西家南家北家,快递员每家都要送1000个包裹,快递员的货车有限先送东家1000个包裹,东家收了100个候发现家里没有空间了得腾缓冲区出来,快递员只好暂时不管东家了(非阻塞啦),去给西家送了200个还有800个,南家300个还有700个,北家1个还有999个。

接下来肿么办?最快的方式当然是各家的空间腾出来后,快递员用epoll_wait就知道哪些可以继续了,这就是异步啦。这个异步非阻塞是相当高的效率,但是麻烦的地方在于,快递员每次都要登记各家的状态,然后跑到各家去继续送(调用不同的处理函数),路上不仅浪费很多时间,而且维护这些信息非常之麻烦啊!每次都得把路重新计算规划,再跑一边非常需要费脑筋啦。

最简单的方式是不要登记各家状态,每家都派一个快递员啦(创建线程),各家有空间这个快递员马上就继续发,这样是最简单的逻辑;缺点是要做线程同步咯,而且很昂贵啦,没法一下子服务几万个用户。

孙悟空的毫毛可以用在这里,分身术,实际上还是一个快递员,但是在各家那里分个身。好处是不用登记那些信息,各家有空间了立马就开始写;比线程的优势是不用锁,开销小。ST就是分身术,虚拟线程,即用户空间线程协程,类似goroutine,或者C#的纤程。

协程完全是不同于进程和线程的一套写代码思路,解决问题的思路不一样,当然结果是不一样的啦。在处理rtmp的edge,以及http-flv的hstrs(http stream trigger rtmp source)时,涉及到多个线程交互,这种就相当于两个异步状态空间相乘,那个是相当之复杂的。这是为何nginx-rtmp实现RTMP比较费劲,要实现RTMP-EDGE,以及HTTP-FLV、HSTRS是非常难的事情。

关于ST更多信息,请参考:http://blog.csdn.net/win_lin/article/details/8242653

比nginx-rtmp高三倍性能的SRS的高性能是个什么球?

SRS单进程能支持9000并发,nginx-rtmp单进程最多支持3000个,单进程的性能SRS是nginx-rtmp的三倍。SRS单进程性能如何做到nginx-rtmp的三倍的?SRS哪几个结构极大提升了性能?

先来看看我们遇到的问题,RTMP协议和HTTP协议是又很大不同的。nginx在分发HLS,即m3u8文本文件和ts视频文件时,对所有连接发送的都是同一个内容,甚至可以调用sendfile让内核自己发fd去,nginx服务器自己要干的事情很少了;如果nginx必须把每个ts的内容读出来,修改里面某些字节,然后每个客户端一次发送的数据前还得加点什么,nginx就会很忙了。

这就是RTMP,每个video或audio包,在发送给某个连接之前,都得修改下时间戳(至少FMS是每个连接收到的媒体数据都是从0开始的时间戳),然后把包再拆分成一些小片段(chunked),每个chunk包前面加几个字节的头信息,然后发送。我勒个去~

举个例子,假设有个视频的I帧有200000bytes,默认的chunk包最大是128字节,所以得拆分成200000/128=1562个chunk包来发送,每个chunk包前面都要加chunk头。没有办法sendfile了吧?可以想象得到内存要被蹂躏成什么样子吧?这就是RTMP流媒体服务器麻烦的地方了,客官可以自己想下搞个什么样子的算法能最高效发送粗去~

nginx-rtmp是性能最高的服务器,比crtmpd都要高,red5根本就低两个级别,wowza也没有它高。SRS做了什么能够比nginx-rtmp单进程还要高三倍?

第一点,st-load,这个是SRS能做到高性能的最重要的原因,一个st-load可以模拟2000+的客户端。一个牛逼的benchmark的工具;如果没有st-load,如何知道系统的性能瓶颈在哪里?总不能打开3000个flash页面播放rtmp流吧?开启3000个ffmpeg来抓流?不靠谱。这就是高性能第一定律:高性能不是想象和猜测粗来的,而是测试、调试和改进粗来的。

第二点,gperf/gprof性能benchmark功能。在编译SRS时,就可以打开gcp或者gprof的性能分析选项,灰常方便就可以拿到数据。缩短了改进和优化的开发周期。

第三点,引用计数的msgs避免内存拷贝。从编码器收到的video/audio数据,转换成SrsSharedPtrMessage放到每个连接的发送队列,避免每个都拷贝一次;因为发送给每个客户端的消息(不是chunked包)头可能不一样,譬如时间戳不一样,但是消息的payload是一样的。

第四点,使用writev发送chunked包,避免消息到chunked包的内存拷贝。可以开辟一个header的缓冲区,专门放每个chunked包的header,然后用iovc保存头的指针和大小,payload的指针和大小,用writev就可以一次发送。

第五点,mw(merged-write)技术,即一次发送多个消息。虽然每个消息使用writev可以避免拷贝,还有更高效的是一次发送多个消息,即把多个消息的chunked头写在header的缓冲区,iovc保存多个消息的chunked头和payload指针,一次writev发送多个消息。这个是最关键所在。

第六点,减少timeout recv,每个连接都是一个st-thread在服务。在发送之前,线程得尝试从连接收取消息,譬如客户端的stop之类的;所以只能recv时指定timeout,譬如300毫秒如果还没有收到消息,就发送连接队列中的消息。这个会导致st的timeout红黑树操作频繁。实际上,可以直接开启一个recv线程,因为客户端的消息非常少,避免timeout接收。

第七点,fast buffer和cache。譬如每次取消息的数组,使用cache;使用fast buffer避免频繁删除;使用header的cache。

第八点,vector还是list?有的地方看起来list更高效,譬如simple buffer这种频繁删除头,以及在结尾加入数据,看起来是list应该做的事情。但是实际上测试发现,vector比list高10%性能。所以,回到第一点,高性能不是猜测和想象粗来的;有的时候有些代码写得很慢,但是这个频率非常低,那么就不要考虑性能,而要考虑可读性。我觉得可以算是高性能第二定律:不要总是考虑高性能,可读性更重要。

另外,nginx-rtmp有多进程啦。没错,可惜SRS也可以有多进程啦;可以有为何没有做呢?首先,9000个连接还不够么?1Mbps的码率可以到9Gbps了哦,伦家的机房交换机有那么牛逼么?敢一个服务器服务那么多用户么?其次,多进程不是万金油的,不过是一种技术,不是没有多进程就低人一等,有了多进程就高人一等,别那么技术控,关键在于对于客户有啥价值。再次,可以用RTMP302支持多进程,这个是最稳定的多进程技术。最后,杰哥的BLS已经实现了多进程,他设计的多进程架构,即一个源站fork多个边缘的进程的结构,是最简单的多进程通信模型。这可以引申出高性能第三定律:表当真呢,高性能不是万金油。

SRS的性能测试,请参考:https://github.com/winlinvip/simple-rtmp-server/wiki/v1_CN_Performance

SRS的性能优化commit,请参考:https://github.com/winlinvip/simple-rtmp-server/tree/2.0release#performance

堪比Google Analytics网站统计的Piwik,不用再装Awstats

被称为赶超Google Analytics的Piwik是一套基于Php+MySQL技术构建的开源网站访问统计系统,前身是 phpMyVisites。协议为GPL。

本文的网站统计主角是 Piwik ,但我想在开头说一说 Awstats 跟 Google Analytics 。



Awstats 是我一贯使用的流量分析工具,它是通过分析 HTTP 服务器的访问日志得到最精确的流量数据,丝毫无差。但就因为这样,HTTP 日志里头有什么,它就只能出什么,单单就只是流量相关的参数。并不能向Piwik, Google Analysis 那样可以获取到访问者的屏幕分辨率,用户的访问忠诚度,连接速率…等更加详细的统计资料。因为后者都基于的是 javaScript 的脚本。

但 Awstats 的流量数据更加准确,因为所有请求都通过 HTTP 服务器,即使是一个小小的 gif 图片,还是一个微不足道的html页面,css,js … HTTP 的日志都会如实记录。

而基于 javaScript 的脚本的 Piwik 跟 Google Analysis, 就只能在你已经把该脚本插入到 <body> 里头的页面才在统计范围,也就是纯页面。所以你会发现,统计流量的话,基于这种方式的的结果会比 Awstats 少了许多。

所以,Awstats 跟他们这是基于2种不同原理的统计方式,各有各好处只能互补,不能替换。

Google Analytics 是提供基于 javaScript  这种统计方式也的第三方机构,同类型的机构也有很多。有的还会在你网页的底部多出一个logo,叫你相当不爽。

要使用 Google Analytics 你并不能简单做一个注册,申请就ok,由于Google Analytics收到大量注册申请,目前对新注册用户数量仍有所限制。需要先进行申请,提交用户姓名和E-mail,进行排队。不过,这个时间似乎并不太长,据某位站长所说,等待时间大概为半个月。(对于我来说有点呛)  而且它还是第三方的统计系统,你不会知道它会拿你的浏量去干什么… 当然,如果是用于改善增加 google 对你的收录数,这是好事。(有这么好吗?)

然而,有了 Piwik ,只要你有一个支持 PHP+Mysql 的环境,你就不需要排队,不需要把事情寄托于第三方。

Piwik 的安装方式超级简单,(比装个Discuz还要简单) ,特别一点的可能就是它要求PHP配置有 mysql_pdo 。

windows环境可以直接在 php.ini 中打开,而Linux环境如果没有的话就需要重新编译php了。

然而这都不是什么问题的话,几分钟你就能把 Piwik 建立起来了。

在安装向导中,会提示让你输入统计站点的域名,然后生成一段 javaScript   的代码用于插入在统计站点网页的 

<body> </body>  里头。

最终配置完成后,你就能在 Piwik 中刷新看到实时的数据。

 

Piwik 的使用很傻瓜化,首页的布局你可以像弄自己的blog 那样随意拖动,或者添加栏目(小工具)。

添加小工具,意思是把常用的图表都直接在首页上列出来。

统计图表基于flash,有动态的现实效果,还能随意切换,列表,柱形,饼型。



也能通过导航栏更加细致地阅读图表。

数据一应俱全,称得上追赶 Google Analytics 并非扯谈。

Piwik 支持多国语言, 所以你们才能看到以上的截图是中文显示。但它的页面显示有几个缺点。

首先是首页能像 blog 一样修改布局的功能,对浏览器的兼容比较差。IE7,IE8 会出现拖动错误的情况。

而Firefox 则相安无事。再就是界面体表显示虽好,但字体无法修改大小,整体看上去页面相当粗糙。

所以!就出现了开发者建立桌面应用(调用Web Serves API)来可视化Piwik数据统计,Desktop Web Analytics 和 Piwik Connector

这2个东西是基于AdobeAIR的应用。所以使用之前要先把该平台装上。然后程序才能运行。你可以在Desktop Web Analytics 的首页上在线一次过自动配置好,也能单一自己下载。按照提示经过简单的API连接配置,就能在本地,无需浏览器,获取到 Piwik 的数据跟漂亮的图表。

更重要一点,AdobeAIR 是跨平台的,所以 Piwik 的“客户端”不管在 Windows,Linux,Mac 都能完美地运行。

怎样,强大吧?!

携程网App网络性能优化案例分析

在4月23日~25日举行的QCon全球软件开发大会(北京站)上,携程网无线开发总监陈浩然给大家分享了《移动开发网络性能优化实践》,总结携程网在App网络性能优化方面的一些实践案例经验。在2014年接手携程网无线App的框架和基础研发工作之后,陈浩然面对的首要工作就是App客户端性能优化,尤其是网络服务性能,这是所有App优化工作的重中之重。

首先介绍一下携程App的网络服务架构。由于携程业务众多,开发资源导致无法全部使用Native来实现业务逻辑,因此有相当一部分频道基于Hybrid实现。网络通讯属于基础&业务框架层中基础设施的一部分,为App提供统一的网络服务:

  • Native端的网络服务

Native模块是携程的核心业务模块(酒店、机票、火车票、攻略等),Native模块的网络服务主要通过TCP连接实现,而非常见的Restful HTTP API那种HTTP连接,只有少数轻量级服务使用HTTP接口作为补充。
    
TCP连接网络服务模块使用了长连接+短连接机制,即有一个长连接池保持一定数目长连接,用于减少每次服务额外的连接,服务完成后会将该连接Socket放回长连接池,继续保持连接状态(一段时间空闲后会被回收);短连接作为补充,每次服务完成后便会主动关闭连接。
    
TCP网络服务的Payload使用的是自定义的数据及序列化协议;HTTP服务的Payload比较简单,即常见的JSON数据格式。

  • Hybrid端的网络服务

Hybrid模块由于是在WebView中展示本地或者直连的H5页面,页面逻辑发起的网络服务都是通过系统WebView的HTTP请求实现的。少量业务场景(需要加密和支付等)以Hybrid桥接接口形式的Native TCP通道来完成网络服务。

下图是网络服务的部署架构图:

携程App所有网络服务,无论是TCP还是HTTP都会先连接到一个API
Gateway服务器。如果是TCP服务,会先连接上TCP Gateway,TCP
Gateway会负责将请求通过HTTP转发到后端的SOA服务接口。HTTP Gateway的原理与之类似。TCP Gateway和HTTP
Gateway的区别仅仅在客户端到服务端的连接方式不同而已。Gateway的作用除了业务请求还有流量控制和熔断。

要发现常见网络性能问题,先来看看一个网络服务做了哪些事情:

1.DNS Lookup

2.TCP Handshake

3.TLS Handshake

4.TCP/HTTP Request/Response

首先会是DNS解析,然后TCP连接握手,TLS连接握手(如果有的话),连接成功后再发送TCP或HTTP请求以及收
到响应。如果能够将这些过程逐一梳理并确保不会存在明显的性能问题,那么基本可以确保获得不错的网络性能。网络服务里有一个重要的性能标准,即
RTT(Round-Trip
Time),往返时延,它表示从发送端发送数据开始,到发送端收到来自接收端的确认(接收端收到数据后便立即发送确认)所间隔的时间。理想情况下可以假设
4G网络RTT为100ms,3G网络RTT为200ms,很容易就能计算出我们的App网络服务耗时的下限,当然还要加上服务器处理时间。

常见的网络性能问题有如下几种:

  • 问题一:DNS问题

DNS出问题的概率其实比大家感觉的要大,首先是DNS被劫持或者失效,2015年初业内比较知名的就有Apple内部
DNS问题导致App Store、iTunes
Connect账户无法登录;京东因为CDN域名付费问题导致服务停摆。携程在去年11月也遇到过DNS问题,主域名被国外服务商误列入黑名单,导致主站
和H5等所有站点无法访问,但是App客户端的Native服务都正常,原因后面介绍。

另一个常见问题就是DNS解析慢或者失败,例如国内中国运营商网络的DNS就很慢,一次DNS查询的耗时甚至都能赶上一次连接的耗时,尤其2G网络情况下,DNS解析失败是很常见的。因此如果直接使用DNS,对于首次网络服务请求耗时和整体服务成功率都有非常大的影响。

  • 问题二:TCP连接问题

DNS成功后拿到IP,便可以发起TCP连接。HTTP协议的网络层也是TCP连接,因此TCP连接的成功和耗时也成为
网络性能的一个因素。我们发现常见的问题有TCP端口被封(例如上海长宽对非HTTP常见端口80、8080、443的封锁),以及TCP连接超时时长问
题。端口被封,直接导致无法连接;连接超时时长过短,在低速网络上可能总是无法连接成果;连接超时过长,又有可能导致用户长时间等待,用户体验差。很多时
候尽快失败重新发起一次连接会很快,这也是移动网络带宽不稳定情况下的一个常见情况。

  • 问题三:Write/Read问题

DNS
Lookup和TCP连接成功后,就会开始发送Request,服务端处理后返回Response,如果是HTTP连接,业内大部分App是使用第三方
SDK或者系统提供的API来实现,那么只能设置些缓存策略和超时时间。iOS上的NSURLConnection超时时间在不同版本上还有不同的定义,
很多时候需要自己设置Timer来实现;如果是直接使用TCP连接实现网络服务,就要自己对读写超时时间负责,与网络连接超时时长参数类似,太小了在低速
网络很容易读写失败,太大了又可能影响用户体验,因此需要非常小心地处理。

我们还遇到另一类问题,某些酒店Wi-Fi对使用非80、8080和443等常见HTTP端口的服务进行了限制,即使发送Request是正常的,服务端能够正常收到,但是Response却被酒店网络proxy或防火墙拦截,客户端最终会等待读取超时。

移动网络和传统网络另一个很大的区别是Connection
Migration问题。定义一个Socket连接是四元组(客户端IP,客户端Port,服务端IP,服务端Port),当用户的网络在WIFI/4G
/3G/2G类型中切换时,其客户端IP会发生变化,如果此时正在进行网络服务通讯,那么Socket连接自身已经失效,最终也会导致网络服务失败。

  • 问题四:传输Payload过大

传的多就传的慢,如果没做过特别优化,传输Payload可能会比实际所需要的大很多,那么对于整体网络服务耗时影响非常大。

  • 问题五:复杂的国内外网络情况

国内运营商互联和海外访问国内带宽低传输慢的问题也令人难非常头疼。

看下携程App用户的网络类型分布:

 

Wi-Fi用户占比已超过60%,4G用户量正接近3G用户量,2G用户在逐步减少,用户的网络越来越好。4G/3G/2G网络的带宽和延迟差别很大,而带宽和延迟是网络性能的重要指标:

 

针对携程App用户的网络带宽和延迟,我们采样了海内外各8个城市的数据:

 

 

注意网络带宽和延迟并没有直接相关性,带宽高不意味着延迟低,延迟再低也不可能快过光速。从上图我们可以看到海内外带宽相差很大,但是延迟基本一致。

针对上面这些问题,在网络复杂环境和国内运营商互通状况无能为力的情况下,就针对性地逐一优化,以期达到目标:连得上、连得快、传输时间短。

  • 优化实践一:优化DNS解析和缓存

由于我们的App网络服务主要基于TCP连接,为了将DNS时间降至最低,我们内置了Server
IP列表,该列表可以在App启动服务中下发更新。App启动后的首次网络服务会从Server
IP列表中取一个IP地址进行TCP连接,同时DNS解析会并行进行,DNS成功后,会返回最适合用户网络的Server IP,那么这个Server
IP会被加入到Server IP列表中被优先使用。

Server IP列表是有权重机制的,DNS解析返回的IP很明显具有最高的权重,每次从Server
IP列表中取IP会取权重最高的IP。列表中IP权重也是动态更新的,根据连接或者服务的成功失败来动态调整,这样即使DNS解析失败,用户在使用一段时
间后也会选取到适合的Server IP。

  • 优化实践二:网络质量检测(根据网络质量来改变策略)

针对网络连接和读写操作的超时时间,我们提出了网络质量检测机制。目前做到的是根据用户是在2G/3G/4G/Wi-Fi的网络环境来设置不同的超时参数,以及网络服务的并发数量。2G/3G/4G网络环境对并发TCP连接的数量是有限制的(2G网络下运营商经常只能允许单个Host一个TCP连接),因此网络服务重要参数能够根据网络质量状况来动态设定对性能和体验都非常重要。 

不过目前携程App网络00质量检测的粒度还比较粗,我们正在做的优化就是能够测算到用户当前的网络RTT,根据RTT
值来设置参数,那会更加准确。Facebook App的做法是HTTP网络服务在HTTP
Response的Header中下发了预估的RTT值,客户端根据这个RTT值便能够设计不同的产品和服务策略。

  • 优化实践三:提供网络服务优先级和依赖机制

由于网络对并发TCP连接的限制,就需要能够控制不必要的网络服务数量,因此我们在通讯模块中加入了网络服务优先级和依
赖机制。发送一个网络服务,可以设置它的优先级,高优先级的服务优先使用长连接,
低优先级的就是用短连接。长连接由于是从长连接池中取到的TCP连接,因此节省了TCP连接时间。

网络服务依赖机制是指可以设置数个服务的依赖关系,即主从服务。假设一个App页面要发多个服务,主服务成功的情况下,才去发子服务,如果主服务失败了,自服务就无需再关心成功或者失败,会直接被取消。如果主服务成功了,那么子服务就会自动触发。

  • 优化实践四:提供网络服务重发机制

移动网络不稳定,如果一次网络服务失败,就立刻反馈给用户你失败了,体验并不友好。我们提供了网络服务重发机制,即当网
络服务在连接失败、写Request失败、读Response失败时自动重发服务;长连接失败时就用短连接来做重发补偿,短连接服务失败时当然还是用短连
接来补偿。这种机制增加了用户体验到的服务成功概率。

当然不是所有网络服务都可以重发,例如当下订单服务在读取Response失败时,就不能重发,因为下单请求可能已经到达服务器,此时重发服务可能会造成重复订单,所以我们添加了重发服务开关,业务段可以自行控制是否需要。

  • 优化实践五:减少数据传输量

我们优化了TCP服务Payload数据的格式和序列化/反序列化算法,从自定义格式转换到了Protocol
Buffer数据格式,效果非常明显。序列化/反序列算法也做了调整,如果大家使用JSON数据格式,选用一个高效的反序列化算法,针对真实业务数据进行
测试,收益明显。

图片格式优化在业界已有成熟的方案,例如Facebook使用的WebP图片格式,已经被国内众多App使用。

  • 优化实践六:优化海外网络性能

海外网络性能的优化手段主要是通过花钱,例如CDN加速,提高带宽,实现动静资源分离,对于App中的Hybrid模块优化效果非常明显。

经过上面的优化手段,携程App的网络性能从优化之初的V5.9版本到现在V6.4版本,服务成功率已经有了大幅提升,
核心服务成功率都在99%以上。注意这是客户端采集的服务成功率,即用户感知到的网络服务成功率,失败量中包含了客户端无网络和服务端的错误。网络服务平
均耗时下降了150-200ms。我们的目标是除2G网络外,核心业务的网络服务成功率都能够达到三个九。

数据格式优化的效果尤其明显,采用新的Protocol Buffer数据格式+Gzip压缩后的Payload大小降低了15%-45%。数据序列化耗时下降了80%-90%。

经历了这半年的网络性能优化,体会最深的就是Logging基础设施的重要性。如果我们没有完整端到端监控和统计的能
力,性能优化只能是盲人摸象。Logging基础设施需要包括客户端埋点采集、服务端T+0处理、后期分析、Portal展示、自动告警等多种功能,这也
不是单纯的客户端框架团队可以完成的,而需要公司多个部门合作完成。

携程基于Elastic Search开发了网络实时监控Portal,能够实时监控所有的网络服务,包括多种维度,可以跟踪到单个目标用户的所有网络请求信息。
用户的性能数据都被喷到Haddop和Hive大数据平台,我们可以轻松制定并分析网络性能KPI,例如服务成功率、服务耗时、连接成功率和连接耗时等,
我们做到了在时间、网络类型、城市、长短连接、服务号等多纬度的分析。下图是我们的网络性能KPI
Portal,可以查看任一服务的成功率,服务耗时、操作系统、版本等各种信息,对于某个服务的性能分析非常有用。

最后看看业界网络性能优化的新技术方向,目前最有潜力的是Google推出的SPDY和QUIC协议。

SPDY
成为HTTP/2.0
Draft,有希望成为未来HTTP协议的新标准。HTTP/2.0提供了很多诱人的特性(多路复用、请求优先级、支持服务端推送、压缩HTTP
Header、强制SSL传输、对服务端程序透明等)。国内很多App包括美团、淘宝、支付宝都已经在尝试使用SPDY协议,Twitter的性能测试表
明可以降低30%的网络延迟,携程也做了性能测试,由于和TCP性能差距不明显,暂未在生产上使用。

QUIC
基于UDP实现的新网络协议,由于TCP协议实现已经内置在操作系统和路由器内核中,Google无法直接改进TCP,因此基于无连接的UDP协议来设计
全新协议可以获得很多好处。首先能够大幅减少连接时间,QUIC可以在发送数据前只需要0 RTT时间,而传统TCP/TLS连接至少需要1-3
RTT时间才能完成连接(即使采用Fast-Open TCP或TLS Snapshot);其次可以解决TCP Head-of-Line
Blocking问题,通常前一个TCP
Packet发送成功前会拥塞后面的Packet发送,而QUIC可以避免这样的问题;QUIC也有更好的移动网络环境下拥塞控制算法;新的连接方式也大
幅减少了Connectiont Migration问题的影响。

随着这些新协议的逐渐成熟,相信未来能够进一步提高移动端的网络服务性能,值得大家保持关注。

NGINX下配置header CACHE-CONTROL max-age

HTTP协议的header Cache -Control指定请求和响应遵循的缓存机制。

在请求消息或响应消息中设置 Cache-Control并不会影响另一个消息处理过程中的缓存处理过程。

请求时的缓存指令包括no-cache、no-store、max-age、 max-stale、min-fresh、only-if-cached等。

响应消息中的指令包括public、private、no-cache、no- store、no-transform、must-revalidate、proxy-revalidate、max-age。



Nginx的ngx_http_headers_module模块可以对Cache-Control头相关的东西进行配置

例如:

1    # 相关页面设置Cache-Control头信息,dns及cdn目录配置10天

2     

3    if ($request_uri ~* “^/$|^/dns/.+/|^/cdn/.+/”) {

4      add_header    Cache-Control  max-age=864000;

5    }

6     

7    if ($request_uri ~* “^/linux/|^/t/”) {

8      add_header    Cache-Control  max-age=86400;

9    }



max-age意思是:客户端本地的缓存,在配置的生存时间内的,客户端可以直接使用,超出生存时间的,需要到服务器上取新数据。当然这些还要看客户端浏览器的设置。

PHP fastcgi TCP(127.0.0.1:9000)和unix domain socket方式性能对比

Nginx连接fastcgi的方式有2种:TCP和unix domain socket 

什么是Unix domain socket?

Unix domain socket 或者 IPC socket是一种终端,可以使同一台操作系统上的两个或多个进程进行数据通信。与管道相比,Unix domain sockets 既可以使用字节流,又可以使用数据队列,而管道通信则只能使用字节流。Unix domain sockets的接口和Internet socket很像,但它不使用网络底层协议来通信。Unix domain socket 的功能是POSIX操作系统里的一种组件。

Unix domain sockets 使用系统文件的地址来作为自己的身份。它可以被系统进程引用。所以两个进程可以同时打开一个Unix domain sockets来进行通信。不过这种通信方式是发生在系统内核里而不会在网络里传播。

下面php fastcgi使用TCP和unix domain socket方式对比

TCP是使用TCP端口连接127.0.0.1:9000

Socket是使用unix domain socket连接套接字/dev/shm/php-cgi.sock(很多教程使用路径/tmp,而路径/dev/shm是个tmpfs,速度比磁盘快得多

测试机是个1核的centos6.4,2用户并发时系统资源消耗50%左右,10用户资源就跑得很满了。

2users 10users
nginx/1.2.9 + PHP 5.2.5 tcp 1060 1294
nginx/1.2.9 + PHP 5.2.5 socket 997 1487
nginx/1.2.9 + PHP 5.3.10 tcp 906 1082
nginx/1.2.9 + PHP 5.3.10 socket 880 1247

结论是在服务器压力不大的情况下,tcp和socket差别不大,但在压力比较满的时候,用套接字方式,效果确实比较好。

因为:对于进程间通讯的两个程序,unix domain socket的流程不会走到TCP 那层,直接以文件形式,以stream socket通讯。如果是TCP socket,则需要走到IP层。对于非同一台服务器上,TCP socket走的就更多了。

下面是php 5.3以上版本将TCP改成socket方式的配置方法:

修改php-fpm.conf(/usr/local/php/etc/php-fpm.conf)

;listen = 127.0.0.1:9000 listen = /dev/shm/php-cgi.sock

修改nginx配置文件server段的配置,将http的方式改为socket方式

 location ~ .*\.(php|php5)?$ { #fastcgi_pass  127.0.0.1:9000; fastcgi_pass   unix:/dev/shm/php-cgi.sock; fastcgi_index index.php; include fastcgi.conf; }

重启php-fpm与nginx

service nginx restart
service php-fpm restart
ls -al /dev/shm

可以看到php-cgi.sock文件unix套接字类型

HTTP响应拆分漏洞 WASC Threat Classification解决方案

HTTP响应拆分漏洞描述:
HTTP响应拆分漏洞,也叫CRLF注入攻击。CR、LF分别对应回车、换行字符。
HTTP响应拆分漏洞危害:攻击者可能注入自定义HTTP头。例如,攻击者可以注入会话cookie或HTML代码。这可能会进行类似的XSS(跨站点脚本)或会话固定漏洞。
HTTP响应拆分漏洞解决方案:
HTTP响应拆分漏洞修复的基本思路:
限制用户输入的CR和LF,或者对CR和LF字符正确编码后再输出,以防止注入自定义HTTP头。
HTTP响应拆分漏洞-PHP语言的解决方案:
这种现象往往表现在带有参数传递的网页,只要合理的过滤好就OK啦,PHP语言的一些过滤方法:
$uuid = trim($uuid);
$uuid = strip_tags($uuid,””); //清除HTML等代码
$uuid = ereg_replace(“\t”,””,$uuid); //去掉制表符号
$uuid = ereg_replace(“\r\n”,””,$uuid); //去掉回车换行符号
$uuid = ereg_replace(“\r”,””,$uuid); //去掉回车
$uuid = ereg_replace(“\n”,””,$uuid); //去掉换行
$uuid = ereg_replace(” “,””,$uuid); //去掉空格
$uuid = ereg_replace(“‘”,””,$uuid); //去掉单引号

Linux 免重新编译php安装扩展(示范zip安装)

PHPExcel读取Excel表格的时候报ZipArchive library is not enabled错误. 缺少zip 模块. 在Linux下没有zip.so这个模块文件(有也不会起作用的),所以需要重新编译一下php的增加zip模块。

1)重新到原来编译php的目录

#cd php-5.3.6/ext/zip

先执行phpize

# /usr/local/php/bin/phpize

返回:Configuring for:
PHP Api Version:         20090626
Zend Module Api No:      20090626
Zend Extension Api No:   220090626

2)运行了这个zip目录下会自动生成几个文件,其中包括configure

  1. #./configure  –enable-zip –with-php-config=/usr/local/php/bin/php-config 
  2. # make
  3. # make install

3)安装完成后修改一下php.ini

  1. # vim /usr/local/php/etc/php.ini

加入

  1. extension=/usr/local/php/lib/php/extensions/no-debug-non-zts-20060613/zip.so   (路径可能不太一样,参考make install 返回路径)
  2. 然后同样在php.ini文件中,将 zlib.output_compression = Off 改为 zlib.output_compression = On .

之后重启/etc/init.d/httpd restart

网站速度页面加载速度影响转化率

2010年还是8秒原则,现在已经进入3秒原则了。我们一直很重视网站性能优化,在人才培养和招聘的时候也都非常重视,但性能优化到底为什么这么重要?对电商网站来说,性能优化对转化率的影响是实实在在的,也是非常有说服力的,这是国外同行webperformancetoday的研究成果,简单翻译一下分享给大家。
当然,网站性能优化带来的好处不止转化率这一点,对基础用户体验、运营成本控制等都有很重要的影响,这些我们后面再说。
直接看图表吧:

字体:        | 上一篇 下一篇 | 打印  | 我要投稿