BlankLin

lazy and boring

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
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      // 简单范型
      class Test<T> {
      private T var;
      public T getVar() {
      return var;
      }
      public void setVar(T var) {
      this.var = var;
      }
      }
      // 多元泛型
      class TestKV<K,V> {
      private K key;
      private V value;
      public K getKey() {
      return key;
      }
      public void setKey(K key) {
      this.key = key;
      }
      public V getValue() {
      return value;
      }
      public void setValue(V value) {
      this.value = value;
      }
      }

      public class Demo {
      public static void main(String[] args) {
      Test<String> test = new Test<String>();
      test.setVar("aa");
      System.out.println(test.getVar());

      TestKV<String, String> testKV = new TestKV<String, String>();
      testKV.setKey("hello");
      testKV.setValue("world");
      System.out.println(testKV.getKey() +":"+testKV.getValue());
      }
      }
    • 泛型接口
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      interface Test<T> {
      public T getVar();
      }
      class TestImpl<T> implement Test<T> {
      private T var;
      public TEstImpl(T var) {
      this.var = var;
      }
      public T getVar() {
      return var;
      }
      public void setVar(T var) {
      this.var = var;
      }
      }
      public class Demo{
      public static void main(String[] args) {
      Test<String> test = new TestImpl<String>("tom");
      System.out.pringln(test.getVar());
      }
      }
    • 泛型方法
      1
      2
      3
      4
      5
      6
      public class Demo {
      public <T> T getObject(Class<T> c) {
      T t = c.newInstance();
      retrun t;
      }
      }

注解

wireshark3.4.8,主界面

avatar

通过ping简单入门

  • 启动wireshark后,wireshark处于抓包状态中
    avatar
  • 在终端输入ping命令后
    1
    ping www.baidu.com
    avatar
  • 通过过滤栏设置过滤条件进行数据包列表过滤
    1
    ip.addr == 180.101.49.12 and icmp
    avatar

ICMP(Internet Control Message Protocol)Internet控制报文协议。它是TCP/IP协议簇的一个子协议,用于在IP主机、路由器之间传递控制消息。控制消息是指网络通不通、主机是否可达、路由是否可用等网络本身的消息。这些控制消息虽然并不传输用户数据,但是对于用户数据的传递起着重要的作用。 ICMP协议是一种面向无连接的协议。

wireshark抓包界面介绍

avatar

  • Display Filter(显示过滤器), 用于设置过滤条件进行数据包列表过滤。菜单路径:Analyze —> Display Filters。
  • Packet List Pane(数据包列表), 显示捕获到的数据包,每个数据包包含编号,时间戳,源地址,目标地址,协议,长度,以及数据包信息。 不同协议的数据包使用了不同的颜色区分显示
  • Packet Details Pane(数据包详细信息), 在数据包列表中选择指定数据包,在数据包详细信息中会显示数据包的所有详细信息内容。数据包详细信息面板是最重要的,用来查看协议中的每一个字段。各行信息分别为
    (1)Frame: 物理层的数据帧概况
    (2)Ethernet II: 数据链路层以太网帧头部信息
    (3)Internet Protocol Version 4: 互联网层IP包头部信息
    (4)Transmission Control Protocol: 传输层T的数据段头部信息,此处是TCP
    (5)Hypertext Transfer Protocol: 应用层的信息,此处是HTTP协议
    avatar

TCP包的具体内容

avatar

抓包过滤器语法

  • 抓包过滤器语法和实例

    抓包过滤器类型Type(host、net、port)、方向Dir(src、dst)、协议Proto(ether、ip、tcp、udp、http、icmp、ftp等)、逻辑运算符(&& 与、|| 或、!非)

(1)协议过滤

比较简单,直接在抓包过滤框中直接输入协议名即可。

TCP,只显示TCP协议的数据包列表

HTTP,只查看HTTP协议的数据包列表

ICMP,只显示ICMP协议的数据包列表

(2)IP过滤

host 192.168.1.104

src host 192.168.1.104

dst host 192.168.1.104

(3)端口过滤

port 80

src port 80

dst port 80

(4)逻辑运算符&& 与、|| 或、!非

src host 192.168.1.104 && dst port 80 抓取主机地址为192.168.1.80、目的端口为80的数据包

host 192.168.1.104 || host 192.168.1.102 抓取主机为192.168.1.104或者192.168.1.102的数据包

!broadcast 不抓取广播数据包

2、显示过滤器语法和实例

(1)比较操作符

比较操作符有== 等于、!= 不等于、> 大于、< 小于、>= 大于等于、<=小于等于。

(2)协议过滤

比较简单,直接在Filter框中直接输入协议名即可。注意:协议名称需要输入小写。

tcp,只显示TCP协议的数据包列表

http,只查看HTTP协议的数据包列表

icmp,只显示ICMP协议的数据包列表

(3) ip过滤

ip.src ==192.168.1.104 显示源地址为192.168.1.104的数据包列表

ip.dst==192.168.1.104, 显示目标地址为192.168.1.104的数据包列表

ip.addr == 192.168.1.104 显示源IP地址或目标IP地址为192.168.1.104的数据包列表

(4)端口过滤

tcp.port ==80, 显示源主机或者目的主机端口为80的数据包列表。

tcp.srcport == 80, 只显示TCP协议的源主机端口为80的数据包列表。

tcp.dstport == 80,只显示TCP协议的目的主机端口为80的数据包列表。

(5) Http模式过滤

http.request.method==”GET”, 只显示HTTP GET方法的。

(6)逻辑运算符为 and/or/not

过滤多个条件组合时,使用and/or。比如获取IP地址为192.168.1.104的ICMP数据包表达式为ip.addr == 192.168.1.104 and icmp

wireshark抓包分析tcp3次握手

以某天气预报api举例,http://jisutianqi.market.alicloudapi.com/weather/query

  • 启动wireshark
  • 用浏览器访问地址
  • 在终端输入,得到实际ip地址
    1
    ping jisutianqi.market.alicloudapi.com
    avatar
  • 在wireshark上过滤
    1
    ip.addr == 47.97.242.71
    avatar
    图中可以看到wireshark截获到了三次握手的三个数据包。第四个包才是HTTP的, 这说明HTTP的确是使用TCP建立连接的。
  • 第一次握手抓包
    客户端发送一个TCP,标志位为SYN,序列号为0, 代表客户端请求建立连接。 如下图。
    avatar
    数据包的关键属性如下:
    • SYN :标志位,表示请求建立连接
    • Seq = 0 :初始建立连接值为0,数据包的相对序列号从0开始,表示当前还没有发送数据
    • Ack =0:初始建立连接值为0,已经收到包的数量,表示当前没有接收到数据
  • 第二次握手抓包
    服务器发回确认包, 标志位为 SYN,ACK. 将确认序号(Acknowledgement Number)设置为客户的I S N加1以.即0+1=1, 如下图
    avatar
    数据包的关键属性如下:
    • [SYN + ACK]: 标志位,同意建立连接,并回送SYN+ACK
    • Seq = 0 :初始建立值为0,表示当前还没有发送数据
    • Ack = 1:表示当前端成功接收的数据位数,虽然客户端没有发送任何有效数据,确认号还是被加1,因为包含SYN或FIN标志位。(并不会对有效数据的计数产生影响,因为含有SYN或FIN标志位的包并不携带有效数据)
  • 第三次握手抓包
    客户端再次发送确认包(ACK) SYN标志位为0,ACK标志位为1.并且把服务器发来ACK的序号字段+1,放在确定字段中发送给对方.并且在数据段放写ISN的+1, 如下图:
    avatar
    数据包的关键属性如下:
    • ACK :标志位,表示已经收到记录
    • Seq = 1 :表示当前已经发送1个数据
    • Ack = 1 : 表示当前端成功接收的数据位数,虽然服务端没有发送任何有效数据,确认号还是被加1,因为包含SYN或FIN标志位(并不会对有效数据的计数产生影响,因为含有SYN或FIN标志位的包并不携带有效数据)。
  • 在TCP层,有个FLAGS字段,这个字段有以下几个标识:SYN, FIN, ACK, PSH, RST, URG。如下
    avatar
    其中,对于我们日常的分析有用的就是前面的五个字段。它们的含义是:
    • SYN表示建立连接,
    • FIN表示关闭连接,
    • ACK表示响应,
    • PSH表示有DATA数据传输,
    • RST表示连接重置

安装Homebrew

Homebrew要安装正确, 确保/usr/local下面出现各种share/include等目录

1
/bin/zsh -c "$(curl -fsSL https://gitee.com/cunkai/HomebrewCN/raw/master/Homebrew.sh)"

安装环境所需插件

1
brew install cmake ninja libtool gettext ccache

修正objcopy的问题

1
2
brew install binutils
ln -s /usr/local/opt/binutils/bin/objcopy /usr/local/bin/objcopy

clion打开clickouse local不成功,无法正常编译debug

1> 安装llvm

1
brew install llvm

2> 配置clion的工具链ToolChain
avatar
cmake和make是新版本就可以了,配置好c和c++编译器(compiler)使用刚装好的llvm下的clang

安装googletest

有报错ld: library not found for -lgtest

1
brew install googletest

avatar

使用支持ninja的CLion版本(可选, 最新版是支持的)

CLion中的CMake使用选项

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache
-DCMAKE_BUILD_TYPE=Debug
-GNinja
-DENABLE_CLICKHOUSE_ALL=OFF
-DENABLE_CLICKHOUSE_SERVER=ON
-DENABLE_CLICKHOUSE_CLIENT=ON
-DUSE_STATIC_LIBRARIES=OFF
-DCLICKHOUSE_SPLIT_BINARY=ON
-DSPLIT_SHARED_LIBRARIES=ON
-DENABLE_LIBRARIES=OFF
-DENABLE_UTILS=OFF
-DENABLE_TESTS=OFF
-DUSE_ROCKSDB=ON
-DENABLE_ROCKSDB=ON
-DUSE_INTERNAL_ROCKSDB_LIBRARY=ON
-DENABLE_PROTOBUF=ON
-DENABLE_GRPC=ON

avatar

点Tools->CMake→Reset Cache and Reload Project

avatar

load过程可能会遇到的错误

1
CMake Error at contrib/croaring-cmake/CMakeLists.txt:22 (add_library):Cannot find source file:…

执行git submodule update —init —recursive 重新拉取相关依赖

编译clickhouse-server

1> 点右上角锤子进行编译
avatar
2> 查看编译进度
avatar

debug方式运行

    1. debug时需要指定配置文件config.xml路径
      1
      --config-file=/Users/blanklin/Code/cpp/clickhouse-debug/conf/config.xml
      avatar
    1. 点右侧的蜘蛛按钮进行debug
      avatar

cpp快速入门

1
2
3
4
5
6
7
8
9
10
#include <iostream>
using namespace std;

// main() 是程序开始执行的地方

int main()
{
cout << "Hello World"; // 输出 Hello World
return 0;
}

接下来我们讲解一下上面这段程序:

  • C++ 语言定义了一些头文件,这些头文件包含了程序中必需的或有用的信息。上面这段程序中,包含了头文件
  • using namespace std; 告诉编译器使用 std 命名空间。命名空间是 C++ 中一个相对新的概念。
  • // main() 是程序开始执行的地方 是一个单行注释。单行注释以 // 开头,在行末结束。
  • int main() 是主函数,程序从这里开始执行。
  • cout << “Hello World”; 会在屏幕上显示消息 “Hello World”。
  • return 0; 终止 main( )函数,并向调用进程返回值 0。

查询cpu的过程

    1. 查看应用的pid,我的应用名称是以dlap开头
      jps的命令参数如下,jps [options] [hostid]
      • -q 不输出类名、Jar名和传入main方法的参数
      • -m 输出传入main方法的参数
      • -l 输出main类或Jar的全限名
      • -v 输出传入JVM的参数
        1
        2
        3
        4
        5
        jps -m -l
        或者
        ps -ef | grep dlap | grep -v grep
        或者
        ps aux | grep dlap | grep -v greppid
        avatar
    1. 查看系统资源占用信息,使用top查一下当前进程pid占用较高的cpu线程
      1
      2
      3
      4
      5
      top -Hp pid
      // 也可以用以下两个命令
      ps -Lfp pid
      // 或者
      ps -mp pid -o THREAD, tid, time | sort -rn
      avatar
    1. 将需要的线程ID转换为16进制格式,可以使用printf "%x\n" tid命令
      1
      printf "%x\n" tid
      avatar
    1. 打印线程堆栈信息,可以使用命令jstack pid | grep tid,注意这里的tid是线程ID的16进制值
      1
      jstack pid | grep tid
      avatar

jmap命令介绍

jmap可以导出堆内容,然后使用jhat进行分析,语法如下

1
2
3
4
5
6
7
8
NAME
jmap - Prints shared object memory maps or heap memory details for a process, core file, or remote debug server. This command is
experimental and unsupported.

SYNOPSIS
jmap [ options ] pid
jmap [ options ] executable core
jmap [ options ] [ pid ] server-id@ ] remote-hostname-or-IP

  • 根据pid查看堆内存使用情况,包括使用的GC算法、堆配置参数和各代中堆内存使用情况
    1
    jmap -heap pid
    avatar
  • 根据pid查看堆内存中的对象数目、大小统计直方图,如果带上live则只统计活对象
    1
    jmap -histo:live pid | more
    avatar

    class name是对象类型,说明如下

    1
    2
    3
    4
    5
    6
    7
    8
    9
    B  byte
    C char
    D double
    F float
    I int
    J long
    Z boolean
    [ 数组,如[I表示int[]
    [L+类名 其他对象
  • 用jmap把进程内存使用情况dump到文件中,再用jhat分析查看
    1
    jmap -dump:format=b,file=dumpFileName pid
    avatar
  • 用jhat查看
    1
    2
    3
    jhat -port 9998 /tmp/dump.dat
    // 注意如果Dump文件太大,可能需要加上-J-Xmx512m这种参数指定最大堆内存
    jhat -J-Xmx512m -port 9998 /tmp/dump.dat
    avatar

    然后用浏览器打开,http://ip:9998

jstat(JVM统计监测工具)

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
NAME
jstat - Monitors Java Virtual Machine (JVM) statistics. This command is experimental and unsupported.

SYNOPSIS
jstat [ generalOption | outputOptions vmid [ interval[s|ms] [ count ] ]

generalOption
A single general command-line option -help or -options. See General Options.

outputOptions
One or more output options that consist of a single statOption, plus any of the -t, -h, and -J options. See Output Options.

vmid
Virtual machine identifier, which is a string that indicates the target JVM. The general syntax is the following:

[protocol:][//]lvmid[@hostname[:port]/servername]

The syntax of the vmid string corresponds to the syntax of a URI. The vmid string can vary from a simple integer that
represents a local JVM to a more complex construction that specifies a communications protocol, port number, and other
implementation-specific values. See Virtual Machine Identifier.

interval [s|ms]
Sampling interval in the specified units, seconds (s) or milliseconds (ms). Default units are milliseconds. Must be a positive
integer. When specified, the jstat command produces its output at each interval.

count
Number of samples to display. The default value is infinity which causes the jstat command to display statistics until the
target JVM terminates or the jstat command is terminated. This value must be a positive integer.
  • 根据pid 间隔250ms 采样条数4 输出GC信息
    1
    jstat -gc pid 250 4
    avatar

    jvm 堆内容布局
    avatar

    1
    2
    堆内存 = 年轻代 + 年老代 + 永久代  
    年轻代 = Eden区 + 两个Survivor区(From和To)

    各列含义

    1
    2
    3
    4
    5
    6
    7
    S0C、S1C、S0U、S1U:Survivor 0/1区容量(Capacity)和使用量(Used)
    EC、EU:Eden区容量和使用量
    OC、OU:年老代容量和使用量
    PC、PU:永久代容量和使用量
    YGC、YGT:年轻代GC次数和GC耗时
    FGC、FGCT:Full GC次数和Full GC耗时
    GCT:GC总耗时

hprof用法

hprof 能展现cpu使用率,堆内存使用情况,语法格式如下

1
2
3
java -agentlib:hprof[=options] ToBeProfiledClass
java -Xrunprof[:options] ToBeProfiledClass
javac -J-agentlib:hprof[=options] ToBeProfiledClass

完整的命令格式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Option Name and Value  Description                    Default
--------------------- ----------- -------
heap=dump|sites|all heap profiling all
cpu=samples|times|old CPU usage off
monitor=y|n monitor contention n
format=a|b text(txt) or binary output a
file=<file> write data to file java.hprof[.txt]
net=<host>:<port> send data over a socket off
depth=<size> stack trace depth 4
interval=<ms> sample interval in ms 10
cutoff=<value> output cutoff point 0.0001
lineno=y|n line number in traces? y
thread=y|n thread in traces? n
doe=y|n dump on exit? y
msa=y|n Solaris micro state accounting n
force=y|n force output to <file> y
verbose=y|n print messages about dumps y

  • 每隔20毫秒采样CPU消耗信息,堆栈深度为3
    1
    java -agentlib:hprof=cpu=samples,interval=20,depth=3 Hello.java
  • 获取CPU消耗信息,能够细到每个方法调用的开始和结束,它的实现使用了字节码注入技术(BCI)
    1
    javac -J-agentlib:hprof=cpu=times Hello.java
1
javac -J-agentlib:hprof=heap=sites Hello.java
1
javac -J-agentlib:hprof=heap=dump Hello.java

注意在JVM启动参数中加入-Xrunprof:heap=sites参数可以生成CPU/Heap Profile文件,但对JVM性能影响非常大,不建议在线上服务器环境使用

jinfo查看jvm启动参数

1
2
3
4
// 看出所有参数
jinfo -flags pid
// 查看某个具体参数,例如InitialHeapSize
jinfo -flag InitialHeapSize pid

avatar

  • 开启/关闭某个jvm参数

    使用jinnfo可以在不重启虚拟机的情况下,动态修改jvm的参数,这个方法在生产环境尤其特别有用

    1
    2
    3
    // jinfo -flag [+|-]name pid
    jinfo -flag +PrintGC pid
    jinfo -flag -PrintGC pid
  • 修改某个JVM进程的值
    1
    2
    // jinfo -flag name=value pid
    jinfo -flag InitialHeapSize=64g pid

    注意并不是所有参数都支持动态修改

  • 查看当前jvm进程所有的系统属性
    1
    jinfo -sysprops pid
    avatar

free命令查看机器物理内存

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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
OPTIONS
-b, --bytes
Display the amount of memory in bytes.

-k, --kilo
Display the amount of memory in kilobytes. This is the default.

-m, --mega
Display the amount of memory in megabytes.

-g, --giga
Display the amount of memory in gigabytes.

--tera Display the amount of memory in terabytes.

-h, --human
Show all output fields automatically scaled to shortest three digit unit and display the units of print out. Following units are used.

B = bytes
K = kilos
M = megas
G = gigas
T = teras

If unit is missing, and you have petabyte of RAM or swap, the number is in terabytes and columns might not be aligned with header.

-w, --wide
Switch to the wide mode. The wide mode produces lines longer than 80 characters. In this mode buffers and cache are reported in two separate columns.

-c, --count count
Display the result count times. Requires the -s option.

-l, --lohi
Show detailed low and high memory statistics.

-s, --seconds seconds
Continuously display the result delay seconds apart. You may actually specify any floating point number for delay, usleep(3) is used for microsecond resolu‐
tion delay times.

--si Use power of 1000 not 1024.

-t, --total
Display a line showing the column totals.

--help Print help.

-V, --version
Display version information.

avatar

问题背景

接收到告警短信,web应用登陆无响应,请求api均为504

影响范围

平台无法正常使用

排查过程

一般情况下,cpp应用占用cpu较高的原因大部分分为以下两个情况:

  • 应用属于计算密集型应用
    使用大量 CPU 会导致平均负载升高,此时system loadcpu使用数率值上是一致的
  • 应用中出现了IO密集型应用
    等待 I/O 也会导致平均负载升高,但 CPU 使用率不一定很高,所以system loadcpu使用率并不会一致

查询该机器的系统负载(system load)

  • 1.系统负载:
    是指系统cpu繁忙程度的度量指标,即有多少个进程在等待被cpu调度,就是进程等待cpu的队列长度

  • 2.平均负载:
    是指单位时间内,处于可运行状态和不可中断状态的进程数。所以,它不仅包括了正在使用 CPU 的进程,还包括等待 CPU 和等待 I/O 的进程,实际上是系统的平均活跃进程数统计

  • 3.uptime详解

    1
    2
    3
    4
    5
    6
    7
    8
    // 观察uptime刷新,w命令/top命令皆可查询到系统的平均负载
    watch -D uptime
    // 得到结果
    11:10:17 up 628 days, 14:06, 2 users, load average: 0.05, 3.53, 6.59
    // 11:10:17是指当前系统时间
    // up 628 days, 14:06 是指机器运行时间
    // 2 users:是指当前登陆有2个用户
    // load average: 0.05, 3.53, 6.59:是指当前1分钟/5分钟/15分钟的平均负载指

    假设平均负载是2,当前cpu数是2cores则说明cpu100%使用,如果是4cores则说明cpu利用率是50%,如果是1cores,则说明有一半的进程都竞争得不到cpu

  • 3.如何查看机器的核心(core)呢

    1
    cat /proc/cpuinfo | grep cores | wc -l
  • 4.如何查看机器是否开启超线程呢?
    1
    2
    // 如何得到的值和grep cores后得到的核心数一致,则说明未开启
    cat /proc/cpuinfo | grep processor | wc -l
    比如我们的机器2颗物理cpu,在每颗物理cpu上又做了6颗逻辑CPU,之后在每颗逻辑CPU上又实现了超线程后,假如此时你在系统中使用cat /proc/cpuinfo |grep ‘processor’|wc –l返回24颗,如果load值(15分钟的返回值作为参考依据)长期在24以上,说明系统已经很繁忙了。

具体分析系统瓶颈

结合平均负载分析,假如我们当前已经知道load很高,但是仍然无法判断是cpu占用率高,还是系统I/O繁忙,又或者是内存不足导致的?

1
vmstat 1

cgi

  • 1、procs列
    r 列表示运行和等待cpu时间片的进程数,如果长期大于cpu核心数,说明cpu不足,需要增加cpu。
    b 列表示在等待资源的进程数,比如正在等待I/O、或者内存交换等。
  • 2、system 显示采集间隔内发生的中断数
    in 列表示在某一时间间隔中观测到的每秒设备中断数。
    cs 列表示每秒产生的上下文切换次数,如当 cs 比磁盘 I/O 和网络信息包速率高得多,都应进行进一步调查。

  • 3、memory列
    swpd 切换到内存交换区的内存数量(k表示)。如果swpd的值不为0,或者比较大,比如超过了100m,只要
    free 当前的空闲页面列表中内存数量(k表示)
    buff 作为buffer cache的内存数量,一般对块设备的读写才需要缓冲。
    cache 作为page cache的内存数量,一般作为文件系统的cache,如果cache较大,说明用到cache的文件较多,如果此时IO中bi比较小,说明文件系统效率比较好。

  • 4、swap列
    si 由内存进入内存交换区数量。
    so 由内存交换区进入内存数量。
    siso的值长期为0,系统性能还是正常

  • 5、IO列
    bi 从块设备读入数据的总量(读磁盘)(每秒kb)。
    bo 块设备写入数据的总量(写磁盘)(每秒kb)
    这里我们设置的bi+bo参考值为1000,如果超过1000,而且wa值较大应该考虑均衡磁盘负载,可以结合iostat输出来分析。

  • 6、cpu列
    cs 表示cpu的使用状态
    us 列显示了用户方式下所花费 CPU 时间的百分比。us的值比较高时,说明用户进程消耗的cpu时间多,但是如果长期大于50%,需要考虑优化用户的程序。
    sy 列显示了内核进程所花费的cpu时间的百分比。这里us + sy的参考值为80%,如果us+sy 大于 80%说明可能存在CPU不足
    id 列显示了cpu处在空闲状态的时间百分比
    wa 列显示了IO等待所占用的CPU时间的百分比。这里wa的参考值为30%,如果wa超过30%,说明IO等待严重,这可能是磁盘大量随机访问造成的,也可能磁盘或者磁盘访问控制器的带宽瓶颈造成的(主要是块操作)。

通过以上分析,可以知道当前机器的瓶颈是cpu负载过高,那么如何知道哪个进程占用cpu资源呢?

查询该机器cpu占用最高的进程

1
2
// 每5秒统计一次
pidstat -u 5 1

cgi

也可以使用top命令查询到cpu占用最高的进程

查询该机器的cpu使用情况

1
2
// 每5秒刷新一次查看所有cpu的统计情况
mpstat -P ALL 5

cgi

查看到进程ID后,可以通过ps aux | grep pid查看进程的详情

1
ps aux | grep pid

cgi

定位到最耗cpu的进程后,使用top -Hp pid命令查看线程列表,并找到占用cpu最高的线程

1
2
3
// `tid`表示线程`ID`,`time`表示线程已经运行的时间
// 这个命令也一样使用ps -mp pid -o THREAD,tid,time | sort -rn
top -Hp pid

cgi

将需要的线程ID转换为16进制格式,可以使用printf "%x\n" tid命令

1
printf "%x\n" tid

warning ipv4 forwarding is disabled. networking will not work.

  • 起因
    今天早上有个同学找过来问为什么xx平台502了,原谅笔者没有没有对该xx平台配置监控告警,原因是这个平台用户数太少。
  • 进入服务器查询
    1
    2
    3
    4
    5
    6
    7
    8
    1. 查log
    docker logs xx
    2. 无报错log,查nginx》error.lo
    connection timeout...
    3. nginx提示连接超时了,ping服务
    curl -i http://ip:port/api/xx/yy
    4. 给了200的返回码,去外网再ping,
    curl: (7) Failed to connect to ip port: Operation timed out
  • 结论,外网无法连通这个ip和端口
    1
    2
    3
    1. 重启docker container
    sudo docker restart container_name
    WARNING: IPv4 forwarding is disabled. Networking will not work.
  • docker network bridge
    docker-bridge

    由于宿主机的IP地址与容器veth pair的 IP地址均不在同一个网段,故仅仅依靠veth pair和namespace的技术,还不足以使宿主机以外的网络主动发现容器的存在。为了使外界可以访问容器中的进程,docker采用了端口绑定的方式,也就是通过iptables的NAT,将宿主机上的端口流量转发到容器内的端口上。
    举例说明

    1
    2
    3
    4
    5
    1. 创建容器,并将宿主机的3306端口绑定到容器的3306端口
    docker run -tid --name db -p 3306:3306 MySQL
    2. 宿主机上,可以通过iptables -t nat -L -n,查到一条DNAT规则
    DNAT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:3306 to:172.17.0.5:3306
    3. 以上的172.17.0.5即为bridge模式下,创建的容器IP
  • 开启 ip 转发

    1
    2
    3
    sudo echo net.ipv4.ip_forward=1 >> /etc/sysctl.d/enable-ip-forward.conf
    或者
    sudo echo 1 > /proc/sys/net/ipv4/ip_forward
  • 重启 network 服务
    1
    sudo systemctl restart network
  • 查看 network 服务
    1
    sudo sysctl net.ipv4.ip_forward

    返回为“net.ipv4.ip_forward = 1”则表示成功了

  • 重启容器
    1
    sudo docker restart container_name
  • 如果还提示上面的ipv4问题
    1
    sudo systemctl restart docker.service
  • 删除容器,再run
    1
    2
    sudo docker rm -f xx
    sudo docker run -d --name xx image_name

  • 关闭mysqld
    1
    ps aux | grep mysqld | grep -v grep | awk '{print $2}' | xargs kill -9
  • 修改my.conf
    1
    2
    3
    vim /etc/my.conf
    # 找到[mysqld]这个section,添加skip-grant-tables,意思是忽略所有表的授权
    skip-grant-tables
  • 开启mysqld服务
    1
    mysqld &
  • 进入mysql,设置密码为空
    1
    2
    3
    4
    5
    mysql -u root
    mysql> use mysql;
    mysql> update user set authentication_string='' where user='root';
    mysql> flush privileges;
    mysql> exit;
  • 撤回skip-grant-tables
    1
    2
    vim /etc/my.conf
    # 找到[mysqld]这个section,注释掉skip-grant-tables
  • 重启mysqld
    1
    2
    ps aux | grep mysqld | grep -v grep | awk '{print $2}' | xargs kill -9
    mysqld &
  • 无密码登录mysql
    1
    2
    3
    4
    5
    6
    mysql -uroot -p

    mysql> use mysql;
    mysql> ALTER user 'root'@'localhost' IDENTIFIED BY 'Qian123#';
    mysql> flush privileges;
    mysql> exit;

  • beego是什么

    beego 是一个快速开发 Go 应用的 HTTP 框架,他可以用来快速开发 API、Web 及后端服务等各种应用,是一个 RESTful 的框架,主要设计灵感来源于 tornado、sinatra 和 flask 这三个框架,但是结合了 Go 本身的一些特性(interface、struct 嵌入等)而设计的一个框架。beego

  • 查看go的安装环境

    1
    go env || grep GO111MODULE

    go-env

  • 打开GO111MODULE

    go在1.11之后推出了自己的官方版本管理工具mod,需要使用mod必须将go的配置参数GO111MODULE打开,用以支持使用模块,注意在打开GO111MODULE后下载的依赖还是存在$GOPATH/pkg/mod中,而go install的结果放在$GOPATH/bin下,但是项目不再局限放在$GOPATH/src下,在任何位置我们都可以使用到$GOPATH/pkg/mod下的依赖

    1
    go env -w GO111MODULE=on
  • 修改go proxy

    由于wall的存在,我们无法使用官方的go proxy,所以需要修改proxy地址

    1
    go env -w GOPROXY=https://goproxy.cn,direct
  • 安装beego和bee

    1
    go get github.com/astaxie/beego
  • 安装bee工具

    bee 工具是一个为了协助快速开发 beego 项目而创建的项目,您可以通过 bee 快速创建项目、实现热编译、开发测试以及开发完之后打包发布的一整套从创建、开发到部署的方案。

    1
    go get github.com/beego/bee
  • 把bee添加为系统命令

    1
    2
    export GOPATH=/Users/blanklin/go
    export PATH=$PATH:$GOPATH/bin
  • 新建helloworld项目

    1
    bee new helloworld
  • helloworld项目目录结构
    helloworld
    ├── conf
    │ └── app.conf
    ├── controllers
    │ └── default.go
    ├── main.go
    ├── models
    ├── routers
    │ └── router.go
    ├── static
    │ ├── css
    │ ├── img
    │ └── js
    ├── tests
    │ └── default_test.go
    └── views
    └── index.tpl

  • 新建api项目

    1
    bee api helloworld
  • api项目目录结构
    helloworld
    ├── conf
    │ └── app.conf
    ├── controllers
    │ └── object.go
    │ └── user.go
    ├── docs
    │ └── doc.go
    ├── main.go
    ├── models
    │ └── object.go
    │ └── user.go
    ├── routers
    │ └── router.go
    └── tests
    └── default_test.go

和web项目对比,少了 static 和 views 目录,多了一个 test 模块,用来做单元测试的
可直接通过参数创建orm:bee api [appname] [-tables=””] [-driver=mysql] [-conn=root:@tcp(127.0.0.1:3306)/test]

  • 使用go mod

    1
    go mod init helloworld
  • 运行beego项目

    1
    2
    3
    bee run
    # 配合conf/app.conf[EnableDocs = true]开启swagger
    bee run -downdoc=true -gendoc=true

    打开浏览器访问beego开启的本地端口,一般是8080,所以地址是:http://localhost:8080

  • 使用pack命令部署生产环境

    1
    2
    3
    4
    bee pack -be GOOS=linux
    # 生成一个压缩文件helloworld.tar.gz
    # 在生成环境解压后运行
    nohup ./helloworld &
  • 使用docker部署生产环境

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    FROM golang:1.14.2-buster

    ENV TZ Asia/Shanghai
    ENV GOKU_LOGLEVEL info

    ENV GOKU_RUNMODE prod
    ENV GOKU_PORT 8080

    RUN go build -v -o ./build/goku ./main.go

    WORKDIR /app

    COPY ../conf /app/conf
    COPY ./build/goku /app/goku

    ENTRYPOINT ["./goku"]
  • 本项目GitHub
    https://github.com/blanklin030/beego-docker

    提供初始化后支持mysql的基础crud和相关配置

  • zabbix介绍

    通过官网我们可以了解zabbix5.0和之前版本的差异及作出的改进

  • 下载zabbix5.0源码

    1
    2
    3
    4
    yum -y install  epel-release wget tar
    wget https://cdn.zabbix.com/zabbix/sources/stable/5.0/zabbix-5.0.2.tar.gz
    tar zxvf zabbix-5.0.2.tar.gz
    cd zabbix-5.0.2
  • 创建zabbix用户

    1
    2
    3
    groupadd zabbix
    useradd -g zabbix zabbix
    usermod -s /sbin/nologin zabbix
  • mysql相关操作

    安装mysql5.7请参考地址

    • 创建zabbix数据库并且授权给zabbix@123456访问
      1
      2
      3
      create database zabbix character set utf8 collate utf8_bin;
      grant all on zabbix.* to zabbix@localhost identified by '123456';
      flush priviledges;
    • 导入zabbix数据到mysql
      1
      2
      3
      mysql -uzabbix -p123456 zabbix < database/mysql/schema.sql
      mysql -uzabbix -p123456 zabbix < database/mysql/images.sql
      mysql -uzabbix -p123456 zabbix < database/mysql/data.sql
  • php7.2安装

    安装php7.2请参考地址

  • nginx安装

    安装nginx请参考地址

  • 安装zabbix-server

    1
    2
    3
    ./configure --prefix=/usr/local/zabbix  --enable-server --enable-agent --with-mysql --enable-ipv6 --with-net-snmp --with-libcurl --with-libxml2
    make&&make install
    chown zabbix:zabbix /usr/local/zabbix/ -R
  • 创建软链接,把zabbix命令设置为系统命令
    1
    ln -s /usr/local/zabbix/sbin/zabbix_*  /usr/local/sbin/
  • 配置zabbix启动脚本

    1
    2
    # 在zabbix源码目录下
    cp misc/init.d/tru64/{zabbix_agentd,zabbix_server} /etc/init.d/;chmod o+x /etc/init.d/zabbix_*
  • 配置zabbix-web

    1
    2
    3
    # 在zabbix源码目录下
    cp -a ui/* /var/www/html/zabbix/
    chown -R nginx:nginx /var/www/html/zabbix
  • 配置nginx
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    server{
    listen 80;
    server_name localhost;
    set $host_path "/var/www/html/zabbix";
    root "$host_path";
    index index.html index.htm index.php;

    location ~ \.php$ {
    fastcgi_pass 127.0.0.1:9000;
    fastcgi_index index.php;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    include fastcgi_params;
    }
    }
  • 配置php

    1
    2
    3
    4
    post_max_size = 16M
    max_execution_time = 300
    max_input_time = 300
    date.timezone = Asia/Shanghai
  • 修改 zabbix server 配置文件

    1
    2
    3
    4
    5
    6
    7
    8
    cd /usr/local/zabbix/etc
    cp zabbix_server.conf zabbix_server.conf.bak
    # 修改以下配置
    LogFile=/tmp/zabbix_server.log
    DBHost=localhost
    DBName=zabbix
    DBUser=zabbix
    DBPassword=123456
  • 重启zabbix server和nginx和php-fpm

    1
    2
    3
    /etc/init.d/zabbix_server  restart
    nginx -s reload
    systemctl restart php
  • 访问zabbix web gui进行安装配置
    zabbix-web-1
    zabbix-web-2
    zabbix-web-3

  • 源码部署zabbix agent

    1
    2
    3
    4
    5
    6
    7
    8
    yum -y install curl curl-devel net-snmp net-snmp-devel perl-DBI
    groupadd zabbix
    useradd -g zabbix zabbix
    usermod -s /sbin/nologin zabbix
    tar -xzf zabbix-5.0.2.tar.gz
    cd zabbix-5.0.2
    ./configure --prefix=/usr/local/zabbix --enable-agent
    make install
  • 创建软链接
    1
    ln -s /usr/local/zabbix/sbin/zabbix_* /usr/local/sbin/
  • 配置启动脚本

    1
    2
    3
    cd zabbix-5.0.2
    cp misc/init.d/tru64/zabbix_agentd /etc/init.d/zabbix_agentd
    chmod o+x /etc/init.d/zabbix_agentd
  • 修改配置

    1
    2
    3
    4
    5
    vim /usr/local/zabbix/etc/zabbix_agentd.conf
    LogFile=/tmp/zabbix_agentd.log
    Server=192.168.2.214 #server端ip
    ServerActive=192.168.2.214 #server端ip
    Hostname = 192.168.2.215 #agent端ip或者是主机名都可以
  • 启动agent

    1
    /etc/init.d/zabbix_agentd
  • 自动发现agent
    zabbix-web-5

yum安装过程

  • 安装nginx最新源
    1
    yum localinstall http://nginx.org/packages/centos/7/noarch/RPMS/nginx-release-centos-7-0.el7.ngx.noarch.rpm
  • 安装nginx
    1
    yum -y install nginx
  • 启动nginx
    1
    yum -y install nginx
  • 设置nginx开机启动
    1
    2
    3
    systemctl enable nginx.service
    # 检查是否成功
    systemctl list-dependencies | grep nginx
  • 通过 egrep 查询 nginx 服务器的用户和用户组

    1
    egrep '^(user|group)' /etc/nginx/nginx.conf
    • 结果示例:
      1
      user nginx;
  • 路径整理

    1
    2
    3
    4
    5
    # nginx 配置文件
    /etc/nginx/nginx.conf

    # nginx 默认项目路径
    /usr/share/nginx/html