【ArchSummit架构师峰会】探讨数据与人工智能相互驱动的关系>>> 了解详情
写点什么

苏宁 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:561981
用户头像

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

关注

评论 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
回复
没有更多了
发现更多内容

云管平台和云服务器一样吗?两者有啥区别?

行云管家

云计算 云服务器

极客欢聚,燃动夏日!开发者嘉年华等你来

飞桨PaddlePaddle

人工智能 百度 paddle 飞桨

DHorse v1.2.1 发布,基于k8s的发布平台

tiandizhiguai

DevOps k8s

苹果APP安装包ipa如何安装在手机上|社区征文

雪奈椰子

年中技术盘点

中航机载新技术预研与应用工程师万胜来《IoTDB 在中航机载智能云制造系统》

Apache IoTDB

时序数据库 IoTDB Apache IoTDB 中国航天

架构师日记-到底该如何搭建一个新系统 | 京东云技术团队

京东科技开发者

架构 架构设计 工程架构 企业号 7 月 PK 榜

向量数据库的崛起:从矢量搜索到深度学习 (二)

极限实验室

深度学习 数据库 搜索 极限科技

壹米滴答助力制造业、商贸业及电商企业提升商业流通效率

联营汇聚

实时社群技术专题(二):百万级成员实时社群技术实现(消息系统篇)

JackJiang

网络编程 即时通讯 IM

常规LED广告显示屏的运营成本怎么估算

Dylan

广告 项目 运营 成本 LED显示屏

浅析JVM GC配置指南 | 京东云技术团队

京东科技开发者

JVM 垃圾回收 GC 企业号 7 月 PK 榜

Kubernetes:快速入门指南

NGINX开源社区

nginx Kubernetes 微服务

思维导图软件哪个好?试用百款导图软件只留下这15个。

彭宏豪95

思维导图 在线协作文档 mac思维导图 效率软件 笔记工具

人人都是架构师-清晰架构 | 京东物流技术团队

京东科技开发者

架构 架构设计 企业号 7 月 PK 榜 清晰架构

性能测试的理解误区

老张

性能测试 稳定性保障

经过半年的努力,我终于成为了谷歌开发者专家(GDE)

拭心

android 面试 谷歌 GDE

【推荐】贵阳市等保测评机构看这里!

行云管家

贵阳 等保 等级保护 等保测评

【活动回顾】Data + AI 时代下的云数仓设计 @Qcon

Databend

掌握这些写简历投简历的“黑魔法”,告别简历已读不回!

王中阳Go

golang 简历优化 面试技巧 求职面试 后端面试

龙蜥开发者说:参与开源要敢于担任不同角色 | 第 21 期

OpenAnolis小助手

开源 标准化 sig 龙蜥开发者说 T-one

我们搬家啦!新家园,新征程,新篇章

KaiwuDB

KaiwuDB 剪彩 揭牌

使用GithubAction自动构建部署项目

EquatorCoco

前端 Github Action 框架模式

2023IKCEST “一带一路” 国际大数据竞赛重磅启动!

飞桨PaddlePaddle

人工智能 百度 paddle 飞桨 百度飞桨

和鲸 × 于峻川丨以遥感领域为例,浅谈 AI for Science 带来的数据开放、跨学科协同及产学研一体

ModelWhale

遥感 AI for Science 协同科研 数据开放 产学研一体

一文看懂基础模型的定义和工作原理

这我可不懂

人工智能 机器学习 基础模型 GPT

衡量开发人员工作效率的五个技巧

高端章鱼哥

代码 代码开发 开发效率

手把手教你用 NebulaGraph AI 全家桶跑图算法

NebulaGraph

人工智能 图数据库

sharding-jdbc分库连接数优化 | 京东物流技术团队

京东科技开发者

分库分表 Sharding sharding-jdbc 企业号 7 月 PK 榜

【IOS】教你如何在手机端轻松安装ipa文件-(安装器已失效21.10)|社区征文

雪奈椰子

使用GPT探索学习新东西的乐趣与惊喜 💡|社区征文

Five

学习 安卓 GPT 年中技术盘点

MobPush 工作台操作指南:查看推送数据

MobTech袤博科技

大数据 前端 后端

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