Cinder 調試 - cinder service 狀態為 down


1. 問題

我們經常會發現某個cinder service 的狀態為 down。比如下面例子中 controller 上的 cinder-scheduler 和 block1 節點上 cinder-volume 的狀態都為 down。

s1@controller:~$ cinder service-list

+------------------+---------------------------+------+---------+-------+----------------------------+-----------------+
| Binary | Host | Zone | Status | State | Updated_at | Disabled Reason |
+------------------+---------------------------+------+---------+-------+----------------------------+-----------------+
| cinder-backup | controller | nova | enabled | up | 2015-03-30T00:53:32.000000 | None |
| cinder-scheduler | controller | nova | enabled | down | 2015-03-30T00:51:53.000000 | None |
| cinder-volume | block1 | nova | enabled | down | 2015-03-30T00:54:43.000000 | None |
| cinder-volume | block2@lvmdriver-b21 | az1 | enabled | up | 2015-03-30T00:54:14.000000 | None |
| cinder-volume | block2@lvmdriver-b22 | az1 | enabled | up | 2015-03-30T00:54:13.000000 | None |
| cinder-volume | network@lvmdriver-network | nova | enabled | up | 2015-03-30T00:54:08.000000 | None |
+------------------+---------------------------+------+---------+-------+----------------------------+-----------------+

先來看看 cinder-list 的實現代碼:

class ServiceController(wsgi.Controller):
    @wsgi.serializers(xml=ServicesIndexTemplate)
    def index(self, req):
        """Return a list of all running services.
        Filter by host & service name.
        """
        context = req.environ['cinder.context']
        authorize(context)
        detailed = self.ext_mgr.is_loaded('os-extended-services')
        now = timeutils.utcnow() //獲取controller 當前的時間
        services = db.service_get_all(context) //從 db 獲取所有的 cinder service 列表
        ...
        svcs = []
        for svc in services: //輪詢每個 service
            delta = now - (svc['updated_at'] or svc['created_at']) //獲取 updated_at。不存在的話,獲取 created_at,並和當前時間計算時間差
            alive = abs(utils.total_seconds(delta)) <= CONF.service_down_time //獲取時間差值的絕對值,並檢查是否小於配置的 server_down_time,該配置項默認是60秒
            art = (alive and "up") or "down" //如果差值小於60,則service 狀態為 up,否則為 down
            active = 'enabled'
            ......
            svcs.append(ret_fields)
        return {'services': svcs}

可見 service 的 up/down 狀態取決於數據庫中 service 表對應某 service 的行的 updated_at 列的值和當前 controller 節點的時間的差值是否在配置的范圍之內

2. Cinder Service 的 update_at 值更新機制 

cinder 的各種service,比如cinder-api,cinder-backup 等,都是 /cinder/service.py 文件中 class Service(service.Service) 的一個實例,該類的 start 方法如下:

def start(self):
        version_string = version.version_string()
        LOG.info(_('Starting %(topic)s node (version %(version_string)s)'),
                 {'topic': self.topic, 'version_string': version_string})
        ...if self.report_interval: //如果設置了 report_interval 配置項,那么該 service 將啟動一個無限循環來執行 report_state 方法,運行間隔就是 report_interval,其默認值是 10 秒
            pulse = loopingcall.FixedIntervalLoopingCall(
                self.report_state)
            pulse.start(interval=self.report_interval,
                        initial_delay=self.report_interval)
            self.timers.append(pulse)
report_state 方法會更新 db 中serive 的各個屬性,其中 updated_at 的值就是所在節點上執行一次該方法的時刻。
def report_state(self):
        """Update the state of this service in the datastore."""
        ctxt = context.get_admin_context()
        zone = CONF.storage_availability_zone
        state_catalog = {}
        try:
            ...
                service_ref = db.service_get(ctxt, self.service_id) // 獲取service 的 ref
            ...
            db.service_update(ctxt, self.service_id, state_catalog) //更新該 service             ...

3. 問題定位步驟

(1)看看是不是在 cinder.conf 中 report_interval 配置項的值是多少,如果超過了 service_down_time 配置項默認的 60 秒,那么該service 的狀態肯定就是 'down' 了。

(2)看 service 所在節點的時間,它的時間和 controller 節點的時間誤差必須在 [service_down_time - report_interval ] 之內,也就是在使用默認配置情況下,時間差必須在 50 秒之內。

(3)看看 service 的 log 文件中,確認 report_state  方法是不是都按時被調用了,不方便看的話,在代碼中加個注釋吧。比如:

2015-04-11 15:26:24.210 8517 DEBUG cinder.service [-] enter report_state .. report_state /usr/lib/python2.7/dist-packages/cinder/service.py:283

4. 問題解決

(1). 檢查 block1 的時間

發現 block1 的時間 和 controller 不同步。通過同步 block1 和 controller 的時間,block1 上的 cinder-volume 的狀態變為了 up。

(2). 檢查 cinder-scheduler service 的 updated_at

發現 cinder-scheduler 的 updated_at 是 2015-03-30 01:32:26, 而 controller 的當前時間是 2015-04-11 02:26:20。排除時間差因素,基本可以確定是該服務的時間上報出了問題。檢查 cinder-schedule 的log,發現因為 bug 該 service 真的down了。fix bug,然后重啟服務,其狀態變為 up。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM