Atom feed of this document
  

 对象存储监控

Darrell Bishop的博客可以说明这些。

OpenStack 对象存储集群是一组跨多节点的多个守护进程协同工作,拥有多个不同的组件,用户必须清楚在集群内部发生了什么,追踪一些计量如CPU使用、负载、内存消耗、磁盘使用量和容量等等都是必要的,但还不够。

在每个服务器中不同的守护进程在做什么?是什么卷在节点8上做对象复制?会花费多久?有错误吗?如果有,什么时候发生的?

在如此一个复杂的系统中,用户可以使用很多合适的工具来回答这些问题,此节描述了一些。

 Swift Recon

中间件Swift Recon(请参阅http://swift.openstack.org/admin_guide.html#cluster-telemetry-and-monitoring) 提供了常见的机器状态,诸如平均负载,套接字状态,/proc/meminfo内容,等等,以及特定的Swift计量:

  • 每个ring文件的MD5值。

  • 最近的对象复制时间。

  • 统计隔离文件的每种类型:账户、容器、或对象。

  • 统计 磁盘上的"async_pendings" (容器更新延迟)

Swift Recon 时一个中间件,它安装在对象服务器的管道中,需要一个选项:一个本地的缓存目录。要追踪 async_pendings,您必需设置为每个对象服务器一个额外的 cron 任务。您通过发送 HTTP 请求直接访问对象服务器或使用 swift-recon 命令行客户端来访问数据均可。

有一些好的对象存储集群统计数据,但一般的服务器计量与现有的服务器监控系统重叠了。要获取指定 Swift 的计量数据到监控系统中,它们必需被修剪。Swift Recon 本质上时作为一个计量收集器的中间件。向计量提供数据到您统计系统的进程,如 collectdgmond,可能已经运行在存储节点上。所以,您可以选择与 Swift Recon 会话或直接收集计量数据。

 Swift-Informant

Florian Hines开发了Swift-Informant中间件 (请参阅 https://github.com/pandemicsyn/swift-informant)用来获取实时的对象存储客户端请求。其驻扎在代理服务的管道中,且在每个请求代理服务都会发送三个计量到statsD服务 (请参阅 http://codeascraft.etsy.com/2011/02/15/measure-anything-measure-everything/):

  • 计量的增长计数器类似于obj.GET.200cont.PUT.404

  • 用于计量的时间数据类似acct.GET.200obj.GET.200。[README中说计量会类似duration.acct.GET.200这样,但是我在代码中没有看到 duration。我不确定Etsy服务做了什么,但是StatsD服务会更改时间计量为五个衍生的计量,使用了新的附加段,所它是可以正常工作的。改变后的计量是这样 acct.GET.200.lower, acct.GET.200.upper, acct.GET.200.mean, acct.GET.200.upper_90, 以及 acct.GET.200.count]。

  • 计数器的增加会由字节传输到计量,如 tfer.obj.PUT.201

这对获取经历事件计量的服务客户端的质量和请求的服务器类型、命令和响应代码的各种排列的卷的感受是有好处的。Swift-informant 也不需要修改核心对象存储代码,因为它是以中间件实现的。但是,它会使您不了解集群传递给代理服务器的过程是如何工作的。如果一个存储节点的响应性降低了,您仅仅能看到一些请求是坏的,高延时或错误状态代码。您不会确切地知道为什么或哪里的请求出现问题。也许出现问题的容器服务器在一个好的节点上,但对象服务器在另一个性能不好的节点上。

 Statsdlog

Florian's Statsdlog 项目增加基于记录事件的 StatsD 计数器。类似于 Swift-informant,它也是非入侵性的,但 statsdlog 可以从所有对象存储的守护进程中追踪事件,而不仅仅是代理服务器。守护进程监听一个 syslog 消息的 UDP 流,当记录行匹配一个正则表达式时,StatsD 计数器会增加。计量名称会映射到正则表达式匹配 JSON 文件格式,允许灵活配置什么计量要从记录流中提取出来。

目前,只有第一个匹配正则表达式会触发 StatsD 计数器的增长,计数器总是由一增长的。无法让计数器由大于一的数目增长或发送实时数据到基于记录内容的 StatsD 中。工具可以扩展来为每一行和数据提取处理更多的计量,包括实时数据。但耦合仍然存在于记录文本格式和记录解析表达式之间,他们自己会变得更加复杂以为ie每一行和数据提取支持多匹配。并且,记录进程介绍了一个触发事件和发送数据给 StatsD 之间的延时。这将是最好的增量错误计数器,他们会发生并在知道要避免记录字符串和正则比阿大时解析之间的耦合是发送实时数据,防止事件和发送数据到 StatsD 之间的时间延时。

下一节描述了对象存储运维计量的两外一种方法。

 Swift StatsD 日志

StatsD (请阅读 http://codeascraft.etsy.com/2011/02/15/measure-anything-measure-everything/) 被设计为应用代码,以深入仪表;计量是由仅仅通知或做某些事情的代码实时发送的。发送一个计量的开销是非常低的:一个 UDP 包的 sendto。如果这个开销仍然太高,StatsD 客户端库可以仅仅发送一个样例的随机部分,且冲刷计量到上游时,StatsD 非常仅近于实际数值。

为了避免使用基于中间件的监控和事后日志处理的内部问题,StatsD 计量的发送被整合到对象存储本身中。提交修改设置 (详见 https://review.openstack.org/#change,6058) 当前通过 15 个对象存储守护进程和临时路径中间件报告 124 个计量。详细的计量方针在 Administrator's Guide 文档中。

计量的发送已与记录框架整合。要将它启用,请配置相关配置文件中的 log_statsd_host 字段。您也可以指定端口和一个默认的采样率。除非有一个特定的调用,指定的默认采样率才会被用于 statsd 记录方法 (见下表) 覆盖。目前,没有记录调用覆盖采样率,但可以想象的是,一些计量可能需要精度 (sample_rate == 1) 而其他的不需要。

[DEFAULT]
     ...
log_statsd_host = 127.0.0.1
log_statsd_port = 8125
log_statsd_default_sample_rate = 1

然后,由 get_logger() 返回的 LogAdapter 对象,通常保存在 self.logger,有了这些新的方法:

  • set_statsd_prefix(self, prefix) 设置客户端库 stat 的前缀值,它会获取前缀给每个计量。默认的前缀是记录者的名称,如 "object-server"、"container-auditor" 等。现在,当确定了控制器对象和示例化请求时,用于将 "proxy-server" 转换为 "proxy-server.Account"、"proxy-server.Container" 或 "proxy-server.Object"。

  • update_stats(self, metric, amount, sample_rate=1) 按照给定的数目增加所提供的计量。当您需要从计数器中添加或减去大于一的数目时,这将会使用到,例如以对象重复符中的计算哈希来增加 "suffix.hashes"。

  • increment(self, metric, sample_rate=1) 以一来增加给定的计数器。

  • decrement(self, metric, sample_rate=1) 以一减少给定的计数器。

  • timing(self, metric, timing_ms, sample_rate=1) 记录给定的计量采取了提供的毫秒数。

  • timing_since(self, metric, orig_time, sample_rate=1) 记录一个其值为 "now" 减去一个已有时间戳的实时计量的便捷方法。

请注意,这些记录方法可能会被任何您有记录者的对象安全调用。如果 StatsD 记录没有配置,这些方法是无操作的。这避免了每个地方记录一个计量的杂乱逻辑。这些示例的使用展示了新的记录方法:

# swift/obj/replicator.py
def update(self, job):
    # ...
    begin = time.time()
    try:
        hashed, local_hash = tpool.execute(tpooled_get_hashes, job['path'],
                do_listdir=(self.replication_count % 10) == 0,
                reclaim_age=self.reclaim_age)
        # See tpooled_get_hashes "Hack".
        if isinstance(hashed, BaseException):
            raise hashed
        self.suffix_hash += hashed
        self.logger.update_stats('suffix.hashes', hashed)
        # ...
    finally:
        self.partition_times.append(time.time() - begin)
        self.logger.timing_since('partition.update.timing', begin)
# swift/container/updater.py
def process_container(self, dbfile):
    # ...
    start_time = time.time()
    # ...
        for event in events:
            if 200 <= event.wait() < 300:
                successes += 1
            else:
                failures += 1
        if successes > failures:
            self.logger.increment('successes')
            # ...
        else:
            self.logger.increment('failures')
            # ...
        # Only track timing data for attempted updates:
        self.logger.timing_since('timing', start_time)
    else:
        self.logger.increment('no_changes')
        self.no_changes += 1

StatsD 的开发团队打算使用 pystatsd 客户端库 (不要与 Github 上的 similar-looking 项目 混淆),但在 PyPI 上发布的版本缺少两个 Github 上的最新版本所需要的特性:在客户端对象配置计量前缀的功能和一个发送实时数据到 "now" 和 "start" 的您已有时间戳之间的便捷方法。所以他们只使用同样的接口从中实现了一个简单的 StatsD 客户端库。这有良好的附加效益,不会引入另一个额外的依赖于对象存储的库。

Questions? Discuss on ask.openstack.org
Found an error? Report a bug against this page


loading table of contents...