Tech-Paul

work hard, play hard

React 组件的优化

减少不必要的渲染:

  • 使用 React.memo 或 PureComponent 来避免不必要的组件更新。这些方法通过浅比较 props 或 state 来决定是否重新渲染组件。
  • 利用 useMemo 和 useCallback 缓存昂贵的计算或回调函数,防止在每次渲染时都重新计算或创建新的函数实例。

代码分割和懒加载:

使用 React.lazy 和 Suspense 来实现组件级别的懒加载,按需加载组件代码,减少初始加载时间。

在路由级别使用代码分割,确保只有访问到特定路由时才加载相应组件。

优化长列表渲染:

  • 使用虚拟滚动库(如 react-window 或 react-virtualized)来只渲染可视区域内的元素,减少 DOM 节点数量,提高性能。
  • 实现懒渲染,即组件进入或即将进入可视区域时才渲染组件。

减少 DOM 操作:

  • 利用 React 的虚拟 DOM 机制,减少实际 DOM 操作的次数。
  • 避免在 render 方法中创建函数或绑定事件处理器,这些操作可以在构造函数或 useEffect 中进行。

优化组件结构:

  • 保持组件树的扁平化,减少不必要的组件嵌套和递归深度,有助于减少渲染时间。
    合理使用 Fragment 避免不必要的额外 DOM 节点。

资源优化:

  • 对图片资源进行压缩,并选择合适的格式,如 WebP。
  • 使用 gzip 等工具对资源文件进行压缩,减少传输大小。
  • 将 CSS 放在头部,JS 放在底部或使用异步加载 JS 文件,避免阻塞页面渲染。

错误边界:

使用错误边界(Error Boundaries)来捕获并处理子组件树中的 JavaScript 错误,防止整个应用崩溃。

其他优化技巧:

  • 批量更新状态,减少由多次状态变更触发的多次重绘。
  • 使用稳定的键(key)来优化列表渲染。
  • 调整 Babel 配置,使用多进程编译、缓存编译文件以及通过 tree shaking 删除冗余代码,提升构建速度和减少打包体积。

http 请求并发优化

  • 使用 HTTP/2 协议:HTTP/2 支持多路复用,可以在同一个 TCP 连接上并行多个请求和响应,从而有效突破浏览器的并发限制。
  • 资源分散到不同域名:通过将资源分散到不同的域名下,可以绕过浏览器对同一域名下的并发连接数限制,实现更高的并发数。
  • 使用 CDN 加速资源加载:通过使用 CDN 加速资源加载,可以减少请求等待时间,提高并发性能。
  • 使用 Web Workers:Web Workers 允许运行与主 JavaScript 执行线程分离的代码,从而可以并行处理多个任务,间接提高并发处理能力。
  • 利用 CDN 和预加载技术:通过 CDN 加速资源加载,预加载关键资源,可以减少请求等待时间,间接提高并发性能。

http 数据分块

  • 动态生成内容、大文件传输或者需要逐步处理和发送数据的情况下,可以考虑使用分块传输编码(Chunked Transfer Encoding)来将数据分成小块发送。这样可以避免一次性发送大量数据导致的性能问题。
  • 服务器在响应头中设置 “Transfer-Encoding: chunked” 来表明使用了分块传输编码。
    数据被分成多个块,每个块都有一个十六进制表示的长度值,后面跟着数据内容,最后以一个长度为 0 的块表示数据传输结束。

http 缓存优化

  • 使用强缓存:通过设置合适的 Cache-Control 和 Expires 头部字段,将资源缓存到浏览器本地,避免重复请求。
  • 使用协商缓存:通过设置 Last-Modified 和 ETag 头部字段,服务器可以根据客户端的请求判断资源是否有更新,从而决定是否返回新的资源。

webpack 优化

。。。

node http 响应优化

集群

  • 利用 Node.js 的 cluster 模块来创建多个子进程,每个子进程都运行自己的事件循环和 V8 实例。这样可以充分利用多核 CPU,提高应用的并发处理能力。
  • 负载均衡器(如 Nginx)可以将请求分发到不同的 Node.js 实例上,进一步分散负载。

微服务架构(Microservices Architecture)是一种软件设计模式,将应用程序划分为多个小型、独立的服务。这些服务可以独立部署、更新、扩展,并通过网络进行通信,通常使用轻量级协议(如 HTTP、gRPC 等)。每个微服务负责处理特定的业务功能,形成松散耦合、独立自治的系统。

微服务架构的关键概念

  • 单一职责: 每个微服务专注于一个特定的业务功能或模块,遵循单一职责原则(SRP)。例如,一个电子商务应用可以分为订单服务、用户服务、支付服务、库存服务等。

  • 独立部署: 各个微服务可以独立开发、测试、部署和更新。这样,更新某一个服务不会影响整个系统,大大提高了灵活性。

  • 松耦合: 微服务之间是松散耦合的,服务之间通过明确的 API 进行通信。这样,服务的内部实现可以独立更改,而不会影响其他服务。

  • 技术异构: 各个微服务可以使用不同的编程语言、数据库、技术栈等。这使得开发团队可以选择最适合某个服务的技术,而不需要整个系统使用同一种技术。

  • 分布式系统: 微服务架构通常是分布式的。服务可能在不同的服务器或容器中运行,依赖网络通信进行协作。分布式架构带来了扩展性和容错性,但也增加了复杂性。

  • 数据隔离: 每个微服务通常都有自己独立的数据库,避免服务之间通过共享数据库紧耦合。数据隔离保证了服务的自治性,但跨服务的数据一致性需要通过业务逻辑或事件机制来确保。

  • 容错性和弹性: 由于微服务架构是分布式的,某个服务可能会出现故障。为了确保系统的高可用性,微服务架构通常会实现容错机制,如服务熔断、自动重启等。

微服务架构的优势

  • 可扩展性: 微服务可以独立扩展,系统中的某个服务遇到高负载时,可以针对该服务进行横向扩展,而不需要扩展整个应用程序。

  • 灵活性: 不同的服务可以使用不同的技术栈,开发团队有更大的灵活性去选择最合适的工具、语言和数据库。

  • 独立开发与部署: 各个微服务可以由不同的团队并行开发,并且可以独立部署。这使得开发周期更短,CI/CD 流程更高效。

  • 容错性: 如果某个服务出现故障,其他服务可以继续正常工作,不会导致整个系统崩溃。容错机制和负载均衡可以进一步提升系统的健壮性。

  • 易于维护: 由于每个服务的代码量较小且专注于单一功能,开发和维护的复杂性相对降低。即使团队规模增大,代码库依然保持简洁易懂。

微服务架构的挑战

  • 分布式复杂性: 微服务架构带来了许多分布式系统的挑战,例如网络延迟、服务间通信失败、数据一致性问题、负载均衡、以及服务发现等。

  • 数据一致性: 每个微服务都有自己的数据库,跨服务的事务和数据一致性管理变得更为复杂。开发者可能需要使用事件驱动的架构或者补偿性事务等模式来确保数据一致性。

  • 运维复杂度: 微服务通常分布在多个服务器或容器中,监控、日志记录、调试和故障排查变得更加复杂。需要借助监控工具(如 Prometheus、ELK 等)和服务治理工具(如 Kubernetes、Istio)来解决。

  • 服务间通信开销: 微服务之间通过网络通信(如 HTTP、gRPC),这增加了系统的通信开销和延迟,尤其是当服务之间的调用链较长时。

  • 部署与协调: 管理多个微服务的部署和协调是个挑战。引入容器化(如 Docker)和编排工具(如 Kubernetes)可以简化这一过程,但也需要额外的学习和运维成本。

微服务与传统单体架构的比较

特性 单体架构 微服务架构
模块化 所有功能都在一个代码库中 每个功能作为独立服务
部署 单一部署,更新必须重新部署整个应用 独立部署,可以单独更新某个服务
扩展性 高耦合,代码难以拆分 松耦合,服务间通过 API 通信
耦合度 高耦合,代码难以拆分 松耦合,服务间通过 API 通信
数据管理 共享数据库,跨模块数据容易访问 独立数据库,数据一致性管理更复杂
故障隔离 整个应用共享资源,部分故障可能影响全局 某个服务故障不会导致整个系统崩溃
开发速度 适合小团队,开发初期速度快 适合大团队,开发可以并行

典型的微服务技术栈

  • API Gateway:如 Nginx、Kong、Traefik,处理服务间通信和路由。
  • 服务发现:如 Consul、Eureka,帮助服务自动注册和发现。
  • 容器化与编排:如 Docker、Kubernetes,管理服务的部署、扩展、监控。
  • 通信协议:如 REST、gRPC、GraphQL,定义服务间通信规范。
  • 服务监控:如 Prometheus、Grafana,监控服务健康状况和性能。
  • 消息队列:如 RabbitMQ、Kafka,用于异步通信和事件驱动架构。

实现分页

确定分页参数

页面大小(pageSize):表示每页显示的数据条数。
当前页码(pageNumber):表示当前要显示的页面编号。

使用 skip 和 limit 方法(MongoDB)

skip 方法用于跳过指定数量的文档,limit 方法用于限制返回的文档数量。
例如,要获取第 2 页,每页显示 10 条数据:
不同的 NoSQL 数据库可能有不同的方法来实现分页,但基本思路是类似的,即通过跳过一定数量的文档并限制返回的文档数量来实现分页效果。

edge 表查询

边(edge)表用于表示两个节点(vertex)之间的关系。通过查询边表,可以获取节点之间的关系信息。这种查询的核心原理是根据指定的条件,从边表中筛选出符合要求的边,并进一步关联节点来获取结果。
边表通常包含以下关键字段:

  • Edge ID:边的唯一标识符。
  • From Vertex:边的起始节点 ID。
  • To Vertex:边的目标节点 ID。
  • Edge Type:边的类型,表示关系的种类(例如“朋友”、“喜欢”、“工作于”等)。
  • Attributes:边的属性,可以包含时间戳、权重、描述等。

事务

数据库的事务(Transaction)是指在数据库管理系统中,一组作为单个工作单元执行的操作。事务具有四个重要的性质,简称为 ACID 属性(Atomicity、Consistency、Isolation、Durability)。通过事务,数据库能够确保数据的一致性、完整性,并且能够正确处理并发操作和系统故障。

事务的四个 ACID 性质

原子性(Atomicity)

  • 原子性意味着事务中所有的操作要么全部执行成功,要么全部不执行,如果事务中某一步失败了,系统会回滚到事务开始之前的状态,保证数据的一致性。
  • 例子:银行转账事务,如果 A 向 B 转账 $100,那么必须保证从 A 的账户扣除 $100 并且 B 的账户增加 $100 这两个操作都成功执行。如果扣除成功但增加失败,事务会回滚,A 的账户不会扣款。

一致性(Consistency)

  • 一致性确保事务在执行前后,数据库都保持一致的状态,事务执行完后,数据库的状态必须满足所有定义的规则(如主键、外键、约束等)。
  • 例子: 在数据库中,转账前后的账户余额总和应该保持不变,不能因为某个事务导致总金额的改变。

隔离性(Isolation)

  • 隔离性保证多个并发事务的执行互不干扰,事务之间是相互隔离的。即使有多个事务同时运行,每个事务看到的数据都是一致的,不会被其他事务未提交的中间状态影响。每个事务都有自己的隔离级别,事务之间的隔离级别可以是串行或并行。
  • 例子: 当一个用户在更新账户余额时,另一个用户进行查询操作时,应该看不到未提交的部分修改,查询结果要么是事务开始前的值,要么是事务提交后的新值。

持久性(Durability)

  • 持久性确保事务一旦提交,修改的数据就会永久保存到数据库中,哪怕系统出现故障或崩溃,数据也不会丢失。

例子:如果一个事务成功提交了转账操作,哪怕数据库服务器之后出现故障,已完成的转账记录依然会被保存下来。

事务的生命周期

  • 开始事务:事务从用户发出的一组 SQL 语句开始。
  • 执行操作: 事务内部的 SQL 操作按照顺序执行。
  • 提交事务: 事务成功完成所有操作后,将数据写入数据库。
  • 回滚事务: 如果事务中出现错误,或者用户主动回滚事务,事务将被撤销,数据恢复到事务开始之前的状态。

事务的隔离级别:

不同的隔离级别影响事务之间的并发控制和数据可见性。常见的隔离级别包括:

  • 读未提交(Read Uncommitted): 事务可以读取其他未提交事务的数据,这可能会导致脏读问题。
  • 读已提交 (Read Committed):事务只能读取其他已提交事务的数据,避免脏读问题,但可能出现不可重复读,即同一个事务在不同的时间点读取到的值不同。
  • 可重复读(Repeatable Read):事务在读取数据时,会锁定数据,避免了不可重复读问题,但可能出现幻读,即同一个事务在不同的时间点读取到的数据数量不同。
  • 可串行化(Serializable):事务在读取数据时,会锁定数据,避免了所有并发问题,但可能导致性能下降。

事务的用途

事务广泛用于需要确保数据一致性和可靠性的操作场景,特别是在涉及多个数据修改的情况下,如银行转账、订单处理、库存管理等。

ArangoDB

在 ArangoDB 中,事务提供了一种安全操作多个集合的方式,以确保数据的一致性。使用事务可以确保一组操作要么全部执行成功,要么在出错时回滚。ArangoDB 支持 JavaScript API 和 AQL(Arango Query Language)来执行事务操作。

使用事务的基本步骤

在 ArangoDB 中,事务主要涉及以下步骤:

指定读写集合:定义需要参与事务的集合。
编写事务函数:定义具体的操作逻辑。
提交或回滚事务:根据操作结果,决定是否提交事务。

ArangoDB 中的事务语法

JavaScript 事务:通过 ArangoDB 的 JavaScript API,可以在事务中执行多步操作。
AQL 事务:通过 AQL 查询,可以执行一些简单的事务操作。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
const db = require("@arangodb").db

function transferFunds() {
const fromUserId = "A"
const toUserId = "B"
const amount = 100

// 开始事务,指定要写入的集合
const trx = db._executeTransaction({
collections: {
write: ["accounts"], // 要写入的集合
},
action: function () {
const accounts = db._collection("accounts")

// 获取用户 A 的账户
const fromUser = accounts.document(fromUserId)
if (fromUser.balance < amount) {
throw new Error("Insufficient balance")
}

// 获取用户 B 的账户
const toUser = accounts.document(toUserId)

// 更新用户 A 的余额
accounts.update(fromUserId, { balance: fromUser.balance - amount })

// 更新用户 B 的余额
accounts.update(toUserId, { balance: toUser.balance + amount })
},
})

return "Transfer completed"
}

// 执行转账事务
transferFunds()
  • db._executeTransaction: 启动事务,定义所需的读写集合。在这个示例中,accounts 集合是写集合,因为我们会更新账户余额。
  • 事务函数 (action):在这个匿名函数中定义了事务的逻辑:
    • 检查用户 A 的余额是否足够,如果不足,会抛出错误并回滚事务。
    • 更新用户 A 的余额,将转出金额从账户中扣除。
    • 更新用户 B 的余额,将转入金额添加到账户中。
  • 回滚与提交:
    • 如果发生任何错误(例如余额不足),事务将自动回滚。
    • 如果操作顺利执行,事务会自动提交。

数据库ORM

ORM(Object-Relational Mapping,对象关系映射)​​ 是一种编程技术,用于在 ​面向对象编程语言​(如 Python、Java、C#、JavaScript)和 ​关系型数据库​(如 MySQL、PostgreSQL、Oracle)之间建立桥梁。它通过将数据库中的表(Table)映射为程序中的类(Class)、表的行(Row)映射为对象(Object)、表的列(Column)映射为对象的属性(Property),使开发者能够用面向对象的方式操作数据库,而无需直接编写 SQL 语句。

ORM 的核心优点

提高开发效率

​无需手写 SQL:ORM 自动生成 SQL 语句,开发者只需操作对象,减少重复的数据库操作代码。
​代码简洁:用面向对象的方式(如 user.save())替代冗长的 SQL 语句(如 INSERT INTO users (name, email) VALUES (…))。
​快速迭代:在业务逻辑复杂或需求频繁变更时,ORM 能更快适应变化。

代码可维护性

​抽象数据库细节:业务逻辑与数据库操作解耦,代码更清晰。
​统一代码风格:所有数据库操作通过 ORM 接口完成,避免 SQL 语句分散在代码各处。

跨数据库兼容

​无缝切换数据库:ORM 封装了不同数据库的 SQL 方言,例如从 MySQL 切换到 PostgreSQL 时,只需修改配置,无需重写 SQL 代码。
​支持多种数据库:主流 ORM 框架(如 SQLAlchemy、TypeORM)支持 MySQL、PostgreSQL、SQLite 等。

防止 SQL 注入

​参数化查询:ORM 自动对用户输入进行转义,避免拼接 SQL 字符串导致的安全漏洞(如 user.query.filter_by(name=user_input) 是安全的)。

高级功能支持

​事务管理:通过简单的 API(如 session.commit())处理复杂的事务。
​关联关系处理:轻松定义一对多、多对多关系(如 User 和 Order 的关联)。
​数据迁移工具:部分 ORM(如 Django ORM)提供数据库迁移工具,自动生成表结构变更脚本。

更好的抽象与复用

​模型复用:通过继承或组合复用模型逻辑(如基类 BaseModel 定义公共字段)。
​查询链式调用:支持链式方法调用构建复杂查询(如 User.query.filter(…).order_by(…).limit(10))。

主流 ORM 框架示例

语言 ORM 框架 特点
Python Django ORM、SQLAlchemy Django ORM 高度集成,SQLAlchemy 灵活
Java Hibernate 企业级应用,支持 JPA 标准
JavaScript TypeORM、Sequelize TypeORM 支持 TypeScript,语法优雅
C# Entity Framework .NET 官方推荐,功能强大

0%