Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

大江戸Ruby会議01 "mission critical"なシステムでも使えるThreadの作り方

5,560 views

Published on

2011/04/10 (日) @深川江戸資料館レクホール

  • ・識別子で思い出しましたが、Thread[;name]に’logger’とか’worker-1’とか固有名を入れて、Threadモニタでその名前を出すようにしたことがあります。似たようなのがあれば標準に提案しませんか。

    ・’aborting’で時間がかかることがあるんですね。。。やってみないとわからない情報なんでしょうねえ。ありがとうございます。

    ・ThreadとSocketの両資源が残っているときにThread#killで回収しようとすると、Socket資源がリークしたりするので、Thread#raiseなどで先にSocketを別の方法で回収、というのが「お行儀のよい」方法だと思います。でも、bindだと資源はリークしないかもだし、きれいごと言ってるだけかもしれません。次の機会があればbindに気をつけてみます。
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
  • nahiさん、コメントありがとうございます。

    ・th_infosは、サンプルコードではHashのkeyにカウンタ-を使っているのですが、
     複数プロセス × 複数スレッドの中で、固有の識別IDになる値をkeyにすることを想定しています。  →サンプルコードは分かりやすくするために、配列にした方がよかったですね。

    ・Thread#alive? だと、’aborting’ もtrueを返すので、異常なThreadを早く検知し、
     再起動するために、statusを使っています。
     statusの適切な更新が難しいというのは、知らなかったので、今後検討したいと思います…。

    ・Thread#kill については、Thread#alive? がfalse を返す場合ならよいのですが、
     Thread#alive?がtrue(または、status が’run’ ) を返して、
     Threadのループ内で更新させる情報(Slide内のThreadWatch#valid? )で
     異常と判断された場合には、Thread#killは必要だと思うのですが、いかがでしょうか?
     →各Thread で、socket をbind() しているような場合、
      Threadを停止(kill)してからでないと、bind()エラーが出ていた記憶があります。
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
  • ・th_infosがArrayでなくてHashなのはなぜなんでしたっけ。

    ・Thread#statusを’run’もしくは’sleep’で比較するのでなく、Thread#alive?を呼んでほしいです。JRubyのようなGILなし環境だと、statusを適切に更新するのが難しいので。。。

    ・今の構成だと、Thread#kill -> Thread#joinが絶対に刺さらないようにする必要があります。ensureでIO#closeとかやったり、ログ書き出し→その先のMutex取れず、などのパターンで刺さると、メインスレッドが止まるので。Thread#kill!だとリークする可能性もあるので、daemon系ではThread#kill系列は基本避けたほうがよいと思います。

    ・と、ここまで書いておいてなんですが、!th.alive?であれば、killとか意味ないかも?
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here

大江戸Ruby会議01 "mission critical"なシステムでも使えるThreadの作り方

  1. 1. 江森 真由美<br />“mission critical”なシステムでも使える Thread の作り方<br />
  2. 2. プロフィール<br />江森 真由美 (@emorima)<br />(株)ケーシーエスキャロット<br />       ユニットマネージャ<br />2004年からRubyを使用<br />
  3. 3. “mission critical”なシステムとは?<br />
  4. 4. “mission “critical”<br />24時間365日、止まらないことを要求される基幹業務、あるいは、そのような業務遂行のために使用されるコンピュータシステムのこと。(中略)<br />このような業務に使用されるシステムには、極めて高い信頼性や耐障害性、障害発生時に被害を最小に食い止める様々な機能、万全のサポート体制などが必要となる。<br />         (IT用語辞典 e-Wordsより)<br />
  5. 5. Threadを作る上でのポイント<br />メインスレッドでは、<br /> 起動したスレッドの状態を監視する。<br />起動したスレッドの状態が異常の場合、スレッドを再起動する。<br />
  6. 6. defself.thread_main(idx)<br />loop do<br />#スレッド処理<br />end<br />end<br />defself.main(argv)<br />th_infos = Hash.new<br />foriin0…100<br />th_infos[i] =Thread.new(i){|idx| thread_main(idx)}<br />end<br />check_threads(th_infos)<br />end<br />
  7. 7. defself.check_threads(th_infos)<br />loop do<br />th_infos.eachdo |i, th|<br />f_restart = false<br />caseth.status<br />when“run”, “sleep”<br />else<br />f_restart = true<br />end<br />iff_restart<br />th.kill<br />th.join<br />th_infos[i] = <br />Thread.new(i) {|idx| thread_main(idx)}<br />end<br />end<br />sleep1<br />end<br />end<br />
  8. 8. でも、これでは不十分<br />「万が一」<br />を<br />考える必要がある<br />
  9. 9. 「万が一」<br />Threadが<br />刺さっても<br />何とか<br />しないといけない<br />
  10. 10. どうするか?<br />少し状況を変えて<br />考えてみましょう<br />
  11. 11. 順調です<br />順調です<br />(嘘だけど)<br />Aさん<br />日報・週報<br />提出<br />Bさん<br />遅れて<br />ます<br />???<br />Dさん<br />Cさん<br />管理者<br />
  12. 12. Threadのループ内で<br />情報更新(報告)<br />その内容で判断する<br />
  13. 13. classThreadWatch<br />definitialize(timer)<br /> @update_time = nil<br />@alive_timer = timer<br />@mutex = Mutex.new<br />end<br />defupdate<br />@mutex.synchronizedo<br />@update_time = Time.now<br />end<br />end<br />def valid?<br />@mutex.synchronizedo<br />returnfalseif!@update_time.nil? &&<br /> (Time.now - @update_time) > @alive_timer)<br /> end<br />true<br />end<br />end<br />
  14. 14. defself.thread_main(idx, watch)<br />loop do<br />watch.update<br />#スレッド処理<br />end<br />end<br />defself.main(argv)<br />th_infos = Hash.new<br />foriin0…100<br />w = ThreadWatch.new(600)<br />th = Thread.new(i, w) do |idx, watch|<br />thread_main(idx, watch)<br />end<br />th_infos[i] =[th, w]<br /> end<br />check_threads(th_infos)<br />end<br />
  15. 15. defself.check_threads(th_infos)<br />loop do<br />th_infos.eachdo |i, info|<br />th, w = info<br />f_restart = false<br />caseth.status<br />when“run”, “sleep”<br />f_restart = true unless w.valid?<br />else<br />f_restart = true<br />end<br />iff_restart<br />th.kill<br />th.join<br />th = Thread.new(i, w) do |idx, watch|<br />thread_main(idx, watch)<br />end<br />th_infos[i] = [th, w]<br /> end<br />end<br />end<br />end<br />
  16. 16. テスト<br />テストの話も<br />しないと…<br />Rubyだし。<br />
  17. 17. テスト<br />無限ループの<br />テストって<br />どうすれば???<br />
  18. 18. 無限ループのテスト<br />loop do がある限り、処理が返ってこないため、テスト確認ができない。<br /><ul><li>ループ処理は、変数やメソッドでループの実行判定をするようにする。</li></li></ul><li>defself.thread_main(idx, watch)<br />while run?<br />watch.update<br />#スレッド処理<br />end<br />end<br />defself.run?<br />true<br />end<br />
  19. 19. describe OedoThread, “thread_main”do<br />class OedoThread<br /> @@counter = 0<br />def self.run?<br /> @@counter += 1<br />return false if @@counter > 3<br />true<br />end<br />end<br /> it “call 3 times” do<br />m_watch = mock(“thread watch”)<br />m_watch.should_receive(:update).exactly(3)<br />OedoThread.thread_main(1, m_watch)<br /> end<br />end<br />
  20. 20. まとめ<br />“mission critical”なシステムでThreadを使う場合<br />Threadのチェックは、Thread.statusの状態チェックだけではなく、Thread側での更新チェックも実装する。<br />チェック結果が異常な場合には、Threadは再起動する。<br />loop do を使うとテストが書けないため、ループを実行するかどうかを判定するメソッド(または変数)を作成する。<br />
  21. 21. ご静聴<br />ありがとう<br />ございました<br />

×