Author: 逸飞

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

张一鸣:你的尺子的长度

编者按:今天例行摸鱼过程中在 Web Archive 上偶然发现了一篇“99房”的博客。99房是张一鸣在创立字节跳动之前的创业项目。根据文中的“延迟满足感”等词,我推测这篇文章应该是他写的吧。在 Google 上搜索了文中的几个句子,发现这篇文章并没有见诸媒体。文章写得挺好,分享给大家。

请注意,本文未获得任何转载授权,主要是除了 CEO 面对面的时候在几十米外眺望过以外,我也和张一鸣没有任何交集……Anyway,如果有任何问题,我当立即删除此文就是了。

原文发表于 2011 年 4 月 11 日。不到一年后,张一鸣创立了字节跳动。

原文链接(需特殊上网能力方可访问):https://web.archive.org/web/20110924075809/http://blog.99fang.com/?p=151

先说一个问题:我已经有一年多没写博客了。原因有两个。

1、发现我所谓的一点感悟和总结,其实很多经典的书有系统的分析和著名的人也有经典的总结,自己写的对人帮助少。

2、相信少说多做,延迟满足感,人生废话居多,行动太少。

但是后来发现这两点不全对。按照哲学和科学的体系,大多数事情都可以从少数公理开始推导,还是需要具体的定理和行动来指导行动。对于写博客而言,只要能做到对有相似经历和相似背景的读者有所裨益,相对容易有共鸣和帮助,就有了价值不是“废话”。

回到正题:看待事情,衡量经历,很多就像拿把尺子去估量,当然这个尺子也许不是一维的,或许也不是直的,但是我发现有一个最关键的因素是这个尺子是否足够长。尺子长短能决定测量的结论:比如你拿把短的尺子去量铁轨是否是直的,答案肯定都是直的。随着年龄的增长,经常发现当年自己在某个问题上想错了,做法错了。这种情况很多时候是因为当年因为年纪小,经历短,所以只能拿把短的尺子去衡量。

我想举几个事情:

1、选择工作:大学毕业的你对于 5 千元薪水和 7 千元薪水,你用当时的尺子感觉差距一定不小。但是可能 3-5 年后,你会发现这个差距可以作为误差,毕业选择工作的时候可以忽略不计此因素。

2、寻找伴侣:年轻人少有对未来伴侣的人品,价值观、追求等关注,肯定少于对外形、活泼,甚至少于对星座、爱好的关注。但是 30 岁的时候你再找(如果你还没找到),相信会变化。

3、关于度尽劫波兄弟在,相逢一笑泯恩仇:我想应该是既然劫波已度过,尺子自然变长了,恩仇已然不重要,是是非非成鸡毛蒜皮。

这些问题有人说是需要阅历,我同意。但是我更多取决于于你心里对尺子设置的长度,你若心中想的是人生你的尺子自然就长当然也不会那发型是否酷来寻找伴侣。

:) 回到正题的正题:创业公司拿多长的尺子去衡量人?

1、是否以会 gdb 打印 map、是否写过分词程序来招工程师,是否以会用 visio 图来招聘产品经理?

2、是否以业内有客户关系来评判商务总监候选人,亦或是在媒体有所资源来选择PR经理?

我想这取决于你如何看待创业,如果你把目光可能到下个月的进展,这些尺子自然合适,但是如果你把创业看作是做一个创造巨大价值的公司和伟大组织的长跑,我相信这些都不是重要标准。这时候你会更加看重:人品、作风、学习力、反省力、价值观。如下三把尺子是递长的:Ta 一年后在公司承担的角色和能成长的高度;假设还有下次创业是否还希望邀请;会不会成为人生道路上的可信赖的好伙伴。

还有一些更极端的例子,在“仰望星空”的时,在想像浩瀚宇宙的边界时,在险峻山峰一览众山小的时,很多人感到看待问题会开阔深刻很多,这些也可以理解成尺子长度变化的效果。

所以很多事情用长的尺子和短尺子衡量的结果不一样。如果你希望的更远,请别忘适时的选择长尺子。

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 仅查看本次重启之后的日志.

启动多个实例