我正在考虑将StatsD数据集添加到我的grails应用程序中,并查看现有的库和代码让我对什么是一个好的可扩展解决方案感到困惑。为了将问题放到上下文中,我正在开发一个在线游戏类型项目,我自然会监控用户与游戏引擎的交互,这些将自然地聚集在X用户将在窗口内执行交互的特定时刻一两秒,然后在10-20秒暂停后重复。
以下是我对今天可用选项的分析。
https://github.com/etsy/statsd/blob/master/examples/StatsdClient.java
“可能有效的最简单的东西”解决方案,我可以将这个类拉入我的项目并将一个单例实例作为一个spring bean实例化并直接使用它。但是在注意到grails-statsd插件创建了一个客户端实例池后,我开始想知道这种方法的可扩展性。
如果许多线程试图同时发送事件,doSend
方法可能会成为瓶颈,但据我所知,由于火灾和忘记性质发送UDP数据包时,这应该很快发生,避免了我们通常与网络连接相关的巨大开销。
https://github.com/charliek/grails-statsd/
有人已经为grails创建了一个StatsD插件,其中包含一些不错的功能,例如注释和withTimer
方法。但是我发现那里的实现缺少示例实现中的一些错误修复,例如在调用String.format
时指定语言环境。当标准执行者可以达到类似的效果时,我也不是为了吸引apache commons-pool的狂热粉丝。
https://github.com/tim-group/java-statsd-client/
这是一个替代的纯Java库,它通过维护自己的ExecutorService来异步操作。它支持整个StatsD API,包括集合和抽样,但不提供任何用于配置线程池和队列大小的挂钩。在出现问题的情况下,对于非关键的事情,例如监控,我认为我更喜欢有限的队列和丢失事件,而不是有一个填满我的堆的无限队列。
https://github.com/vznet/play-statsd/
现在我无法在我的grails项目中直接使用此代码,但我认为值得一看,看看事情是如何实现的。一般来说,我喜欢StatsdClient.scala
中的代码构建方式,非常干净和可读。似乎也有区域设置错误,但其他功能完整与etsy示例。有趣的是,除非有一些我不理解的scala魔法,否则这似乎会为发送到StatsD的每个数据点创建一个新的套接字。虽然这种方法很好地避免了对象池或执行程序线程的必要性,但我无法想象它的效率非常高,可能会在请求线程中执行DNS查找,并尽快返回给用户。
到目前为止,看起来最好的现有解决方案是grails插件,只要我能接受公共池依赖,但是现在我正在认真考虑周日编写我自己的版本,它结合了每个实现的最佳部分
答案 0 :(得分:9)
作为java-statsd-client的主要提交者,以及在制作中使用此库的人,我想尝试消除你对“拥有一个填满我的堆的无限队列”的恐惧。
我认为你通过对Etsy StatsD客户端示例的分析几乎把它钉在了“当你说”由于火灾和忘记发送UDP数据包的性质时,这应该很快发生,避免了我们通常与网络相关的巨大开销连接“。
我的理解是,当前实现java-statsd-client的方式,构建大型出站消息队列的约束是发送消息而忘记UDP数据包的速度。我不是这个领域的专家,但我不知道这可能阻止无限队列可能会产生的任何方式。
当您最初进行评估时,java-statsd-client存在许多未解决的问题(例如,区域设置/字符编码含糊不清,缺乏采样支持),但最近已经解决了这些问题。剩下的问题是是否存在填补堆的真正风险。我很想听到社群对这个问题的看法,如果共识是存在问题,我很乐意探讨在图书馆中引入限制队列。
答案 1 :(得分:1)
睡了一个星期后,我想我会继续使用现有的grails StatsD插件。这样做的理由是,尽管我可以使用Executor实现类似的效果来处理并发,但是不使用对象池,这仍然会被绑定到单个客户端/套接字实例,理论上相当明显应用程序中的瓶颈。因此,如果我还需要一个游泳池,我也可以使用其他人做过所有努力的工作:)
答案 2 :(得分:0)
我在搜索纯Java StatsD客户端时遇到了StatsD over SLF4J,并将其与Java StatsD Client进行了比较,您提到了这个问题。基于阅读来源,我想出了与问题有关的细分。
编辑:下表已针对java-statsd-client 3.0.1版进行了更新,其中已解决了许多原始问题。
| java-statsd-client | statsd-over-slf4j ——————————————————————————+————————————————————————+———————————————————— messages support sampling | yes | yes ——————————————————————————+————————————————————————+———————————————————— actual sampling performed | no, left to caller | yes, using java.util.Random ——————————————————————————+————————————————————————+———————————————————— nonblocking impl worker | single daemon thread | single daemon thread ——————————————————————————+————————————————————————+———————————————————— nonblocking impl queue | unbounded | caller-specified bound ——————————————————————————+————————————————————————+———————————————————— String.format locale | none* | Locale.US ——————————————————————————+————————————————————————+———————————————————— charset for message bytes | UTF-8** | default, can be overridden * no localisation is applied ** this is the charset that StatsD reads with