IntelliJ IDEA 运行在 JVM 上,JVM 有很多的选项和开关配置可以用来调整性能,也就是说,可以通过手动的调整这些 JVM 参数来优化 IntelliJ IDEA 的性能。这篇文章主要是总结一下我的学习过程。
首先打开 Memory Indicator
可以在设置中设定:
或者新版本中,只需要右击右下角状态栏然后选择 memory indicator 即可。
可以看到普通使用 IntelliJ IDEA 大概就使用了 800M 左右的内存。
在菜单 Help | Edit Custom VM Options
中可以设置。
下载安装包后一定要把压缩包下的 README 读完,里面有详细的路径及配置说明。这里先给一个全部内容的预览,下面再一一解释。
-ea
-Xms2g
-Xmx2g
-XX:ReservedCodeCacheSize=240m
-XX:+UseConcMarkSweepGC
-XX:SoftRefLRUPolicyMSPerMB=50
-Dfile.encoding=UTF-8
-Dsun.io.useCanonCaches=false
-Djava.net.preferIPv4Stack=true
-XX:+HeapDumpOnOutOfMemoryError
-XX:-OmitStackTraceInFastThrow
-Dawt.useSystemAAFontSettings=lcd
-Dsun.java2d.renderer=sun.java2d.marlin.MarlinRenderingEngine
-Xms
和 -Xmx
配置堆内存,也就是 IntelliJ 可以使用的内存。
-Xms
初始堆内存,调大该内存可以让启动速度更快,以省去分配内存的时间-Xmx
最大堆内存,如果遇到 OutOfMemoryError
可以调大该数值,最大不要超过系统 1/4.-XX:+UseConcMarkSweepGC
参数用来调整 GC 算法。使用该算法利用多个线程在后台进行 GC,以避免应用程序停止。
当分配超过 4GB 的堆内存时,可以尝试使用 -XX:+UseG1GC
.
-ea
选项开启 assertions。如果调试 IntelliJ 或者开发插件时可能用到,对 IntelliJ 性能并没有影响。
-server
虚拟机的解释执行模式。
-XX:SoftRefLRUPolicyMSPerMB=[value]
参数用来控制每 M 空间中 soft reference 保证存活的毫秒数。默认的时间是 1000,JetBrains 推荐 50。
-XX:ReservedCodeCacheSize=510m
设置编译器最大的 code cache,另外一个相关的 JVM 参数是 -XX:InitialCodeCacheSize
JetBrains 推荐这里使用 240m. 1
-Dsun.io.useCanonCaches=[boolean]
该参数是否开启文件名及路径缓存,默认 java 会缓存文件名 30 秒 2,JetBrains 建议关闭。
-XX:+OmitStackTraceInFastThrow
JetBrains 官方推荐的参数。
-XX:MaxJavaStackTraceDepth=-1
JVM 在实现 java.lang.Throwable.fillInStackTrace()
时把整个调用栈上的所有 Java 栈帧消息记录下来
-XX:+HeapDumpOnOutOfMemoryError
当发生 OutOfMemoryError
时 dump 堆内容。3
搜索 rz sz 命令使用方式进来的,可以不用往下看了,直接学习 scp 或者 rsync 吧, rz sz 看了一下还是有很多限制的。
虽然它可以实现向服务器发送文件,或者接受服务器的文件,但是限制条件必须在 screen 中执行,另外如果要在 Tmux 中使用还需要特殊的 hack 1
所以最基本的使用就是:
rz -be
目前我的情况是,家中有一个千兆主路由放在客厅接外面的宽带,而我自己的房间有一台比较老的 Netgear 3800 路由来无线桥接连接外面的主路由,因为我不想我的 3800 路由中的设备暴露到主路由的设置中,所以用了 OpenWrt 的桥接模式。但是随着我在 3800 这台路下接的设备增多,导致目前 3800 这台路由不堪重负,已经影响到了我日常 streaming 局域网 NAS 中的电影。所以最近想更换一下这台已经 8 年历史的 WNDR 3800 路由器。
首先我了解了一下,WNDR3800 标称的是 300Mbps 双频千兆路由器,WiFi 下 5GHz,理论传输速率应该有 37.5MB/s,但实际应该是达不到的,但即使只有一半的速率 10MB/s ,理论上串流局域网的视频应该是问题不大的,而现在的问题就出现在局域网中用 WiFi 连接的设备,理论上只能达到 4MB/s 的峰值速度。
首先细想了想理论上我的 WNDR3800 路由下面四个 LAN 口都是千兆网口,有线速度不应该那么差的,所以我先用我现有的几根网线连接了设备,但发现速度依然不够理想。
用 iperf 测试两台使用网线连接的设备,测试的速度大致只有在 30~45 Mbits/s 左右,换算成传输的速度除以 8,那就比较可怜了。
我就有点怀疑我的网线,可能是比较老的网线(这几根网线已经跟随我差不多快 6 年了,所以应该就是一个最高百兆的网线),所以立即下单了两根六类网线。
如何识别五类网线,超五类网线?
在怀疑完网线之后,就想是不是设备接口的限制,于是就从路由器开始排查。
确定是千兆网口
查了一下 T1 盒子的无线网卡:
而一查有线网卡,竟然是一个百兆网卡,怪不得比无线还慢。既然有线不能用,那就只能上无线了。
首先盒子的无线网卡是支持 802.11 ac 协议的,理论上是没有跑满带宽的,那么就是无线路由器到了上限。300Mbps 是 WNDR3800 标称的传输速度,但是实际即使靠的最近也不大可能达到理论速度的。再者我的 WNDR3800 有线连着一台 NAS,一台 Proxmox 服务器,本来传输压力就有些大,所以我期望无线能达到理论的一半就已经很好了,但实际上我测试,用一台 WNDR3800 有线连接的设备开启 iperf -s
,再用一台无线连接,iperf -c IP
,测试的结果是 60 Mbits/s 左右。
然后我想起来我还有一台小米路由器 (Mi Wifi 3G),之前因为总是断线所以就收起来了,然后去官网 查了一下配置,发现配置要比我的 WNDR3800 好不少,并且用 Android 连接后可以达到 800Mpbs。
所以现在就是要找一个比较稳定的固件了,官方的固件,无疑就是 OpenWrt 了。
Protocol
在 OpenWrt
CI/CD 不必多说。
CI/CD 解决的问题:
gitlab CI 依赖于项目根目录中定义的 .gitlab-ci.yml
文件,这个文件定义了 GitLab CI 应该做的事情。每次提交代码 GitLab 会检查该文件,然后将该文件定义的内容提交给 GitLab Runner 执行。
gitlab-ci 中配置的所有可执行的 job 称为 pipeline,Pipeline 可以认为是一次构建过程。Pipeline 中可以包含多个 stage.
在 GitLab 后台可以看到如图,整个过程称为一个 pipeline,这个 pipeline 包括两个 stage(阶段)。每个阶段就只有一个任务,gitlab-ci 在运行时只有当一个 stage 中所有的任务都执行完成才会进入下一个 stage.
首先来对 .gitlab-ci.yml
文件有一个整体的了解。
# 定义 stages
stages:
- test
- build
# 定义 job
job1:
stage: test
script:
- echo "test stage"
job1_1:
stage: test
script:
- echo "test stage: job1_1"
# 定义 job
job2:
stage: build
script:
- echo "build stage"
stage 可以理解为阶段,是 gitlab-ci 的概念,流程中的阶段,可以包括测试,编译,发布,部署等,在 .gitlab-ci.yml
文件中会用到。
定义:
- stages:
- build
- deploy
- release
job 或者又被称为 app,由 job 组成 gitlab-ci 的 stage 阶段,多个 job 可以并发执行。
举例:
build_front:
stage: build
build_backend:
stage: build
上面两个 app (build_front, build_backend) 将会在 build 阶段并发执行。
gitlab-ci 中集成了很多默认的变量,可以通过 variables 关键字来定义自己的变量,也可以在 gitlab 提供的界面上配置。gitlab 提供的 UI 可以配置全组或者 project 级别的环境变量。
比如一些敏感的信息,比如 Nexus 密码,Docker Registry 密码或者密钥之类等等
GitLab CI 中是 Runner 真正在执行 .gitlab-ci.yml
中定义的任务,Runner 可以是虚拟机,物理机,Docker 容器或者容器集群。GitLab 和 GitLab Runner 直接通过 API 通信,所以需要保证 GitLab 和 Runner 直接可以通过 HTTP 进行通信。
GitLab Runner 可以分为两种类型: Shared Runner (共享型) 和 Specific Runner(指定)
GitLab Runner 的安装参考官方网站 即可,代码也是开源的.
全部的关键词可以在官网 查看。
最常用的一个关键词了,script 定义具体需要执行的任务。
before_script 定义在每一个 job 之前的任务,必须是 Array 类型。
after_script 每一个 job 之后执行,即使 job 失败了也会执行,Array 类型。
定义需要缓存的文件或者路径。
有时候没有修改一些可能需要重新跑 build 的代码,不想 GitLab Runner 空跑,可以使用 only 关键字,以及 change 关键字实现只有部分文件改动后再触发 build.
only: # 下面的条件都成立
refs: # 下面的分支中任一分支改变
- release
changes: # 下面的文件中任一文件发生改变
- .gitlab-ci.yml
- Dockerfile
当 release 分支改变,同时 .gitlab-ci.yml 文件或者 Dockerfile 文件发生改变时,触发这个阶段的执行。
假如一个项目中集成了很多个模块,而每一个模块中的内容编译方式都不同。那么可以使用 gitlab-ci 提供的 include 关键字,对各个模块进行分拆。在每一个模块下放置 .gitlab-ci.yml
文件,然后再到根目录中创建 .gitlab-ci.yml
文件使用 include 关键字引入进来,对各个模块进行解耦。
include:
- local: module1/.gitlab-ci.yml
- local: module2/.gitlab-ci.yml
Build:
stage: build
script:
- echo 'build projects'
- "mvn $MAVEN_CLI_OPTS clean compile -Dmaven.test.skip=true"
- 'mvn $MAVEN_CLI_OPTS -U clean package -Dmaven.test.skip=true'
- 'mvn $MAVEN_CLI_OPTS sonar:sonar -Dsonar.projectKey=projectname -Dsonar.host.url=http://url -Dsonar.login=xxxxx'
Test:
stage: test
script:
- echo 'test projects'
- 'mvn $MAVEN_CLI_OPTS clean test'
only:
- master
- staging
在 Linux 下可以通过 etherwake 命令来网络唤醒设备。
sudo apt install etherwake
首先检查 BIOS 中设置,Wake on LAN 是否开启。一般在 BIOS > Power Management > “Wake On LAN” 这个选项下。然后重启进入系统,用如下命令查看网卡 eth0
是否开启了 Wake on LAN:
ethtool eth0
输出:
Settings for eth0:
Supported ports: [ TP ]
Supported link modes: 10baseT/Half 10baseT/Full
100baseT/Half 100baseT/Full
1000baseT/Full
Supported pause frame use: Symmetric
Supports auto-negotiation: Yes
Supported FEC modes: Not reported
Advertised link modes: 1000baseT/Full
Advertised pause frame use: Symmetric
Advertised auto-negotiation: Yes
Advertised FEC modes: Not reported
Speed: 1000Mb/s
Duplex: Full
Port: Twisted Pair
PHYAD: 1
Transceiver: internal
Auto-negotiation: on
MDI-X: off (auto)
Supports Wake-on: pumbg
Wake-on: g
Current message level: 0x00000007 (7)
drv probe link
Link detected: yes
结果中可以一眼就看到:
Supports Wake-on: pumbg
Wake-on: g
如果没有看到这个字样,或者是 off 状态,需要手动启动一下:
ethtool -s eth0 wol g
说明:
-s NIC
, 我这里的 eth0 是网络接口的设备名,根据不同的设备填写不同,可以通过 ifconfig
来查看wol g
表示设置 Wake-on-LAN 选项使用 MagicPacket.在 Linux 下执行如下命令唤醒设备:
sudo apt install wakeonlan
wakeonlan MAC_ADDRESS
或者
etherwake MAC_ADDRESS
可以通过 ping 命令和 arp 命令来获取局域网中的设备 MAC 地址:
ping -c 4 SERVER_IP && arp -n
在安装 Proxmox 后在它的文档中了解到了 cloud-init。所以就来梳理一下,什么是 cloud-init,它解决了什么实际问题,以及最重要的它该怎么用。
cloud-init 是一套工业标准为的是统一不同操作系统发行版在跨平台的云端服务器上初始化安装的流程。 cloud-init 是运行在 Guest machine 中,并在初始化时将一些自定义的配置应用到 Guest machine 中的应用程序。想象一下,假如你是一个云主机提供商,每天都需要为客户初始化成千上万台虚拟主机,这些机器可能使用不用的操作系统,可能根据客户需求设定不同的 IP 地址,不同的 SSH key,以及设置不同的 hostname 等等,这个时候需要怎么办,cloud-init 就是为了解决这个问题而诞生的。
cloud-init 最早由 Ubuntu 的开发商 Canonical 开发,现在已经支持绝大多数 Linux 发行版和 FreeBSD 系统。而目前大部分的公有云都在用 cloud-init 初始化系统配置,cloud-init 也支持部分私有云 (KVM, OpenStack, LXD 等等) 1,已经成为了事实上的标准。而这里就回到了 Proxmox,因为 Proxmox 是用来部署和管理虚拟机的平台,所以天然的适合 cloud-init 的使用场景,甚至可以说是不可或缺的一部分。
当我们在 AWS,或者 Google Cloud 这些公有云中申请计算资源的时候,云服务的提供商总是会叫我们选择一个系统镜像,然后做一些基础设置 (Hostname, SSH key 等等),然后在此基础上进行系统创建。cloud-init 正是在这个背景下诞生,自动化将用户数据初始化到系统实例中。
cloud-init 的主旨是定义一些独立于操作系统的配置,比如 hostname, networking configuration 等等。
cloud-init 特性:
cloud-init 对系统的初始化分为这几个阶段:
当系统启动的时候,generator 会检查 cloud-init.target
是否需要启动。默认情况下,generator 会启动 cloud-init. 但是如下情况 cloud-init 不会在开机运行:
/etc/cloud/cloud-init.disabled
文件存在时/proc/cmdline
包含 cloud-init=disabled
时,当在容器中运行时,内核命令可能会被忽略,但是 cloud-init 会读取 KERNEL_CMDLINE
这个环境变量Local 阶段会在挂载根分区 /
时,立即执行
cloud-init-local.service
Local 阶段的目的是:
local
data source大多数情况下,这个阶段就只会做这些事情。它会在 datasource 中查找,并应用网络配置。网络配置可能从这些地方来:
dhcp on eth0
,在虚拟机内自行通过 DHCP 获取 IP/etc/cloud/cloud.cfg
中配置 network: {config: disabled}
来禁用如果是该实例的第一次启动,那么被选中的网络配置会被应用,所有老旧的配置都会会清除。
该阶段需要阻止网络服务启动以及老的配置被应用,这可能带来一些负面的影响,比如 DHCP 服务挂起,或者已经广播了老的 hostname,这可能导致系统进入一个奇怪的状态需要重启网络设备。
cloud-init 然后再继续启动系统,将网络配置应用后启动。
在 local 阶段后,网络服务启动后,启动
cloud-init.service
该阶段需要所有的网络配置已经被应用,并且网络在线,然后才会应用所有的 user-data
#include
或者 #include-once
包括 http该阶段运行 disk_set
和 mounts
模块,可能会分区并格式化任何配置挂载点(比如 /etc/fstab
中)的磁盘。这个模块不能再早运行,因为有可能有些信息来源于网络,只有等网络信息获取到后才能执行。比如用户可能在网络资源中提供了挂载点配置信息。
在一些云服务中,比如 Azure,这个阶段会创建可以被挂载的文件系统。
part-handler
也会在这个阶段运行,包括 cloud-config bootcmd
。
在网络启动后运行:
cloud-config.service
这个阶段只会运行 config 模块,不会对其他阶段产生影响的模块在这里运行。
启动的最后阶段运行:
cloud-final.service
用户登录系统后习惯于运行的脚本在这个阶段运行,包括:
runcmd
)cloud-init 一般是安装在虚拟机中的,Ubuntu 系的系统直接安装即可:
apt install cloud-init
绝大部分的发行版会提供开箱即用 (ready-to-use) 的 Cloud-Init 镜像(一般以 .qcow2
文件发布),所以你可以下载这些文件,然后直接导入。比如说 Ubuntu 提供的镜像:https://cloud-images.ubuntu.com/
虽然大部分发行版都提供了开箱即用的 Cloud-Init 镜像,但还是推荐如果要更高的定制化需求可以自己来制作符合自己需求的镜像。
在 Proxmox 下,一旦制作好了 Cloud-Init 镜像,推荐将该镜像转换成 VM template, 通过 template 可以快速创建虚拟机。
# download
wget https://cloud-images.ubuntu.com/bionic/current/bionic-server-cloudimg-amd64.img
# create a new vm
qm create 9000 --memory 2048 --net0 virtio,bridge=vmbr0
# import the downloaded disk to local-lvm storage
qm importdisk 9000 bionic-server-cloudimg-amd64.img local-lvm
# finally attach the new disk to the VM as scsi drive
qm set 9000 --scsihw virtio-scsi-pci --scsi0 local-lvm:vm-9000-disk-1
Add cloud-init CDROM drive
qm set 9000 --ide2 local-lvm:cloudinit
为了从 Cloud-Init 镜像直接启动需要设置 bootdisk 参数到 scsi0
,然后设置 BIOS 从 disk 启动
qm set 9000 --boot c --bootdisk scsi0
然后配置 serial console 将其作为显示输出,这是 OpenStack 镜像必须设置的内容
qm set 9000 --serial0 socket --vga serial0
最后就可以将 VM 转换成 template,然后通过该模板就可以快速创建 clones,从 VM templates 部署系统要远远快于一个完整的 clone:
qm template 9000
可以使用如下命令从 template 中克隆系统:
qm clone 9000 123 --name ubuntu2
设置 SSH,及网络(这里的 IP 地址需要改成自己的网络环境的地址):
qm set 123 --sshkey ~/.ssh/id_rsa.pub
qm set 123 --ipconfig0 ip=10.0.10.123/24,gw=10.0.10.1
cloud-init 配置文件在:
/etc/cloud/cloud.cfg
/etc/cloud/cloud.cfg.d/*.cfg
cloud-init 在配置文件 /etc/cloud/cloud.cfg
中定义了各个阶段需要执行的任务,任务以 module 形式组织。
cloud.cfg 中指定了 set_hostname
这个 module, 则表示 cloud-init 会执行设置 hostname 的任务,但是具体设置的内容由 metadata 指定。
cloud-init 的日志在:
/var/log/cloud-init-output.log: 每一个阶段的输出
/var/log/cloud-init.log: 每一个操作更详细的调试日志
/run/cloud-init: contains logs about how cloud-init decided to enable or disable itself, as well as what platforms/datasources were detected. These logs are most useful when trying to determine what cloud-init ran or did not run.
数据存放在:
/var/lib/cloud
在安装 ubuntu server 18.04 的时候没有选择用静态地址,所以路由器 DHCP 随机分配了一个,然后进系统才想起来配置一下静态地址。传统的做法是修改 /etc/network/interfaces
文件,配置接口的静态地址即可。不过网上搜索一番学习之后发现了一个新方法,使用 netplan 来做修改。2
修改 /etc/netplan/50-cloud-init.yaml
文件,原来的 DHCP 配置可以看到 dhcp4: yes
这一行配置的是 yes
,现在修改成这样:
network:
ethernets:
ens18:
dhcp4: no
addresses: [192.168.2.10/24]
gateway4: 192.168.2.1
nameservers:
addresses: [114.114.114.114, 8.8.8.8]
version: 2
然后应用到接口:
sudo netplan --debug apply
sudo netplan apply
这里千万要小心配置,如果配错可能导致无法连上系统的!
在了解 BitTorrent 协议的时候,想着 .torrent
文件是如何生成的,所以就找了几个 CLI,比如 transmission-cli
和 mktorrent
这两个开源的制作 torrent 文件的开源项目,发现他们就是按照一种约定的格式来生成文件。而这个约定的结构中就少不了现在要谈的 BenCode 编码。
BitTorrent 协议使用 .torrent
文件来描述资源信息。.torrent
文件使用一套 BenCode 编码来对信息进行描述。
BenCode 是用于编码 torrent 文件的一种编码格式。BenCode 支持四种数据类型:
需要注意的是 BenCode 只用 ASCII 字符进行编码,如果是非 ASCII 码,BenCode 会用一种编码方式将其转换成 ASCII 码。
在编码字符串时 BenCode 选择将字符长度编码在其中:
<Length>:<Content>
比如 6:string
就表示 string
本身。其中 6 表示的是字符串长度。长度使用十进制表示。
整数编码时在前后加 i
和 e
,比如:
i123e
表示整数 123 . 这种方式也可以表示负数:i-1e
.
不过需要注意的是 i-0e
, i03e
这样的表示是非法的,但是 i0e
是合法的,表示整数 0 .
列表前后用 l
和 e
标识。列表中的元素可以是 BenCode 支持的任何一种类型。比如要编码字符串 content
和数字 42:
l7:contenti42ee
注意这里每个类型的边界都有定义清楚。字符串可以用长度来限定边界,但是整数一定需要 i
和 e
来限定边界。
字典类型可以保存一对一的关系,在 BenCode 中 KEY 必须为字符串类型,而 VALUE 可以是 BenCode 支持的任意一种类型。字典编码时用 d
和 e
限定范围。
另外需要注意,字典中 KEY 和 VALUE 必须相邻,字典依照 KEY 的字母序排序。
比如要定义 “name” -> “Ein Verne”, “age” -> 18, “interests” -> [“book”, “movie”]
首先要到 KEY 进行排序 “age”, “interests”, “name”
3:age9:Ein Verne
9:interestsi18e
4:namel4:book5:moviee
然后把上面的 KEY VALUE 连接起来,并在前后加上字典的 d
和 e
限定。
d3:age9:Ein Verne9:interestsi18e4:namel4:book5:movieee
类似 | 数据 | 编码 |
---|---|---|
int | -42 | i-42e |
string | ‘span’ | 4:spam |
list | [‘XYZ’, 432] | l3:XYZi432ee |
dict | {‘XYZ’: 432} | d3:XYZi432ee |
在了解了 BenCode 的编码后,用纯文本文件打开 .torrent
文件就能知道一二了。本质上 torrent 文件就是一个用 BenCode 编码的纯文本文件,torrent 在 BitTorrent 协议中又被称为 metainfo。
metainfo 是一个 BenCode 编码的字典:
announce
tracker 的地址
info
字典,单文件和多文件略有不同
torrent 文件中的所有字符串必须是 UTF-8 编码的。
我在本地新建了一个 README.md 文件,然后用如下命令创建一个 torrent 文件 “test.torrent”.
mktorrent -a http://announce.url -c "This is comments" -l 18 -o "test.torrent" -p -v README.md
然后查看 cat test.torrent
内容:
d8:announce19:http://announce.url7:comment16:This is comments10:created by13:mktorrent 1.013:creation datei1585360743e4:infod6:lengthi5e4:name9:README.md12:piece lengthi262144e6:pieces20:h7@xxxxxlxx]7:privatei1eee
拆解这个编码,先分段开。
d
8:announce -> 19:http://announce.url
7:comment -> 16:This is comments
10:created by -> 13:mktorrent 1.0
13:creation date -> i1585360743e
4:info
d
6:length -> i5e
4:name -> 9:README.md
12:piece length -> i262144e
6:pieces -> 20:h7@xxxxxxxxx
7:private -> i1e
e
e
拆解后可以看到 info 字典中有这么几项:
注:pieces 中有些特殊字符,在文章中用其他字符替换了。
多文件时 info 字典中会有一个 files 列表,这个列表由字典组成,每一个字典中是文件的内容,包括文件名和文件长度。
比如对当前文件夹下 README.md
和 README1.md
两个文件制作 torrent.
mktorrent -a http://announce.url -c "This is comments" -l 18 -o "test.torrent" -p -v .
得到的 torrent 文件:
d8:announce19:http://announce.url7:comment16:This is comments10:created by13:mktorrent 1.013:creation datei1585361538e4:infod5:filesld6:lengthi5e4:pathl9:README.mdeed6:lengthi0e4:pathl10:README1.mdeee4:name1:.12:piece lengthi262144e6:pieces20:rhr7r@rorrrlrrrrrrrr7:privatei1eee
拆解一下:
d
8:announce -> 19:http://announce.url
7:comment -> 16:This is comments
10:created by -> 13:mktorrent 1.0
13:creation date -> i1585361538e
4:info ->
d
5:files -> l
d
6:length -> i5e
4:path -> l 9:README.md e
e
d
6:length -> i0e
4:path -> l 10:README1.md e
e
e
4:name -> 1:.
12:piece length -> i262144e
6:pieces -> 20:rhrxxxxxxxxrrrrrr
7:private -> i1e
e
e
多文件时 info 字典中的内容稍微多一些。
构造好字典之后,使用如下库调用即可。
可以对 torrent 文件进行编辑的客户端:
qm
是 [[Proxmox VE]] 系统上用来管理 Qemu/Kvm 虚拟机的命令。可以用这个命令来创建,销毁虚拟机,也可以用它来控制虚拟机的启动,暂停,继续和停止。另外也可以用 qm 命令来设定虚拟机的配置。qm
命令也可以用来创建和删除虚拟磁盘 (virtual disks).
使用已经上传到 local
storage 的 iso 文件来在 local-lvm
storage 上创建一个 4G IDE 的虚拟磁盘。
qm create 300 -ide0 local-lvm:4 -net0 e1000 -cdrom local:iso/proxmox-mailgateway_2.1.iso
启动 VM
qm start 300
发送一个停止请求,并等待 VM 停止:
qm shutdown 3000 && qm wait 300
等待 40 秒:
qm shutdown 3000 && qm wait 300 -timeout 40
虚拟机的配置文件可以在 /etc/pve/qemu
文件找到。
配置文件都是纯文本,你可以用任何编辑器来编辑。不过建议用 qm
命令或者通过界面来进行修改。对配置的任何修改都需要重启 VM 才能生效。
因为加入了一些 PT 的关系,本地的硬盘空间立即捉襟见肘,毕竟有些蓝光原盘动不动就 40+GB,所以陆陆续续给威联通也加了一些硬盘,之前一直买的是酷狼的 4T 盘,但是用了一年快两年的样子竟然挂了,这是我最初买的那一块所以也折腾了一下,因为系统和一些配置都在这一块盘上。所以强烈建议重要资料一定多处备份,不仅需要通过本地冗余备份,最好也多地备份,比如本地和其他云端备份服务实时同步。
再回到这次的主题,关于如何选购一块硬盘。打开京东能看到主流的硬盘厂商提供了种类丰富的各种用途的磁盘。但对于消费者而言,很多人其实并不知道其中的具体技术细节。很多人可能知道酷狼是 NAS 盘,酷鱼是普通家用盘,但谁也没有具体分析过这二者的区别,商家宣传也不会刻意宣传技术细节。
硬盘的技术最早在 1956 年被 IBM 发明,之后便迅速成为了 60 年代通用计算机的组成部分 1。 历史上最多的时候有超过 200 家硬盘制造厂商 2,经过兼容合并后目前市场上比较著名的就只有 Seagate, Toshiba 和 Western Digital 了。再之后的故事大家都知道了,随着 SSD(Solid-state Drive) 的兴起,尤其是 NAND 技术的发展,HDD 逐渐式微,但不可否认的是 HDD 目前依然保留着自己在计算机领域的地位。
目前市场是两个主要的硬盘大小就是 3.5 寸,主要给台式机用,和 2.5 寸主要给笔记本用。HDD 通过 PATA(Parallel ATA), SATA(Serial ATA, 600MB/s), USB 和 SAS(Serial Attached SCSI, 12Gb/s) 接口和其他硬件系统连接。
我们知道计算机的世界其实是一个二进制的世界,底层都是 0 和 1 的无尽组合,对于数据来说也是,那么作为二进制数据的存储设备硬盘而言,就是要记录下 0 和 1 的组合。在网上可以看到很多的硬盘拆解的图片,能看到一个大大的一个像 CD 一样的盘片,在盘片上会有很多磁性物质,通过盘片的快速旋转和磁头的移动来读写数据。但实际上可能要更加复杂一些。
硬盘的主要构造:
说明:
上面也提到盘片是真正用来存储数据的地方,那么盘片是如何做到的呢?盘面和磁带的原理比较相似,在磁盘的表面有一层磁性材料,而磁头通常是线圈缠绕在磁芯上
虽然原理很简单,但是盘片,磁头,以及机械内部的制作都是需要非常精密的工艺和材料的。
具体再看纵向每一个盘片之间。
图片源自 Cameron Hart
说明:
所有的盘片都固定在主轴上,所有盘片之间都是平行的,每一个盘片的存储面都有一个磁头,现在主流的硬盘盘面都会有上下两面。
操作系统以扇区的形式将信息存储在硬盘上,每个扇区包括 512 字节的数据和一些其他信息。每一个扇区有两个部分数据:
扇区头标,包括:
这三个部分可以唯一确定一块数据的具体地址。
盘片盘面区域
在了解了硬盘的物理结构后,再来看真实过程中硬盘如何读写数据。
当系统需要从磁盘读取数据时,系统将数据逻辑地址传给磁盘,磁盘的控制电路按照寻址逻辑将地址翻译成物理地址,确定要读取的数据在哪一个盘面,哪一个磁道,哪一扇区。为了读写这个扇区的数据需要做以下步骤:
一个 7200 转 / 每分钟的硬盘,旋转一周所需时间 60*1000/7200 = 8.33ms,平均旋转延迟时间,假设为半圈也就是 4.17ms。平均寻道时间和平均旋转时间称为平均存取时间。
磁盘单次 IO 时间 = 寻道时间 + 旋转时间 + 存取时间
总结上面磁盘的读写可以知道数据的读写是按照从上到下,在盘面上从外向内进行。
因为硬盘的这种机械构造,所以磁盘本身的存取速度要比内存慢很多,再加上机械运动更加耗时。
所以为了提高硬盘的效率,减少磁盘 IO,磁盘往往不是严格的按需读取,而是每次都预先读取,即使只需要一个字节,磁盘也会从这个位置开始,顺序读取后面一定长度的数据放入内存。这样做的依据是计算机科学中著名的局部性原理,当一个数据被用到时,其附近的其他数据通常也会马上被用到。
页 (Page) 是许多计算机存储管理器的逻辑块,硬件和操作系统往往将主存和磁盘存储区域分割为连续的大小相等的块,每一个存储块称为一页(通常为 4k),主存和磁盘以页为单位交换数据。当程序要读取的数据不在主存中,会产生一个缺页异常,系统会向磁盘发出读盘信号,磁盘会找到数据的起始位置并向后连续读取一页或几页载入内存中,然后异常返回,程序继续运行。
一般硬盘上都会带一个比较小的磁盘缓冲存储器,将要写的数据缓冲,进而减少磁头移动,再一次性写入。
硬盘内部因为是机械结构,在磁头和盘片之间有一个很小的空隙,如果硬盘有震动或者抖动,那么就可能造成磁盘数据损毁,所以在硬盘通电后就尽量不要移动硬盘,并且要尽量减缓硬盘转动可能带来的共振。
机械硬盘的内部构造必须保证觉得无尘,一旦有小的灰尘进入硬盘密封层,和磁头与盘片发生碰撞就可能造成机械设备的损坏。
另外也不要对正在运行的磁盘突然断电,用正常的方式关闭系统,等待系统将缓存数据写回磁盘,然后再断电。所以如果家里有 NAS,建议还是购入 UPS,以免家中停电或者跳闸时可能对数据造成损害。
介绍了硬盘物理的构成,现在回到操作系统软件层面,相信装过机的人一定知道分区,在安装系统的时候要给系统划分一个系统分区。那么硬件启动的时候引导然后在硬盘上对应的地方启动系统。那么这里就需要知道整个磁盘的第一个扇区。
每一块物理硬盘的第一个扇区记录了整块磁盘的重要信息,包括:
以前在使用 Windows 的时候有一个不小的疑惑,一块硬盘只能够划分四个分区(主分区 + 扩展分区),原因就在这里,分区表只有 64 bytes 大小,最多只能容纳四个分区。但实际上 Windows 可以通过逻辑分区来划分更多的分区。
再上面说了那么多原理之后,假如硬盘厂商要提高硬盘的容量会怎么做呢?数据是存放在盘片上的,而具体数据是存在扇区上的。所以很自然的会想到:
前两者会增加硬盘的体积和重量,而现在的硬盘标准是固定的,随意改变硬盘大小必然会引起问题。所以目前大部分的解决方案就是提高单个磁盘数据存储的密度。于是这个公司的硬件工程师就提出了各种各样的办法。
最早期磁性颗粒平铺在盘片上,磁感应的方向是水平的,这类技术被称为 LMR(Longitudinal magnetic recording, 水平磁性记录)。这种方式有一个缺点,盘片利用率不高,当磁力颗粒很小,相互靠近时,容易受到干扰,方向发生混乱。所以 LMR 时代,单盘存储的数据有限。
为了解决 LMR 容量的限制,工程师们又想出了让磁性颗粒和磁感应方向相对盘片垂直。这个就叫做 PMR(Perpendicular Magnetic Recordking, 垂直磁性记录)。
在 PMR 技术下,3.5 寸盘,单碟磁盘的容量可以达到 1TB 左右。
不过随着互联网发展人们要存储的东西越来越多,PMR 逐渐不够用了,所以硬件工程师又想出了 SMR(Shingled Magneting Recordking,叠瓦式磁记录技术)。
SMR 利用了磁道与磁道之间的距离,通常硬盘的磁道与磁道之间存在一个保护距离,保护不同磁道直接的磁性颗粒不造成干扰。另外一个现实情况便是,硬盘信息的读取和写入是两个不同的操作,读取磁头和写入磁头也是不一样的。现代硬盘读写的磁头不同,写入磁头是传统的磁感应磁头,比较宽,读取磁头是新型的 MR 磁头,比较窄,磁道在划分的时候,需要满足最宽的标准。但是写入磁头在工作的时候,实际上对于每一个磁道,写入的信息宽度和读取的宽度是一样的,那么,磁道的空间就造成了浪费。于是工程师想到,把这部分浪费的磁道重叠起来,和房屋的瓦片一样,写入的时候沿着每条磁道上方写入,中间留下一小段保护距离,然后接着写另一条磁道。
使用 SMR 技术的硬盘又被网友称为叠瓦盘。
在 SMR 技术的帮助下,磁盘存储的容量大大增加了,但是缺点也很明显。首先是磁盘信息密度高,转速不能太快。另外 SMR 硬盘,单纯读问题不大,但是如果要修改某个磁道上的数据就比较麻烦,磁道间隙小,磁头比较宽,修改相邻磁道数据必然会相互影响。
解决这个问题的方法就是,每重叠一部分磁道时,隔开一些,另外就是设置专用缓冲区,当修改磁道 2 数据时,把磁道 3 的数据先取出来放到缓冲区,等磁道 2 数据改完再将磁道 3 数据写回。
也正是因为这个原因,一般的 SMR 硬盘具有大缓存的特点,一般可以达到 256MB,而普通的硬盘 64MB 足够。因为这样特殊的设计,在修改大量数据时会比较慢,时间久了会对硬盘读写性能造成影响。
相较于 PMR 硬盘,SMR 硬盘不适合用来当作系统盘或者需要频繁读写的硬盘来使用
NAS 盘和普通盘的本质区别在于 Time Limited Error Recovery,TLER 技术(希捷叫 ERC,ErrorRecovery Control)3。
一块硬盘长时间运行过程中,可能会因为各种情况出现读写错误,并且运行时间越长,出现的可能性越大,但是出现错误后,硬盘不会因此而损坏,硬盘内部的控制器会尝试进行修复,转移,纠错等操作,这一过程根据修复的难度,会用时几秒到几百秒左右,在这期间,硬盘会处于一个停止响应的状态。
在 RAID 中,一旦发现一块硬盘在一定时间内无响应,就会认为硬盘损坏,剔除该硬盘。如果硬盘硬因为一个可恢复的读写错误进入无响应状态,而刚好这个硬盘处于一个 RAID 阵列,无响应时间一旦超过 8 秒的阈值,RAID 控制器自然会认为硬盘损坏,并开始一系列恢复操作。这时 TLER 就派上了用场,有 TLER 功能的硬盘将执行正常的错误恢复,但 7 秒后,会向 RAID 控制器发出错误消息,并将错误恢复任务推迟到稍后的时间。通过协调错误处理,硬盘驱动器不会从 RAID 阵列中删除,从而避免了整个 RAID 恢复、替换、重建和返回操作。也就是说有 TLER 功能的硬盘,在硬盘恢复期间,会每隔 7 秒向 raid 控制器报告一次”正常”从而阻止阵列的重建。
有 TLER 功能的 NAS 盘更加适合在 RAID 阵列中工作,TLER 不会减少读写时可能造成的错误,也不会加快错误恢复速度,但可以在纠错中保护未响应的硬盘不被 RAID 控制器因为超时而误判为硬盘损坏。
NAS 盘只有在 RAID 阵列中才能体现其价值。
在看了硬盘的工作原理,再回到如何选购一块硬盘的主题上。相信到这里,再去看硬盘的配置信息,比如转速 5400 RPM,7200 RPM,缓存 64MB, 256MB ,使用的 PMR, 还是 SMR 技术,就比较清楚了,然后再根据自身的情况酌情选购即可。
有的时候想要查看一个网页有多少其他的页面链接过来,这个搜索语法似乎在 Google 上没见过,平时用的比较多语法也就是用 site:
来查看某个站点中的关键字。
那有什么方法可以查看某一个页面有谁链接过来了呢?
在 Google Search Console 中可以查看到:
Search Console > choose your property > Links > External links > Top linking sites
ahrefs 是一个逆向链接的索引,可以简单的查看一些,但如果要查看完整的报告则需要订阅。