如何进行不同数据库的集群操作?--从部署谈起,今天来看MySQL和NoSql数据库Redis的集群
篇幅较长,主要分为mysql和Redis两部分。找想要的部分可见目录食用。。
目录
什么是集群?为什么要集群?
1.1 数据库主要分为两大类:关系型数据库与 NoSQL 数据库
1.2 为什么还要用 NoSQL 数据库呢?
-------------------华丽分割线--------------
一、关系型数据库MySQL
1.部署mysql
1.1安装依赖
1.2下载解压源码包
1.3源码编译安装
1.4部署mysql
测试安装效果:
集群方式
mysql的主从复制模式:
异步复制
实验1:添加slave1
1.环境配置
编辑
2.开启slave,测试:
实验2:在有数据的情况下添加slave2
1.环境配置
2.测试
实验3:延迟复制
实验4:慢查询日志
编辑
实验5:并行复制
测试:
半同步复制
1.gtid模式
2.半同步模式
组复制(高可用)
组复制的流程图:
实验
1.初始化数据库数据,防止出现问题
2.向本地解析文件中配置其他几台主机内容
3.配置sql内容
4.配置另外两台
5测试
MySQL路由
MySQL-router的部署方式
测试
MySQL高可用--MHA
1.MHA简介
2.MHA的部署
(1)搭建主两从架构
(2)安装MHA所需要的软件
编辑
(3)配置MHA管理环境
1.生成配置目录和配置文件
2.编写一个配置文件
2.检测配置
3.MHA故障切换
(1)master未出现故障手动切换
编辑
(2)master出现故障手动切换
编辑
(3)自动切换
4.添加VIP功能
二、Redis非关系型数据库
1.Redis特点
2.Redis应用场景
3.缓存的实现流程
数据更新操作流程
数据读操作流程
4.Redis的安装
4.1.rpm包方式安装
4.2.源码安装
4.3.基本操作
(1)查看配置(红色是命令,黄色是结果)
(2)写入和读取数据
(3)选择数据库 Redis中有0-15个数据库
(4)改变键名
(5)设定数据过期时间 / 持久化(设置时间版)保持
(6)删除
(7)判断key的存在
(8)清空当前库
(9)清空所有库
5.Redis主从复制
5.1.环境
5.2.配置主从同步
(1)修改master节点的配置文件
(2)配置slave节点
(3)测试
6.Redis的哨兵(高可用)
6.1.哨兵的实验过程
6.2架构缺陷
7.Redis Cluster(无中心化设计)
7.1.工作原理
7.2创建Redis Cluster的要求
7.3部署Redis Cluster
7.4集群扩容
7.5集群维护
总结
什么是集群?为什么要集群?
- 通俗一点来说,就是让若干台计算机联合起来工作 (服务),可以是并行的,也可以是做备份。
- 数据库集群的特征就是 有多台机器,这多台机器上都有数据库, 这些数据库的数据是完全一样的,即相当于一套数据的多个副本。集群就是要保证这些副本的实时或准时实(可以延时一会)的同步,即如果一台机器上的数据更改时,集群系统要保证这个更改实时或准时实的应用到所有的机器上,实现数据同步。
集群主要解决两个问题:
- 负载均衡:这个主要是解决访问量大的问题。一台机器的读写能力是有限的,当同时有大量用户访问的时候,仅一台机器可能就会因负载过大而垮掉。而使用集群后,集群系统会将访问量均衡到每台机器上,也即多台机器分担了访问量,这就达到了负载均衡的目的。
- 当机:当只有一台机器时,如果这台机器因意外当机会需要停机维护,那么此时系统就不能访问,对于一些使用量大,使用频繁的系统而言,这样是肯定不行的。如果使用集群,只有集群中有一台机器还在运行,就能让系统继续运行下去,而且对于重新启动的机器,能很快的同步在停机时间用户所做的更改。我的当前公司很喜欢用顶这个词,当一台机器垮掉时,能立马有另一台机器顶上。
1.1 数据库主要分为两大类:关系型数据库与 NoSQL 数据库
- 关系型数据库,是建立在关系模型基础上的数据库,其借助于集合代数等数学概念和方法来处理数据库 中的数据主流的 MySQL、Oracle、MS SQL Server 和 DB2 都属于这类传统数据库。
- NoSQL 数据库,全称为 Not Only SQL,意思就是适用关系型数据库的时候就使用关系型数据库,不适 用的时候也没有必要非使用关系型数据库不可,可以考虑使用更加合适的数据存储。主要分为临时性键 值存储(memcached、Redis)、永久性键值存储(ROMA、Redis)、面向文档的数据库 (MongoDB、CouchDB)、面向列的数据库(Cassandra、HBase),每种 NoSQL 都有其特有的使用 场景及优点。
1.2 为什么还要用 NoSQL 数据库呢?
主要是由于随着互联网发展,数据量越来越大,对性能要求越来越高,传统数据库存在着先天性的缺 陷,即单机(单库)性能瓶颈,并且扩展困难。这样既有单机单库瓶颈,却又扩展困难,自然无法满足 日益增长的海量数据存储及其性能要求,所以才会出现了各种不同的 NoSQL 产品,NoSQL 根本性的优势在于在云计算时代,简单、易于大规模分布式扩展,并且读写性能非常高
-------------------华丽分割线--------------
实验环境:
- vmware支持的redhat7.9虚拟机若干(做MySQL)9.4虚拟机若干台(做Redis)
- 虚拟机可联网,无其他操作的全新环境
- 虚拟机每一个都可以进行yum下载,拥有顺畅下载的本地仓库
- 关闭防火墙,selinux
一、关系型数据库MySQL
如果你安装的redhat7.9是带图形化的可以利用以下命令禁掉:
systemctl set-default multi-user.target #这条命令会永久关闭图形化
reboot #重启即可
1.部署mysql
- 在企业中90%的服务器操作系统均为Linux
- 在企业中对于Mysql的安装通常用源码编译的方式来进行(源码编译相比软件安装其可拓展性,功能性更强,对于使用者来说也更加灵活)
步骤:
- 安装依赖
- 下载解压源码包
- 源码编译安装mysql
- 使用部署
1.1安装依赖
yum install cmake gcc-c++ openssl-devel \ ncurses-devel.x86_64 libtirpc-devel-1.3.3-8.el9_4.x86_64.rpm rpcgen.x86_64 -y
1.2下载解压源码包
可自行去官网查找包,用xftp传输(速度快)
1.3源码编译安装
这一步时间比较漫长,稍作等待
[root@mysql-node10 mysql-5.7.44]# cmake \
-DCMAKE_INSTALL_PREFIX=/usr/local/mysql \ #指定安装路径
-DMYSQL_DATADIR=/data/mysql \ #指定数据目录
-DMYSQL_UNIX_ADDR=/data/mysql/mysql.sock \ #指定套接字文件
-DWITH_INNOBASE_STORAGE_ENGINE=1 \ #指定启用INNODB存储引擎,默认用myisam
-DWITH_EXTRA_CHARSETS=all \ #扩展字符集
-DDEFAULT_CHARSET=utf8mb4 \ #指定默认字符集
-DDEFAULT_COLLATION=utf8mb4_unicode_ci \ #指定默认校验字符集
-DWITH_BOOST=/root/mysql-5.7.44/boost/boost_1_59_0/ #指定c++库依赖[root@mysql-node10 mysql-5.7.44]# make -j2 #-j2 表示有几个核心就跑几个进程
[root@mysql-node10 mysql-5.7.44# make install
出现以下画面说明就成功下载中了:
这一步出现问题的小伙伴看这里:
切记要删除缓存再重新检测
1.4部署mysql
mkdir /data/mysql/
chown -R /data/mysql/#生成启动脚本
[root@node10 ~]# cd /usr/local/mysql/support-files/
[root@node10 support-files]# cp mysql.server /etc/init.d/mysqld#修改环境变量
[root@node10 ~]# vim ~/.bash_profile
export PATH=$PATH:/usr/local/mysql/bin
[root@node10 ~]# source ~/.bash_profile#生成配置文件
[root@node10 my.cnf.d]# vim /etc/my.cnf
[mysqld]
datadir=/data/mysql #指定数据目录
socket=/data/mysql/mysql.sock #指定套接字
symbolic-links=0 #数据只能存放到数据目录中,禁止链接到数据目录#数据库初始化建立mysql基本数据
[root@node10 ~]# mysqld --initialize --user=mysql
[root@node10 ~]# /etc/init.d/mysqld start#数据库安全初始化
[root@node10 ~]# mysql_secure_installationEnter password for user root: #输入当前密码
New password: #输入新密码
Re-enter new password: #重复密码Press y|Y for Yes, any other key for No: no #是否启用密码插件Change the password for root ? ((Press y|Y for Yes, any other key for No) : no
#是否要重置密码Remove anonymous users? (Press y|Y for Yes, any other key for No) : yDisallow root login remotely? (Press y|Y for Yes, any other key for No) : yRemove test database and access to it? (Press y|Y for Yes, any other key for No) : yReload privilege tables now? (Press y|Y for Yes, any other key for No) : y
测试安装效果:
(如下图则安装完成)
集群方式
mysql的主从复制模式:
异步复制
MySQL异步复制是主从复制过程中默认的复制模式。主从复制涉及三个线程,master I/O线程、slave I/O线程、slave sql线程。因为是异步复制,所以master事务的提交,不需要经过slave的确认,即master I/O线程提交事务后,不需要等待slave I/O线程的回复确认,master并不保证binlog一定写入到了relay log中;而slave I/O把binlog写入relay log后,由slave sql线程异步执行应用到slave mysql中,slave I/O也不需要slave sql的回复确认,并不保证relay log日志完整写入到了mysql中。
实验1:添加slave1
1.环境配置
主机名称 | ip | 角色 |
mysql-node1 | 172.25.254.10 | master |
mysql-node2 | 172.25.254,20 | slave |
配置master[root@mysql-node10 ~]# vim /etc/my.cnf
[mysqld]
datadir=/data/mysql
socket=/data/mysql/mysql.sock
symbolic-links=0
log-bin=mysql-bin #添加
server-id=1 #添加[root@mysql-node10 ~]# /etc/init.d/mysqld restart #进入数据库配置用户权限
[root@mysql-node10 ~]# mysql -plee##生成专门用来做复制的用户,此用户是用于slave端做认证用
mysql> CREATE USER 'repl'@'%' IDENTIFIED BY 'lee';
mysql> GRANT REPLICATION SLAVE ON *.* TO repl@'%'; ##对这个用户进行授权配置slave[root@mysql-node2 ~]# vim /etc/my.cnf
[mysqld]
datadir=/data/mysql
socket=/data/mysql/mysql.sock
symbolic-links=0
server-id=2 #添加[root@mysql-node2 ~]# /etc/init.d/mysqld restart
[root@mysql-node2 ~]# mysql -plee
定位mysql-node2
2.开启slave,测试:
定位mysql-node1
实验2:在有数据的情况下添加slave2
1.环境配置
主机名称 | ip | 角色 |
mysql-node1 | 172.25.254.10 | master |
mysql-node2 | 172.25.254,20 | slave1 |
mysql-node3 | 172.25.254.30 | slave2 |
#完成基础配置
[root@mysql-node3 ~]# vim /etc/my.cnf
[mysqld]
datadir=/data/mysql
socket=/data/mysql/mysql.sock
symbolic-links=0
server-id=3
[root@mysql-node3 ~]# /etc/init.d/mysqld restart
跟实验1稍有不同,这里需要先从master节点备份数据(在企业中备份需要锁表以保证备份前后的数据一致)
[root@mysql-node1 ~]# mysqldump -uroot -plee lee > lee.sql
因为此时的mysql-node3中没有任何数据,所以需要拉平数据。
#利用master节点中备份出来的lee.sql在slave2中拉平数据
[root@mysql-node3 ~]# mysql -uroot -plee -e "create database lee;"
[root@mysql-node3 ~]# mysql -uroot -p lee < lee.sql
[roort@mysql-node3~]#mysql -uroot -plee -e "select * from lee.userlist;"
配置slave2的功能(同实验一)
注意:master的状态可能会发生改变,要查了之后里面立马配置slave
[root@mysql-node3 ~]# mysql -uroot -plee
mysql> CHANGE MASTER TO
MASTER_HOST='172.25.254.10',
MASTER_USER='repl',
MASTER_PASSWORD='lee',
MASTER_LOG_FILE='mysql-bin.000001',
MASTER_LOG_POS=1251;
mysql> start slave; #开启slave功能
mysql> SHOW SLAVE STATUS\G; #查看配置是否成功
2.测试
在mysql-node1中向表lee.userlist插入数据,看两个从机是否同步
mysql> insert into lee.userlist values('五条悟','555');
实验3:延迟复制
#在slave端(随便开一台)
mysql> STOP SLAVE SQL_THREAD;
mysql> CHANGE MASTER TO MASTER_DELAY=60; #设置延迟时间
mysql> START SLAVE SQL_THREAD;
mysql> SHOW SLAVE STATUS\G;Master_Server_Id: 1Master_UUID: db2d8c92-4dc2-11ef-b6b0-000c299355eaMaster_Info_File: /data/mysql/master.infoSQL_Delay: 60 ##延迟效果SQL_Remaining_Delay: NULLSlave_SQL_Running_State: Slave has read all relay log; waiting for more
updatesMaster_Retry_Count: 86400
测试: 在master中写入数据后过了延迟时间才能被查询到
实验4:慢查询日志
当执行SQL超过long_query_time参数设定的时间阈值(默认10s)时,就被认为是慢查询,这个 SQL语句就是需要优化的
慢查询被记录在慢查询日志里 ,慢查询日志默认是不开启的 。如果需要优化SQL语句,就可以开启这个功能,它可以让你很容易地知道哪些语句是需要优化的。
未开启状态:
开启慢查询:
mysql> SET GLOBAL slow_query_log=ON;
mysql> SET long_query_time=4;
mysql> SHOW VARIABLES like "slow%";
cat /data/mysql/mysql-node1-slow.log
可以看到日志内容:
实验5:并行复制
默认情况下slave中使用的是sql单线程回放
在master中时多用户读写,如果使用sql单线程回放那么会造成主从延迟严重
开启MySQL的多线程回放可以解决上述问题
在slaves中设定[root@mysql-node2 ~]# vim /etc/my.cnf
[mysqld]
datadir=/data/mysql
socket=/data/mysql/mysql.sock
server-id=2
gtid_mode=ON
enforce-gtid-consistency=ON
slave-parallel-type=LOGICAL_CLOCK #基于组提交,
slave-parallel-workers=16 #开启线程数量#master信息在表中记录,默认记录在/data/mysql//master.info
master_info_repository=TABLE
relay_log_info_repository=TABLE
relay_log_recovery=ON #日志回放恢复功能开启[root@mysql-node2 ~]# /etc/init.d/mysql start
测试:
此时sql线程转化为协调线程,16个worker负责处理sql协调线程发送过来的处理请求
半同步复制
基于传统异步存在的缺陷,mysql在5.5版本推出半同步复制,是对传统异步复制的改进。在master事务commit前,必须确保binlog日志已经写入slave 的relay log日志中,收到slave给master的响应后,才能进行事务的commit。但是后半部分的relay log到sql线程仍然属于异步执行。
1.gtid模式
当为启用gtid时我们要考虑的问题 在master端的写入时多用户读写,在slave端的复制时单线程日志回放,所以slave端一定会延迟与 master端
这种延迟在slave端的延迟可能会不一致,当master挂掉后slave接管,一般会挑选一个和master延迟日 志最接近的充当新的master 那么为接管master的主机继续充当slave角色并会指向到新master上,作为其slave 这时候按照之前的配置我们需要知道新的master上的pos的id,但是我们无法确定新的master和slave之间差多少
当激活GITD之后
当master出现问题后,slave2和master的数据最接近,会被作为新的master slave1指向新的master,但是他不会去检测新的master的pos id,只需要继续读取自己gtid_next即可
#在master端和slave端开启gtid模式[root@mysql-node1 ~]# vim /etc/my.cnf
[mysqld]
datadir=/data/mysql
socket=/data/mysql/mysql.sock
server-id=1
log-bin=mysql-bin
gtid_mode=ON
enforce-gtid-consistency=ON
symbolic-links=0[root@mysql-node1 ~]# /etc/init.d/mysqld restart
[root@mysql-node2 ~]# vim /etc/my.cnf
[mysqld]
datadir=/data/mysql
socket=/data/mysql/mysql.sock
server-id=2
log-bin=mysql-bin
gtid_mode=ON
enforce-gtid-consistency=ON
symbolic-links=0[root@mysql-node2 ~]# /etc/init.d/mysqld restart
[root@mysql-node3 ~]# vim /etc/my.cnf
[mysqld]
datadir=/data/mysql
socket=/data/mysql/mysql.sock
server-id=3
log-bin=mysql-bin
gtid_mode=ON
enforce-gtid-consistency=ON
symbolic-links=0[root@mysql-node3 ~]# /etc/init.d/mysqld restart#停止slave端
[root@mysql-node2 ~]# mysql -p
mysql> stop slave;[root@mysql-node3 ~]# mysql -p
mysql> stop slave;#开启slave端的gtid
mysql> CHANGE MASTER TO MASTER_HOST='172.25.254.10', MASTER_USER='repl',
MASTER_PASSWORD='lee', MASTER_AUTO_POSITION=1;
2.半同步模式
定位master端 配置版同步模式
[root@mysql-node1 ~]# vim /etc/my.cnf //配置文件内容
[mysqld]
datadir=/data/mysql
socket=/data/mysql/mysql.sock
server-id=1
log-bin=mysql-bin
gtid_mode=ON
enforce-gtid-consistency=ON
rpl_semi_sync_master_enabled=1
symbolic-links=0
进入mysql安装办同步插件
[root@mysql-node1 ~]# mysql -p lee
mysql> INSTALL PLUGIN rpl_semi_sync_master SONAME 'semisync_master.so';
#查看插件情况
mysql> SELECT PLUGIN_NAME, PLUGIN_STATUS
-> FROM INFORMATION_SCHEMA.PLUGINS
-> WHERE PLUGIN_NAME LIKE '%semi%';
#打开半同步功能
mysql> SET GLOBAL rpl_semi_sync_master_enabled = 1;
#查看半同步功能状态
mysql> SHOW VARIABLES LIKE 'rpl_semi_sync%';
mysql> SHOW STATUS LIKE 'Rpl_semi_sync%';
mysql> show plugins
定位mysql-node2
#配置文件内容
[root@mysql-node2 ~]# vim /etc/my.cnf
[mysqld]
datadir=/data/mysql
socket=/data/mysql/mysql.sock
server-id=1
log-bin=mysql-bin
gtid_mode=ON
enforce-gtid-consistency=ON
rpl_semi_sync_master_enabled=1 #开启半同步功能
symbolic-links=0
进入mysql 进行操作
[root@mysql-node2 ~]# mysql -plee
mysql> INSTALL PLUGIN rpl_semi_sync_slave SONAME 'semisync_slave.so';
mysql> SET GLOBAL rpl_semi_sync_slave_enabled =1;
mysql> STOP SLAVE IO_THREAD; #重启io线程,半同步才能生效
mysql> START SLAVE IO_THREAD; ##重启io线程,半同步才能生效
mysql> SHOW VARIABLES LIKE 'rpl_semi_sync%';
mysql> SHOW STATUS LIKE 'Rpl_semi_sync%';
测试
mysql> SHOW STATUS LIKE 'Rpl_semi_sync%';
+--------------------------------------------+-------+
| Variable_name | Value |
+--------------------------------------------+-------+
| Rpl_semi_sync_master_clients | 2 |
| Rpl_semi_sync_master_net_avg_wait_time | 0 |
| Rpl_semi_sync_master_net_wait_time | 0 |
| Rpl_semi_sync_master_net_waits | 2 |
| Rpl_semi_sync_master_no_times | 0 |
| Rpl_semi_sync_master_no_tx | 0 | #未同步数据0笔
| Rpl_semi_sync_master_status | ON |
| Rpl_semi_sync_master_timefunc_failures | 0 |
| Rpl_semi_sync_master_tx_avg_wait_time | 981 |
| Rpl_semi_sync_master_tx_wait_time | 981 |
| Rpl_semi_sync_master_tx_waits | 1 |
| Rpl_semi_sync_master_wait_pos_backtraverse | 0 |
| Rpl_semi_sync_master_wait_sessions | 0 |
| Rpl_semi_sync_master_yes_tx | 1 | #已同步数据1笔
+--------------------------------------------+-------+
14 rows in set (0.00 sec)
模拟故障
定位mysql-node2,mysql-node3,关闭io线程
[root@mysql-node2 ~]# mysql -plee
mysql> STOP SLAVE IO_THREAD;
[root@mysql-node3 ~]# mysql -plee
mysql> STOP SLAVE IO_THREAD;
定位master端 插入数据
mysql> insert into lee.userlist values ('user5','555');
Query OK, 1 row affected (10.00 sec) #10秒超时
mysql> SHOW STATUS LIKE 'Rpl_semi%';
+--------------------------------------------+-------+
| Variable_name | Value |
+--------------------------------------------+-------+
| Rpl_semi_sync_master_clients | 0 |
| Rpl_semi_sync_master_net_avg_wait_time | 0 |
| Rpl_semi_sync_master_net_wait_time | 0 |
| Rpl_semi_sync_master_net_waits | 2 |
| Rpl_semi_sync_master_no_times | 1 |
| Rpl_semi_sync_master_no_tx | 1 | #一笔数据为同步
| Rpl_semi_sync_master_status | OFF | #自动转为异步模式,当
slave恢复
| Rpl_semi_sync_master_timefunc_failures | 0 | #会自动恢复
| Rpl_semi_sync_master_tx_avg_wait_time | 981 |
| Rpl_semi_sync_master_tx_wait_time | 981 |
| Rpl_semi_sync_master_tx_waits | 1 |
| Rpl_semi_sync_master_wait_pos_backtraverse | 0 |
| Rpl_semi_sync_master_wait_sessions | 0 |
| Rpl_semi_sync_master_yes_tx | 1 |
+--------------------------------------------+-------+
组复制(高可用)
基于传统异步复制和半同步复制的缺陷——数据的一致性问题无法保证,MySQL官方在5.7.17版本正式推出组复制(MySQL Group Replication,简称MGR)。
由若干个节点共同组成一个复制组,一个事务的提交,必须经过组内大多数节点(N / 2 + 1)决议并通过,才能得以提交。如上图所示,由3个节点组成一个复制组,Consensus层为一致性协议层,在事务提交过程中,发生组间通讯,由2个节点决议(certify)通过这个事务,事务才能够最终得以提交并响应。
引入组复制,主要是为了解决传统异步复制和半同步复制可能产生数据不一致的问题。组复制依靠分布式一致性协议(Paxos协议的变体),实现了分布式下数据的最终一致性,提供了真正的数据高可用方案(是否真正高可用还有待商榷)。其提供的多写方案,给我们实现多活方案带来了希望。
MGR环境下,服务器数量必须是3台以上,并且是单数,实现2/n+1的算法。
组复制的流程图:
注意:节点数量不能超过9台
实验
环境
主机名称 | ip | 角色 |
mysql-node1 | 172.25.254.10 | master |
mysql-node2 | 172.25.254,20 | slave1 |
mysql-node3 | 172.25.254.30 | slave2 |
1.初始化数据库数据,防止出现问题
#在mysql-node1中
rm -fr /data/mysql/* #删除这个目录下的内容
[root@mysql-node1 ~]# vim /etc/my.cnf #编辑配置内容
2.向本地解析文件中配置其他几台主机内容
3.配置sql内容
[root@mysql-node1 ~]# mysqld --user=mysql --initialize
[root@mysql-node1 ~]# /etc/init.d/mysqld start
[root@mysql-node1 ~]# mysql -uroot -p初始化后生成的密码 -e "alter user root@localhost identified by 'lee';"进入mysql配置[root@mysql-node10 ~]# mysql -plee
mysql> SET SQL_LOG_BIN=0;mysql> CREATE USER rpl_user@'%' IDENTIFIED BY 'lee';mysql> GRANT REPLICATION SLAVE ON *.* TO rpl_user@'%';mysql> FLUSH PRIVILEGES;mysql> SET SQL_LOG_BIN=1;mysql> CHANGE MASTER TO MASTER_USER='rpl_user', MASTER_PASSWORD='lee' FOR CHANNEL
'group_replication_recovery';mysql> START GROUP_REPLICATION;mysql> SELECT * FROM performance_schema.replication_group_members;
投个小懒,提高效率:
[root@mysql-node2 & 3 ~]# scp /etc/my.cnf root@172.25.254.20:/etc/my.cnf
[root@mysql-node2 & 3 ~]# scp /etc/my.cnf root@172.25.254.30:/etc/my.cnf
4.配置另外两台
#修改mysql—node2和mysl-node3中的配置[root@mysql-node2 & 3 ~]# rm -fr/data/mysql/
[root@mysql-node1 ~]# vim /etc/my.cnf
[mysqld]
datadir=/data/mysql
socket=/data/mysql/mysql.sock
symbolic-links=0
server-id=2 #在3上写3
disabled_storage_engines="MyISAM,BLACKHOLE,FEDERATED,ARCHIVE,MEMORY"
gtid_mode=ON
enforce_gtid_consistency=ON
master_info_repository=TABLE
relay_log_info_repository=TABLE
binlog_checksum=NONE
log_slave_updates=ON
log_bin=binlog
binlog_format=ROW
plugin_load_add='group_replication.so'
transaction_write_set_extraction=XXHASH64
group_replication_group_name="aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa"
group_replication_start_on_boot=off
group_replication_local_address="172.25.254.20:33061" #在3上要写30
group_replication_group_seeds="172.25.254.10:33061,172.25.254.20:33061,
172.25.254.30:33061"
group_replication_ip_whitelist="172.25.254.0/24,127.0.0.1/8"
group_replication_bootstrap_group=off
group_replication_single_primary_mode=OFF
group_replication_enforce_update_everywhere_checks=ON
group_replication_allow_local_disjoint_gtids_join=1
[root@mysql-node1 ~]# mysqld --user=mysql --initialize
[root@mysql-node1 ~]# /etc/init.d/mysqld start
[root@mysql-node1 ~]# mysql -uroot -p初始化后生成的密码 -e "alter user
root@localhost identified by 'lee';"#配置sql[root@mysql-node2 & 3 ~]# mysql -plee
mysql> SET SQL_LOG_BIN=0;mysql> CREATE USER rpl_user@'%' IDENTIFIED BY 'lee';mysql> GRANT REPLICATION SLAVE ON *.* TO rpl_user@'%';mysql> FLUSH PRIVILEGES;mysql> SET SQL_LOG_BIN=1;mysql> CHANGE MASTER TO MASTER_USER='rpl_user', MASTER_PASSWORD='lee' FOR CHANNEL
'group_replication_recovery';mysql> START GROUP_REPLICATION;mysql> SELECT * FROM performance_schema.replication_group_members;
5测试
#在mysql-node1中
[root@mysql-node1 ~]# mysql -pmysql> CREATE DATABASE lee;mysql> CREATE TABLE lee.userlist(-> username VARCHAR(10) PRIMARY KEY NOT NULL,-> password VARCHAR(50) NOT NULL-> );mysql> INSERT INTO lee.userlist VALUES ('user1','111');mysql> SELECT * FROM lee.userlist;
+----------+----------+
| username | password |
+----------+----------+
| user1 | 111 |
+----------+----------+#在mysql-node2中
[root@mysql-node2 ~]# mysql -pmysql> INSERT INTO lee.userlist values ('user2','222');mysql> select * from lee.userlist;
+----------+----------+
| username | password |
+----------+----------+
| user1 | 111 |
| user2 | 222 |
+----------+----------+#mysql—node3中
[root@mysql-node3 ~]# mysql -pmysql> INSERT INTO lee.userlist values ('user3','333');mysql> select * from lee.userlist;
+----------+----------+
| username | password |
+----------+----------+
| user1 | 111 |
| user2 | 222 |
| user3 | 333 |
+----------+----------+
MySQL路由
mysql-router是一个对应用程序透明的InnoDB Cluster连接路由服务,提供负载均衡、应用连接故障转移和客户端路 由。 利用路由器的连接路由特性,用户可以编写应用程序来连接到路由器,并令路由器使用相应的路由策略来处理连接,使其连接到正确的MySQL数据库服务器。
MySQL-router的部署方式
主机名称 | ip | 角色 |
mysql-node1 | 172.25.254.10 | master |
mysql-node2 | 172.25.254,20 | slave1 |
mysql-node3 | 172.25.254.30 | slave2 |
mysql-node4 | 172.25.254.40 | router |
定位router端
#安装mysql-router
[root@mysql-router ~]# rpm -ivh mysql-router-community-8.4.0-1.el7.x86_64.rpm
#配置mysql-router
[root@mysql-router ~]# vim /etc/mysqlrouter/mysqlrouter.conf
[routing:ro]
bind_address = 0.0.0.0
bind_port = 7001
destinations = 172.25.254.10:3306,172.25.254.20:3306,172.25.254.30:3306 routing_strategy = round-robin
[routing:rw]
bind_address = 0.0.0.0
bind_port = 7002
destinations = 172.25.254.30:3306,172.25.254.20:3306,172.25.254.10:3306 routing_strategy = first-available
[root@mysql-router ~]# systemctl start mysqlrouter.service
测试
#建立测试用户
mysql> CREATE USER lee@'%' IDENTIFIED BY 'lee';
mysql> GRANT ALL ON lee.* TO lee@'%';
#查看调度效果
[root@mysql-node10 & 20 & 30 ~]# watch -1 lsof -i :3306
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
mysqld 9879 mysql 22u IPv6 56697 0t0 TCP *:mysql (LISTEN)
[root@mysql-router ~]# mysql -ulee -plee -h 172.25.254.40 -P 7001
通过最后一行命令查看是否可以登录上指定的数据库,登录上则mysql-router成功,否则失败。查看日志排错。
MySQL高可用--MHA
1.MHA简介
什么是MHA?
- MHA(Master High Availability)是一套优秀的MySQL高可用环境下故障切换和主从复制的软件。
- MHA 的出现就是解决MySQL 单点的问题。
- MySQL故障切换过程中,MHA能做到0-30秒内自动完成故障切换操作。
- MHA能在故障切换的过程中最大程度上保证数据的一致性,以达到真正意义上的高可用。
MHA的特点是什么?
- 自动故障切换过程中,MHA从宕机的主服务器上保存二进制日志,最大程度的保证数据不丢失
- 使用半同步复制,可以大大降低数据丢失的风险,如果只有一个slave已经收到了最新的二进制日 志,MHA可以将最新的二进制日志应用于其他所有的slave服务器上,因此可以保证所有节点的数 据一致性
- 目前MHA支持一主多从架构,最少三台服务,即一主两从
MHA的工作原理?
- 目前MHA主要支持一主多从的架构,要搭建MHA,要求一个复制集群必须最少有3台数据库服务器, 一主二从,即一台充当Master,台充当备用Master,另一台充当从库。
- MHA Node 运行在每台 MySQL 服务器上
- MHAManager 会定时探测集群中的master 节点
- 当master 出现故障时,它可以自动将最新数据的slave 提升为新的master 然后将所有其他的slave 重新指向新的master,VIP自动漂移到新的master。
- 整个故障转移过程对应用程序完全透明。
2.MHA的部署
环境
主机名称 | ip | 角色 |
mysql-node1 | 172.25.254.10 | master |
mysql-node2 | 172.25.254,20 172.25.254.11 | slave1 第二个临时ip做检测用 |
mysql-node3 | 172.25.254.30 | slave2 |
mysql-MHA | 172.25.254.50 | MHA |
(1)搭建主两从架构
#在master节点中
[root@mysql-node1 ~]# /etc/init.d/mysqld stop
[root@mysql-node1 ~]# rm -fr /data/mysql/* #删除之前的数据
[root@mysql-node1 ~]# vim /etc/my.cnf
[mysqld]
datadir=/data/mysql
socket=/data/mysql/mysql.sock
server-id=1
log-bin=mysql-bin
gtid_mode=ON
log_slave_updates=ON #这一行一定要写进去 因为在后面做MHA检测的时候必须要有否则报错
enforce-gtid-consistency=ON
symbolic-links=0[root@mysql-node1 ~]# mysqld --user mysql --initialize #初始化
[root@mysql-node1 ~]# /etc/init.d/mysqld start
[root@mysql-node1 ~]# mysql_secure_installation
[root@mysql-node1 ~]# mysql -p
mysql> CREATE USER 'repl'@'%' IDENTIFIED BY 'lee';mysql> GRANT REPLICATION SLAVE ON *.* TO repl@'%';mysql> INSTALL PLUGIN rpl_semi_sync_master SONAME 'semisync_master.so';mysql> SET GLOBAL rpl_semi_sync_master_enabled = 1;
做好设置之后打开数据库进入检查开关情况,如下图则成功
定位mysql-node2和mysql-node3,初始化数据库再重启数据库更新密码,加入免密认证
#在slave1和slave2
[root@mysql-node2 & 3 ~]# /etc/init.d/mysqld stop
[root@mysql-node2 & 3 ~]# rm -fr /data/mysql/*
[root@mysql-node2 & 3 ~]# vim /etc/my.cnf
[mysqld]
datadir=/data/mysql
socket=/data/mysql/mysql.sock
server-id=1
log-bin=mysql-bin
gtid_mode=ON
log_slave_updates=ON
enforce-gtid-consistency=ON
symbolic-links=0[root@mysql-node2 & 3 ~]# mysqld --user mysql --initialize
[root@mysql-node2 & 3 ~]# /etc/init.d/mysqld start
[root@mysql-node2 & 3 ~]# mysql_secure_installation[root@mysql-node2 & 3 ~]# mysql -p
mysql> CHANGE MASTER TO MASTER_HOST='172.25.254.10', MASTER_USER='repl',
MASTER_PASSWORD='lee', MASTER_AUTO_POSITION=1;mysql> start slave;mysql> INSTALL PLUGIN rpl_semi_sync_slave SONAME 'semisync_slave.so';mysql> SET GLOBAL rpl_semi_sync_slave_enabled =1;mysql> STOP SLAVE IO_THREAD;mysql> START SLAVE IO_THREAD;mysql> SHOW STATUS LIKE 'Rpl_semi_sync%';
输入如图所示的命令即可查看状态,必须是开启的。
(2)安装MHA所需要的软件
[root@mysql-mha ~]# unzip MHA-7.zip #解压已经导入的软件包
注意要进入解压后的软件包目录之后再继续yum
[root@mysql-mha MHA-7]# yum install *.rpm -y
利用scp传输过去给其他几台主机:
这里想要速度变快就更改/etc/.sshd/ssh_config中的USERDNS yes 为 no 记得要重启sshd服务
工具包介绍
2.Node工具包 (通常用master主机直接调用,无需人去执行)
save_binary_logs #保存和复制master的二进制日志
apply_diff_relay_logs #识别差异的中继日志事件并将其差异的事件应用于其他的slave
filter_mysqlbinlog #去除不必要的ROLLBACK事件(MHA已不再使用这个工具)
purge_relay_logs #清除中继日志(不会阻塞SQL线程)
(3)配置MHA管理环境
1.生成配置目录和配置文件
[root@mysql-mha ~]# masterha_manager --help
Usage:masterha_manager --global_conf=/etc/masterha_default.cnf #全局配置文件,记录公共设定--conf=/usr/local/masterha/conf/app1.cnf #不同管理配置文件,记录各自配置See online reference (http://code.google.com/p/mysql-master-ha/wiki/masterha_manager) fordetails.
2.编写一个配置文件
解压源码包后在samples中找到配置文件的模板文件
#生成配置文件
[root@mysql-mha ~]# mkdir /etc/masterha
[root@mysql-mha MHA-7]# tar zxf mha4mysql-manager-0.58.tar.gz
[root@mysql-mha MHA-7]# cd mha4mysql-manager-0.58/samples/conf/
[root@mysql-mha conf]# cat masterha_default.cnf app1.cnf > /etc/masterha/app1.cnf#编辑配置文件
[root@mysql-mha ~]# vim /etc/masterha/app1.cnf
[server default]
user=root #mysql管理员用户,因为需要做自动化配置
password=lee #mysql密码
ssh_user=root #ssh远程登陆用户
repl_user=repl #mysql主从复制中负责认证的用户
repl_password=lee #mysql主从复制中负责认证的用户密码
master_binlog_dir= /data/mysql #二进制日志目录
remote_workdir=/tmp #远程工作目录#此参数使为了提供冗余检测,方式是判断mha主机网络自身的问题无法连接数据库节点,应为集群之外的主机
secondary_check_script= masterha_secondary_check -s 172.25.254.10 -s 172.25.254.11##注意:两节点必须有一个是下面server中的 一台不是ping_interval=3 #每隔3秒检测一次#发生故障后调用的脚本,用来迁移vip
# master_ip_failover_script= /script/masterha/master_ip_failover#电源管理脚本
# shutdown_script= /script/masterha/power_manager#当发生故障后用此脚本发邮件或者告警通知
# report_script= /script/masterha/send_report#在线切换时调用的vip迁移脚本,手动
# master_ip_online_change_script= /script/masterha/master_ip_online_change
manager_workdir=/etc/masterha #mha工作目录
manager_log=/var/etc/masterha/manager.log #mha日志
[server1]
hostname=172.25.254.10
candidate_master=1 #可能作为master的主机check_repl_delay=0 ##默认情况下如果一个slave落后master 100M的relay logs的话#MHA将不会选择该slave作为一个新的master#因为对于这个slave的恢复需要花费很长时间#通过设置check_repl_delay=0#MHA触发切换在选择一个新的master的时候将会忽略复制延时#这个参数对于设置了candidate_master=1的主机非常有用#因为这个候选主在切换的过程中一定是新的master[server2]
hostname=172.25.254.20
candidate_master=1 #可能作为master的主机
check_repl_delay=0[server3]
hostname=172.25.254.30
no_master=1 #不会作为master的主机
2.检测配置
a.检测网络以及ssh免密
[root@mysql-mha ~]# masterha_check_ssh --conf=/etc/masterha/app1.cnf
b.检测数据主从复制情况
[root@mysql-mha ~]# masterha_check_repl --conf=/etc/masterha/app1.cnf
note:如果出现报错就去看日志的详细描述,常见错误如下:
- 防火墙没关
- selinux不是disabled状态
- /etc/masterha/app1.cnf这个配置文件内容不对
- 其他主机的/etc/my.cnf配置文件内容缺失
如果你很幸运,那么就是下面的成功画面:
3.MHA故障切换
(1)master未出现故障手动切换
#在master数据节点还在正常工作情况下
[root@mysql-mha ~]# masterha_master_switch \
--conf=/etc/masterha/app1.cnf \ # 指定配置文件
--master_state=alive \ #指定master节点状态
--new_master_host=172.25.254.20 \ #指定新master节点
--new_master_port=3306 \ #执行新master节点端口
--orig_master_is_new_slave \ #原始master会变成新的slave
--running_updates_limit=10000 #切换的超时时间检测:
[root@mysql-mha masterha]# masterha_check_repl --conf=/etc/masterha/app1.cnf
(2)master出现故障手动切换
#模拟master故障
[root@mysql-node2 mysql]# /etc/init.d/mysqld stop#在MHA-master中做故障切换
[root@mysql-mha masterha]# masterha_master_switch --master_state=dead --
conf=/etc/masterha/app1.cnf --dead_master_host=192.168.56.12 --
dead_master_port=3306 --new_master_host=192.168.56.11 --new_master_port=3306 --
ignore_last_failover
--ignore_last_failover 表示忽略在/etc/masterha/目录中在切换过程中生成的锁文件masterha_master_switch --master_state=dead --conf=/etc/masterha/app1.cnf --
dead_master_host=172.25.254.20 --dead_master_port=3306 --
new_master_host=172.25.254.10 --new_master_port=3306 --ignore_last_failover
--dead_master_ip=<dead_master_ip> is not set. Using 172.25.254.20.
恢复故障mysql节点
[root@mysql-node20 tmp]# /etc/init.d/mysqld start Starting MySQL. SUCCESS! [root@mysql-node20 tmp]# mysql -p
mysql> CHANGE MASTER TO MASTER_HOST='172.25.254.10', MASTER_USER='repl', MASTER_PASSWORD='lee', MASTER_AUTO_POSITION=1;
(3)自动切换
[root@mysql-mha masterha]# rm -fr app1.failover.complete #删掉切换锁文件#监控程序通过指定配置文件监控master状态,当master出问题后自动切换并退出避免重复做故障切换
[root@mysql-mha masterha]# masterha_manager --conf=/etc/masterha/app1.cnf
[root@mysql-mha masterha]# cat /etc/masterha/manager.log#恢复故障节点
[root@mysql-node20 mysql]# /etc/init.d/mysqld startmysql> CHANGE MASTER TO MASTER_HOST='172.25.254.10', MASTER_USER='repl',
MASTER_PASSWORD='lee', MASTER_AUTO_POSITION=1#清除所锁文件[root@mysql-mha masterha]# rm -rf app1.failover.complete manager.log
4.添加VIP功能
上传脚本(已写好的)
[root@mysql-mha ~]# ls
master_ip_failover master_ip_online_change MHA-7 MHA-7.zip
[root@mysql-mha ~]# cp master_ip_failover master_ip_online_change /usr/local/bin/
[root@mysql-mha ~]# chmod +x /usr/local/bin/master_ip_*
#修改脚本在脚本中只需要修改下vip即可[root@mysql-mha ~]# vim /usr/local/bin/master_ip_failover
my $vip = '172.25.254.100/24';
my $ssh_start_vip = "/sbin/ip addr add $vip dev eth0";
my $ssh_stop_vip = "/sbin/ip addr del $vip dev eth0";[root@mysql-mha ~]# vim /usr/local/bin/master_ip_online_change
my $vip = '172.25.254.100/24';
my $ssh_start_vip = "/sbin/ip addr add $vip dev eth0";
my $ssh_stop_vip = "/sbin/ip addr del $vip dev eth0";
my $exit_code = 0;[root@mysql-mha masterha]# masterha_manager --conf=/etc/masterha/app1.cnf #启动监控程序
[root@mysql-node10 tmp]# ip a a 172.25.254.100/24 dev eth0 #在master节点添加VIP
模拟故障:
[root@mysql-node10 ~]# /etc/init.d/mysqld stop #关闭主节点服务
[root@mysql-mha masterha]# cat manager.log
恢复故障主机:
[root@mysql-node20 mysql]# /etc/init.d/mysqld start
mysql> CHANGE MASTER TO MASTER_HOST='172.25.254.10', MASTER_USER='repl', MASTER_PASSWORD='lee', MASTER_AUTO_POSITION=1
[root@mysql-mha masterha]# rm -rf app1.failover.complete manager.log
手动切换后查看vip变化
[root@mysql-mha masterha]# masterha_master_switch --conf=/etc/masterha/app1.cnf --master_state=alive --new_master_host=172.25.254.10 --new_master_port=3306 -- orig_master_is_new_slave --running_updates_limit=10000
[root@mysql-node10 ~]# ip a #查看ip变化
二、Redis非关系型数据库
1.Redis特点
- 速度快: 10W QPS,基于内存,C语言实现
- 单线程
- 持久化
- 支持多种数据结构
- 支持多种编程语言
- 功能丰富: 支持Lua脚本,发布订阅,事务,pipeline等功能
- 简单: 代码短小精悍(单机核心代码只有23000行左右),单线程开发容易,不依赖外部库,使用简单(单线程之所以超级快,是因为:纯内存、非阻塞、避免切换和竞态消耗)
- 主从复制
- 支持高可用和分布式
2.Redis应用场景
3.缓存的实现流程
数据更新操作流程
数据读操作流程
4.Redis的安装
官方下载地址:http://download.redis.io/releases/
任意选择以下方式安装(仅使用1种方式即可)
4.1.rpm包方式安装
[root@redis-node1 ~]# dnf install redis -y
4.2.源码安装
[root@redis-node1 ~]# tar zxf redis-7.4.0.tar.gz
[root@redis-node1 ~]# ls
redis-7.4.0 redis-7.4.0.tar.gz#安装编译工具
[root@redis-node1 redis-7.4.0]# dnf install make gcc initscripts-10.11.6-1.el9.x86_64 -y#执行编译命令
[root@redis-node1 redis-7.4.0]# make
[root@redis-node1 redis-7.4.0]# make install#启动Redis
[root@redis-node1 redis-7.4.0]# cd utils/
[root@redis-node1 utils]# ./install_server.sh配置Redis
[root@redis-node1 utils]# vim /etc/redis/6379.conf
bind * -::*[root@redis-node1 utils]# /etc/init.d/redis_6379 restart
Stopping ...
Redis stopped
Starting Redis server...[root@redis-node1 utils]# netstat -antlpe | grep redis
tcp 0 0 0.0.0.0:6379 0.0.0.0:* LISTEN 067267 38417/redis-server
tcp6 0 0 :::6379#查看信息
[root@redis-node1 utils]# redis-cli
127.0.0.1:6379> info
如果提示如下图所示:
vim /etc/redis/redis.conf #进入Redis的主配置文件
如下图则表示成功进入了Redis,即可开始使用
4.3.基本操作
(1)查看配置(红色是命令,黄色是结果)
(2)写入和读取数据
(3)选择数据库 Redis中有0-15个数据库
(4)改变键名
(5)设定数据过期时间 / 持久化(设置时间版)保持
127.0.0.1:6379> PERSIST name 持久化保持
(6)删除
(7)判断key的存在
(8)清空当前库
127.0.0.1:6379> flushdb
(9)清空所有库
127.0.0.1:6379[1]> FLUSHALL
5.Redis主从复制
5.1.环境
需要安装同样的数据库主机三台
主机名称 | ip | 角色 |
redis-node1 | 172.25.254.10 | master |
redis-node2 | 172.25.254,20 | slave |
redis-node3 | 172.25.254.30 | slave |
5.2.配置主从同步
- slave节点发送同步亲求到master节点
- slave节点通过master节点的认证开始进行同步
- master节点会开启bgsave进程发送内存rbd到slave节点,在此过程中是异步操作,也就是说 master节点仍然可以进行写入动作
- slave节点收到rdb后首先清空自己的所有数据
- slave节点加载rdb并进行数据恢复 在master和slave同步过程中master还会开启新的bgsave进程把没有同步的数据进行缓存 然后通过自有的replactionfeedslave函数把未通过内存快照发动到slave的数据一条一条写入到 slave中
(1)修改master节点的配置文件
[root@redis-node1 & node2 & node3 ~]# vim /etc/redis/6379.conf
修改配置文件之后需要重启服务
[root@redis-node1 &node2 & node3 ~]# /etc/init.d/redis_6379 restart
(2)配置slave节点
[root@redis-node2 & 3 ~]# vim /etc/redis/6379.conf
[root@redis-node2 & 3 ~]# /etc/init.d/redis_6379 restart
(3)测试
#在mastser节点
[root@redis-node1 ~]# redis-cli
127.0.0.1:6379> set name yara
OK#在slave节点查看
[root@redis-node2 ~]# redis-cli
127.0.0.1:6379> get name
"yara"
6.Redis的哨兵(高可用)
每个哨兵(Sentinel)进程会向其它哨兵(Sentinel)、Master、Slave定时发送消息,以确认对方是否”活” 着,如果发现对方在指定配置时间(此项可配置)内未得到回应,则暂时认为对方已离线,也就是所谓的” 主观认为宕机” (主观:是每个成员都具有的独自的而且可能相同也可能不同的意识),英文名称: Subjective Down,简称SDOWN
有主观宕机,对应的有客观宕机。当“哨兵群”中的多数Sentinel进程在对Master主服务器做出SDOWN 的 判断,并且通过 SENTINEL is-master-down-by-addr 命令互相交流之后,得出的Master Server下线判 断,这种方式就是“客观宕机”(客观:是不依赖于某种意识而已经实际存在的一切事物),英文名称是: Objectively Down, 简称 ODOWN
6.1.哨兵的实验过程
在所有阶段中关闭 protected-mode no
#编辑配置文件
[root@redis-node1 ~]# cd redis-7.4.0/
[root@redis-node1 redis-7.4.0]# cp sentinel.conf /etc/redis/
[root@redis-node1 redis-7.4.0]# vim /etc/redis/sentinel.conf
protected-mode no #关闭保护模式
port 26379 #监听端口
daemonize no #进入不打如后台
pidfile /var/run/redis-sentinel.pid #sentinel进程pid文件
loglevel notice #日志级别
sentinel monitor mymaster 172.25.254.100 6379 2 #创建sentinel监控监控master主机,2表示必须得到2票
sentinel down-after-milliseconds mymaster 10000 #master中断时长,10秒连不上视为master下线
sentinel parallel-syncs mymaster 1 #发生故障转移后,同时开始同步新
master数据的slave数量
sentinel failover-timeout mymaster 180000 #整个故障切换的超时时间为3分钟####复制配置文件到其他阶段
[root@redis-node1 redis-7.4.0]# scp /etc/redis/sentinel.conf
root@172.25.254.201:/etc/redis/
root@172.25.254.201's password:
sentinel.conf
100% 14KB 9.7MB/s 00:00
[root@redis-node1 redis-7.4.0]# scp /etc/redis/sentinel.conf
root@172.25.254.200:/etc/redis/
root@172.25.254.200's password:
sentinel.conf
启动服务
[root@redis-node1 redis-7.4.0]# redis-sentinel /etc/redis/sentinel.conf
39319:X 05 Aug 2024 20:53:16.807 # WARNING Memory overcommit must be enabled!
Without it, a background save or replication may fail under low memory condition.
Being disabled, it can also cause failures without low memory condition, see
https://github.com/jemalloc/jemalloc/issues/1328. To fix this issue add
'vm.overcommit_memory = 1' to /etc/sysctl.conf and then reboot or run the command
'sysctl vm.overcommit_memory=1' for this to take effect.
39319:X 05 Aug 2024 20:53:16.807 * oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
39319:X 05 Aug 2024 20:53:16.807 * Redis version=7.4.0, bits=64, commit=00000000,
modified=0, pid=39319, just started
39319:X 05 Aug 2024 20:53:16.807 * Configuration loaded
39319:X 05 Aug 2024 20:53:16.808 * Increased maximum number of open files to
10032 (it was originally set to 1024).
39319:X 05 Aug 2024 20:53:16.808 * monotonic clock: POSIX clock_gettime
_._
_.-``__ ''-._
_.-`` `. `_. ''-._ Redis Community Edition
.-`` .-```. ```\/ _.,_ ''-._ 7.4.0 (00000000/0) 64 bit
( ' , .-` | `, ) Running in sentinel mode
|`-._`-...-` __...-.``-._|'` _.-'| Port: 26379
| `-._ `._ / _.-' | PID: 39319
`-._ `-._ `-./ _.-' _.-'
|`-._`-._ `-.__.-' _.-'_.-'|
| `-._`-._ _.-'_.-' | https://redis.io
`-._ `-._`-.__.-'_.-' _.-'
|`-._`-._ `-.__.-' _.-'_.-'|
| `-._`-._ _.-'_.-' |
`-._ `-._`-.__.-'_.-' _.-'
`-._ `-.__.-' _.-'
`-._ _.-'
`-.__.-'
39319:X 05 Aug 2024 20:53:16.810 * Sentinel new configuration saved on disk
39319:X 05 Aug 2024 20:53:16.810 * Sentinel ID is
e568add863fd7c132e03f7a6ce2c5ef367d3bdae
39319:X 05 Aug 2024 20:53:16.810 # +monitor master mymaster 172.25.254.100 6379
quorum 2
39319:X 05 Aug 2024 20:53:16.811 * +slave slave 172.25.254.201:6379
172.25.254.201 6379 @ mymaster 172.25.254.100 6379
39319:X 05 Aug 2024 20:53:16.812 * Sentinel new configuration saved on disk
39319:X 05 Aug 2024 20:53:16.812 * +slave slave 172.25.254.200:6379
172.25.254.200 6379 @ mymaster 172.25.254.100 6379
39319:X 05 Aug 2024 20:53:16.813 * Sentinel new configuration saved on disk
39319:X 05 Aug 2024 20:53:41.769 * +sentinel sentinel
4fe1dcbe25a801e75d6edfc5b0a8517bfa7992c3 172.25.254.200 26379 @ mymaster
172.25.254.100 6379
39319:X 05 Aug 2024 20:53:41.771 * Sentinel new configuration saved on disk
39319:X 05 Aug 2024 20:53:57.227 * +sentinel sentinel
83f928aafe317a5f9081eea8fc5c383ff31c55ef 172.25.254.201 26379 @ mymaster
172.25.254.100 6379
39319:X 05 Aug 2024 20:53:57.229 * Sentinel new configuration saved on disk
测试
在开一个master节点终端
[root@redis-node1 ~]# redis-cli
127.0.0.1:6379> SHUTDOWN[root@redis-node2 ~]# redis-cli
127.0.0.1:6379> info replications
127.0.0.1:6379> info replication
# Replication
role:master
connected_slaves:2
slave0:ip=172.25.254.201,port=6379,state=online,offset=211455,lag=1
slave1:ip=172.25.254.100,port=6379,state=online,offset=211455,lag=1
master_failover_state:no-failover
master_replid:d42fd72f3dfae94c84ca722ad1653417495ef4fd
master_replid2:290c3407108cc6120086981b7149a6fa377594c4
master_repl_offset:211598
second_repl_offset:185931
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:150986
repl_backlog_histlen:60613
6.2架构缺陷
在生产环境中如果master和slave中的网络出现故障,由于哨兵的存在会把master提出去 当网络恢复后,master发现环境发生改变,master就会把自己的身份转换成slave master变成slave后会把网络故障那段时间写入自己中的数据清掉,这样数据就丢失了。
如何解决这一问题呢?
master在被写入数据时会持续连接slave,mater确保有2个slave可以写入我才允许写入 如果slave数量少于2个便拒绝写入
#在matster中设定
[root@redis-node2 ~]# redis-cli
127.0.0.1:6379> CONFIG GET min-slaves-to-write
1) "min-slaves-to-write"
2) "0" 127.0.0.1:6379> CONFIG set min-slaves-to-write 2
OK
127.0.0.1:6379> CONFIG GET min-slaves-to-write
1) "min-slaves-to-write"
2) "2"
#如果要永久保存写到配置文件中/etc/redis/6379.conf
7.Redis Cluster(无中心化设计)
7.1.工作原理
在哨兵sentinel机制中,可以解决redis高可用问题,即当master故障后可以自动将slave提升为master, 从而可以保证redis服务的正常使用,但是无法解决redis单机写入的瓶颈问题,即单机redis写入性能受限于单机的内存大小、并发数量、网卡速率等因素。
redis 3.0版本之后推出了无中心架构的redis cluster机制,在无中心的redis集群当中,其每个节点保存当前节点数据和整个集群状态,每个节点都和其他所有节点连接
Redis cluster的架构虽然解决了并发的问题,但是又引入了一个新的问题,每个Redis master的高可用 如何解决?
那就是对每个master 节点都实现主从复制,从而实现 redis 高可用性
7.2创建Redis Cluster的要求
7.3部署Redis Cluster
在所有主机中
[root@redis-masterx ~]# vim /etc/redis/redis.conf
masterauth "123456" #集群主从认证
requirepass "123456" #redis登陆密码 redis-cli 命令连接redis后要用“auth 密码”进行认证
cluster-enabled yes #开启cluster集群功能
cluster-config-file nodes-6379.conf #指定集群配置文件
cluster-node-timeout 15000 #节点加入集群的超时时间单位是ms[root@redis-master1 ~]# systemctl restart redis.service
[root@redis-master1 ~]# redis-cli
127.0.0.1:6379> auth 123456
OK
127.0.0.1:6379> info# Cluster
cluster_enabled:1
注意观察命令行前面主机称号
#配置文件位置 [root@redis-master1 ~]# ll /var/lib/redis/nodes-6379.conf
[root@redis-master1 ~]# redis-cli --cluster create -a 123456 \
> 172.25.254.10:6379 172.25.254.20:6379 172.25.254.30:6379 \
> 172.25.254.110:6379 172.25.254.120:6379 172.25.254.130:6379 \
> --cluster-replicas 1
>>> Performing hash slots allocation on 6 nodes...
Master[0] -> Slots 0 - 5460 #哈希槽分配
Master[1] -> Slots 5461 - 10922Master[2] -> Slots 10923 - 16383
Adding replica 172.25.254.120:6379 to 172.25.254.10:6379 #主从分配情况
Adding replica 172.25.254.130:6379 to 172.25.254.20:6379
Adding replica 172.25.254.110:6379 to 172.25.254.30:6379
M: 5ab2e93f4f0783983676f7bd118efaacfb202bd1 172.25.254.10:6379slots:[0-5460] (5461 slots) master
M: ba504e78f14df5944280f9035543277a0cf5976b 172.25.254.20:6379slots:[5461-10922] (5462 slots) master
M: 1fcaeb1dd936b46f4ea1efe4330c54195e66acf7 172.25.254.30:6379slots:[10923-16383] (5461 slots) master
S: c20c9b5465b2e64868161c0e285d55bc81358ba4 172.25.254.110:6379replicates 1fcaeb1dd936b46f4ea1efe4330c54195e66acf7
S: d458f34fa900d83212c021dc1e65396e490b5495 172.25.254.120:6379replicates 5ab2e93f4f0783983676f7bd118efaacfb202bd1
S: 83d7a82fe896cf9f4d8212cb533058659bba16ce 172.25.254.130:6379replicates ba504e78f14df5944280f9035543277a0cf5976b
Can I set the above configuration? (type 'yes' to accept): yes>>> Performing Cluster Check (using node 172.25.254.10:6379)
M: 5ab2e93f4f0783983676f7bd118efaacfb202bd1 172.25.254.10:6379slots:[0-5460] (5461 slots) master1 additional replica(s)
S: c20c9b5465b2e64868161c0e285d55bc81358ba4 172.25.254.110:6379slots: (0 slots) slavereplicates 1fcaeb1dd936b46f4ea1efe4330c54195e66acf7
M: ba504e78f14df5944280f9035543277a0cf5976b 172.25.254.20:6379slots:[5461-10922] (5462 slots) master1 additional replica(s)
S: 83d7a82fe896cf9f4d8212cb533058659bba16ce 172.25.254.130:6379slots: (0 slots) slavereplicates ba504e78f14df5944280f9035543277a0cf5976b
M: 1fcaeb1dd936b46f4ea1efe4330c54195e66acf7 172.25.254.30:6379slots:[10923-16383] (5461 slots) master1 additional replica(s)
S: d458f34fa900d83212c021dc1e65396e490b5495 172.25.254.120:6379slots: (0 slots) slavereplicates 5ab2e93f4f0783983676f7bd118efaacfb202bd1
[OK] All nodes agree about slots configuration.
>>> Check for open slots... #检查打开的哈希槽位
>>> Check slots coverage... #检查槽位覆盖范围
[OK] All 16384 slots covered. #所有槽位分配完成
检查Redis集群状态
[root@redis-master1 ~]# redis-cli -a 123456 --cluster info 172.25.254.10:6379
#查看集群状态
Warning: Using a password with '-a' or '-u' option on the command line interface
may not be safe.
172.25.254.10:6379 (5ab2e93f...) -> 0 keys | 5461 slots | 1 slaves.
172.25.254.20:6379 (ba504e78...) -> 0 keys | 5462 slots | 1 slaves.
172.25.254.30:6379 (1fcaeb1d...) -> 0 keys | 5461 slots | 1 slaves.
[OK] 0 keys in 3 masters.
0.00 keys per slot on average.[root@redis-master1 ~]# redis-cli -a 123456 cluster info
Warning: Using a password with '-a' or '-u' option on the command line interface
may not be safe.
cluster_state:ok
cluster_slots_assigned:16384
cluster_slots_ok:16384
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:6
cluster_size:3
cluster_current_epoch:6
cluster_my_epoch:1
cluster_stats_messages_ping_sent:821
cluster_stats_messages_pong_sent:801
cluster_stats_messages_sent:1622
cluster_stats_messages_ping_received:796
cluster_stats_messages_pong_received:821
cluster_stats_messages_meet_received:5
cluster_stats_messages_received:1622[root@redis-master1 ~]# redis-cli -a 123456 --cluster check 172.25.254.10:6379
#检测集群
Warning: Using a password with '-a' or '-u' option on the command line interface
may not be safe.
172.25.254.10:6379 (5ab2e93f...) -> 0 keys | 5461 slots | 1 slaves.
172.25.254.20:6379 (ba504e78...) -> 0 keys | 5462 slots | 1 slaves.
172.25.254.30:6379 (1fcaeb1d...) -> 0 keys | 5461 slots | 1 slaves.
[OK] 0 keys in 3 masters.
0.00 keys per slot on average.
>>> Performing Cluster Check (using node 172.25.254.10:6379)
M: 5ab2e93f4f0783983676f7bd118efaacfb202bd1 172.25.254.10:6379slots:[0-5460] (5461 slots) master1 additional replica(s)
S: c20c9b5465b2e64868161c0e285d55bc81358ba4 172.25.254.110:6379slots: (0 slots) slavereplicates 1fcaeb1dd936b46f4ea1efe4330c54195e66acf7
M: ba504e78f14df5944280f9035543277a0cf5976b 172.25.254.20:6379slots:[5461-10922] (5462 slots) master1 additional replica(s)
S: 83d7a82fe896cf9f4d8212cb533058659bba16ce 172.25.254.130:6379slots: (0 slots) slavereplicates ba504e78f14df5944280f9035543277a0cf5976b
M: 1fcaeb1dd936b46f4ea1efe4330c54195e66acf7 172.25.254.30:6379slots:[10923-16383] (5461 slots) master1 additional replica(s)
S: d458f34fa900d83212c021dc1e65396e490b5495 172.25.254.120:6379slots: (0 slots) slavereplicates 5ab2e93f4f0783983676f7bd118efaacfb202bd1
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
写入数据[root@redis-master1 ~]# redis-cli -a 123456
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.127.0.0.1:6379> set key1 value1 #被分配到20的hash槽位上
(error) MOVED 9189 172.25.254.20:6379 [root@redis-master2 ~]# redis-cli -a 123456
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
127.0.0.1:6379> set key1 value1
OK
7.4集群扩容
#添加master [root@redis-master1 ~]# redis-cli -a 123456 --cluster add-node 172.25.254.40:6379 172.25.254.10:6379
[root@redis-master1 ~]# redis-cli -a 123456 --cluster info 172.25.254.10:6379
#分配槽位
[root@redis-master1 ~]# redis-cli -a 123456 --cluster reshard 172.25.254.10:6379
#添加salve
[root@redis-master1 ~]# redis-cli -a 123456 --cluster add-node 172.25.254.140:6379 172.25.254.10:6379 --cluster-slave --cluster-master-id 009571cb206a89afa6658b60b2d403136056ac09
7.5集群维护
添加节点的时候是先添加node节点到集群,然后分配槽位,删除节点的操作与添加节点的操作正好相 反,是先将被删除的Redis node上的槽位迁移到集群中的其他Redis node节点上,然后再将其删除,如 果一个Redis node节点上的槽位没有被完全迁移,删除该node的时候会提示有数据且无法删除。
#移除要下线主机的哈希槽位
[root@redis-master2 ~]# redis-cli -a 123456 --cluster reshard 172.25.254.20:6379#删除master
[root@redis-master2 ~]# redis-cli -a 123456 --cluster del-node
172.25.254.120:6379 d458f34fa900d83212c021dc1e65396e490b5495[root@redis-master2 ~]# redis-cli -a 123456 --cluster del-node
172.25.254.10:6379 5ab2e93f4f0783983676f7bd118efaacfb202bd1
总结
至此我们的数据库集群技术就到这里
相关文章:

如何进行不同数据库的集群操作?--从部署谈起,今天来看MySQL和NoSql数据库Redis的集群
篇幅较长,主要分为mysql和Redis两部分。找想要的部分可见目录食用。。 目录 什么是集群?为什么要集群? 1.1 数据库主要分为两大类:关系型数据库与 NoSQL 数据库 1.2 为什么还要用 NoSQL 数据库呢? ----------------…...

第 6 章图像聚类
本章将介绍几种聚类方法,并展示如何利用它们对图像进行聚类,从而寻找相似的图像组。聚类可以用于识别、划分图像数据集,组织与导航。此外,我们还会对聚类后的图像进行相似性可视化。 6.1 K-means聚类 K-means 是一种将输入数据划…...

HC-SR501人体红外传感器详解(STM32)
目录 一、介绍 二、传感器原理 1.原理图 2.引脚描述 3.工作原理介绍 三、程序设计 main.c文件 body_hw.h文件 body_hw.c文件 四、实验效果 五、资料获取 项目分享 一、介绍 HC-SR501人体红外模块是基于红外线技术的自动控制模块,采用德国原装进口LHI77…...

关于武汉芯景科技有限公司的IIC电平转换芯片XJ9517开发指南(兼容PCF9517)
一、芯片引脚介绍 1.芯片引脚 2.引脚描述 二、系统结构图 三、功能描述 1.电平转换 2.芯片使能/失能 EN 引脚为高电平有效,内部上拉至 VCC(B),允许用户选择中继器何时有效。这可用于在上电时隔离行为不良的从机,直到…...
C语言:scanf()、getchar()、gets()
一、gets() gets()能吸收空格和换行,因此输入后,对输出要去除空格 和换行\n; #include <stdio.h> #include <string.h> int main() {char str[1000];int count0;gets(str);for(int i0;i<strlen(str);i)count;printf("%s\n",str…...

基于MATLAB的全景图像拼接系统实现
简要的论文框架和技术思路 摘要 本文深入探讨了基于MATLAB平台的块匹配全景图像拼接系统的设计与实现。通过详细解析SIFT/SURF特征提取、RANSAC变换估计、APAP局部对齐、图割算法拼接缝选择及multi-band blending图像融合等关键技术,构建了高效且高质量的全景图像…...

AI模型“减肥”风潮:量化究竟带来了什么?
量化对大模型的影响是什么 ©作者|YXFFF 来源|神州问学 引言 大模型在NLP和CV领域的广泛应用中展现了强大的能力,但随着模型规模的扩大,对计算和存储资源的需求也急剧增加,特别是在资源受限的设备上面临挑战。量化技术通过将模型参数和…...

第四届“长城杯”网络安全大赛 暨京津冀网络安全技能竞赛(初赛) 全方向 题解WriteUp
战队名称:TeamGipsy 战队排名:18 SQLUP 题目描述:a website developed by a novice developer. 开题,是个登录界面。 账号admin,随便什么密码都能登录 点击头像可以进行文件上传 先简单上传个木马试试 测一下&…...

ETCD的备份和恢复
一、引言 ETCD是一个高度可用的键值存储系统,被广泛应用于Kubernetes等分布式系统中以存储关键配置数据和服务发现信息。由于ETCD的重要性,确保其数据的安全性和可靠性至关重要。本文将介绍ETCD备份与恢复的基础知识、常用方法及最佳实践。 二、概述 …...
Linux Makefile文本处理函数知识详解
1.Makefile函数 GNU make 提供了大量的函数用来处理文件名、变量、文本和命令。通过这些函数,用户可以节省很多精力,编写出更加灵活和健壮的Makefile。函数的使用和变量引用的展开方式相同: $(function arguments)${function arguments}关于…...

Rust的数据类型
【图书介绍】《Rust编程与项目实战》-CSDN博客 《Rust编程与项目实战》(朱文伟,李建英)【摘要 书评 试读】- 京东图书 (jd.com) Rust到底值不值得学,之一 -CSDN博客 Rust到底值不值得学,之二-CSDN博客 3.5 数据类型的定义和分类 在Rust…...

如何在vim中批量注释和取消注释
一、批量注释 首先在你需要注释的初始所在行在命令模式下输入CTRL v,然后按下HJKL来控制方向(不能使用键盘上的箭头方向键): 然后输入 shifti: 输入两个斜杠然后加exc就可以完成批量注释: 二、批量取消注…...

Centos7.9 安装Elasticsearch 8.15.1(图文教程)
本章教程,主要记录在Centos7.9 安装Elasticsearch 8.15.1的整个安装过程。 一、下载安装包 下载地址: https://www.elastic.co/cn/downloads/past-releases/elasticsearch-8-15-1 你可以通过手动下载然后上传到服务器,也可以直接使用在线下载的方式。 wget https://artifacts…...

哈希表-数据结构
一、哈希表基本概念 哈希表(也称为散列表)是根据键而直接访问在内存存储位置的数据结构,也就是说实际上是经过哈希函数进行映射,映射道表中一个位置来访问记录,这个存放记录的数组称为散列表。 哈希函数:就…...

指针之旅(4)—— 指针与函数:函数指针、转移表、回调函数
目录 1. 函数名的理解 1.1 “函数名”和“&函数名”的含义 1.2 函数(名)的数据类型 2. 函数指针(变量) 2.1 函数指针(变量)的创建格式 2.2 函数指针(变量)的使用格式 2.3 例子 判别 3. typedef 关键字 3.1 typedef的作用 3.2 typedef的运作逻辑 和 函数指针类型…...

打造线上+线下相结合的O2O平台预约上门服务小程序源码系统 带完整的安装代码包以及搭建部署教程
系统概述 本系统采用前后端分离的设计架构,前端以微信小程序为载体,提供直观、易用的用户界面;后端则采用稳定的服务器架构,确保数据处理的高效与安全。系统主要包括用户端、商户端和管理员端三大模块,通过API接口实现…...
python sys模块
在Python中,sys模块提供了访问和使用解释器的许多功能的方法,包括命令行参数、环境变量、路径管理、标准输入输出流等。sys模块是Python的标准库的一部分,不需要额外安装即可使用。 常用的sys模块功能 1. sys.argv sys.argv是一个包含命令…...

【Linux 报错】SSH服务器拒绝了密码。请再试一次。(xshell)
出现该错误 可能的原因: 你写入的登录密码错误了,错误原因有: 1、本来输入就错误了 2、创建用户时,只创建了用户名,但密码没有重新设置 3、多人使用同一台服务器时,该服务器管理员(本体&#x…...

云计算实训43——部署k8s基础环境、配置内核模块、基本组件安装
一、前期系统环境准备 1、关闭防火墙与selinux [rootk8s-master ~]# systemctl stop firewalld[rootk8s-master ~]# systemctl disable firewalldRemoved symlink /etc/systemd/system/multi-user.target.wants/firewalld.service. Removed symlink /etc/systemd/system/dbus…...

TAbleau 可视化 干货分享 | 简单三步助你打造完美仪表板
只需单击几下,你将能轻松创建美观、信息丰富的可视化效果、节省时间并推动业务向前发展! 借助精心设计的仪表板,分析师可以更好地理解复杂数据背后的信息,更有效地向他人分享你的见解,从而做出更明智的决策。 值得思考…...
k8s从入门到放弃之Ingress七层负载
k8s从入门到放弃之Ingress七层负载 在Kubernetes(简称K8s)中,Ingress是一个API对象,它允许你定义如何从集群外部访问集群内部的服务。Ingress可以提供负载均衡、SSL终结和基于名称的虚拟主机等功能。通过Ingress,你可…...
1688商品列表API与其他数据源的对接思路
将1688商品列表API与其他数据源对接时,需结合业务场景设计数据流转链路,重点关注数据格式兼容性、接口调用频率控制及数据一致性维护。以下是具体对接思路及关键技术点: 一、核心对接场景与目标 商品数据同步 场景:将1688商品信息…...

Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决
Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决 问题背景 在一个基于 Spring Cloud Gateway WebFlux 构建的微服务项目中,新增了一个本地验证码接口 /code,使用函数式路由(RouterFunction)和 Hutool 的 Circle…...
rnn判断string中第一次出现a的下标
# coding:utf8 import torch import torch.nn as nn import numpy as np import random import json""" 基于pytorch的网络编写 实现一个RNN网络完成多分类任务 判断字符 a 第一次出现在字符串中的位置 """class TorchModel(nn.Module):def __in…...
安卓基础(aar)
重新设置java21的环境,临时设置 $env:JAVA_HOME "D:\Android Studio\jbr" 查看当前环境变量 JAVA_HOME 的值 echo $env:JAVA_HOME 构建ARR文件 ./gradlew :private-lib:assembleRelease 目录是这样的: MyApp/ ├── app/ …...

深度学习水论文:mamba+图像增强
🧀当前视觉领域对高效长序列建模需求激增,对Mamba图像增强这方向的研究自然也逐渐火热。原因在于其高效长程建模,以及动态计算优势,在图像质量提升和细节恢复方面有难以替代的作用。 🧀因此短时间内,就有不…...
为什么要创建 Vue 实例
核心原因:Vue 需要一个「控制中心」来驱动整个应用 你可以把 Vue 实例想象成你应用的**「大脑」或「引擎」。它负责协调模板、数据、逻辑和行为,将它们变成一个活的、可交互的应用**。没有这个实例,你的代码只是一堆静态的 HTML、JavaScript 变量和函数,无法「活」起来。 …...

热烈祝贺埃文科技正式加入可信数据空间发展联盟
2025年4月29日,在福州举办的第八届数字中国建设峰会“可信数据空间分论坛”上,可信数据空间发展联盟正式宣告成立。国家数据局党组书记、局长刘烈宏出席并致辞,强调该联盟是推进全国一体化数据市场建设的关键抓手。 郑州埃文科技有限公司&am…...
大数据驱动企业决策智能化的路径与实践
📝个人主页🌹:慌ZHANG-CSDN博客 🌹🌹期待您的关注 🌹🌹 一、引言:数据驱动的企业竞争力重构 在这个瞬息万变的商业时代,“快者胜”的竞争逻辑愈发明显。企业如何在复杂环…...
深入理解 React 样式方案
React 的样式方案较多,在应用开发初期,开发者需要根据项目业务具体情况选择对应样式方案。React 样式方案主要有: 1. 内联样式 2. module css 3. css in js 4. tailwind css 这些方案中,均有各自的优势和缺点。 1. 方案优劣势 1. 内联样式: 简单直观,适合动态样式和…...