Upgrade to Pro — share decks privately, control downloads, hide ads and more …

yapcasia2015

Sponsored · Your Podcast. Everywhere. Effortlessly. Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.

 yapcasia2015

我々はどのように冗長化を失敗したのか

Avatar for kenjiskywalker

kenjiskywalker

August 21, 2015
Tweet

More Decks by kenjiskywalker

Other Decks in Technology

Transcript

  1. 我々は   どのように   冗長化を失敗したのか YAPC::Asia  2015   2015/08/22  (Day

     2) kenjiskywalker Photos : https://www.flickr.com/photos/gsfc 1
  2. 話すこと 挑戦したこと   冗長化について   Redis  +  Redis  Sentinel  

    Consul   MySQL  +  mysqlfailover   consul-template   hostsの順番   クラウドという名の混乱   対応   冗長化の終わり、そして 3
  3. Kenji Naito a.k.a kenjiskywalker The world is not complete Photos

    : https://www.flickr.com/photos/gsfc YAPC::Asia 2014 2014/08/29 (day 1) 12
  4. ”冗長化(じょうちょうか)とは、    システムの一部に    何らかの障害が発生した場合に備えて、    障害発生後でも    システム全体の機能を維持し  

     続けられるように予備装置を    平常時からバックアップとして    配置し運用しておくこと。    冗長化によって得られる安全性は    冗長性と呼ばれる。” Wikipedia調べ 16
  5. 構成 Public Web Server A 02 Web Server A 01

    Web Sever B 02 Web Server B 01 26
  6. nginx + Redis(Slave) Application A 02 各ウェブサーバでは   nginxとRedis、  

    Web  Applicationが動いている nginx + Redis(Master) Application A 01 29
  7. 監視用のサーバを置いた場合   監視用のサーバも遷移させる? nginx + Redis Application A 01 Sentinel

    x1 nginx + Redis Application A 02 Sentinel x1 nginx + Redis Application A 03-01 Sentinel x1 nginx + Redis Application A 03-01 Sentinel x1 ? 35
  8. Master : Sentinel x1 Slave : Sentinel x2 Redis Master

    Sentinel x1 Redis Master Sentinel x2 38
  9. Masterが遷移した際に   Redis  Sentinelの数を   操作する(Master  x1/Slave  x2)に   する必要がある

    Redis (New) Slave Sentinel x1 ⇣ Sentinel x2 Redis (New) Master Sentinel x2 ⇣ Sentinel x1 39
  10. 44

  11. #!/usr/bin/env ruby redis_name = 'foo-redis' fqdn = 'service.dc1.consul' master_redis_name =

    "master.#{redis_name}.#{fqdn}" master_redis_hosts = `host -W 1 #{master_redis_name}| grep has`.split("\n") # マスターが複数台起動していたなら if master_redis_hosts.length > 1 exit 2 end redis_is_runnning = `netstat -l | grep -w 6379` # Redisが動いていなければfail if redis_is_runnning.nil? exit 2 end # Roleがmasterであればtrue my_redis_role = `/usr/local/bin/redis-cli info | grep role` my_redis_role.chomp! if "#{my_redis_role}" == "role:master" exit 0 else exit 2 end 47
  12. #!/usr/bin/env ruby redis_name = 'foo-redis' fqdn = 'service.dc1.consul' master_redis_name =

    "master.#{redis_name}.#{fqdn}" master_redis_hosts = `host -W 1 #{master_redis_name}| grep has`.split("\n") # マスターが複数台起動していたなら if master_redis_hosts.length > 1 exit 2 end redis_is_runnning = `netstat -l | grep -w 6379` # Redisが動いていなければfail if redis_is_runnning.nil? exit 2 end # Roleがmasterであればtrue my_redis_role = `/usr/local/bin/redis-cli info | grep role` my_redis_role.chomp! if "#{my_redis_role}" == "role:master" exit 0 else exit 2 end 1、RedisのMasterのDNSが     複数のIPアドレスを返していない   2、自分のサーバでRedisが動いている   3、その動いているRedisはMasterである 48
  13. #!/usr/bin/env ruby redis_name = 'foo-redis' fqdn = 'service.dc1.consul' master_redis_name =

    "master.#{redis_name}.#{fqdn}" master_redis_hosts = `host -W 1 #{master_redis_name}| grep has`.split("\n") # マスターが複数台起動していたなら if master_redis_hosts.length > 1 exit 2 end redis_is_runnning = `netstat -l | grep -w 6379` # Redisが動いていなければfail if redis_is_runnning.nil? exit 2 end # Roleがmasterであればtrue my_redis_role = `/usr/local/bin/redis-cli info | grep role` my_redis_role.chomp! if "#{my_redis_role}" == "role:master" exit 0 else exit 2 end この3つの条件を   満たした時のみ RedisのMasterのDNSレコードを   Consulで返すようにした 49
  14. { "service": { "id": "foo-redis master check in HOSTNAME", "tags":

    ["master"], "name": "foo-redis", "check": { "script": "/opt/consul/bin/redis-master-check.rb", "interval": "30s" } } } 50
  15. nothing Old Master fail Run Redis fail over nothing master.foo-redis.service.dc1.consul

    54 master.foo-redis.service.dc1.consul 54 192.0.2.11 check ok check ng failover nothing nothing
  16. #!/bin/bash curl -X PUT -d '{"Node":"foo-db-master"}' localhost:8500/v1/catalog/deregister curl -X DELETE

    http://localhost:8500/v1/kv/foo-db-master 遷移実行前(before_exec) deregister-master-db.sh 遷移前にMasterのDNSレコードを削除し   接続できないようにする 69
  17. #!/bin/bash curl -X PUT -d '{"Node":"foo-db-slave"}' localhost:8500/v1/catalog/deregister curl -X PUT

    -d '{"Node":"foo-db-master}", "Address":"192.0.2.110"}' \ localhost:8500/v1/catalog/register curl -X PUT -d '192.0.2.110' http://localhost:8500/v1/kv/foo-db-master 遷移実行後(after_exec) register-master-db.sh Masterの遷移が正常に完了した後   Masterのレコードを新MasterのIPアドレスで返す ※  kvは念のための設定 70
  18. 変化があった場合に   /etc/hostsを書き換えて   Dnsmasqを再起動させるようにした consul = "127.0.0.1:8500" template {

    source = "/etc/hosts.ctmpl" destination = "/etc/hosts" command = "service dnsmasq restart" } /etc/consul.d/consul-template.cfg 83
  19. # This file generated by consul-template 127.0.0.1 localhost localhost.localdomain localhost4

    localhost4.localdomain4 ::1 localhost localhost.localdomain localhost6 localhost6.localdomain6 # node{{ range nodes }} {{.Address}} {{.Node}} {{.Address}} {{.Node}}.node.dc1.consul{{end}} {{range services}} # service {{.Name}}{{range service .Name}} {{.Address}} {{.Name}}.service.dc1.consul{{end}}{{end}} /etc/hosts.ctmpl 84
  20. 作成されるhostsファイル # This file generated by consul-template 127.0.0.1 localhost localhost.localdomain

    localhost4 localhost4.localdomain4 ::1 localhost localhost.localdomain localhost6 localhost6.localdomain6 # node 192.0.2.111 foo-db-master 192.0.2.111 foo-db-master.node.dc1.consul 192.0.2.112 foo-db-slave 192.0.2.112 foo-db-slvave.node.dc1.consul ... # service bar-app 192.0.2.11 bar-app.service.dc1.consul 192.0.2.12 bar-app.service.dc1.consul 85
  21. # node 192.0.2.11 foo-app01 192.0.2.11 foo-app01.node.dc1.consul 192.0.2.12 foo-app02 192.0.2.12 foo-app02.node.dc1.consul

    192.0.2.13 foo-app03 192.0.2.13 foo-app03.node.dc1.consul # service foo-app 192.0.2.11 foo-app.service.dc1.consul 192.0.2.12 foo-app.service.dc1.consul 192.0.2.13 foo-app.service.dc1.consul 試しにfoo-app02を止めると 87
  22. こうなる。便利 こうなる # node 192.0.2.11 foo-app01 192.0.2.11 foo-app01.node.dc1.consul 192.0.2.13 foo-app03

    192.0.2.13 foo-app03.node.dc1.consul # service foo-app 192.0.2.11 foo-app.service.dc1.consul 192.0.2.13 foo-app.service.dc1.consul 88
  23. 今考えていることメモ Web  API側、ネイティブアプリ側   それぞれでデータストアに   アクセスできない時に   即エラーを返さず、  

    バッファリング機能を搭載し   エラーまでのタイムアウト時間を   伸ばすか?しかしその影響は   どの範囲まで許容できる? 92
  24. hostsに設定が書いてある場合   上から順に見ていき、   最初にヒットしたレコードを返す hosts --- # service foo-app

    192.0.2.11 foo-app.service.dc1.consul 192.0.2.12 foo-app.service.dc1.consul --- 101 request response
  25. def is_alive(self): """Determine if connection to server is still alive.

    Returns bool - True = alive, False = error or cannot connect. """ res = True try: if self.db_conn is None: res = False else: # ping and is_connected only work partially, try exec_query # to make sure connection is really alive retval = self.db_conn.is_connected() if retval: self.exec_query("SHOW DATABASES") else: res = False except: res = False return res Health  Check時に   MySQLに接続し   SHOW  DATABASESを実行 111
  26. def _reconnect_master(self, pingtime=3): """Tries to reconnect to the master This

    method tries to reconnect to the mast after 3 attemps, returns False. """ if self.master and self.master.is_alive(): return True is_connected = False i = 0 while i < 3: try: self.master.connect() is_connected = True break except: pass time.sleep(pingtime) i += 1 return is_connected 失敗した場合は   ping(pingtime)  x3  試す x3はハードコードされている 112
  27. 122

  28. 127

  29. 129

  30. 138

  31. 149

  32. Redis   http://redis.io/   Redis  Sentinel   http://redis.io/topics/sentinel   MySQL

      https://www-jp.mysql.com/   MySQL  Utilities   https://dev.mysql.com/downloads/utilities/   Consul  by  HashiCorp   https://www.consul.io/   consul-template   https://github.com/hashicorp/consul-template   Dnsmasq  -  network  services  for  small  networks.  -  Simon  Kelley   http://www.thekelleys.org.uk/dnsmasq/doc.html   Consulと自作OSSを活用した100台規模のWebサービス運用  by  FUJIWARA  Shunichiro   https://speakerdeck.com/fujiwara3/consultozi-zuo-osswohuo-yong-sita100tai-gui-mo- falsewebsabisuyun-yong 参考URL 155
  33. 参考URL 式年遷宮Infrastracture  /  さよならインターネット   http://blog.kenjiskywalker.org/blog/2013/08/11/shikinen-sengoo-infrastracture/   神宮式年遷宮  /  Wikipedia

      https://ja.wikipedia.org/wiki/%E7%A5%9E%E5%AE%AE%E5%BC%8F %E5%B9%B4%E9%81%B7%E5%AE%AE   冗長化  /  Wikipedia   https://ja.wikipedia.org/wiki/%E5%86%97%E9%95%B7%E5%8C%96   完成されたシステムなどない。完成された人間もいない。あるのは成長し続ける未完成 なシステムと、それを支える未完成な人間だけだ  /  YAPC::Asia  Tokyo  2014   http://yapcasia.org/2014/talk/show/4c7651e8-ed53-11e3-9faf-6ba36aeab6a4   156
  34. 「迷ったら健全な方」   Being  healthy  dev  and  ops  in  Cookpad  by

     Issei  Naruta  /  Speaker  Deck   https://speakerdeck.com/mirakui/being-healthy-dev-and-ops-in-cookpad   「仕事道具に対しても責任を持ちたい」   監視ツールの話  by  @kazeburo  /  slideshare   http://www.slideshare.net/kazeburo/ss-13361002 参考URL 157 ImmutableServer  /  Martin  Fowler   http://martinfowler.com/bliki/ImmutableServer.html   BlueGreenDeployment  /  Martin  Fowler   http://martinfowler.com/bliki/BlueGreenDeployment.html   Trash  Your  Servers  and  Burn  Your  Code:  Immutable  Infrastructure  and  Disposable  Components  /  Chad  Fowler http://chadfowler.com/blog/2013/06/23/immutable-deployments/   インフラ系技術の流れ  /  Gosuke  Miyashita   http://mizzy.org/blog/2013/10/29/1/   Rebuild.fm  25:  Immutable  Infrastructure  (Naoya  Ito,  Gosuke  Miyashita).   http://rebuild.fm/25/