0%

systemd

systemd(system daemon)是 linux 下的一种 init 软件, 提供更优秀的框架以表示系统服务间的依赖关系, 并依此实现系统初始化时服务的并行启动, 同时达到降低 shell 的系统开销的效果, 最终代替常用的 System V 与 BSD 风格 init 程序

  • 采用 socket 激活式与总线激活式服务, 以提高相互依赖的各服务的并行运行性能
  • 采用 cgroup 代替 PID 来追踪进程, 依此即使是两次 fork 之后生成的守护进程也不会脱离 systemd 的控制

CGroup

cgroup 是 linux 内核的一个功能, 用来限制、控制与分离一个进程组的资源(如 CPU、内存、磁盘输入输出等)

cgroup 是 linux 内核提供的一种机制, 这种机制可以根据需求把一系列系统任务及其子任务整合(或分隔)到按资源划分等级的不同组内, 从而为系统资源管理提供一个统一的框架. 简单说, cgroup 可以限制、记录任务组所使用的物理资源, 本质上来说, cgroup 是内核附加在程序上的一系列钩子(hook), 通过程序运行时对资源的调度触发相应的钩子以达到资源追踪和限制的目的.

作用

  • 资源限制: cgroup 可以对任务需要的资源总额进行限制, 例如设定任务运行使用的内存上限, 一旦超出就触发 OOM
  • 优先级分配: 通过分配的 CPU 时间片数量和磁盘 IO 带宽, 实际上就等于控制了任务运行的优先级
  • 资源统计: cgroup 可以统计系统的资源使用量, 例如 CPU 使用时长、内存使用量等
  • 任务控制: cgroup 可以对任务执行挂起、恢复等操作
阅读全文 »

敲黑板

onMenuShareAppMessage (微信提示: 即将废弃)

  • jweixin-1.4.0.js
企微(4.0.6) 中使用此 API 的位置
  • 转发
  • 转发给客户
  • 群发到客户群
  • 发表到客户的朋友圈
  • 分享到同事吧
  • 分享到微信
  • 分享到微信朋友圈使用此 onMenuShareTimeline, 但无法设置分享信息
阅读全文 »

Docker 网络

Docker 网络架构源自一种叫作容器网络模型(CNM)的方案, 该方案是开源的并且支持插接式连接

Libnetwork 是 Docker 对 CNM 的一种实现, 提供了 Docker 核心网络架构的全部功能. 不同的驱动可以通过插拔的方式接入 Libnetwork 来提供定制化的网络拓扑

CNM 定义了 3 个基本要素:沙盒(Sandbox)、终端(Endpoint)和网络(Network)

  • 沙盒是一个独立的网络栈, 其中包括以太网接口、端口、路由表以及 DNS 配置
  • 终端就是虚拟网络接口。就像普通网络接口一样,终端主要职责是负责创建连接. 在 CNM 中, 终端负责将沙盒连接到网络
  • 网络是 802.1d 网桥(类似大家熟知的交换机)的软件实现. 因此, 网络就是需要交互的终端的集合, 并且终端之间相互独立

docker 网络采用 veth-pair 技术, 每次启动容器时会自动创建一对虚拟网络设备接口, 一端连着网络协议栈, 一端彼此相连, 停止容器时自动删除, docker0 网卡作为中间的桥梁, 常见的网络模式包含 bridge, host, none, container, overlay 等.

阅读全文 »

敲黑板

vagrant 命令行报错 Encoding::UndefinedConversionError

使用 vagrant 命令时提示 process_builder.rb:44:in `encode!’: “\xE5” to UTF-8 in conversion from ASCII-8BIT to UTF-8 to UTF-16LE (Encoding::UndefinedConversionError)

本例使用的 vagrant 版本为 2.2.10, 安装目录:<br/> D:\HashiCorp\Vagrant\embedded\gems\2.2.10\gems\childprocess-4.0.0\lib\childprocess\windows\process_builder.rb 第 44 行

修改 newstr.encode!(‘UTF-16LE’) 为 <br/> newstr.encode!(‘UTF-16LE’, invalid: :replace, undef: :replace, replace: ‘?’) 参考连接

vagrant 自制 box 启动时 Authentication failure

  • vagrant 2.3.6
  • virtualBox 7.0.8
  • win 11

Authentication failure 是 ssh 登录证书错误, 但虚拟机已经启动完成

  • .ssh/authorized_keys.vagrant/machines/default/virtualbox/private_key 有变化(内容改动/文件存在)
1
2
3
4
5
6
7
8
9
10
11
12
13
...
==> default: Forwarding ports...
default: 22 (guest) => 2222 (host) (adapter 1)
==> default: Booting VM...
==> default: Waiting for machine to boot. This may take a few minutes...
default: SSH address: 127.0.0.1:2222
default: SSH username: vagrant
default: SSH auth method: private key
default: Warning: Authentication failure. Retrying...
default: Warning: Authentication failure. Retrying...
default: Warning: Authentication failure. Retrying...
default: Warning: Authentication failure. Retrying...
...
阅读全文 »

shell 重置密码

  1. 开机按 e 键进入内核编辑
  2. 光标移动到倒数第二段 Linux16 末尾添加 init=/bin/sh
  3. ctrl + x 进行引导启动, 成功进入命令提示界面
  4. 输入 mount -o remount, rw / 挂载根目录
  5. 使用 passwd 命令修改指定用户密码
  6. 直到提示 passwd: all authentication tokens updated successfully.
  7. 输入 touch /.autorelabel 回车
  8. 输入 exec /sbin/init 回车重启系统

命令

  • export 导出全局变量
  • declare 声明变量
  • unset 删除变量
  • local 声明局部变量,一般用于函数内部

单中括号是 POSIX 标准兼容的适用于所有 Unix/Linux 系统, 其他一切双方括号, 双圆括号不是 POSIX 标准兼容的但广泛用于 Bash、Zsh等Shell

PowerShell

dir env: | Get-childItem env: 查看所有的环境变量

$env:[NAME] 查看指定环境变量

设置环境变量

$env:[NAME=VALUE] 仅在当前会话窗口中有效

[System.Environment]::SetEnvironmentVariable(NAME, VALUE, ‘User|Machine’) 永久生效, User 表示用户级别, Machine 表示系统级别

删除环境变量

Remove-Item env:[NAME] 仅在当前会话窗口中有效

[System.Environment]::SetEnvironmentVariable(NAME, $null, “User|Machine”) 永久生效, 将环境变量的设置为 $null

阅读全文 »

敲黑板

启动 nginx 失败

命令行提示错误 98: address already in use

查找系统进程中已存在的 nginx 进程号, 使用 kill -9 $PID 关闭进程后重启 nginx 服务

内置变量

  • $nginx_version nginx 版本

  • $connection_requests TCP 链接当前的请求数量

  • $proxy_protocol_addr 获取代理访问服务器的客户端地址,如果是直接访问,该值为空字符串

    阅读全文 »

敲黑板

  • Package docker-ce is not available, but is referred to by another package.

    如果提示未发现可用的 docker-ce 包时,检查系统镜像源是否正确(如果不能翻墙时, 使用国内的镜像源修改 /etc/apt/source.list)

  • Got permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Get http://%2Fvar%2Frun%2Fdocker.sock/v1.24/images/json: dial unix /var/run/docker.sock: connect: permission denied

    执行 docker 相关命令时提示, 表示 docker 权限不足

    • 使用 sudo 命令运行 docker 命令

    • 将当前用户加入到 docker 组中

1
2
3
4
[root@localhost ~]# cat /etc/group | grep docker
docker:x:994:vagrant
[root@localhost ~]# cat /etc/gshadow | grep docker
docker:!::vagrant
1
2
3
4
5
6
7
8
9
10
groupadd docker # 添加 docker 用户组
gpasswd -a $USER docker # 添加登陆用户到 docker 用户组中
newgrp docker # 更新用户组
或者
usermod -aG docker $USER # 给用户添加一个新的附属组
newgrp docker # 重新登陆组

systemctl restart docker # 重启 docker 服务

systemctl enable docker # 设置 docker 守护进程开机启动
阅读全文 »

–no-sandbox –disable-web-security –user-data-dir=C:\chromedata

fetch() 表单上传时, 不能设置 Content-Type 头, 否则会丢失文件边界

浏览器引擎

浏览器 渲染引擎 js 引擎
IE Trident JScript(IE3.0-IE8.0) / Chakra(IE9~)
Chrome webkit / Blink V8
Safari webkit Nitro(SquirrelFish)
Firefox Gecko ~Monkey 系列(SpiderMonkey / TraceMonkey / JaegerMonkey / OdinMonkey)
Opera WebKit / Blink Carakan

改变原数组的方法

  • pop 从数组中删除最后一个元素,并返回该元素的值(数组为空时返回 undefined). 此方法更改数组的长度
  • push 将一个或多个元素添加到数组的末尾, 并返回该数组的新长度
  • shift 从数组中删除第一个元素,并返回该元素的值(数组为空则返回 undefined). 此方法更改数组的长度
  • unshift 将一个或多个元素添加到数组的开头. 并返回该数组的新长度(该方法修改原有数组)
  • reverse 将数组中元素的位置颠倒, 并返回该数组. 该方法会改变原数组
  • sort 用原地算法对数组的元素进行排序, 并返回数组
    • compareFunction 用来指定按某种顺序进行排列的函数, 省略则按照转换为的字符串的 unicode 位点进行排序
      • firstEl 第一个用于比较的元素
      • secondEl 第二个用于比较的元素
  • splice 通过删除或替换现有元素或者原地添加新的元素来修改数组, 并以数组形式返回被修改的内容. 此方法会改变原数组
    • start 指定修改的开始位置
    • deleteCount 整数, 表示要移除的数组元素的个数, 如果为 0 或者负数, 则不移除元素
    • item1, item2 要添加进数组的元素,从 start 位置开始, 不指定则删除数组元素
  • fill 用一个固定值填充一个数组中从起始索引到终止索引内的全部元素. 不包括终止索引. 返回修改后的数组
    • value 用来填充数组元素的值
    • start 起始索引, 默认值为 0
    • end 终止索引, 默认值为 this.length
  • copyWithin 浅复制数组的一部分到同一数组中的另一个位置, 并返回它, 不会改变原数组的长度. 返回改变后的数组
    • target 整数, 复制序列到该位置, 如果是负数, target 将从末尾开始计算. 如果 target 大于等于 arr.length, 将会不发生拷贝
    • start 整数, 开始复制元素的起始位置, 如果是负数, start 将从末尾开始计算. 如果 start 被忽略, copyWithin 将会从 0 开始复制
    • end 整数, 开始复制元素的结束位置, copyWithin 将会拷贝到该位置, 但不包括 end 这个位置的元素. 如果是负数, end 将从末尾开始计算. 如果忽略则复制到数组结尾
阅读全文 »

TreeWalker

表示文档子树中的节点和它们的位置

  • root 表示对象的根节点
  • whatShow, 默认值: 0xFFFFFFFF, 表示位掩码的 unsigned long, 由 NodeFilter 的常用属性组合而成, 此参数便于筛选出特定类型的节点
    • 0xFFFFFFFF, NodeFilter.SHOW_ALL 显示所有节点
    • 0x2 , NodeFilter.SHOW_ATTIBUTE 显示 Attr 节点
    • 0x80 , NodeFilter.SHOW_COMMENT 显示 Comment 节点
    • 0x1 , NodeFilter.SHOW_ELEMENT 显示 Element 节点
    • 0x4 , NodeFilter.SHOW_TEXT 显示 Text 节点
  • filter, 回调函数或包含 acceptNode() 方法的对象, 其返回值为 NodeFilter.FILTER_ACCEPT, NodeFilter.FILTER_REJECT 或 NodeFilter.FILTER_SKIP
    • NodeFilter.FILTER_ACCEPT 包含此节点
    • NodeFilter.FILTER_REJECT 不包含以此节点为根的子树中的任意节点
    • NodeFilter.FILTER_SKIP 不包含此节点
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 返回新创建的 TreeWalker 对象 
const tw = document.createTreeWalker(root, whatToShow, filter);

const treeWalker = document.createTreeWalker(document.body, NodeFilter.SHOW_ElEMENT, (node) =>
node.classList.contains('no-escape')
? NodeFilter.FILTER_REJECT
: node.closest('.escape')
? NodeFilter.FILTER_ACCEPT
: NodeFilter.FILTER_SKIP
);
while (treeWalker.nextNode()) {
for (const node of treeWalker.currentNode.childNodes) {
if (node.nodeType === Node.TEXT_NODE && /\S/.test(node.data)) {
// 排除仅含空白符的文本节点
node.data = encodeURI(node.data.replace(/\s+/g, " "));
}
}
}

treeWalker

  • root, 只读属性, 表示新建 TreeWalker 时所声明的根节点

  • whatToShow, 只读属性, 返回一个 unsigned long 类型的常量位掩码, 表示需要筛选的 Node 类型

  • filter, 只读属性, 返回一个实现 NodeFilter 接口对象, 用来挑选相关的节点

  • currentNode, 返回 TreeWalker 当前指向的 Node

  • parentNode(), 移动当前 Node 到文档顺序中的第一个可见的祖先节点并返回该节点, 如果没有则返回 null 同时不会发生移动

  • firstChild(), 移动当前 Node 到当前节点的第一个可见子节点并返回该节点, 如果没有则返回 null 同时不会发生移动

  • lastChild(), 移动当前 Node 到当前节点的最后一个可见子节点并返回该节点, 如果没有则返回 null 同时不会发生移动

  • previousSibling(), 移动当前 Node 到当前节点的前一个兄弟节点并返回该节点, 如果没有则返回 null 同时不会发生移动

  • nextSibling(), 移动当前 Node 到当前节点的后一个兄弟节点并返回该节点, 如果没有则返回 null 同时不会发生移动

  • previousNode(), 移动当前 Node 到文档顺序中前一个节点并返回该节点, 如果没有则返回 null 同时不会发生移动

  • nextNode(), 移动当前 Node 到文档顺序中下一个节点并返回该节点, 如果没有则返回 null 同时不会发生移动

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<template>
<!DOCTYPE html>
<html lang="en">
<head><title>Demo</title>
<body>
<div id="container"></div>
</body>
</html>
</template>
<script>
const w1 = document.createTreeWalker(document.body, NodeFilter.SHOW_ALL);
const node = w1.firstChild(); // nodeName: #Text

const w2 = document.createTreeWalker(document.body, NodeFilter.SHOW_ELEMENT);
const el = w2.firstChild(); // nodeName: DIV
</script>

函数防抖

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/**
* @method debounce 函数防抖
* @param {Function} fn 执行方法
* @param {Number} delay 延迟时间 默认 300 毫秒
* @returns {Function}
*/
const debounce = function (fn, delay) {
if (typeof fn !== 'function') throw new Error('fn is not Function');
delay = delay >= 0 ? delay : 300;

let timer;
return function () {
let context = this;
let args = arguments;

if (timer) clearTimeout(timer);

timer = setTimeout(() => {
fn.apply(context, args);
}, delay);
};
};

函数节流

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/**
* @method throttle 函数节流
* @param {Function} fn 执行方法
* @param {Number} delay 延迟时间 默认 300 毫秒
* @returns {Function}
*/
const throttle = function (fn, delay) {
if (typeof fn !== 'function') throw new Error('fn is not Function');
delay = delay >= 0 ? delay : 300;

var previous = 0;
return function () {
var _this = this;
var args = arguments;
var now = new Date();
if (now - previous > delay) {
fn.apply(_this, args);
previous = now;
}
};
};
阅读全文 »