增量更新模型的讨论
2015-09-16 11:50
155 查看
客户端和服务端的数据同步过程中,客户端有缓存,不需要每次都是全量刷新,所以可以采用增量的方式更新。
每次在客户端进行刷新的时候,服务端会将最新的增删改操作推送到客户端,客户端对其缓存进行操作,以保持数据的同步。
[图片来自参考文献 1]
我们要实现的是数据的同步,那么我们只要每次在本地列表需要更新时,将所有后端数据库的信息拉取到本地,进行对比,如果有新增就新增,有修改就修改,如果新来的版本里面某一项不见了,就直接在本地缓存中删除该项即可。
优点:
写接口时很清爽,它是最简单的实现
缺点:
服务端发送多余的数据
只能用于小数据量,在数据量比较大的时候,单次刷新的操作就耗费很多网路流量。
应用场景:IMAP 协议,新闻类 APP 中的每日头条,如 Yahoo News Digest
在 CalD*** 日历协议中,每个日历事件都拥有一个 ETag 来标记它的版本信息,客户端对比服务器发来的 ETag 来决定要不要更新某项日历事件,此处的 ETag 和 HTTP headers 中 Last-Modified 和 ETag 其实是一样的东西,用于标记版本信息。这种方式即为接下来要提到的 Timestamp Transfer。
[图片来自参考文献 1]
客户端存储上次拉取的数据的 Timestamp,在请求更新数据时,携带该 Timestamp 作为本地数据版本信息。数据库内每行数据设置一个 LAST_UPDATE_TIME 字段,服务器将比该时间更新的数据返回给客户端。
优点:
相对于 Full Transfer 来说减少了冗余数据的传输
缺点:
传输时 Timestamp 作为版本信息需要精确控制,请求错误的版本号可能带来本地数据的不准确
已经删除的数据其实已经不存在了,取不到 LAST_UPDATE_TIME
第二个缺点可以通过设置 IS_DELETE 字段来避免,每次删除数据时,仅仅更新 LAST_UPDATE_TIME 和设置 IS_DELETE 为 True 来标记已删除。此处带来的缺点是,被删除的数据继续占用空间,不过当只有一个客户端时,可以在客户端确认删除缓存中相应数据后删除数据库中 IS_DELETE 为 True 的数据,这个方法被成为 Soft Delete.
[图片来自参考文献 1]
服务器接收到客户端发来的更新请求时,将客户端根据 Reconciliation 算法生成的值来确定要返回给客户端的增删改信息。此处说的 Reconciliation 算法的作用与 Checksum 校验和类似,用于校验数据是否已经修改。
优点:
避免了查询数据库时对 LAST_UPDATE_TIME 的条件过滤
缺点:
Reconciliation 算法普适性低
Reconciliation 算法开发周期长
优点:
保持了所有数据的精确可同步
缺点:
客户端很久不更新以后单次的更新补丁很大
如果数据改动很多,那记录操作的表将会变得很大
APPLICATION DESIGN
两种增量更新方案
RFC 4791 - CalD***
AppSync.org
Evernote Synchronization via EDAM
Object Synchronizer
每次在客户端进行刷新的时候,服务端会将最新的增删改操作推送到客户端,客户端对其缓存进行操作,以保持数据的同步。
最原始的方法 - Full Transfer
[图片来自参考文献 1]
我们要实现的是数据的同步,那么我们只要每次在本地列表需要更新时,将所有后端数据库的信息拉取到本地,进行对比,如果有新增就新增,有修改就修改,如果新来的版本里面某一项不见了,就直接在本地缓存中删除该项即可。
优点:
写接口时很清爽,它是最简单的实现
缺点:
服务端发送多余的数据
只能用于小数据量,在数据量比较大的时候,单次刷新的操作就耗费很多网路流量。
应用场景:IMAP 协议,新闻类 APP 中的每日头条,如 Yahoo News Digest
在 CalD*** 日历协议中,每个日历事件都拥有一个 ETag 来标记它的版本信息,客户端对比服务器发来的 ETag 来决定要不要更新某项日历事件,此处的 ETag 和 HTTP headers 中 Last-Modified 和 ETag 其实是一样的东西,用于标记版本信息。这种方式即为接下来要提到的 Timestamp Transfer。
根据修改时间来拉取增删改信息 - Timestamp Transfer
[图片来自参考文献 1]
客户端存储上次拉取的数据的 Timestamp,在请求更新数据时,携带该 Timestamp 作为本地数据版本信息。数据库内每行数据设置一个 LAST_UPDATE_TIME 字段,服务器将比该时间更新的数据返回给客户端。
优点:
相对于 Full Transfer 来说减少了冗余数据的传输
缺点:
传输时 Timestamp 作为版本信息需要精确控制,请求错误的版本号可能带来本地数据的不准确
已经删除的数据其实已经不存在了,取不到 LAST_UPDATE_TIME
第二个缺点可以通过设置 IS_DELETE 字段来避免,每次删除数据时,仅仅更新 LAST_UPDATE_TIME 和设置 IS_DELETE 为 True 来标记已删除。此处带来的缺点是,被删除的数据继续占用空间,不过当只有一个客户端时,可以在客户端确认删除缓存中相应数据后删除数据库中 IS_DELETE 为 True 的数据,这个方法被成为 Soft Delete.
结合算法和修改时间来拉取增删改信息 - Mathematical Transfer
[图片来自参考文献 1]
服务器接收到客户端发来的更新请求时,将客户端根据 Reconciliation 算法生成的值来确定要返回给客户端的增删改信息。此处说的 Reconciliation 算法的作用与 Checksum 校验和类似,用于校验数据是否已经修改。
优点:
避免了查询数据库时对 LAST_UPDATE_TIME 的条件过滤
缺点:
Reconciliation 算法普适性低
Reconciliation 算法开发周期长
增删改日志 - SYNC
服务端记录数据的每次操作都记录进一个增量数据库,数据库内记录了每条操作的对象 ID 和操作的内容。此处思想类似于 Patch 补丁操作,客户端发送一个 Timestamp 信息,服务器将这个时间以后的所有增删改操作返回给客户端,客户端再进行打补丁操作,使得最终结果与服务端同步。优点:
保持了所有数据的精确可同步
缺点:
客户端很久不更新以后单次的更新补丁很大
如果数据改动很多,那记录操作的表将会变得很大
场景
我们现在的需求是,有一个订单模块,某一用户在 APP 中可以点击刷新订单列表,将服务器上其所有订单显示出来。# 订单更新操作 def order_update(request): # 对其中一个订单做更新操作 order = Order.objects.get(id=1) order.update_time = time.time() order.save() # 设置缓存内的版本信息 cache_time = time.time() cache.set('order_list_' + str(request.user.id), cache_time, 3600 * 24 * 7) return JsonResponse({}) # 返回订单列表 def order_list(request): # 保存客户端的版本信息 since,即 timestamp since = request.GET.get('since') or 0 since = float(str(since)) # 取出缓存中最新版本信息 since_cache since_cache = cache.get('order_list_'+ str(request.user.id)) # 如果客户端携带版本信息为 0,说明客户端请求全量更新 # 或者当缓存中版本新于客户端版本信息,则返回 update_time 新于客户端版本的所有条目 if (since == 0) or since_cache and (since_cache > since): orders = Order.objects.filter(user=request.user, update_time__gt=since) data = [order.id for order in orders] return JsonResponse({ 'status': 1001, 'since': since_cache, 'data': data }) # 没有更新,直接返回最新的缓存时间 else: return JsonResponse({ 'status': 1001, 'since': since_cache, 'data': [] })
筛选的情况
有时候我们只需要更新满足筛选条件的条目,客户端利用 Timestamp Transfer 来进行拉取所有增删改信息,但是只针对满足筛选条件的那些项目进行更新操作,其余的直接丢弃。参考文献
DATA SYNCHRONIZATION PATTERNS IN MOBILEAPPLICATION DESIGN
两种增量更新方案
RFC 4791 - CalD***
AppSync.org
Evernote Synchronization via EDAM
Object Synchronizer
相关文章推荐
- JBD日志的定位、分析和恢复
- 程序员面试、算法研究、编程艺术、红黑树、数据挖掘5大系列集锦
- 切换UNDO表空间
- XP的IIS虚拟目录 访问 IIS 元数据库失败
- Android四大基本组件介绍与生命周期
- UML 类图
- html checkbox attr and prop
- 在注册表中修改远程端口
- 我究竟是怎么了
- Android列表对话框用法实例分析
- STL::STRING格式化字符串
- Hadoop YARN如何调度内存和CPU
- 虽然Png本身不失真,但是IE显示的时候失真
- 如何发布Node模块到NPM社区
- Linux下进程信息/proc/pid/status的深入分析
- javascript学习笔记
- 2015 9月16日 工作计划与执行
- java中将数组、对象、Map、List转换成JSON数据
- ServletConfig对象详解
- 实时DevExpress内存监视