《数据密集型系统应用》笔记(一)

104 阅读7分钟

《数据密集型系统应用》笔记(一)

(最近得闲,有点想要将之前想看未看挥着看了没有整理的内容进行整理,某种意义上像是还债)

data-intensive applications, 这个概念是相对于计算密集型(Compute-intensive), 到时考虑到目前的AI计算密集型其实也有不少, 但是不是本书讨论的重点;

内容涉及: NoSQL 、消息队列,缓存,搜索索引,批处理和流处理框架

设计的目标: 可靠性,可扩展性和可维护性, (从这点看,有点万变不离其宗的以为, 包括DDD等 架构设计之道,目的都是为了这个,说到底就是架构的本质离不开“人”)

可靠性、可扩展性、可维护性; (Reliability、 scalability, maintainability)

1数据存储 多层, DB cache 、search indexes, streaming, batch process,

从实际的实现层面包括redis mysql, kafka, 还有clickhouse等

image-20240611142140594.png

可靠性(Reliability)

系统在困境(adversity)(硬件故障、软件故障、人为错误)中仍可正常工作(正确完成功 能,并能达到期望的性能水准)。

具体可以展开讲: 容错(faulttolerant ) faut != failure , fault等于莫非定理中的故障,偏离标准,是无可避免的,而failure则是用户感知到的服务停止,这是可以避免的。

可靠性挑战: 硬件错误大规模部署中不可避免增加故障率; 软件错误,包括各种底层bug等; 人为错误,

可扩展性(Scalability)

有合理的办法应对系统的增长(数据量、流量、复杂性)

(这里指的不是代码的可扩展性), 可扩展性指的是负载的可扩展性 可扩展性要考虑几个维度

  1. 负载 (客观流量) )
  2. 性能, 计算效率,比如mapreduce的团团, 平响时间等等, 99th

应对措施:

  1. 纵向扩展
  2. 横向扩展 elastic

可维护性(Maintainability)

许多不同的人(工程师、运维)在不同的生命周期,都能高效地在系统上工作(使系统保持 现有行为,并适应新的应用场景)。

(这里也不仅止开发代码的维护,视角要放远 ) 持续的维护阶段,包括修复漏 洞、保持系统正常运行、调查失效、适配新的平台、为新的场景进行修改、偿还技术债、添 加新的功能

这里是对自己的负责和对团队的负责, 也是对后来人的负责

工程师层面: 可操作性(Operability) 便于运维团队保持系统平稳运行。 简单性(Simplicity) 从系统中消除尽可能多的复杂度(complexity),使新工程师也能轻松理解系统。(注意这 和用户接口的简单性不一样。),(这里其实和设计的高内聚低耦合是统一的) 高内聚决定了差异及复杂性在内层, 低耦合决定了依赖的简单性 可演化性(evolability) 使工程师在未来能轻松地对系统进行更改,当需求变化时为新应用场景做适配。也称为可扩 展性(extensibility),可修改性(modifiability)或可塑性(plasticity)这里就是代码的可扩展性了

运维层面: 人生苦短,关爱运维

在实施层面的注意事项就不提了, 这里注意下规范性和预防层面的

  1. 通过良好的监控,提供对系统内部状态和运行时行为的可见性(visibility) 可太对了哥, 面板 、SLO、各种监控用起来
  2. 为自动化提供良好支持,将系统与标准化工具相集成 这就要求入乡随俗或者是尽量使用标准件,而不是定制件,不好维护
  3. 避免依赖单台机器(在整个系统继续不间断运行的情况下允许机器停机维护) 避免单点
  4. 提供良好的文档和易于理解的操作模型(“如果做X,会发生Y”) 这个其实难度是很高的
  5. 提供良好的默认行为,但需要时也允许管理员自由覆盖默认值 这条我倒是觉得是最重要,最有用的, 类似于各种拆箱即用的组件,是他们配置少么? 不是的, 是因为他们的默认行为设置合理 .
  6. 有条件时进行自我修复,但需要时也允许管理员手动控制系统状态
  7. 行为可预测,最大限度减少意外

数据模型和查询语言

数据建模, 数据选型

经典的关系数据

image-20240611145905662.png

当然如果用非关系库,NOSQL的的文档数据表示将更加简单,一个json 即可描述 ,但是描述连接就很麻烦 连接其实也是有意义的,比如推荐, 比如使用 area job school进行协同过滤

NoSql不好描述多对多,这个其实也是设计思想的原罪

关系模型和网络模型(network model)

网络模型 ,“Greater Seattle Area”地区可能是一条记录,每个居住在该地区的用户都可以与之相关联。这允许对多对一和多对多的关系进行建模; 网络模型中记录之间的链接不是外键,而更像编程语言中的指针,访问记录的唯一方法是跟随从根记录起沿这些链路所形成的路径。这被称为访问路径 (access path)。 听着访问效率就很低啊, 而且深度也可能不一

关系模型

行数据= 关系

文档数据库, 在表示多对一和多对多的关系时,关系数据库和文档数据库并没有根本的不同,也就是说文档数据库还是要退化为行数据,使用关联id进行维护;

文档数据!=无模式,而应该叫做 读时模式,schema-on-read , 如果切换过模式呢? 那么感觉读模式的兼容将较为复杂

模式的变更,无论在文档还是关系变更汇总,都是一件大事

在上述情况下,模式的坏处远大于它的帮助,无模式文档可能是一个更加自然的数据模型

查询的数据局部性

文档通常以单个连续字符串形式进行存储,编码为JSON,XML或其二进制变体(如 MongoDB的BSON)。如果应用程序经常需要访问整个文档(例如,将其渲染至网页),那 么存储局部性会带来性能优势 先简单将理解局部性就是将数据进行文档聚合存储

文档+关系数据库

数据查询语言

可以是SQL ,也可以是别的命令式语言,声明式语言

MapReduce查询

MapReduce既不是一个声明式的查询语言,也不是一个完全命令式的查询API,而是处于两 者之间。

e.g


db.observations.mapReduce(function map() {
var year = this.observationTimestamp.getFullYear();
var month = this.observationTimestamp.getMonth() + 1;
emit(year + "-" + month, this.numAnimals);
},
function reduce(key, values) {
return Array.sum(values);
},
{
query: {
family: "Sharks"
},
out: "monthlySharkReport"
});

可以看到 1.search 2. map 3.reduce 4. ou

mapreduce之所以适应大数据 MapReduce是一个相当底层的编程模型,用于计算机集群上的分布式执行

图数据

(有接触的包括neo4j,) 1对多 使用文档型 多对多,那么连接才是数据中最密集的关系,那么使用图更加合适

一个图由两种对象组成:顶点(vertices)(也称为节点(nodes) 或实体(entities)), 和边(edges)( 也称为关系(relationships)或弧 (arcs)

社交关系, 网络图谱 铁路网络

在曾经的一个主数据(cim-service)的项目中有使用到该类型图数据库, sql参考

WITH RECURSIVE
-- in_usa 包含所有的美国境内的位置ID
in_usa(vertex_id) AS (
SELECT vertex_id FROM vertices WHERE properties ->> 'name' = 'United States'
UNION
SELECT edges.tail_vertex FROM edges
JOIN in_usa ON edges.head_vertex = in_usa.vertex_id
WHERE edges.label = 'within'
),
-- in_europe 包含所有的欧洲境内的位置ID
in_europe(vertex_id) AS (
SELECT vertex_id FROM vertices WHERE properties ->> 'name' = 'Europe'
UNION
SELECT edges.tail_vertex FROM edges
JOIN in_europe ON edges.head_vertex = in_europe.vertex_id
WHERE edges.label = 'within' ),
-- born_in_usa 包含了所有类型为Person,且出生在美国的顶点
born_in_usa(vertex_id) AS (
SELECT edges.tail_vertex FROM edges
JOIN in_usa ON edges.head_vertex = in_usa.vertex_id
WHERE edges.label = 'born_in' ),
-- lives_in_europe 包含了所有类型为Person,且居住在欧洲的顶点。
lives_in_europe(vertex_id) AS (
SELECT edges.tail_vertex FROM edges
JOIN in_europe ON edges.head_vertex = in_europe.vertex_id
WHERE edges.label = 'lives_in')
SELECT vertices.properties ->> 'name'
FROM vertices
JOIN born_in_usa ON vertices.vertex_id = born_in_usa.vertex_id
JOIN lives_in_europe ON vertices.vertex_id = lives_in_europe.vertex_id;

cim-service

RDF数据模型、

感觉是个糟粕, 被抛弃的设计