0%

可读流

ReadableStream

创建并从给定的 Handler 返回一个可读流对象

RS 构造方法

创建并从给定的处理程序返回一个可读的流对象

可读流配置项

underlyingSource 可选的定义可读流的行为方式的配置项

  • start(controller) 由开发人员定义, 当流对象被创建时立刻调用, 执行其他任何必须的设置流功能, 如果过程是异步的则返回一个 Promise
    • controller 根据 type='bytes' 属性传递的 ReadableStreamDefaultControllerReadableByteStreamController 控制器实例
  • pull(controller) 由开发人员定义, 当流的内部队列不满时, 会重复调用这个方法, 直到队列补满
  • cancel(reason) 由开发人员定义, 当该流被取消时调用
  • type 控制正在处理的可读类型的流, 默认 ReadableStreamDefaultController, type='bytes' 表示 ReadableByteStreamController
  • autoAllocateChunkSize 开启流自动分配缓冲区, 使用正整数设置
阅读全文 »

目前仅在 chrome 86 (edge 86, opera 72)及以上版本支持, safari 和 firefox 暂时不支持

允许 Web 应用程序从用户设备的本地文件系统中操作文件, 它为 Web 应用程序提供了更多的灵活性和功能, 使其更接近于本地应用程序的体验

File System API 遵循同源策略, 只允许 Web 应用程序在具有相同源的文件系统上进行操作, 当使用该 API 时, 会提示用户授权应用程序访问文件系统

  • 将文件从本地文件系统上传到 Web 应用程序
  • 将 Web 应用程中的数据写入到本地文件系统中
  • 在用户的本地文件系统中创建、重命名和删除文件
  • 读取本地文件系统上的文件内容
1
2
3
4
5
6
7
8
9
/**
* 继承
* FileSystemHandle
* <- FileSystemFileHandle
* <- FileSystemDirectoryHandle
* FileSystemSyncAccessHandle
* WritableStream
* <- FileSystemWritableFileStream
*/

window.showOpenFilePicker, window.showSaveFilePicker, window.showDirectoryPicker API 只能由用户行为触发, 程序主动调用报安全错误
SecurityError: Failed to execute ‘showDirectoryPicker’ on ‘Window’: Must be handling a user gesture to show a file picker.

createSyncAccessHandle(), FileSystemSyncAccessHandle 只能在专用的 web worker 中使用

navigator.storage 只读属性返回一个单例的 StorageManager 对象, 只能在 HTTPS 中使用

FileSystemHandle接口

是 File System API 表示文件或目录条目的对象, 多个句柄可以代表同一个条目,通常情况下, 使用它的子接口 FileSystemFileHandleFileSystemDirectoryHandle

阅读全文 »

Lua 是一门强大、快速、轻量的嵌入式动态类型脚本语言, 使用 ANSI C 语言编写并以源代码形式开放, 其设计目的是为了嵌入应用程序中, 从而为应用程序提供灵活的扩展和定制功能

数据类型

Lua 有八种基本数据类型: nil、boolean、number、string、function、userdata、thread、table

  • nil 表示一个有意义的值不存在时的状态, nil 和 false 逻辑表达式中都表示假, 其他任何值都表示真
  • userdata 表示任意存储在变量中的 C 数据, 完全用户数据: 指一块由 Lua 管理的内存对应的对象; 轻量用户数据: 指一个简单的 C 指针
  • table 本质是一个关联数组, 数组的索引可以是数字、字符串或表类型, 下标默认从 1 开始, table 可以包含任何类型的值(nil 除外), 任何键的值若为 nil 就不会被记入表内, table 的创建通过 构造表达式 {} 完成

table、function、thread、userdata 在 Lua 中是引用类型, 对其操作都是针对引用而不是针对值的操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
print("数据类型: nil boolean number string userdata function trhead table")
print("nil 表示一个无效值(在条件表达式中相当于false)")
print("boolean 表示 true 和 false, 除了 nil 和 false 值表示为 false, 其他值(包括0)都为 true, ")
print("number 表示双精度类型的实浮点数, 数字字符串相加将转换成数字相加")
print("string 表示一对双引号或者单引号包含的内容, [[ 内容 ]] 表示块字符串, .. 字符串拼接, # 计算字符串或表的长度")
print("userdata 表示任意存储在变量中的 C 数据结构")
print("function 由 C 或 Lua 编写的函数")
print("thread 表示执行的独立线程, 用于执行协同程序")
print("table 其实是一个关联数组, 数组的索引可以是数字、字符串或者表类型, 下标默认从 1 开始, table 的创建通过'构造表达式'完成, 空表: {}")
print("---------------------------------------")

print("变量的三种类型: 全局变量, 局部变量(local 声明), 表中的域")
print("变量批量赋值时, 多余的变量会赋值为 nil, 多余的值会被忽略")
print("---------------------------------------")
阅读全文 »

主从复制

将一台 Redis 服务器的数据,复制到其他的 Redis 服务器. 前者称为主节点(Master/Leader),后者称为从节点(Slave/Follower), 数据的复制是单向的!只能由主节点复制到从节点(主节点以写为主、从节点以读为主)—— 读写分离.
===每台 Redis 服务器都是主节点===
一个主节点可以有 0 个或者多个从节点, 但每个从节点只能有一个主节点

1
2
3
4
5
6
7
8
9
10
11
12
13
127.0.0.1:6379> INFO replication # 当前副本的信息
# Replication
role:master
connected_slaves:0
master_failover_state:no-failover
master_replid:e49c9c650c72cd6e3f369365808da6de6efd3825
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:0
second_repl_offset:-1
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0

作用

  • 数据冗余: 主从复制实现了数据的热备份, 是持久化之外的一种数据冗余的方式
  • 故障恢复: 当主节点故障时, 从节点可以暂时替代主节点提供服务, 是一种服务冗余的方式
  • 负载均衡: 在主从复制的基础上, 配合读写分离, 由主节点进行写操作, 从节点进行读操作, 分担节点的负载; 尤其是在多读少写的场景下, 通过多个从节点分担负载, 提高并发量
  • 高可用(集群)基石: 主从复制还是哨兵和集群能够实施的基础

复制原理

Redis 2.8 以上使用 PSYNC 命令完成同步

  1. 从节点向主节点发送 PSYNC 命令, 如果从节点是首次连接主节点时会触发一次全量复制
  2. 接到 PSYNC 命令的主节点会调用 BGSAVE 命令 fork 一个新线程创建 RDB 文件, 并使用缓冲区记录接下来执行的所有写命令
  3. 当 RDB 文件生成完毕后, 主节点向所有从节点发送 RDB 文件, 并在发送期间继续记录被执行的写命令
  4. 从节点接收到 RDB 文件后丢弃所有旧数据并载入这个文件
  5. 主节点将缓冲区记录的所有写命令发送给从节点执行
  6. 如果从节点断开连接后重连, 主节点仅将部分缺失的数据同步给从节点
  • 全量复制: 从节点接收到数据库文件后, 将其全部加载到内存中
  • 增量复制: 主节点将新的所有收集到的修改命令依次传给从节点, 完成同步
阅读全文 »

Redis 函数

Redis 7.0 支持

Redis 函数是临时脚本的进化步骤, 函数提供与脚本相同的核心功能但却是数据库的一流软件工件

Redis 将函数作为数据库的一个组成部分进行管理, 并通过数据持久化和复制确保它们的可用性. 由于函数是数据库的一部分, 因此在使用前声明, 因此应用程序不需要在运行时加载它们, 也不必冒事务中止的风险. 使用函数的应用程序仅依赖于它们的 API, 而不依赖于数据库中的嵌入式脚本逻辑

Redis 函数可以将 Lua 的所有可用功能用于临时脚本, 唯一例外的是 Redis Lua 脚本调试器

Redis 函数还通过启用代码共享来简化开发, 每个函数都属于一个库, 任何给定的库都可以包含多个函数, 库的内容是不可变的, 并且不允许对其功能进行选择性更新. 取而代之的是, 库作为一个整体进行更新, 在一个操作中将它们的所有功能一起更新. 这允许从同一库中的其他函数调用函数, 或者通过使用库内部方法中的公共代码在函数之间共享代码, 这些函数也可以采用语言本机参数

Redis 函数也被持久化到 AOF 文件中, 并从主服务器复制到副本服务器, 因此它们与数据一样可以持久化

Redis 函数的执行是原子的, 函数的执行在其整个时间内阻止所有服务器活动, 类似于事务的语义, 已执行函数的阻塞语义始终适用于所有连接的客户端, 因为运行一个函数会阻塞 Redis 服务器

  • 函数都属于一个库, 任何给定的库都可以包含多个函数
  • 库的内容是不可变的, 并且不允许选择性地更新其函数, 只能将库作为一个整体进行更新

函数命令

  • FUNCTION help 显示 FUNCTION 的帮助信息
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
38
39
40
41
127.0.0.1:6379> FUNCTION help
1) FUNCTION <subcommand> [<arg> [value] [opt] ...]. Subcommands are:
2) LOAD [REPLACE] <FUNCTION CODE>
3) Create a new library with the given library name and code.
4) DELETE <LIBRARY NAME>
5) Delete the given library.
6) LIST [LIBRARYNAME PATTERN] [WITHCODE]
7) Return general information on all the libraries:
8) * Library name
9) * The engine used to run the Library
10) * Library description
11) * Functions list
12) * Library code (if WITHCODE is given)
13) It also possible to get only function that matches a pattern using LIBRARYNAME argument.
14) STATS
15) Return information about the current function running:
16) * Function name
17) * Command used to run the function
18) * Duration in MS that the function is running
19) If no function is running, return nil
20) In addition, returns a list of available engines.
21) KILL
22) Kill the current running function.
23) FLUSH [ASYNC|SYNC]
24) Delete all the libraries.
25) When called without the optional mode argument, the behavior is determined by the
26) lazyfree-lazy-user-flush configuration directive. Valid modes are:
27) * ASYNC: Asynchronously flush the libraries.
28) * SYNC: Synchronously flush the libraries.
29) DUMP
30) Return a serialized payload representing the current libraries, can be restored using FUNCTION RESTORE command
31) RESTORE <PAYLOAD> [FLUSH|APPEND|REPLACE]
32) Restore the libraries represented by the given payload, it is possible to give a restore policy to
33) control how to handle existing libraries (default APPEND):
34) * FLUSH: delete all existing libraries.
35) * APPEND: appends the restored libraries to the existing libraries. On collision, abort.
36) * REPLACE: appends the restored libraries to the existing libraries, On collision, replace the old
37) libraries with the new libraries (notice that even on this option there is a chance of failure
38) in case of functions name collision with another library).
39) HELP
40) Prints this help.
阅读全文 »

Lists 命令

Redis 3.2 之后, List 数据类型底层使用 quickList 代替双向链表和压缩列表

List 是一个有序重复的双向链表, 按照添加的顺序排序, 可以添加一个元素到列表的头部(左边)、尾部(右边), 一个列表最多可以包含 2^32-1(40 多亿) 个元素.

List 类型的底层数据结构是由双向链表压缩列表实现的

  • 如果列表元素的个数小于 512 个,列表每个元素值都小于 64B 时, Redis 使用压缩列表作为底层数据结构
  • 如果列表元素不满足上面的条件, Redis 使用双向链表作为底层数据结构
1
2
3
# 配置底层数据结构存储数量限制
hash-max-listpack-entries 512
hash-max-listpack-value 64

添加元素

LPUSH 和 LPUSHX 命令将多个元素逆序插入到列表头部

  • LPUSH key element [element …] 批量添加多个元素到列表头部并返回列表的长度, 列表为空或者不存在新建
  • LPUSHX key element [element …] 批量添加多个元素到已存在的列表头部并返回列表的长度, 列表为空或者不存在返回 0
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
127.0.0.1:6379> LPUSH list:zhang name1 name2 name3
(integer) 3
127.0.0.1:6379> LPUSHX list:zhang name1 name4 name5 name6
(integer) 7
127.0.0.1:6379> LPUSH list:zhang name1 name4 name5 name6
(integer) 11

# LPUSH 和 LPUSHX 命令将多个元素**逆序**插入到列表头部
127.0.0.1:6379> LRANGE list:zhang 0 11
1) "name6"
2) "name5"
3) "name4"
4) "name1"
5) "name6"
6) "name5"
7) "name4"
8) "name1"
9) "name3"
10) "name2"
11) "name1"

# LPUSHX 对空列表或不存在的列表不进行操作
127.0.0.1:6379> LPUSHX list:zhang:1 name1 name2 name3
(integer) 0
127.0.0.1:6379> KEYS *
1) "list:zhang"
2) "age"
3) "name"
4) "hash:zhang"
阅读全文 »

发布订阅

Redis 发布/订阅(pub/sub)是一种消息通信模式: 发送者(pub)发送消息, 订阅者(sub)接收消息
它采用事件作为基本的通信机制,提供大规模系统所要求的松散耦合的交互模式: 订阅者(如客户端)以事件订阅的方式表达出它有兴趣接收的一个事件或一类事件;发布者(如服务器)可将订阅者感兴趣的事件随时通知相关订阅者
订阅者对一个或多个频道感兴趣,只需接收感兴趣的消息,不需要知道什么样的发布者发布的. 这种发布者和订阅者的解耦合可以带来更大的扩展性和更加动态的网络拓扑

  • 发布者: 无需独占链接, 可以在 publish 发布消息的同时, 使用同一个链接进行其他操作
  • 订阅者: 需要独占链接, 在 subscribe 期间, 以阻塞的方式等待消息

发布消息

  • PUBLISH channel message 给指定的频道发送消息并返回接收到消息的订阅者数量, 0 表示没有订阅者
  • SPUBLISH shardchannel message 给指定的碎片频道发送消息并返回接收到消息的订阅者数量, 0 表示没有订阅者, 7.0.0 支持

普通订阅

  • SUBSCRIBE channel [channel …] 订阅指定频道立即进入阻塞状态等待接收消息
  • UNSUBSCRIBE [channel [channel …]] 根据给定频道取消客户端订阅, 如果未指定则取消所有频道订阅
阅读全文 »

HyperLogLog

HyperLogLog 是用来做基数统计的算法, 优点是在输入元素的数量或者体积非常大时, 计算基数所需的空间总是固定的、并且是很小的. 每个 HyperLogLog 键只需要花费 12KB 内存, 就可以计算接近 2^64 个不同元素的基数, 并产生标准误差接近于 0.81% 的近似值, 因为 HyperLogLog 只会根据输入元素来计算基数, 而不会储存输入元素本身

比如数据集 {1, 3, 5, 7, 5, 7, 8}, 那么这个数据集的基数集为 {1, 3, 5 ,7, 8}, 基数(不重复元素)为 5. 基数估计就是在误差可接受的范围内,快速计算基数

  • PFADD key [element [element …]] 添加元素

  • PFCOUNT key [key …] 根据 key 计算基数并返回, 0 表示 key 不存在

1
2
3
4
5
6
7
8
9
10
11
12
127.0.0.1:6379> PFADD hll foo bar zap
(integer) 1
127.0.0.1:6379> PFADD hll zap zap zap
(integer) 0
127.0.0.1:6379> PFADD hll foo bar
(integer) 0
127.0.0.1:6379> PFCOUNT hll
(integer) 3
127.0.0.1:6379> PFADD other-hll 1 2 3
(integer) 1
127.0.0.1:6379> PFCOUNT hll other-hll
(integer) 6
阅读全文 »

Sets 命令

Set 是无序不重复的集合, 集合成员是唯一的, 集合对象的编码可以是 intset 或者 hashtable, 集合是通过哈希表实现的, 最大的成员数为 2^32-1(40 多亿)个成员.

Set: 键名: key, 键类型: set, 键值: string

Set 类型的底层数据结构是由哈希表整数集合实现的

  • 如果集合中的元素都是整数且元素个数小于 512 个, Redis 使用整数集合作为底层数据结构
  • 如果集合中的元素不满足上面条件, Redis 使用哈希表作为底层数据结构
1
2
# 配置底层数据结构存储数量限制
set-max-intset-entries 512

成员操作

  • SADD key member [member …] 向集合中添加多个成员并返回添加成功的数量, 0 表示有重复成员

  • SCARD key 获取集合成员的数量, 集合为空或者不存在返回 0

  • SMEMBERS key 获取集合中所有的成员, 集合为空或者不存在返回 (empty array)

是否包含成员

  • SISMEMBER key member 判断 member 是不是集合的成员, 1 是, 0 不是或者集合为空或者不存在
  • SMISMEMBER key member [member …] 批量判断多个 member 是不是集合的成员, 1 是, 0 不是或者集合为空或者不存在, Redis 6.2.0 支持
1
2
3
4
5
6
7
8
9
10
11
12
13
14
127.0.0.1:6379> KEYS *  # 查看当前数据库中的 key
(empty array)
# 空集合判断是否包含成员
127.0.0.1:6379> SMISMEMBER myset hello hehe
1) (integer) 0
2) (integer) 0
# 向 myset 添加成员
127.0.0.1:6379> SADD myset hello world hehe haha gg
(integer)
# 判断 myset 是否包含成员
127.0.0.1:6379> SMISMEMBER myset hello yy hehe
1) (integer) 1
2) (integer) 0
3) (integer) 1
阅读全文 »

Strings 命令

字符串是基础的 key-value 类型, 存储字节序列, 包括文本、序列化对象和二进制数组, 一个 key 对应一个 value, value 可以是字符串、整数或浮点数, value 最多可以是 512MB.

String 类型的底层的数据结构实现主要是 int 和 SDS(Simple Dynamic String)

因为 C 语言的字符串并不记录自身长度, 所以获取长度的复杂度为 O(n), SDS 结构里用 len 属性记录字符串长度, 所有复杂度为 O(1)

设置值

  • SET key value [NX|XX] [GET] [EX seconds|PX milliseconds|EXAT unix-time-seconds|PXAT unix-time-milliseconds|KEEPTTL]

    为 key 设置字符串的值, 执行成功返回 ok, 每次更新 key 的值时会自动清除过期时间

    • NX 仅当 key 不存在时设置
    • XX 仅当 key 存在时设置
    • EX 过期时间, 单位秒
    • PX 过期时间, 单位毫秒
    • EXAT 过期时间戳, 单位秒
    • PXAT 过期时间戳, 单位毫秒
    • KEEPTTL 保留 key 关联的生存时间
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
127.0.0.1:6379> SET age 18
OK
127.0.0.1:6379> EXPIRE age 100
(integer) 1
127.0.0.1:6379> TTL age
(integer) 98
127.0.0.1:6379> SET age 20
OK
127.0.0.1:6379> TTL age
(integer) -1

# 使用 KEEPTTL 保留 key 关联的生存时间
127.0.0.1:6379> SET age 18 EX 100
OK
127.0.0.1:6379> TTL age
(integer) 98
127.0.0.1:6379> SET age 20 KEEPTTL
OK
127.0.0.1:6379> GET age
"20"
127.0.0.1:6379> TTL age
(integer) 79
  • SETNX key value 当 key 不存在时设置指定 key 的值, 返回值 1 成功, 0 失败
1
2
3
4
5
6
7
8
9
10
11
127.0.0.1:6379> KEYS *
1) "xiaoming"
2) "name"
127.0.0.1:6379> SETNX age 18
(integer) 1
127.0.0.1:6379> SETNX age 18
(integer) 0
127.0.0.1:6379> KEYS *
1) "xiaoming"
2) "age"
3) "name"
  • APPEND key value 在指定 key 末尾(如果为字符串)追加内容, key 不存在同 SET 并返回追加内容的长度
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
127.0.0.1:6379> APPEND age 1
(integer) 3
127.0.0.1:6379> GET age
"181"
127.0.0.1:6379> APPEND addr beijing
(integer) 7
127.0.0.1:6379> KEYS *
1) "xiaoming"
2) "age"
3) "addr"
4) "name"
127.0.0.1:6379> APPEND a hello
(integer) 5
127.0.0.1:6379> APPEND b gg
(integer) 2

过期时间

  • SETEX key seconds value 设置 key 的值并设置过期时间(单位秒), 返回 ok
  • PSETEX key milliseconds value 设置 key 的值的值并设置过期时间(单位毫秒), 返回 ok
1
2
3
4
127.0.0.1:6379> SETEX addr 20 beijing
OK
127.0.0.1:6379> PSETEX addr 20000 beijing
OK

批量设置值

  • MSET key value [key value …] 批量设置 key 的值
  • MSETNX key value [key value …] 批量设置 key 的值且当所有的 key 不存在时, 返回值 1 成功, 0 失败
1
2
3
4
5
6
7
127.0.0.1:6379> KEYS *
1) "age"
2) "name"
3) "hash:zhang"
# 当且仅当所有 key 都不存在时设置成功返回 1
127.0.0.1:6379> MSETNX name zhangsan age 18 addr beijing
(integer) 0
  • SETRANGE key offset value

    覆盖指定 key 的从指定偏移量开始的字符串的一部分, 返回修改后字符串长度, key 不存在则新建

1
2
3
4
127.0.0.1:6379> SETRANG name 1 xyz
(integer) 8
127.0.0.1:6379> GET name
"axyz1234"
阅读全文 »