我有一个基于python的守护进程,通过HTTP为一些命令行工具提供类似REST的接口.该工具的一般性质是接受请求,执行一些命令行操作,将pickle数据结构存储到磁盘,并将一些数据返回给调用者.在守护程序启动时产生了一个辅助线程,它定期查看磁盘上的pickle数据,并根据数据中的内容进行一些清理.
如果pickle数据所在的磁盘恰好是Linux机器上的本地磁盘,则可以正常工作.如果你切换到安装了NFS的磁盘,守护进程就可以正常启动,但是随着时间的推移,NFS挂载的共享"消失",并且守护进程无法通过类似的调用来判断它在磁盘上的位置os.getcwd().您将开始看到它记录错误,如:
2011-07-13 09:19:36,238 INFO Retrieved submit directory '/tech/condor_logs/submit'
2011-07-13 09:19:36,239 DEBUG CondorAgent.post_submit.do_submit(): handler.path: /condor/submit?queue=Q2%40scheduler
2011-07-13 09:19:36,239 DEBUG CondorAgent.post_submit.do_submit(): submitting from temporary submission directory '/tech/condor_logs/submit/tmpoF8YXk'
2011-07-13 09:19:36,240 ERROR Caught un-handled exception: [Errno 2] No such file or directory
2011-07-13 09:19:36,241 INFO submitter - - [13/Jul/2011 09:19:36] "POST /condor/submit?queue=Q2%40scheduler HTTP/1.1" 500 -
Run Code Online (Sandbox Code Playgroud)
未处理的异常解析为守护程序无法再查看磁盘.此时任何试图找出守护程序当前工作目录的尝试os.getcwd()都将失败.即使尝试更改为NFS挂载的根目录/tech也会失败.一直logger.logging.*以来,这些方法都很乐意将日志和调试消息写入位于NFS安装的共享位置的日志文件中/tech/condor_logs/logs/CondorAgentLog.
磁盘绝对是可用的.还有其他基于C++的守护进程,在基于python的守护进程时,在此共享上具有更高的频率读取和写入.
我陷入了调试这个问题的僵局.既然它适用于本地磁盘,代码的一般结构一定要好,对吧?有一些关于NFS挂载的共享和我的代码是不兼容的,但我不知道它可能是什么.
在处理长时间运行的Python守护程序时,是否必须实现特殊注意事项,这些守护程序将经常读取和写入安装在NFS上的文件共享?
如果有人想看到代码处理HTTP请求并将pickle对象写入磁盘的部分在github 这里.通过读取pickle对象,子线程用来定期清理磁盘中的东西的部分就在这里.
我有我的问题的答案,它与我在NFS共享上进行文件I/O的事实无关.事实证明,如果I/O超过NFS安装而不是本地磁盘,问题就会显得更快.
一条关键信息是代码通过SocketServer.ThreadingMixIn和HTTPServer类运行.
我的处理程序代码正在做一些接近以下的事情:
base_dir = getBaseDirFromConfigFile()
current_dir = os.getcwd()
temporary_dir = tempfile.mkdtemp(dir=base_dir)
chdir(temporary_dir)
doSomething()
chdir(current_dir)
cleanUp(temporary_dir)
Run Code Online (Sandbox Code Playgroud)
这就是流量,或多或少.
问题不在于I/O是在NFS上完成的.问题os.getcwd()是不是线程本地的,它是一个全局的过程.因此,当一个线程发出一个chdir()移动到它刚刚创建的临时空间时base_dir,下一个线程调用os.getcwd()将获得另一个线程,temporary_dir而不是启动HTTP服务器的静态基本目录.
解决方案是摆脱chdir()和getcwd()调用.启动并停留在一个目录中,并通过绝对路径访问其他所有内容.
NFS vs本地文件通过我循环播放.事实证明我的阻止:
chdir(temporary_dir)
doSomething()
chdir(current_dir)
cleanUp(temporary_dir)
Run Code Online (Sandbox Code Playgroud)
当文件系统是NFS而不是本地时,运行速度要慢得多.它使问题更快地发生,因为它增加了一个线程仍处于doSomething()运行状态而另一个线程运行current_dir = os.getcwd()代码块部分的机会.在本地磁盘上,线程在整个代码块中移动很快,很少像那样交叉.但是,给它足够的时间(大约一周),并在使用本地磁盘时出现问题.
这是Python中线程安全操作的一个重要教训!
| 归档时间: |
|
| 查看次数: |
2619 次 |
| 最近记录: |