Skip to content

Commit 5e2bfc9

Browse files
committed
debug skill
1 parent 700ced8 commit 5e2bfc9

File tree

1 file changed

+20
-7
lines changed

1 file changed

+20
-7
lines changed

debug/index.rst

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -64,32 +64,44 @@ Debug 调试技巧
6464
- 拼写错误。不要笑,这个错误其实很常见,推荐打开编辑器的拼写检查,可以消除一些类似问题。
6565
- 类型错误。在动态语言和弱类型语言当中比较常见的一种错误(动态语言确实更容易出 bug),可以借助类型强转,type hint 工具。
6666
- 资源没有关闭。打开的文件等资源一定要关闭,防止资源泄露。go 的 defer 和 python 的 with 最好用上
67-
- 连接池使用不当打满连接数。连接池应该是全局共享的(单例),而不是每个请求都要去创建连接池。连接池应该是一个应用共享的
6867
- 深浅拷贝问题。不同语言可能又不同的拷贝模型,确定你的参数是深拷贝还是浅拷贝,能否修改,修改了之后是否有副作用。
69-
- 请求超时。网络请求的 client 是否有设置超时,比如有些 go 的 client 需要显式自己传进去超时参数
7068
- 数组越界错误。注意涉及到数组的时候使用的下标是否会越界。越界了 python 抛出异常,go 直接 panic 掉。
7169
- 参数校验。一般来自用户的输入都要假设参数可能是错误甚至是恶意参数,后台必须要进行类型,长度等检查
7270
- 参数单位是否匹配。比如 go 需要时间的参数 time.Duration 有没有乘以对应的 time.Second/MilliSecond 等。
73-
- 数据库查询参数错误。查询数据库的时候可能因为一些不合理参数导致数据库慢查询,比如过量查询导致慢查询。可以在入口处做一下限制。比如限制limit 大小
7471
- 路径错误。编写一些脚本需要处理文件的时候,推荐使用绝对路径比较不容易出错。
7572
- 空值错误。比如直接赋值一个 go 里边的 map 会 panic,你需要先给 map make 一个值,很多 go 新手会重复犯这个错(go slice 却可以直接声明之后 append)
7673
- 零值和空值。有时候我们根据业务来区分零值(一个类型的初始化值)和空值 (None/nil等),注意处理上的细微区别。
7774
- 闭包问题。循环里闭包引用的是最后一个循环变量的值,需要注意一下,很多语言都有类似问题,可以通过临时变量或者传参的方式避免
7875
- 遍历修改列表问题。一边遍历,一边修改可能会使得迭代器失效而出错,最好不要遍历的时候修改列表。
7976
- 遍历修改元素值问题。这一点 go 和 python 表现不同,go 比如你去循环一个 []Struct 是无法修改每个元素的,go 会拷贝每一个元素值,需要通过下标或者指针修改
8077

78+
网络问题
79+
~~~~~~~~~~~~~~~~~~~~~~
80+
- 请求超时。网络请求的 client(http/rpc) 是否有设置超时,比如有些 go 的 client 需要显式自己传进去超时参数,否则可能导致 block
81+
- 连接池打满。连接池应该是服务共享的(单例),而不是每个请求都要去创建连接池导致打满连接池
82+
83+
数据库问题
84+
~~~~~~~~~~~~~~~~~~~~~~
85+
- 查询参数非法。查询数据库的时候可能因为一些不合理参数导致数据库慢查询,比如过量查询导致慢查询。可以在入口处做一下限制。比如限制limit 大小
86+
- 查询参数类型不匹配。注意如果传入类型不对,可能导致数据库没法利用索引导致慢查询,注意查询的参数类型和数据库类型匹配
87+
- 连接池跳涨。除了不当使用连接池之外,如果是启动了大量的服务容器也可能有这个问题,注意限制单服务连接池的大小
88+
- 主写从读。很多采用最终一致性模型,但是对于一些对时延敏感的场景要考虑是否会有主从延迟问题
89+
8190
并发问题
8291
~~~~~~~~~~~~~~~~~~~~~~
83-
- 线程安全。如果不是线程安全的操作,应该通过加锁等方式做数据同步。比如 go 里边如果多个 goroutine 并发读写 map 程序会出错。利用好 race detector
84-
但是有些语言有 GIL 可以保证内部数据结构的一些原子操作,所以要区分不同编程语言决定。
92+
- 线程安全。如果不是线程安全的操作(原子操作),应该通过加锁等方式做数据同步。比如 go 里边如果多个 goroutine 并发读写 map 程序会出错(lock/sync.Map)。利用好 race detector。
93+
但是有些语言有 GIL 可以保证内部数据结构的一些原子操作,这个时候可以不用加锁,所以要区分不同编程语言决定。
94+
- 分布式锁。分布式服务对于需要数据同步的操作可以使用分布式锁
95+
- goroutine泄露。确保你的 goroutine 可以完成退出
8596

8697
依赖库问题
8798
~~~~~~~~~~~~~~~~~~~~~~
88-
- 依赖版本是否一致。笔者曾经因为开发工具的自动 import 引入了错误的包导致一个挺难查的 bug(vendor 和 gopath 下不同的redigo 版本)
99+
- 依赖版本是否一致。笔者曾经因为开发工具的自动 import 引入了错误的包版本导致一个挺难查的 bug(vendor 和 gopath 下不同的redigo 版本),
100+
要小心因为不同版本导致的一些隐蔽的难查的 bug。
89101

90102
日志错误
91103
~~~~~~~~~~~~~~~~~~~~~~
92-
- 日志级别错误。线上使用了 debug 级别,可能导致日志打满,如果没有滚动日志可能会导致服务器磁盘打满。一定要注意不同环境日志级别
104+
- 日志级别错误。线上使用了 debug 级别,可能导致日志打满,如果没有滚动日志可能会导致服务器磁盘打满。一定要注意不同环境日志级别,推荐集中式日志收集系统
93105
- 日志参数错误。日志语句对应的占位符要和传参的个数一致。
94106
- 缺少足够信息。如果是为了 debug 加上的日志一定要有足够的上下文信息帮助排查问题。
95107

@@ -101,6 +113,7 @@ Debug 调试技巧
101113
~~~~~~~~~~~~~~~~~~~~~~
102114
- 配置环境写错。看起来是一个很傻的错误,但是其实还挺常见,注意不同环境配置是否对的上,别把测试的写到正式环境了。启动服务时打印配置看看
103115
- 服务启动命令是否写错。有些服务依赖命令行启动的时候容易写错参数,建议通过配置文件的形式传进去。
116+
- 配置字符串是否有多余空白符。笔者也被这个小问题坑过,手动编辑的时候人工加上了空白符导致我比对出错,注意配置参数都要去掉空白符
104117

105118
字符串问题
106119
~~~~~~~~~~~~~~~~~~~~~~

0 commit comments

Comments
 (0)