我们做了一款智能血压计,通过蓝牙连接手机APP。
用户测量血压后,数据会通过蓝牙同步到手机,APP展示结果,同时上传到云端。但用户反馈,测量后数据同步慢,APP响应卡顿,有时候要等好几秒才能看到结果。
我负责了这次性能调优,花了两周时间,把平均响应时间从2秒降到了400毫秒,降了80%。本文分享完整的调优过程。
一、产品背景
先说说这款血压计的背景。
1. 产品介绍
这是一款家用智能血压计,主要功能:
- 测量收缩压、舒张压、心率
- 通过蓝牙BLE连接手机APP
- 测量数据同步到APP
- APP展示历史数据、趋势图表
- 数据上传到云端,多设备同步
- 异常数据提醒
2. 技术架构
- 设备端:嵌入式C,蓝牙BLE 5.0
- 手机端:iOS(Swift)和Android(Kotlin)
- 云端:Java + Spring Boot,MySQL
- 通信协议:自定义蓝牙协议 + HTTPS
3. 性能问题
用户反馈的主要问题:
- 测量完成后,APP要等2-3秒才显示结果
- 历史数据加载慢,尤其是数据多的时候
- 趋势图表渲染卡顿
- 云端同步慢,有时候同步失败
- 蓝牙连接不稳定,经常断连
二、性能分析
优化之前,先做全面的性能分析,找到瓶颈。
1. 拆解响应时间
我把从测量完成到APP显示结果的整个过程拆解了一下:
- 设备测量完成,发送数据(约200ms)
- 蓝牙数据传输(约500ms)
- APP接收和解析数据(约300ms)
- APP计算和校验(约200ms)
- APPUI渲染(约400ms)
- 云端同步(约400ms,异步)
总时间:约2秒(云端同步异步,不影响主流程,但UI渲染和数据处理是瓶颈)
2. 各环节分析
- 蓝牙传输:500ms,偏慢。正常BLE传输应该在200ms以内
- 数据解析:300ms,偏慢。数据量不大,不应该这么慢
- UI渲染:400ms,偏慢。只是显示几个数字,不应该这么慢
- 历史数据加载:测试了一下,加载100条数据要2秒,太慢了
- 图表渲染:渲染30天的趋势图要1.5秒,卡顿明显
三、优化过程
针对这些瓶颈,分步进行优化。
第一阶段:蓝牙通信优化
1. 问题:蓝牙传输慢
分析发现,蓝牙传输慢的原因:
- 每次只传20字节(BLE默认MTU),一个数据包要分多次传
- 传输间隔设置得太大(50ms)
- 没有用数据压缩,原始数据直接传
- 每次传输都要等待ACK,串行传输
2. 优化方案
- 协商更大的MTU:从默认的23字节(有效载荷20字节),协商到247字节(有效载荷244字节)。这样一次就能传更多数据,减少传输次数。
- 减小传输间隔:从50ms减小到15ms,提高传输频率。
- 数据压缩:用简单的压缩算法(如RLE或自定义压缩),减少数据量。血压数据有很多重复的0,压缩效果很好。
- 批量传输:把多个测量数据打包一起传,减少传输次数。
3. 效果
蓝牙传输时间从500ms降到了150ms,提升了70%。
第二阶段:数据解析优化
1. 问题:数据解析慢
分析发现,数据解析慢的原因:
- 解析逻辑写得很复杂,有很多嵌套的if-else
- 每次解析都创建大量临时对象,导致GC频繁
- 没有用缓存,相同的数据重复解析
- 解析和校验混在一起,逻辑混乱
2. 优化方案
- 重构解析逻辑:用状态机代替嵌套if-else,解析更清晰,也更快。
- 对象复用:用对象池复用数据对象,减少GC。
- 解析结果缓存:相同的数据包,解析结果缓存起来,避免重复解析。
- 分离解析和校验:先解析,再异步校验,不阻塞主流程。
3. 效果
数据解析时间从300ms降到了80ms,提升了73%。
第三阶段:UI渲染优化
1. 问题:UI渲染慢
分析发现,UI渲染慢的原因:
- 结果页面有很多控件,布局嵌套深
- 每次更新数据,都重新渲染整个页面
- 数字用了自定义控件,绘制复杂
- 没有用硬件加速
2. 优化方案
- 简化布局:减少布局嵌套,用ConstraintLayout(Android)或Auto Layout(iOS)优化布局。
- 局部更新:只更新变化的控件,不重新渲染整个页面。
- 优化自定义控件:简化绘制逻辑,减少不必要的绘制操作。用缓存(bitmap缓存)避免重复绘制。
- 开启硬件加速:确保UI渲染使用硬件加速。
- 异步加载:历史数据和图表异步加载,不阻塞主界面。
3. 效果
UI渲染时间从400ms降到了120ms,提升了70%。
第四阶段:历史数据加载优化
1. 问题:历史数据加载慢
分析发现,历史数据加载慢的原因:
- 一次性加载所有数据,数据量大
- 数据库查询没有索引
- 数据转换慢,从数据库对象到UI对象的转换效率低
- 没有分页,一次加载全部
2. 优化方案
- 分页加载:每次只加载20条,滚动到底部再加载下一页。
- 数据库索引:给常用的查询字段(时间、用户ID)加索引。
- 数据转换优化:用更高效的方式转换数据,避免反射。
- 本地缓存:最近的数据缓存在内存中,不用每次都查数据库。
- 预加载:在用户看当前页的时候,预加载下一页数据。
3. 效果
历史数据加载时间从2秒降到了300ms,提升了85%。
第五阶段:图表渲染优化
1. 问题:图表渲染卡顿
分析发现,图表渲染卡顿的原因:
- 用了第三方图表库,功能强大但性能一般
- 每次渲染都重新计算所有数据点
- 没有用硬件加速
- 数据点太多,30天的数据有上千个点
2. 优化方案
- 数据降采样:显示30天数据时,不需要显示每个数据点,按天聚合(每天的平均值、最大值、最小值),数据点从上千个降到30个。
- 缓存绘制结果:图表绘制结果缓存为bitmap,数据不变时直接显示缓存。
- 用更轻量的图表库:或者自己实现简单的图表,性能更好。
- 硬件加速:确保图表绘制使用硬件加速。
- 懒加载:先显示概览图,用户放大后再加载详细数据。
3. 效果
图表渲染时间从1.5秒降到了200ms,提升了87%。
第六阶段:云端同步优化
1. 问题:云端同步慢
分析发现,云端同步慢的原因:
- 每次同步都建立新的HTTPS连接,握手开销大
- 数据格式用XML,体积大,解析慢
- 同步策略不合理,每次都全量同步
- 没有重试机制,网络不好时同步失败
2. 优化方案
- 连接复用:用连接池复用HTTPS连接,减少握手开销。
- 改用JSON:JSON比XML体积小,解析快。或者用Protobuf,体积更小,解析更快。
- 增量同步:只同步上次同步之后的新数据,不全量同步。
- 批量同步:多条数据打包一起同步,减少请求次数。
- 重试机制:同步失败时自动重试,指数退避。
- 离线优先:数据先存本地,后台异步同步,不阻塞用户操作。
3. 效果
云端同步时间从400ms降到了100ms(单条数据),同步成功率从95%提升到99.9%。
四、优化效果
说说优化后的整体效果。
1. 响应时间
- 测量结果显示:从2000ms降到400ms,降低80%
- 历史数据加载:从2000ms降到300ms,降低85%
- 图表渲染:从1500ms降到200ms,降低87%
- 云端同步:从400ms降到100ms,降低75%
2. 用户体验
- 用户反馈明显改善,不再抱怨慢
- APP Store和应用商店的评分提升了
- 用户留存率提高了
- 客服关于性能的投诉减少了80%
3. 系统稳定性
- 蓝牙断连率降低了60%
- 云端同步失败率降低了90%
- APP崩溃率降低了50%
五、踩过的坑
说说优化过程中踩过的坑。
坑一:MTU协商失败
协商更大的MTU时,有些老旧设备不支持,协商失败后蓝牙连接断开。
解决:
- 协商MTU时加超时处理
- 协商失败后回退到默认MTU
- 对不同设备做兼容性测试
教训: 蓝牙兼容性很重要,不能假设所有设备都支持新特性。
坑二:数据压缩导致兼容性问题
引入数据压缩后,旧版本的APP不支持压缩格式,解析失败。
解决:
- 在协议中加版本号和压缩标志
- 旧版本APP不支持压缩时,设备端用未压缩格式
- 灰度发布,逐步推广
教训: 协议变更要考虑向后兼容。
坑三:分页加载导致数据不一致
分页加载时,如果用户在加载过程中新增了数据,可能导致数据重复或遗漏。
解决:
- 用游标分页(基于时间戳或ID),不用偏移量分页
- 加载时锁定数据范围
- 数据变更时,刷新当前页
教训: 分页加载要考虑数据动态变化的情况。
坑四:图表降采样导致信息丢失
数据降采样后,图表显示的是平均值,但用户可能想看到异常值(如血压突然升高)。
解决:
- 降采样时保留最大值和最小值
- 概览图显示平均值,放大后显示原始数据
- 异常值用特殊标记突出显示
教训: 性能优化不能以牺牲用户体验为代价。
坑五:异步同步导致数据冲突
离线优先,数据先存本地,后台异步同步。但如果多设备同时修改同一条数据,会产生冲突。
解决:
- 用最后写入胜出(Last Write Wins)策略
- 或者用版本号冲突检测,冲突时让用户选择
- 重要数据用服务端时间戳为准
教训: 分布式系统的数据一致性是个难题,要设计好冲突处理策略。
六、物联网设备性能调优的一般思路
总结一下物联网设备性能调优的一般思路:
1. 先测量,再优化
不要盲目优化,先用工具测量,找到瓶颈。
- 蓝牙抓包工具:分析蓝牙通信
- 性能分析工具:Android Profiler、Xcode Instruments
- 日志埋点:记录每个环节的耗时
- 云端APM:分析服务端性能
2. 端到端分析
物联网应用的性能问题,可能出在设备端、通信、手机端、云端任何一个环节。要端到端分析,找到真正的瓶颈。
3. 优先优化用户感知的环节
用户能感知到的延迟,优先优化。比如测量结果显示、历史数据加载。后台同步等用户感知不到的,可以后优化。
4. 离线优先
物联网设备经常网络不好,要设计成离线优先:
- 数据先存本地
- 后台异步同步
- 不阻塞用户操作
- 同步失败自动重试
5. 兼容性很重要
物联网设备的兼容性很重要:
- 不同手机型号的蓝牙兼容性
- 不同系统版本的兼容性
- 新旧版本APP的兼容性
- 不同网络环境的兼容性
七、写在最后
这次血压计的性能调优,把响应时间降了80%,用户体验明显改善。
物联网应用的性能调优,和纯互联网应用不太一样。它涉及设备端、通信、手机端、云端多个环节,任何一个环节出问题,都会影响整体体验。需要端到端分析,找到真正的瓶颈,针对性优化。
2022年了,物联网设备越来越普及,智能手表、智能血压计、智能家居……用户对物联网设备的体验要求也越来越高。作为开发者,我们要关注性能,关注体验,让物联网设备真正好用。
最后,用一句话总结:"物联网性能调优,端到端分析,找到瓶颈,针对性优化。优先优化用户感知的环节,同时注意兼容性和离线体验。"
愿你的物联网设备,又快又稳。
评论(0)
暂无评论,快来抢沙发~
评论功能仅对会员开放,请先登录
登录