■現象
The SQL Server Network Interface library was unable to close socket
handle due to a closesocket failure under memory pressure.
Winsock error code: 0x2747.
または、
「ユーザーsaはログインできませんでした」
のエラーが出て、SQL Serverにつながらなくなる。
■原因
サーバメモリ不足の可能性がある。
正確には、アプリケーションが利用可能なメモリの限界に達した。
と言い換えることができる。
メモリ不足のため、ネットワークライブラリがクライアントからの接続を
受け付けなくなり、ログインできませんのエラーが発生した。
■調査
まず、前提として、物理メモリは、OSとアプリで分け合って利用している。
もともと利用可能な割合は決まっていて、32ビットOSで4GBメモリならば
OSは2GB、アプリは2GBとなる。
・物理アドレス拡張 (PAE)
http://www.atmarkit.co.jp/fwin2k/win2ktips/1125paeon/paeon.html
・3GBスイッチ
http://webdesign-ginou.com/pc/pc_mac_kiki/3gb_switch.html
のオプションでこれらの割合は変更可能であるが、今回は未設定という
前提で対処方法を検討してみる。
■検証
仮に32ビットOSで4GBメモリが実装済みとする。
最大使用可能量は、
OSは2GB、アプリは2GBとなる。
ここで、SQL Serverは、最大2GB使用可能であると言える。
SQL Serverでは、「
max server memory
」のパラメータでメモリ使用量を
調整可能であるが、注意点としてSQLServer全体の使用量上限でなく
あくまでバッファキャッシュの上限を決めることができる。
http://technet.microsoft.com/ja-jp/library/ms180797(v=sql.105).aspx
「プロセスとしての SQL Server は、max server memory オプションで
指定された容量を超える」とあることから「
max server memory
」に
2GB割り当ててしまうと、メモリ不足エラーが発生する。
※SQL Server総使用メモリ=プロセス使用分+バッファキャッシュ割り当て分
■対処
今回のエラーの場合は、
SQL Serverサービスの再起動が必要である。
メモリ使用量が少ないからといって、DBに割り当て過ぎると
今回のような障害が発生する可能性がある。
他のアプリケーションの最大メモリ使用を見ながら、
SQL Serverの
「
max server memory
」には、余裕を見て初めは少なめに割り当て
すると良いだろう。
バッファキャッシュは、検索などを早くするためなので
少なめであっても使えなくはならないはずだ。
補足ではあるが、AWEオプションを有効にしていると、仮想メモリに
待避できないようなので、物理メモリを
SQL Serverが占有しやすくなる。
このオプションをOFFにすると、パフォーマンスは下がるだろうが
メモリを占有するなどの障害は減るかもしれない。
http://technet.microsoft.com/ja-jp/library/ms190673(v=sql.105).aspx
■今後
まずサーバのメモリを増やす方法が考えられる。
64ビットOSにリプレイスすれば、使用可能メモリも大幅に増やせる。
もし、32ビットOSでメモリが不足気味であれば、先に述べたように
メモリの割り当てを少なめにして、他のアプリがムダに占有していないか
調査も必要であろう。またSQLを見直すことでも使用メモリを減らせるはずだ。
Out2Dev BLOG
2013年8月21日水曜日
2013年5月10日金曜日
The provider is not compatible with the version of Oracle client
「 The provider is not compatible with the version of Oracle client 」
または、
「 プロバイダは、このバージョンのOracleクライアントと互換性がありません 」
というエラーが出た場合についての対処について
■原因
ODACをインストールした際に、「Instant Client」にチェックを付け導入した。
これにより参照順序が変わり、 「Instant Client」がインストールされたフォルダを
参照するようになった。(先にDB本体をインストール済みであった。)
マニュアルを見ると、
.NET Framework 2.0用のOracle.DataAccess.dllおよび.NET Framework 4用の
Oracle.DataAccess.dllは両方とも同じ非管理DLL(OraOps11w.dll)を使用するとある。
しかし、 「Instant Client」は、「OraOps11w.dll」が同梱されていないようである。
さらにマニュアルを見ると、
Oracle.DataAccess.dllアセンブリの非管理DLLの正しいバージョンでの使用を
強制するため、Oracle.DataAccess.dllが依存する非管理DLLと異なるバージョンを
ロードすると例外が発生するとある。
この例外が、先に書いたエラーメッセージである。
■対処
「OraOps11w.dll」を 「Instant Client」が導入されているフォルダにコピーする。
具体的には、※各自の環境により変化するが・・
「C:\app\ユーザー名\product\11.1.0\db_1\BIN」配下の
・ OraOps11.dll
・ OraOps11w.dll
を以下にコピーする。
「C:\app\ユーザー名\product\11.1.0\client_1\ODP.NET\bin\2.x」
この作業により、 「Oracle.DataAccess.dll」は、 「OraOps11w.dll」を
正しく参照できるようになり、問題は解決するはずである。
■対策
今回のケースでは、エラーメッセージが分かりにくく、根本原因を突き止めにくい。
より分かりやすいエラーメッセージを望むとともに、再発防止策として、
あらかじめアプリのインストーラーに必要なDLLを含めておくとよいであろう。
■追記
別の原因が見つかったので追記します。
サーバーOSが64bitの場合、
・ODAC(11.2.0.3.0)の場合、64bit用のDLLがインストールされる。
・ODAC(11.2.0.2.1)の場合、32bit用のDLLがインストールされる。
この違いに気がつかず、アプリ側をx86指定でコンパイルしていると
ODAC(11.2.0.3.0)の場合、先のエラーが発生する。
(x64とx86は、互換性がないためである)
解決策は、
32bitで進める場合、ODAC(11.2.0.3.0)をアンインストール、ODAC(11.2.0.2.1) をインストール
64bitで進める場合、x86→x64に変更してコンパイルすればよいだろう。
または、
「 プロバイダは、このバージョンのOracleクライアントと互換性がありません 」
というエラーが出た場合についての対処について
■原因
ODACをインストールした際に、「Instant Client」にチェックを付け導入した。
これにより参照順序が変わり、 「Instant Client」がインストールされたフォルダを
参照するようになった。(先にDB本体をインストール済みであった。)
マニュアルを見ると、
.NET Framework 2.0用のOracle.DataAccess.dllおよび.NET Framework 4用の
Oracle.DataAccess.dllは両方とも同じ非管理DLL(OraOps11w.dll)を使用するとある。
しかし、 「Instant Client」は、「OraOps11w.dll」が同梱されていないようである。
さらにマニュアルを見ると、
Oracle.DataAccess.dllアセンブリの非管理DLLの正しいバージョンでの使用を
強制するため、Oracle.DataAccess.dllが依存する非管理DLLと異なるバージョンを
ロードすると例外が発生するとある。
この例外が、先に書いたエラーメッセージである。
■対処
「OraOps11w.dll」を 「Instant Client」が導入されているフォルダにコピーする。
具体的には、※各自の環境により変化するが・・
「C:\app\ユーザー名\product\11.1.0\db_1\BIN」配下の
・ OraOps11.dll
・ OraOps11w.dll
を以下にコピーする。
「C:\app\ユーザー名\product\11.1.0\client_1\ODP.NET\bin\2.x」
この作業により、 「Oracle.DataAccess.dll」は、 「OraOps11w.dll」を
正しく参照できるようになり、問題は解決するはずである。
■対策
今回のケースでは、エラーメッセージが分かりにくく、根本原因を突き止めにくい。
より分かりやすいエラーメッセージを望むとともに、再発防止策として、
あらかじめアプリのインストーラーに必要なDLLを含めておくとよいであろう。
■追記
別の原因が見つかったので追記します。
サーバーOSが64bitの場合、
・ODAC(11.2.0.3.0)の場合、64bit用のDLLがインストールされる。
・ODAC(11.2.0.2.1)の場合、32bit用のDLLがインストールされる。
この違いに気がつかず、アプリ側をx86指定でコンパイルしていると
ODAC(11.2.0.3.0)の場合、先のエラーが発生する。
(x64とx86は、互換性がないためである)
解決策は、
32bitで進める場合、ODAC(11.2.0.3.0)をアンインストール、ODAC(11.2.0.2.1) をインストール
64bitで進める場合、x86→x64に変更してコンパイルすればよいだろう。
2013年2月1日金曜日
Windows 2008 Server R2 + FTPS ( FTP + SSL )で「ディレクトリ一覧を取得できませんでした」のエラー
■環境
Windows 2008 Server R2
IIS 7.5
■ネットワーク構成
▲サーバー ⇔ FW(NAT)★ ⇔ インターネット ⇔ クライアント
※▲・・ローカルIP
※★・・グローバルIP
※FW・・ファイヤーウオール
※NAT・・プライベートIPアドレスをグローバルIP アドレスに変換
■ポイント
FTPは、2つの通信ポートを利用する
①コネクション確率用(デフォルト21番)
②データ送受信用(デフォルト20番)
また、PASVモードの場合、②データ送受信用は、ある範囲内で
ポート番号が可変する。
SSL化していると、Activeモードは利用できず、PASVモードを使う必要がある。
ポート番号は、20、21番から別の2つの番号に変更可
■エラーの原因
データ送受信用ポートがファイヤーウォールで
ブロックされている可能性が高い。
「ディレクトリ一覧を取得できませんでした」
コネクションは確立され、つながるのだが、データ送受信段階になって
ファイヤーウオールに拒否られてる状態である。
では、ファイヤーウオールを解放しようとしてもポート番号が可変のため、
どこを解放すべきか判断がつけられない。
■対処方法
下記のサイトを参考にした。
http://junpla.blog3.fc2.com/blog-entry-247.html
A.ファイヤーウオールにFTP用のポート2つを開ける
B.データ送受信用ポートの範囲を明示する(1024番以降でFromTo指定)
C.ファイヤーウオールの外部IPを指定する
D.上記、設定後、サーバー再起動が必要(Microsoft FTP Serviceの再起動でもよい)
では、設定内容を見ていこう
Aについては、下記のイメージ
Source:Any
Destination:XXX.XXX.XXX.XXX(★グローバルIP)
Service:ftp
Port:XXXX,YYYY(FTPの2つのポート番号)
Action:permit
Bについて、データ送受信用のポート範囲を指定
Windows 2008 Server R2 のIISマネージャ
FTPグループ
FTPファイアウォールのサポートを選択
データチャンネルのポート範囲を入力
例えば、5678-5678
とすると、5678番のみがデータ通信用ポートして利用される
→つまり、ファイヤーウオールに明示的設定可能になる
※ここで設定するポートとは、データ通信用であり、コネクション用ポートは関係ない。
※ポート範囲が1つでも複数台からFTPできた。
Cについて、PASVモードのため必要と思われる
Windows 2008 Server R2 のIISマネージャ
FTPグループ
FTPファイアウォールのサポートを選択
ファイヤーウオールの外部IPアドレスを入力
上記「ネットワーク構成」で記載した★グローバルIPを入力すればよい
Dについては、よく分からないが、設定反映に必要だった。
■通信確認
利用したソフトウェア:WinSCP
プロトコル:FTP
暗号化:SSL明確な暗号
ホスト名:★グローバルIP
ポート番号:コネクション確率用のポート番号
ユーザー名:FTPのユーザー名
パスワード:FTPのパスワード
※接続のタブ→パッシブモードにチェックを付ける
ログインして、ファイルの読み書きができればOK(ここは各自権限設定によるが)
■最後に
初めて、FTPSを構築しようとすると、はまりやすいところである。
FTPSが開通しないと、プロジェクトが先に進まなくなることもあるだろう。
インフラセットアップは、やってみないと分からない部分であり、
普段から練習もできなかったりする。日頃から知識を蓄えておいて先人のノウハウを
参考にしながら、試行錯誤するしかないようである。
■追記 2014/05/01
IIS7.5のFTPのデータチャネルのポート範囲がグレーアウトしている場合は、
大元のFTPで設定が可能となっている。
2012年12月9日日曜日
SQLSERVER デットロックを防ぐ②
デットロックが発生原因について、もうひとつ付け加えたい。
■現象
2つのセッションがあり、1つのテーブルがあるとする。
①あるセッションは、テーブルにINSERTを実行
②あるセッションは、条件指定でSELECTを実行
ここで、デットロックが発生したとする。
①と②は、まったく条件が異なるため、デットロックしないはずでは。。
■原因
テーブルには、INDEXが設定されており、INSERTが
COMMITされるまでは、その INDEX を利用したSELECTがロック待ちになる。
(INDEXの木構造を再構築中のためではないか)
■対策
INDEXを参照しないでSELECTする。
利用頻度が低い INDEX は、削除した方が、INSERTも早くなる。
INDEXは、パフォーマンスを大幅に改善することがあるが、
デットロックを引き起こす原因になることも忘れてはならない。
■現象
2つのセッションがあり、1つのテーブルがあるとする。
①あるセッションは、テーブルにINSERTを実行
②あるセッションは、条件指定でSELECTを実行
ここで、デットロックが発生したとする。
①と②は、まったく条件が異なるため、デットロックしないはずでは。。
■原因
テーブルには、INDEXが設定されており、INSERTが
COMMITされるまでは、その INDEX を利用したSELECTがロック待ちになる。
(INDEXの木構造を再構築中のためではないか)
■対策
INDEXを参照しないでSELECTする。
利用頻度が低い INDEX は、削除した方が、INSERTも早くなる。
INDEXは、パフォーマンスを大幅に改善することがあるが、
デットロックを引き起こす原因になることも忘れてはならない。
SQLSERVER NOLOCKオプションの有効性
今回は、NOLOCKオプションについて、いくつか書いてみたいと思う。
■効果
あるテーブルがUPDATEされ、COMMIT待ちの状態であるが、
NOLOCKオプションをつけると、COMMIT前のデータがSELECTできてしまう。
つまり、複数のセッションで処理する場合、待ち時間がなくなるため
パフォーマンスアップにつながるわけである。
■弊害
COMMIT前のデータが読めるというのは、ダーティリードとも呼ばれる。
何が問題かというと、ROLLBACKされたときに、読み取ったデータが
存在しなくなるということである。または存在しても異なっている場合がある。
取得した値を利用して、処理をしてみたが、あるタイミングで、その値は
無効なものとなっている。前提が崩れているとすれば処理結果も信用できない。
また、NOLOCKオプションを付ける前だと、ロック待ちとして排他されていたが
付けた後だと、同時実行されるようになり、整合性に問題がでる場合がある。
■使用場所
①別記「SQLSERVER デットロックを防ぐ」にあるように、デットロック回避に使う。
→NOLOCKオプションでSELECT後、一意キーでアクセスすることにより、
ロック範囲を狭めるのと、整合性の確認、パフォーマンスアップにつながる。
②ROLLBACKがほぼなく、パフォーマンスアップしたい箇所につかう。
または、ROLLBACKされても整合性に問題が起きない箇所。
在庫データの参照など、ダーティリード時の影響が大きい箇所などには適用せず
リスクが比較的少ない箇所から実験するのもひとつの手である。
■効果
あるテーブルがUPDATEされ、COMMIT待ちの状態であるが、
NOLOCKオプションをつけると、COMMIT前のデータがSELECTできてしまう。
つまり、複数のセッションで処理する場合、待ち時間がなくなるため
パフォーマンスアップにつながるわけである。
■弊害
COMMIT前のデータが読めるというのは、ダーティリードとも呼ばれる。
何が問題かというと、ROLLBACKされたときに、読み取ったデータが
存在しなくなるということである。または存在しても異なっている場合がある。
取得した値を利用して、処理をしてみたが、あるタイミングで、その値は
無効なものとなっている。前提が崩れているとすれば処理結果も信用できない。
また、NOLOCKオプションを付ける前だと、ロック待ちとして排他されていたが
付けた後だと、同時実行されるようになり、整合性に問題がでる場合がある。
■使用場所
①別記「SQLSERVER デットロックを防ぐ」にあるように、デットロック回避に使う。
→NOLOCKオプションでSELECT後、一意キーでアクセスすることにより、
ロック範囲を狭めるのと、整合性の確認、パフォーマンスアップにつながる。
②ROLLBACKがほぼなく、パフォーマンスアップしたい箇所につかう。
または、ROLLBACKされても整合性に問題が起きない箇所。
在庫データの参照など、ダーティリード時の影響が大きい箇所などには適用せず
リスクが比較的少ない箇所から実験するのもひとつの手である。
SQLSERVER デットロックを防ぐ
2つのセッションが1つのテーブルにアクセスするとき、異なる抽出条件に
なっているにも関わらず、そこでデットロックが発生することはないだろうか?
■状況
たとえば、テーブルのカラムが
ID
GROUP
NAME
AGE
となっていて、
セッション①
WHERE ID = 1
セッション②
WHERE ID = 2
などとアクセスする。
このとき、別のデータを取得しようとしているので、ぶつからないはずである。
■原因
いくつかあるのだが、以下のような場合である。
①ID、GROUPのカラムで複合一意キーを指定していたが、どちらか片方で
アクセスしていた。
②一意キー以外の条件でアクセスすると、関係ないレコードまでロックされる
(SQLSERVERは、勝手に広範囲をロックしてしまうようだ)
■対応策
①複合一意キーの場合は、その定義順序で、定義されているカラムを必ず指定すること
② 一意キー以外の条件でアクセスする場合、WITH (NOLOCK) オプションでまず
データを取得する。その後、取得結果をカーソルでまわしながら、一意キーで
再度SELECTする。
※ WITH (NOLOCK) オプションは、ROLLBACK時の影響があることから乱用は避けたい
このような対応で、ロック範囲は意図した通りとなり、デットロックは軽減される。
■参考
ロック範囲が意図した範囲か確認する方法として、以下がある。
「Management Studio」を2つ起動させておく。
①片方で、範囲外と思われるレコードをUPDATE
②もう片方で、確認したいSELECT文を流す( 調べたいWHERE句を指定して )
以上を実行してみて、固まる(ロック待ち)となれば、ぶつかっているし、
無事にSELECTできれば、ロック範囲は重なっていない。
なっているにも関わらず、そこでデットロックが発生することはないだろうか?
■状況
たとえば、テーブルのカラムが
ID
GROUP
NAME
AGE
となっていて、
セッション①
WHERE ID = 1
セッション②
WHERE ID = 2
などとアクセスする。
このとき、別のデータを取得しようとしているので、ぶつからないはずである。
■原因
いくつかあるのだが、以下のような場合である。
①ID、GROUPのカラムで複合一意キーを指定していたが、どちらか片方で
アクセスしていた。
②一意キー以外の条件でアクセスすると、関係ないレコードまでロックされる
(SQLSERVERは、勝手に広範囲をロックしてしまうようだ)
■対応策
①複合一意キーの場合は、その定義順序で、定義されているカラムを必ず指定すること
② 一意キー以外の条件でアクセスする場合、WITH (NOLOCK) オプションでまず
データを取得する。その後、取得結果をカーソルでまわしながら、一意キーで
再度SELECTする。
※ WITH (NOLOCK) オプションは、ROLLBACK時の影響があることから乱用は避けたい
このような対応で、ロック範囲は意図した通りとなり、デットロックは軽減される。
■参考
ロック範囲が意図した範囲か確認する方法として、以下がある。
「Management Studio」を2つ起動させておく。
①片方で、範囲外と思われるレコードをUPDATE
②もう片方で、確認したいSELECT文を流す( 調べたいWHERE句を指定して )
以上を実行してみて、固まる(ロック待ち)となれば、ぶつかっているし、
無事にSELECTできれば、ロック範囲は重なっていない。
2012年8月22日水曜日
SQLSERVER 3414 エラー
昨日まで使えたのに今日立ち上げたらつながらなくなった
ということはないだろうか?
Management Studioでデータベースを開こうとすると以下のエラー出る
・エラー 3414、Error: 3414 ( MSSQLSERVER_3414 )
・データベースにアクセスできません。接続できない
・復元中にエラーが発生したので、データベース は再開されません
・利用できません、利用不可
・An error occurred during recovery, preventing the database
これは、データベース起動中にエラーが発生しオープンできずにいる状態で
Management Studioからどうすることもできないように見える。
が、しかし、そこはデータベースなので万が一のディスクエラーにもある程度
対処できるようコマンドが用意されているのだ。
■手順 (Resolution)
①ステータスリセット
exec master..sp_resetstatus データベース名
②データベースをリカバリ
DBCC DBRECOVER ('データベース名', IGNOREERRORS)
③復旧後の整合性チェック
DBCC CHECKDB ('データベース名') WITH NO_INFOMSGS, ALL_ERRORMSGS;
④ ③でエラーが出ず、データベースが開ければ無事完了である
■結果
このような事態が本番環境で発生するとサービスが停止してしまうので影響は甚大である。
普段から障害発生時を想定して、エラー原因と対処方法などを調べておいたり、
実際、テスト環境で発生したときにじっくり対処方法を検討し、まとめておくとよいだろう。
ということはないだろうか?
Management Studioでデータベースを開こうとすると以下のエラー出る
・エラー 3414、Error: 3414 ( MSSQLSERVER_3414 )
・データベースにアクセスできません。接続できない
・復元中にエラーが発生したので、データベース は再開されません
・利用できません、利用不可
・An error occurred during recovery, preventing the database
これは、データベース起動中にエラーが発生しオープンできずにいる状態で
Management Studioからどうすることもできないように見える。
が、しかし、そこはデータベースなので万が一のディスクエラーにもある程度
対処できるようコマンドが用意されているのだ。
■手順 (Resolution)
①ステータスリセット
exec master..sp_resetstatus データベース名
②データベースをリカバリ
DBCC DBRECOVER ('データベース名', IGNOREERRORS)
③復旧後の整合性チェック
DBCC CHECKDB ('データベース名') WITH NO_INFOMSGS, ALL_ERRORMSGS;
④ ③でエラーが出ず、データベースが開ければ無事完了である
■結果
このような事態が本番環境で発生するとサービスが停止してしまうので影響は甚大である。
普段から障害発生時を想定して、エラー原因と対処方法などを調べておいたり、
実際、テスト環境で発生したときにじっくり対処方法を検討し、まとめておくとよいだろう。
登録:
投稿 (Atom)