计算机

Linux 下的内核参数调优与 sysctl

最近在配置 influxdb 的 udp 端口的时候看到文档[1]里面提到:强烈建议修改 Linux 的默认网络 buffer 大小,否则会对性能有严重影响。感觉挺有意思,深入研究了一下 Linux 下 TCP 和 UDP 的一些参数配置。

influxdb 的推荐配置

首先查看这两个配置:

sysctl net.core.rmem_max  # 读取 buffer 最大值
sysctl net.core.rmem_default  # 读取 buffer 默认值

然后更新这两个配置为 25 MiB

sysctl -w net.core.rmem_max=26214400
sysctl -w net.core.rmem_default=26214400

最后写入到配置文件,以便重启之后依然生效

# /etc/sysctl.conf
net.core.rmem_max=26214400
net.core.rmem_default=26214400

这里的设置其实就是增大网络 buffer 的大小,避免收到的 udp 包过多的时候造成丢包或者阻塞的现象。

sysctl 命令

在上面的命令中,我们使用了 sysctl。sysctl 的 man page 也很简洁:sysctl – configure kernel parameters at runtime。也就是说在运行时调整内核参数。

sysctl -a 显示当前的所有参数
sysctl -w xxx=xxx 设定内核参数
sysctl xxx 显示内核参数的值
sysctl -fFILE 加载给定文件的值,默认是 /etc/sysctl.conf 也就是我们刚刚更改的文件

我们可以看下阿里云上默认的 ubuntu 机器的 /etc/sysctl.conf 文件:

[email protected] [01:53:09 AM] [~]
-> % cat /etc/sysctl.conf
vm.swappiness = 0
net.ipv4.neigh.default.gc_stale_time=120

# see details in https://help.aliyun.com/knowledge_detail/39428.html
net.ipv4.conf.all.rp_filter=0
net.ipv4.conf.default.rp_filter=0
net.ipv4.conf.default.arp_announce = 2
net.ipv4.conf.lo.arp_announce=2
net.ipv4.conf.all.arp_announce=2

# see details in https://help.aliyun.com/knowledge_detail/41334.html
net.ipv4.tcp_max_tw_buckets = 5000
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_max_syn_backlog = 1024
net.ipv4.tcp_synack_retries = 2

kernel.sysrq=1

sysctl 可以控制的配置大概分成了以下几类:

  • 内核子系统 (通常前缀为: kernel.)
  • 网络子系统 (通常前缀为: net.)
  • 虚拟内存子系统 (通常前缀为: vm.)
  • MDADM 子系统 (通常前缀为: dev.)

对应的参数除了使用 sysctl 读取以外,还可以直接通过文件系统读取:

cat /proc/sys/net/core/

甚至也可以写入来直接更新内核参数,这样证实了 Linux 下一切皆文件的设计理念。

在 docker 中如何设置 sysctl

我们知道在 docker 中,容器适合宿主机共享同一个内核的,那么显然容器是不能随便动宿主机的配置的。所以 /proc/sys 目录在容器中默认是只读挂载的。

要想在容器运行的时候更改内核参数,需要在 docker run 的时候添加参数:

  1. --cap-add=SYS_ADMIN
  2. --privileged
  3. --sysctl

以上三个参数任选其一,应该就可以了

在 kubernetes 中如何设置 sysctl

在 docker 中设置还好说,其实就是把默认的只读属性去掉就好了。在 kubernetes 的 pod 中要想设置 sysctl 就比较复杂了,因为你不知道 pod 究竟会调度到哪台机器上。在这里我没有深入研究了,毕竟 influxdb 这种有状态的服务还没有迁到 kubernetes 上,看了下官方文档[4],大概思路是:

  1. 给对应机器的 kubelet 指定参数,然后使用 taint 调度到这台机器上
  2. 对于一些安全的属性,可以直接在 pod 中使用 securityContext 设置
apiVersion: v1
kind: Pod
metadata:
  name: sysctl-example
spec:
  securityContext:
    sysctls:
    - name: kernel.shm_rmid_forced
      value: "0"
    - name: net.core.somaxconn
      value: "1024"
    - name: kernel.msgmax
      value: "65536"
  ...

参考资料

  1. https://docs.influxdata.com/influxdb/v1.7/supported_protocols/udp/
  2. https://stackoverflow.com/questions/54845095/cannot-run-sysctl-command-in-dockerfile
  3. https://www.kernel.org/doc/Documentation/sysctl/README
  4. https://kubernetes.io/zh/docs/tasks/administer-cluster/sysctl-cluster/

节选:Choose Boring Technology

It’s really worthwhile to natually write down what all of the awkward things you’d have to do are. A lot of the time when you do this, you realize that the situation isn’t really that bad. Or it may be bad, but not as bad as the task of operationalizing a new thing.

But it can go the other way, too. You can list all of the unnatual costs and conclude that adding a new thing will be worth it.

Happiness comes from shipping stuff.

IT桔子逆向实战

使用 jadx 反编译

首先,我们到豌豆荚下载最新的 APK。然后执行 jadx-gui itjuzi.apk。很遗憾发现加壳了,应该是百度的壳,我们先跳过,去找一个老版本,看看有没有没加过壳的。

很遗憾,没有找到不带壳的版本,所以我们需要进行脱壳

脱壳

阅读了[这篇文章][1],我们知道凡是脱壳都会有两个步骤,一个是找到原始的 classes.dex 文件,一个是修复这个 dex 文件。

首先,我们知道动态加载的dex必然会调用dalvik/vm/DvmDex.cpp中以下两个函数任意一个:

  1. dvmDexFileOpenFromFd 从文件描述符获取DexFile结构体
  2. dvmDexFileOpenPartial 从内存获取DexFile结构体

通过编写函数可以把这个 dex 文件 dump 出来,但是这个函数运行在哪儿呢?

未完待续。。

[1] https://bbs.pediy.com/thread-218891.htm

手机如何使用 Charles 抓 https 包

问题描述

安装 Charles 之后,使用手机自带浏览器访问 http://chls.pro/ssl ,下载到了 getssl.crt 文件,点击安装之后提示“未找到可安装的证书”

解决方法

首先下载 Chrome 浏览器,然后再访问 http://chls.pro/ssl ,安装下载到的证书就好了。

通过浏览器访问 https://www.baidu.com ,Charles 中能够抓到包的内容,说明安装成功了

参考

  1. https://segmentfault.com/a/1190000011573699
  2. https://testerhome.com/topics/9445

systemd

YN:如何使安装的服务开机启动?是更改 wantedby 吗?如果是,wantedby 的值应该是什么?

对于 nginx 这样的 daemon 服务如何管理?


大多数的 Linux 系统已经选择了 systemd 来作为进程管理器。之前打算使用 supervisord 来部署服务,思考之后发现还不如直接使用 systemd 呢。这篇文章简单介绍下 systemd。

例子

我们从一个例子开始,比如说我们有如下的 go 程序:

package main

import (
    "fmt"
    "net/http"
)

func handler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Hi there!")
}

func main() {
    http.HandleFunc("/", handler)
    http.ListenAndServe(":8181", nil)
}

编译到 /opt/listen/listen 这里。

首先我们添加一个用户,用来运行我们的服务:

adduser -r -M -s /bin/false www-data

记下这条命令,如果需要添加用户来运行服务,可以使用这条。

Unit 文件

Unit 文件定义了一个 systemd 服务。/usr/lib/systemd/system/ 存放了系统安装的软件的 unit 文件,/etc/systemd/system/ 存放了系统自带的服务的 unit 文件。

我们编辑 /etc/systemd/system/listen.service 文件:

[Unit]
Description=Listen

[Service]
User=www-data
Group=www-data
Restart=on-failure
ExecStart=/opt/listen/listen
WorkingDirectory=/opt/listen

Environment=VAR1=whatever "VAR2=something else"
EnvironmentFile=/path/to/file/with/variables

[Install]
WantedBy=multi-user.target

然后

sudo systemctl enable listen
sudo systemctl status listen
sudo systemctl start listen

其他一些常用的操作还包括:

systemctl start/stop/restart    
systemctl reload/reload-or-restart  
systemctl enable/disable    
systemctl status    
systemctl is-active 
systemctl is-enabled
systemctl is-failed
systemctl list-units [--all] [--state=…]    
systemctl list-unit-files
systemctl daemon-reload 
systemctl cat [unit-name]   
systemctl edit [uni-name]
systemctl list-dependencies [unit]

依赖管理

In that case add Requires=B and After=B to the [Unit] section of A. If the dependency is optional, add Wants=B and After=B instead. Note that Wants= and Requires= do not imply After=, meaning that if After= is not specified, the two units will be started in parallel.

if you service depends on another service, use requires= + after= or wants= + after=

Type: simple / forking

关于每个字段的含义,可以参考这篇文章

使用 journalctl 查看日志

首先吐槽一下, 为什么要使用 journal 这么一个拗口的单词, 叫做 logctl 不好么…

journalctl -u service-name.service

还可以添加 -b 仅查看本次重启之后的日志.

启动多个实例

strace

尽管在线下会做充足的测试,但是线上出问题是难免的。当我们的程序在线上运行中遇到问题的时候,而我们又没有日志可以观察到底哪里出了问题,这时候可以使用 strace 命令。strace 可以直接根据 pid 附着到进程上,打印出进程的一些统计信息,为排查 bug 提供有意义的参考。

Strace 的选项

  1. c – See what time is spend and where (combine with -S for sorting)
  2. f – Track process including forked child processes
  3. o my-process-trace.txt – Log strace output to a file
  4. p 1234 – Track a process by PID
  5. P /tmp – Track a process when interacting with a path
  6. T – Display syscall duration in the output

Track by specific system call group

  1. e trace=ipc – Track communication between processes (IPC)
  2. e trace=memory – Track memory syscalls
  3. e trace=network – Track memory syscalls
  4. e trace=process – Track process calls (like fork, exec)
  5. e trace=signal – Track process signal handling (like HUP, exit)
  6. e trace=file – Track file related syscalls

Trace multiple syscalls

strace -e open,close

统计进程系统调用花费时间

strace -c -f -p 11084

一般来说要加上 -f 选项,这样才能跟踪多进程程序,也就是 fork 之后的进程。

strace -o output.txt -T -tt -e trace=all -p 28979

使用和这个命令可以统计每一个系统调用的时间

  1. 使用 struss 查看系统问题 https://www.ibm.com/developerworks/cn/linux/l-tsl/index.html
  2. strace 的详细用法 https://blog.csdn.net/uisoul/article/details/83143290
  3. https://blog.csdn.net/budong282712018/article/details/83151953
  4. https://blog.csdn.net/maple_leaves_for_me/article/details/42391979
  5. https://blog.51cto.com/5iwww/771031
  6. https://blog.csdn.net/lotluck/article/details/77943152
  7. https://linux-audit.com/the-ultimate-strace-cheat-sheet/

使用 caddy 运行 php

使用 caddy 运行 PHP

caddyfile

example.com {
    gzip
    root /srv
    fastcgi / 127.0.0.1:9000 php # php variant only
    on startup php-fpm7 # php variant only
}

example.com 记得改成自己的域名

docker-compose.yml

version: "3"

services:
  caddy:
    image: abiosoft/caddy:php
    environment:
      ACME_AGREE: 1
    volumes:
      - "/etc/Caddyfile:/etc/Caddyfile"
      - "/etc/caddy:/root/.caddy"
      - "/var/www/html:/srv"
    ports:
      - "80:80"
      - "443:443"
      - "2015:2015"

参考

  1. http://blog.extlux.com/2018/08/06/docker-%E8%BF%90%E8%A1%8C%E5%B8%A6php%E7%9A%84caddy/