07.20 - 性能
TCP
TTL(time to live):记录通过路由器的次数。
TCP Sync Flood:
利用TCP栈收到SYN包后的超时等待时间,大量发送SYN包到服务端,最终导致无法响应其他正常网络包
- tcp_syncookies:根据源地址端口、目标地址端口和时间戳计算出seq
- tcp_synack_retries:减少重试次数
- tcp_max_syn_backlog:增大SYN连接数
- tcp_abort_on_overflow:超过流量时拒绝连接
SACK(Selective Acks)
TCP Header中使用Sack标识当前收到的数据包范围,服务器如果恶意发送Sack,会消耗发送包性能,恶意共计。
TCP性能优化
服务端:
- 增加TCP初始拥塞窗口cwnd值=10
- 禁用空闲状态后的Slow Start Restart机制(cwd: tcp_slow_start_after_idle)
- Enable Window Scaling配置以增加吞吐量(64K->1GB)
- Enable TCP Fast Open 3次握手->2次
客户端:
- 减少数据传输量
- 务必进行数据压缩
- 尽量使用最近的服务端(减少路由)
- 尽可能重用TCP连接
HTTP
基于TCP的应用层协议。
响应码
- 1xx:指示信息--表示请求已接收,继续处理
- 2xx:成功--表示请求已被成功接收、理解、接受
- 3xx:重定向--要完成请求必须进行更进一步的操作
- 4xx:客户端错误--请求有语法错误或请求无法实现
- 5xx:服务器端错误--服务器未能实现合法的请求
KeepAlive:
推荐一个浏览器针对一个域名最多创建两个链路,状态由HTTP Header控制。
- 客户端不需要再发送请求时要发送Connection: Close关闭连接
- 客户端必须确保HTTP请求正确,例如Content-Length长度正确、Encoding正确
- HTTP 1.1或者1.0版本的Proxy能够正确处理连接保持
- 如果没有side effect,HTTP 1.1客户端可以重试请求
- 客户端需要控制并发连接数
Pipeline: 持续向服务器并行发送多次请求。
Multipart
- 上传文件的一种方式
- 单个消息主题内包装一个或多个实体
- 各个实体所使用boundary做分割
- 可同事携带二进制、纯文本实体
Http性能优化思路
- TCP连接三次握手导致的延迟
- TCP慢启动拥塞控制机制
- Nagle算法(TCP_NODELAY可关闭)
- TCP ACK延迟的影响
- TIME_WAIT可能导致端口耗尽
Http性能优化
- 使用keeplive重用连接
- 使用Chunked transfer encoding
- 使用Pipeline特性实现
- 跨range获取资源
- 缓存
- 减少DNS lookup(尽量使用ip)
- 减少Http请求数
使用图片Sprite技术、JavaScript/CSS文件合并、资源inline化
- 使用CDN
- Gzip压缩文本内容
- 避免Http重定向
App性能优化
移动网络性能:
- 设备空闲时重新激活网络延迟会非常差
- 避免周期性和不必要的数据传输
- App切换到后台后避免保持长连接
- 考虑离线情况
- 尽可能本地缓存数据
- 在弱网络下测试实际性能
信令风暴 频繁小流量数据交互大量消耗信令信道资源,引发雪崩
- 单次传输的数据量较小
- 接入和释放频次较高
- 在线时间长但传送数据的时间很短
- 上下行传输的数据量较为对称
工具
网络分析工具:Surge/Repilica
Http分析工具:Charles(Mac)/Fiddler(Win)
终极网络分析工具: Wireshark
网络性能监控(76)
网络性能监控维度
- 网络服务成功率
- 平均耗时
- 耗时分布
用户数据分析:
- 网络服务错误类型分布
- 请求和响应报文大小
- 网络服务过程细分
- 网络错误
- Trace 日志
App端Logging基础设施提供端到端监控
- 客户端埋点采集实时上传
- 服务端T+0处理
- Portal展示 (实时/小时级)
- 自动告警 (分钟级)
- Trace日志后期分析
移动网络优化案例:
- 基于TCP原生Socket实现网络服务
业界有大众点评、QQ空间以及IM类(微信/QQ等)
- TCP长短连接结合:长连接为主,短连接为辅
- 设计目标:提高网络连通性和服务成功率,减少连接时间和传输数据大小
优化DNS
- 内置Server IP列表,彻底消除DNS问题影响
- Server IP权重机制,根据网络状态选择服务IP
- IP权重根据网络服务结果和端到端延迟调整IP权重
- 备选DNS解析
- 可选:HTTP-DNS可解决DNS劫持问题
网络质量监控
- 使用App端到服务端的 Ping 值作为 RTT 时间计算因子
- TCP连接、发送和接收数据的超时时长
- 网络服务并发数量
TCP连接优化
- 优先使用长连接,长连接池已满时使用短连接
- 动态参数调整:长连接池个数和连接超时时间
- 自动重试不同端口 (80、8080、443…)
- App启动时预热移动网络
启动时加载webview、调一个http请求
弱网和网络抖动
- 减少长连接池数量为1
- 增加网络连接和服务超时时长
- 可选:尝试QUIC协议 (基于UDP),面向弱网有优势
网络抖动下策略调整
WIFI和移动网络类型互相切换时,会导致App客户端IP变化,自动关闭空闲长连接,现有网络服务自动重试
减少数据传输
- 优化TCP服务数据格式
自定义格式转到Protocol Buffer格式
- 优化TCP服务数据序列化反序列化算法(Protocol Buffer)
- 优化图片格式 (WebP,Android 4.0以上支持)
Networking Tricks
- iOS App中原生Socket不能直接唤醒移动网络
- 确保连接被保持住:SO_KEEPALIVE参数
- 处理SIGPIPE或者关闭:SO_NOSIGPIPE参数
- 关闭Nagle算法影响:TCP_NODELAY参数
Hybrid网络服务优化
未使用HTTP Hook技术,目前采用Hybrid接口转发,未来计划采用iOS Network Extension实现
客户端的TCP通信是借助native完成的
HTTP请求通过TCP Gateway中转至H5 Gateway(97)
- 平均网络服务成功率可提升至 99.2%+,服务耗时降低 30%
安全方案:HTTPS迁移问题
- 安全性上升,防劫持效果明显
- 加载时间明显升高,携程AB测试下增加40%+
- 携程Workaround:
Hybrid框架检测网页内容,如果发现内容劫持,自动使用HTTPS重刷页面
QZone App Hybrid
- 启用HTTPS+SPDY协议支持
- 提升TCP连接的复用率:页面入口发起一个HTTPS请求 (空内容),减少连接时间,预请求复用的命中率75%左右
- 提升SSL session的复用率:服务端支持session ticket和session cache,命中率40%左右
- 减少页面中请求域名的数量:域名收敛,减少DNS解析时长
React Native
推荐辅助工具:
- watchMan
- Flow
IDE:
- Nuclide
- Sublime
- Visual Studio Code
ES6
ES6 相对 ES5 的重要改进:
- 新增 let 与 const 命令
- 变量的解构(Destructuring)
- 扩展运算(...)
- Class
- 箭头函数
- Promise 对象
React
虚拟DOM:根据 React 的设计,所有的 DOM 变动,都 先在虚拟 DOM 上发生,然后再将实际发生变动的部分,反映在真 实 DOM上,这种算法叫做 DOM diff ,它可以极大提高网页的性能 表现。
flexbox 布局
常用API
- AppRegistry
- Platform
- Alert
- AsyncStorage(文件形式,可替换)
- CameraRoll
常用组件
- Text
- TextInput
- Touchable 类组件
- Image
- WebView
- ListView (SGListview)
组件的生命周期
导航栏
- Navigator(推荐) & NavigatorIOS
- NavigationBar
网络请求
- Fetch(官方推荐)
- XMLHttpRequest
- WebSocket
通讯机制
- Native 调 JS:
有现成的接口,类似 webview 提供的 ‒ stringByEvaluatingJavaScriptFromString 方法可以直接在当 前 context 上执行一段JS脚本; 并且可以获取执行后的返回值,这个返回值就相当于 JS 向 Native 传递信息。
- JS 调 Native:
JS 并不能主动调到 Native 层,所以 JS 对 Native 的调用是先 存到一个 Queue 里面,Native 调 JS 时才会把 Queue 里的方 法返回给 Native 层去执行。
RN性能分析
Question
React Native开发方式?跨平台?
需要有团队专门做中间件。
UI渲染限制比较大。
适用于哪些项目
适用于大型互联网项目,或者尝试使用下新技术。
网络访问,用native还是ajax?
重构的可能?
监控信息时机?
Hybrid框架设计
职责划分
- 交互性强的页面使用Native;
- 核心业务流程使用Native;
- 硬件交互频繁的用Native;
- 其他都可以使用Hybrid开发
Android Native&Javascript通讯原理(8)
callback机制
Bridge.js通过sequenceId完成函数的中间转换
使用Base64Encode替换UrlEncode
BusinessJob(37)
开发方式
- 代码结构: React Native更为合理,组件化程度高
- UI布局:Web布局灵活度 > React Native > Native
- UI截面图:React Native使用的是原生组件,
- 路由/Navigation:React Native & Native更胜一筹
- 第三方生态链:Native modules + js modules = React Native modules
性能 & 体验
- 内存:Native最少;因为React Native含有框架,所以相对较高,但是后期平稳后会优于Native。
- CPU:React Native居中。
- 动画:React Native动画需求基本满足。
- 安装包体积:React Native框架打包后,811KB。相比热更新,可以忽略和考虑资源规划。
- Big ListView
- 真机体验:Native >= React Native > H5/Hybrid
更新 & 维护
- 更新能力: H5/Hybird > React Native > Native
- 维护成本: H5/Hybird <= React Native < Native
- Native的原生控件有更好的体验;
- Native有更好的手势识别;
- Native有更合适的线程模型,尽管Web Worker可以解决一部分问题,但如图像解码、文本渲染仍无法多线程渲染,这影响了Web的流畅性。 ——Occhino
框架设计
MVVM
- Model 只负责原始数据模型定义
- ViewModel 负责UI组件的业务逻辑和展示数据管理
- View 负责UI渲染
工程解耦
- 资源放置在各个工程,在打包时进行抽取合并。
- Bus只作为一个通道,继续需要分别提供BusObject进行注册。
- Bundle化,iOS为.a+bundle android基于aar。
减少AppSize:
编译选型
- 打包选择cpu架构 只选择armv7+arm64(必须),armv7 用于兼容老设备
- Strip style设置,不要将符号表打进Release包的exe 子工程deploy target version调整,7.0vs6.0的xib优化
图片
- png也需要压缩
- jpg质量建议0.8
- 使用svg矢量图替换存色图片(iOS,svg‒>font),成本偏高
代码
- 减少冗余代码
- 部分业务转用H5 Hybrid或者React Native
- Tips: 如果有使用Marsony这个框架,将头文件中的 category实现放到单独.m文件
xib的使用?
日志系统
- 成熟App必备组件,用户数据分析依赖于此
- 用户行为日志
- 性能数据日志
- 自动埋点日志
- trace/metrics (number value)
- 独立日志系统,和App服务分开
- 日志记录SDK
日志维度:trace/metrics
ABTest
随机的选取一定比例的用户,访问不同的实验内容,根据转化率比 例判断哪个实验更好。
Crash
- crash是在App使用过程中非正常终止
- 不同于web开发,在App上是一种正常表现
- crash数据需要监控,收集
- 推荐使用腾讯bugly,免费,功能强大,反馈问题响应及时
故障率=crash次数/app打开次数,业界平均0.8%以内
hotfix
iOS:jspatch
Android:https://github.com/dodola/RocooFix
hotfix发布
shotfix脚本传输过程中需要加密 hotfix脚本需要签名,加载时,需要校验签名 jspatch替换正在执行的函数会导致偶发crash
测试
UI自动化测试
- case维护成本偏高
- 自动化做回归测试比较合适
- 不建议小团队做UI自动化测试
单元测试
- 核心代码需要单元测试,提升稳定性
专项测试
- 耗电、流量、启动时间、稳定性
- 可以和monkey测试同步进行
发布
所有的发布需要可回滚
灰度发布:版本号要与数字版本区分开。
- Android选择部分渠道、部分用户灰度升级
- 后台关注升级上来的用户转化率、crash率等
- iOS灰度发布效果不佳,testflight不好用,可以考虑部分 越狱渠道灰度发布
渠道包&动态打包
- 只支持Android,iOS需要重新打包
- apk包的/meta/inf/目录可以存放渠道文件,修改/添加时 APK包签名不变
灰度发布 display version、数字版本;
定制版本管理
独立git分支,不进主版本