我们做了一款智能血压计,通过蓝牙连接手机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显示结果的整个过程拆解了一下:

  1. 设备测量完成,发送数据(约200ms)
  2. 蓝牙数据传输(约500ms)
  3. APP接收和解析数据(约300ms)
  4. APP计算和校验(约200ms)
  5. APPUI渲染(约400ms)
  6. 云端同步(约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年了,物联网设备越来越普及,智能手表、智能血压计、智能家居……用户对物联网设备的体验要求也越来越高。作为开发者,我们要关注性能,关注体验,让物联网设备真正好用。

最后,用一句话总结:"物联网性能调优,端到端分析,找到瓶颈,针对性优化。优先优化用户感知的环节,同时注意兼容性和离线体验。"

愿你的物联网设备,又快又稳。