blog.kotamiyake.me

為せば成る、為さねば成らぬ何事も

個人のRailsプロジェクトでDockerを使って環境構築をしていた際にハマったお話。

原因

  • Rackのバージョンが上がって、ホストとポートを分割する挙動が変わりアンダースコアのホストがマッチしなくなった

Rackの挙動の変更点は以下の通り。

対策

  • docker-composeのサービス名をハイフンで繋ぐよう修正する

経緯

元々以下のような構成でdocker-composeを使って環境を構築していました。

アプリ本体とwebpack-dev-serverを動かすアプリを分離する構成です。

services:
  app:
    <<: *app
    command: ["bundle", "exec", "rails", "s", "-p", "3000", "-b", "0.0.0.0"]
    environment:
      WEBPACKER_DEV_SERVER_HOST: webpack_dev_server
    ports:
      - 3000:3000
    depends_on:
      - db
  webpack_dev_server:
    <<: *app
    command: ["bin/webpack-dev-server"]
    environment:
      WEBPACKER_DEV_SERVER_HOST: 0.0.0.0
    ports:
      - 3035:3035

それから開発中にRackのバージョンをアップデートしたところ、以下のエラーが吐き出されてjsが参照できなくなりました。

#<SocketError: Failed to open TCP connection to webpack_dev_server:3035:80 (getaddrinfo: Name or service not known)>

今回は開発環境での出来事だったので特に問題はなかったのですが、みなさんもgemのアップデートの際にはくれぐれもご注意を…。

仕事でGIL(Global Interpreter Lock)についての話がでてきたので、改めてどういうものなのか整理してみました。

GILとは何なのか?

Wikipediaによると、

グローバルインタプリタロック(英: Global Interpreter Lock, GIL)とは、プログラミング言語のインタプリタのスレッドによって保持されるスレッドセーフでないコードを、他のスレッドと共有してしまうことを防ぐための排他 ロックである。

グローバルインタプリタロック – Wikipedia

スレッドによって保持されるスレッドセーフでないコードを、他のスレッドと共有してしまうこと」というのは一体どういうことなのでしょうか。

まずはスレッドについての理解を深める必要がありそうです。

計算機上で、複数の処理を同時に実行する(並行計算、マルチタスク)場合、処理を分割し、同時に実行する部分を指定する事が出来る、処理の分割の単位として、スレッドとプロセスがある。

スレッド (コンピュータ) – Wikipedia

またまたWikipediaからの引用になるのですが、複数の処理を並列で動かす場合には、処理分割の単位としてスレッドとプロセスがあります。

それぞれの違いやメリット・デメリットについては、参考記事を読んでいただきたいのですが、ここで重要なのは処理分割の単位としてスレッドを選んだ場合には、同一メモリ上で処理が実行されるため、複数のスレッドで同じデータが操作される可能性があるということです。

それが最初にWikipediaから引用した部分の「スレッドによって保持されるスレッドセーフでないコードを、他のスレッドと共有してしまうこと」に繋がります。

そしてその問題を防いでくれる機構がGILというわけです。

RubyにおけるGIL

Rubyのマルチスレッドで動くという触れ込みだが、実際にはGILの影響で完全にスレッド数に比例してパフォーマンスがあがるというわけではようです。

ただRubyのコードで処理時間を取られることは少なく、ほとんどがGILが解除されるI/O待ちに処理時間が取られるので、かなりのケースで並列処理が可能なようです。

まとめ

簡単な説明となりましたが、さらに詳しく理解したい方は参考記事を読んだり、そこに出てくるキーワードでさらに調査していただければと思います。

実際にRubyがどのように動いているかについて読んでいただいた方の理解が深まれば幸いです。

参考記事