写点什么

苏宁 11.11:苏宁物流移动端百万级离线数据处理方案

  • 2018-11-09
  • 本文字数:2950 字

    阅读完需:约 10 分钟

苏宁11.11:苏宁物流移动端百万级离线数据处理方案

本文为“InfoQ x 苏宁 2018 双十一”特别策划系列文章之一。

背景

随着苏宁物流的发展,对网点的整合,很好的强化了苏宁物流最后一公里配送能力,可以在相对短期内整合双方在仓储、干线、末端等方面的快递网络资源,编织一张覆盖最后一公里的密织高效网络,整合完成将极大地强化苏宁物流最后一公里配送能力,提高配送效率,降低运营成本。


其中物流移动端在仓储,干线和末端等各个环节都扮演一个非常重要的角色,然而移动端的用户和我们一般的移动互联网用户有相同的地方也有很大区别,首先物流移动端的用户基本上是我们处在一线的操作人员,界面的交互和服务的响应速度直接影响用户的作业速度。另外移动互联网用户一般是手机,而物流移动端的用户包括手机和手持码枪,这就对我们移动应用提出了更高的要求,不仅仅要具有手机的灵活性还要有手持的实用性。最后随着 3G,4G 的普及移动互联网用户手机联网性普通很好,但是我们的一线作业人员可能处在仓库的角落,信号的盲区,这就要求我们的应用不仅要在有信号的情况下可以作业,在无信号的状态下也可以正常作业。


为了实现各大区网点不能满足实时的网络交互环境的情况下正常作业,这就要求我们操作终端多向前走一步,同时能满足各网点无论在网络环境好坏的情况下都能完成作业。如果满足这些条件就需要本来在服务端处理的数据下载到码枪,在码枪本地本地进行校验处理,服务器的主数据量在都在万级以上,最大的一张表数据在百万级,而正常作业下我们用的码枪都是安卓系统,运行内存在 2G,4G,有的码枪甚至处理内存在 1G。如果通过对码枪的更新换代可以更换性能更好的码枪,但是这种成本是巨大的 ,所以通过对技术上的实现去节省成本和增加用户体验是我们苏宁物流要首当其冲面对的问题。

我们的解决方案

一、数据处理实际逻辑

  1. 通过网络下载 txt 文件

  2. 按行读取每行字符串文本

  3. 采用 String.split 函数按照指定的格式分割字符串为字符数组

  4. 通过字符数组组装 Entity 数据类,讲数据类添加到 List 里缓存

  5. 判断 List 的 Size 大小,达到 3000 条后调用 Greendao 方法启动线程开启事务批量插入,清空 List 继续循环

  6. 未达 3000 条继续循环走 2 流程



图 1、数据处理逻辑流程

二、性能瓶颈分析

使用 TraceView 找到性能的瓶颈,TraceView 是 Android SDK 中内置的一个工具,它可以加载 trace 文件,用图形的形式展示代码的执行时间、次数及调用栈。


生成 trace 文件有三种方法:


  • 使用代码

  • 使用 Android Studio

  • 使用 DDMS



图 2、开始 trace



图 3、写入到 trace 文件



图 4、执行耗时分析



图 5、函数耗时分析


通过 TraceView 分析,另外结合代码分析总结出几个性能瓶颈


  1. String .split 采用正则匹配,大数据量效率低

  2. 读文件比较耗时,如果数据库速度大于文件读取速度,则会等待文件读取

  3. 插入数据库也比较耗时,如果插入速度小于文件读取速度,则文件读取会阻塞等待

  4. 每次使用 GreenDao 开启线程,没有限制最大线程数,开启大量线程,导致数据库连接数超出上限,极易 OOM

  5. 另外,通过代码日志分析得出,Entity 没有重用,每次循环创建新的 Entity,导致内存不足,频繁耗时 GC,界面卡顿。

三、解决方案:

  1. 针对 Spilt 的优化:重写了 String.split 的实现方式,采用效率更高的 index 方式代替原来的正则匹配,依据业务特点固定了分割数目

  2. 针对对象没有重用的优化:采用动态事务,在事务中采用单条连续插入数据库,操作避免创建多余对象,达到指定数量后一起 Commit 到数据库

  3. 单次提交数量优化:经过多次测试,统计出单次提交 12000 条为效率最高的提交量

  4. 针对相互等待问题:采用阻塞队列,对象池方式减少等待


具体流程图如下:



图 6、优化流程图

四、结果对比:

通过测试的对比可以发现,同样的数据,合理匹配文件的读写速度和数据库的读写速度,减少等待间隔。


  • 在单次 8000 量的时候 ,速度可以比原来缩减 3 分 40 秒,

  • 在单次 10000 量的时候可以比原来缩减 3 分 50 秒,

  • 在单量 15000 量的时候可以缩减 3 分 50 秒左右,

  • 在单次 12000 量的时候可以缩减 3 分 57 秒。



图 7、优化对比

五、优化方案+

完成的上步之后,虽然性能上有了很大的提升,但是为了给一线的苏宁物流用户提供更优的用户体验,我们想到了优化方案+。

1. 传统 Rollback Journal

SQLite 实现 原子性提交和回滚操作 的默认方法是 rollback journal。当对 DB 进行写操作的时候,SQLite 首先将准备要修改部分的原始内容(以 Page 为单位)拷贝到“回滚日志”中,用于后续可能的 Rollback 操作以及 Crash、断电等意外造成写操作中断时恢复 DB 的原始状态,回滚日志存放于名为“DB 文件名-journal”的独立文件中。对原始内容做备份后,才能写入修改后的内容到 DB 主文件中,当写入操作完成,用户提交事务后,SQLite 清空 -journal 的内容,至此完成一个完整的写事务。


Rollback 模式中,每次拷贝原始内容或写入新内容后,都需要确保之前写入的数据真正写入到磁盘,而不是缓存在操作系统中,这需要发起一次 fsync 操作,通知并等待操作系统将缓存真正写入磁盘,这个过程十分耗时。


除了耗时的 fsync 操作,写入 -journal 以及 DB 主文件的时候,是需要独占整个 DB 的,否则别的线程/进程可能读取到写到一半的内容。这样的设计使得写操作与读操作是互斥的,并发性很差。

2. WAL 模式的应用

WAL 模式则改变了上述流程,写操作不直接写入 DB 主文件,而是写到“DB 文件名-wal”文件(以下简称“-wal”)的末尾,并且通过 -shm 共享内存文件来实现 -wal 内容的索引。读操作时,将结合 DB 主文件以及 -wal 的内容返回结果。由于读操作只读取 DB 主文件和 -wal 前面没在写的部分,不需要读取写操作正在写到一半的内容,WAL 模式下读与写操作的并发由此实现。


WAL 写操作除了上面的流程,还增加了一步:Checkpoint,即将 -wal 的内容与合并到 DB 主文件。 由于写操作将内容临时写到 -wal 文件,-wal 文件会不断增大且拖慢读操作,因此需要定期进行 Checkpoint 操作将 -wal 文件保持在合理的大小。Checkpoint 操作比较耗时且会阻塞读操作,但由于时效性要求较低,遇到堵塞可以暂时放弃继续 DB 读写操作,不至于太过影响读写性能。SQLite 官方默认的 Checkpoint 阈值是 1000 page,即当 -wal 文件达到 1000 page 大小时,写操作的线程在完成写操作后同步进行 Checkpoint 操作;Android Framework 的 Checkpoint 阈值是 100 page。


基于 WAL 的基本工作方式,做额外的两个优化点:


  1. 写入 -wal 文件时不进行 fsync 操作,因为 -wal 文件损坏只影响新写入的没 Checkpoint 部分数据而非整个数据库损坏,影响相对小;

  2. 将需要进行 fsync 的 Checkpoint 操作放到独立线程执行,让写操作能尽快返回。

结束语

物流行业快速发展的今天移动端在作业中的占比量越来越大,苏宁物流一线的作业人员的手持数量每年也在呈几何倍数上涨,在苏宁物流移动端速度发展的这些年,我们从老的黑白机到现在的智能安卓机,从传统过渡到移动互联网和正在进行的智能化,我们一直坚持用技术为一线作业人员减轻作业负责,提升作业效率,在这种大环境下对我们苏宁物流来说是压力也是机遇,不忘初心,砥砺前行,始终不忘造极,以极客的精神打造极致的用户体验。


作者:李健普,苏宁易购物流研发中心移动端开发工程师,负责物流移动端的开发工作,曾负责开发了快递,分拨,仓库,售后等客户端 ,具有较丰富的移动开发经验,对物流作业相关设备开发经验丰富。


2018-11-09 09:562085
用户头像

发布了 164 篇内容, 共 107.5 次阅读, 收获喜欢 392 次。

关注

评论 11 条评论

发布
用户头像
厉害了,又学到了不少
2018-11-13 16:28
回复
用户头像
牛B
2018-11-13 16:24
回复
用户头像
牛B
2018-11-13 16:24
回复
用户头像
学习了
2018-11-13 16:22
回复
用户头像
牛逼了,受益匪浅,点赞👍
2018-11-13 16:20
回复
用户头像
加个队列也能写一篇。。
2018-11-09 15:52
回复
用户头像
深入浅出,收获很多。感谢楼主分享。
2018-11-09 11:58
回复
用户头像
作者有心了,感谢分享。
2018-11-09 11:05
回复
用户头像
很棒,支持一下。受益匪浅。感谢楼主分享
2018-11-09 10:35
回复
用户头像
很棒,支持一下。受益匪浅。感谢楼主分享
2018-11-09 10:34
回复
用户头像
支持作者,学习到很多,棒棒哒!
2018-11-09 10:32
回复
没有更多了
发现更多内容

行业案例| MongoDB在腾讯零售优码中的应用

MongoDB中文社区

mongodb

华创视讯加入龙蜥社区,携手共建开源新生态

OpenAnolis小助手

开源 龙蜥社区 CLA 华创视讯 龙腾计划

Mysql的事务操作问题

恒山其若陋兮

MySQL 5月月更

Redis命令HSCAN踩坑指南

Qunar技术沙龙

dba

区块链系统开发,交易所交易平台搭建

Geek_56201b

技术干货| MongoDB如何查询Null或不存在的字段?

MongoDB中文社区

mongodb

基调听云研发总监杨金全出席CSDN可观测性与APM峰会

基调听云

云原生 APM 可观测性 基调听云

建木持续集成平台v2.3.1发布

Jianmu

开源 DevOps 自动化 持续集成 gitops

Java中容易混淆的基础知识

工程师日月

java 5月月更

飞桨云上沙龙——智能制造专场

百度大脑

渗透测试工具一一Nmap(从初级到高级)

网络安全学海

网络安全 渗透测试 WEB安全 漏洞挖掘 nmap

解决方案| 阿里云数据库MongoDB版助力餐道显著提升运维效率,打造卓越餐饮/零售服务

MongoDB中文社区

mongodb

gRPC服务开发和接口测试初探【Go】

FunTester

虎符交易所Hoo研究院|币海寻珠 2022年4月下半月区块链投融事件TOP20

区块链前沿News

虎符研究院

用阅读和写作应对未来风险

石云升

写作 阅读 5月日更

企评家|华润三九医药股份有限公司成长性评价报告摘要

企评家

塔米狗企评家 企业评价 企业成长性分析 企评家 企业投资价值评价

从手工测试到自动化测试进阶,需要学什么?结合自身分享我10+年的测试经验!

伤心的辣条

Python 程序人生 软件测试 自动化测试 接口测试

TiKV 缩容不掉如何解决?

TiDB 社区干货传送门

信息系统的建设周期

奔向架构师

信息系统 5月月更

去哪儿网MySQL日志分析实践,80%数据丢失都给你救回来!

Qunar技术沙龙

dba

从活动能力层建设看业务架构

Qunar技术沙龙

业务架构

观测云产品更新|优化观测云商业版升级流程;新增进程、日志、链路详情页关联网络;场景模块优化等

观测云

运维 可观测性 可观测

【愚公系列】2022年05月 二十三种设计模式(七)-桥接模式(Bridge Pattern)

愚公搬代码

5月月更

恒源云 (Gpushare)_Restormer:用于高分辨率图像重建的高效Transformer

恒源云

人工智能 深度学习 Transformer

在基础语法中Java与c++有哪些不同?(对于学过c++转Java必看)

工程师日月

c++ java 5月月更

遇到bug怎么分析,这篇文章值得一看

伤心的辣条

Python 程序人生 软件测试 自动化测试 测试开发

Hadoop hdfs 的shell操作

Emperor_LawD

hadoop Shell 5月月更

Flutter 组件渲染模式详解

岛上码农

flutter ios 安卓开发 跨平台应用 5月月更

nginx配置系列(十)代理服务(proxy_pass)

乌龟哥哥

5月月更

LabVIEW仪器控制:智能示波器(普源DS1000E)

不脱发的程序猿

LabVIEW 串口通信 VISA LabVIEW示波器软件

模块一

Geek_28cf33

苏宁11.11:苏宁物流移动端百万级离线数据处理方案_5G/IoT_徐川_InfoQ精选文章