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

本文涉及的产品
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
简介: 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
相关文章
|
1天前
|
NoSQL 关系型数据库 应用服务中间件
docker基础篇:安装tomcat
docker基础篇:安装tomcat
88 64
|
2天前
|
关系型数据库 MySQL 数据库
docker高级篇(大厂进阶):安装mysql主从复制
docker高级篇(大厂进阶):安装mysql主从复制
42 24
|
3天前
|
NoSQL 算法 Redis
docker高级篇(大厂进阶):安装redis集群
docker高级篇(大厂进阶):安装redis集群
51 24
|
11天前
|
NoSQL Java 关系型数据库
Liunx部署java项目Tomcat、Redis、Mysql教程
本文详细介绍了如何在 Linux 服务器上安装和配置 Tomcat、MySQL 和 Redis,并部署 Java 项目。通过这些步骤,您可以搭建一个高效稳定的 Java 应用运行环境。希望本文能为您在实际操作中提供有价值的参考。
72 26
|
2天前
|
Ubuntu Linux Docker
Ubuntu22.04上Docker的安装
通过以上详细的安装步骤和命令,您可以在Ubuntu 22.04系统上顺利安装
33 11
|
29天前
|
缓存 Linux Docker
【最新版正确姿势】Docker安装教程(简单几步即可完成)
之前的老版本Docker安装教程已经发生了变化,本文分享了Docker最新版安装教程,其他操作系统版本也可以参考官 方的其他安装版本文档。
1006 2
【最新版正确姿势】Docker安装教程(简单几步即可完成)
|
1月前
|
Java 应用服务中间件 Linux
【Docker容器化技术】docker安装与部署、常用命令、容器数据卷、应用部署实战、Dockerfile、服务编排docker-compose、私有仓库
本文主要讲解了Docker的安装与部署、常用命令、容器数据卷、应用部署实战、Dockerfile、服务编排docker-compose、私有仓库以及Docker容器虚拟化与传统虚拟机比较。
540 11
【Docker容器化技术】docker安装与部署、常用命令、容器数据卷、应用部署实战、Dockerfile、服务编排docker-compose、私有仓库
|
1月前
|
监控 前端开发 Java
【技术开发】接口管理平台要用什么技术栈?推荐:Java+Vue3+Docker+MySQL
该文档介绍了基于Java后端和Vue3前端构建的管理系统的技术栈及功能模块,涵盖管理后台的访问、登录、首页概览、API接口管理、接口权限设置、接口监控、计费管理、账号管理、应用管理、数据库配置、站点配置及管理员个人设置等内容,并提供了访问地址及操作指南。
|
1月前
|
关系型数据库 MySQL Docker
docker环境下mysql镜像启动后权限更改问题的解决
在Docker环境下运行MySQL容器时,权限问题是一个常见的困扰。通过正确设置目录和文件的权限,可以确保MySQL容器顺利启动并正常运行。本文提供了多种解决方案,包括在主机上设置正确的权限、使用Dockerfile和Docker Compose进行配置、在容器启动后手动更改权限以及使用 `init`脚本自动更改权限。根据实际情况选择合适的方法,可以有效解决MySQL容器启动后的权限问题。希望本文对您在Docker环境下运行MySQL容器有所帮助。
149 1
|
1月前
|
Docker 容器
【赵渝强老师】使用二进制包方式安装Docker
本文介绍了在企业生产环境中无法直接访问外网时,如何使用Docker官方提供的二进制包进行Docker的离线安装。文章详细列出了从安装wget、下载Docker安装包、解压、复制命令到启动Docker服务的具体步骤,并提供了相关命令和示例图片。最后,还介绍了如何设置Docker为开机自启模式。
下一篇
DataWorks