SE の雑記

SQL Server の情報をメインに Microsoft 製品の勉強内容を日々投稿

SQL Database に接続する際の接続フローについて

leave a comment

2020/7/1 に SQL Database で次のような障害が発生しました。

7/1

Azure SQL Database – Japan East – Mitigated (Tracking ID CLCK-LD0)

Summary of Impact: Between 09:30 and 11:15 UTC on 01 Jul 2020, a subset of customers using SQL Database in Japan East may have experienced service connection failures or possible timeouts. Services utilizing SQL Databases may have also been impacted.

Preliminary Root Cause: We determined that instances of a gateway service responsible for handling traffic to and from some SQL Databases became unhealthy. This prevented some connections from completing as expected and caused downstream impact to services leveraging SQL Databases.

Mitigation: We performed a manual restart of the impacted gateways to mitigate the issue.

Next Steps: We will continue to investigate to establish the full root cause and prevent future occurrences. A full Root-Cause Analysis will be provided in the next 72 hours. Stay informed about Azure service issues by creating custom service health alerts: https://aka.ms/ash-videos for video tutorials and https://aka.ms/ash-alerts for how-to documentation.

最終的な RCA (Root Cause Analysis : 根本原因解析) としては、次のような内容が公開されています。

Summary of impact: Between 09:24 and 11:15 UTC on 01 Jul 2020, a subset of customers using Azure SQL Database, Azure SQL Data Warehouse/ Synapse analytics in Japan East may have experienced service connection failures or possible timeouts. Services utilizing SQL Databases may have also been impacted.

Root cause: Connections to Azure SQL Database and related data services go through a load balanced set of front-end nodes (Gateways) that provide directory lookup services and reroute the incoming connections to the intended backend-end nodes hosting the database. For scalability and zone redundancy purposes, there are multiple active SQL Gateway clusters in a region. During this incident, one of the SQL Gateway clusters became unhealthy having an intermittent impact on login availability. A specific network traffic pattern combined with a networking stack configuration on the SQL Gateway instances triggered an imbalance on the CPU processing of new connection requests. The persistence of such CPU imbalance over a long period of time caused high response latency and increased timeouts on connection requests. The error condition propagated across multiple instances of the SQL Gateway cluster in this region, sometimes causing a service restart.

Mitigation: Multiple SQL Gateway instances became healthy upon the triggered service restart. On further investigation, we were able to isolate the specific network pattern and the configuration setting that caused this incident and were able to reconfigure the traffic to prevent a recurrence.

Next Steps: We apologize for the impact to affected customers. We are continuously taking steps to improve the Microsoft Azure platform and our processes to help ensure such incidents do not occur in the future. In this case, this includes (but is not limited to):

  • Fix the underlying issue that causes service restart when such a condition occurs.
  • Improve the alerting logic and add identified telemetry to diagnose this kind of issues faster.
  • Activate a newer SQL Gateway cluster in this region with a more efficient networking stack configuration that reduces the chances of hitting a processing imbalance.

障害の原因としては、「SQL Gateway クラスタ」の一つで問題が発生し、新規接続要求の CPU 処理の問題や、エラーが複数の SQL Gateway クラスターに伝搬しサービスが再起動してしまい、ログインと可用性に断続的に影響を与えたということになっています。

この障害が発生していた際には、既存の接続ついては接続が維持できていたが、新規の接続が許可されないというような状態になっていた環境もあったのではないでしょうか。

障害が発生している最中に、新規の接続を試してみたのですが、SQL Database の論理サーバー名への接続を行おうとしてもタイムアウトが発生 / Pre-Login のフェーズまでは進んだが、そこから先に進むことができず、エラーとなるというような状態となっており、新規の接続を確立することができませんでした。

障害が回復した後に、SQL Database のセッションの状態や起動タイミングを確認してみたところ、データベースについては再起動が行われておらず、いくつかのセッションについては接続が切断されず残ったままとなっていましたので、私の環境については、データベースでは問題は発生しておらず、ゲートウェイ経由での接続のみ問題が発生していたようでした。

 

以前、SQL Database v12 の接続のリダイレクトについて という投稿を書いたのですが、改めて、SQL Database に接続する際には、どのような動作が行われているのかをまとめてみたいと思います。

 

SQL Database の接続ポリシー

SQL Database の接続には「プロキシ」「リダイレクト」「の 2 種類の接続ポリシーがあり、このアーキテクチャについては、Azure SQL Database と Azure Synapse Analytics の接続アーキテクチャ で解説が行われています。

接続ポリシーは、論理サーバー単位で設定することができ、ポータルから操作する場合は「ファイアウォールと仮想ネットワーク」の「接続ポリシー」から変更できます。

image

デフォルトでは「既定」が選択された状態となっており、「既定」に設定されている場合は、次のような動作になります。

  • Azure 外部からのアクセスについては「プロキシ」が使用される
  • Azure 内部からのアクセスについては「リダイレクト」が使用される

「プロキシ」が使用されている場合は、Azure SQL Database ゲートウェイ (今回障害が発生したとアナウンスされている環境) 経由ですべての接続が行われます。

「リダイレクト」が使用されている場合も、最初は SQL Database ゲートウェイに接続されますが、ゲートウェイから実際のデータベースクラスターへの接続情報がアナウンスされ、該当の接続については、以降はデータベースクラスターと直接通信が行われる形になります。

今回の障害ケースでは「SQL Database ゲートウェイを介しての接続」が受け付けていないように見えました。
「リダイレクト」が使用されており、「ゲートウェイ経由の新規接続」ではなく、「コネクションプールによる接続済みセッションの再利用」であれば、継続してクエリを実行することができていたようになっていたのではないでしょうか。 (プロキシでコネクションプールの接続を再利用できる環境が存在しなかったので、試せなかったのですが、実はプロキシでもコネクションプールの接続が再利用できていたのかもしれませんが)

 

SQL Database では、コントロールリング (Control Ring : CR or コントロールクラスター) と テナントリング (Tenant Ring : TR or データベースクラスター) という二つのリングが存在しています。

現時点で公開されている情報としては、Azure SQL Database と SQL Managed Instance の高可用性 になるかと思います。

この技術情報では、次のような図が紹介されています。

image

SQL Database に接続を行う際には、最初にコントロールリングのゲートウェイに接続を行います。
このゲートウェイが ゲートウェイ IP アドレス で記載されている IP の環境となります。

東日本と西日本であれば、次の IP アドレスですね。

image

SQL Database では接続する際には必ず論理サーバーが作成され、「~.database.windows.net」というサーバー名のエンドポイントが付与されます。

この論理サーバー名を DNS で解決してみます。

$sqldbName = "xxxxxxxx.database.windows.net"
$ret = Resolve-DnsName -Type ALL -Name $sqldbName

while($true){
    $ret = Resolve-DnsName -Type ALL -Name $ret.Server
    if($null -ne $ret.IpAddress){
        break
    }
}
$ret | Select *

 

間に一つ CNAME が入るのですが、今回私が使用している環境は、東日本にデプロイしている環境です。

最終的な IP アドレスとしては「13.78.61.196」の「cr2.japaneast1-a.control.database.windows.net」という東日本のゲートウェイ IP アドレスを持つゲートウェイサーバーに対して接続が行われるということが確認できますね。

cr がコントロールリングを表しているのかと思います。

image

「プロキシ」「リダイレクト」のどちらを使用していても、最初に接続されるのは、このコントロールリングのゲートウェイとなります。

RCA で書かれている「SQL Gateway クラスター (インスタンス)」がこのゲートウェイとなるかと思います。

SQL Database への接続の橋渡しをする環境で障害が発生していたため、新規の接続が不可能になっていたのではないでしょうか。

「プロキシ」「リダイレクト」ともに最初の接続に関しては、ゲートウェイに対して行われ、そこから選択している接続方式に応じて、ゲートウェイ経由で接続が行われるか、データベースクラスターにリダイレクトが行われるかが変わります。

プロキシの場合は、ゲートウェイで障害が発生していると接続できませんが、リダイレクトの場合は、一度接続が行われると、該当の接続は、ゲートウェイを介さないで直接データベースクラスターに接続が行われた状態が維持されます。

どちらの接続についてもセッションの最初のアクセスについては、ゲートウェイが基点となりますので、ここが落ちるとデータベースへの接続を完了することができません。

image

 

コネクションプールを使用している場合は、データベースクラスターに直接接続されているコネクションを再利用できますので、障害が発生していても、プーリングされているセッションについては、クエリの実行を維持できたかと思います。

 

それでは、各接続について Azure SQL Database と Azure Synapse Analytics の接続アーキテクチャ のドキュメントを見ながら、詳細に見ていきましょう。

プロキシによる接続

「プロキシ」による接続については次のようになります。

image

 

アプリケーションからの接続については、必ずゲートウェイを経由して接続が行われます。

先ほどの環境であれば、「cr2.japaneast1-a.control.database.windows.net」がゲートウェイですね。

image

この接続方式については、アプリケーションはデータベースクラスター内の環境には直接アクセスができなくても、ゲートウェイに対してのみアクセスができれば接続を確立することができます。

アーキテクチャでは次のように解説が行われています。

プロキシ: このモードでは、すべての接続が Azure SQL Database ゲートウェイ経由でプロキシ化されるため、待機時間が長くなり、スループットが低下します。 接続でこのモードを使用するには、クライアントのポート 1433 で、クライアントから、Azure SQL Database ゲートウェイの IP アドレスへのアウトバウンド通信を許可する必要があります。

プロキシを使用する場合は、必ずゲートウェイを介しての接続となるため、データベースへの接続に対してワンクッション挟むことになります。

ドキュメントではこれが「すべての接続が Azure SQL Database ゲートウェイ経由でプロキシ化されるため、待機時間が長くなり、スループットが低下します。」というように表現されています。

ゲートウェイに対して TCP 1433 で接続することができる経路さえ確保できていれば、SQL Database のデータベースに対してアクセスすることができるため、ネットワークの疎通要件はとてもシンプルなものになります。 (DAC で接続する場合はゲートウェイに対して TCP 1434 で接続が行われます)

ただし、ゲートウェイを介すことによるスループットへの影響や、今回のようなゲートウェイに障害が発生した場合の接続性については、考慮をしておく必要があります。

 

リダイレクトによる接続

「リダイレクト」による接続は次のようになります。

image

最初の接続については、「プロキシ」と同様にゲートウェイに接続が行われます。

image

この後の動作が、リダイレクト固有になります。

「プロキシ」の場合は、ゲートウェイからデータベースクラスターに接続が行われますが、リダイレクトの場合はゲートウェイに接続をした後はデータベースクラスターに直接接続が行われます。

今回の環境であれば、ゲートウェイに接続した後は、次のようなサーバーの情報を受け取ります。

image

 

SQL Database では TLS の暗号化がデフォルトで動作しており、パケットの中身が見えなかったので、クライアントの DNS キャッシュから取得しています。

$cachedRecord = Get-DnsClientCache -Type A | Where-Object Entry -Match "database.windows.net"
$cachedRecord | ForEach-Object{
    try{
        $tmp = $_
        Get-NetTCPConnection -RemoteAddress $_.Data -ErrorAction Stop | ForEach-Object{
            Write-Host ("{0},{2} : {1} : {3}" -f $tmp.Entry, ($_.RemoteAddress).ToString(), ($_.RemotePort).ToString(),($_.State).ToString())
        }
    }catch{
    }
}

 

「xxxxx.trxxxx.japaneast1-a.worker.database.windows.net,11<ポート番号>」というような情報を確認することができました。

tr がテナントリングを表しているのかと。

これがデータベースクラスター (テナントリング) の実際のデータベースのノードの情報となり、「リダイレクト」の場合は、実際のクエリ実行についてはゲートウェイではなく、このサーバーに対して実行が行われます。

image

初回の接続については、ゲートウェイからデータベースが配置されている実際のデータベースクラスターの情報を入手する必要がありますが、コネクションが確立されている間は、データベースクラスターに直接接続されている状態となります。

このような動作を行うため、データベースクラスターに対して直接接続されているセッションについては、コネクションプールで使いまわしている間は、ゲートウェイがダウンしていても接続が行えることになります。 (今回の障害については、このケースに当てはまっている接続については、データベースにクエリ実行ができていたのかと思います)

 

「リダイレクト」については、Azure 内からの利用でない場合も、接続ポリシーをリダイレクトに設定することで、オンプレミス等からの接続についてもこの方式にすることができます。

ただし、ドキュメントでも解説されているように、ネットワークの要件は次のようになります。

リダイレクト (推奨): クライアントは、データベースをホストしているノードへの直接接続を確立します。これにより、待機時間が短縮され、スループットが向上します。 接続でこのモードを使用するには、クライアントで次を行う必要があります。

  • 11000 から 11999 の範囲のポートで、クライアントから、リージョン内のすべての Azure SQL IP アドレスへのアウトバウンド通信を許可します。 SQL のサービス タグを使用すると、この管理が簡単になります。
  • ポート 1433 で、クライアントから、Azure SQL Database ゲートウェイの IP アドレスへのアウトバウンド通信を許可します。

初回の接続については、ゲートウェイに対してアクセスする必要がありますので、プロキシと同様のネットワーク要件 (TCP 1433) が必要となります。

これに追加して、データベースクラスターに直接アクセスを行うためにデータベースクラスターへの TCP 11000~11999 の範囲での通信の許可が必要となります。

Azure SQL で使用されている IP アドレスについては、Azure IP Ranges and Service Tags ? Public Cloud で確認することができ、7/7 時点の東日本であれば、次の IP アドレスの TCP 11000~11999 への接続許可が必要となります。

"addressPrefixes": [

"13.78.61.196/32",

"13.78.104.0/27",

"13.78.105.0/27",

"13.78.121.203/32",

"23.102.69.95/32",

"23.102.71.13/32",

"23.102.74.190/32",

"40.79.184.0/27",

"40.79.185.0/27",

"40.79.192.0/27",

"40.79.193.0/27",

"52.185.152.149/32",

"52.243.32.19/32",

"52.243.43.186/32",

"104.41.168.103/32",

"104.41.169.34/32",

"191.237.240.43/32",

"191.237.240.44/32",

"191.237.240.46/32"

        ]

IP アドレスは追加 / 削除される可能性があるため、動的にメンテナンスをするのはちょっと大変かと思いますので、Azure 外からリダイレクトを使用してアクセスする場合に厳密にアウトバウンドを制御しようとした場合は、IP アドレスの変化にどのように追随するかは要件等となります。

ちなみにフェールオーバーすると、IP アドレス / 接続先のポート番号ともに変更されますので、「いま接続している IP / ポートだけを許可しておけばいい」ということはできません。

 

プロキシとリダイレクトではこのような接続の方法の違いがあります。

SQL Database に接続する場合「プロキシ」「リダイレクト」ともに「ゲートウェイからどのサーバー (データベースクラスター)」に接続すればよいかの情報については必ず渡す必要があります。

サーバー名として論理サーバー名を指定した場合は、どのサーバーに接続すればよいかを判断することができますが、ゲートウェイに対してパブリック IP で接続を行った場合は「どのサーバーに接続すればよいか」は判断することができません。

(ゲートウェイのパブリック IP は、SQL Database の全ユーザーが共通して利用するものですので)

image

論理サーバー名を指定しない (IP アドレスを直接指定 or hosts 等のエイリアスで指定した名称で接続) で接続を行う場合には、ログイン名の後ろに「@サーバー名」を指定しないと、適切なサーバーにリダイレクトすることができないということも、ここまでの内容がわかると理解できるのではないでしょうか。

image

 

 

 

 

おまけ

ここまでの内容を理解できているとこんなこともできたりします。

誰もサポートしてくれないので単なる実験ですが。

Windows ファイアウォールで TCP 1433 の送信をブロックするルールを作成してみます。

image

「プロキシ」「リダイレクト」ともに最初の接続はゲートウェイを介して行われますので、TCP 1433 の送信がブロックされていると、SQL Database に接続することはできません。

image

では、データベースクラスターの情報がわかっている場合はどうでしょうか?

image

この場合、ゲートウェイを介していないので TCP 1433 のアウトバウンドが完全に拒否されていても、データベースクラスターの TCP 11090 に対して直接接続しているので接続することが可能です。

データベースクラスターはフェールオーバーすると使用しているポート番号を含め、変更されますので、今使用している接続文字列だとそのうち接続ができなくなる & もともとこのような接続をサポートしているとは言っていないのでどこまで動くかの責任は一切負いませんが。

ただし、このような接続が可能ということを技術的に把握しておけると、ゲートウェイで障害が発生していても「リダイレクトでコネクションプールが有効な接続についてはクエリ実行を維持することができていた理由」について、理解することができるのではないでしょうか。

 

おまけ 2

仕事柄、各種 DMV の情報を確認して、SQL Database の状態を取得することがあるのですが、「sys.dm_exec_sessions」の「host_name」の「DBxx」(環境によってはWFxxだったはず) というホスト名が気になったことはありませんでしょうか?

(私は気になったのですが)

image

ホスト名の DB の後ろの数字、多分ポート番号です。

今回の環境であれば 11090 というポートで SQL Server のインスタンスを起動している環境となっているので DB90 となっているのかと思います。

Share

Written by Masayuki.Ozawa

7月 7th, 2020 at 10:10 pm

Leave a Reply