AWS Lambda 按序处理同一个 Kinesis Shard 中的消息

当 AWS Lambda 由 Kinesis 消息来触发时,一个 Kinesis Shard 会相应启动一个 Lambda 实例,比如说 Kinesis Stream 有 5 个 Shards, 那同时只会启动 5 个 Lambda 实例。那么把多条消息发送到同一个 Kinesis Shard 中去,这些消息会被如何消费呢?答案是按顺消息,不管这些消息是否被不同的 Lambda 实例处理。本文就是关于怎么去理解 https://aws.amazon.com/lambda/faqs/ 的下面那段话的内容:

Q: How does AWS Lambda process data from Amazon Kinesis streams and Amazon DynamoDB Streams?
AWS Lambda 如何处理来自于 Amazon Kinesis 和 DynamoDB 的数据

The Amazon Kinesis and DynamoDB Streams records sent to your AWS Lambda function are strictly serialized, per shard. This means that if you put two records in the same shard, Lambda guarantees that your Lambda function will be successfully invoked with the first record before it is invoked with the second record. If the invocation for one record times out, is throttled, or encounters any other error, Lambda will retry until it succeeds (or the record reaches its 24-hour expiration) before moving on to the next record. The ordering of records across different shards is not guaranteed, and processing of each shard happens in parallel.
从 Kinesis 和 DynamoDB 单个 Shard 上的记录会被 Lambda 严格的按序处理。这意味着如果你送两条记录到相同的 Shard, Lambda 将会保证第一条记录成功处理后才会处理第二条记录。假如处理第一条记录时超时,或超过资源使用上限,或碰到任何错误, Lambda 将会不断重试直到成功(或记录在 24 小时后过期), 而后才会去处理下一条记录。跨 Shard 的记录不保证到达顺序,且是并行处理多个 Shard 来的记录。

可以做几个试验,下面的代码可以保证消息总是被发送到同一个 Kinesis Shard,因为 PartitionKey 参数是一个常量 阅读全文 >>

《Practical Vim》阅读笔记 (4)

一路阅读完第五章直接跳跃到第十章有关宏的内容,宏的录制和回放功能是多数编辑器都会提供,但我却基本不用这一功能。在 Vim 中宏比点号(.) 更有效的处理重复性操作,既然作为一个 Vimer, 以重复操作为耻,因而十分有必要对它加以了解和掌握的,又是一个一分钟上手需一辈子来掌握的东西。

1. 宏是录制在某个寄存器中,用 q{register} 启动录制,例如 qa, 然后执行一系操作,再次按 q 结束录制,第一次回放用 @{register}, 如 @a,以后多次执行上一次宏回放可用 @@.也可以支持数字,如 10@a, 或 10@@:reg a 可查看寄存器 a 中宏的内容

2. 录制宏的一条金律是:确保每一条命令是可重复的。h, j, k, l, 没什么意义,而 0e, A, I 就是可重复的。当回放宏时遇到光标移动失败时, 如光标已在行首,宏中有 h 操作,那么后续的操作被放弃,根据 visualbell 配置可能有响声提示。宏的 motion 失败即放弃的特性让我们在重复执行宏时可以用一个足够大的数字,如 200@@, 反正无副作用

3. 宏的序列执行与并发执行,当用 5@a 执行宏 "a   0f.r)w~j, 其实是把宏放在一个队列里,往下跳行执行,其他任何一行执行失败,后续行将得不到更新。如果针对宏 "a   0f.r)w~, 对选择的多行执行 :'<,'>normal @a 时效果就不一样了,它的意思是针对选择的多行单独执行宏,任何行的失败互不影响,所以它是并发执行的 阅读全文 >>

AWS S3 Key 前缀分布优化数据请求的性能

很早就想写下这篇日志的,因为实际使用 AWS S3 来存取文件使用什么样的 Key 对性能的影响是极其大的。当然,如果你对 S3 的并发请求在 50 以内是无所谓的,要是并发要求很高的话,Key 的选择就变得至关重要的,不可不察。S3 Key 从第一个字符算起的任意长度子字符串都被称作前缀(prefix), 而对 S3 文件访问性能影响不在完整的 Key, 恰恰是那个前缀。

背景:我们最初在使用 S3 时,存储的文件的 Key 直接用了数据库的自增 ID,于是保存到 Bucket 中大概下面那样子的

examplebucket/12134850.csv
examplebucket/12134851.csv
examplebucket/12134852.csv
examplebucket/12134853.csv
examplebucket/12134854.csv
examplebucket/12134855.csv
examplebucket/12134856.csv
examplebucket/12134857.csv
examplebucket/12134858.csv

Bucket 中有百万个文件,当初测试时 60 个左右的 Lambda 实例同时访问这个 Bucket 中不同的文件时,加载每个 S3 文件的时间大约在几百毫秒,然后并发上到 70, 80 后加载同样大小的 S3 文件的时间陡然增加到 10 秒以上,并发继续上到 100 以上直接导致众多 S3 的请求超时。后来了解到虽然一个 Bucket 中放多少个文件是没有限制的,而且官方文档说了文件多了并不影响访问的性能,但背后却有一个文件的分区存储机制,这个才是关键。

S3 的分区存储就像是硬盘分区,或文件分布在不同硬盘上的效果。试想一下,如果我们多个线程同时从一块硬盘上读取数据,每个线程需共同一个磁头来读取数据,性能就差; 但如果那些线程同时从不同的硬盘上读取各自的数据,那性能就大大提升了,它们互不干扰。在使用机械硬盘时我有过这样的体验,在同一个磁盘上拷贝文件比从一个磁盘拷贝到另一个磁盘要慢很多。 阅读全文 >>

《Practical Vim》阅读笔记 (3)

1. 学习完前面的三大模式:正常模式,插入模式和可视模式后,现在步入了命令模式。:, / 或 ?, 和 <C-r>= 分别进入到 Ex 命令,搜索和表达式,它们都被称作命令模式, 以前还常常把正常模式说成是命令模式。: 后的是 Ex 命令,是因为我们仍然沿袭了 Vim 的前身 Ex。我在 Mac 下输入命令 ex 就会看到这个

进入到 Vim 的 Ex mode, 输入 visual 命令就是正常的 Vim 界面。Vim 之于 Ex 就像 Gui 之于 Shell, Vim 的 Ex 命令可以做任何操作,见 :h ex-cmd-index

2. 命令模式在 : 提示符下输入时可以使用插入模式下的很多命令,如 <C-w>, <C-u>, <C-k>, <C-v>, <C-r>{reg}, 甚至是 <C-r>=,就是不能用 motion 命令,光标移得靠方向键

3. 在阅读本章之前对 Vi 的命令模式只能用不觉明厉来形容,它对我的贡献仅仅是 :wq 之类的,模式查找,简单替换,再就是执行一些未设置快捷键插件功能。也一直未理解替换怎么是 %s/abc/dev, 只是依葫芦画瓢,现在终于可以在本章中理解那些命令了。从中真的能体会到 Ex 命令模式的乐趣,Ex 是不会把整个文件内容显示在屏幕上的, Ex 命令通常由 范围 + 命令 组成。

:2           -- 光标跳到第一行,正常模式下可以 2G, 或 2gg
:print    -- 打印当前行的内容

范围和命令一般会写在一块,范围可借用同样意义的特殊字符,默认操作当前行,因此下面一系列的命令就好理解了 阅读全文 >>

Spring 项目中把属性或 SQL 语句写在 .xml 文件中

Spring 项目中把大量的 SQL 分散在 Java 代码中,无 Here Doc 的情况下用加号来连接写着实在是不爽,于是之前思考这个 Spring 项目中把 SQL 语句写在 .sql 文件中 --  把它们写在 *.sql 文件中,但是这个 *.sql 需要特定的格式来标识属性 Key

--!select.user
select id, firstname, lastname, address
--!update.user
update ........

而且还需要一个额外的类 SqlPropertySourceFactory 来解析上面的 *.sql 文件, 识别出 select.user 是 Key, 紧接着后面的块是相应的属性值,用注解引用它时还有点额外的 factory 属性来配置,如

@PropertySource(value = "classpath:sql/queries.sql", factory = SqlPropertySourceFactory.class)

所以一直在思考是否能够再简单些,是否能用一个自定义的注解,如

@SqlPropertySource("classpath:sql/queries.sql")

捉摸了很久,似乎有点难度,不过再不断发掘的过程中找到了这个类 org.springframework.core.io.support.PropertiesLoaderUtils, 有下面的代码片断 阅读全文 >>