编程笔记

lifelong learning & practice makes perfect

使用

  1. 状态
    auto,on和off

  2. 启用
    export GO111MODULE=on

  3. 固定版本号
    在go.mod里使用replace将任意版本的package替换为需要的版本

    1
    2
    3
    4
    5
    6
    7
    8
    module programnotes.cn/test
    go 1.13
    require (
    gorm.io/driver/mysql v1.1.3
    gorm.io/gorm v1.22.2
    )
    replace gorm.io/gorm => gorm.io/gorm v1.21.15
    replace gorm.io/driver/mysql => gorm.io/driver/mysql v1.0.5

    有些没节操的package不遵循规范,小版本改动不兼容导致线上bug,google的grpc就被吐槽过,这里将依赖设置成测试过的稳定版本可以减少依赖的package不兼容变更带来的问题.
    go get -u 解决依赖时可能改动项目中其他的package的版本,固定版本号也可以减少意外的版本变更,例如:这里升级gorm的版本也会改动mysql的版本.

定义

对流量进行按需分发的服务,通过将流量分发到不同的后端服务来扩展应用系统的

服务吞吐能力,并且可以消除系统中的单点故障,提升应用系统的可用性。
主要为HTTP/HTTPS/TCP/UDP/QUICk几种类型的请求设置转发规则。

负载均衡算法

  1. 轮询(Round Robin):第一个请求选择列表中的第一个服务器,按顺序移动列表直到结尾,循环。
  2. 最小连接(Least Connections):优先选择连接数最少的服务器
  3. 请求来源(Source):根据请求源的 IP 的散列(hash)来选择要转发的服务器。

    7层负载均衡与4层负载均衡

    4层

    4层 LB 主要是通过报文中的目的地址和端口,再加上负载均衡设备设置的服务器
    选择方式,决定最终选择的内部服务器。负载能力实现主要基于数据包的传输层信息
    ( ip + port )进行负载转发。
  • 基于域名或URL转发

    7层

    7层 LB 也称为“内容交换”,主要通过报文中真正有意义的应用层内容(证书,
    cookies,http头部信息),会在负载均衡设备上进行证书校验,三次握手等操作,再
    加上负载均衡设备设置的服务器选择方式,决定最终的内服务器。负载能力实现主要基
    于应数据包应用层信息( domain+port+url 等)进行负载转发。
  • 基于内容的路由
  • HTTP标头改写、重定向、重写、限速等

参考

wrk

  1. usage
    HTTP benchmarking tool.
    More information: https://github.com/wg/wrk.
  2. param
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    Options:
    -c, --connections <N> Connections to keep open //连接数
    -d, --duration <T> Duration of test //测试时间
    -t, --threads <N> Number of threads to use //线程数

    -s, --script <S> Load Lua script file //lua脚本
    -H, --header <H> Add header to request //添加头信息
    --latency Print latency statistics
    --timeout <T> Socket/request timeout
    -v, --version Print version details //版本信息
    Numeric arguments may include a SI unit (1k, 1M, 1G)
    Time arguments may include a time unit (2s, 2m, 2h)

examples

  1. 测试go-zero demo中的check接口
    1
    wrk -t10 -c1000 -d30s --latency "http://localhost:8888/check?book=go-zero"
  2. 结果
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    Running 30s test @ http://localhost:8888/check? book=go-zero
    10 threads and 1000 connections
    Thread Stats Avg Stdev Max +/- Stdev
    Latency 128.84ms 60.10ms 593.00ms 77.53%
    Req/Sec 794.67 304.69 1.95k 69.54%
    Latency Distribution
    50% 115.23ms
    75% 153.24ms
    90% 203.13ms
    99% 339.48ms
    233390 requests in 30.10s, 29.60MB read
    Requests/sec: 7754.33
    Transfer/sec: 0.98MB

ubuntu下使用

  1. 安装
    1
    2
    3
    4
    5
    6
    7
    8
    git clone https://github.com/wg/wrk.git

    // 构建可执行文件
    cd wrk
    make

    // 软连接
    ln -s 绝对路径/wrk /usr/local/bin(任意在PATH中的路径都可以)

https://hub.docker.com/_/mysql?tab=description&page=1&ordering=last_updated

  1. 拉取镜像
    docker pull mysql

  2. 运行

    1
    docker run --name some-mysql -e MYSQL_ROOT_PASSWORD=my-secret-pw -d mysql:tag

    where some-mysql is the name you want to assign to your container, my-secret-pw is the password to be set for the MySQL
    root user and tag is the tag specifying the MySQL version you want. See the list above for relevant tags.

    1
    docker run --name docker_mysql -p 3306:3306 -e MYSQL_ROOT_PASSWORD=your_password -d mysql
  3. 修改验证密码,修改后才能用root@密码登陆

    1
    ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY 'your_password';
  4. 创建新用户

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    mysql8版本执行 grant all privileges on *.*  to  'root'@'%'  identified by 'root'  with grant option;
    会报语法错误 ERROR 1064 (42000)

    应先创建新用户
    create user 'admin'@'%' identified by 'password';

    执行授权

    GRANT ALL PRIVILEGES ON *.* TO 'admin'@'%';
    (MariaDB: GRANT ALL PRIVILEGES ON *.* TO 'admin'@'%' identified by 'password';)

    刷新
    flush privileges;

    授权远程

    ALTER USER 'admin'@'%' IDENTIFIED WITH mysql_native_password BY 'password';
    (MariaDB: ALTER USER admin@'%' IDENTIFIED VIA mysql_native_password;)

    刷新
    flush privileges;

    references: https://blog.csdn.net/java_cai_niao_han/article/details/110442608

准备

基础环境

docker & docker-compose 安装配置

  1. 使用轻量服务器预装docker的镜像
    操作系统信息,lsb_release -a

    1
    2
    3
    4
    5
    LSB Version:    :core-4.1-amd64:core-4.1-noarch
    Distributor ID: CentOS
    Description: CentOS Linux release 7.9.2009 (Core)
    Release: 7.9.2009
    Codename: Core
  2. yum update,更新预装软件docker等

  3. 设置用户组
    将当前用户加入docker用户组

  4. 安装docker-compose
    yum安装的版本太老使用安装包安装,可以在github仓库的release页面下载
    下载解压到/usr/local/bin/目录下,增加执行权限,可使用如下命令安装

    1
    2
    3
    sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose

    sudo chmod +x /usr/local/bin/docker-compose
  5. 设置阿里云容器加速

    • 安装/升级Docker客户端
      推荐安装1.10.0以上版本的Docker客户端,参考文档docker-ce

    • 配置镜像加速器
      针对Docker客户端版本大于 1.10.0 的用户
      您可以通过修改daemon配置文件/etc/docker/daemon.json来使用加速器

      1
      2
      3
      4
      5
      6
      7
      8
      sudo mkdir -p /etc/docker
      sudo tee /etc/docker/daemon.json <<-'EOF'
      {
      "registry-mirrors": ["https://6ly480gk.mirror.aliyuncs.com"]
      }
      EOF
      sudo systemctl daemon-reload
      sudo systemctl restart docker
  6. 参考:

git 安装配置

在centos上使用yum安装的git版本太老,需要自己编译或通过第三方安装如ius

  1. 在阿里云提供的镜像上已有阿里云的镜像配置,在执行以下命令安装依赖时自动安装了v2.24.4版本的git:

    1
    yum install curl-devel expat-devel gettext-devel openssl-devel zlib-devel asciidoc
  2. 配置用户

    使用git config配置用户名,邮箱

    1
    2
    git config --global user.name "xxx"
    git config --global user.email "xxx"
  3. 配置~/.ssh/config

    1
    2
    3
    4
    5
    Host github.com
    HostName github.com
    IdentityFile ~/.ssh/id_rsa_git //秘钥位置
    PreferredAuthentications publickey
    User xxxx //这里填用户名
  4. ssh配置了key,在非root用户目录下,且以非root用户登录,ssh -T git@github.com报”Permission denied (publickey).”,使用-i指定秘钥后就ok了,是什么问题,没有使用当前目录下的key?
    通过ssh -vT git@github.com调试发现,ssh确实在~/.ssh下寻找了id_rsa的key,不存在,而配置文件config名错误(写成了congfig),
    导致ssh没有去读上面配置的id_rsa_git秘钥,没有找到秘钥就报错了

  5. 修改git秘钥的密码[可选]
    ssh-keygen -f id_rsa_git -p

其他工具安装

  1. fish安装 yum install fish

issue

  1. 通过秘钥ssh到服务器,配置并连接过服务器,更换秘钥后无法连接,报错.
    此时需要通过 ssh-keygen -R 服务器ip 删除记录,更换密钥后需要删除信息,不然无法使用新密钥登录
    -R命令作用:Removes all keys belonging to hostname from a known_hosts file. This option is useful to delete hashed hosts (see the -H option above).

  2. centos设置go/bin到PATH
    将export PATH=$PATH:/home/xxxx_user_name_xxxx/go/bin添加到~/.bash_profile不起效,还是每次都要重新source才能使用go安装到bin目录下的可执行程序.
    默认的bash和fish都是这样.

    解决: 将export PATH=$PATH:/home/xxxx_user_name_xxxx/go/bin添加到~/.bashrc后执行

    1
    source ~/.bashrc

使用

通过docker和compose可以很方便的部署搭建基础环境,部署应用,在github有个项目awesome-compose包含很多常用环境的样例配置文件,
通过这些样例可以快速搭建环境

ElasticSearch应用(ELK)搭建

  1. 基于awesome-compose中elasticsearch-logstash-kibana搭建

workflow

config

  1. set editor for git

    • configfile: .gitconfig

    • positon: ~/.git/.gitconfig or ~/.gitconfig

    • add one row: editor = vim

      1
      2
      [core]
      editor = vim

using git

stash

  1. 通过git stash命令将本地修改暂存至stash中,等同于git stash push

    1
    2
    git stash
    git stash push
  2. 通过git stash pop命令将stash中的修改恢复至本地

    1
    2
    git stash appply # 当仅有一个stash时,可以直接用apply
    git stash pop
  3. git stash show 展示暂存的内容

    1
    2
    git stash show
    git stash show 1 # 展示第一个stash,每个暂存有序号,默认是0
  4. git stash push将修改暂存

references

what

  1. m3u8

  2. ffmpeg

how

  1. 通过fiddler等工具拿到m3u8文件,查看文件内容是否规范
    下载时通过文件类型,url过滤快速找出含有m3u8文件的数据,在pc端抓包比较方便.手机端抓包https需要安装证书.

  2. 通过ffmpeg下载

    1
    ffmpeg.exe -i input.m3u8 -c copy output.mp4
    • -i 指定输入参数,m3u8文件
    • -c copy 指定输出文件
  3. 在m3u8文件内的视频文件如果是通过http/https下载需要指定白名单

    1
    -protocol_whitelist "file,http,https,tls,tcp"

    把这个参数加上,指定协议白名单即可,完整的命令如下:

    1
    ffmpeg.exe -protocol_whitelist "file,http,https,tls,tcp" -i input.m3u8 -c copy output.mp4

    不指定白名单ffmpeg会报错:”Protocol ‘https’ not on whitelist ‘file,crypto’!”

string

redis的string是动态字符串,可以修改

底层结构,分为embStr和raw两种格式

较短的使用embStr存储,最多44字节,更长的使用raw格式存储。两种格式的底层结构不同。
  1. emb

  2. raw

list

底层数据结构:链表

  1. 插入、删除 O(1)
  2. 查询O(n)
  3. redis底层存储使用的不是简单的链表,使用了quicklist(快速链表:A doubly linked list of ziplists意思为一个由ziplist组成的双向链表)。
    ziplist,压缩列表。它将所有的元素紧挨着一起存储,分配的是一块连续的内存。当数据量比较多的时候才会
    改成 quicklist。因为普通的链表需要的附加指针空间太大,会比较浪费空间,而且会加重内存的碎片化。

set

Usage

  1. api

    redis support sadd,members…

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    // using go-zero
    go func() {
    for {
    s := time.Now().Second()
    redis.Sadd("order_id"+strconv.Itoa(s), strconv.Itoa(s))
    }
    }()
    tt := time.NewTicker(time.Second)
    for now := range tt.C {
    vs, _ := rr.Smembers("order_id" + strconv.Itoa(now.Second() ))
    fmt.Println(now.Second(), vs)
    redis.Del("order_id" + strconv.Itoa(now.Second()))
    }

redis 安全

Reids 支持tcp,不支持ssl安全链接,可以通过ssl代理软件实现安全通讯,在公网使用时需要考虑加上ssl保证服务安全。

  1. spiped:redis官方推荐的代理软件
    会在客户端和服务器各启动一个spiped 进程。redis客户端和服务端通信需要通过sniped。

  2. 单节点设置password

    • config file:
      • redis.conf (位置: /etc/redis.conf)
    • setting:
      • requirepass “hello world”
      • 注意需要带上引号
      • 这种设置方式需要重启redis
      • 重启命令: sudo redis-server /etc/redis.conf
  3. 集群

redis性能

指标查看

通过客户端执行info,可查看,加上参数可以查询特定指标,如memory查看内存相关的,包含:

  • server: 查看 Redis 服务器信息,如 Redis 的版本
  • clients: 客户端的连接部分
  • memory: 内存消耗相关信息
  • persistence: RDB和AOF相关信息
  • stats: 一般统计
  • replication: 主/从复制信息
  • cpu: 统计CPU的消耗
  • commandstats: Redis命令统计
  • cluster: Redis集群信息
  • keyspace: 数据库的相关统计
  • modules: Module 相关信息
    它也可以采取以下值:
  • all: 返回所有信息
  • default: 值返回默认设置的信息
  • everything: 包括 all 和 modules

key

  1. evicted_keys: 因为maxmemory限制被回收的key
  2. expired_keys:过期的key数量
  3. keyspace_hits: 在主字典中成功查找到key的次数
  4. keyspace_misses: 在主字典中查找key失败的次数
  5. 阿里云dms,redis监控图例

参考

  1. https://www.redis.com.cn/commands/info.html
  2. 缓存模式:Cache-Aside,Read-Through…

disadvantage

  1. 输出日志不方便,直接输出无法用于辅助定位错误,指针直接输出是一串地址

advantage

错误信息,多次构建,报错信息不一致

  1. 垃圾信息,提示信息不明确
    1
    2
    3
    unexpected fault address 0x7f01d3b9f000
    fatal error: fault
    [signal SIGBUS: bus error code=0x2 addr=0x7f01d3b9f000 pc=0x45b898]
  2. 磁盘不足
    1
    go build github.com/cespare/xxhash/v2: mkdir ....   no space left on device
  3. 磁盘不足
    1
    compile: writing output: write $WORK/....../_pkg_.a: no space left on device
  4. unexpected fault address
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
       unexpected fault address 0x7f713df35000
    fatal error: fault
    [signal SIGBUS: bus error code=0x2 addr=0x7f713df35000 pc=0x45b96a]

    goroutine 1 [running]:
    runtime.throw(0x690d25, 0x5)
    /usr/local/go/src/runtime/panic.go:774 +0x72 fp=0xc000746ef0 sp=0xc000746ec0 pc=0x42da22
    runtime.sigpanic()
    /usr/local/go/src/runtime/signal_unix.go:391 +0x455 fp=0xc000746f20 sp=0xc000746ef0 pc=0x4429c5
    runtime.memmove(0x7f713d9ffea0, 0xc00d5da000, 0x5fc838)
    /usr/local/go/src/runtime/memmove_amd64.s:422 +0x50a fp=0xc000746f28 sp=0xc000746f20 pc=0x45b96a
    cmd/link/internal/ld.(*OutBuf).Write(0xc000096880, 0xc00d5da000, 0x5fc838, 0x68c130, 0x0, 0x0, 0x0)
    /usr/local/go/src/cmd/link/internal/ld/outbuf.go:65 +0xa0 fp=0xc000746f78 sp=0xc00074Build step 'Execute shell' marked build as failure

    磁盘腾出空间后,能够正常构建

  5. 多次构建失败后,尝试构建其他项目,发现大部分都构建失败且失败报错信息类似
  6. du -h 查询文件占用磁盘大小,逸K,M,G为单位
    查询后发现磁盘占用95%,仅剩几G空间,清空部分后构建正常了