
ServiceNowでデータのセキュリティを守る必要はあるものの、ACLが複雑になってパフォーマンスが心配ってことありますよね?
そこで今日はACLの設定によってパフォーマンスにどんな影響がでるかを実際に検証してみます。
ACLの設定の違いによるパフォーマンスを実際に検証
検証の目的
- ACLの設定の違いにより、パフォーマンスにどのような影響が出るのかを検証
- Allow If、Deny-Unless、ロール、レコードの条件、スクリプトでそれぞれどのような違いがあるかを検証
検証の前提
- 検証する環境はDeveloperインスタンスを使うので、本番インスタンスとは測定値が異なる可能性があります。
- ACLの条件はロール、レコードの条件、スクリプトの3パターンで検証するが、パターンが多くなるため複数条件を組み合わせた全パターンの検証は行いません。
検証方法
- ServiceNowの「応答時間インジケーター」と「スクリプトデバッガー」を利用する
- 応答時間インジケーターではサーバーの処理時間、スクリプトデバッガーではトランザクション数を計測値とする。


検証パターン
【パターン毎の検証】
各パターンでACLの設定の違いにより、どのようなパフォーマンスの影響が出るか検証します。
→ロール、レコードの条件、スクリプトによる条件でどのようなパフォーマンス影響が出るかを検証。
ロール、レコードの条件、スクリプトによる条件とはACLの設定箇所を指しています。
・ロール

・レコードの条件

・スクリプトによる条件

【パターン間の検証】
- ①と②の比較により、参照の拒否はDeny UnlessとAllow Ifのどちらがパフォーマンス上優位か検証
- ③と④の比較により、Deny-Unlessでレコードを絞り込んだ上で、Allow Ifを評価した方がパフォーマンスの向上を見込めるのか検証
前回記事にした、Deny-Unless ACLのユースケースとして不要なACL評価を減らすことにより、パフォーマンスの向上を見込めないか?という疑問からこの検証を始めました。
# | パターン | Deny-Unless | Allow-If |
---|---|---|---|
① | Deny-Unlessでテーブル全体へのアクセスを拒否 | × | ー |
② | Deny-Unlessで全て許可した後、Allow Ifで拒否 | 〇 | × |
③ | Deny-Unlessで一部のレコードを拒否した後、残りのレコードをAllow Ifで許可 | 〇 | 〇 |
④ | Allow Ifで許可 | ー | 〇 |
×:拒否
〇:許可
検証の準備
- ①検証用のユーザーを作成
A・B Userを作成し、それぞれA UserにのみRequesterロールを付与します。
- ②ACLを設定するためのテーブルを作成
Taskテーブルを継承した申請テーブルを作成しました。
自分の会社のレコードだけ参照可能、という条件を追加するために「会社」カラムを持たせています。 - ③申請テーブルにデータを作成
- パフォーマンス測定のために、申請レコードを30,000レコード作成しました。
(バックグラウンドスクリプトで作成したのですが時間がかかりすぎて一旦検証を止めて寝ました。) - 30,000レコードのうち100レコードには会社項目に”A Company”を設定し、残りの29,900レコードには”ACME Japan”を設定しています。
- パフォーマンス測定のために、申請レコードを30,000レコード作成しました。
- ④ロールでアクセス拒否・許可を行うためのACLを作成
- Requesterロールを持っているユーザー以外の参照を拒否するDeny-Unless ACLを作成
- Requesterロールを持っているユーザーの参照を許可するAllow If ACLを作成
- ⑤レコードの条件に応じてアクセス拒否・許可を行うためのACLを作成
- 会社項目の値に応じて拒否・許可を行うACLをDeny-Unless、Allow Ifでそれぞれ作成。
- ⑥スクリプトでアクセス拒否・許可を行うためのACLを作成
- ログインユーザーのロールで判別
- レコードの会社レコードで判別
①Deny-Unlessでテーブル全体へのアクセスを拒否

ユーザーがテーブルに対し、アクセスリクエストを行った際にDeny-Unless ACLでアクセスを拒否します。
そのため、Allow IfのACLは評価されないままアクセスが拒否されます。
# | Deny-Unlessの拒否パターン | ロール | レコードの条件 | スクリプト |
---|---|---|---|---|
①-1 | ロールで拒否 | × | ー | ー |
①-2 | レコードの条件で拒否 | ー | × | ー |
①-3 | スクリプトで拒否(スクリプト内の条件はロール) | ー | ー | × |
①-4 | スクリプトで拒否(スクリプト内の条件はレコード) | ー | ー | × |
①-5 | 1~4のACL全てをアクティブ化した上で拒否 | × | × | × |
×:拒否
ロール、レコードの条件、スクリプトによる条件で拒否を行い、パフォーマンスを測定します。
スクリプト内の条件は、ロールとレコードで違いを測定するためにロールを判別するスクリプト、レコードの条件で判別するスクリプトを記述します。
また、1~4の全てをアクティブ化したときのパフォーマンスも測定してみます。
②Allow Ifで拒否

このパターンではAllow If ACLで許可を与えず、アクセスを拒否します。
# | Allow-If | ロール | レコード | スクリプト |
---|---|---|---|---|
②-1 | ロールで拒否 | × | ー | ー |
②-2 | レコードの条件で拒否 | ー | × | ー |
②-3 | スクリプトで拒否(スクリプト内の条件はロール) | ー | ー | × |
②-4 | スクリプトで拒否(スクリプト内の条件はレコード) | ー | ー | × |
②-5 | ②-1~4のACL全てをアクティブ化した上で拒否 | × | × | × |
×:拒否
「①Deny-Unlessでテーブル全体へのアクセスを拒否」のパターンと比べて、どのようなパフォーマンスの違いがあるかが②での主な検証ポイントとなります。
③Allow Ifで許可

次に③では、Allow If ACLでアクセス許可を与えます。
# | Allow Ifの許可パターン | ロール | レコード | スクリプト |
---|---|---|---|---|
③-1 | ロールで許可 | 〇 | ー | ー |
③-2 | レコードの条件で許可 | ー | 〇 | ー |
③-3 | スクリプトで許可(スクリプト内の条件はロール) | ー | ー | 〇 |
③-4 | スクリプトで許可(スクリプト内の条件はレコード) | ー | ー | 〇 |
③-5 | 1~4のACLを全てアクティブ化した上で許可 | 〇 | 〇 | 〇 |
ここではロールによる許可、レコードによる許可、スクリプトによる許可でどのようなパフォーマンスの違いがあるかを見ていきます。
また、スクリプトではロール、レコードの条件それぞれのパターンも検証します。
③-5では1~4のACL全てをアクティブ化した上でアクセスを許可し、パフォーマンスの測定を行います。

許可対象のレコードは30,000レコードのうち、100レコードとします。
④Deny-Unlessで一部のレコードを拒否した後、残りのレコードをAllow Ifで許可

④ではDeny-UnlessとAllow Ifを組み合わせてパフォーマンスの検証を行います。
Deny-Unless ACLはレコードの条件でアクセスを拒否します。
Deny Unlessの拒否パターン | ロール | レコードの条件 | スクリプト |
---|---|---|---|
レコードの条件で拒否 | ー | × | ー |
作成したAllow If ACLは③と同様のパターンです。
# | Allow Ifの許可パターン | ロール | レコードの条件 | スクリプト |
---|---|---|---|---|
④-1 | ロールで許可 | 〇 | ー | ー |
④-2 | レコードの条件で許可 | ー | 〇 | ー |
④-3 | スクリプトで許可(スクリプト内の条件はロール) | ー | ー | 〇 |
④-4 | スクリプトで許可(スクリプト内の条件はレコード) | ー | ー | 〇 |
④-5 | 1~4のACLを全てアクティブ化した上で許可 | 〇 | 〇 | 〇 |
Deny-Unless ACLで29,900レコードのアクセスを拒否し、Allow Ifの評価対象を100レコードのみに絞ることで、「③Allow Ifで許可」と比較して、パフォーマンスの向上を期待しています。

検証結果

それでは各パターンの検証結果を紹介します。
検証結果:①Deny-Unlessでテーブル全体へのアクセスを拒否
# | Deny-Unlessの拒否パターン | サーバー処理時間 | トランザクション数 |
---|---|---|---|
①-1 | ロールで拒否 | 305ms | 5 |
①-2 | レコードの条件で拒否 | 901ms | 268 |
①-3 | スクリプトで拒否(スクリプト内の条件はロール) | 725ms | 268 |
①-4 | スクリプトで拒否(スクリプト内の条件はレコード) | 852ms | 268 |
①-5 | 1~4のACL全てをアクティブ化した上で拒否 | 254ms | 5 |
結果としては「①-5:1~4のACL全てをアクティブ化した上で拒否」のパフォーマンスが最もよかったですが、これはロールが優先的に評価され、レコードの条件、スクリプトが評価されなかったためだと思われます。
そのため、①-1とは誤差があるものの、まずはロールでDeny-Unlessを設定した方がパフォーマンス上良さそうです。
スクリプトよりレコードの条件で拒否した方がサーバー処理時間が多くかかっていたのは意外な結果でした。
検証結果:②Allow Ifで拒否
# | Allow-If | サーバー処理時間 | トランザクション数 |
---|---|---|---|
②-1 | ロールで拒否 | 253ms | 5 |
②-2 | レコードの条件で拒否 | 274ms | 10 |
②-3 | スクリプトで拒否(スクリプト内の条件はロール) | 508ms | 268 |
②-4 | スクリプトで拒否(スクリプト内の条件はレコード) | 530ms | 268 |
②-5 | ②-1~4のACL全てをアクティブ化した上で拒否 | 690ms | 268 |
こちらの検証結果としては、「②-1:ロールで拒否」したパターンが最もサーバー処理時間が短く、トランザクション数も少なかったです。
一方で「②-5:1~4のACL全てをアクティブ化した上で拒否」のパターンが最もパフォーマンスが悪かったですが、こちらはDeny-UnlessのACLとは異なり、1~4の全てのACLが評価された上でアクセスが拒否されたためだと考えられます。
そのため、Allow IfのACLが増えれば増えるほど、評価対象のACLが増えていくためパフォーマンスは悪化していくと予想されます。

適切にDeny-Unless ACLを設定することで、無駄なAllow If ACLの評価を減らし、パフォーマンスを向上できる可能性はありそうですね。
ただ、①ではレコードの条件が最も時間がかかっており、トランザクション数も268だったのに対し、②ではレコードの条件はサーバー処理時間も短く、トランザクション数も10と少なかった理由は良く分からず、引き続き調査が必要です。
検証結果:③Allow Ifで許可
# | Allow Ifの許可パターン | サーバー処理時間 | トランザクション数 |
---|---|---|---|
③-1 | ロールで許可 | 1199ms | 452 |
③-2 | レコードの条件で許可 | 1157ms | 434 |
③-3 | スクリプトで許可(スクリプト内の条件はロール) | 1172ms | 452 |
③-4 | スクリプトで許可(スクリプト内の条件はレコード) | 959ms | 434 |
③-5 | 1~4のACLを全てアクティブ化した上で許可 | 1812ms | 452 |
こちらは意外な結果が出ました。
なんとロールで許可するパターンよりも、レコードを条件としたスクリプトを記述したパターンが最もパフォーマンスが良かったです。
ただ、こちらは全てのケースに当てはまる訳ではなく、スクリプトの処理内容に依存することは言うまでもありません。
また、「③-5:1~4のACLを全てアクティブ化した上で許可」が一番パフォーマンスが悪かったことは想定通りで、1~4のACL全てが評価された結果だと考えられます。

当たり前ですが、パフォーマンスのことを考えるとACLはなるべくシンプルにしないといけませんね。
検証結果:④Deny-Unlessで一部のレコードを拒否した後、残りのレコードをAllow Ifで許可
# | Allow Ifの許可パターン | サーバー処理時間 | トランザクション数 |
---|---|---|---|
④-1 | ロールで許可 | 1536ms | 434 |
④-2 | レコードの条件で許可 | 1028ms | 434 |
④-3 | スクリプトで許可(スクリプト内の条件はロール) | 1188ms | 434 |
④-4 | スクリプトで許可(スクリプト内の条件はレコード) | 965ms | 434 |
④-5 | 1~4のACLを全てアクティブ化した上で許可 | 1664ms | 434 |
Deny-Unless ACLであらかじめ30,000レコードのうち、29,900レコードのアクセスを拒否することで、後続のAllow If ACLのパフォーマンスが向上できるのではと予想していましたが、③の結果と比べて大きな差は見られませんでした。
Deny-Unlessでアクセスが拒否されたものの、Allow IfのACL自体は評価されているためだと考えられます。
検証結果のまとめ
Deny-Unlessでのアクセス拒否、Allow Ifのアクセス許可はともにロールで判別する方がパフォーマンス上優位…..のはずでしたが場合によってはレコードの条件、スクリプトによる条件の方が良いケースもあるようです。
ただ、かの有名なChuck Tomasi氏は、ロールが一番最初に評価され、かつキャッシュされるため可能な限りロールをACLの条件に利用するのが常に効率的とコメントしています。

ServiceNow Communityより引用
(https://www.servicenow.com/community/grc-forum/order-of-execution-of-an-acl/m-p/1311960)
また、Allow If ACLは増えれば増えるほど評価されるACLも増えていくため、予めテーブルに対するアクセスが拒否されるユーザーが明確な場合は、Deny-Unlessで最初にアクセスを拒否することで、Allow If ACLの評価もされず、パフォーマンスの向上も見込めそうです。

色々検証してみたものの….ACLのパフォーマンスに関する公式情報をServiceNow社には出してほしいというのが正直な感想です。
おまけ
ちなみに遅いACLはシステムログに出力されます。

コメント