SLAをメールでレポート(ZabbixのITサービスの活用)

システム運用していて、SLA管理のためにサービスレベルを定期的にレポートしたい場合もあるかと思います。
ZabbixにはITサービス機能があり、サービスの稼働率を算出することができます。

例えば次のような形で設定できます。

  • サービスAとサービスBの監視をZabbixで監視
  • サービスAはWebサーバ3台、DBサーバ2台で構成
  • サービスBはWebサーバ2台、DBサーバ2台、認証サーバ2台で構成
  • サービスAが稼働継続するには少なくともWebサーバ、DBサーバが1台以上稼働している必要がある
  • サービスBが稼働継続するには少なくともWebサーバ、DBサーバ、認証サーバが1台以上稼働している必要がある

このような環境があった場合にそれぞれのサーバの稼働率からサービス自体の稼働率を算出することができます。

ZabbixのITサービスの機能を使うことで次のようにできます。
設定は「設定」→「ITサービス」から実行します。

ルートの子としてサービスA、サービスBを登録します。
この時、ステータス計算アルゴリズムとして「子に一つでも障害があった場合に検知」を選択。

サービスAの子としてWeb、DBを、サービスBの子としてWeb、DB、認証を登録します。
この時、ステータス計算アルゴリズムとして「すべての子に障害があった場合に検知」を選択。

最後にWeb、DB、認証の各子として実際のサーバの台数分登録します。
この時、サービスレベルを算出する元となる死活監視のトリガー条件を各子に設定します。

設定ができると、「監視データ」→「ITサービス」の欄で稼働状況が確認できます。

SLAの算出期間は

  • 今日
  • 今週
  • 今月
  • 今年
  • 最新24時間
  • 最新7日
  • 最新30日
  • 最新365日

から選択できます。


このようにブラウザの画面を見ることでSLAを確認することができますが、
エクスポートの機能などは今のところ搭載されてはいません。

Zabbix APIを使ってITサービス情報を取得

毎回画面を見ないでもITサービス情報をレポート通知をする仕組みを考えてみます。

ITサービスの情報は、Zabbix APIを使うことで取得することができます。
そこで、Zabbix APIを利用してSLAの情報を取得してみます。

ITサービスの情報取得には次の2つのメソッドを利用します。

service.get
service.getSla

ITサービス基本情報の取得

ITサービスの基本情報はservice.getメソッドを利用して取得します。
パラメータとしては次のようなものが設定できます。

  • parentids
  • childids
  • countOutput
  • selectParent
  • selectDependencies
  • selectParentDependencies
  • selectTimes
  • selectAlarms
  • selectTrigger
  • sortfield
  • sortorder
  • output

例えば、serviceの詳細情報を親のIDも含めて取得したい場合はパラメータを次のようにします。
"params":{"selectParent":"refer","output":"extend"}

次のような値が取得できます。

{"jsonrpc":"2.0","result":[
    {
         "serviceid":"1",
          "name":"Service A",
          "status":"0",
          "algorithm":"1",
          "triggerid":"0",
          "showsla":"1",
          "goodsla":"99.9000",
          "sortorder":"0",
          "parent":[]
    },
    {
          "serviceid":"2",
          "name":"Web",
          "status":"0",
          "algorithm":"2",
          "triggerid":"0",
          "showsla":"1",
          "goodsla":"99.9000",
          "sortorder":"0",
          "parent":{
                               "serviceid":"1"
                           }
    },
・・・略
SLA情報の取得

次に、SLAの情報を取得します。
SLAの取得にはservice.getSlaメソッドを利用します。
パラメータは次のような形で設定。
"params":{"serviceids":[1,2],"intervals":{"from":"1356966000","to":"1359558000"}}

これは、サービスID1,2のSLAを2013/01/01 00:00〜2013/01/31 00:00の期間で算出する例です。

取得できる値は次のような形式です。

{"jsonrpc":"2.0","result":{
      "1":{
               "status":"0",
               "problems":,
               "sla":[{
                           "from":"1356966000",
                           "to":"1359558000",
                           "sla":98.406404320988,
                           "okTime":2550694,
                           "problemTime":41306,
                           "downtimeTime":0
                          }]
              },
      "2":{
               "status":"0",
               "problems":,
               "sla":[{
                           "from":"1356966000",
                           "to":"1359558000",
                           "sla":98.406404320988,
                           "okTime":2550694,
                           "problemTime":41306,
                           "downtimeTime":0
                         }]
               }
},"id":1}

SLA出力スクリプト

このservice.*のAPIを利用してSLAを外部に出力するためのスクリプトを作成します。

it_service_report.rb

#!/bin/env ruby

require 'rubygems'
require 'zbxapi'

ZABBIX_API_URL = 'http://Zabbixサーバホスト名/zabbix/api_jsonrpc.php'
ZABBIX_LOGINID = 'Zabbixサーバへのログインユーザ名'
ZABBIX_PASSWORD = 'Zabbixサーバへのログインパスワード'
TO = Time.now
case ARGV[0]
when "1day" then
    FROM = TO - 86400
when "1week" then
    FROM = TO - 604800
when "1month" then
    FROM = TO - 2592000
when "1year" then
    FROM = TO - 31536000
else
    puts "Argument Error!:Please input output term(ex. 1day,1week,1month,1year)"
    exit(0)
end

zbxapi = ZabbixAPI.new(ZABBIX_API_URL)
zbxapi.login(ZABBIX_LOGINID,ZABBIX_PASSWORD)

## Get IT Service list
$services = zbxapi.raw_api("service.get", {:selectParent => "refer",:output => "extend"})

serviceids = []
$services.each do |service|
    serviceids << service['serviceid']
end

## Get SLA info
slas = zbxapi.raw_api("service.getSla", {:output => "name",:serviceids => serviceids, :intervals => {:from => FROM, :to => TO}})

$services.each do |service|
    slas.each do |sla|
        if sla.first == service['serviceid']
            service['sla'] = sla[1]['sla'][0]['sla']
        end
    end
end

## Pickup Parent Service
parents = $services.find_all do |service|
    service['parent'].empty?
end

## Search Child
def check_child(parents,level)
    parents.each do |parent|
        $output_data << {:level => level, :service => parent}
        childs = $services.find_all do |service|
            !service['parent'].empty? && service['parent']['serviceid'] == parent['serviceid']
        end
        if childs
            check_child(childs,level+1)
        end
    end
end

$output_data = []
level = 0

check_child(parents,level)

## Print Out
puts "[Calculation Term]From:#{Time.at(FROM.to_i)} - To:#{Time.at(TO.to_i)}"
$output_data.each do |line|
    puts "     "*line[:level] + "[ #{line[:service]['name']} ] SLA => #{line[:service]['sla']}"
end

実行すると次のようにSLA情報が出力されます。

$ ruby it_service_report.rb 1month
[Calculation Term]From:Sat Jan 05 11:14:02 +0000 2013 - To:Mon Feb 04 11:14:02 +0000 2013
[ Service A ] SLA => 100
     [ Web ] SLA => 100
          [ Web Server 1 ] SLA => 100
          [ Web Server 2 ] SLA => 100
          [ Web Server 3 ] SLA => 100
     [ DB ] SLA => 100
          [ DB Server 1 ] SLA => 100
          [ DB Server 2 ] SLA => 100
[ Service B ] SLA => 100
     [ Web Server ] SLA => 100

あとは、この出力結果をメールで飛ばせるよう仕組みを作ればOKです。

ITサービスのAPIを利用することのメリットとしては、SLAを算出する期間を自由に設定できる点です。
Zabbixの管理画面からでは固定された期間でのSLAしか取得できませんが、APIを利用することでFromとToの時刻が指定できるので、使い所があるかもしれません。