安装Cassandra

安装方式参考官网,环境Ubuntu18.04

1. 写入Cassandra仓库

echo "deb http://www.apache.org/dist/cassandra/debian 311x main" | sudo tee -a /etc/apt/sources.list.d/cassandra.sources.list

2. 添加仓库公钥

curl https://www.apache.org/dist/cassandra/KEYS | sudo apt-key add -

3. 更新仓库源

sudo apt-get update

若是出现错误:

GPG error: http://www.apache.org 311x InRelease: The following signatures couldn't be verified because the public key is not available: NO_PUBKEY A278B781FE4B2BDA

执行操作:

sudo apt-key adv --keyserver pool.sks-keyservers.net --recv-key A278B781FE4B2BDA

4. 通过apt安装

sudo apt install cassandra

等待安装完成后,Cassandra默认即已启动,通过cql命令即可进入交互环境:

cqlsh localhost

若成功进入,证明安装成功。
Cassandra相关命令:

sudo service cassandra start #启动
sudo service cassandra stop #停止
nodetool status #查看Cassandra状态,nodetool是Cassandra自带的管理工具

Cassandra相关文件和目录:

配置文件目录:/etc/cassandra/
日志存储目录:/var/log/cassandra/
数据存储目录:/var/lib/cassandra/
启动配置文件(配置Cassandra启动时的堆大小等):/etc/default/cassandra

Cassandra配置用户名和密码

默认情况下,Cassandra是不需要授权即可登录的,下面配置Cassandra为用户名和密码授权并添加用户。

1. 修改授权方式

修改Cassandra的配置文件/etc/cassandra/cassandra.yaml:

sudo vi /etc/cassandra/cassandra.yaml

找到authenticatorCassandraAuthorizer字段配置如下:

authenticator: PasswordAuthenticator
authorizer: CassandraAuthorizer

然后重启Cassandra

service cassandra restart

2. 添加新用户

Cassandra默认有一个用户名和密码都为cassandra的超级用户,以该用户身份登录Cassandra

cqlsh localhost -ucassandra -pcassandra

然后创建一个新的超级用户:

cassandra@cqlsh> create user wt with password 'ceshi' superuser;

若无错误提示,即创建成功。

3. 删除默认用户

为更好的保证安全性,可以将默认的cassandra用户删除,通过exit命令退出Cassandra后,用新创建的超级用户身份登入:

cqlsh localhost -uwt -pceshi

然后删除默认的cassandra用户:

wt@cqlsh> drop user cassandra;

若无任何错误提示,即删除成功。

在所有服务器上安装Cassandra

在要搭建集群的所有服务器上依次安装好Cassandra,这里用虚拟机创建了3个服务器,系统均为Ubuntu18.04ip信息如下:

服务器名称ip
服务器1192.168.22.130
服务器2192.168.22.131
服务器3192.168.22.132

分布式集群配置

这里选定服务器1与服务器2为seed(种子)节点,服务器3为普通节点,首先配置服务器1,编辑/etc/cassandra/cassandra.yaml配置文件:

sudo vi /etc/cassandra/cassandra.yaml

找到并配置以下字段:

seed_provider:
    # Addresses of hosts that are deemed contact points. 
    # Cassandra nodes use this list of hosts to find each other and learn
    # the topology of the ring.  You must change this if you are running
    # multiple nodes!
    - class_name: org.apache.cassandra.locator.SimpleSeedProvider
      parameters:
          # seeds is actually a comma-delimited list of addresses.
          # Ex: "<ip1>,<ip2>,<ip3>"
        - seeds: "192.168.22.130,192.168.22.131"  #填入所有种子节点的ip,逗号隔开,约在425行位置
listen_address: 192.168.22.130 #将默认的localhost修改为服务器自己的实际ip地址,约在599行位置
rpc_address: 192.168.22.130 #将默认的localhost修改为服务器自己的实际ip地址,约在676行位置

服务器23的配置同服务器1,只是将listen_addressrpc_address配置为各自的ip即可。
全都配置完成后,将所有服务器的cassandra关闭,然后先启动所有seed节点,再启动普通节点。当所有服务器启动完成后,在任一服务器上查看cassandra状态:

nodetool status

若想访问数据库,连接至集群的任一节点即可。

cassandra集群的数据存储

复制因子

简单的说就是当写入一条记录到cassandra时,要为其保留几个副本,默认情况下复制因子是1,即只保留一份,若当前节点挂掉,则可能导致该部分数据无法访问的情况。复制因子的设置不能超过集群的节点数量,否则无法进行写入。复制因子的设定是在建立keyspace时确定的,如我们上边的集群中节点数量为3,建立一个复制因子为2keyspace

create keyspace test with replication = {'class': 'SimpleStrategy', 'replication_factor': 2}

其中class是复制策略,对于单数据中心而言(一个数据中心一般为一个集群),采用SimpleStrategy,对于多数据中心而言,采用NetworkTopologyStrategy,replication_factor指明了复制因子大小。若要更改已存在命名空间的复制因子大小,cql语句为:

alert keyspace "test" with replication = {'class': 'SimpleStrategy', 'replication_factor': 1}

数据存储和复制策略

当设置了复制因子后,若插入一条数据,这条数据应该插入到哪个节点呢?并且根据复制因子的设定,哪些节点应复制数据的备份呢?可以对要插入记录的的key值进行hash计算,根据hash值确定插入或复制的节点,比如节点数量为n,则将主键为key的记录插入到第hash(key) % n个节点上,但当节点数量发生变动时,比如增加了一个节点,则每个节点上的数据都会变动,因为对于同样的key,记录要放在第hash(key) % (n + 1)个节点上,相当于每个节点上对应的key值都要变动。因此cassandra采用了一致性哈希的策略。所谓一致性hash,即设置对所有keyhash,使hash值都能落到一个区间,这个区间叫做一致性hash环。如设置一个0~232hash环,对任一keyhash,使之在0~232内有唯一对应的值,即在hash环内有一个对应的位置,对于节点,也采取同样操作(如对节点的iphash),来确定节点在hash环上的位置,将该key的记录存储在顺时针方向距离最近的节点上,将该key的记录的副本复制到顺时针方向相邻的数量为复制因子个数的节点上,如对于4个节点复制因子为3的命名空间中,存储一条记录时,示意图如下:

hash_cassandra.png

这样,当节点数量改变时,如在节点3和4间有了一个新节点,则只有其相邻节点的数据会发生变动,其它节点可以不受影响。但这种方式也存在一个问题,当集群中节点数量较少时,可能存在数据插入偏向某一节点的情况,因此,cassandra中拥有虚拟节点的概念,即在hash环中插入若干虚拟节点,一个真实节点对应若干虚拟节点,当一条数据想要插入时,会在包括虚拟节点内的所有节点中选择节点插入,若选择到了一个虚拟节点,虽然对数据来说是插入到了该虚拟节点中,但实际上数据是存储在该虚拟节点所对应的真实节点中,这样,通过在hash环中遍布虚拟节点,便有效解决了偏向问题。

这种策略也决定了cassandra集群只能保证数据的最终一致性,因为从一个节点到其它节点的数据拷贝是需要时间的,若节点在备份还未完成时挂掉,则可能导致数据不是最新,只有经过一定时间,备份全都完成,才会保证数据的最终一致。根据CAP(分别代表一致性、可用性、分区容错性)定理,任何共享数据中心只能保证一致性、可用性、分区容错性中的两个,虽然cassandra牺牲了强一致性,但很好的保证了可用性和分区容错性,在专注于可用和容错,不要求实时一致性的场景中,cassandra是极好的选择。

Gossip协议

提到cassandra,不得不提一下gossip协议,cassandra天生就是分布式的,其拥有去中心化的特点,即集群中的任何节点都是平等的,没有中心节点,各节点没有主次之分,像Mongodb等分布式数据库大多拥有中心节点的概念,即数据读写请求都是通过中心节点进行协调的,若所有中心节点崩溃,则整个集群也将瘫痪,但cassandra集群中的各个节点都可以独立进行读写操作的协调,也即要访问集群,连接至任一节点即可,虽然cassandra存在种子节点,但种子节点只是为了集群能自发发现其它节点,没有任何特殊地位。之所以能有这个特点,正是因为cassandra集群采用了Gossip协议。cassandra的节点发现、信息传送都是基于Gossip协议的。

Gossip协议又称八卦协议,集群中的任何节点都是平等的,都可以向其它节点随意发送消息,就像八卦聊天一样,我可以和任何人发起聊天,共享消息,这样一传十,十传百,对于某一消息,集群中的所有节点最终都将会收到。对于某一节点,其发送消息时,会随机选择一台活着的节点和不可达的节点发送同步请求,若发送到的节点不是种子节点,还会随机向一台种子节点发送请求,每个消息中都有一个版本号,其它节点收到消息后,会拿消息的版本号与自身版本号做对比,以确定哪些内容是需要我更新的,或者哪些数据是已经过时,需要你更新的,然后收到消息的节点又会以同样的方式将消息传递给其它节点或者返回更新消息给发送者,这样最终一条消息会传遍集群中所有节点,实现节点状态的最终一致。因活着的节点也会向已不可达的节点发送消息,因此若死亡节点复活或新增节点,则节点有机会收到消息,加入集群聊天队伍,这也就实现了集群中节点的自发管理与发现。