私たちは、問題を発見しました
日常点検データストレージ、午前中に駐車した最新データの格納時間。すぐに問題を特定しようとすると、リモートサーバにログインします。
定期的なタスクが機能するかどうか、エラーメッセージがある場合
crontab -l
検査には実行中のエラーレコードが存在しない、通常のタスクが動作することがわかりました。
取得プログラムが実行されているビューのシステムプロセス、
ps -ef | grep xxxappspider
次の出力
朝の午前1時40分で、あなたは、プロセスが正常に起動見ることができますが、実行されていない、おそらくコードは、問題をデッドロック表示されますか?ログを表示するには有用な情報を記録しません。
コードを確認し、バグを再現しよう
サーバーでは、手動で正常に実行できるプログラムを実行します。コードの簡単なレビュー、それはデッドロックにつながるどこにも見つけることができませんでした。
この問題を解決します
より緊急のタスクが手元にありますので、単にログのより詳細なプログラムを追加して、スケジュールされたタスクが再び実行されているように、その後、詰まったプロセスを殺します。
次の問題が再び発生し、同じ正規タスクの朝は立ち往生場合に登場しました。まず、原因サーバ、他のタスクが正常に動作している同じサーバーを除外。ストレージを除外するための第2の理由は、私たちのコレクションは、データベースに格納された一連の操作の後、カフカへの統一されたキューの結果です。カフカは問題がないだけで、このタスクを1つ発生した場合、すべてのアプリケーションが、使用されているキュー。そして、あなたは大体それがこの仕事で、決定することができ、朝の何らかの理由で立ち往生しているため、実行されます。
まあ、それは私たちの大きなキルに自分自身を再配置する時間です:PY-スパイ
これは私がして聞いていた、Python用の性能解析ツールである「蛇が言う」ライブラリは、今と、それを利用することを知ったとき。
簡単に言えば使用する方法を見て:
[test@localhost ~]# py-spy --help
py-spy 0.1.11
A sampling profiler for Python programs
USAGE:
py-spy [FLAGS] [OPTIONS] --pid <pid> [python_program]...
FLAGS:
--dump Dump the current stack traces to stdout
-F, --function Aggregate samples by function name instead of by line number
-h, --help Prints help information
--nonblocking Don't pause the python process when collecting samples. Setting this option will reduce the
perfomance impact of sampling, but may lead to inaccurate results
-V, --version Prints version information
OPTIONS:
-d, --duration <duration> The number of seconds to sample for when generating a flame graph [default: 2]
-f, --flame <flamefile> Generate a flame graph and write to a file
-p, --pid <pid> PID of a running python program to spy on
-r, --rate <rate> The number of samples to collect per second [default: 100]
ARGS:
<python_program>... commandline of a python program to run
あなただけが視覚的義務のすべての時間のかかるプロセスを表示するには、Pythonのプロセスpidができるようになります入力する必要があります。さらに重要なのは、それがコードをリセットする必要はありません、私たちが今経験している状況のために非常に適切で実行することができます。
インストールは非常に簡単です:
pip install py-spy
使用するのは非常にシンプル:
# 先找到这个卡住的Python进程的pid
ps -ef |grep python |grep ***
# 启动 py-spy 观察这进程
py-spy --pid 32179
次のように出力情報は、次のとおりです。
可以看到,程序是卡在了建立网络连接的部分。hand_request
是一个为某个App请求签名的函数,被单独放在了utils
这个目录下。接下来就简单了,找到这个函数,在第43行,发现了一个 post 请求。嗯,其实不管是 post 还是 get 都不要紧,重要的是这个请求没有加 timeout
参数!!!
Requests 文档里写的很清楚了,如果没有超时参数,程序有可能永远失去响应。
超时
你可以告诉 requests 在经过以
timeout
参数设定的秒数时间之后停止等待响应。基本上所有的生产代码都应该使用这一参数。如果不使用,你的程序可能会永远失去响应:>>> requests.get('http://github.com', timeout=0.001) Traceback (most recent call last): File "<stdin>", line 1, in <module> requests.exceptions.Timeout: HTTPConnectionPool(host='github.com', port=80): Request timed out. (timeout=0.001)
注意
timeout
仅对连接过程有效,与响应体的下载无关。timeout
并不是整个下载响应的时间限制,而是如果服务器在timeout
秒内没有应答,将会引发一个异常(更精确地说,是在timeout
秒内没有从基础套接字上接收到任何字节的数据时)If no timeout is specified explicitly, requests do not time out.
至此,Debug完成。
总结
这么低级的 bug,确实是我自己写的。
当初写的时候忽视了这个问题,测试的时候没有发现问题也就过去了。第一次发现问题的时候,查问题并不仔细,只简单看了spiders
目录下的几个爬虫代码,没有去检查utils
目录下的工具类的代码,故而并没有找到具体问题。第二次通过 py-spy 的帮助,成功找到并解决了问题。
解决问题后,反思下原因:很可能是这个 App 会在凌晨进行维护,导致请求没有得到响应,同时没有设置超时函数,程序就会一直卡在哪里。
最后,推荐一下《捕蛇者说》,这是一个关于“编程、程序员、Python”的中文博客。没事听听大佬们唠嗑,真的很涨知识。