分布式数据库架构

分布式数据库架构

1、MySQL常见架构设计

对于mysql架构,一定会使用到读写分离,在此基础上有五种常见架构设计:一主一从或多从、主主复制、级联复制、主主与级联复制结合。

1.1、主从复制

这种架构设计是使用的最多的。在读写分离的基础上,会存在一台master作为写机,一个或多个slave作为读机。因为在实际的情况下,读的请求量一般是远远大于写请求的。
在这里插入图片描述
采用这种架构之后,当应用写入输入时,会把数据写入到master节点,然后由master节点将写入数据复制到slave节点上。

缺点:

  • master单机故障
  • 对master进行维护时,无法接收写请求
  • master复制延迟,查询数据延迟
  • slave提升为master后,可能会发生数据丢失(数据不一致)

1.1.1、 主从复制搭建

1、首先需要在两台机器上安装mysql镜像以及创建mysql容器

docker pull mysql:5.7

docker run --name mysql3307 -p 3307:3306 --privileged=true -ti -e MYSQL_ROOT_PASSWORD=123456 -e MYSQL_USER=user -e MYSQL_PASSWORD=pass -v /home/mysql/docker-data/3307/conf:/etc/mysql/conf.d -v /home/mysql/docker-data/3307/data/:/var/lib/mysql -v /home/mysql/docker-data/3307/logs/:/var/log/mysql -d mysql:5.7

2、需要在两台机器上的/home/mysql/docker-data/3307/conf目录下,需要创建mysql的配置文件my.cnf

my.cnf配置文件内容如下:

# For advice on how to change settings please see
# http://dev.mysql.com/doc/refman/5.7/en/server-configuration-defaults.html

[mysqld]
#
# Remove leading # and set to the amount of RAM for the most important data
# cache in MySQL. Start at 70% of total RAM for dedicated server, else 10%.
# innodb_buffer_pool_size = 128M
#
# Remove leading # to turn on a very important data integrity option: logging
# changes to the binary log between backups.
# log_bin
#
# Remove leading # to set options mainly useful for reporting servers.
# The server defaults are faster for transactions and fast SELECTs.
# Adjust sizes as needed, experiment to find the optimal values.
# join_buffer_size = 128M
# sort_buffer_size = 2M
# read_rnd_buffer_size = 2M
#datadir=/home/mysql/docker-data/3307/data
#socket=/home/mysql/docker-data/3307/mysql.sock

character_set_server=utf8
init_connect='SET NAMES utf8'

# Disabling symbolic-links is recommended to prevent assorted security risks
symbolic-links=0

#log-error=/home/mysql/docker-data/3307/logs/mysqld.log
#pid-file=/home/mysql/docker-data/3307/mysqld.pid
lower_case_table_names=1
#指定主机号,不允许出现重复
server-id=423307
#开启binlog
log-bin=mysql-bin
auto_increment_increment=2
auto_increment_offset=1

#rpl_semi_sync_master_enabled=1
#rpl_semi_sync_master_timeout=10000

3、在master的docker容器中添加mysql权限,开启备份机复制,并且设置备份用户信息。

#添加权限
GRANT REPLICATION SLAVE,FILE,REPLICATION CLIENT ON *.* TO 'repluser'@'%' IDENTIFIED BY '123456';

#刷新权限
FLUSH PRIVILEGES;

在这里插入图片描述
4、设置并刷新权限后,重启mysql服务器,可以查看master上的binlog信息。

show master status;

在这里插入图片描述
注意:至此上述步骤两台机器上都需要执行,参数上的设置按实际情况来定。

5、接着在slave中进入到mysql容器,设置master信息,用于标注当前slave的master是谁。

change master to master_host='localhost',master_port=3307,master_user='repluser',master_password='123456',master_log_file='mysql-bin.000002',master_log_pos=154;

参数解析

change master to master_host='master的ip',
master_port=master的端口号,
master_user='repluser',master_password='123456',
master_log_file='master中的binlob文件',
master_log_pos=master中的position位置信息;

在这里插入图片描述
6、设置完成后,还要开启slave中的IOSQL线程,这两个线程主要用于slave中进行数据备份,可以先查看slave中这两个线程的状态。

show slave status\G

在这里插入图片描述
开启slave中的IOSQL线程

start slave;

在这里插入图片描述
至此mysql主从复制搭建完成。

7、 相关状态信息的查看

查看slave中的binlog是否已经开启

show global variables like "%log%";

在这里插入图片描述
接着还可以查看master、slave中的进程信息

在master mysql中输入:

show processlist;

在这里插入图片描述
从上图中可以看出:master已经把所有的binlog发送给slave,并且等待更多的更新操作。

在slave mysql中输入:

show processlist;

在这里插入图片描述
从上图可以看出:在slave它已经连接到了master,正在等待master发送事件,并且slave已经读取了所有的relay log信息,并且正在等待更多的更新操作。

8、测试验证

连接主库,并在主库中创建数据库,创建数据库表以及添加行记录。此时会发现从库中也会创建相应的数据库和数据库表和行记录。

1.1.2、 MySQL复制原理

在mysql中,其有两种复制机制,分别是:异步复制半同步复制。默认采用异步复制。(上述主从复制操作为异步复制)

异步复制执行流程

在这里插入图片描述

  • 1、应用事务提交到master
  • 2、master接收到应用事务提交请求后,会更新内部的binlog日志,接着让mysql引擎执行事务操作,并返回给客户端执行结果信息。同时在master中会存在一个事件监听,其会一直监听master中binlog日志文件的改变,一旦发现日志文件发生改变,则会触发dump线程。
  • 3、dump线程被触发后,会通知slave中的IO线程现在有事务操作需要进行同步。
  • 4、slave中IO线程接收到通知后,会从slave中relay-log.info文件中获取slave中的binlog日志文件和pos位置信息。接着会把这部分信息发送给master的dump线程。
  • 5、master的dump线程接收到这些信息后,会根据slave发送的binlog日志文件和pos位置,将最新的binlog日志和pos位置后面的内容同步给slave的IO线程。
  • 6、slave的IO线程接收到这些信息后,会将这部分内容同步到slave的relay-bin文件中。
  • 7、当relay-bin文件发生改变后,会触发slave线程执行sql操作。(异步操作)
  • 8、当slave向relay-bin写入完成后,还会向master返回一个ACK消息,通知slave已经执行成功。

总结:对于这一系列操作,可以发现master和slave在进行同步时是以异步的方式完成的,master写入完binlog后,会马上通过引擎进行事务提交并向客户端返回响应,对于与slave同步的操作,则是异步完成的。

虽然这种方式的RT很快,但是很容易出现数据不一致的情况。

半同步复制执行流程

在这里插入图片描述

  • 半同步复制与异步复制的工作流程大体相似,但不同的是,当master中的binlog日志写入完成后,其不会马上通过引擎进行事务提交,而会处于等待,等到slave同步完成向master返回ACK通知后,才会唤醒等待,继续向下执行。
  • 等待的时长,默认为10秒,但该时间可以配置。
  • 半同步复制尽量的避免的主从数据不一致的情况,但是会造成吞吐量的降低。

对于这个问题,mysql也进行了解决,假设使用半同步复制进行备份时,slave节点挂掉了,那么当master等待10秒后,仍然会进行引擎提交,同时会将半同步复制切换为异步复制。等到slave节点重启后,又会自动的从异步复制切换到半同步复制。

主从异步复制日志效果

Mysql在进行复制操作时,默认是基于异步复制完成的。那为了更好的体会异步复制的效果,可以通过mysql日志来查看具体的复制过程效果。

启动主从两台Mysql服务器。

查看master的Mysql日志信息

docker logs -f mysql3307 | grep binlog_dump

在这里插入图片描述
​根据当前查看的日志信息,在master中已经开启了dump线程连接到了id为273307的slave节点,并且该id就是在slave的mysql配置文件中设置的id。

同时pos内容包括当前的binlog日志和pos位置。

查看slave的mysql日志信息
在这里插入图片描述
根据slave中的日志信息,可以看到,当前slave中已经开启了relay-log日志,其对应文件信息就是xxxxx-relay-bin。其内部保存的就是slave中的相关binlog信息和pos位置信息。

同时在slave中也已经开启了SQL Thread,并且根据信息可以,它会从xxxx-relay-bin.000001文件的4位置开始复制。

同时在slave中也开启了IO Thread,其已经连接到master,并且会从master的binlog日志的154的位置开启复制。

查看master当前的binlog日志信息

#确定当前master正在使用的binlog日志文件
cat mysql-bin.index

#查看当前binlog日志文件内容
tail -f mysql-bin.000002

在这里插入图片描述
查看slave当前的日志信息

cat relay-log.info

cat master.info

在这里插入图片描述
在这里插入图片描述

cat xxxxxxxxxx-relay-bin.index

在这里插入图片描述
在这里插入图片描述
监控slave日志信息

tail -f 8122977f8b0a-relay-bin.000002

在这里插入图片描述
master中新增数据,触发主从同步

  • 查看master修改前后的binlog日志
cat mysql-bin.000002 

在这里插入图片描述

  • 查看slave复制前后的relay-bin日志
 tail -f 41dc8a520939-relay-bin.000002

在这里插入图片描述

1.1.3、 主从半同步复制搭建

1、配置
进入mysql容器,加载lib,主从节点都要配置,因为主从节点间会存在切换。

install plugin rpl_semi_sync_master soname 'semisync_master.so';

install plugin rpl_semi_sync_slave soname 'semisync_slave.so';

在这里插入图片描述
查看插件信息

show plugins;

在这里插入图片描述
2、启用半同步(务必先启用从库,再启用主库

#先启用从库,再启用主库

#从库:
set global rpl_semi_sync_slave_enabled= {0|1};  # 1:启用,0:禁止

#主库:
set global rpl_semi_sync_master_enabled= {0|1}; # 1:启用,0:禁止

set global rpl_semi_sync_master_timeout=10000;  # 单位为ms

在这里插入图片描述
在这里插入图片描述
3、重启从库IO Thread

stop slave io_thread;
start slave io_thread;

4、截止到此已经完成半同步开启配置,可以查看主库状态信息和参数信息

#查询状态信息
show global status like "%sync%";

#查询参数信息
show global variables like '%sync%';

show global status like “%sync%”;
在这里插入图片描述
show global variables like ‘%sync%’;
在这里插入图片描述
根据上述的配置,当前主从两台服务器的复制方式已经改为半同步复制。接下来就可以来查看具体的效果。

  • 正常的向master中添加数据,slave可以进行正常数据更新。

master打印日志信息如下: 开启半同步复制,关闭异步复制
在这里插入图片描述

  • 关闭slave的IO Thread或者停止salve服务

再次向master中添加数据。此时可以发现,当进行数据提交时,会出现等待,过了十秒后,会对数据进行保存。同时slave中不会同步的进行数据更新。
在这里插入图片描述
在这里插入图片描述
如上图所示,超过时间后,半同步复制会转化为异步复制。此时复制机制就会由半同步复制转换为异步复制,当再次向master中添加数据,不会再次出现等待。

  • slave中重新开启IO Thread。

异步复制会再次转换为半同步复制,其次,在slave IO Tthread关闭这段时间内的数据,会同步到slave中,不会出现数据丢失。

1.2、主主复制

对于主从复制来说,其内部会存在一台master以及一台或多台slave。但有一个非常明显的问题,master是单点存在。一旦master宕机,则无法进行数据的写入。为了解决这个问题,可以使用主主复制架构。

在主主复制架构中,会存在两台master,没有slave。并且会对这两台master进行读写分离,两台master会进行相互的复制。

主主复制架构图
在这里插入图片描述
在此架构中,两台master会进行双向复制,为什么这么做呢? 因为假设现在负责写的master宕机了,那么写的工作则会交给之前负责读的服务器来完成,相当于它即负责写又负责读。等到原先负责写的master恢复了,其在继续负责写工作。 反之亦然。因此才需要两者间进行双向复制。

此时缺点也非常明显,虽然master不存在单点了,但是对于读来说,如果并发量大的话,它肯定扛不住。对于主主复制架构来说,应用较少。

1.2.1、主主复制搭建

主主复制的搭建和主从非常类似,只不过主主复制会进行互指。

1、参照主从完成搭建。(按照上述主从复制结构搭建)

2、原slave端也要开启权限

#添加权限
GRANT REPLICATION SLAVE,FILE,REPLICATION CLIENT ON *.* TO 'repluser'@'%' IDENTIFIED BY '123456';

#刷新权限
FLUSH PRIVILEGES;

#重启mysql服务并查看binlog信息
show master status

3、在master这一端也要配置slave的相关配置

change master to master_host='localhost',master_port=3308,master_user='repluser',master_password='123456',master_log_file='mysql-bin.000002',master_log_pos=154;

start slave;

4、查看master和slave的进程列表:show processlist。可以发现他们现在互为主备。

master
在这里插入图片描述
slave在这里插入图片描述

5、测试
当在两台服务器中添加数据,都可以完成双向同步。

1.3、级联复制架构

当读压力现在增大并且还想减小主从复制的性能消耗,可以采用级联复制架构。
在这里插入图片描述
写请求的入口仍为一个,但当master向slave进行复制时,对于slave可以分为多层, master只要向其中两台slave复制即可,然后再由slave将其数据复制到后面更多的slave中。

通过这种方式可以减轻master向slave复制的IO压力。

但是这种架构也存在一个弊端:slave的延迟会加大。

1.4、双主与级联复制结合架构

对于master在前面几种架构设计中,都存在单点问题, 对于master单点问题的解决,可以采用当前的架构。通过这种架构不仅可以解决master单点的问题,也可以解决slave延迟的问题。
在这里插入图片描述

2、Mysql高可用实践

以主主架构为例,现在不管写或者读,只要其中一个宕机,则会把它本身工作交给另外一台服务器完成。此时就需要对IP进行一个自动的指向。而且这种服务器IP切换,对于上层应用来说,应该是完全隐藏的,其无需知道当前是由谁来完成具体工作,其只需要来连接一个IP就可以。

对于这种需求,就需要通过keepAlived来完成IP的自动切换。
在这里插入图片描述
对于keepalived会在多台mysql服务器进行安装, 同时keepalived间也分为master和slave, 同时master会虚拟化一个VIP供应用进行连接。 如果一旦master挂掉后,会由slave节点继续工作,同时slave节点也会虚拟出相同VIP,供应用进行连接。

2.1、keepAlived高可用配置

1、安装keepalived

1. 下载keepalied安装包 http://www.keepalived.org/download.html
2. yum -y install openssl-devel gcc gcc-c++
3. mkdir /etc/keepalived
4. 上传安装包并解压  tar -zxvf keepalived-2.0.18.tar.gz
5. mv keepalived-2.0.18 /usr/local/keepalived
6. cd /usr/local/keepalived
7. ./configure && make && make install
8.创建启动文件
cp  -a /usr/local/etc/keepalived   /etc/init.d/
cp  -a /usr/local/etc/sysconfig/keepalived    /etc/sysconfig/
cp  -a /usr/local/sbin/keepalived    /usr/sbin/

2、编写执行shell脚本

进入/etc/keepalived。创建chk.sh,同时赋予执行权限:chmod +x chk.sh

#! /bin/bash
mysql -h 127.0.0.1 -u root -p123456 -P 3312 -e "show status;" >/dev/null 2>&1
if [ $? == 0 ]
then
    echo " $host mysql login successfully "
    exit 0
else
    echo "  mysql login faild"
    killall keepalived
    exit 2
fi

3、编写keepAlived配置文件

cd /etc/keepalived

vi keepalived.conf

! Configuration File for keepalived
#简单的头部,这里主要可以做邮件通知报警等的设置,此处就暂不配置了;
global_defs {
    #notificationd LVS_DEVEL
    router_id MYSQL_4   #唯一标识不允许出现重复
    script_user root
    enable_script_security
}
#预先定义一个脚本,方便后面调用,也可以定义多个,方便选择;
vrrp_script chk_haproxy {
    script "/etc/keepalived/chk.sh"
    interval 2  #脚本循环运行间隔
}
#VRRP虚拟路由冗余协议配置
vrrp_instance VI_1 {   #VI_1 是自定义的名称;
    state BACKUP    #MASTER表示是一台主设备,BACKUP表示为备用设备【我们这里因为设置为开启不抢占,所以都设置为备用】
    nopreempt      #开启不抢占
    interface ens33   #指定VIP需要绑定的物理网卡
    virtual_router_id 11   #VRID虚拟路由标识,也叫做分组名称,该组内的设备需要相同
    priority 130   #定义这台设备的优先级 1-254;开启了不抢占,所以此处优先级必须高于另一台

    advert_int 1   #生存检测时的组播信息发送间隔,组内一致
    authentication {    #设置验证信息,组内一致
        auth_type PASS   #有PASS 和 AH 两种,常用 PASS
        auth_pass 111111    #密码
    }
    virtual_ipaddress {
        192.168.200.200    #指定VIP地址,组内一致,可以设置多个IP
    }
    track_script {    #使用在这个域中使用预先定义的脚本,上面定义的
        chk_haproxy
    }
}

4、启动keepAlived

systemctl start keepalived

5、查看keepAlived执行状态

ps -ef|grep keepalived

在这里插入图片描述
6、可以通过tail -f /var/log/messages

7、查看ip信息,此时可以发现出现了配置的虚拟ip

ip a

8、测试
通过navicat使用虚拟IP连接mysql,当前连接IP为VIP。可以连接成功。

3、数据切分核心思想

3.1、为什么要进行数据切分?

当前微服务架构非常流行,很多都会采用微服务架构对其系统进行拆分。 而虽然产生了多个微服务,但因为其用户量和数据量的问题,很有可能仍然使用的是同一个数据库。
在这里插入图片描述
但是随着用户量和数据量增加,就会出现很多影响数据库性能的因素,如:数据存储量、IO瓶颈、访问量瓶颈等。此时就需要将数据进行拆分,从一个库拆分成多个库。

3.2、数据拆分方式

垂直拆分

垂直拆分是按照业务将表进行分类并分布到不同的数据节点上。在初始进行数据拆分时,使用垂直拆分是非常直观的一种方式。
在这里插入图片描述
垂直拆分的优点:

  • 拆分规则明确,按照不同的功能模块或服务分配不同的数据库。
  • 数据维护与定位简单。

垂直拆分的缺点:

  • 对于读写极其频繁且数据量超大的表,仍然存在存储与性能瓶颈。简单的索引此时已经无法解决问题。
  • 会出现跨库join。
  • 需要对代码进行重构,修改原有的事务操作。
  • 某个表数据量达到一定程度后扩展起来较为困难。

水平拆分

​为了解决垂直拆分出现的问题,可以使用水平拆分继续横向扩展,首先,可以如果当前数据库的容量没有问题的话,可以对读写极其频繁且数据量超大的表进行分表操作。由一张表拆分出多张表。

在一个库中,拆分出多张表,每张表存储不同的数据,这样对于其操作效率会有明显的提升。而且因为处于同一个库中,也不会出现分布式事务的问题。
在这里插入图片描述

而拆分出多张表后,如果当前数据库的容量已经不够了,但是还要继续拆分的话,就可以进行分库操作,产生多个数据库,然后在扩展出的数据库中继续扩展表。
在这里插入图片描述

水平拆分的优点:

  • 尽量的避免了跨库join操作。
  • 不会存在超大型表的性能瓶颈问题。
  • 事务处理相对简单。
  • 只要拆分规则定义好,很难出现扩展性的限制。

水平拆分的缺点:

  • 拆分规则不好明确,规则一定会和业务挂钩,如根据id、根据时间等。
  • 不好明确数据位置,难以进行维护。
  • 多数据源管理难度加大,代码复杂度增加。
  • 也会存在分布式事务问题
  • 数据库维护成本增加

数据切分带来的问题

  • 按照用户ID求模,将数据分散到不同的数据库,具有相同数据用户的数据都被分散到一个库中。
  • 按照日期,将不同月甚至日的数据分散到不同的库中。
  • 按照某个特定的字段求模,或者根据特定范围段分散到不同的库中。

数据切分带来的核心问题

  • 产生引入分布式事务的问题。
  • 跨节点 Join 的问题。
  • 跨节点合并排序分页问题。

3.3、Mycat中间件使用

当对数据拆分后会产生诸多的问题,对于这些问题的解决,可以借助于数据库中间件来进行解决,现在时下比较流行的是使用Mycat。

Mycat是一款数据库中间件,对于应用程序来说是完全透明化的,不管底层的数据如何拆分,应用只需要连接Mycat即可完成对数据的操作。同时它还支持MySQL、SQL Server、Oracle、DB2、PostgreSQL等主流数据库。但是Mycat不会进行数据存储,它只是用于数据的路由。

其底层是基于拦截思想实现,其会拦截用户发送过来的SQL语句,首先对SQL语句做了一些特定的分析:如分片分析、路由分析、读写分离分析、缓存分析等,然后将此SQL发往后端的真实数据库,并将返回的结果做适当的处理,最终再返回给用户。
在这里插入图片描述

Mycat特性

  • 支持SQL92标准
  • 遵守Mysql原生协议,跨语言,跨平台,跨数据库的通用中间件代理。
  • 基于心跳的自动故障切换,支持读写分离,支持MySQL主从,以及galera cluster集群。
  • 支持Galera for MySQL集群,Percona Cluster或者MariaDB cluster
  • 基于Nio实现,有效管理线程,高并发问题。
  • 支持数据的多片自动路由与聚合,支持sum,count,max等常用的聚合函数。
  • 支持单库内部任意join,支持跨库2表join。
  • 支持通过全局表,ER关系的分片策略,实现了高效的多表join查询。
  • 支持多租户方案。
  • 支持分布式事务(弱xa)。
  • 支持全局序列号,解决分布式下的主键生成问题。
  • 分片规则丰富,插件化开发,易于扩展。
  • 强大的web,命令行监控。
  • 支持前端作为mysq通用代理,后端JDBC方式支持Oracle、DB2、SQL Server 、 mongodb 。
  • 支持密码加密
  • 支持服务降级
  • 支持IP白名单
  • 支持SQL黑名单、sql注入攻击拦截
  • 支持分表(1.6)
  • 集群基于ZooKeeper管理,在线升级,扩容,智能优化,大数据处理(2.0开发版)。

Mycat源码的本地部署运行

**源码下载:**https://codeload.github.com/MyCATApache/Mycat-Server/zip/Mycat-server-1675-release

默认端口:8066

配置启动参数:

-DMYCAT_HOME=D:\workspace\Mycat-Server-Mycat-server-1675-release\src\main
#设置堆外内存大小
-XX:MaxDirectMemorySize=512M 

注意:为什么要设置堆外内存:当使用mycat对非分片查询时,会把所有的数据查询出来,然后把这部分数据放在堆外内存中

在Mycat有核心三个配置文件,分别为:sever.xml、schema.xml、rule.xml

  • server.xml:是Mycat服务器参数调整和用户授权的配置文件。
  • schema.xml:是逻辑库定义和表以及分片定义的配置文件
  • rule.xml:是分片规则的配置文件,分片规则的具体一些参数信息单独存放为文件,也在这个目录下,配置文件修改需要重启MyCAT。

MyCat核心概念

在学习Mycat首先需要先对其内部一些核心概念有足够的了解。

  • 逻辑库:Mycat中的虚拟数据库。对应实际数据库的概念。在没有使用mycat时,应用需要确定当前连接的数据库等信息,那么当使用mycat后,也需要先虚拟一个数据库,用于应用的连接。
  • 逻辑表:mycat中的虚拟数据表。对应时间数据库中数据表的概念。
  • 非分片表:没有进行数据切分的表。
  • 分片表:已经被数据拆分的表,每个分片表中都有原有数据表的一部分数据。多张分片表可以构成一个完整数据表。
  • ER表:子表的记录与所关联的父表记录存放在同一个数据分片上,即子表依赖于父表,通过表分组(Table Group)保证数据Join不会跨库操作。表分组(Table Group)是解决跨分片数据join的一种很好的思路,也是数据切分规划的重要一条规则
  • 全局表:可以理解为是一张数据冗余表,如状态表,每一个数据分片节点又保存了一份状态表数据。数据冗余是解决跨分片数据join的一种很好的思路,也是数据切分规划的另外一条重要规则。
  • 分片节点(dataNode):数据切分后,每一个数据分片表所在的数据库就是分片节点。
  • 节点主机(dataHost):数据切分后,每个分片节点(dataNode)不一定都会独占一台机器,同一机器上面可以有多个分片数据库,这样一个或多个分片节点(dataNode)所在的机器就是节点主机(dataHost),为了规避单节点主机并发数限制,尽量将读写压力高的分片节点(dataNode)均衡的放在不同的节点主机(dataHost)。
  • 分片规则(rule):按照某种业务规则把数据分到某个分片的规则就是分片规则。
  • 全局序列号(sequence):也可以理解为分布式id。数据切分后,原有的关系数据库中的主键约束在分布式条件下将无法使用,因此需要引入外部机制保证数据唯一性标识,这种保证全局性的数据唯一标识的机制就是全局序列号(sequence),如UUID、雪花算法等。

4、Mycat企业级应用实践

4.1、环境参数配置

在server.xml 文件中的system标签下配置所有的参数,全部为环境参数,可以根据当前需要进行开启和配置,如:设置mycat连接端口号

<property name="serverPort">8066</property>

在这里插入图片描述

4.2、数据非分片

4.2.1、配置初始化信息

应用连接mycat的话,也需要设置用户名、密码、被连接数据库信息,要配置这些信息的话,可以修改server.xml,在其内部添加内容如下:

<!--配置自定义用户信息-->
<!--连接用户名-->
<user name="mycat">
    <!--连接密码-->
    <property name="password">mycat</property>
    <!--创建虚拟数据库-->
    <property name="schemas">userdb</property>
    <!--指定该库是否只读-->
    <!--<property name="readOnly">true</property>-->
</user>

4.2.2、配置虚拟数据库&表

<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">

	<!--配置虚拟数据库-->
	<!--name:虚拟逻辑数据库名称,对应server.xml中的schemas属性值-->
	<!--dataNode:逻辑库中逻辑表的默认数据节点-->
	<!--sqlMaxLimit:类似于SQL上添加limit,如schema为非分片库,则该属性无效-->
	<schema name="userdb" checkSQLschema="true" dataNode="localdn" sqlMaxLimit="500">
		<!--配置虚拟逻辑表-->
		<!--name:逻辑表名称,必须唯一-->
		<!--dataNode:逻辑表所处的数据节点,值必须与dataNode标签中的name属性对应。如果值过多可以用$连接,如:dn$1-99,dn$200-400-->
		<!--primaryKey:逻辑表对应的真实表的主键id的字段名-->
		<table name="tb_user" dataNode="localdn" primaryKey="user_id"/>
	</schema>

	<!--配置dataNode信息-->
	<!--name:当前datanode名称-->
	<!--dataHost:分片节点所处的节点主机,该值必须与dataHost标签中的name属性对应-->
	<!--database:当前数据节点所对应的实际物理数据库-->
	<dataNode name="localdn" dataHost="localdh" database="user"/>

	<!--配置节点主机-->
	<!--balance:用于进行读操作指向,有三个值可选
		0:所有读操作都发送到当前可用的writeHost上
		1:所有读操作都随机的发送到readHost上
		2:所有读操作都随机发送在writeHost与readHost上
	-->
	<!--maxCon:指定每个读写实例连接池的最大连接。也就是说,标签内嵌套的writeHost、readHost标签都会使用这个属性的值来实例化出连接池的最大连接数-->
	<!--minCon:指定每个读写实例连接池的最小连接,初始化连接池的大小-->
	<!--name:当前节点主机名称,不允许出现重复-->
	<!--dbType:当时使用的数据库类型-->
	<!--dbDriver:当前使用的数据库驱动-->
	<!--writeType:用于写操作指向,有三个值可选
		0:所有写操作都发送到可用的writeHost上
		1:所有写操作都随机发送到readHost上
		2:所有写操作都随机发送在writeHost与readHost上
	-->
	<!--readHost是从属于writeHost的,即意味着它从那个writeHost获取同步数据。
		因此,当它所属的writeHost宕机了,则它也不会再参与到读写分离中来,即“不工作了”。这是因为此时,它的数据已经“不可靠”了。
		基于这个考虑,目前mycat 1.3和1.4版本中,若想支持MySQL一主一从的标准配置,并且在主节点宕机的情况下,从节点还能读取数据。
		则需要在Mycat里配置为两个writeHost并设置banlance=1。”-->
	<!--switchType:设置节点切换操作,有三个值可选
		-1:不自动切换
		1:自动切换,默认值
		2:基于mysql主从同步的状态决定是否切换
	-->
	<!--slaveThreshold:主从同步状态决定是否切换,延迟超过该值就不切换-->
	<dataHost balance="0" maxCon="100" minCon="10" name="localdh" dbType="mysql" dbDriver="jdbc" writeType="0" switchType="1" slaveThreshold="1000">
		<!--查询心跳-->
		<heartbeat>select user()</heartbeat>
		<!--配置写节点实际物理数据库信息-->
		<writeHost url="jdbc:mysql://localhost:3306" host="host1" password="root" user="root"></writeHost>
	</dataHost>
</mycat:schema>

4.2.3 测试

通过navicat创建本地数据库连接并创建对应数据库,同时创建mycat连接。 在mycat连接中操作表,添加数据,可以发现,本地数据库中同步的也新增了对应的数据。

4.3、根据ID取模数据分片

当一个数据表中的数据量非常大时,就需要考虑对表内数据进行分片,拆分的规则有很多种,比较简单的一种就是,通过对id进行取模,完成数据分片。

1)修改schema.xml

table标签新增属性:subTables、rule

<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">

	<!--配置虚拟数据库-->
	<!--name:虚拟逻辑数据库名称,对应server.xml中的schemas属性值-->
	<!--dataNode:逻辑库中逻辑表的默认数据节点-->
	<!--sqlMaxLimit:类似于SQL上添加limit,如schema为非分片库,则该属性无效-->
	<schema name="userdb" checkSQLschema="true" dataNode="localdn" sqlMaxLimit="500">
		<!--配置虚拟逻辑表-->
		<!--name:逻辑表名称,必须唯一-->
		<!--dataNode:逻辑表所处的数据节点,值必须与dataNode标签中的name属性对应。如果值过多可以用$连接,如:dn$1-99,dn$200-400-->
		<!--primaryKey:逻辑表对应的真实表的主键id的字段名-->
		<!--subTables:分表的名称。可以存在多个,tb_user1,tb_user2,tb_user3.如果分表较多,可以通过$连接:tb_user$1-3-->
		<!--rule:分片规则,对应rule.xml中配置-->
		<table name="tb_user" dataNode="localdn" primaryKey="user_id" subTables="tb_user$1-3" rule="mod-long"/>
	</schema>

	<!--配置dataNode信息-->
	<!--name:当前datanode名称-->
	<!--dataHost:分片节点所处的节点主机,该值必须与dataHost标签中的name属性对应-->
	<!--database:当前数据节点所对应的实际物理数据库-->
	<dataNode name="localdn" dataHost="localdh" database="user"/>

	<!--配置节点主机-->
	<!--balance:用于进行读操作指向,有三个值可选
		0:所有读操作都发送到当前可用的writeHost上
		1:所有读操作都随机的发送到readHost上
		2:所有读操作都随机发送在writeHost与readHost上
	-->
	<!--maxCon:指定每个读写实例连接池的最大连接。也就是说,标签内嵌套的writeHost、readHost标签都会使用这个属性的值来实例化出连接池的最大连接数-->
	<!--minCon:指定每个读写实例连接池的最小连接,初始化连接池的大小-->
	<!--name:当前节点主机名称,不允许出现重复-->
	<!--dbType:当时使用的数据库类型-->
	<!--dbDriver:当前使用的数据库驱动-->
	<!--writeType:用于写操作指向,有三个值可选
		0:所有写操作都发送到可用的writeHost上
		1:所有写操作都随机发送到readHost上
		2:所有写操作都随机发送在writeHost与readHost上
	-->
	<!--readHost是从属于writeHost的,即意味着它从那个writeHost获取同步数据。
		因此,当它所属的writeHost宕机了,则它也不会再参与到读写分离中来,即“不工作了”。这是因为此时,它的数据已经“不可靠”了。
		基于这个考虑,目前mycat 1.3和1.4版本中,若想支持MySQL一主一从的标准配置,并且在主节点宕机的情况下,从节点还能读取数据。
		则需要在Mycat里配置为两个writeHost并设置banlance=1。”-->
	<!--switchType:设置节点切换操作,有三个值可选
		-1:不自动切换
		1:自动切换,默认值
		2:基于mysql主从同步的状态决定是否切换
	-->
	<!--slaveThreshold:主从同步状态决定是否切换,延迟超过该值就不切换-->
	<dataHost balance="0" maxCon="100" minCon="10" name="localdh" dbType="mysql" dbDriver="jdbc" writeType="0" switchType="1" slaveThreshold="1000">
		<!--查询心跳-->
		<heartbeat>select user()</heartbeat>
		<!--配置写节点实际物理数据库信息-->
		<writeHost url="jdbc:mysql://localhost:3306" host="host1" password="root" user="root"></writeHost>
	</dataHost>
</mycat:schema>

2)修改rule.xml

在schema.xml中已经指定规则为mod-long。因此需要到该文件中修改对应信息。

<tableRule name="mod-long">
    <rule>
        <!--当用用于id取模的字段-->
        <columns>user_id</columns>
        <algorithm>mod-long</algorithm>
    </rule>
</tableRule>

<!--修改当前的分片数量-->
<function name="mod-long" class="io.mycat.route.function.PartitionByMod">
		<!-- how many data nodes -->
		<!-- 根据datanode数量进行取模分片,也就是要模几。 -->
		<property name="count">3</property>
	</function>

3)测试

  • 向数据库中插入一千条数据,可以发现,其会根据id取模,放入不同的三张表中。

  • 当根据id查询时,会通过对id的取模,确定当前要查询的分片。并且首先会先查询mycat中的ehcache缓存,再来查询数据分片。

  • 当查询所有数据时,会查询所有数据分片。

4)缺陷

通过id取模分片这种方式实际中应用较少。主要因为两点问题:

根据id取模,1)散列不均匀,出现数据倾斜。2)动态扩容时,存在rehash,出现数据丢失。

1)数据散列不均匀,容易出现数据倾斜。每张表中的数据量差距较大。

2)动态扩容后,当需要新增表时,需要对模数修改,有可能就会造成当查询某个分片时,在该分片中找不到对应数据。

3)动态扩容后,要进行rehash操作。

4.4、全局序列号

当进行数据切分后,数据会存放在多张表中,如果仍然通过数据库自增id的方式,就会出现ID重复的问题,造成数据错乱。所以当拆分完数据后,需要让每一条数据都有自己的ID,并且在多表中不能出现重复。比较常见的会使用雪花算法来生成分布式id。

在Mycat中也提供了四种方式来进行分布式id生成:基于文件、基于数据库、基于时间戳和基于ZK。

4.4.1、基于本地文件方式生成

优点:本地加载,读取速度较快。

缺点:当MyCAT重新发布后,配置文件中的sequence会恢复到初始值。

​生成的id没有含义,如时间。

​MyCat如果存在多个,会出现id重复问题。

1)修改sequence_conf.properties

USER.HISIDS=  #使用过的历史分段,可不配置
USER.MINID=1  #最小ID值
USER.MAXID=200000  #最大ID值
USER.CURID=1000  #当前ID值

2)修改server.xml

<!--设置全局序号生成方式
   0:文件
   1:数据库
   2:时间戳
   3:zookeeper
  -->
<property name="sequnceHandlerType">0</property>
<!--进入序列匹配流程, 必须带有MYCATSEQ_或者 mycatseq_-->
<property name="sequnceHandlerPattern">(?:(\s*next\s+value\s+for\s*MYCATSEQ_(\w+))(,|\)|\s)*)+</property>
<property name="sequenceHanlderClass">io.mycat.route.sequence.handler.HttpIncrSequenceHandler</property>

3)测试

重启mycat,并查询是否修改成功

show @@sysparam

在这里插入图片描述

通过navicat插入数据

insert into tb_user(user_id,user_name) values('next value for MYCATSEQ_USER','wangwu')

通过程序插入数据

@Insert("insert into tb_user(user_id,user_name) values('next value for MYCATSEQ_USER',#{userName})")
void addUser(User user);

4.4.2、基于数据库生成

优点:能够进行id批量生成,在分布式下,可以避免id重复问题。

缺点:ID没有意义,对数据库有压力。

1)在实际数据库执行dbseq.sql中的sql语句,执行完毕后,会创建一张表。
在这里插入图片描述

2)修改sequence_db_conf.properties

TB_USER=localdn

3)修改server.xml文件,修改全局序列号生成方式为数据库方式

<property name="sequnceHandlerType">1</property>

4)修改schema.xml。在table中添加自增属性

<table name="tb_user" dataNode="localdn" primaryKey="id" subTables="tb_user$1-3" rule="mod-long" autoIncrement="true"/>

5)测试

通过navicat新增记录

insert into tb_user(user_id,user_name) values('next value for MYCATSEQ_TB_USER','wangwu')

在这里插入图片描述

4.4.3、基于zookeeper生成

1)修改server.xml,更改生成模式

<property name="sequenceHandlerType">3</property>

2)修改myid.properties,配置zk连接信息

loadZk=true
zkURL=192.168.200.131:2181
clusterId=01
myid=mycat_fz_01
clusterNodes=mycat_fz_01
#server  booster  ;   booster install on db same server,will reset all minCon to 1
#type=server
#boosterDataHosts=localhost1

3)修改sequence_distributed_conf.properties

INSTANCEID=ZK #声明使用zk生成
CLUSTERID=01

4)测试

启动mycatServer后,通过zk客户端查看节点信息。会发现新增了一个mycat节点

./zkCli.sh

ls /

在这里插入图片描述
插入数据

insert into tb_user(user_id,user_name) values('n
ext value for MYCATSEQ_TB_USER12','heima')

next value for MYCATSEQ_ 后的内容可以随意指定。
在这里插入图片描述

5)特性:

ID 结构:long 64 位,ID 最大可占 63 位

* |current time millis(微秒时间戳 38 位,可以使用 17 年)|clusterId(机房或者 ZKid,通过配置文件配置 5位)|instanceId(实例 ID,可以通过 ZK 或者配置文件获取,5 位)|threadId(线程 ID,9 位)|increment(自增,6 位)

* 一共 63 位,可以承受单机房单机器单线程 1000*(2^6)=640000 的并发。

* 无悲观锁,无强竞争,吞吐量更高

7.4.4)基于时间戳生成

优点:不存在上面两种方案因为mycat的重启导致id重复的现象,ID= 64 位二进制 (42(毫秒)+5(机器 ID)+5(业务编码)+12(重复累加),每毫秒可以并发 12 位二进制的累加。

缺点:数据类型太长,建议采用bigint(最大取值18446744073709551615)

1)修改server.xml。更改生成方式

<property name="sequenceHandlerType">2</property>

2)修改sequence_time_conf.properties

#sequence depend on TIME
#WORKID与DATAACENTERID: 0-31 任意整数。多mycat节点下,每个节点的WORKID、DATAACENTERID不能重复,组成唯一标识,总共支持32*32=1024 种组合
WORKID=01
DATAACENTERID=01

3)测试

新增数据

insert into tb_user(user_id,user_name) values('next value for MYCATSEQ_TB_USER12','heima')

next value for MYCATSEQ_ 后的内容可以随意指定。
在这里插入图片描述

5、MyCat分库&读写分离

之前已经基于id取模完成了分表操作,但是一个数据库的容量毕竟是有限制的,如果数据量非常大,分表已经满足不了的话,就会进行分库操作。

​当前分库架构如下:
在这里插入图片描述

现在存在两个主库,并且各自都有从节点。 当插入数据时,根据id取模放入不同的库中。同时主从间在进行写时复制的同时,还要完成主从读写分离的配置。

1)修改schema.xml。配置多datenode与datahost。同时配置主从读写分离。

<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">

    <schema name="userdb" checkSQLschema="true" dataNode="dn09" sqlMaxLimit="500">
        <table name="tb_user" dataNode="dn09,dn10" primaryKey="user_id" rule="mod-long"/>
    </schema>

    
    <dataNode name="dn09" dataHost="dh09" database="user"/>
    <dataNode name="dn10" dataHost="dh10" database="user"/>

    <dataHost name="dh09" balance="1" maxCon="100" minCon="10"  dbType="mysql" dbDriver="jdbc" writeType="0" switchType="1" slaveThreshold="1000">
        <!--查询心跳-->
        <heartbeat>select user()</heartbeat>
        <!--配置写节点实际物理数据库信息-->
        <writeHost url="jdbc:mysql://192.168.200.142:3309" host="host1"  user="root" password="123456">
            <!--配置读节点实际物理数据库信息-->
            <readHost host="host2" url="jdbc:mysql://192.168.200.145:3309" user="root" password="123456" ></readHost>
        </writeHost>
    </dataHost>

    <dataHost name="dh10" balance="1" maxCon="100" minCon="10"  dbType="mysql" dbDriver="jdbc" writeType="0" switchType="1" slaveThreshold="1000">
        <!--查询心跳-->
        <heartbeat>select user()</heartbeat>
        <!--配置写节点实际物理数据库信息-->
        <writeHost url="jdbc:mysql://192.168.200.142:3310" host="host1"  user="root" password="123456">
            <!--配置读节点实际物理数据库信息-->
            <readHost host="host2" url="jdbc:mysql://192.168.200.145:3310" user="root" password="123456" ></readHost>
        </writeHost>
    </dataHost>
</mycat:schema>

2)修改rule.xml。配置取模时的模数

<function name="mod-long" class="io.mycat.route.function.PartitionByMod">
    <!-- how many data nodes -->
    <!-- 根据datanode数量进行取模分片,也就是要模几。 -->
    <property name="count">2</property>
</function>

3)进行批量数据添加,可以发现数据落在了不同的库中。
在这里插入图片描述
在这里插入图片描述

4)读写分离验证

设置log4j2.xml的日志级别为DEBUG

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="DEBUG">
		........
        <asyncRoot level="DEBUG" includeLocation="true">
			........
        </asyncRoot>
    </Loggers>
</Configuration>

基于mysql服务进行数据查看,观察控制台信息,可以看到对于read请求的数据源,分别使用的是配置文件的配置。

在这里插入图片描述
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/31777.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

JS 介绍 Babel 的使用及 presets plugins 的概念

一、Babel 是什么 Bebal 可以帮助我们将新 JS 语法编译为可执行且兼容旧浏览器版本的一款编译工具。 举个例子&#xff0c;ES6&#xff08;编译前&#xff09;&#xff1a; const fn () > {};ES5&#xff08;编译后&#xff09;&#xff1a; var fn function() {}二、B…

设计模式-抽象工厂模式

抽象工厂模式 1、抽象工厂模式简介2、具体实现 1、抽象工厂模式简介 抽象工厂模式(Abstract Factory Pattern)在工厂模式尚添加了一个创建不同工厂的抽象接口(抽象类或接口实现)&#xff0c;该接口可叫做超级工厂。在使用过程中&#xff0c;我们首先通过抽象接口创建不同的工厂…

【HTML界面设计(二)】说说模块、登录界面

记录很早之前写的前端界面&#xff08;具体时间有点久远&#xff09; 一、说说模板 采用 适配器&#xff08;Adapter&#xff09;原理 来设计这款说说模板&#xff0c;首先看一下完整效果 这是demo样图&#xff0c;需要通过业务需求进行修改的部分 这一部分&#xff0c;就是dem…

Redis系列--布隆过滤器(Bloom Filter)

一、前言 在实际开发中&#xff0c;会遇到很多要判断一个元素是否在某个集合中的业务场景&#xff0c;类似于垃圾邮件的识别&#xff0c;恶意ip地址的访问&#xff0c;缓存穿透等情况。类似于缓存穿透这种情况&#xff0c;有许多的解决方法&#xff0c;如&#xff1a;redis存储…

宏景eHR SQL注入漏洞复现(CNVD-2023-08743)

0x01 产品简介 宏景eHR人力资源管理软件是一款人力资源管理与数字化应用相融合&#xff0c;满足动态化、协同化、流程化、战略化需求的软件。 0x02 漏洞概述 宏景eHR 存在SQL注入漏洞&#xff0c;未经过身份认证的远程攻击者可利用此漏洞执行任意SQL指令&#xff0c;从而窃取数…

如何在大规模服务中迁移缓存

当您启动初始服务时&#xff0c;通常会过度设计以考虑大量流量。但是&#xff0c;当您的服务达到爆炸式增长阶段&#xff0c;或者如果您的服务请求和处理大量流量时&#xff0c;您将需要重新考虑您的架构以适应它。糟糕的系统设计导致难以扩展或无法满足处理大量流量的需求&…

docker基础

文章目录 通过Vagrant安装虚拟机修改虚拟机网络配置 docker CE安装(在linux上)docker desktop安装(在MacOS上)Docker架构关于-阿里云镜像加速服务配置centos卸载docker 官网: http://www.docker.com 仓库: https://hub.docker.com Docker安装在虚拟机上&#xff0c;可以通过V…

Go语言的TCP和HTTP网络服务基础

目录 【TCP Socket 编程模型】 Socket读操作 【HTTP网络服务】 HTTP客户端 HTTP服务端 TCP/IP 网络模型实现了两种传输层协议&#xff1a;TCP 和 UDP&#xff0c;其中TCP 是面向连接的流协议&#xff0c;为通信的两端提供稳定可靠的数据传输服务&#xff1b;UDP 提供了一种…

[MySQL]不就是SQL语句

前言 本期主要的学习目标是SQl语句中的DDL和DML实现对数据库的操作和增删改功能&#xff0c;学习完本章节之后需要对SQL语句手到擒来。 1.SQL语句基本介绍 SQL&#xff08;Structured Query Language&#xff09;是一种用于管理关系型数据库的编程语言。它允许用户在数据库中存…

双因素身份验证在远程访问中的重要性

在快速发展的数字环境中&#xff0c;远程访问计算机和其他设备已成为企业运营的必要条件。无论是在家庭办公室运营的小型初创公司&#xff0c;还是团队分散在全球各地的跨国公司&#xff0c;远程访问解决方案都能保证工作效率和连接性&#xff0c;能够跨越距离和时间的阻碍。 …

7Z045 引脚功能详解

本文针对7Z045芯片&#xff0c;详细讲解硬件设计需要注意的技术点&#xff0c;可以作为设计和检查时候的参考文件。问了方便实用&#xff0c;按照Bank顺序排列&#xff0c;包含配置Bank、HR Bank、HP Bank、GTX Bank、供电引脚等。 参考文档包括&#xff1a; ds191-XC7Z030-X…

怎么计算 flex-shrink 的缩放尺寸

计算公式: 子元素的宽度 - (子元素的宽度的总和 - 父盒子的宽度) * (某个元素的flex-shrink / flex-shrink总和) 面试问题是这样的下面 left 和 right 的宽度分别是多少 * {padding: 0;margin: 0;}.container {width: 500px;height: 300px;display: flex;}.left {width: 500px…

红日靶场(一)外网到内网速通

红日靶场&#xff08;一&#xff09; 下载地址&#xff1a;http://vulnstack.qiyuanxuetang.net/vuln/detail/2/ win7:双网卡机器 win2003:域内机器 win2008域控 web阶段 访问目标机器 先进行一波信息收集&#xff0c;扫一下端口和目录 扫到phpmyadmin&#xff0c;还有一堆…

【资料分享】Xilinx Zynq-7010/7020工业核心板规格书(双核ARM Cortex-A9 + FPGA,主频766MHz)

1 核心板简介 创龙科技SOM-TLZ7x是一款基于Xilinx Zynq-7000系列XC7Z010/XC7Z020高性能低功耗处理器设计的异构多核SoC工业核心板&#xff0c;处理器集成PS端双核ARM Cortex-A9 PL端Artix-7架构28nm可编程逻辑资源&#xff0c;通过工业级B2B连接器引出千兆网口、USB、CAN、UA…

Triton教程 --- 动态批处理

Triton教程 — 动态批处理 Triton系列教程: 快速开始利用Triton部署你自己的模型Triton架构模型仓库存储代理模型设置优化动态批处理 Triton 提供了动态批处理功能&#xff0c;将多个请求组合在一起执行同一模型以提供更大的吞吐量。 默认情况下&#xff0c;只有当每个输入在…

【开源与项目实战:开源实战】81 | 开源实战三(上):借Google Guava学习发现和开发通用功能模块

上几节课&#xff0c;我们拿 Unix 这个超级大型开源软件的开发作为引子&#xff0c;从代码设计编写和研发管理两个角度&#xff0c;讲了如何应对大型复杂项目的开发。接下来&#xff0c;我们再讲一下 Google 开源的 Java 开发库 Google Guava。 Google Guava 是一个非常成功、…

io.netty学习(十一)Reactor 模型

目录 前言 传统服务的设计模型 NIO 分发模型 Reactor 模型 1、Reactor 处理请求的流程 2、Reactor 三种角色 单Reactor 单线程模型 1、消息处理流程 2、缺点 单Reactor 多线程模型 1、消息处理流程 2、缺点 主从Reactor 多线程模型 主从Reactor 多线程模型示例 1…

CTF-Show密码学:ZIP文件密码破解【暴力破解】

萌新 隐写23 题目内容&#xff1a; 文件的主人喜欢用生日做密码&#xff0c;而且还是个90后。 一、已知条件 在这个题目中&#xff0c;我们有以下已知条件&#xff1a; 文件的主人喜欢用生日做密码 - 这个条件告诉我们&#xff0c;密码可能是一个八位的纯数字密码&#xff0c…

云原生之深入解析如何正确计算Kubernetes容器CPU使用率

一、简介说明 使用 Prometheus 配置 kubernetes 环境中 Container 的 CPU 使用率时&#xff0c;会经常遇到 CPU 使用超出 100%&#xff0c;现在来分析一下&#xff1a; container_spec_cpu_period&#xff1a;当对容器进行 CPU 限制时&#xff0c;CFS 调度的时间窗口&#xff…

[架构之路-214]- UML-类图图解、详解、结构化、本质化讲解

目录 一、什么是类 1.1 概述 1.2 UML中类的表示 1.3 接口 1.4 抽象类 1.5 模板类 二、什么类图 2.1 概述 2.2 类关系 三、UML类图 3.1 结构关系 3.1.1 完全一体&#xff1a;继承关系 &#xff08;类与类耦合度最高&#xff0c;类与类之间最强的关系&#xff09; …