前言: 此方案之前是为了提升京东搜推广研效而设计,最终除了通过 BaaS 底座通用能力复用提升了研发效率,和 FaaS 更细粒度二层调度编排提升了资源使用率之外,也通过存算解耦实现了多分片应用更新从小时级到秒级的跨越 本文后续将探讨的自定义灰度发布、多集群管理及数据密集型应用多分片管理等能力,均以 CRD 为实现载体。 2 技术挑战及应对策略 Serverless 架构在适配搜推广数据密集型场景的落地过程中并非一帆风顺,需直面业务特性与技术架构适配的多维度挑战。 2.1 搜推广业务的应用特点及落地挑战 如上一章节所述,业务在开发与运维层面的痛点,与搜推广场景的特性密切相关,该类应用具备四大典型特征:数据体量庞大、计算密集、业务链路复杂、实时响应要求高。 结语 前文详细阐述了我主导设计与实践的通用云原生 Serverless 架构,该架构最初面向搜推广等多分片数据密集型应用,如今已突破业务边界,实现了更广泛的场景适配。
比较极端的情况下,如果某一个 key 的请求特别多,同样会造成热点分片。 一些数据库,比如 Cassandra 的 key 可以是一个联合主键(>=2 个字段),哈希分片的时候只有第一个字段参与。 事务 事务是对数据库操作的一种抽象,可以简化应用程序的逻辑。 ACID 事务有四个特性:ACID。 一致性(Consistency):在事务开始之前和事务结束以后,数据库的完整性没有被破坏。“完整性”指的是应用程序的一些预设约束——数据的不变性。 有的预设约束是由数据库保证的,比如外键约束、唯一索引;有的预设约束需要应用程序自己保证,比如账户的余额必须大于等于 0。 隔离性(Isolation):多个事务并发、交叉执行可能会相互影响。 对单副本的数据库来说,持久性的意思是数据被写入外存,比如 HDD 或 SSD。对多副本的数据库来说,持久性意味着数据以及成功复制到其它节点。
《数据密集型应用系统设计》 - 应用系统概览 引言 系统应用概览是纯理论的部分虽然很简单,但是看完之后发现其实很多时候有一些术语在自己的观念里面是很狭隘的,作者在书中用了更加严谨的解释话语论述一些软件和系统设计中常见的问题 介绍 现代应用设计更加趋向单一化和模块化,现代信息系统到数据量极速膨胀,换来的是数据复杂和各模块多变,应用系统通常需要包含下面的内容。 数据库:存储数据。 重新认识数据系统 在一个数据系统的架构中,我们通常会判断一个应用系统的三种特性支持,这三种特性即:可靠性、可扩展,可维护性。 可靠性 所谓可靠性不单单指的是系统能在发生异常的时候可以正常运行,实际上包含更多内容: 应用该程序执行用户期望功能。 容忍错误数据或者不正确的操作。 合理到系统负载和释放性能。 权限管理。 和线程执行并行部分的时候计算公式为: T(N) = B + (T - B) / N(N为处理器或者CPU数量) 这里我们不需要记住复杂的公式,我们只需要知道这个阿姆达定理解释了要优化一个程序的性能,性能的提升远不如我们想象中的那么多,
Followers 的数据可能落后 leader 非常多,数据一致性差。 半同步复制 正常情况下,leader 和 followers 之间的数据是一致的。 多主复制 多主复制,也称为 Multi-Master Replication。 从数据库的角度看,多主复制可以实现写扩展和就近接入降低延迟,但是存在写冲突的问题 —— 如果同一条记录在不同的 master 被同时修改,就产生了冲突。 还有一些业务场景符合多主复制的逻辑,不过这里多主复制不一定是为了提升写性能。比如: App 的多端数据同步。每一个终端就是一个 master。CouchDB 是一个专门为解决这类问题设计的数据库。 冲突处理则要根据应用的容忍性进行选择,比如选择时间戳最大的、选择某个 master 的修改、业务定制化处理等等。 个人觉得,如果是为了实现写性能的扩展,可以通过分片(sharding)来实现。
消息代理虽然可以看作是优化数据流的数据库,但是消息队列和数据库是存在本质差距的,主要的差距如下: 数据库需要保证数据的持久化,删除需要指定的命令完成,否则不能擅自丢失数据。 日志存储队列 日志存储结构的关键是 顺序读写 和 追加,在[[《数据密集型型系统设计》LSM-Tree VS BTree]]中介绍了有关日志存储结构的特点。 通过上面几点我们可以了解到,针对不同的应用场景,选择消息的处理方式也不一样: 如果消息的处理代价非常高但消息的排序不是非常重要,可以并行处理保证消息的正常消费。 消费者跟不上生产者 上面基本讨论了消费者跟不上生产者的的一系列问题,我们可以总结为三种处理方式: 丢弃消息 消息缓冲 应用抗压 使用比较多的方式是日志作为消息缓冲,因为缓冲要求具备较大并且固定大小的缓冲 所以代理丢弃的消息是缓冲区容量不能容纳的旧消息,实现的方式是监控消费者落后日志头部的距离,落后非常多的情况下需要进行报警,防止消息积压。
第四章主要介绍数据的序列化和反序列化,以及迭代升级过程中如何保证兼容性。 分布式系统滚动升级的过程中,新旧数据与代码是同时并存的。如果出现异常,可能还需要回退程序。 因此,升级过程中需要保证: 向后兼容(Backward compatibility):新代码要能正确读取旧数据。 向前兼容(Forward compatibility):旧代码要能正确读取新数据。 而在应用后台内部,JSON 和 XML 都不是一个好选择。 二进制编码 Protobuf 和 Thrift Protobuf 和 Thrift 的设计原理、编码规则、使用方式都非常接近。 在应用代码里调用这些生成的代码。 因此修改 field name 不影响数据的序列化和反序列化。 每一个 field 都有一个与之对应的类型,修改类型的时候要小心注意其兼容性。
系统的演进除了数据结构和数据模型本身的演变之外,数据编码和数据之间的交互模式也在不断的进行演变,数据模式和格式改变的时候,通常需要应用程序的对应改变,而应用系统的痛点如下:新版本的部署需要滚动升级(分阶段下线节点然后有序上线 客户端应用程序需要依赖用户自行进行更新,或者使用强制更新手段强制升级。这样的应用程序调整不可避免的带来关键性问题:前后兼容。什么是前后兼容?向后兼容:较新的代码由旧代码编写的数据。 这种处理方案有点类似数据库的版本快照,Thrift:处理方式是使用列表对于字段标签参数化,虽然没有灵活的多版本变化,但是列表可以进行嵌套可以有更多灵活组合。 写模式和读模式 写模式:指的是对于任意数据可以使用已知模式的所有版本编码,比如编译到应用程序的模式。读模式:需要根据模式解码某种数据的时候,期望数据符合某种模式。 另一种选择是客户端请求的API版本存储服务器,同时提供多版本的接口管理调用功能。
数据分片技术作为一种有效的解决方案,能够将海量数据拆分成小块,以便于分布式存储和处理。同时,数据一致性问题也随着分片而成为一个挑战,YashanDB通过其特有的数据分片技术提供了一种高效的解决方案。 本文旨在探讨YashanDB的数据分片技术应用,分析其核心技术点、实现原理和优势,帮助读者更深刻理解其在大数据环境中的价值。 这些策略各有应用场景:- 范围分片:将数据按某个范围划分,每个分片负责一个范围内的记录,适合需要范围查询的场景。 分片的优势和应用场景YashanDB的数据分片技术不仅提供了高效数据存储解决方案,还具有以下优势:1. 性能提升:数据分片能够显著提升查询性能,通过并行访问不同的分片,提高系统的整体响应速度。2. 常见应用场景包括大数据分析、电商交易系统、社交网络等领域。这些业务的特点通常要求在实时数据处理和分析的同时,能够管理巨量用户数据。
假期宅家,这两天在看一本书:Designing Data-Intensive Application,书名翻译成中文是设计数据密集型应用 —— 大部分互联网应用都属于数据密集型应用。 通读下来,这本书并没有教怎么设计一个应用(Application),而是介绍各种数据系统(Data System)背后的设计思想和技术 —— The Big Ideas Behind Reliable, 图数据库在一些特殊场景可能会有应用,比较社交关系链分析等。 远古的层级模型、网络模型这里就不说了。(文档模型和层级模型,图模型和网络模型看起来都挺像的。) Key-Value 在互联网的应用是非常广的,这里的 value 可以是 string、list、set 等,代表作是 redis。 查询语言(接口) 数据系统提供的接口多种多样。应用最广的应该是 SQL。虽然都叫 SQL ,但是每个数据库的 SQL 可能都不太一样。
第三章主要介绍可持久化的数据索引——主流的可持久化数据索引有下面几种: Hash Index。 LSM-Tree。 B-Tree。 B+Tree。 的文件用于持久化保存数据。 随着外存上的数据/文件越来越多,为了尽可能保证数据的有序性和回收一些无效数据,外存上的 SST 之间会进行 compaction。 B-Tree 将数据划分成一个个固定大小的 page,一般是 4/8/16 KB,每次读写一个 page。一个 page 上保存的数据是有序的,方便快速查找。 ? 没有具体的场景,很难说谁浪费的多。 但是,实践中 LSM-Tree(RocksDB) 的压缩效果明显优于 B-Tree/B+Tree(InnoDB)[7]。
『数据密集型应用系统设计』读书笔记(一) 發佈於 2021-12-15 这本书一直在我的待读列表,但是一直没有机会拜读,直到最近 2021 年已经快要过去,感觉需要在年末提升一下自己。 数据密集型与计算密集型 对于一个应用系统,如果”数据”是其成败决定性因素,包括数据的规模、数据的复杂度或者数据产生与变化的速率等,我们就可以称为”数据密集型(Data-Intensive)应用系统”。 内容安排 全书分为三大部分: 主要讨论有关增强数据密集型应用系统所需的若干基本原则 我们将从单机的数据存储转向跨机器的分布式系统,将依次讨论数据远程复制、数据分区、事务、分布式系统的更多细节以及分布式环境如何达成一致性与共识 主要针对产生派生数据的系统(所谓派生数据主要指在异构系统中,如果无法用一个数据源来解决所有问题,那么一种自然的方式就是集成多个不同的数据库、缓存模块以及索引模块) 可靠、可扩展与可维护的应用系统 -- 当然为了弄清楚异常值有多槽糕,需要关注更大的百分位数如 95、99 和 99.9(缩写为 p95、p99 和 p999)值,作为典型的响应时间阈值。
『数据密集型应用系统设计』读书笔记(五) 發佈於 2021-12-26 在前面几章,我们讨论了数据系统的各个方面,但仅限于数据存储在单台机器上的情况。 每个跟随者从领导者拉取日志,并相应更新其本地数据库副本,方法是按照领导者处理的相同顺序应用所有写入 当客户想要从数据库中读取数据时,它可以向领导者或追随者查询。 通常情况下,复制的速度相当快: 大多数数据库系统能在一秒向从库应用变更,但它们不能提供复制用时的保证。 通常情况下,基于领导者的复制都配置为完全异步,异步复制已经被广泛使用了。 所以对于读多写少的场景,我们可以选择创建很多从库,并将读请求分散到所有的从库上去。这样能减小主库的负载,并允许向最近的副本发送读请求。 不过,当应用程序从异步从库读取时,如果从库落后,它可能会看到过时的信息。这会导致数据库中出现明显的不一致。同时对主库和从库执行相同的查询,可能得到不同的结果,因为并非所有的写入都反映在从库中。
对象关系不匹配 目前大多数应用程序开发都使用面向对象的编程语言来开发,如果数据存储在关系表中,那么需要一个笨拙的转换层,处于应用程序代码中的对象和表,行,列的数据库模型之间。 本章将只关注数据模型中的差异。 支持文档数据模型的主要论据是架构灵活性,因局部性而拥有更好的性能,以及对于某些应用程序而言更接近于应用程序使用的数据结构。 关系模型优势在于通过为连接提供更好的支持以及支持多对一和多对多的关系。 如果你的应用程序大多数的关系是一对多关系(树状结构化数据),甚至大多数记录之间不存在关系,那么使用文档模型是合适的。 但是,要是多对多关系在你的数据中很常见呢? 关系模型可以处理多对多关系的简单情况,但是随着数据之间的连接变得更加复杂,将数据建模为图显得更加自然。
第 1 章 可靠、可扩展与可维护的应用系统 目前许多的新型应用都属于「数据密集型」(data-intensive),而不是计算密集型(compute-intensive),对于这些应用,CPU 的处理能力并不是第一限制性因素 近年来出现了许多用于数据存储和处理的新工具,它们可以针对各种不同的应用场景进行优化,不适合再归为数据库、队列、高速缓存等不同类型,因此我们将其统称为「数据系统」(data system)。 此外,越来越多的应用系统需求广泛,单个组件无法满足所有数据处理与存储需求。因此需要将任务分解,每个组件负责高效完成其中一部分,多个组件依靠应用代码有机衔接起来。 例如,许多应用系统包括以下模块: 「数据库」:用来存储数据,以方便应用再次访问 「高速缓存」:缓存那些复杂或操作代价昂贵的结果,以加快下一次访问 「索引」:允许用户按关键字搜索数据并进行各种过滤 「流式处理 硬件冗余方案可以使得单台机器完全失效的概率降为非常低的水平,而近年来随着数据量和应用计算需求的增加,更多的应用可以运行在大规模机器之上,随之而来的硬件故障率呈线性增长。
一个数据库在最基础的层次上需要完成两件事情: 当你把数据交给数据库时,它应当把数据存储起来;而后当你向数据库要数据时,它应当把数据返回给你。 我们应当选择那些能为应用带来最大收益而且又不会引入超出必要开销的索引。 散列索引 ---- 我们从键值数据(key-value Data)的索引开始介绍。 这是一个仅追加的文件,每个 B 树的修改在其能被应用到树本身的页面之前都必须先写入到该文件。 但随着数据库开始应用到那些不涉及到钱的领域,术语交易/事务(transaction)仍留了下来,用于指代一组读写操作构成的逻辑单元。 应用程序通常使用索引通过某个键查找少量记录。 由于这些应用程序是交互式的,这种访问模式被称为在线事务处理(OLTP, OnLine Transaction Processing)。
不懂数据库的全栈工程师不是好架构师 —— Vonng 周六停更 Spring Boot 从入门到实践系列教程 读一本好书《设计数据密集型应用》- Designing 第二章将对几种不同的数据模型和查询语言进行比较。从程序员的角度看,这是数据库之间最明显的区别。不同的数据模型适用于不同的应用场景。 第三章将深入存储引擎内部,研究数据库如何在磁盘上摆放数据。 分区 (Partitioning) 将一个大型数据库拆分成较小的子集(称为分区(partitions)),从而不同的分区可以指派给不同的节点(node)(亦称分片(shard))。 但所有的讨论都假定了应用中只用了一种数据库。 现实世界中的数据系统往往更为复杂。大型应用程序经常需要以多种方式访问和处理数据,没有一个数据库可以同时满足所有这些不同的需求。 因此应用程序通常组合使用多种组件:数据存储,索引,缓存,分析系统,等等,并实现在这些组件中移动数据的机制。
然而,这种规范化本质上是一种「多对一」的关系,对于文档模型来说,其通常对「联结」操作支持较弱(即关系数据库中通过外键关联至其他表中的行),导致有时候需要在应用层代码中进行模拟联结。 网络模型是对层次模型的推广,其支持对多对一与多对多的关系进行建模,在联结操作上,网络模型通过类似于编程语言中的指针方式进行实现。 在存在多对多关系的模型中,访问路径需要由应用程序代码进行跟踪,使得数据库的查询与更新变得异常复杂而没有灵活性。 相比之下,关系模型则是定义了所有数据的格式:关系(表)只是元组(行)的集合。 如果应用大部分是一对多关系(树结构数据)或者记录之间没有关系,那么「文档模型」是最合适的;而如果数据中多对多关系很常见,那么可以使用「关系模型」来处理较简单的多对多情况,但随着数据之间的关联越来越复杂, 历史上,数据最初被表示为一棵大树(层次模型),但是这不利于表示多对多的关系,所以发明了「关系模型」来解决这个问题;而最近,开发人员发现一些应用也不太适合关系模型,于是又出现了新的非关系 NoSQL 数据存储
存储数据的模型可以使JSON也可以是XML类型。 如何展示以及表示JSON,以及如何操作和处理数据模型使应用开发人员天职工作。 越底层的工程师需要考虑的内容越多,需要具备过硬的软硬件知识。 关于网络模型的历史,可以看看wiki的相关介绍: CODASYL - Wikipedia CODASYL属于层次模型的推广,网络模型的架构之下每个记录可能多个父节点,通过一个节点服务多个纪录,实现一对多和多对一的模型 虽然关系型数据库的扩展带来的是越来越复杂的关系模型,但是关系模型的最大特点是只需要构建一次查询优化器就可以使得所有的应用程序都可以通用。最终查询优化器解决了网络模型链路查找的痛点问题。 文档模型和关系模型 现今的数据和网络结构通常是文档模型和关系模型的结合,文档模型可以聚合多个关系表的内容仅限一次展示,但是如果存在多对多的关系,由于文档模型的自由一定程度上需要应用程序进行限制和防范, 当然我不推荐你研究过深,这种东西在国外应用场景也不多见,看起来壮阔的脑图实际上用起来因人而异,至少OB软件个人不太喜欢用。
『数据密集型应用系统设计』读书笔记(四) 發佈於 2021-12-20 编码与演化 在大多数情况下,修改应用程序的功能也意味着需要更改其存储的数据: 可能需要使用新的字段或记录类型,或者以新方式展示现有数据 我们在之前讨论的数据模型有不同的方法来应对这种变化。 当数据格式(format)或模式(schema)发生变化时,通常需要对应用程序代码进行相应的更改。 但在大型应用程序中,代码变更通常不会立即完成: 对于服务端(server-side)应用程序,可能需要执行滚动升级 对于客户端(client-side)应用程序,用户可能相当长一段时间里都不会去升级软件 你的应用程序代码可以调用此生成的代码来对模式的记录进行编码或解码。 我们主要介绍一下 protobuf。 数据可以通过多种方式从一个流程流向另一个流程: 通过数据库 通过服务调用 通过异步消息传递 数据库中的数据流 在数据库中,写入数据库的过程对数据进行编码,从数据库读取的过程对数据进行解码。
应用程序不可避免地需要随时间而变化、调整。在大多数情况下,更改应用程序功能时,也需要更改其存储的数据:可能需要捕获新的字段或记录类型,或者需要以新的方式呈现已有数据。 ,包含了不同时间写入的新旧数据的混合体 在「应用程序」层面,数据格式或模式的变化需要应用程序代码进行相应的调整。 1.4.1 写模式和读模式 当应用程序需要编码某些数据时(例如写入文件或通过网络发送),其使用所知道的模式的任意版本来进行编码,这被称为「写模式」(writer's schema);而当应用程序需要解码某些数据时 具体来说,客户端可以是 「Web 浏览器」,也可以是「本地应用」,服务器的响应可以是直接用于「前端展示」的 HTML、CSS 等,也可以是便于客户端应用程序进一步处理的「编码数据」(如 JSON)。 此外,服务器本身也可以作为另一项服务的客户端(例如 web 应用服务器作为数据库的客户端)。