最新发布《数智时代的AI人才粮仓模型解读白皮书(2024版)》,立即领取! 了解详情
写点什么

有赞零售 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:003435

评论 1 条评论

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

谈谈数智人力建设过程中发现的问题及感悟

用友BIP

数智人力

国内外常用的Scrum敏捷看板工具

顿顿顿

Scrum 敏捷开发

2023京东全球科技探索者大会暨京东云峰会来了!

京东科技开发者

人工智能 AI 京东云 AIGC 企业号 6 月 PK 榜

中原银行 OLAP 架构实时化演进

Apache Flink

大数据 flink 实时计算

单元测试|Unittest setup前置初始化和teardown后置操作

霍格沃兹测试开发学社

HttpRunner

软件测试/测试开发丨学习笔记之Docker常用命令

测试人

Docker 程序员 容器 软件测试 测试开发

火山引擎DataTester:企业如何使用A/B实验优化商业化能力

字节跳动数据平台

A/B 测试

建设数字工厂:华为云数字工厂平台接入第三方网关设备数据

华为云开发者联盟

云计算 后端 华为云 华为云开发者联盟 企业号 6 月 PK 榜

WorkPlus AI助理正式上线!为企业打造定制化的AI私有助理

WorkPlus

接口测试|HttpRunner接口关联与常用断言

霍格沃兹测试开发学社

HttpRunner

将 NGINX 部署为 API 网关,第 1 部分

NGINX开源社区

nginx 网关 NGINX Kubernetes Gateway

敏捷项目管理流程及工具

顿顿顿

敏捷项目 敏捷项目管理 敏捷工具 scrum敏捷工具

【有奖征文 】AI编程:华为云CodeArts Snap入门体验

华为云PaaS服务小智

人工智能 AI

接口测试|HttpRunner header处理以及发送post请求

霍格沃兹测试开发学社

HttpRunner

接口测试|HttpRunner获取响应数据&extract提取值到变量

霍格沃兹测试开发学社

HttpRunner

接口测试|Fiddler介绍以及安装

霍格沃兹测试开发学社

fiddler

如何使用敏捷工具管理敏捷缺陷

顿顿顿

Scrum 敏捷开发 缺陷管理

接口测试|HttpRunner环境变量与跨文件输出传递变量

霍格沃兹测试开发学社

HttpRunner

这样的全面预算体系才能构建一流财务体系!

用友BIP

全面预算

客户案例|某知名连锁咖啡品牌点餐小程序排障实录

观测云

可观测性 观测云 云原生可观测 可观测性用观测云

软件测试/测试开发丨学习笔记之Python运算符

测试人

Python 程序员 软件测试 运算符

佳创视讯亮相深圳文博会 以科技赋能文旅产业数字化进程

科技热闻

英特尔Flex系列GPU支持数字内容创作,提高创意生产力

E科讯

ABAQUS 在按键手感分析中的应用

思茂信息

软件设计 abaqus abaqus软件 abaqus有限元仿真 有限元仿真技术

Run in PaddleX 2.0,一站式搞定飞桨精选模型开发全流程!

飞桨PaddlePaddle

人工智能 百度 paddle 飞桨

上新!智能分析云助力【消费品行业】实现数智驱动

用友BIP

数据分析

如何实时统计最近 15 秒的商品销售额|Flink-Learning 实战营

Apache Flink

大数据 flink 实时计算

如何用好数智员工实现轻松采购?

用友BIP

数智底座 Pass平台 采购云

SaaS产品如何用好大模型?腾讯云给出了一个参考答案

ToB行业头条

供应链协同——企业全球供应链可持续发展的基础

用友BIP

全球化 中企出海

接口测试|Fiddler界面主菜单功能介绍(一)

霍格沃兹测试开发学社

fiddler

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