05-Docker安装Mysql、Redis、Tomcat(下)

本文涉及的产品
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 Tair(兼容Redis),内存型 2GB
简介: 05-Docker安装Mysql、Redis、Tomcat

哈希槽分区


哈希槽分区是为了解决一致性哈希算法的数据倾斜问题。


哈希槽实质上就是一个数组,数组 [0, 2^14 - 1]形成的 hash slot空间。


目的是为了解决均匀分配的问题。在数据和节点之间又加入了一层,把这层称之为槽(slot),用于管理数据和节点之间的关系。就相当于节点上放的是槽,槽里面放的是数据。


槽解决的是粒度问题,相当于把粒度变大了,这样便于数据移动。


哈希解决的是映射问题,使用key的哈希值来计算所在的槽,便于数据分配。


一个集群只能有 16394个槽,编号 0 - 16383(2^14 - 1)。这些槽会分配给集群中所有的主节点,分配策略没有要求。可以指定哪些编号的槽分配给哪个主节点,集群会记录节点和槽的对应关系。


解决了节点和槽的关系后,接下来就需要对key求哈希值,然后对16384取余,根据余数决定key落到哪个槽里。


slot = CRC16(key) % 16384


以槽为单位移动数据,因为槽的数目是固定的,处理起来比较容易,这样数据移动问题就解决了。


Redis集群存储策略


Redis集群使用的就是哈希槽。Redis集群有16384个哈希槽,每个key通过CRC16校验后对16384取模来决定放置在哪个槽,集群的每个节点负责一部分hash槽。


哈希槽数量16384(2^14)的决定原因:


CRC16算法产生的hash值有 16bit,该算法可以产生 2^16 = 65536个值。但是为了心跳方便和数据传输最大化,槽的数量只能有 2^14


  1. 如果槽位数量为65535个,那么发送心跳信息的消息头将达到 8k,发送的心跳包过于庞大。在消息头中最占空间的是 myslots[CLUSTER_SLOTS/8]。当槽位为65536时,这块的大小是 :


65536 ÷ 8 ÷ 1024 = 8Kb


每秒中redis节点需要发送一定数量的ping消息作为心跳,如果槽位为65536,那么这个ping消息头就会太大浪费带宽。


  1. redis集群的主节点数量基本不可能超过1000个。集群节点越多,心跳包的消息体内携带的数据越多。如果节点超过1000个,也会导致网络拥堵。因此redis作者不建议redis cluster节点超过1000个。对于节点数在1000以内的redis cluster集群,16384个槽位足够了,没有必要扩展到65536个。


  1. 槽位越小,节点少的情况下压缩比越高,容易传输。Redis主节点的配置信息中它锁负责的哈希槽是通过一张bitmap的形式来保存的,在传输过程中会对bitmap进行压缩,但是如果bitmap的填充率 slots / N(N为节点数)很高的话,bitmap的压缩率就很低。如果节点数很少,而哈希槽数很多的话,bitmap的压缩率就很低。


原文:


正常的心跳数据包带有节点的完整配置,使得可以用幂等方式用旧的节点替换旧节点,以便更新旧的配置。这意味着它们包含原始节点的插槽配置,该节点使用 2k 的空间和 16k 的插槽,而不是使用 8k 的空间(使用65k的插槽)。


同时,因为其他设计折衷,Redis集群的主节点不太可能扩展到1000个以上


Redis集群中内置了16384个哈希槽,redis会根据节点数量大致均等的将哈希槽映射到不同的节点。当需要在Redis集群中放置一个Key-Value时,redis先对key使用 CRC16 算法算出一个结果,然后把结果对 16384 取余,这样每个key都会对应一个编号在0-16383之间的哈希槽,也就是映射到某个节点上。


@Test
public void test() {
    // import io.lettuce.core.cluster.SlotHash;
    System.out.println(SlotHash.getSlot('A'));  // 计算结果6373,存入上图的Node2
    System.out.println(SlotHash.getSlot('B'));  // 计算结果10374,存入上图的Node2
    System.out.println(SlotHash.getSlot('C'));  // 计算结果14503,存入上图的Node3
    System.out.println(SlotHash.getSlot('Hello'));  // 计算结果866,存入上图的Node1
}


3主3从Redis集群


搭建


使用docker搭建3主3从的Redis集群,每台主机都对应一台从机。


启动6台redis容器


# 启动第1台节点
# --net host 使用宿主机的IP和端口,默认
# --cluster-enabled yes 开启redis集群
# --appendonly yes 开启redis持久化
# --port 6381 配置redis端口号
docker run -d --name redis-node-1 --net host --privileged=true -v /app/redis-cluster/share/redis-node-1:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6381
# 启动第2台节点
docker run -d --name redis-node-2 --net host --privileged=true -v /app/redis-cluster/share/redis-node-2:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6382
# 启动第3台节点
docker run -d --name redis-node-3 --net host --privileged=true -v /app/redis-cluster/share/redis-node-3:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6383
# 启动第4台节点
docker run -d --name redis-node-4 --net host --privileged=true -v /app/redis-cluster/share/redis-node-4:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6384
# 启动第5台节点
docker run -d --name redis-node-5 --net host --privileged=true -v /app/redis-cluster/share/redis-node-5:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6385
# 启动第6台节点
docker run -d --name redis-node-6 --net host --privileged=true -v /app/redis-cluster/share/redis-node-6:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6386


构建主从关系:


  1. 进入节点1(或其中任意一个节点):


docker exec -it redis-node-1 /bin/bash


  1. 构建主从关系:


# 宿主机IP:端口
redis-cli --cluster create 192.168.xxx.xxx:6381 192.168.xxx.xxx:6382 192.168.xxx.


  1. redis尝试自动进行主从节点分配


  1. 因为我们的docker容器IP相同,所以会出现警告,可以直接忽略该警告


[WARNING] Some slaves are in the same host as their master


  1. redis自动分配结果完成后,需要输入 Yes 确认配置信息:


M: f451eb48bbc0a7c31c7da022ffe80cc1696e0f37 192.168.xxx.xxx:6381
   slots:[0-5460] (5461 slots) master
M: 05984211b8c38222a73abeff1d4e459c0fe1efbc 192.168.xxx.xxx:6382
   slots:[5461-10922] (5462 slots) master
M: 1fc935c12b1d34a7df50aed643c195eb29bb3435 192.168.xxx.xxx:6383
   slots:[10923-16383] (5461 slots) master
S: f8d0de47114bf33438747acd713cce4e412ae721 192.168.xxx.xxx:6384
   replicates 1fc935c12b1d34a7df50aed643c195eb29bb3435
S: de0b393c17e452d856f6de2b348e9ca4e5aa4002 192.168.xxx.xxx:6385
   replicates f451eb48bbc0a7c31c7da022ffe80cc1696e0f37
S: 0c0767e13a09ee48541738d4163592cd9842c143 192.168.xxx.xxx:6386
   replicates 05984211b8c38222a73abeff1d4e459c0fe1efbc
Can I set the above configuration? (type 'yes' to accept):


  1. 输入Yes确认后,redis会向其他节点发送信息加入集群,并分配哈希槽:


>>> Nodes configuration updated
>>> Assign a different config epoch to each node
>>> Sending CLUSTER MEET messages to join the cluster
Waiting for the cluster to join
.....
>>> Performing Cluster Check (using node 192.168.xxx.xxx:6381)
M: f451eb48bbc0a7c31c7da022ffe80cc1696e0f37 192.168.xxx.xxx:6381
   slots:[0-5460] (5461 slots) master
   1 additional replica(s)
M: 1fc935c12b1d34a7df50aed643c195eb29bb3435 192.168.xxx.xxx:6383
   slots:[10923-16383] (5461 slots) master
   1 additional replica(s)
M: 05984211b8c38222a73abeff1d4e459c0fe1efbc 192.168.xxx.xxx:6382
   slots:[5461-10922] (5462 slots) master
   1 additional replica(s)
S: 0c0767e13a09ee48541738d4163592cd9842c143 192.168.xxx.xxx:6386
   slots: (0 slots) slave
   replicates 05984211b8c38222a73abeff1d4e459c0fe1efbc
S: f8d0de47114bf33438747acd713cce4e412ae721 192.168.xxx.xxx:6384
   slots: (0 slots) slave
   replicates 1fc935c12b1d34a7df50aed643c195eb29bb3435
S: de0b393c17e452d856f6de2b348e9ca4e5aa4002 192.168.xxx.xxx:6385
   slots: (0 slots) slave
   replicates f451eb48bbc0a7c31c7da022ffe80cc1696e0f37
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.


查看集群状态:


  1. 进入容器节点1(或集群中其他节点):


docker exec -it redis-node-1 /bin/bash


  1. 使用redis-cli连接到6381节点:


redis-cli -p 6381


  1. 使用redis的相关命令查看集群状态:


cluster info


其中,分配的哈希槽数量 cluster_slots_assigned为16384,集群节点数量cluster_known_nodes为6


  1. 查看集群节点信息


cluster nodes


Redis集群读写出错


当使用 redis-cli连接redis集群时,需要添加 -c参数,否则可能会出现读写出错。


示例:


  1. 进入容器节点1


docker exec -it redis-node-1 /bin/bash


  1. 使用redis-cli连接,不加-c参数时


redis-cli -p 6381


  1. 此时向redis中添加键值对,可能会成功,也可能会失败


set k1 v1


报错:k1经过计算得到的哈希槽为12706,但是当前连接的redis-server为6381(即节点1),它的哈希槽为:[0,5460](在创建构建主从关系时redis有提示,也可以通过 cluster nodes查看),所以会因为存不进去而报错。


执行 set k2 v2可以成功,因为k2计算出的哈希槽在[0-5460]区间中。


  1. 使用-c参数的redis-cli命令连接即可


redis-cli -p 6381 -c


  1. 此时可以正常的插入所有数据


set k1 v1


会有提示信息,哈希槽为12706,重定向到6383(即节点3,哈希槽[10923, 16383]):


集群信息检查


检查查看集群信息:


  1. 进入容器节点1


docker exec -it redis-node-1 /bin/bash


  1. 进行集群信息检查


# 输入任意一台主节点地址都可以进行集群检查
redis-cli --cluster check 192.168.xxx.xxx:6381


返回的检查结果:


当前集群中各个节点存储的key的数量
192.168.xxx.xxx:6381 (f451eb48...) -> 0 keys | 5461 slots | 1 slaves.
192.168.xxx.xxx:6383 (1fc935c1...) -> 1 keys | 5461 slots | 1 slaves.
192.168.xxx.xxx:6382 (05984211...) -> 0 keys | 5462 slots | 1 slaves.
[OK] 1 keys in 3 masters.  
0.00 keys per slot on average.
主从机器信息
>>> Performing Cluster Check (using node 192.168.xxx.xxx:6381)
M: f451eb48bbc0a7c31c7da022ffe80cc1696e0f37 192.168.xxx.xxx:6381
   slots:[0-5460] (5461 slots) master
   1 additional replica(s)
M: 1fc935c12b1d34a7df50aed643c195eb29bb3435 192.168.xxx.xxx:6383
   slots:[10923-16383] (5461 slots) master
   1 additional replica(s)
M: 05984211b8c38222a73abeff1d4e459c0fe1efbc 192.168.xxx.xxx:6382
   slots:[5461-10922] (5462 slots) master
   1 additional replica(s)
S: 0c0767e13a09ee48541738d4163592cd9842c143 192.168.xxx.xxx:6386
   slots: (0 slots) slave
   replicates 05984211b8c38222a73abeff1d4e459c0fe1efbc
S: f8d0de47114bf33438747acd713cce4e412ae721 192.168.xxx.xxx:6384
   slots: (0 slots) slave
   replicates 1fc935c12b1d34a7df50aed643c195eb29bb3435
S: de0b393c17e452d856f6de2b348e9ca4e5aa4002 192.168.xxx.xxx:6385
   slots: (0 slots) slave
   replicates f451eb48bbc0a7c31c7da022ffe80cc1696e0f37
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.


主从扩容缩容


主从扩容


假如因为业务量激增,需要向当前3主3从的集群中再加入1主1从两个节点。


步骤:


  1. 启动2台新的容器节点


# 启动第7台节点
docker run -d --name redis-node-7 --net host --privileged=true -v /app/redis-cluster/share/redis-node-7:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6387
# 启动第8台节点
docker run -d --name redis-node-8 --net host --privileged=true -v /app/redis-cluster/share/redis-node-8:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6388


  1. 进入6387(节点7)容器内部


docker exec -it redis-node-7 /bin/bash


  1. 将6387作为master加入集群


# redis-cli --cluster add-node 本节点地址 要加入的集群中的其中一个节点地址
redis-cli --cluster add-node 192.168.xxx.xxx:6387 192.168.xxx.xxx:6381


  1. 检查当前集群状态


redis-cli --cluster check 192.168.xxx.xxx:6381


可以发现,6371节点已经作为master加入了集群,但是该节点没有被分配槽位。


  1. 重新分配集群的槽位


redis-cli --cluster reshard 192.168.xxx.xxx:6381


redis经过槽位检查后,会提示需要分配的槽位数量:


例如,我们现在是4台master,我们想要给node7分配4096个槽位,这样每个节点都是4096个槽位。


输入4096后,会让输入要接收这些哈希槽的节点ID,填入node7的节点ID即可。(就是节点信息中很长的一串十六进制串)。


然后会提示,询问要从哪些节点中拨出一部分槽位凑足4096个分给Node7。一般选择 all,即将之前的3个主节点的槽位都均一些给Node7,这样可以使得每个节点的槽位数相等均衡。


输入all之后,redis会列出一个计划,内容是自动从前面的3台master中拨出一部分槽位分给Node7的槽位,需要确认一下分配的计划。


输入yes确认后,redis便会自动重新洗牌,给Node7分配槽位。


重新分配完成后,可以进行集群信息检查,查看分配结果:


redis-cli --cluster check 192.168.xxx.xxx:6381


可以发现重新洗牌后的槽位分配为:


节点1:[1365-5460](供4096个槽位),,,分配前为[0-5460](共5461个槽位)
节点2:[6827-10922](共4096个槽位),,,分配前为[5461-10922](共5461个槽位)
节点3:[12288-16383](共4096个槽位),,,分配前为[10923-16383](共5462个槽位)
节点7:[0-1364],[5461-6826],[10923-12287](共4096个槽位),从每个节点中匀出来了一部分给了节点7


因为可能有些槽位中已经存储了key,完全的重新洗牌重新分配的成本过高,所以redis选择从前3个节点中匀出来一部分给节点7


为主节点6387分配从节点6388:


redis-cli --cluster add-node 192.168.xxx.xxx:6388 192.168.xxx.xxx:6381 --cluster-slave --cluster-master-id node7节点的十六进制编号字符串


redis便会向6388发送消息,使其加入集群并成为6387的从节点。


检查集群当前状态


redis-cli --cluster check 192.168.xxx.xxx:6381


主从缩容


假如业务高峰期过去,需要将4主4从重新缩容到3主3从。即从集群中移除node8和node7.


首先删除从节点6388:


  1. 进入容器节点1


docker exec -it redis-node-1 /bin/bash


  1. 检查容器状态,获取6388的节点编号


redis-cli --cluster check 192.168.xxx.xxx:6381


  1. 将6388从集群中移除


redis-cli --cluster del-node 192.168.xxx.xxx:6388 6388节点编号


对node7重新分配哈希槽:


  1. 对集群重新分配哈希槽


redis-cli --cluster reshard 192.168.xxx.xxx:6381


  1. redis经过槽位检查后,会提示需要分配的槽位数量:


How many slots do you want to move (from 1 to 16384)?


如果我们想直接把node7的4096个哈希槽全部分给某个节点,可以直接输入4096。


输入4096后,会让输入要接收这些哈希槽的节点ID。假如我们想把这4096个槽都分给Node1,直接输入node1节点的编号即可。


然后会提示,询问要从哪些节点中拨出一部分槽位凑足4096个分给Node1。这里我们输入node7的节点编号,回车后输入done。


node7上面没有了哈希槽,此时便可以将node7从集群中移除。(如果node7上面有哈希槽,直接从集群中移除会报错)


redis-cli --cluster del-node 192.168.xxx.xxx:6387 node7节点编号


Docker 安装 tomcat


拉取 :



自动启动(docker启动的时候自启动)


docker update redis --restart=always
docker update mysql --restart=always
相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore     ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库 ECS 实例和一台目标数据库 RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
29天前
|
关系型数据库 MySQL Linux
Docker安装Mysql5.7,解决无法访问DockerHub问题
当 Docker Hub 无法访问时,可以通过配置国内镜像加速来解决应用安装失败和镜像拉取超时的问题。本文介绍了如何在 CentOS 上一键配置国内镜像加速,并成功拉取 MySQL 5.7 镜像。
242 2
Docker安装Mysql5.7,解决无法访问DockerHub问题
|
1月前
|
Java 关系型数据库 MySQL
自动化测试项目实战笔记(一):JDK、Tomcat、MySQL、Jpress环境安装和搭建
这篇文章是关于自动化测试项目实战笔记,涵盖了JDK、Tomcat、MySQL、Jpress环境的安装和搭建过程,以及测试用例和常见问题总结。
47 1
自动化测试项目实战笔记(一):JDK、Tomcat、MySQL、Jpress环境安装和搭建
|
13天前
|
关系型数据库 MySQL Docker
docker环境下mysql镜像启动后权限更改问题的解决
在Docker环境下运行MySQL容器时,权限问题是一个常见的困扰。通过正确设置目录和文件的权限,可以确保MySQL容器顺利启动并正常运行。本文提供了多种解决方案,包括在主机上设置正确的权限、使用Dockerfile和Docker Compose进行配置、在容器启动后手动更改权限以及使用 `init`脚本自动更改权限。根据实际情况选择合适的方法,可以有效解决MySQL容器启动后的权限问题。希望本文对您在Docker环境下运行MySQL容器有所帮助。
21 1
|
1月前
|
NoSQL Linux Redis
Docker学习二(Centos):Docker安装并运行redis(成功运行)
这篇文章介绍了在CentOS系统上使用Docker安装并运行Redis数据库的详细步骤,包括拉取Redis镜像、创建挂载目录、下载配置文件、修改配置以及使用Docker命令运行Redis容器,并检查运行状态和使用Navicat连接Redis。
218 3
|
1月前
|
存储 NoSQL 大数据
大数据-51 Redis 高可用方案CAP-AP 主从复制 一主一从 全量和增量同步 哨兵模式 docker-compose测试
大数据-51 Redis 高可用方案CAP-AP 主从复制 一主一从 全量和增量同步 哨兵模式 docker-compose测试
32 3
|
1月前
|
消息中间件 NoSQL Kafka
Flink-10 Flink Java 3分钟上手 Docker容器化部署 JobManager TaskManager Kafka Redis Dockerfile docker-compose
Flink-10 Flink Java 3分钟上手 Docker容器化部署 JobManager TaskManager Kafka Redis Dockerfile docker-compose
36 4
|
1月前
|
弹性计算 关系型数据库 MySQL
Docker安装MySQL
这篇文章详细介绍了如何使用Docker安装MySQL数据库服务,包括拉取镜像、配置数据卷以及启动容器的步骤。
272 0
Docker安装MySQL
|
1月前
|
NoSQL 关系型数据库 MySQL
Tomcat、MySQL、Redis最大支持说明
综上所述,Tomcat、MySQL、Redis的并发处理能力均非固定值,而是通过合理的配置与优化策略,结合系统硬件资源,共同决定了它们在实际应用中的表现。开发者应根据应用的具体需求和资源条件,对这些组件进行细致的调优,以达到最佳性能表现。
32 0
|
NoSQL 关系型数据库 PHP
|
1月前
|
消息中间件 缓存 NoSQL
Redis 是一个高性能的键值对存储系统,常用于缓存、消息队列和会话管理等场景。
【10月更文挑战第4天】Redis 是一个高性能的键值对存储系统,常用于缓存、消息队列和会话管理等场景。随着数据增长,有时需要将 Redis 数据导出以进行分析、备份或迁移。本文详细介绍几种导出方法:1)使用 Redis 命令与重定向;2)利用 Redis 的 RDB 和 AOF 持久化功能;3)借助第三方工具如 `redis-dump`。每种方法均附有示例代码,帮助你轻松完成数据导出任务。无论数据量大小,总有一款适合你。
72 6