3

我目前正在考虑在 PlayFramework 项目中使用 Cassandra 作为我的数据库。我一直在寻找响应式驱动程序,看来我的选择仅限于 Phantom 和 Quill。我在 nosql 数据库方面的经验仅限于 MongoDB,而且我之前没有使用过任何 Quill 或 Phantom。

看看这里的比较,似乎最终可能会在 Phantom 中编写更多代码。此外,使用 DSL 来描述模型似乎违反直觉(来自沉重的 hibernate/JPA 背景)——但这可能就是我。

我想知道是否有人可以提供实用的建议/用例,其中一个会优于另一个以及每个需要注意的事项?

4

2 回答 2

10

作为 phantom 的作者,以一个略带偏见的观点来看,我对 phantom 的设计目标有很强的把握。Quill 图书馆网站上有一个现有的 Quill 和 Phantom 之间的比较,这自然偏向另一个方向。

Phantom 旨在成为应用程序层的完美选择,而 Quill 旨在成为最精美的字符串生成器,当您在 Cassandra 之上构建大型应用程序时,这不是一个非常有用的比较。

使用幻影的优点

  • 关于类型安全以及 DSL 对 Cassandra 功能的改进程度,确实没有什么可比拟的。DSL 对您的数据结构有非常“深入”的了解,并为 Cassandra 功能提供完整的支持。它在编译时就知道 Cassandra 什么是可能的,什么不是。

  • Quill 开发人员认为 phantom 有更多的依赖项,但这并不完全准确,因为其中大多数是可选的,包括 Play iteratees 和流支持之类的东西。不想要的就得不到,就这么简单。

  • Quill 比较简单地说:“您可以通过扩展 DSL 来扩展 Phantom 以添加新功能,尽管这可能不是一个简单的过程。”,这有点不准确。作为游戏中的新手,Quill 在 Cassandra 功能支持方面是一个玩具,您经常会发现自己需要添加功能。毫无疑问,Phantom 有其差距,但它是一个成熟得多的替代方案,并且需要扩展的次数要少得多。

  • 对于更复杂的功能,我们已经在几天或几周内解决了大多数错误,但通常您可能需要的一切都已经存在,目前在 Quill 中找不到许多功能,甚至需要我几个小时才能写下来。

  • 我不是来自强大的 JPA 背景,但 Cassandra 和 phantom 之间的映射是一个非常强大的层,因为它允许您直接从映射 DSL 自动生成表的整个模式。它还允许 DSL 在编译时完全模仿 Cassandra 的行为,它会知道关于您选择的主键等哪些查询是可能的,quill 根本没有这样的支持。

  • Phantom 具有非常强大的应用程序级抽象层,例如连接器、数据库、数据库的自动生成,以及帮助您将应用程序运行到生产中的东西。

  • Quill 背后的代码要复杂得多,虽然我会是第一个对它背后的工程能力给予高度评价的人,但当我认为用户友好时,这个故事并不能成立。

  • 奎尔试图一口气做更多的事情。它是一个用于生成的迷你引擎,几年前 scalaquery 尝试做的事情是在他们决定完全专注于 SQL dbs 并放弃对其他任何东西的支持之前。它是现代 Slick 的前身,并使用类似的 QDSL 引用方法。

  • Quill 是一个泄漏的抽象。由于它们旨在支持更广泛的数据库,因此它们对数据库细节的特殊性的支持要差得多。下面是一个例子:

从您阅读的比较中非常基本的示例中:

val getAllByCountry = quote {
  (country: String) => query[WeatherStation]
     .filter(_.country == country)
  }
}

到目前为止一切都很好,如果我们包含必要的映射代码,可能比幻影等价物更简洁。

select.where(_.country eqs country).fetch()

但让我们进一步探索。如果你想获取一个这样的国家怎么办?或者,如果您试图获取PagingState信息怎么办?或者输入现有PagingState内容以在 UI 上显示内容。

这就是 Quill 至少在比较中未能为用户提供任何关于他们最终体验的真实预览的地方。很自然地假设,每当您访问某个工具的页面时,它都会将自己描述为该类别中最好的工具,正如我们在 phantom 背后所做的那样,但这绝不是完整的故事。

为了更简洁,一些更酷的东西:

select.where(_.country eqs country).fetchRecord()
select.where(_.country eqs country).one()

部分选择呢?

select(_.country, _.city).where(_.country eqs country)

Phantom 在语义上区分了使用 Cassandra 在运行时可能发生的所有事情,它首先尝试使用编译时技巧和领域知识来防止运行时错误。你怎么能有 Quill 等价物?

此外,Quill 完全能够直接从case class.

  case class WeatherStation(
    country: String,
    city: String,
    stationId: String,
    entry: Int,
    value: Int
  )

  object WeatherStation {

    val getAllByCountry = quote {
      (country: String) =>
        query[WeatherStation].filter(_.country == country)
    }

    val getAllByCountryAndCity = quote {
      (country: String, city: String) =>
        getAllByCountry(country).filter(_.city == city)
    }

    val getAllByCountryCityAndId = quote {
      (country: String, city: String, stationId: String) =>
        getAllByCountryAndCity(country, city).filter(_.stationId == stationId)
    }
  }

但它缺乏任何关于你的模式的知识。如果国家不是主要的一部分怎么办?该查询无效,幻影不会让您编译它,这只是最基本的示例。

Phantom 可以直接从表中自动生成 CQL,它可以动态生成整个数据库,专业版甚至可以自动迁移表并帮助您处理模式不一致,并为您提供非常先进的 UI 和监控界面,您可以在其中可以即时升级和降级模式。

缺点

  • Phantom 确实确实让扩展之类的东西稍微不那么冗长了TypeCodec,但是从 phantom 2.9.0 开始,我们引入了一个非常强大的宏机制来编码 Cassandra 中的类型,它根本不依赖TypeCodec

  • Phantom 需要围绕定义表 DSL 的最少样板,并且本质上不能很好地用于共享表列。可以做到,但不是最漂亮的代码,也不是最差的。

总体

  • Quill 是一款非常棒的软件,由非常有才华的人编写,对此毫无疑问。
  • 严格来说,它比 phantom 在查询生成方面要好,如果我们要与谁是最精简最卑鄙的字符串生成器 Quill 获胜,则可以通过 QDSL 减少无法通过 EDSL 减少的样板。
    • 它在应用层是一个非常低劣的工具,对大多数人来说更不自然。Slick 在一定程度上普及了这些概念,但是您希望作为应用程序生命周期一部分的一些最基本的功能无法通过 QDSL 轻松实现,或者至少尚未实现。
    • Phantom 更加成熟,被广泛采用,拥有更多的资源和创始团队的投入,长期的路线图以及与 Datastax 的重要合作伙伴关系,帮助我们掌握所有功能。
于 2016-06-21T15:26:39.190 回答
0

我们从 Quill 开始,然后因为 Phantom 的功能和易于更改而选择了 Phantom。但是我们在负载测试中遇到了严重的问题,发现它没有释放 CPU 线程和网络连接。我们在我的本地 mac 机器以及 AMI Linux 服务器的 AWS EC2-Cluster 上进行了测试。本质上,资源没有被释放,并且会出现内存不足的异常。如果这个问题得到解决,Phantom 会很棒。就目前而言,我不能向任何拥有需要高性能的生产系统的人推荐使用 Phantom。

在生产的最后一刻,我们不得不更改所有代码并切换回 Quill,这对我来说很痛苦。

我已经打开了 Phantom 的问题,希望他们能尽快解决这个问题。随附的是一个项目,它通过并行运行一个简单的 JSON/REST scala 项目来测试 Quill 和 Phantom 之间的负载。

https://github.com/yleun/cassandra-loadtest

如果 Phantom 可以修复这个 Out-of-Memory 异常,它可能会是一个优于 Quill 的数据库客户端,但就目前而言,它还没有准备好生产,我希望其他人在花费大量时间后不会遇到我的问题使用 Phantom 构建。

于 2017-06-10T00:40:26.563 回答