Docker 安装 Mysql
以安装 Mysql 5.7为例:
docker pull mysql:5.7
Mysql 单机
Mysql 5.7安装
启动 Mysql 容器,并配置容器卷映射:
docker run -d -p 3306:3306 \ --privileged=true \ -v /app/mysql/log:/var/log/mysql \ -v /app/mysql/data:/var/lib/mysql \ -v /app/mysql/conf:/etc/mysql/conf \ -e MYSQL_ROOT_PASSWORD=root \ --name mysql \ mysql:5.7
参数说明:
-d -> 后台运行容器并返回容器ID,即启动守护式容器
-p 3306:3306 -> (宿主机端口 : 容器内软件端口)将容器的端口映射到主机的端口
-e -> 为容器添加环境变量
-v 容器挂载
-name 起名
在/app/mysql/conf
下新建 my.cnf
,通过容器卷同步给mysql实例,解决中文乱码问题:
[client] default_character_set=utf8 [mysqld] collation_server = utf8_general_ci character_set_server = utf8
重启mysql容器,使得容器重新加载配置文件:
docker restart mysql
此时便解决了中文乱码(中文插入报错)问题。
而且因为启动时将容器做了容器卷映射,将mysql的配置(映射到/app/mysql/conf)、数据(映射到/app/mysql/data)、日志(映射到/app/mysql/log)都映射到了宿主机实际目录,所以即使删除了容器,也不会产生太大影响。只需要再执行一下启动Mysql容器命令,容器卷还按相同位置进行映射,所有的数据便都可以正常恢复。
Mysql 主从复制安装
安装主服务器容器实例(端口号3307):
- 启动容器实例
docker run -p 3307:3306 \ --name mysql-master \ --privileged=true \ -v /app/mysql-master/log:/var/log/mysql \ -v /app/mysql-master/data:/var/lib/mysql \ -v /app/mysql-master/conf:/etc/mysql \ -e MYSQL_ROOT_PASSWORD=root \ -d mysql:5.7
- 进入
/app/mysql-master/conf
,新建my.cnf
配置文件:
[mysqld] ## 设置server_id, 同一个局域网中需要唯一 server_id=101 ## 指定不需要同步的数据库名称 binlog-ignore-db=mysql ## 开启二进制日志功能 log-bin=mall-mysql-bin ## 设置二进制日志使用内存大小(事务) binlog_cache_size=1M ## 设置使用的二进制日志格式(mixed,statement,row) binlog_format=mixed ## 二进制日志过期清理时间。默认值为0,表示不自动清理 expire_logs_days=7 ## 跳过主从复制中遇到的所有错误或指定类型的错误,避免slave端复制中断 ## 如:1062错误是指一些主键重复,1032错误是因为主从数据库数据不一致 slave_skip_errors=1062
- 重启容器实例
docker restart mysql-master
- 进入容器实例内
docker exec -it mysql-master /bin/bash
- 登录mysql,创建数据同步用户
-- 首先使用 mysql -uroot -p 登录mysql -- 创建数据同步用户 create user 'slave'@'%' identified by '123456'; -- 授权 grant replication slave, replication client on *.* to 'slave'@'%'; flush privileges;
安装从服务器容器实例(端口号3308):
- 启动容器服务:
docker run -p 3308:3306 \ --name mysql-slave \ --privileged=true \ -v /app/mysql-slave/log:/var/log/mysql \ -v /app/mysql-slave/data:/var/lib/mysql \ -v /app/mysql-slave/conf:/etc/mysql \ -e MYSQL_ROOT_PASSWORD=root \ -d mysql:5.7
- 进入
/app/mysql-slave/conf
目录,创建my.cnf
配置文件:
[mysqld] ## 设置server_id, 同一个局域网内需要唯一 server_id=102 ## 指定不需要同步的数据库名称 binlog-ignore-db=mysql ## 开启二进制日志功能,以备slave作为其它数据库实例的Master时使用 log-bin=mall-mysql-slave1-bin ## 设置二进制日志使用内存大小(事务) binlog_cache_size=1M ## 设置使用的二进制日志格式(mixed,statement,row) binlog_format=mixed ## 二进制日志过期清理时间。默认值为0,表示不自动清理 expire_logs_days=7 ## 跳过主从复制中遇到的所有错误或指定类型的错误,避免slave端复制中断 ## 如:1062错误是指一些主键重复,1032是因为主从数据库数据不一致 slave_skip_errors=1062 ## relay_log配置中继日志 relay_log=mall-mysql-relay-bin ## log_slave_updates表示slave将复制事件写进自己的二进制日志 log_slave_updates=1 ## slave设置只读(具有super权限的用户除外) read_only=1
- 修改完配置需要重启slave容器实例
docker restart mysql-slave
在主数据库中查看主从同步状态:
- 进入主数据库容器:
docker exec -it mysql-master /bin/bash
- 进入Mysql
mysql -uroot -p
- 查看主从同步状态
show master status;
主要查看返回结果的文件名File
、当前位置Position
进入从数据库容器,配置主从复制:
- 进入从数据库容器:
docker exec -it mysql-slave /bin/bash
- 进入数据库
mysql -uroot -p
- 配置从数据库所属的主数据库:
-- 格式: -- change master to master_host='宿主机ip',master_user='主数据库配置的主从复制用户名',master_password='主数据库配置的主从复制用户密码',master_port=宿主机主数据库端口,master_log_file='主数据库主从同步状态的文件名File',master_log_pos=主数据库主从同步状态的Position,master_connect_retry=连接失败重试时间间隔(秒); change master to master_host='192.168.xxx.xxx',master_user='slave',master_password='123456',master_port=3307,master_log_file='mall-mysql-bin.000001',master_log_pos=769,master_connect_retry=30;
- 查看主从同步状态:
# \G 可以将横向的结果集表格转换成纵向展示。 # slave status的字段比较多,纵向展示比友好 show slave status \G;
除了展示刚刚配置的主数据库信息外,主要关注 Slave_IO_Running
、
Slave_SQL_Running
。目前两个值应该都为 No
,表示还没有开始。
- 开启主从同步:
start slave;
- 再次查看主从同步状态,
Slave_IO_Running
、Slave_SQL_Running
都变为Yes
。
主从复制测试:
- 在主数据库上新建库、使用库、新建表、插入数据
create database db01; use db01; create table t1 (id int, name varchar(20)); insert into t1 values (1, 'abc');
- 在从数据库上使用库、查看记录
show databases; use db01; select * from t1;
Docker安装Redis
以 Redis 6.0.8 为例:
docker pull redis:6.0.8
单机版安装
实际应用版Redis
配置文件、数据文件都和容器卷进行映射。
步骤:
- 宿主机创建目录
/app/redis
- 在
/app/redis
下创建文件redis.conf
,主要修改以下几项配置
# 开启密码验证(可选) requirepass snow # 允许redis外地连接,需要注释掉绑定的IP # bind 127.0.0.1 # 关闭保护模式(可选) protected-mode no # 注释掉daemonize yes,或者配置成 daemonize no。因为该配置和 docker run中的 -d 参数冲突,会导致容器一直启动失败 daemonize no # 开启redis数据持久化, (可选) appendonly yes
即最后的配置文件为:
- 启动docker容器:(因为要使用自定义的配置文件,所以需要指定容器运行的命令为
redis-server 容器内配置文件路径
)
docker run -d -p 6379:6379 --name redis --privileged=true \ -v /app/redis/redis.conf:/etc/redis/redis.conf \ -v /app/redis/data:/data \ redis:6.0.8 \ redis-server /etc/redis/redis.conf
参数说明:
–privileged=true -> privileged关键字是docker 0.6版本中引入docker 使用该参数 container内的root拥有真正的root权限。 否则,container内的root只是外部的一个普通用户权限。
集群存储算法
分布式存储算法
分布式存储的常见算法:
- 哈希取余算法分区
- 一致性哈希算法分区
- 哈希槽算法分区
哈希取余算法
算法描述:hash(key) % N
(其中,key
是要存入Redis的键名,N
是Redis集群的机器台数)。用户每次读写操作,都是根据传入的键名经过哈希运算,对机器台数取余决定该键存储在哪台服务器上。
优点:简单直接有效,只需要预估好数据规划好节点,就能保证一段时间的数据支撑。使用Hash算法让固定的一部分请求落到同一台服务器上,这样每台服务器固定处理一部分请求(并维护这些请求的信息),起到负载均衡+分而治之的作用。
缺点:原来规划好的节点,如果进行了扩容或者缩容,导致节点有变动,映射关系需要重新进行计算。在服务器个数固定不变时没问题,如果需要弹性扩容或者故障停机的情况下,原来取模公式中的 N就会发生变化,此时经过取模运算的结果就会发生很大变化,导致根据公式获取的服务器变得不可控。
一致性哈希算法
算法背景:一致性哈希算法是为了解决哈希取余算法中的分布式缓存数据变动和映射问题。当服务器个数发生变化时,尽量减少影响到客户端与服务器的映射关系。
算法描述:
一致性哈希算法必然有个hash函数并按照算法产生Hash值,这个算法的所有可能哈希值会构成一个全量集,这个集合可以成为一个Hash区间[0, 2^32 - 1],这是一个线性空间。但是在这个算法中,我们通过适当的逻辑控制将它首尾相连(0 = 2^32),这样让它逻辑上形成了一个环形空间。
它也是按照使用取模的方式。前面的哈希取余算法是对节点个数进行取模,而一致性哈希算法是对 2^32取模。
简单来说,一致性Hash算法将整个哈希值空间组成一个虚拟的圆环。如假设某个哈希函数H的值空间为 0到2^32 - 1(即哈希值是一个32位无符号整形),整个哈希环如下图:整个空间按顺时针方向组织,圆环的正上方的点代表0,0点右侧的第一个点代表1,以此类推,2、3、4…直到2^32 - 1,也就是说0点左侧的第一个点代表 2^32 - 1。0 和 2^32 - 1在零点钟方向重合,我们把这个由 2^32个点组成的圆环称为Hash环。
有了哈希环之后,还需要进行节点映射,将集群中各个IP节点映射到环上的某一个位置。
将各个服务器使用Hash进行一个哈希,具体可以选择服务器的IP或主机名作为关键字进行哈希。这样每台机器就能确定其在哈希环上的位置。
假如4个节点NodeA、B、C、D,经过IP地址的哈希函数计算(hash(ip)),使用IP地址哈希值后在环空间的位置如下:
key落到服务器的落键规则。当我们需要存储一个key键值对时,首先计算key的hash值(hash(key)),将这个key使用相同的函数hash,计算出哈希值并确定此数据在环上的位置,从此位置沿环顺时针“行走”,第一台遇到的服务器就是其应该定位到的服务器,并将该键值对存储字该节点上。
假如我们有ObjectA、B、C、D四个数据对象,经过哈希计算后,在环空间上的位置如下:根据一致性hash算法,数据A会被定位到NodeA上,B被定位到NodeB上,C被定位到NodeC上,D被定位到NodeD上。
假设NodeC宕机,可以看到此时对象A、B、D不会受到影响,只有C对象被重新定位到NodeD。
一般的,在一致性Hash算法中,如果一台服务器不可用,则受影响的数据仅仅是此服务器到其环空间中前一台服务器(即沿着逆时针方向行走遇到的第一台服务器)之间的数据,其他不会受到影响。
即:假设NodeC宕机,只会影响到Hash定位到NodeB到NodeC之间的数据,并且这些数据会被转移到NodeD进行存储。
假如需要扩容增加一台节点NodeX,NodeX的hash(ip)位于NodeB和NodeC之间,那受到影响的就是NodeB 到 NodeX 之间的数据。重新将B到X的数据录入到X节点上即可,不会导致Hash取余全部数据重新洗牌的后果。
但是Hash环会存在数据倾斜问题。
一致性Hash算法在服务节点太少时,容易因为节点分布不均匀而造成数据倾斜(被缓存的对象都集中到某一台或某几台服务器)。
为了解决数据倾斜问题,一致性哈希算法引入了虚拟节点机制。
对每一个服务节点计算多个哈希,每个计算结果位置都放置一个此服务节点,称为虚拟节点。具体做法可以先确定每个物理节点关联的虚拟节点数量,然后在IP或主机名后面加上编号。
例如,可以对NodeA节点虚拟出 NodeA#1、NodeA#2、NodeA#3,对NodeB虚拟出NodeB#1、NodeB#2、NodeB#3的节点,形成六个虚拟节点。
优点:加入和删除节点时,只会影响哈希环中顺时针方向相邻节点,对其他节点无影响。
缺点:数据的分布和节点的位置有关,因为这些节点不是均匀分布在哈希环上的,所以在数据进行存储时达不到均匀部分的效果。