Java驱动提供了各种设置选项,在开始使用时我们需要知道哪些一般准则和最佳实践能帮我们轻松构建一个在生产环境中有复原力的、实时的且高性能的应用呢?
基于大量和您类似的Datastax客户和Cassandra企业用户所累积的经验,本文将介绍大部分应用程序会遇到的一般情况。
由于篇幅原因,请前往DataStax官方技术博客查看完整文章,获取更多技术细节和示例代码。
01 引言
在本文开始前,我们默认您已经对这些内容有所了解:客户端与服务端架构的应用程序、Cassandra基础,还有Datastax Java驱动的主要元素,例如Sessions(会话)、Statements(语句)、Results sets(结果集)、Rows(行)。
本文介绍的最佳实践的方法也可以运用到其它的开发语言中(及其关联的DataStax驱动),但是在本文中我们将会专注于Java驱动。我们将最佳实践的方法分为四部分:总体指导、建立连接、查询语句和查询结果。
02 最佳实践:总体指导
当今最佳的实践方法是使用最新的DataStax Java驱动,即版本4.x。虽然3.x版本的驱动仍然可用,且在必要情况下依然是个不错的选择,本文会把重点放在4.x的驱动。
使用您正在使用的Datastax Java驱动主要版本(比如4.x)中最新的细分版本(比如截止2020年8月,4.x中的4.9.0或3.x中的3.10.0)。
在多数据中心部署的情况下,我们建议一个应用实例仅与单独一个数据中心挂钩使用。每一个应用都应将驱动程序连接到每一个当地的数据中心(如下图所示),并且应使用Global Load Balancer(全局负载平衡器)在多个应用实例中引导流量。
使用与数据库查询有关的指标来对应用程序进行监测。这个会非常有助于测试应用程序的查询性能。在默认情况下所有的指标收集功能都是处于禁用状态。如果您需要它们,您需要在建立连接的时候启用。
03 最佳实践:建立连接
用于建立与Cassandra的连接的CqlSession对象,可以通过很多不同的方式进行配置,包括通过配置文件或者编程方式建立连接——我们建议使用配置文件。当我们与Cassandra创建连接时,以下是一些最重要的考虑因素。
- 请使用单独的CqlSession:一个应用程序只使用一个单独的CqlSession对象来连接到数据库。
- 在application.conf里设定选项:将所有非默认的选项在jar包里的application.conf文件中进行定义。
- 遵循您安全性的最佳做法,同时使用适当的身份验证和SSL选项。
- 在创建连接的时使用多个接触点(Contact Points)。这样的话,您的应用即使在单个(或多个节点)脱机时仍可与数据库建立连接。
- 只提供一个数据中心的接触点,这个数据中心会被设为本地的数据中心(如下所示)。
- 使用默认的负载平衡策略:当建立连接时,使用默认参数DefaultLoadBalancingPolicy。此负载平衡策略会更有效且相对平衡地调用节点进行查询。
- 当建立连接时,显式地指定使用本地的数据中心。
- 显式地将一致性级别设定为LOCAL_QUORUM并将默认串行一致性设为LOCAL_SERIAL。不然,默认的一致性是LOCAL_ONE,默认串行一致性级别为SERIAL,这些通常都不建议使用。
- 不要将默认查询幂等性设置为true。其默认值为false,请保留它。设置为true很危险,因为一些操作是通过幂等查询自动完成的,但事实上不是所有操作都是幂等的。因此,请针对每次查询显式明确地设置幂等查询操作。
- 请在advanced.metrics中启用合适的指标,从而启用指标收集功能。因为没有一个“启用所有指标”的选项,您必须明确指出您需要启动的每一个指标。
04 最佳实践:查询语句
Cassandra的查询会先创建一个Statement对象,再通过CqlSession对象执行。以下有很多种Statement种类:
- 简易语句(SimpleStatement): 由CQL字符串或查询生成器(Query Builder)创建。
- 参数化查询语句(PreparedStatement): 可以在构建一次后被重复使用多次的语句,对于有不同参数的常见查询而言,此种语句具有实用、高性能且更安全的优势。
- 绑定语句(BoundStatement): 用于对PrepareStatement查询的单次调用,并允许用户绑定只适用于此次调用的参数。
- 批处理语句(BatchStatement): 封装多个简易语句或者绑定语句,并批量执行。
当执行查询语句时,这里有一些需要注意的重要事项:
- 请注意在DataStax Java驱动程序4.x的版本中,所有的Statements都是不可变的(immutable)。因此如果想要重新设置Statement的选项的话,您必须为这个值重新分配一个引用。
- 避免以编程方式发出DDL语句,除非可以确保它们不会被应用程序中的多个实例并发执行。
- 不要将CQL作为字符串执行(如通过CqlSession#execute(String)),而是为CQL字符串创建一个Simple Statement以便设置Statement的选项,如一致性级别或者幂等性。
- 通过CqlSession#prepare()准备所有可以重复使用的语句。
- 如果一个CQL查询确实是幂等的,请通过Statement#setIdempotent()来设置幂等的选项。这是为了能够自动重复执行陈述语句(如:自动重试或者推测执行)。作为安全预防措施,驱动程序不会自动重新处理任何幂等设置为false(否)的语句。
- 谨慎使用Batch Statement(批处理语句),因为Cassandra集群的协调节点(coordinator)负责在内部处理这些查询,发出多个查询会增加协调节点的负荷。
- 我们应该避免Light weight transactions(轻量级事务),因为它们的性能相较于一般操作会慢很多。一般情况下,会有其它可以避免Light weight transactions的方式来建构应用程序。总之,轻量级事务的存在是有原因的,但请合理使用。
05 最佳实践:查询结果
根据查询被执行的方式,查询结果会通过以下几种方式被返回:
- Synchronous execution(同步执行):返回一个可以被同步处理的ResultSet
- Asynchronous execution(异步执行):返回一个可以通过CompletionStage API 异步处理查询的CompletionStage<AsyncResultSet>。
- Reactive execution(响应式执行):返回一个ReactiveResultSet,它可以通过Reactive Labraries (响应库)以响应式的方法处理结果。
最常见的处理方式排列序可能为Synchronous > Reactive > Asynchronous。
以下是一些处理查询结果的最佳实践方法:
- 养成在CQL查询中指定所有需要被返回的列的习惯。比如但凡可以请避免使用 "SELECT * FROM …"这样的查询语句。如果表的结构将来发生变化的话,这样做会有帮助。
- 像其它数据库一样,请注意像“SELECT * FROM ks.tbl”这样的简单语句会返回数据库中的所有数据。Cassandra是为储存海量数据而设计的,这种请求很可能会返回一个含有巨量数据的结果。尽管有时候确实需要进行全表扫描,但也请尽量避免这种情况。
- 当处理多个语句时,利用异步执行(asynchronous execution)同时处理多条查询。
- 对于INSERT、UPDATE或DELETE的操作,请确保捕获异常以确保操作成功。
- 一般情况下,使用驱动程序默认的分页方法,这种方法在一页读取完毕时将自动获取下一页。
- 避免调用 ResultSet#all(),因为这会将所有结果导入一个在内存中的列表(List),这样会影响性能或产生内存错误
06 总结
本文包含了许多适应大多数用例且最常见的最佳实践。但是在某些情况下,使用其它不同的设置或方法也许确实是得当的,所以这篇文章应该只作为一个起点。
我们建议可以从这些设置和实践中入手,开始建立一个可用的应用程序。如果您发现应用程序没有如预期一样运行,可以考虑参考DataStax Java驱动程序文章(或者其它资源)来微调您的设置。
有了这些最佳实践作为您的起点,您正走在通往顺利搭建以Cassandra作为后台的应用程序的光明大道上。请享受这个过程吧!
阅读完整文章,请访问DataStax技术博客:
使用DataStax Java驱动程序的最佳实践www.cnblogs.com