0%

目前仅在 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("---------------------------------------")
阅读全文 »

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"
阅读全文 »

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
阅读全文 »

发布订阅

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

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

发布消息

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

普通订阅

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

缓存穿透、击穿、雪崩

缓存穿透

缓存穿透是指缓存和数据库中都没有的数据, 在高并发下对不存在的 key 的操作. 由于缓存是不命中时被动写的, 并且出于容错考虑, 如果存储层查不到数据则不写入缓存, 这将导致这个不存在的数据每次请求都要到存储层去查询, 失去的缓存的意义. 在流量大时, 可能引起数据库崩溃. 或者有人利用不存在的 key 频繁攻击应用, 可能会引起应用的崩溃

解决办法

  • 接口层增加校验, 如用户鉴权校验、id 做基础校验、 id <= 0 的直接拦截
  • 从缓存取不到的数据, 在数据库中也取不到时,可以将 key-value 写为 key-null, 缓存有效时间设置短点, 这样可以防止攻击用户反复用同一个 key 暴力攻击
  • 布隆过滤器, 类似于一个 hash set, 用于快速判断某个元素是否存在于集合中, 其典型的应用场景就是快速判断一个 key 是否存在于某容器, 不存在就直接返回. 布隆过滤器的关键就在于 hash 算法和容器大小

缓存击穿

缓存击穿是指缓存中没有但数据库中有的数据(一般是缓存时间到期), 在高并发下对同一 key 的操作. 如果在缓存中没有获取到数据, 又同时在数据库中获取到数据, 引起数据库压力过大.

解决办法

  • 设置热点数据永不过期
  • 接口限流与熔断、降级, 重要的接口一定要做好限流策略, 防止用户恶意刷接口, 同时要降级准备, 当接口中的某些服务不可用时, 进行熔断, 失败快速返回机制
  • 加互斥锁

缓存雪崩

缓存雪崩是指缓存中数据大批量到过期时间, 而查询数据量巨大, 引起数据库压力过大甚至崩溃. 和缓存击穿不同的是, 缓存击穿指并发查询同一条数据, 缓存雪崩是不同数据都过期了, 很多数据都查不到从而查询数据库

解决办法

  • 缓存数据的过期时间设置随机, 防止同一时间大量数据过期现象发生
  • 如果缓存数据库是分布式部署, 将热点数据均匀分布在不同的缓存数据库中
  • 设置热点数据永不过期
阅读全文 »

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"
阅读全文 »

Redis

Remote Dictionary Server 即远程字典服务, 是一个开源的使用 ANSI C 语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value 数据库,并提供多种语言的 API, Redis 能读的速度是 11 万次/s,写的速度是 8.1 万次/s
Redis 通常被称为数据结构服务器, 因为它的核心数据类型包括字符串、列表、字典(或哈希)、集合和排序集合等大多编程语言都支持的数据类型. 高版本版的 Redis 还添加了计算基数、地理定位和流处理等高级功能

数据类型

redis-1

阅读全文 »

命令行输出内容变身

格式: \033[显示方式;前景色;背景色 m …… \033[0m

  • \033[ 固定格式
  • \033[0m 非必需, 如果省略表示后面输出内容的样式都会应用当前设置的样式

属性集

前景色 背景色 色值
30 40 黑色
31 41 红色
32 42 绿色
33 43 黄色
34 44 蓝色
35 45 紫红色
36 46 青蓝色
37 47 白色

显示方式

显示方式 表现行为
0 默认
1 高亮
4 下划线
5 闪烁
7 反色
8 不可见
1
2
3
4
5
6
7
8
# 输出字体为绿色的 你好hello world
[root@localhost ~]# printf '\033[1;32m你好hello world\033[0m\n'
# 输出字体为绿色并带有下划线的 你好hello world
[root@localhost ~]# printf '\033[4;32m你好hello world\033[0m\n'
# 输出背景色为绿色的 你好hello world
[root@localhost ~]# printf '\033[7;32m你好hello world\033[0m\n'
# 输出内容不可见
[root@localhost ~]# printf '\033[8;32m你好hello world\033[0m\n'
阅读全文 »