0%

Kafka和Elasticsearch概念对照
Kafka 和 Elasticsearch(ES)在存储和分布式架构上有很多相似之处,尽管它们设计目标不同。Kafka 是一个分布式流处理平台,侧重于消息的发布与订阅,而 Elasticsearch 是一个分布式搜索和分析引擎,侧重于存储和查询结构化或非结构化数据。但在一些核心概念上,两者确实有相似之处。以下是它们的概念对照:


Kafka Elasticsearch 对应关系与描述
Topic Index 都是数据的逻辑分类单位。Kafka 的 Topic 用于存储一类消息,ES 的 Index 用于存储一类文档。
Partition Shard 分区和分片是分布式存储的基本单位,负责将数据分布到多个节点上以实现并行处理和高可用性。
Replica Replica 两者的副本机制都是为了容灾和高可用。Kafka 为分区创建副本,ES 为分片创建副本。
Broker Node Kafka 的 Broker 和 ES 的 Node 都是集群的基本组成节点,负责数据的存储和处理。
Controller Master Node Kafka 的 Controller 和 ES 的 Master Node 都是集群的管理节点,负责分区或分片的分配、元数据的协调等任务。
Producer Indexer Producer 向 Kafka 写入消息,相当于 Indexer 向 Elasticsearch 写入文档。
Consumer Search Client Consumer 从 Kafka 消费消息,相当于 Search Client 从 Elasticsearch 查询数据。
Consumer Group Query Distributing Kafka 的 Consumer Group 是消费负载均衡的单位,类似于 ES 的查询在多个节点上的分发和协调机制。
Offset _id 或 Scroll Cursor Kafka 的 Offset 用于追踪消息消费进度,类似于 Elasticsearch 的文档唯一标识符 _id 或滚动查询(Scroll API)的游标。
Log Segment Kafka 中的日志文件(Log)对应 ES 中的分段(Segment),都是底层存储单位,并且采用不可变文件的方式进行存储。
Retention Policy Index Lifecycle Management Kafka 的消息保留策略(按时间或大小)与 Elasticsearch 的索引生命周期管理(如冷存储、过期删除等)类似,用于管理数据的存储周期。
Rebalance Reallocation Kafka 的 Rebalance 和 ES 的 Reallocation 都是分区或分片在节点间重新分配的过程,用于应对节点加入、退出或故障。
ZooKeeper / Kafka Metadata Cluster State Kafka 使用 ZooKeeper 或内部元数据管理集群状态,ES 使用 Cluster State 保存分片、节点等元数据信息。

深入比较:核心存储机制

  • 数据存储

    • Kafka:以日志为核心,数据写入后只能追加,且有明确的保留时间或大小限制。
    • Elasticsearch:基于倒排索引和列式存储,支持快速查询和全文搜索。
  • 查询与消费

    • Kafka:数据按 Offset 顺序读取,不支持复杂查询。
    • Elasticsearch:支持丰富的查询 DSL,可以根据字段、全文、聚合等多种方式查询。
  • 容灾机制

    • Kafka:通过分区副本(Replication)实现容灾,Leader 分区负责读写,Follower 分区用于备份。
    • Elasticsearch:通过分片副本(Replica)实现容灾,所有副本都可以提供读服务。

总结

Kafka 和 Elasticsearch 的架构设计虽然有许多相似之处,但它们的用途不同:

  • Kafka:更适合消息的高吞吐生产与消费,擅长实时流处理。
  • Elasticsearch:更适合海量数据的快速检索与分析,擅长全文搜索与聚合查询。

这种相似性使得两者经常组合使用,例如 Kafka 用于流数据传输,Elasticsearch 用于后续的存储和分析。

OAuth2.0
OAuth 2.0 是一个广泛使用的授权框架,允许用户授权第三方应用访问其在服务提供者(如 Google、Facebook、GitHub 等)上的受保护资源,而无需分享其用户名和密码。下面是 OAuth 2.0 的基本授权流程,我们以一个典型的 “用户通过 Google 账户登录第三方应用” 的场景为例:

OAuth 2.0 的授权流程(典型授权码授权流程)

假设你想使用一个第三方应用(例如:一个待开发的任务管理应用),它要求访问你的 Google 日历,OAuth 2.0 就是用来处理这类授权的协议。

流程步骤:

1. 用户发起授权请求

用户访问第三方应用的某个功能,第三方应用请求获取访问用户在 Google 上的某些数据(例如:Google 日历数据)。为了访问这些数据,第三方应用必须首先获得授权。

  • 第三方应用会将用户重定向到 Google 的授权服务器。
  • 重定向的 URL 中包含必要的参数:
    • client_id:第三方应用的标识符,用于区分不同的客户端。
    • redirect_uri:用户授权后,Google 重定向到的回调地址。
    • response_type:通常是 code,表示请求授权码。
    • scope:请求的权限范围,决定了第三方应用可以访问哪些用户资源(如 https://www.googleapis.com/auth/calendar)。
    • state:防止跨站请求伪造(CSRF)攻击的随机字符串。

请求示例:

1
2
3
4
5
6
GET https://accounts.google.com/o/oauth2/v2/auth?
client_id=YOUR_CLIENT_ID
&redirect_uri=https://yourapp.com/oauth2callback
&response_type=code
&scope=https://www.googleapis.com/auth/calendar
&state=xyz123

2. 用户授权

  • 用户被引导到 Google 的授权页面,在该页面上,Google 会询问用户是否允许第三方应用访问其 Google 日历。
  • 用户可以选择“允许”或“拒绝”授权。如果用户允许,Google 会将用户重定向回第三方应用指定的 redirect_uri,并附带一个授权码(Authorization Code)。

重定向示例:

1
2
3
https://yourapp.com/oauth2callback?
code=AUTHORIZATION_CODE
&state=xyz123

3. 客户端请求访问令牌

  • 第三方应用(客户端)收到授权码后,接着通过向 Google 的授权服务器发起请求来交换访问令牌(Access Token)。
  • 这个请求需要包含以下信息:
    • client_id:第三方应用的标识符。
    • client_secret:第三方应用的密钥,用于验证其身份。
    • code:从重定向中获得的授权码。
    • redirect_uri:必须与授权请求时提供的重定向 URI 完全一致。
    • grant_type:通常是 authorization_code,表示通过授权码换取令牌。

请求示例:

1
2
3
4
5
6
7
8
POST https://oauth2.googleapis.com/token
Content-Type: application/x-www-form-urlencoded

client_id=YOUR_CLIENT_ID
&client_secret=YOUR_CLIENT_SECRET
&code=AUTHORIZATION_CODE
&redirect_uri=https://yourapp.com/oauth2callback
&grant_type=authorization_code

4. 授权服务器返回访问令牌

  • Google 的授权服务器会验证请求,并返回一个包含访问令牌的响应。访问令牌可以用于访问 Google API,获得用户授权的资源(如 Google 日历数据)。
  • 除了 access_token,响应中通常还会包含 expires_in(令牌的有效期,通常是一个小时)和 refresh_token(刷新令牌,用于获取新的访问令牌)。

响应示例:

1
2
3
4
5
6
{
"access_token": "ACCESS_TOKEN",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": "REFRESH_TOKEN"
}

5. 客户端使用访问令牌访问资源

  • 第三方应用可以使用获得的 access_token 来访问用户授权的资源(如 Google 日历数据)。
  • 在每个请求中,客户端将 access_token 作为 HTTP 请求头的一部分发送给 Google API。

请求示例:

1
2
GET https://www.googleapis.com/calendar/v3/calendars/primary/events
Authorization: Bearer ACCESS_TOKEN

Google 会验证令牌,如果令牌有效,API 就会返回用户的日历数据。

6. 令牌过期与刷新

  • 访问令牌有时效性,一旦过期,客户端可以使用 refresh_token 来获取一个新的访问令牌,而无需再次请求用户授权。
  • 使用 refresh_token 刷新访问令牌的请求格式如下:
1
2
3
4
5
6
7
POST https://oauth2.googleapis.com/token
Content-Type: application/x-www-form-urlencoded

client_id=YOUR_CLIENT_ID
&client_secret=YOUR_CLIENT_SECRET
&refresh_token=REFRESH_TOKEN
&grant_type=refresh_token

响应示例:

1
2
3
4
5
{
"access_token": "NEW_ACCESS_TOKEN",
"token_type": "Bearer",
"expires_in": 3600
}

总结流程

  1. 用户请求授权:第三方应用将用户重定向到授权服务器(如 Google)以请求授权。
  2. 用户授权:用户在授权页面同意授权后,授权服务器返回授权码。
  3. 交换访问令牌:第三方应用使用授权码请求访问令牌。
  4. 获取用户数据:第三方应用使用访问令牌请求用户数据。
  5. 令牌刷新(可选):访问令牌过期时,第三方应用使用刷新令牌获取新的访问令牌。

其他授权方式

除了授权码授权(Authorization Code Grant)外,OAuth 2.0 还定义了其他授权方式,如:

  • 简化授权流程(Implicit Grant):用于浏览器端应用,令牌直接通过 URL 传递。
  • 客户端凭证授权(Client Credentials Grant):用于机器对机器的通信,没有用户参与。
  • 密码授权(Resource Owner Password Credentials Grant):用户提供用户名和密码,客户端直接获取访问令牌,不推荐用于公共应用。

这些不同的授权方式适应不同的场景,但授权码授权是最常用、最安全的一种。

总结:

OAuth 2.0 的流程包括授权请求、用户授权、访问令牌交换和资源访问等多个步骤,确保了第三方应用能够安全地访问用户的受保护资源,而不需要直接获取用户的凭证。

负载和占用百分比

假设你有一台 32 核的服务器,如果 Load Average 为 8,意味着在这 1 分钟的时间内,系统平均有 8 个任务正在运行或等待。由于你有 32 个核心,意味着 CPU 仍然有足够的资源去处理这些任务,系统没有过载。

如果 Load Average 大于 32(例如达到 40、50),这才表明任务超过了 CPU 的承载能力,有许多任务在排队等待执行,系统可能出现性能问题。

在 top 命令输出中,%CPU 是按单核的使用率计算的,即:

100% 的 CPU 使用率表示该进程占用了一个 CPU 核心的全部资源。
如果有 32 核 CPU,理论上一个进程的 %CPU 值最高可以达到 3200%,也就是占满所有 32 个核心。

AST 抽象语法树示例

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
`-FunctionDecl 0x12d0ffa20 <hello.c:2:1, line:11:1> line:2:5 main 'int (int, char **)'
|-ParmVarDecl 0x12d0ff800 <col:10, col:14> col:14 argc 'int'
|-ParmVarDecl 0x12d0ff900 <col:20, col:31> col:26 argv 'char **':'char **'
`-CompoundStmt 0x12d0fff68 <col:33, line:11:1>
|-DeclStmt 0x12d0ffb70 <line:3:5, col:17>
| `-VarDecl 0x12d0ffae8 <col:5, col:15> col:9 used age 'int' cinit
| `-IntegerLiteral 0x12d0ffb50 <col:15> 'int' 45
|-IfStmt 0x12d0fff08 <line:4:5, line:9:5> has_else
| |-BinaryOperator 0x12d0ffc60 <line:4:9, col:21> 'int' '>='
| | |-ImplicitCastExpr 0x12d0ffc48 <col:9> 'int' <LValueToRValue>
| | | `-DeclRefExpr 0x12d0ffb88 <col:9> 'int' lvalue Var 0x12d0ffae8 'age' 'int'
| | `-BinaryOperator 0x12d0ffc28 <col:16, col:21> 'int' '+'
| | |-BinaryOperator 0x12d0ffbe8 <col:16, col:19> 'int' '+'
| | | |-IntegerLiteral 0x12d0ffba8 <col:16> 'int' 17
| | | `-IntegerLiteral 0x12d0ffbc8 <col:19> 'int' 8
| | `-IntegerLiteral 0x12d0ffc08 <col:21> 'int' 20
| |-CompoundStmt 0x12d0ffdc0 <col:25, line:6:5>
| | `-CallExpr 0x12d0ffd68 <line:5:9, col:35> 'int'
| | |-ImplicitCastExpr 0x12d0ffd50 <col:9> 'int (*)(const char *, ...)' <FunctionToPointerDecay>
| | | `-DeclRefExpr 0x12d0ffc80 <col:9> 'int (const char *, ...)' Function 0x12d0e5588 'printf' 'int (const char *, ...)'
| | `-ImplicitCastExpr 0x12d0ffda8 <col:16> 'const char *' <NoOp>
| | `-ImplicitCastExpr 0x12d0ffd90 <col:16> 'char *' <ArrayToPointerDecay>
| | `-StringLiteral 0x12d0ffcd8 <col:16> 'char[17]' lvalue "Hello old man!\\n"
| `-CompoundStmt 0x12d0ffef0 <line:7:9, line:9:5>
| `-CallExpr 0x12d0ffe98 <line:8:9, col:37> 'int'
| |-ImplicitCastExpr 0x12d0ffe80 <col:9> 'int (*)(const char *, ...)' <FunctionToPointerDecay>
| | `-DeclRefExpr 0x12d0ffdd8 <col:9> 'int (const char *, ...)' Function 0x12d0e5588 'printf' 'int (const char *, ...)'
| `-ImplicitCastExpr 0x12d0ffed8 <col:16> 'const char *' <NoOp>
| `-ImplicitCastExpr 0x12d0ffec0 <col:16> 'char *' <ArrayToPointerDecay>
| `-StringLiteral 0x12d0ffe38 <col:16> 'char[19]' lvalue "Hello young man!\\n"
`-ReturnStmt 0x12d0fff58 <line:10:5, col:12>
`-IntegerLiteral 0x12d0fff38 <col:12> 'int' 0
❯ clang -Xclang -ast-dump -fsyntax-only hello.c > hello.ast


poetry使用

1
2
3
4
5
poetry config virtualenvs.in-project true
poetry config --list
poetry show --tree
poetry install

激活环境是

1
source .venv/bin/activate

在IDE是添加已有的环境,而不是新建环境
Existing

然后再执行一次 poetry install, 依赖就出来了

柯里化是什么意思
ChatGPT
柯里化(Currying)是一种将多参数函数转换为一系列单参数函数的技术。在柯里化中,你可以将一个带有多个参数的函数转换为一系列只接受一个参数的函数,每个函数都返回一个新的函数,直到接受足够数量的参数后才执行原始函数。

下面是一个简单的 JavaScript 示例来说明柯里化的概念:

javascript
Copy code
// 原始的多参数函数
function add(x, y) {
return x + y;
}

// 柯里化函数
function curriedAdd(x) {
return function(y) {
return x + y;
};
}

// 使用柯里化函数
const addTwo = curriedAdd(2);
console.log(addTwo(3)); // 输出 5
在这个例子中,我们有一个原始的多参数函数 add(x, y),它接受两个参数并返回它们的和。然后,我们定义了一个柯里化函数 curriedAdd(x),它接受一个参数 x 并返回一个新的函数,这个新函数接受另一个参数 y,并返回 x + y 的结果。最后,我们使用 curriedAdd(2) 来部分应用函数,得到一个新的函数 addTwo,它等价于 function(y) { return 2 + y; },然后我们可以使用这个新函数来计算 2 + 3 的结果。

柯里化的好处在于它能够将原始的多参数函数转换为一系列单参数函数,这样可以更加灵活地进行函数组合和重用,并且能够方便地进行函数的部分应用。

柯里化 是什么意思,举个例子
ChatGPT
柯里化(Currying)是一种将多参数函数转换为一系列单参数函数的技术。在柯里化中,你可以将一个带有多个参数的函数转换为一系列只接受一个参数的函数,每个函数都返回一个新的函数,直到接受足够数量的参数后才执行原始函数。

下面是一个简单的 JavaScript 示例来说明柯里化的概念:

javascript
Copy code
// 原始的多参数函数
function add(x, y) {
return x + y;
}

// 柯里化函数
function curriedAdd(x) {
return function(y) {
return x + y;
};
}

// 使用柯里化函数
const addTwo = curriedAdd(2);
console.log(addTwo(3)); // 输出 5
在这个例子中,我们有一个原始的多参数函数 add(x, y),它接受两个参数并返回它们的和。然后,我们定义了一个柯里化函数 curriedAdd(x),它接受一个参数 x 并返回一个新的函数,这个新函数接受另一个参数 y,并返回 x + y 的结果。最后,我们使用 curriedAdd(2) 来部分应用函数,得到一个新的函数 addTwo,它等价于 function(y) { return 2 + y; },然后我们可以使用这个新函数来计算 2 + 3 的结果。

柯里化的好处在于它能够将原始的多参数函数转换为一系列单参数函数,这样可以更加灵活地进行函数组合和重用,并且能够方便地进行函数的部分应用。

brew install 如何忽略证书错误

1
2
3
4
5
6
7
8
9
10
11
12
13
14
brew install timothyye/tap/glance                       7s xhs@xhsdeMac-mini 17:51:35
Running `brew update --auto-update`...
==> Fetching timothyye/tap/glance
Error: glance: Failed to download resource "glance"
Failure while executing; `/usr/bin/env /opt/homebrew/Library/Homebrew/shims/shared/curl --disable --cookie /dev/null --globoff --show-error --user-agent Homebrew/4.1.3\ \(Macintosh\;\ arm64\ Mac\ OS\ X\ 13.6.3\)\ curl/8.1.2 --header Accept-Language:\ en --retry 3 --fail --location --silent --head https://download.xiaozhou.xyz/glance-mac64-0.1.tar.gz` exited with 60. Here's the output:
curl: (60) SSL certificate problem: certificate has expired
More details here: https://curl.se/docs/sslcerts.html

curl failed to verify the legitimacy of the server and therefore could not
establish a secure connection to it. To learn more about this situation and
how to fix it, please visit the web page mentioned above.
HTTP/1.1 200 Connection established


ChatGPT
对于 Homebrew,通常情况下它会使用系统中的 curl 或者其他下载工具来下载软件包。因此,要让 Homebrew 忽略证书错误,你可以尝试在运行 brew install 命令之前设置相关的环境变量,让底层的下载工具忽略 SSL 证书验证。

你可以通过设置 HOMEBREW_CURLRC 环境变量来传递 curl 参数。在终端中执行以下命令:

bash
Copy code
export HOMEBREW_CURLRC=1
echo “-k” >> ~/.curlrc
这样做会将 -k 参数添加到 curl 的默认配置文件 ~/.curlrc 中,从而告诉 curl 忽略 SSL 证书验证。然后你再运行 brew install 命令时,Homebrew 应该会使用忽略证书错误的 curl 参数。

请注意,忽略 SSL 证书错误会降低安全性,只应该在调试或者特定情况下使用。