DeNAにおけるOpenStack Upgrade

はじめに

こんにちは。IT基盤部でOpenStackの運用をしています酒井です。
弊社では先日社内のOpenStackのアップグレードを行いました。今回は弊社で実施したアップグレード手順についてできるだけ詳しく紹介させていただきます。

なぜアップグレードするのか

OpenStackのリリースサイクルはこちらにあるように約半年ごとに新しいバージョンがリリースされ新機能が追加されます。弊社ではkiloとlibetyを利用していましたが、mitakaで導入された新しい機能を使いたいため、ひとまず両環境をmitakaにアップグレードすることをターゲットとしました。また、弊社ではSDNとしてBig Cloud Fabric(以下BCF)を使用していますが、BCFのサポートするOpenStackバージョンが決まっているため、OpenStackをアップグレードしないとBCFをアップグレードできない、という事情もありました。

OpenStackの構成

弊社のOpenStackの構成としては以下の通りです。

OSUbuntu 14.04
OpenStack Versionkilo/liberty
OpenStack ComponentKeystone, Glance, Nova, Neutron, Cinder, Ironic
HypervisorKVM
Cinder BackendCeph
Neutron mechanism_driversopenvswitch, bsn_ml2, networking_bigswitch_l3_pe
(l3-agentは無し)

OpenStack環境が2環境あり、それぞれkiloとlibertyを利用していました。kiloからmitakaへのアップグレードは一度には行わず、kiloからliberty、libertyからmitakaと2回に分けてアップグレードしました。これは当時使っていたBCFのバージョンではkiloとlibertyのみをサポートしており、mitakaをサポートしているバージョンのBCFではkiloをサポートしていなかったため、このような段階的なアップグレードをする必要があったためです。

アップグレード手順

基本的な手順としては以下のようになります。

  1. 事前準備
    1. 新バージョンのController Nodeを新規で構築する。(DB, rabbitmqはController Node上で動作する構成)
  2. メンテナンス期間: 各コンポーネント毎に以下の作業を行う
    1. 旧バージョンのController Nodeのサービス停止
    2. DBを新バージョンに対応させるためマイグレーション
    3. 新バージョンのController Nodeのサービス起動
    4. 動作確認
    5. DNS更新してエンドポイント切り替え
    6. Compute Node上で動作するサービスがあれば(弊社のケースではNovaとNeutron)新バージョンにアップグレード

各コンポーネントのAPIの停止を伴うため、社内の関係者と調整しメンテナンス期間を設けてアップグレード作業を行いました。コンポーネントのアップグレードはKeystone, Glance, Nova, Neutron, Cinder, Ironicの順に行いました。各コンポーネントごとの詳細な手順を以下に説明します。なお、kiloからlibertyへのアップグレードとlibertyからmitakaへのアップグレードでは手順はほぼ同様でしたが、一部異なる箇所がありましたのでそこは個別に説明します。

Keystone

旧バージョンのController Nodeのkeystoneを停止します。

service apache2 stop

次にkeystone DBを新バージョンに対応させるためスキーマのマイグレーションします。

mysqldump -uroot -h$OLD_DB_SERVER -p --opt --add-drop-database --single-transaction --master-data=2 keystone > keystone-db-backup.sql
mysql -uroot -h$NEW_DB_SERVER -p -f keystone < keystone-db-backup.sql
sudo su -s /bin/sh -c "keystone-manage db_sync" keystone

新バージョンのController Nodeでサービス再開します

service apache2 start

以下のような動作確認をします。

# 35357ポートの確認
TOKEN=$(openstack --os-url http://$MY_IP:35357/v2.0 token issue -f json | jq -r .id)
openstack --os-url http://$MY_IP:35357/v2.0 --os-token $TOKEN user list
# 5000ポートの確認
openstack --os-url http://$MY_IP:5000/v2.0 token issue

問題なければDNSを更新してendpointを新バージョンに切り替えます。

Glance

旧バージョンのController Nodeのglanceを停止します。

stop glance-registry
stop glance-api

次にglance DBを新バージョンに対応させるためスキーマのマイグレーションします。

mysqldump -uroot -h$OLD_DB_SERVER -p --opt --add-drop-database --single-transaction --master-data=2 glance > glance-db-backup.sql
mysql -uroot -h$NEW_DB_SERVER -p -f glance < glance-db-backup.sql
sudo su -s /bin/sh -c "glance-manage db_sync" glance

旧バージョンのController Node上に保存されているimageファイルを新バージョンのController Nodeにコピーします。

rsync -av $OLD_CONTROLLER_NODE:/var/lib/glance/images/
/var/lib/glance/images/

新バージョンのController Nodeでサービス再開します

start glance-api
start glance-registry

以下のような動作確認をします。

MY_IP=`hostname -i`
# glance image-listの確認
glance --os-image-url http://$MY_IP:9292/ image-list
# glance image-createの確認
echo dummy | glance --os-image-url http://$MY_IP:9292/ image-create --disk-format raw --container-format bare --name dummy_image
# glance image-downloadの確認
glance --os-image-url http://$MY_IP:9292/ image-download <新規イメージのID> > dummy_image
cat dummy_image # dummyと表示されればOK
# glance image-deleteの確認
glance --os-image-url http://$MY_IP:9292/ image-delete <新規イメージのID>

問題なければDNSを更新してendpointを新バージョンに切り替えます。

Nova(Controller Node)

旧バージョンのController Nodeのnovaを停止します。

stop nova-cert
stop nova-consoleauth
stop nova-novncproxy
stop nova-conductor
stop nova-scheduler
stop nova-compute
stop nova-api

nova DBを新バージョンに対応させるためスキーマのマイグレーションします。

mysqldump -uroot -h$OLD_DB_SERVER -p --opt --add-drop-database --single-transaction --master-data=2 nova > nova-db-backup.sql
mysql -uroot -h$NEW_DB_SERVER -p -f nova < nova-db-backup.sql
sudo su -s /bin/sh -c "nova-manage db sync" nova
# mitakaへのアップグレードの場合は nova-api DBのマイグレーションも必要です。
sudo su -s /bin/sh -c "nova-manage api_db sync" nova

新バージョンのController Nodeでサービス再開します

start nova-api
start nova-compute
start nova-scheduler
start nova-conductor
start nova-novncproxy
start nova-consoleauth
start nova-cert

以下のような動作確認をします。

MY_IP=`hostname -i`
PROJECT_ID=$(openstack project show $OS_PROJECT_NAME -f json | jq -r .id)
TOKEN=$(openstack token issue -f json | jq -r .id)
curl -i http://$MY_IP:8774/v2/$PROJECT_ID/servers/detail  -H "Accept: application/json" -H "X-Auth-Token: $TOKEN"
curl -i http://$MY_IP:8774/v2/$PROJECT_ID/images/detail  -H "Accept: application/json" -H "X-Auth-Token: $TOKEN"

問題なければDNSを更新してendpointを新バージョンに切り替えます。

Nova(Compute Node)

最初にneutron-ovs-cleanupが起動していることを確認します。neutron-ovs-cleanupが停止しているとnova-compute再起動時にneutron-ovs-cleanupが実行され、インスタンスの通信が途切れてしまうためです。

status neutron-ovs-cleanup

新バージョンのaptリポジトリを追加します。kiloからlibertyへのアップグレードの場合は以下のようになります。

OLD_OS_VERSION=kilo
NEW_OS_VERSION=liberty
echo "deb http://ubuntu-cloud.archive.canonical.com/ubuntu trusty-updates/$NEW_OS_VERSION main" > /etc/apt/sources.list.d/cloudarchive-$NEW_OS_VERSION.list
mv /etc/apt/sources.list.d/cloudarchive-$OLD_OS_VERSION.list /tmp
apt-get update

まずnova, neutron, openvswitch以外のパッケージをアップグレードします。

apt-mark hold nova-compute
apt-mark hold openvswitch-common openvswitch-switch
apt-mark hold neutron-plugin-openvswitch-agent neutron-plugin-ml2
apt-get dist-upgrade

nova.confを必要に応じて修正した後、novaをアップグレードします。

apt-mark unhold nova-compute
apt-get dist-upgrade

当該Compute Nodeのnova-computeがupしていることを確認します。

nova service-list

Neutron(Controller Node)

旧バージョンのController NodeのNeutronを停止します。neutron-dhcp-agentを止める前にstate downにすることによりdnsmasqプロセスを終了させることができます。またその後state upにすることにより、新バージョンのneutron-dhcp-agentが各ネットワークに自動的にbindされるようになります。

neutron agent-update --admin-state-down $DHCP_AGENT_ID
# dnsmasqプロセスがいないことを確認した後neutron-dhcp-agentを停止する
stop neutron-dhcp-agent
neutron agent-update --admin-state-up $DHCP_AGENT_ID
stop neutron-metadata-agent
stop neutron-plugin-openvswitch-agent
stop neutron-server

Neutron DBを新バージョンに対応させるためスキーマのマイグレーションします。

mysqldump -uroot -h$OLD_DB_SERVER -p --opt --add-drop-database --single-transaction --master-data=2 neutron > neutron-db-backup.sql
mysql -uroot -h$OLD_DB_SERVER -p -f neutron < neutron-db-backup.sql
sudo su -s /bin/sh -c "neutron-db-manage --config-file /etc/neutron/neutron.conf --config-file /etc/neutron/plugins/ml2/ml2_conf.ini upgrade head" neutron

新バージョンのController Nodeでサービス再開します

start neutron-server
start neutron-plugin-openvswitch-agent
start neutron-metadata-agent
start neutron-dhcp-agent

以下のような動作確認をします。

TOKEN=$(openstack token issue -f json | jq -r .id)
curl -i http://$MY_IP:9696/v2.0/networks.json -H "Accept: application/json" -H "X-Auth-Token: $TOKEN"

問題なければDNSを更新してendpointを新バージョンに切り替えます。

Neutron(Compute Node)

openvswitch、Neutronの順にアップグレードを行います。 まずopenvswitchのアップグレードについてですが、kiloからlibertyへのアップグレードの場合、qvo Portのother_configに設定を追加する必要があります。以下のようにkiloではother_configが空になっているため、libertyへアップグレード後neutron-openvswitch-agentを再起動するとtagの情報が失われtagの再割り当てが行われます。その結果インスタンスの通信が数秒程度途絶えることになります。

# kiloではother_configは空になっている
ovs-vsctl --columns=name,other_config list Port qvoe97fb5a8-67
name                : "qvoe97fb5a8-67"
other_config        : {}
# libertyでは各種コンフィグが保存されている
ovs-vsctl --columns=name,other_config list Port qvoe97fb5a8-67
name                : "qvoe97fb5a8-67"
other_config        : {net_uuid="83b7bfb1-0b2f-406a-8725-fdaa7daf563f", network_type=vlan, physical_network="physnet1", segmentation_id="113", tag="5"}

これを避けるため、アップグレード前に全Portに対し以下のようなコマンドを実行し手動でother_configを設定しました。

ovs-vsctl set Port qvoe97fb5a8-67 other_config='{net_uuid="83b7bfb1-0b2f-406a-8725-fdaa7daf563f", network_type=vlan, physical_network="physnet1", segmentation_id="113", tag="5"}'

またkiloからlibertyの場合、conntrack zoneの対応もする必要があります。libertyではportごとに個別のconntrack zoneを使ってコネクションを管理するようになりました。kiloではconntrack zoneの指定はされておらず全てのportがデフォルトのzone 0で管理されていました。そのままlibertyにアップグレードするとzoneが新規に割り当てられてしまい(ソースコードはこちら)、割り当てられたzoneにはコネクションがないためそのコネクションのパケットがドロップしてしまうということがわかりました。これを回避するため、neutron-openvswitch-agentがzone 0を使い続けるよう、まず以下のようなルールを追加設定しました。

iptables -t raw -A neutron-openvswi-PREROUTING -m physdev --physdev-in $dev -j CT --zone 0

また、既存のiptables-saveコマンドのwrapperを以下のように作成しました。

cat <<EOF | sudo tee /usr/local/sbin/iptables-save
#!/bin/sh
/sbin/iptables-save "\$@" | sed 's/ -j CT$/ -j CT --zone 0/'
EOF
chmod +x /usr/local/sbin/iptables-save

vi /etc/neutron/rootwrap.conf
# /usr/local/sbin/を優先するよう以下のように修正
exec_dirs=/usr/local/sbin,/sbin,/usr/sbin,/bin,/usr/bin,/usr/local/bin

この二つの対応により各portがzone 0を使い続けるようになります。

以上で準備ができましたのでopenvswitchのアップグレードを行います。openvswitch-switchパッケージインストール時にopenvswitch-switchサービスが再起動されるのですが、そのタイミングでネットワークが不通になることがありました。それを避けるためにここではopenvswitch-switchサービスを再起動しないようにしています。

# ダミーの何もしないinvoke-rc.dで本物のinvoke-rc.dを隠すことでopenvswitch-switchを再起動しないようにする
ln -s `which true` /usr/local/sbin/invoke-rc.d
apt-mark unhold openvswitch-common openvswitch-switch
apt-get dist-upgrade -s
apt-get dist-upgrade
# invole-rc.dを元に戻す
rm /usr/local/sbin/invoke-rc.d

パッケージのアップグレードが終わった後で手動でモジュール再読込を実施します。弊社の環境ではこのタイミングでインスタンスの通信が0.5秒程度途切れました。

/usr/share/openvswitch/scripts/ovs-ctl force-reload-kmod

次にNeutronのアップグレードです。まずアップグレードの前にneutron-openvswitch-agentを停止します。

stop neutron-plugin-openvswitch-agent

kiloからlibertyへのアップグレード時にはNeutronのアップグレードの前にOVSブリッジにfail_mode: secureを設定する必要があります。Neutronのバージョン7.2.0からOVSブリッジにfail_mode: secureが設定されるようになりました。fail_mode: secureでない状態でneutron-openvswitch-agentを起動するとneutron-openvswitch-agentによりOVSブリッジにfail_mode: secureが設定されるのですが、この処理にはフロー情報のクリアが伴いインスタンスのネットワーク断が発生してしまいます。 これを避けるため、事前にfail_mode: secureの設定、フロー情報のリストアを行います。

ovs-ofctl dump-flows br-ex | grep -v NXST_FLOW > br-ex.flow; ovs-vsctl set-fail-mode br-ex secure; ovs-ofctl add-flows br-ex - < br-ex.flow

Neutronのコンフィグを必要に応じて修正した後、neutronをアップグレードします。

apt-mark unhold neutron-plugin-openvswitch-agent neutron-plugin-ml2
apt-get dist-upgrade

当該Compute Nodeのneutron-plugin-openvswitch-agentがupしていることを確認します。

neutron agent-list

Cinder

旧バージョンのController Nodeのcinderを停止します。

stop cinder-volume
stop cinder-scheduler
stop cinder-api

次にcinder DBを新バージョンに対応させるためスキーマのマイグレーションします。

mysqldump -uroot -h$OLD_DB_SERVER -p --opt --add-drop-database --single-transaction --master-data=2 cinder > cinder-db-backup.sql
mysql -uroot -h$NEW_DB_SERVER -p -f cinder < cinder-db-backup.sql
sudo su -s /bin/sh -c "cinder-manage db sync" cinder

弊社の場合cinder DBのvolumesテーブルのhostカラムを更新する必要がありました。このカラムには以下のようにcinder-volumeを動かしていた旧Controller Nodeのホスト名が含まれていました。Controller Nodeのホスト名が変わる度にこのカラムを更新するのは手間なので、弊社ではcinder.confにhostパラメタとして別名を定義し、その値をこのカラムに使用するようDBを更新しました。

mysql> select distinct(host) from volumes;
+-------------------------------+
| host                          |
+-------------------------------+
| CONTROLLER_HOSTNAME@ceph#CEPH |
+-------------------------------+

新バージョンのController Nodeでサービス再開します

start cinder-api
start cinder-scheduler
start cinder-volume

以下のような動作確認をします。

MY_IP=`hostname -i`
PROJECT_ID=$(openstack project show $OS_PROJECT_NAME -f json | jq -r .id)
TOKEN=$(openstack token issue -f json | jq -r .id)
curl -i http://$MY_IP:8776/v2/$PROJECT_ID/volumes/detail?all_tenants=1 -H "Accept: application/json" -H "X-Auth-Token: $TOKEN"

問題なければDNSを更新してendpointを新バージョンに切り替えます。

Ironic

旧バージョンのController Nodeのironicを停止します。

stop ironic-conductor
stop ironic-api

次にironic DBを新バージョンに対応させるためスキーマのマイグレーションします。

mysqldump -uroot -h$OLD_DB_SERVER -p --opt --add-drop-database --single-transaction --master-data=2 ironic > ironic-db-backup.sql
mysql -uroot -h$NEW_DB_SERVER -p -f ironic < ironic-db-backup.sql
sudo su -s /bin/sh -c "ironic-dbsync --config-file /etc/ironic/ironic.conf upgrade" ironic

弊社の場合nova DBのinstancesテーブルのhost/launched_onカラムを更新する必要がありました。これらには旧バージョンのController Nodeのホスト名が保存されていたのですが、以下のようにこれらの値を新バージョンのController Nodeのホスト名に更新しました。なお、cinder DBの場合と同様に別名を使うということも検討したのですが、BCF環境ではホスト名を使ったほうが安全にアップグレードが行えるということがわかり(詳細は割愛しますが)、ホスト名を使い続けることとしました。

mysql> update instances set host = '$NEW_CONTROLLER_NODE' where host = '$OLD_CONTROLLER_NODE';
mysql> update instances set launched_on = '$NEW_CONTROLLER_NODE' where launched_on = '$OLD_CONTROLLER_NODE';

旧バージョンのController Node上に保存されているtftp関連のファイルやimageファイルを新バージョンのController Nodeにコピーします。

mkdir /tftpboot
chown ironic.ironic /tftpboot
rsync -av $OLD_CONTROLLER_NODE:/tftpboot/ /tftpboot/
rsync -av $OLD_CONTROLLER_NODE:/var/lib/ironic/images/ /var/lib/ironic/images/
rsync -av $OLD_CONTROLLER_NODE:/var/lib/ironic/master_images/ /var/lib/ironic/master_images/

新バージョンのController Nodeでサービス再開します

start ironic-api
start ironic-conductor

以下のような動作確認をします。

MY_IP=`hostname -i`
TOKEN=$(openstack token issue -f json | jq -r .id)
curl -g -i -X GET http://$MY_IP:6385/v1/nodes -H "X-OpenStack-Ironic-API-Version: 1.9" -H "User-Agent: python-ironicclient" -H "Content-Type: application/json" -H "Accept: application/json" -H "X-Auth-Token: $TOKEN"

問題なければDNSを更新してendpointを新バージョンに切り替えます。 最後にaggregateに新しいController Nodeを追加、古いController Nodeを削除して終了です。

nova aggregate-add-host $AGGREGATE_ID $NEW_CONTROLLER_NODE
nova aggregate-remove-host $AGGREGATE_ID $OLD_CONTROLLER_NODE

その他

インタフェース構成の改善

一連のアップグレード作業を通じて、いくつか改善したいことが見つかりました。一つはCompute Nodeのインタフェース構成です。現状は以下の図の「現状の構成」のようにbr-exにIPアドレスを割り当てています。この構成だとopenvswitchのアップグレードに何らかの理由で失敗しbr-exがdownしたままになるとCompute Node自体が通信できなくなります。弊社ではCompute NodeはCephのStorage Nodeを兼ねているため、インスタンスのI/Oが詰まってしまうことになります。

これを以下の図の「改善案」のようにbr0というlinux bridgeを追加しそこにbr-exを接続しIPアドレスはbr0に割り当てる構成にすることを検討しています。これにより、openvswitchのアップグレードを仮に失敗したとしてもCompute Node自体はbr0のIPアドレスを使って通信できCephには影響を与えなくすることができます。linux bridgeが一つ増えることで性能面では不利になると思われますが、その辺りを検証した後に本番環境に適用していきたいと考えています。 interfaces.png

まとめ

弊社で行ったOpenStackアップグレードの手順について紹介させていただきました。弊社では6月、7月にkiloからlibertyへのアップグレードを1回、libertyからmitakaを2回行ったのですが、アップグレード作業中もその後も障害は発生していません。newton以降へのアップグレードは今のところ未定ですが、アップグレードを行った際にはまたその手順を公開したいと考えています。

続きを読む
ツイート
シェア
あとで読む
ブックマーク
送る
メールで送る

DeNAにおけるOpenStack運用#3

DeNAのOpenStackインフラ運用を担当している窪田です。 最後にご紹介するのはSDS Cephについてです。採用の背景と、これまで運用していく中で直面したパフォーマンスの問題、それをどのようにシューティングしたのかについてご紹介します。

採用の背景

第一回の小野の記事で、Ceph導入によって実現されたこととして、OpenStackとの連携、ストレージプールの外部化、ライブマイグレーションを取り上げました。実のところこれらのことはCephでなくても近年リリースされている商用ストレージやSDSをうたうプロダクトであれば大抵できることで、これらの実現の他にも重要視していることがありました。 決め手となったのはOSSプロダクトであることです。OSSだとなぜいいのかというと、ソースコードが公開されていることによって、やろうと思えばソフトウェアの振る舞いを詳細に把握することが可能ですし、そうすることでパフォーマンス上のトラブルが起きたときに自力で何がボトルネックとなっているのかを見極め、問題をうやむやにせず納得のいく対応策を練ることができる場合があるからです。これまでDeNAのインフラを運用してきた経験からその重要性を無視できず、中身がブラックボックスなものはできれば避けたいという思いがありました。

構成

本題に入る前に弊社環境の構成について触れておきます。弊社インフラの全てがこの構成で運用しているわけでなく、まだ社内の開発者用のインフラに限定しています。 Cephはブロックストレージ、オブジェクトストレージ、ファイルシステムの三用途に使えますが、弊社ではKVM仮想マシンのストレージとして使うのが目的なのでブロックストレージ機能のみ使っています。 Cephのバージョンは0.94.6のHammerリリースを使っています。最新版ではないのでこれから述べることは最新版では当てはまらない情報も含まれていますがそこはご容赦ください。

個々のサーバのハードウェアとソフトウェアの構成は下図のようになっています。

ceph-blog-node.png

ALL HDDです。ネットワークは物理的に一つのLANに全Ceph nodeがつながっています。 Cephのパフォーマンスをより引き出すには、Ceph nodeのクラスタにそれ専用のサーバを設け、Cephクラスタ内の通信は専用のネットワークを敷く(Cluster Network)など考えられますが、 まずは今あるハードウェア資産を活かして最小限のハードウェアコストで構成し、ボトルネックを見極め、どうしてもハードウェアリソースの増強が必要な場合は追加投資、あるいはCephの導入を見送る選択肢も残しつつ進めていくことにしました。 結果、後述するチューニングを経てこの物理構成を崩さず今に至っています。ですが問題がないわけではありません。ネットワークでいえば輻輳しやすい問題があります。

今はコストを抑えたハードウェア構成を組んでいますが、これで十分と考えているわけでなく、物理的なI/Oの性能が不足しているならSSDを導入することや、後述のfsync/fdatasyncの性能問題のようなCephならではの欠点を補えるようなストレージを導入してマルチバックエンドストレージ構成にするなども視野に入れて検討しています。

ネットワークの輻輳

各Ceph nodeで稼働しているOSDが相互にTCPセッションをはってメッシュ状に通信している上に、Ceph nodeはCompute nodeも兼ねているので、OSDはCephクライアントとなるNova instanceともTCPセッションをはっています。なので各node間の同時通信が発生しやすく、バーストトラフィックによるパケットの廃棄(パケロス)が起きやすい構成です。 パケロスを抑える効果的な手段は、大きなフレームバッファを搭載しているネットワークスイッチを導入する、CephのPublic NetworkとCluster Networkを物理的に分ける、など考えられますが、既存資産を限りなく使い切りたいので、発想を変えてパケロスを抑えるのを諦め、BigSwitchとLinuxのQoS機能を組み合わせ、Nova instanceのトラフィックを優先してユーザ影響を軽減するような仕組みにできないかを検証しています。

パフォーマンスチューニング

上図のようなハードウェア構成でぜひやるべきことが2つあります。

  • ジャーナルとデータ領域を一つの物理ディスクに共存させない
  • tcmallocのキャッシュサイズを拡張する

Cephは一つのOSDに対して二度の書き込みを行います。一度目がジャーナル領域、二度目がデータ領域です。ジャーナルに書き込まれた時点でOSDはクライアントに書き込み完了のレスポンスを返すことができるので、ジャーナルにSSDのような高速なハードウェアを使う方が良いという話を聞きますが、弊社ではSSDは使わず、4つのHDDを下図のように構成しています。

ceph-blog-disk.png

Linuxルートファイルシステムが保存されているディスクは冗長化のためHW RAIDでミラーリング(RAID1)し、同ディスクに全OSDのジャーナルをファイルとして置いた構成です。 ディスクの数にもよりますが、一つのディスクにジャーナルとデータ領域を共存させるよりも、ジャーナルはデータ領域とは物理的に別のディスクを使ったほうがI/Oスループットが向上します。ジャーナルへのI/Oはシーケンシャルwriteなので、ランダムI/O中心のデータ領域と比べてディスクへの負荷が低く、高いIOPSが出やすいです。

ご参考までに、ディスクの負荷がどの程度改善するのかを、データ領域側ディスクのiostatの%utilをグラフ化したもので比較すると、下のように50%前後で推移していたのが15%前後まで下がりました。

ジャーナルと共存した場合 ceph-blog-before.png

ジャーナルと共存しない場合 ceph-blog-after.png

あとこの構成にする上で設定しておくべきこととしてあるのが、ジャーナル側ディスクのLinux I/OスケジューラをDeadlineスケジューラにすることです。その他のI/Oスケジューラだと複数のOSDからくるシーケンシャルwriteを効率良くさばけず、パフォーマンスを維持できないのでDeadlineスケジューラは必須です。

tcmallocのキャッシュサイズを拡張するチューニングについてはCephコミュニティなどからも報告があり、詳細はそちらに譲ります。 tcmallocのキャッシュサイズ拡張は、あらゆるワークロードでパフォーマンスが向上するわけではなさそうですが、弊社環境では劇的な効果がありました。 弊社では前述したように28 Ceph node、56 OSDで約1,500のNova instance(KVM仮想マシン)がCeph上で常時稼働していますが、 Nova instanceが増えるにつれて1 OSDあたりがさばくメッセージ量が増え、tcmallocのキャッシュメモリの獲得、解放にかかるCPU処理が重くなり、 クライアントのI/Oリクエストが数秒から数十秒以上待たされる現象が頻発していたのですが、このチューニングによって秒単位の遅延がほとんど発生しなくなりました。 Cephクライアントを増やしていくとパフォーマンスが劣化するような現象にあたった場合は試してみるとよいでしょう。

ログ分析

パフォーマンスボトルネックの解析で実際に役立ったログの分析方法を一つご紹介します。 CephはI/Oのパフォーマンスが何らかの要因で劣化すると、クライアントからのI/Oリクエストの遅延間隔をログに記録します。slow requestと書かれたログです。弊社では遅延の要因を判断する上でslow requestをよくみています。slow requestのログの末尾にはOSDの何の処理に時間がかかっているのかがマーキングされており、チューニングの判断材料にしています。下記のようなログが書き出されます。

  • "currently no flag points reached"
  • "currently started"
  • "currently waiting for rw locks"
  • "currently waiting for subops from "
  • "currently commit_sent"

この中でも"currently commit_sent"はあまり深刻に受け止める必要のないログです。このログはジャーナルにwrite済みのデータをデータ領域にwriteするのが遅れていることを示しており、言い換えればジャーナルにデータが何秒滞留しているかを示しています。クライアントへのレスポンスが遅延しているわけではなく、ジャーナルのサイズに余裕がある場合はこのログが断片的に出ても問題ないとみなしており、弊社ではほぼ無視しています。

その他のログは重要です。ここでは"currently waiting for subops from "だけ取り上げてみましょう。 OSDのwrite処理はまずPrimary OSDがクライアントからwriteのメッセージを受けてSecondary OSDとTertiary OSDにwriteメッセージを投げます(レプリケーション数3で運用しています)が、投げたメッセージに対してSecondaryかTertiaryのどちらかのレスポンスが遅れるとこのログが出ます。ログのfromの後ろにSecondaryとTertiaryのIDが入るのでどのSecondaryまたはTertiaryかは特定できます。なのでこのログが出たときはログを出しているPrimaryに遅延の原因があるわけでなく、そのOSDとレプリケーションを組んでいるSecondaryかTertiaryのどちらかに原因があるはずです。

他にもslow requestのログに含まれる情報で役に立つものとしてRBD imageのIDがあります。RBD imageはCinder volumeでもあるので、どのCinder volumeのI/Oが遅延しているのかを特定できます。

fsync問題

前述のチューニングである程度パフォーマンスは改善するのですが、それでもなお課題として残っているのがfsync/fdatasyncシステムコールを多用するwrite処理が苦手なことです。そのようなアプリケーションで例をいえばMySQLのトランザクションのコミット処理が当てはまります。 なぜ苦手なのかというと、Cephは複数のI/Oを同時並行処理するようなワークロードが得意ですが、fsyncのようなデータ同期を挟まれてしまうと後続のwriteが待たされてしまいます。図にするとこのようなイメージです。

ceph-blog-write.png

Cephのようにネットワークまたぎで同期レプリケーションまでやるストレージだと、サーバローカルのストレージへのI/Oで完結する場合に比べてどうしてもレイテンシが長くなり、fsyncによるレスポンス待ちの影響が際立ちます。

弊社ではこの問題の根本解決は現状無理だと判断し、クライアントのローカルファイルシステム(ext4やxfs)のバリアオプションを無効にすることでfsyncによるパフォーマンスの劣化を抑えています。バリアオプションを無効化すればfsyncによるデータ同期を回避でき、同時並行writeを維持しやすく、writeレスポンス待ちの影響を軽減できます。ただしバリアオプションの無効化には副作用があり、リスクを許容できるかを検討した上で使う必要があるのでご注意ください。弊社では前述したように社内の開発者向け環境で、最悪、データが一部欠損するようなことがあっても大きな問題にはならないようなものなどに限定して使っています。

まとめ

Cephのパフォーマンスチューニングにフォーカスしてこれまで取り組んできたことをいくつかご紹介しました。冒頭でCephの良さの一つにソースコードが公開されていることをあげましたが、ここでご紹介したパフォーマンス問題の解析でもそれが大いに役立ってくれました。まだまだCephの運用経験が浅く、わかってないことも多いのですが、今後も経験を積むことで理解がどこまでも深まっていくと思います。この記事でCephを使ってみたくなった方が少しでも増えればと思っています。

最後に

DeNAのOpenStackインフラについて三回にわたってご紹介しましたがいかがでしたでしょうか。 宣伝ですが、2017年2月10日(金) に DeNA TechCon 2017 が開催されます。OpenStackに関するセクションも予定しており、ブログでご紹介しきれなかった内容もお話できればと思っているのでぜひご参加ください。

続きを読む
ツイート
シェア
あとで読む
ブックマーク
送る
メールで送る

DeNAにおけるOpenStack運用#2

こんにちは。IT基盤部でOpenStackの運用をしています酒井です。
私からは弊社OpenStack環境で使用しているSDNについてご紹介したいと思います。前回の記事で紹介しましたように、弊社ではBigSwitch Networks社のBig Cloud Fabric(以下BCF)を使用しています。本エントリーでは弊社がどのようにBCFをOpenStackとインテグレーションしているか、どのように運用しているのかについて紹介させていただきます。

OpenStackとSDNの導入の狙い

従来はネットワークのconfig変更をする場合、サーバエンジニアからネットワークエンジニアにその作業を「依頼」する形を取っていたのですが、この「依頼」を無くすことが狙いでした。依頼内容としてはスイッチへのVLAN設定やACL設定、LBへのオブジェクト追加など比較的簡単な作業です。しかし、依頼件数が多い時などはネットワークエンジニアがその依頼を作業するまでに数日要することもあり、スピード感に欠ける状況となっていました。それをOpenStackとSDNの導入によって、自動化したり、サーバエンジニアが自ら行うことができるようにすることで作業のスピードを上げることができ、またネットワークエンジニアもより高度なスキルを要する業務に集中できるのではないかと考えました。

構成

OpenStack + BCF 構成パターン

BCFをOpenStackと共に使用する方法としては3パターンあります。一つめはOpenStackのアンダーレイネットワークとしてBCFを使用する方法でこの場合はOpenStackとBCFの連携はありません。二つ目はP-Fabricと呼ばれる方法でOpenStackとBCFでLayer2の情報のみ連携しルーティングは物理ネットワーク上で行います。それに対しP+V FabricというパターンではLayer2, Layer3が連携され、各Compute Node上で分散ルーティングされます。P+V Fabricの方が柔軟なネットワーク構成が可能ではあるのですが、NATが必須となる仕様となっておりNATの運用に手間をかけたくなかったため、弊社ではP-Fabricのパターンを採用しました。 OpenStack_BCF_integration_pattern.png

BCFの構成

BCFはリーフ&スパイン型のスイッチ郡とBCFコントローラから構成されます。BCFコントローラが全スイッチを集中管理しており、設定作業をする際も個別のスイッチにログインする必要はなくBCFコントローラで全ての作業ができます。POD全体を一つの大きなスイッチ(文字通りBIG SWITCH)のように扱うことができる、というのが特徴です。また、BCFコントローラ、スイッチともLinuxが動作しているため、いざとなればサーバ管理者が慣れ親しんだLinuxコマンドでトラブルシューティングする、ということも可能です。弊社ではスイッチにはDELL社の製品を使用し、リーフ - スパイン間は40Gbps、リーフ - サーバ間は10Gbpsで接続しています。 ONE_BIG_SWITCH.png

OpenStackのネットワーク構成

OpenStackのネットワーク構成としては、ネットワークオプションの一つであるプロバイダーネットワークとして構成しています。Controller Nodeでneutron-serverが動作し、各Compute Nodeではneutron-openvswitch-agentが動作します。neutron-serverではbigswitch社のプラグインであるbsnstacklibと弊社内製プラグインのnetworking-bigswitch-l3-peを使用しています。内製プラグインを開発した背景については後述します。

OpenStackとBCFの連携

ここではOpenStackがどのようにBCFと連携をしているのかを具体的に紹介したいと思います。こちらがBCFのコンフィグの例になります。

tenant demo.openstack
  id 1a2cf63967ca4f26ae5356bb2e6c818c
  origination openstack
  !
  logical-router
    route 0.0.0.0/0 next-hop tenant system
    interface segment net_demo
      ip address 10.66.16.1/24
    interface tenant system
  !
  segment net_demo
    id 5310d836-c170-4fda-882c-8a61324d90c6
    origination openstack
    !
    endpoint 0485e7a0-198f-4b88-a877-ca79d3e882bc
      attachment-point interface-group osvdev0013 vlan 300
      ip 10.66.16.2
      mac fa:16:3e:ef:4f:f4
      origination openstack
    !
    member interface-group osvdev0013 vlan 300
      origination openstackdev

OpenStackとBCFのオブジェクトの対応は以下の通りです。

OpenStackBCF
Projecttenant
Networksegment
Portendpoint
Routerlogical-router

前述したようにP-fabricの構成ではLayer 2の情報が連携されます。具体的には、Project, Network, Portの情報がneutron-serverのbsnstacklibプラグインによってBCF Controllerに同期されます。しかし、Layer 3の情報に相当する logical-router のコンフィグは同期されない仕様となっています。そのため、プロジェクト毎にネットワークを作成する場合はlogical-router部分の設定を手動で追加する必要がありましたが、これでは不便なためnetworking-bigswitch-l3-peプラグインを開発しました。BCF ControllerにはAPIが用意されており、このようにpluginからAPIをコールしています。

障害事例

ここでOpenStack + BCF環境で弊社が遭遇した障害の一つとその解決方法についてご紹介しましょう。

障害内容

ある時、新規に作成したインスタンスが通信できないという障害が発生しました。各Compute Node上のneutron-openvswitch-agentのログを調べてみると、以下のようなneutron-serverに対するリクエストが失敗し続けていました。

2016-08-31 03:48:25.294 9269 ERROR neutron.plugins.ml2.drivers.openvswitch.agent.ovsneutronagent [req-57ee640e-5534-4c17-8818-4ec71381ab07 - - - - -] processnetworkports - iteration:1081082 - failure while retrieving port details from server

調査してみると、neutron-sererのbsnstacklibプラグインの不具合が原因となりリクエストがタイムアウトしていました(この不具合については既に修正済みとなっています)。neutron-openvswitch-agentはこのリクエストが失敗すると全ての管理情報を再同期しようとするため(ソースコードだとこの辺り)、さらにneutron-serverに大量のリクエストが集まり処理しきれず再度失敗する、ということを繰り返していました。

復旧方法

まずneutron-serverの負荷を減らしリクエストを捌ききるために、各Compute Node上のneutron-openvswtich-agentを1台ずつ止めていく、というオペレーションをしていきました。すると無事neutron-serverに溜まっていたリクエストがなくなりました。次は止めたneutron-openvswitch-agentを起動していくわけですが、しかし、ここで一つ問題ありました。その時使用していたneutron-openvswitch-agentのバージョン(liberty, 2:7.0.4-0ubuntu1~cloud0)だと、起動時にインスタンスの通信が数秒途切れることが分かっていました。neutronのリポジトリを調べてみるとこれらのパッチ(Cleanup stale OVS flows for physical bridges, Don't disconnect br-int from phys br if connected)で修正されていることが分かりました。これらのパッチを適用した後、止めていたneutron-openvswitch-agentを一つずつ起動しneutron-serverがリクエストを処理し終わるのを待つ、というオペレーションをしていくことで無事復旧することができました。

まとめ

OpenStack環境のSDNに使用しているBCFについて紹介させていただきました。当初の狙い通り、OpenStackとBCFを連携させることで、ネットワークエンジニアへ依頼をすることなく、サーバエンジニアが自らネットワーク構築や設定変更ができる環境を構築することができました。
BCFとのインテグレーションについてご紹介したように、製品自体がユースケースに合わない場合でもAPIを完備していることでユーザ自身がカスタマイズできることはSDN製品の良いところだと思います。またトラブルシューティングについても、OpenStackやそのプラグインはオープンソースなのでいざとなればユーザ自身が調査し問題解決できることもご理解いただけたかと思います。

次回はいよいよSDS編です。

続きを読む
ツイート
シェア
あとで読む
ブックマーク
送る
メールで送る

DeNAにおけるOpenStack運用#1

DeNAでシステムインフラを運用しています小野です。
今回から3回に渡って、OpenStackの運用についてご紹介したいと思います。

OpenStackとは

OpenStackとは、いわゆるクラウド環境を構築/運用管理するためのOSS platformです。2010年にRack Space社とNASAのjoint projectとして始まり現在ではOpenStack Foundationが管理しています。

openstack-cloud-software-vertical-web.png

OpenStackは多数のOSSで構成されています。mysqlやrabbitmqなどお馴染みのOSSもbackendに使われていますが、OpenStack固有のOSSが主要コンポーネントになっています。例えばcomputing(vmやcontainer)の管理をするnova、ネットワークを管理するneutron、WebUIを管理するhorizonなどなどです。こちらでどういったコンポーネントがあるかを確認できます。

stackalytics.comというサイトでOpenStackの開発状況のactivityが見れるのですが、最新versionでは150社以上が開発に参加しているようで非常にglobal且つ活発であることがわかります。

半年毎に新versionがリリースされるスケジュールになっており、名称はアルファベット順に頭文字を使うルールになっています。Aから始まり最新versionではMまで進んでおりMitakaと呼ばれています。次期version(もう間もなくリリース予定なのですが)はMの次のNの頭文字を使いNuetonに決まっています。

この半年のリリーススケジュールに合わせ、半期毎にOpenStack summitというカンファレンスが開催されておりOpenStack界では一番のイベントとなっています。ここでは最新knowledgeの共有やuser事例紹介、次期version設計の為のdiscussionがopenに行われます。DeNAでも2014年11月に開催されたパリsummit以降参加するようになりました。

以前は完成度の低さが揶揄されていた時期もあったようですが、現在ではprivated cloudのみならずPublic cloudの基盤としても使われており、今やこの分野では完全なデファクトになっています。日本でも数年前からIT系企業を中心に利用する企業が増えています。

取組みの背景

何が課題だった?

DeNAでは以前からマイクロなレベルの効率化を追求していましたが長らく大きくは変わっていないところがあり、それはネットワーク管理の部分でした。この分野はサーバ管理と比べるとレガシー度が高く、市場環境として商用ハードウェアアプライアンス製品の独壇場になっていたことが主要因でなかなか効率化が進んでいませんでした。サーバ管理がよりオープンに進化しエコシステムが形成されていったのと比べると、違いは歴然です。その為自動化・効率化したくてもし難いという状況が続き、ネットワークのconfig変更が発生すると「依頼」という形で専任の担当者に作業してもらうということが続いていました。

またサーバがハードウェア故障等でお亡くなりになってしまった場合、代替機を構築する必要が発生します。いくらそれなりにprovisioningを自動化していようとも、creativeではない作業に時間を割くのは何となく気が乗らず不毛に感じるもので、こういうのを何とかしたいという考えがありました。

Publicクラウドの充実

一方でここ3〜5年ほどでPublicクラウドの品質/機能も著しく向上し、クラウドfirstが普通になってきました。あらゆることを 最少人数且つ最速でやり易いこういった環境と比べると、オンプレミスの作業効率は見劣っています。それならばPublicクラウドに移行するという考えもあり得るわけですが、弊社の現時点での試算ではコストが割に合いません。CAPEXではなくOPEXで考えてもです。その為オンプレのまま作業効率を上げたいという方向での取組も重要と捉えていました。
※ とはいえ適材適所でPublicクラウドもかなり利用してはいます

高難度技術への取組み

また違う観点として、より広範な人材を育てるべくサーバー管理、ネットワーク管理の融合を進めたいという考えもありました。
どうしてもある程度組織的に大きくなると業務分担が進みます。現在のDeNAでもサーバ管理とネットワーク管理でグループが別れているのですが、以前は違っておりその方がスピード感がありました。
なのでそれに近付けたいという思いと、OpenStackの運用は非常に広範囲な技術知識が要求されますので、個々人にとってもより広範な技術領域の習得に繋がる機会を創出することはプラスであるという考えからも、この両者の管理を融合してきたいという考えを持っていました。

ちなみにDeNAのインフラ部門では以前からアプリケーションレイヤーも含めた全方位的な管理スタイルをとっています。アプリケーションがトラブルを起こすことは極めて多いので、one stopで障害対応等する為にはアプリケーションのソースを理解しカバーすることが重要と考えています。

以前のOpenStackは単にサーバーをサーブするだけの仕組みにしかみえず、その割にバックエンドの構成が複雑なことと、そういう範囲であれば既に内製開発した同機能を提供するtoolを持っていたことから利用メリットを感じませんでした。
それが近年この分野でOpenStackがデファクトの位置を得始めるとOpenStackとのintegrationをうたう製品やソフトウェアが増え始め、ネットワーク管理とのintegrationも現実的になってきました。その為最初に挙げたような課題解決の為の基盤の中心としてOpenStackの導入を本格検討し始めました。
そしてDeNAでも2016年3月よりOpenStackを使った新世代のインフラ基盤の稼働を開始しています。
今年年初の弊社のTechカンファレンスで発表させて頂いた構想で、ほぼこれを実現したものになります。 ※ 但し最後の方にあるOSコンテナ、S(M)R-IOVなどはまだこれからのロードマップになっています。

SDX integration

SDXとは?

DeNAではOpenStackを導入するにあたって、SDN(Software Defined Network)とSDS(Software Defined Storage)を当初から導入しています。Software Defined Xというのは、XをSoftware的に扱うという意味です。ネットワークもストレージも従来はハードウェアアプライアンスが支配的で管理操作のためのAPIというのは非常に貧弱でしたが、そういったものにAPIをしっかり持たせてあらゆる操作をAPI経由で行う≒ソフトウェア的に扱えるようにしよう、というものでよく使われる表現です。

SDN(Software Defined Network)

SDNにはBigSwitch Networks社のBigCloudFabric(以下BCF)という製品を使っています。 bcf_pv0616a.png

BCFの場合各スイッチを管理するcontrollerが存在し、configuration変更等はcontrollerを介して各スイッチに反映されます。
なので何かを変更したい、情報を取得したいという場合controllerに投げればあとはよしなにやってくれるというわけです。
こう出来ると、サーバを起動する前にネットワーク(VRF/VLAN)の作成をしそこに配置する、なんて連携も簡単に出来ます。awsでvpcを作成しsecurity groupでacl管理するような事ができるわけです。

スクリーンショット 2016-09-27 14.37.25.png OpenStack画面上からのネットワーク作成がスイッチ側に伝わる様子
プロジェクトの作成はVRFの作成にあたります

スイッチ上ではSwitch Light OSというLinux(Debian)ベースのネットワークOSが動いておりcontrollerからの指示を受け自身の設定変更などを行っています。このSwitch Light OSもBigSwitch社が提供していますが、スイッチそのものはDELL社の製品を使っています。
このようにハードウェアとOSが分かれて組合せ出来るのはサーバ管理の世界では当たり前ですが、ネットワーク機器においてはこういうことも長らくできなかったわけです。

switch_light_archictecture.png

BCFの機能上の特徴としてはunderlayネットワークをサポートしてるというのがあります。underlayネットワークの説明をするには、その逆のoverlayネットワークの説明をした方がわかりやすいです。

overlayネットワークとは、ネットワークアドレスが重複しても動作できるネットワークのことです。例えば172.16.0.1/24というネットワークをいくつ作っても動作出来るようなネットワークです。Publicクラウドではこれが当たり前に出来ないと困ります。利用者側で自由にアドレス設計出来ないと使い難くてしょうがないですからね。

overlayネットワークはvxlanやgreというプロトコルを使うことで実現します。実は現在世にあるSDN製品は殆どが何故かoverlayを前提にしています。
underlayはその逆で、ネットワークアドレスの重複を認めないネットワークです。従来型のネットワークと言え、オンプレミスの環境ではこちらが普通です。

overlayネットワークは非常に柔軟性は高いのですが、それを実現する為のprotocolが重く性能面でのデメリットがあるのと、セグメントを跨って通信するにはNATが必要になるという制約も発生します。オンプレミス環境ではIP managementを自分達で出来ますのでoverlayの必要性はそもそも低く、余計なプロトコル層が増えることで負荷や障害の難易度をいたずらに上げたくはないというのもあり、DeNAではunderlayネットワークでの運用を優先しBCFを採用しています。

SDS(Software Defined Storage)

そしてSDSとしてはCephを使っています。

Ceph_Logo_Standard_RGB_120411_fa.png

Cephは分散ストレージソフトウェアです。カリフォルニア大学サンタクルーズ校で開発された後2006年にOSS化されました。現在ではRedHat社がメンテナンスをしており商用サポートも行っています。
blockストレージとしてもobjectストレージとしてもfileストレージとしても使える代物なのですが、DeNAでは主にblockストレージとして使っています。awsで言えばEBSにあたる使い方になります。

CephはOpenStackのBlock Strage Interfaceであるcinderに対応してるので、cinderのapi callでcephに自由にボリュームを作成することが出来ます。

DeNAではcephをguestの起動diskとして使っています。こうすることで再構築のような作業をほぼ0にすることが出来ます。 仮にguestが稼働しているhostサーバが死んでもすぐ別のhostサーバで起動すればいいだけなので。

スクリーンショット 2016-09-27 15.33.31.png

cephによるstorage poolからguestのimageを再読込して別のhostサーバで起動する様子
cephはデータを3重化して保持しておりこのstorage pool自体が壊れてしまうことはない想定

また、livemigrationも可能になりハードの不調が疑われる筐体からguestを逃がす事が簡易に出来るなど、運用面でかなりのメリットを得ています。

なお、ハードウェア構成としてはいわゆるハイパーコンバージドな、compute nodeとstorage nodeを一体化した構成にしており、hypervisorはKVMを使っています。

最後に

SDNやSDSで実現してることはPublicクラウドでは当たり前のことですが、それがオンプレの環境でも出来るというのをイメージ頂けたかと思います。
OpenStackを使うならSDN、SDSもしっかり含めインフラ全体をintegrationし、単なるvmをサーブするだけではない環境として高い運用効率を得ることがポイントではないかと思います。

PublicクラウドはこういったIaaSだけではなくPaaSも充実してるものもありますが、OpenStackもPaaS関連のprojectが多々あるので、今後はそこも似てくるかもしれません。

OpenStackはOSSですが、各ベンダーが商用サポートを付けているdistrubusion版が多数存在します。CentOSに対するRedHat Enterpriseのようなものです。
そういうものが存在するというのは、裏を返せば運用していくのはそれなりの難易度が必要ということで、そこそこ骨が折れるのが正直なところです。
次回以降はSDN、SDS周りのより詳細な部分をお伝えしたいと思います。
本格運用を開始してまだ半年程度ではありますが、結構いろいろな格闘がありました。

続きを読む
ツイート
シェア
あとで読む
ブックマーク
送る
メールで送る