硬核干货——《中小企业 AI 实战指南》免费下载! 了解详情
写点什么

有赞零售 App 离线切换技术方案

  • 2019-08-18
  • 本文字数:3777 字

    阅读完需:约 12 分钟

有赞零售 App 离线切换技术方案

一、离线模式的价值

有赞零售客户端的用户是需要经营线下门店的商家,在商家的经营时间内,如果软件不能保证正常使用会导致经营效率下降,甚至客户流失。因此除了不断优化软件性能,降低崩溃率,还要做好异常情况的降级处理,比如遇到网络故障和服务器故障等情况时,软件要保证核心功能的可用性,此时软件的工作模式被称为离线模式。


在离线模式下,客户端不能和服务端进行正常的数据通信,所有的数据存储和计算逻辑都要客户端独立完成。目前有赞零售客户端在离线模式下支持登录、收银支付、订单管理、会员积分、部分营销活动等核心功能,即使在极端情况下,有赞零售客户端依然保证商户的经营活动正常进行。


在客户端离线解决方案中主要有两个问题:


1、如何准确及时的触发或退出离线模式。


2、离线场景下的各个业务如何进行数据处理和同步。


本文针对第一个问题,以 iOS 零售客户端为例对其技术实现细节展开分析。

二、离线切换的技术实现

首先我们要清楚商家在什么场景下需要切换到离线模式。试想一下这样的场景:


小明是一名门店收银员,此时正是店里的客流高峰期,收银机前等待结账的顾客已经排起了队,不凑巧的是,此时店里的网络信号很不稳定,开单会等待很久才能有结果,有时会提示网络超时,收银效率很低,排队等待的顾客开始有些不耐烦了,小明只能一边安抚顾客,一边尝试着进行开单收银操作。后来网络彻底断掉,软件无法进行开单操作了,排队的顾客放下准备买的东西离开了,小明只能干等着技术人员来修复网络。


如果以上场景,收银软件能够切换成离线模式,脱离对网络的依赖,确保现有的顾客都能顺利进行结账,收银效率和顾客体验都不会受到影响。此外也存在服务器出现故障的情况,导致客户端的数据请求失败,此时也需要切换到离线模式。因此有赞零售客户端设计了两种切换离线的功能:手动切换能力和针对断网和服务故障的自动切换能力。


为此我们设计一个离线模块用来实现离线模式的触发和退出,它位于业务层和网络层的中间。业务层中各业务模块通过依赖注入的方式获取离线的状态变化和原因,而离线场景下的具体功能由各业务模块实现。业务层通过网络层发送业务数据请求,如果返回的数据出现异常,网络模块会将错误分别发送给业务层和离线模块,离线模块分析接口信息和返回的数据,进而启动服务故障识别功能。



离线模块主要提供三个能力:


  • 离线状态管理

  • 网络故障检测

  • 核心服务故障检测

2.1 离线状态管理

是否处于离线状态是由三个因子共同决定的:


  • 标记离线

  • 网络故障

  • 服务故障


其中标记离线是用户想要主动启动离线模式时,点击指定按钮触发离线模式。网络故障和服务故障是触发离线状态的另外两个条件。我们通过有限状态机维护离线状态的变化,只有当标记离线、网络故障和服务故障的状态都是 False,才会恢复在线状态,否则一直是离线状态。


标记离线通过本地文件缓存来保存状态,因此软件崩溃并不会影响离线状态的管理。对于网络故障,细分为蜂窝移动网络故障还是 WIFI 故障。服务故障解析是根据报错的接口判断出是哪个业务域出的问题。网络故障和服务故障都是实时监测获取状态,具体的监测手段会在下文展开介绍。

2.2 网络故障检测


要实现网络状态的实时监测,我们首先考虑采用苹果官方提供的 Reachability 库,Reachability 的实现依赖于系统提供的 SCNetworkReachability 类,SCNetworkReachability 允许应用程序获取当前系统的网络配置情况,包括网络类型和当前的连接状态。


Reachability 的使用分为同步模式和异步模式。在同步模式下,应用程序主动调用 Reachability 的currentReachabilityStatus方法获取当前的网络连接状态。


currentReachabilityStatus{    NSAssert(_reachabilityRef != NULL, @"currentNetworkStatus called with NULL SCNetworkReachabilityRef");    NetworkStatus returnValue = NotReachable;    SCNetworkReachabilityFlags flags;    // 同步模式获取网络连接状态    if (SCNetworkReachabilityGetFlags(_reachabilityRef, &flags))    {        returnValue = [self networkStatusForFlags: flags];    }
return returnValue;}
复制代码


在异步模式下,应用程序需要调用 Reachability 的startNotifier方法开启一个 RunLoop 去监听网络状态的变化,当网络状态发生变化时,Reachability 会执行ReachabilityCallback回调函数,在这个回调函数里会发送kReachabilityChangedNotification通知,应用程序监听这个通知就可以感知网络状态的变化。源码如下:


- (BOOL)startNotifier{    BOOL returnValue = NO;    SCNetworkReachabilityContext context = {0, (__bridge void *)(self), NULL, NULL, NULL};    // 构造一个监听网络连接状态的上下文信息,详细说明见下面
// 通过调用 SCNetworkReachabilitySetCallback 函数(并传入 Reachability 对象的 ref,以及根据 SCNetworkReachabilityCallBack 自定义的一个回调函数和上述 context)设置 ref 的网络连接状态变化时对应的回调函数为 ReachabilityCallback if (SCNetworkReachabilitySetCallback(_reachabilityRef, ReachabilityCallback, &context)) { // 通过调用 SCNetworkReachabilityScheduleWithRunLoop 函数设置 Reachability 对象的 ref 在 Current Runloop 中对应的模式(kCFRunLoopDefaultMode)开始监听网络状态 if (SCNetworkReachabilityScheduleWithRunLoop(_reachabilityRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode)) { returnValue = YES; } }
// 如果监听成功,返回 YES,否则返回 NO return returnValue;}
...static void ReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkReachabilityFlags flags, void* info){#pragma unused (target, flags) NSCAssert(info != NULL, @"info was NULL in ReachabilityCallback"); NSCAssert([(__bridge NSObject*) info isKindOfClass: [Reachability class]], @"info was wrong class in ReachabilityCallback");
Reachability* noteObject = (__bridge Reachability *)info; // 因为上述 context 传入的是 self(Reachability 对象),所以这里的 info 为 Reachability 对象类型
// 发送一个全局通知告诉监听者网络连接状态已发生改变,可通过 noteObject 获取状态 [[NSNotificationCenter defaultCenter] postNotificationName: kReachabilityChangedNotification object: noteObject];}
复制代码


然而 Reachability 存在一个缺陷,当应用程序可以将一个数据包发出时,SCNetworkReachability 就认为网络是可达的,但是这个数据包是否到达目标地址,SCNetworkReachability 并不清楚,所以它并不能真正检测服务可达性。


于是我们采用一个三方开源库 RealReachability 的方案,这个库是在 Reachability 的基础上进行改进,借助系统的 Socket 库实现的 ping 功能,通过不断对目标地址发送 ping 请求,根据返回的结果判断目标地址是否可达,因而可以更准确的识别当前的网络状态。


在实际应用中,会遇到网络状况时好时坏的情况,RealReachability 的方案会造成业务层频繁地在离线模式和正常模式间来回切换,影响用户体验,有的场景下甚至会导致反复刷新页面,进而引起卡顿。为了解决这个问题,我们在 RealReachability 上再一次进行优化,加入网络防抖功能,它的机制是网络状态的变化不会实时影响离线状态,而是设置一个时间缓冲值 T1,当网络断开时,我们会等待 T1 时间再检查网络是否断开,如果此时网络已经恢复,不会触发离线模式,如果此时网络仍然是断开的,就触发离线模式。在这个缓冲时间内的网络反复变化不会影响离线状态,因此就不会造成频繁的离线切换。



此外 RealReachabilityping 检测的时间间隔为 T2,当发现网络连接断开时,为了及时地检测到网络的恢复,我们会以更快的频率进行 ping 操作,网络恢复后检测的时间间隔也会恢复到 T2。

2.3 服务故障检测

服务故障的检测流程如下图所示:



第一阶段是网络层错误分发,业务层通过网络层发送请求给相应的服务端,当返回的数据出现异常,网络层会启动错误处理的流程,一方面会把错误信息返回给业务层,另一方面把错误信息和请求接口信息一起发给离线模块。


第二阶段是错误信息的本地解析,离线模块维护一份核心业务白名单,这里会配置客户端使用的各个核心业务的接口信息,根据这个白名单可以判断请求的接口所属的业务领域,如果当前报错的接口命中了白名单,离线模块会认为核心业务存在故障风险。


第三阶段是服务端的故障检测,离线模块会请求 QoS 智能决策系统,它根据不同业务后端系统的报警信息来判断是否发生服务故障。如果它判断发生了服务故障,离线模块会收到通知,进而更新本地的离线状态。


第四阶段是故障恢复的检测,离线模块会启动后台线程定期去轮询 QoS 智能决策系统,直到它判断服务故障已经恢复,停止轮询并更新离线状态。

三、展望

本文介绍了零售客户端离线切换解决方案,接下来的问题是业务层如何进行数据处理和同步,以收银开单流程为例,涉及到账号、商品、营销、会员、支付、订单等多个业务模块,各个模块在离线状态下如何存储和处理数据,保证用户在离线状态下可以完成收银功能,以上这些问题我们会在后续文章里详细介绍,敬请期待。



本文转载自公众号有赞 coder(ID:youzan_coder)


原文链接


https://mp.weixin.qq.com/s/ZuQ85PnhOW94m0U4_Yk_2w


2019-08-18 08:003976

评论 1 条评论

发布
用户头像
看文章好像只写了判断离线,但是离线之后如何继续收银还没写完吧
2019-08-19 20:44
回复
没有更多了
发现更多内容

电路模型和电路定律 (Ⅱ)

謓泽

3月月更

如何实现24小时客户服务

小炮

客户服务

安全大讲堂 | 孙朝晖:全量数据是一切网络安全分析的起点

腾讯安全云鼎实验室

数据分析 网络安全 数据安全 安全大讲堂

web前端培训React合成事件原理解析

@零度

React web前端开发

ModStartCMS模块化建站系统 v3.5.0 多图字段支持,系统优化升级

ModStart开源

从持续交付到业务创新(下):有效的业务创新

阿里云云效

云计算 阿里云 云原生 研发效能

隐私安全的必答题,网易云信如何解?

网易云信

隐私安全

深度揭秘阿里云 Serverless Kubernetes

Serverless Devs

6张图为你分析Kafka Producer 消息缓存模型

华为云开发者联盟

kafka 消息 Kafka Producer 消息缓存模型 消息缓存

31岁的Python,蝉联年度编程语言排行榜冠军

JackTian

Python 编程 程序员 编程语言 后端

从持续交付到业务创新(上):互联网时代研发效能的核心

阿里云云效

云计算 阿里云 云原生 研发效能 持续交付

金三银四的 Vue 面试准备

CRMEB

如何使用Java AWT 创建一个简易计算器

华为云开发者联盟

Java 计算器 GUI AWT 图形

即学即会 Serverless 系列:初识 Serverless 架构

Serverless Devs

云计算 阿里云 Serverless 架构

信创云管理平台,头部券商解决异构云资源管理的关键

BoCloud博云

信创 云管平台

《Mybatis 手撸专栏》第1章:开篇介绍,我要带你撸 Mybatis 啦!

小傅哥

小傅哥 mybatis 手写Mybatis

ironSource 推出全球首个跨渠道应用营销平台 ironSource Luna

科技热闻

OceanBase 源码解读(八):事务日志的提交和回放

OceanBase 数据库

oceanbase 源码解读

动态卡片:富媒体内容井喷式增长下,新一代移动端动态研发的模式

蚂蚁集团移动开发平台 mPaaS

ios android 前端 mPaaS 卡片技术

字节跳动流式数据集成基于Flink Checkpoint两阶段提交的实践和优化背景

字节跳动数据平台

大数据 flink 字节跳动 数据集成

中国企业的测试之道被美国学习了?

博文视点Broadview

TSP 平台场景中的 MQTT 主题设计|车联网平台搭建从入门到精通 03

EMQ映云科技

开源 物联网 IoT mqtt emq

资金管理系统解决方案

低代码小观

资产管理 企业管理系统 资金安全 CRM系统 客户关系管理系统

Redis面试题:基本数据类型与底层存储结构

Linux服务器开发

redis 面试题 Linux服务器开发 Linux后台开发 BAT面试题

科技筑基、高效实战:中科柏诚信云链正当时

联营汇聚

ShardingSphere-Proxy 5.0 分库分表(一)

神农写代码

阿里巴巴开源大规模稀疏模型训练/预测引擎DeepRec

阿里云大数据AI技术

机器学习 深度学习 搜索引擎 分布式训练 推荐引擎

API接口知识小结

源字节1号

程序员 有趣的技术知识

打印总是遇到问题?一文教你如何在优麒麟上使用 CUPS 管理打印机

优麒麟

Linux 终端 优麒麟 打印机管理

小程序多端引流新思路:App公域流量挖掘

Speedoooo

APP开发 智慧终端 引流获客工具 引流获客系统

企业知识管理的措施

小炮

知识管理

有赞零售 App 离线切换技术方案_技术管理_余颖_InfoQ精选文章