当前位置:   article > 正文

Docker安装Cassandra数据库,在SpringBoot中连接Cassandra

连接cassandra

简介

Apache Cassandra是一个高度可扩展的高性能分布式数据库,旨在处理许多商用服务器上的大量数据,提供高可用性而没有单点故障。它是NoSQL数据库的一种。首先让我们了解一下NoSQL数据库的作用。

NoSQL 数据库

NoSQL数据库(有时称为“Not Only SQL”)是一种数据库,它提供了一种存储和检索关系数据库中使用的表格关系以外的数据的机制。这些数据库是无模式的,支持简单的复制,具有简单的API,最终是一致的,并且可以处理大量数据。

什么是Apache Cassandra?

Apache Cassandra是一个开源,分布式和分散/分布式存储系统(数据库),用于管理分布在世界各地的大量结构化数据。它提供高可用性服务,没有单点故障。

以下列出了Apache Cassandra的一些值得注意的地方-

  • 它具有可伸缩性,容错性和一致性。
  • 它是一个面向列的数据库。
  • 其分发设计基于亚马逊的Dynamo及其在Google的Bigtable上的数据模型。
  • 它创建于Facebook,与关系数据库管理系统截然不同。
  • Cassandra实现了Dynamo风格的复制模型,没有单点故障,但是添加了更强大的“column family”数据模型。
  • 一些大型公司(例如Facebook,Twitter,Cisco,Rackspace,ebay,Twitter,Netflix等)正在使用Cassandra。

特性:

弹性可扩展性 - Cassandra是高度可扩展的; 它允许添加更多的硬件以适应更多的客户和更多的数据根据要求。
始终基于架构 - Cassandra没有单点故障,它可以连续用于不能承担故障的关键业务应用程序。
快速线性性能 - Cassandra是线性可扩展性的,即它为你增加集群中的节点数量增加你的吞吐量。因此,保持一个快速的响应时间。
灵活的数据存储 - Cassandra适应所有可能的数据格式,包括:结构化,半结构化和非结构化。它可以根据您的需要动态地适应变化的数据结构。
便捷的数据分发 - 可以在多个数据中心之间复制数据,可以灵活地在需要时分发数据。
事务支持 - Cassandra支持属性,如原子性,一致性,隔离和持久性(ACID)。
快速写入 - Cassandra被设计为在廉价的商品硬件上运行。 它执行快速写入,并可以存储数百TB的数据,而不牺牲读取效率。

Cassandra特点

Cassandra由于其出色的技术特性而变得如此受欢迎。以下是Cassandra的一些功能:

  • 弹性可扩展性– Cassandra具有高度可扩展性;它允许添加更多硬件,以根据需求容纳更多客户和更多数据。
  • 始终在线-Cassandra没有单点故障,并且可以连续用于无法承受故障的关键业务应用程序。
  • 快速的线性规模性能-Cassandra具有线性可扩展性,即,随着集群中节点数量的增加,它可以提高吞吐量。因此,它保持了快速的响应时间。
  • 灵活的数据存储-Cassandra可容纳所有可能的数据格式,包括:结构化,半结构化和非结构化。它可以根据需要动态适应对数据结构的更改。
  • 轻松进行数据分发-Cassandra通过在多个数据中心之间复制数据,提供了在所需位置分发数据的灵活性。
  • 事务支持-Cassandra支持原子性,一致性,隔离性和持久性(ACID)等属性。
  • 快速写入-Cassandra旨在在廉价的商品硬件上运行。它执行快速的写入,并且可以存储数百TB的数据,而不会牺牲读取效率。

架构

Cassandra的设计目标是在多个节点上处理大数据工作负载而不会出现任何单点故障。 Cassandra在其节点之间具有对等分布式系统,并且数据分布在集群中的所有节点之间。

  • 集群中的所有节点都扮演相同的角色。每个节点都是独立的,并同时互连到其他节点。
  • 集群中的每个节点都可以接受读写请求,而不管数据实际位于集群中的何处。
  • 当某个节点发生故障时,可以从网络中的其他节点处理读/写请求。

Cassandra中的数据复制

在Cassandra中,集群中的一个或多个节点充当给定数据段的副本。如果检测到某些节点响应的值过时,则Cassandra会将最新值返回给客户端。返回最新值后,Cassandra在后台执行读取修复以更新过时的值。

下图显示了Cassandra如何在集群中的节点之间使用数据复制以确保没有单点故障的示意图。

Cassandra使用Gossip协议,以允许节点彼此通信并检测集群中的任何故障节点。

入门安装:使用docker-compose 安装

docker-compose.yaml

  1. version: "3.8"
  2. services:
  3. cassandra:
  4. image: cassandra:4.1
  5. container_name: cassandra
  6. ports:
  7. - 9042:9042
  8. volumes:
  9. - $PWD/commitlog:/var/lib/cassandra/commitlog
  10. - $PWD/hints:/var/lib/cassandra/hints
  11. - $PWD/data:/var/lib/cassandra/data
  12. - $PWD/saved_caches:/var/lib/cassandra/saved_caches
  13. - $PWD/logs:/var/log/cassandra

启动容器

使用如下指令启动容器:

docker-compose up -d

注意:如果如果没有在docker-compose.yaml文件所在目录或者文件名不是docker-compose.yaml,需要通过-f指定文件所在位置。即如:

docker-compose -f cassandra-start-up.yaml up -d

启动好之后,可以进入到容器之中:

  1. ➜ cassandra docker-compose up -d
  2. Creating network "cassandra_default" with the default driver
  3. Pulling cassandra (cassandra:4.1)...
  4. 4.1: Pulling from library/cassandra
  5. eaead16dc43b: Pull complete
  6. 46e1869246ce: Pull complete
  7. bbd45db92608: Pull complete
  8. 6fcfd0f47989: Pull complete
  9. 996685dfbe33: Pull complete
  10. 4927828dcc1b: Pull complete
  11. 7f67cde8352d: Pull complete
  12. 09bb07e15655: Pull complete
  13. b8d7c6610af3: Pull complete
  14. Status: Downloaded newer image for cassandra:4.1
  15. Creating cassandra ... done
  16. ➜ cassandra docker ps
  17. CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
  18. cdf4f5b56a88 cassandra:4.1 "docker-entrypoint.s…" 10 minutes ago Up 10 minutes 7000-7001/tcp, 7199/tcp, 9160/tcp, 0.0.0.0:9042->9042/tcp cassandra
  19. ➜ cassandra docker exec -it cdf4f5b56a88 bash
  20. root@cdf4f5b56a88:/# cqlsh
  21. Connected to Test Cluster at 127.0.0.1:9042
  22. [cqlsh 6.1.0 | Cassandra 4.1-beta1 | CQL spec 3.4.6 | Native protocol v5]
  23. Use HELP for help.
  24. cqlsh> desc keyspaces;
  25. system system_distributed system_traces system_virtual_schema
  26. system_auth system_schema system_views

可以看到,我们已经通过cqlsh命令,登录到了当前的Cassandra数据库。
但是这里会有疑惑产生:

登录数据库的指令太过简单了吧?!如果需要登录指定主机地址的数据库,应该怎么设置主机地址?
登录数据库的指令不需要用户名和密码嘛?
需要的话,我的用户名和密码是什么?就目前而言,我并没有做任何设置。
如何设置用户名和密码?
 

cqlsh的基本命令 


选项    使用/作用
help    此命令用于显示有关CQLsh命令选项的帮助主题。
version    它用于查看您正在使用的CQLsh的版本。
color    它用于彩色输出。
debug    它显示其他调试信息。
execute    它用于引导shell接受并执行CQL命令。
show    显示当前会话详情

这里的options包括哪些呢? 官网写的很详细,我就不抄了,看这里 cqlsh: the CQL shell
我就挑几个最关心的看一下:

-u USERNAME --username=USERNAME
Authenticate as user.

-p PASSWORD --password=PASSWORD
Authenticate using password.

-k KEYSPACE --keyspace=KEYSPACE
Authenticate to the given keyspace.

这三个是用来指定用户名和密码以及keySpace的。

–credentials=CREDENTIALS
Specify an alternative credentials file location.

这个是用来指定credentials的。

为什么没有输入用户名和密码就直接登录了?


这里是由于没有做任何个性化配置,我们使用的相关配置是默认配置文件cassandra.yaml文件里的配置,这个配置文件在容器里的/opt/cassandra/conf目录下。这里的配置内容是
 

  1. #AllowAllAuthenticator performs no checks - set it to disable authentication.
  2. authenticator: AllowAllAuthenticator

当这里配置为AllowAllAuthenticator的时候,将不做任何的检查。是设置为关闭认证。
要想启用用户名密码登录,就需要将其设置为PasswordAuthenticator:

authenticator: PasswordAuthenticator

不过这个时候会发现,容器中没有vim,也没有vi,那就只能把容器里的文件copy出来,修改完再copy回去了。

docker cp cdf4f5b56a88:/opt/cassandra/conf/cassandra.yaml .

我这是把文件从容器中copy当当前位置,修改完之后再copy回去,source和destination位置互换,即:

docker cp cassandra.yaml cdf4f5b56a88:/opt/cassandra/conf/

替换完成之后,再重新启动容器:

docker restart cdf4f5b56a88

重启完之后再进入容器,再使用cqlsh指令登录,发得到如下错误:

  1. ➜  cassandra docker exec -it cdf4f5b56a88 bash
  2. root@cdf4f5b56a88:/# cqlsh
  3. Connection error: ('Unable to connect to any servers', {'127.0.0.1:9042': ConnectionRefusedError(111, "Tried connecting to [('127.0.0.1', 9042)]. Last error: Connection refused")})
  4. root@cdf4f5b56a88:/#

看上面的提示,似乎也看不出来什么错误,只是connection refused。那就想着用用户名和密码尝试一下吧?由于我们没有设置用户名和密码,这个时候就只能使用系统默认设置的用户名和密码都是cassandra的账户进行登录。

  1. root@cdf4f5b56a88:/# cqlsh -u cassandra -p cassandra
  2. Warning: Using a password on the command line interface can be insecure.
  3. Recommendation: use the credentials file to securely provide the password.
  4. Connected to Test Cluster at 127.0.0.1:9042
  5. [cqlsh 6.1.0 | Cassandra 4.1-beta1 | CQL spec 3.4.6 | Native protocol v5]
  6. Use HELP for help.
  7. cassandra@cqlsh>

创建新用户


cassnadra划分了三种角色类型:

xxopr: 应用账号,只能进行对表的查询、数据插入、数据删除等DML操作
xxdata: 相当于数据OWNER用户,对表空间内的对象拥有增删改查等DDL操作
cassandra: 超级用户,用于创建表空间的,DBA权限管理

这里先创建一个superuser:

create user root_cassandra with password '123456' superuser;

然后使用这个用户进行登录:

  1. root@cdf4f5b56a88:/# cqlsh -u root_cassandra -p 123456
  2. Warning: Using a password on the command line interface can be insecure.
  3. Recommendation: use the credentials file to securely provide the password.
  4. Connected to Test Cluster at 127.0.0.1:9042
  5. [cqlsh 6.1.0 | Cassandra 4.1-beta1 | CQL spec 3.4.6 | Native protocol v5]
  6. Use HELP for help.
  7. root_cassandra@cqlsh> list users;
  8. name | super | datacenters
  9. ----------------+-------+-------------
  10. cassandra | True | ALL
  11. root_cassandra | True | ALL
  12. (2 rows)
  13. root_cassandra@cqlsh>

可以看到,这里已经有两个超级用户了,不想保留cassandra这个用户的可以直接drop掉。

drop user cassandra

简单操作

既然已经到这里了,那就创建一个用户,试试简单操作先:

  1. root_cassandra@cqlsh> create user test_data with password '123456' nosuperuser;
  2. root_cassandra@cqlsh> exit;
  3. root@cdf4f5b56a88:/# cqlsh -u test_data -p 123456
  4. Warning: Using a password on the command line interface can be insecure.
  5. Recommendation: use the credentials file to securely provide the password.
  6. Connected to Test Cluster at 127.0.0.1:9042
  7. [cqlsh 6.1.0 | Cassandra 4.1-beta1 | CQL spec 3.4.6 | Native protocol v5]
  8. Use HELP for help.
  9. test_data@cqlsh> CREATE KEYSPACE IF NOT EXISTS store WITH REPLICATION = { 'class' : 'SimpleStrategy', 'replication_factor' : '1' };
  10. test_data@cqlsh> desc keyspaces;
  11. store system_auth system_schema system_views
  12. system system_distributed system_traces system_virtual_schema
  13. test_data@cqlsh> desc keyspace store
  14. CREATE KEYSPACE store WITH replication = {'class': 'SimpleStrategy', 'replication_factor': '1'} AND durable_writes = true;
  15. test_data@cqlsh> CREATE TABLE IF NOT EXISTS store.shopping_cart (
  16. ... userid text PRIMARY KEY,
  17. ... item_count int,
  18. ... last_update_timestamp timestamp
  19. ... );
  20. test_data@cqlsh> INSERT INTO store.shopping_cart
  21. ... (userid, item_count, last_update_timestamp)
  22. ... VALUES ('9876', 2, toTimeStamp(now()));
  23. test_data@cqlsh> INSERT INTO store.shopping_cart
  24. ... (userid, item_count, last_update_timestamp)
  25. ... VALUES ('1234', 5, toTimeStamp(now()));

可以看到已经创建了一个keyspace为store的库,创建了一个表shopping_cart,并插入了一些数据。查看一下表结构以及数据:

  1. test_data@cqlsh:store> select * from store.shopping_cart;
  2. userid | item_count | last_update_timestamp
  3. --------+------------+---------------------------------
  4. 1234 | 5 | 2022-11-05 08:39:47.077000+0000
  5. 9876 | 2 | 2022-11-05 08:39:46.226000+0000
  6. (2 rows)
  7. test_data@cqlsh:store> desc table shopping_cart;
  8. CREATE TABLE store.shopping_cart (
  9. userid text PRIMARY KEY,
  10. item_count int,
  11. last_update_timestamp timestamp
  12. ) WITH additional_write_policy = '99p'
  13. AND bloom_filter_fp_chance = 0.01
  14. AND caching = {'keys': 'ALL', 'rows_per_partition': 'NONE'}
  15. AND cdc = false
  16. AND comment = ''
  17. AND compaction = {'class': 'org.apache.cassandra.db.compaction.SizeTieredCompactionStrategy', 'max_threshold': '32', 'min_threshold': '4'}
  18. AND compression = {'chunk_length_in_kb': '16', 'class': 'org.apache.cassandra.io.compress.LZ4Compressor'}
  19. AND memtable = 'default'
  20. AND crc_check_chance = 1.0
  21. AND default_time_to_live = 0
  22. AND extensions = {}
  23. AND gc_grace_seconds = 864000
  24. AND max_index_interval = 2048
  25. AND memtable_flush_period_in_ms = 0
  26. AND min_index_interval = 128
  27. AND read_repair = 'BLOCKING'
  28. AND speculative_retry = '99p';
  29. test_data@cqlsh:store>

到此完成了Cassandra的启动。 

在SpringBoot中连接Cassandra

1.添加Cassandra的依赖:

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  3. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
  4. <modelVersion>4.0.0</modelVersion>
  5. <parent>
  6. <groupId>org.springframework.boot</groupId>
  7. <artifactId>spring-boot-starter-parent</artifactId>
  8. <version>2.5.14</version>
  9. <relativePath/>
  10. </parent>
  11. <groupId>com.example</groupId>
  12. <artifactId>demo</artifactId>
  13. <version>0.0.1-SNAPSHOT</version>
  14. <name>demo</name>
  15. <description>Demo project for Spring Boot</description>
  16. <properties>
  17. <java.version>1.8</java.version>
  18. </properties>
  19. <dependencies>
  20. <dependency>
  21. <groupId>org.springframework.boot</groupId>
  22. <artifactId>spring-boot-starter-data-cassandra</artifactId>
  23. </dependency>
  24. <dependency>
  25. <groupId>org.springframework.boot</groupId>
  26. <artifactId>spring-boot-starter-web</artifactId>
  27. </dependency>
  28. <dependency>
  29. <groupId>org.springframework.boot</groupId>
  30. <artifactId>spring-boot-starter-test</artifactId>
  31. <scope>test</scope>
  32. </dependency>
  33. </dependencies>
  34. <build>
  35. <plugins>
  36. <plugin>
  37. <groupId>org.springframework.boot</groupId>
  38. <artifactId>spring-boot-maven-plugin</artifactId>
  39. </plugin>
  40. </plugins>
  41. </build>
  42. </project>

2.添加Cassandra的配置:

  1. spring:
  2. data:
  3. cassandra:
  4. contact-points: localhost
  5. port: 9042
  6. keyspace-name: store
  7. username: root_cassandra
  8. password: 123456

3.添加配置类

  1. package com.example.demo;
  2. import org.springframework.boot.context.properties.ConfigurationProperties;
  3. import org.springframework.stereotype.Component;
  4. @Component
  5. @ConfigurationProperties(prefix = "spring.data.cassandra",
  6. ignoreInvalidFields = true)
  7. public class CassandraConfigurationProperties {
  8. private String contactPoints;
  9. private int port = 9042;
  10. private String username;
  11. private String password;
  12. private String keyspaceName;
  13. public String getContactPoints() {
  14. return contactPoints;
  15. }
  16. public void setContactPoints(String contactPoints) {
  17. this.contactPoints = contactPoints;
  18. }
  19. public int getPort() {
  20. return port;
  21. }
  22. public void setPort(int port) {
  23. this.port = port;
  24. }
  25. public String getUsername() {
  26. return username;
  27. }
  28. public void setUsername(String username) {
  29. this.username = username;
  30. }
  31. public String getPassword() {
  32. return password;
  33. }
  34. public void setPassword(String password) {
  35. this.password = password;
  36. }
  37. public String getKeyspaceName() {
  38. return keyspaceName;
  39. }
  40. public void setKeyspaceName(String keyspaceName) {
  41. this.keyspaceName = keyspaceName;
  42. }
  43. }

  1. package com.example.demo;
  2. import org.springframework.beans.factory.annotation.Autowired;
  3. import org.springframework.boot.context.properties.EnableConfigurationProperties;
  4. import org.springframework.context.annotation.Configuration;
  5. import org.springframework.data.cassandra.config.AbstractCassandraConfiguration;
  6. import org.springframework.data.cassandra.config.CqlSessionFactoryBean;
  7. @Configuration
  8. @EnableConfigurationProperties(CassandraConfigurationProperties.class)
  9. public class CassandraConfiguration extends AbstractCassandraConfiguration {
  10. @Autowired
  11. private CassandraConfigurationProperties cassandraConfigurationProperties;
  12. @Override
  13. protected String getKeyspaceName() {
  14. return cassandraConfigurationProperties.getKeyspaceName();
  15. }
  16. @Override
  17. protected String getContactPoints() {
  18. return cassandraConfigurationProperties.getContactPoints();
  19. }
  20. @Override
  21. protected int getPort() {
  22. return cassandraConfigurationProperties.getPort();
  23. }
  24. @Override
  25. public CqlSessionFactoryBean cassandraSession() {
  26. CqlSessionFactoryBean cqlSessionFactoryBean = super.cassandraSession();
  27. cqlSessionFactoryBean.setPassword(cassandraConfigurationProperties.getPassword());
  28. cqlSessionFactoryBean.setUsername(cassandraConfigurationProperties.getUsername());
  29. return cqlSessionFactoryBean;
  30. }
  31. }

设置对应的实体类:

  1. package com.example.demo;
  2. import org.springframework.data.cassandra.core.cql.PrimaryKeyType;
  3. import org.springframework.data.cassandra.core.mapping.Column;
  4. import org.springframework.data.cassandra.core.mapping.PrimaryKeyColumn;
  5. import org.springframework.data.cassandra.core.mapping.Table;
  6. import java.util.Date;
  7. @Table("shopping_cart")
  8. public class ShoppingCart {
  9. @PrimaryKeyColumn(type = PrimaryKeyType.PARTITIONED)
  10. private String userid;
  11. @Column
  12. private int item_count;
  13. @Column
  14. private Date last_update_timestamp;
  15. public String getUserid() {
  16. return userid;
  17. }
  18. public void setUserid(String userid) {
  19. this.userid = userid;
  20. }
  21. public int getItem_count() {
  22. return item_count;
  23. }
  24. public void setItem_count(int item_count) {
  25. this.item_count = item_count;
  26. }
  27. public Date getLast_update_timestamp() {
  28. return last_update_timestamp;
  29. }
  30. public void setLast_update_timestamp(Date last_update_timestamp) {
  31. this.last_update_timestamp = last_update_timestamp;
  32. }
  33. @Override
  34. public String toString() {
  35. return "ShoppingCart{" +
  36. "userid='" + userid + '\'' +
  37. ", item_count=" + item_count +
  38. ", last_update_timestamp=" + last_update_timestamp +
  39. '}';
  40. }
  41. }

设置接口类:

  1. package com.example.demo;
  2. import org.springframework.data.cassandra.repository.CassandraRepository;
  3. public interface ShoppingCartRepo extends CassandraRepository<ShoppingCart, String> {
  4. }

设置SpringBoot的启动类:

  1. package com.example.demo;
  2. import org.springframework.boot.SpringApplication;
  3. import org.springframework.boot.autoconfigure.SpringBootApplication;
  4. @SpringBootApplication
  5. public class DemoApplication {
  6. public static void main(String[] args) {
  7. SpringApplication.run(DemoApplication.class, args);
  8. }
  9. }

编写Cassandra的测试代码:

  1. package com.example.demo;
  2. import org.junit.jupiter.api.Test;
  3. import org.springframework.beans.factory.annotation.Autowired;
  4. import org.springframework.boot.test.context.SpringBootTest;
  5. import org.springframework.data.cassandra.core.CassandraTemplate;
  6. import java.util.List;
  7. @SpringBootTest
  8. class DemoApplicationTests {
  9. @Autowired
  10. private CassandraTemplate cassandraTemplate;
  11. @Test
  12. void query() {
  13. ShoppingCart cart = cassandraTemplate.selectOne("select * from store.shopping_cart", ShoppingCart.class);
  14. System.out.println(cart);
  15. }
  16. @Autowired
  17. private ShoppingCartRepo shoppingCartRepo;
  18. @Test
  19. void query2(){
  20. List<ShoppingCart> all = shoppingCartRepo.findAll();
  21. System.out.println(all);
  22. }
  23. }

运行结果

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/weixin_40725706/article/detail/126366
推荐阅读
相关标签
  

闽ICP备14008679号