GVM(Go Version Manager)是一款用于管理和切换不同Go语言版本的工具。它允许用户在同一台计算机上轻松安装、使用和管理多个Go版本,同时还能确保项目之间的依赖关系井然有序。GVM的主要功能包括:

  1. 安装和卸载Go版本:GVM允许用户快速安装和卸载Go语言的不同版本,以便在不同项目中使用。
  2. 切换Go版本:GVM可以轻松切换当前正在使用的Go版本,这对于在不同项目中使用不同Go版本的开发者来说非常有用。
  3. 设置默认Go版本:GVM允许用户设置一个默认的Go版本,以便在新的终端会话中自动使用。
  4. 管理Go的环境变量:GVM可以自动管理Go的环境变量,如GOROOTGOPATH,以确保每个Go版本的正确配置。
  5. 支持离线安装:GVM支持通过本地二进制包进行Go语言的安装,这对于无法访问Go官方网站的用户来说非常有帮助。

通过GVM,开发者可以更方便地在不同版本的Go语言之间进行切换,从而提高开发效率和降低潜在的兼容性问题。

问题:GVM工具默认从官网下载安装包安装,因为众所周知的原因,国内网络无法访问到golang官网,因此下载安装包会失败。包括安装gvm工具本身也是一样。

如何安装gvm

首先将gvm安装脚本内容拷贝到本地,使用可以访问外网的浏览器打开:

https://raw.githubusercontent.com/moovweb/gvm/master/binscripts/gvm-installer

然后执行以下命令安装:

yum install bison
# 设置安装的代码源仓库,默认是github,在国内大概率拉不下来,因此需要拉到国内
export SRC_REPO=https://gitee.com/voidint/gvm.git
# 安装
./gvm_install.sh

用法:

# 查看所有版本
gvm list
# 使用指定版本
gvm use go1.18
# 设置默认的版本
gvm use go1.18 --default

如何基于本地包安装go

gvm默认使用golang官网来下载二进制,但是国内无法访问golang官网,所以是无法安装成功。gvm提供了通过离线二进制包安装的能力,可以在国内golang网站下载好二进制包,放到~/.gvm/archive/目录下,然后执行命令安装:

gvm install go1.21.5 --binary

这样就解决了网络不通的问题。

注意:版本号必须要匹配

一、安装cfssl

在github上拉取最新版本代码:https://github.com/cloudflare/cfssl.git,然后进入代码目录执行make all编译二进制。编译成功后会在当前目录下的bin/目录下生成几个二进制:

bin
├── cfssl
├── cfssl-bundle
├── cfssl-certinfo
├── cfssl-newkey
├── cfssl-scan
├── cfssljson
├── mkbundle
└── multirootca

二、生成CA

// todo

三、生成中间CA

// todo

四、生成服务器证书

填写需要生成的证书的信息:

{
  "CN": "example.com",
  "hosts": [
    "example.com",
    "www.example.com"
  ],
  "key": {
    "algo": "rsa",
    "size": 2048
  },
  "names": [
    {
      "C": "US",
      "ST": "California",
      "L": "Mountain View",
      "O": "Your Org Name",
      "OU": "Your Org Unit"
    }
  ]
}

生成csr:

./cfssl genkey certs/server.json | ./cfssljson  -bare server

签发证书:

./cfssl sign -ca certs/intermediate.crt -ca-key certs/intermediate-key.pem -config certs/rootca-config.json -profile server server.csr | ./cfssljson -bare server

参数说明:

  • -ca/-ca-key: CA证书和私钥
  • -config: 证书的配置文件,包含了一系列的证书参数,如过期时间、加密方式等等
  • -profile: 定义于config中的配置,一个config可以包含多个profile

NVM(Node Version Manager)是一个用于管理和切换不同版本Node.js的命令行工具。它允许用户在同一台计算机上轻松安装、使用和管理多个Node.js版本,从而确保开发者可以在不同项目中使用不同版本的Node.js,避免版本冲突带来的问题。

NVM的主要功能和特点包括:

  1. 安装和卸载Node.js版本:NVM允许用户快速安装和卸载Node.js的不同版本,以便在不同项目中使用。
  2. 切换Node.js版本:NVM可以轻松切换当前正在使用的Node.js版本,这对于在不同项目中使用不同Node.js版本的开发者来说非常有用。
  3. 设置默认Node.js版本:NVM允许用户设置一个默认的Node.js版本,以便在新的终端会话中自动使用。
  4. 查看已安装的Node.js版本:NVM可以列出已安装的所有Node.js版本,方便用户查看和管理。
  5. 支持自定义安装路径:NVM支持自定义Node.js的安装路径,可以根据用户需求进行配置。
  6. 无需管理员权限:NVM不需要管理员权限,用户可以在自己的用户空间内安装和管理Node.js版本。

通过NVM,开发者可以更方便地在不同版本的Node.js之间进行切换,从而提高开发效率和降低潜在的兼容性问题。以下是NVM的一些常用命令:

安装NVM

注意:需要外网环境,可以先到github.com上把Install.sh脚本内容拷贝到本地文件中

curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.38.0/install.sh | bash

或者:

curl -o- https://file.maqian.xin/scripts/nvm_install.sh | bash

安装版本

nvm install 14.17.0

切换版本

nvm use 14.17.0

设置默认版本

nvm alias default 14.17.0

查看已安装的所有版本

nvm ls

查看可用的Node.js版本

nvm ls-remote

卸载

nvm uninstall 14.17.0

opencore在开机控制台显示的分辨率和实际系统起来后设置的并不是同步的,这会导致登陆时看到的界面和登录后看到的界面有个差距,每次都要跳一下。

但好在opencore有配置可以调整这个分辨率,在UEFI设置 => 显示输出 => 控制台分辨率中可以调整。

第一步:将mp4视频文件转码为ts流

ffmpeg -i 1.mp4 -c copy -vbsf h264_mp4toannexb 1.ts
ffmpeg -i 2.mp4 -c copy -vbsf h264_mp4toannexb 2.ts

第二步:使用ffmpeg把ts流合并成mp4

ffmpeg -i "concat:1.ts|2.ts" -absf aac_adtstoas combine.mp4

import time


# 进度条打印函数
def print_progress_bar(iteration, total, prefix='', suffix='', decimals=1, length=100, fill='=', print_end="\r"):
    """
    Call in a loop to create terminal progress bar
    @params:
        iteration   - Required  : current iteration (Int)
        total       - Required  : total iterations (Int)
        prefix      - Optional  : prefix string (Str)
        suffix      - Optional  : suffix string (Str)
        decimals    - Optional  : positive number of decimals in percent complete (Int)
        length      - Optional  : character length of bar (Int)
        fill        - Optional  : bar fill character (Str)
        print_end    - Optional  : end character (e.g. "\r", "\r\n") (Str)
    """
    percent = ("{0:." + str(decimals) + "f}").format(100 * (iteration / float(total)))
    filled_length = int(length * iteration // total)
    bar = fill * filled_length + ">" + '-' * (length - filled_length)
    print(f'\r{prefix} |{bar}| {percent}% {suffix}', end=print_end)
    # Print New Line on Complete
    if iteration == total:
        print()


if __name__ == '__main__':
    for i in range(1, 11):
        print_progress_bar(i, 10, "Progress: ", )
        time.sleep(0.2)

几年前在深信服工作时整理出来的一篇文章,突然需要找了好久才找到,归档记录一下。

一、负载高的原因

通常,我们说的负载高是指CPU高,因为负载的直接体现是CPU。CPU在某个时刻要处理的任务多了,处理不过来,就会出现负载高的情况。

导致负载高的问题主要有以下几个:

  • CPU自身性能不够,系统和任务多,无法处理这么多任务。
  • 内存不足,会频繁触cache回收,有时会杀掉很多进程,导致CPU高。
  • IO高,进程持续高IO读写,导致CPU大部分时间都用来处理系统IO了。

排查负载的的主要思路:uptime ==> mpstat ==> free ==> dmesg ==> tcpdump。

二、分析CPU占用

2.1 分析uptime

uptime命令可以看到系统的运行时间,和当前系统负载:

12:46:32 up 148 days, 19:18, 2 users, load average: 0.00, 0.01, 0.05 

后面的load average表示系统的负载,三个数值分别表示1分钟、5分钟以及15分钟的平均负载。“负载”可以简单理解成当前CPU需要执行的任务数量,如果同一时刻CPU只用处理1个或者1个不到的任务,那么基本上是没有问题的,可以认为CPU不是那么繁忙。如果同一时刻负载需要处理2个、3个甚至更高,CPU可能就比较繁忙了。

一般来说,当单核CPU负载超过3时,就可以认为负载较高了。注意这里说的是单核CPU,如果是多核,对应的负载也要乘以核数。如当前系统核数等于4,那么负载超出12就是比较高的。当然,这个3也不是严格固定的,只是一个大概的范围,负载高低可以根据这个因子大概推断。例如4核的设备,负载在10左右也属于偏高了。

这个3是根据历史数据分析大概得到的,并非完全的界定值。具体是否高还需要分析mpstat数据,两者结合来看。在多核CPU场景(特别是CPU数量较多的时候,如56核、96核的设备),可能某些CPU已经跑满了,但是实际的负载就被平均下来了。

查看CPU核数的办法:

cat /proc/cpuinfo | grep name | wc -l

设备的负载状态可以使用uptime分析工具来辅助分析,把黑匣子中整天的uptime数据直接复制进去就可以画出负载图形:

image.png

根据趋势图很容易就能看到负载高的时间点,然后根据时间点去看mpstat记录,定位具体导致负载高的原因。

2.2 mpstat分析

mpstat是对CPU的抽样,基本的用法:

mpstat -P ALL 1 3

参数-P ALL表示打印出所有CPU的采样数据,ALL也可以改成对应的CPU号表示显示指定CPU抽样数据。如果不加这个参数,命令只会打出所有CPU的平均值,不会打印出详细的每个CPU数据。后面的1 3表示每1秒打印1次,一共打印3次,3也可以省略,命令会一直持续打。输出的内容:

Linux 3.10.0-957.21.3.el7.x86_64 (vm2019)     04/14/2020     _x86_64_    (2 CPU)

11:33:26 PM  CPU    %usr   %nice    %sys %iowait    %irq   %soft  %steal  %guest  %gnice   %idle
11:33:27 PM  all    0.00    0.00    0.51    0.00    0.00    0.00    0.00    0.00    0.00   99.49
11:33:27 PM    0    0.00    0.00    1.00    0.00    0.00    0.00    0.00    0.00    0.00   99.00
11:33:27 PM    1    0.00    0.00    1.00    0.00    0.00    0.00    0.00    0.00    0.00   99.00

每一列的数之表示当前模块占用的CPU百分比,最后一列idle表示空闲比例。其他常见列的含义:

  • usr: CPU花费在用户态调用的时间
  • nice: CPU花费在程序调度上时间
  • sys: CPU花费在系统调用上的时间
  • iowait: CPU花费在IO上的时间
  • irq: CPU花费在硬件中断上的时间
  • soft: CPU花费在软件中断上的时间

usr/sys/nice高

usr和sys和nice高比较少见,它们高基本上是应用层程序占用导致,如果是他们高,下一步思路是定位到具体的应用程序。常见的办法是通过top命令跟踪看到底是哪个程序占用的CPU:

执行top命令后,会展示出当前系统环境下进程的资源消耗,默认每秒会统计一次并刷新。同时,这个界面是一个交互式的界面,还可以继续输入参数进去,可以用来对进程排序等A座。例如判断CPU占用的场景,可以输入P来对进程CPU使用排序。因此很容易能找到占用CPU高的程序,然后根据进程功能和工作场景判断,或者使用第三方profile工具来对程序抽样。

iowait高

iowait高有两种常见的场景:

  1. 进程在进行大量IO操作
  2. 内存不足,释放系统在回收cache资源

低端平台下的大部分场景,都是内存不足导致的,内存不足触发cache回收,把缓存的IO数据瞬间刷到磁盘,导致iowait高。

这一点在下面的内存分析中会再详细说明。

soft高

soft高表示设备软中断多,这种情况下,多半是网络环境中存在异常流量,要针对LAN或者WAN抓包分析数据。

抓包主要分析的要素:

  1. SYN/FIN等包的比例是否正常,如果比例超过总抓包数量的10,就很异常了。
  2. 数据包内容是否有问题,这里经常出现问题的就是代理环境,经常有客户端的包都是错误的。
  3. 流量流速是否正常,是否有突发流量。

异常流量可以参考上面的案例来抓包排查,异常流量一般都是很难定位的,需要大量的抓包和分析才行。

三、分析内存

查看系统当前内存状态的命令是free,输出内容为:

[maqianos@vm2019:~]$ free -m
              total        used        free      shared  buff/cache   available
Mem:           3789        1408         367           0        2013        2070
Swap:             0           0           0

这里需要重点关注的是free和cache两列,free表示的是剩余内存,cache表示的是缓存下来的IO数据。linux为了提升系统性能,会把一部分IO数据缓存在内存里面,内存不足或者触发了回收的阈值时,会自动清理cache,把数据写到磁盘。很多时候,cache会突然下降了几百兆,造成IO高,CPU瞬间跑满。

这些cache也是可以执行命令手动释放的:

echo 3 > /proc/sys/vm/drop_caches

除了free以外,top命令也可以统计进程占用的内存大小,执行完top后输入M可以对进程占用的内存排序。这样很容易定位到内存的使用者,如果能发现内存在持续增长,说明可能存在内存泄漏,需要调试进程的内存泄露。

四、流量分析

流量是负载分析中最重要的一环,很多场景负载高都是因为流量导致的。分析流量就是要抓包,流量异常的场景,抓包很容易就能看出来。对流量而言,一个非常重要的信息就是dmesg,流量异常dmesg中会打印很多很明显的日志信息。

例如:

  • Out of socket memory
  • TCP: too many of orphaned sockets
  • TCP: time wait bucket table overflow
  • possible SYN flooding on port 9090. Sending cookies.

这些都是典型的异常日志,属于非业务层面的日志,一旦出现这种问题,就需要重视了。

这种场景就要抓包了,抓包主要需要观察的几个点:

  • 各种数据包比例是否正常,比如SYN/FIN这些特殊包的发包频次,是否特别高。

单用户统计,是否存在单个IP发包特别多的情况。

  • 代理场景下关注代理的数据包是否有问题,腾讯系的产品经常会出现这种问题。

五、参考

typecho一直都是用的mysql作为数据库存储,最近因为服务器到期需要迁移网站,所有的服务都转到docker了,迁移起来略显麻烦,因此就想抛弃mysql了,直接使用sqlite作为存储。这样迁移网站只要复制一下db文件就可以了,不用每次都得搭个mysql或者容器,简单方便。

typecho本身就是支持sqlite的,只不过在安装的时候如果选择了mysql,就没有办法在界面上更改数据库类型了,要修改只能通过改代码配置来完成。数据库的配置放在网站根路径下的config.inc.php文件中,有这么一段:

/** 定义数据库参数 */
$db = new Typecho_Db('Pdo_Mysql', 'tp_');
$db->addServer(array (
  'host' => 'db',
  'user' => 'xxxxx',
  'password' => 'xxxxxx',
  'charset' => 'utf8',
  'port' => '3306',
  'database' => 'typecho',
), Typecho_Db::READ | Typecho_Db::WRITE);
Typecho_Db::set($db);

要想改成sqlite的方式,只需修改配置为以下内容即可:

/** 定义数据库参数 */
$db = new Typecho_Db('Pdo_SQLite', 'tp_');
$db->addServer(array (
  'file' => '/xx/xx/xx/xx.db',
), Typecho_Db::READ | Typecho_Db::WRITE);
Typecho_Db::set($db);

修改之后即可生效,但这里还缺少了重要的一步:迁移数据。如何迁移数据可参考使用Navicate迁移Mysql到Sqlite

迁移完成后的几处安全建议:

  1. 不要将db文件放到网站目录内,可能导致db文件通过外部链接下载
  2. db文件命名尽量随机,不要轻易被人猜出
  3. 如果db文件放在网站目录内,要在nginx配置设置访问db文件直接返回404

迁移之后如何验证切换成功了:

  1. 确认网站可以正常访问
  2. 每查看一次网站,都会导致db文件更新,可通过后台查看文件更新时间是不是最新

第一步:创建sqlite文件

点击左上角的连接按钮,选择sqlite,在弹出的窗口中选择新建sqlite3,然后设置好各项配置:

最后选择保存即可创建sqlite文件

第二步:连接mysql

再次点击左上角按钮连接,选择mysql,在弹出的窗口中配置好连接信息:

第三步:数据同步

在工具栏,点击工具-数据传输,左边选择mysql连接和数据库,右边选择sqlite连接和数据库:

注意:传输到sqlite中的数据库使用默认的main就好了,不要

然后一直选择下一步就行了,之后执行完成后就会生成sqlite文件了。

因为家里宽带申请到了公网IP,希望可以直接通过公网IP访问回家。但是公网IP并不是固定的,每隔一段时间就会变化一下,导致需要频繁变化访问回家的公网IP,着实不爽。于是就想着使用ddns来解决这个问题。本想着是自己写个程序,通过dnspod的api接口来动态更新ip,但是程序写到一半后发现群晖已经就有这个功能了,于是干脆就直接用群晖的功能来做dns了。

群晖的ddns配置在控制面板-外部访问中,默认支持了多家云厂商的ddns,国内常见的如:

  • dnspod
  • 花生壳

因为我的域名都托管在了腾讯云,腾讯云的dns解析就是dnspod,因此可以直接使用dnspod.cn来配置ddns。

首先,进入到dnspod控制台页面,点击右上角个人头像,选择“API密钥“:

进入到API密钥页面,将tab栏切换到DNSPod Token(注意,不是腾讯云API密钥),然后点击下面的创建密钥来生成token:

创建完成token后,会分配一个ID和Token:

这里要注意的是需要将token保存下载,因为系统不会保存token信息,以后在控制台也无法查到,所以务必要妥善保存。

将id和token分别填入到群晖中的用户名和密码栏目,主机名称填写对应的域名,如www.xxxx.com,服务供应商选择DNSPod.cn(不要选DNSPod.com了)。提交即可完成ddns配置:

如果配置成功,在控制面板中就能看到ddns的状态是正常,此时说明ddns就生效了: