主从同步延迟的解决办法

  1. 如果主库和从库服务器配置不一样,从库的差点,那么就可能导致延迟时间加长。这时候,换成相同的服务器配置服务器即可。
  2. 从库压力太大了。一般主从了,从库基本用来查询,比如可能运营或者开发者自己都在从库上进行一系列的 sql 操作。那简单呗。多配几个从库,分摊压力,一主多从。
  3. 大事务。比如 delete 这种语句 不 limit 限制一下,如果数据量过大,导致主库运行时都花费了长时间,再同步到从库,这个时间间隔过长。

MySQL连接数过多的处理方法

当线上紧急出现mysql连接过多的故障, 可以通过以下两个方法修复

1. GDB紧急修改最大连接数

gdb -p $(cat /data/mydata/xxx.pid) -ex “set max_connections=500” -batch

2. 进入数据库全局修改

set GLOBAL max_connnections = 500

出现的原因

出现的原因有多种:

  1. 应用程序占用连接后没有释放
  2. 单纯业务量大, 连接爆了

解决办法

  1. 重构应用程序代码, 及时关闭连接, 或统一管理引入连接池概念
  2. 配置 interactive_timeout 重新定义交互式连接, 服务端等待的最大时间
  3. 配置 wait_timeout 重新定义非交互式, 服务端等待的最大时间 (默认28800 8小时)
  4. 引入分布式, 主从分离, 负载均衡等 降低数据库的压力

什么是分布式ID?

分布式系统全局唯一的 id

分布式ID需要满足什么条件?

  • 唯一性:必须保证ID是全局性唯一的,基本要求
  • 高性能:高可用低延时,ID生成响应要块,否则反倒会成为业务瓶颈
  • 高可用:100%的可用性是骗人的,但是也要无限接近于100%的可用性
  • 有序性:最好趋势递增,这个要求就得看具体业务场景了,一般不严格要求
  • 易拓展:要秉着拿来即用的设计原则,在系统设计和实现上要尽可能的简单

有哪些分布式ID的生成方式?

  • UUID
  • 数据库自增ID
  • 数据库多主模式
  • 号段模式
  • Redis
  • 雪花算法(SnowFlake)
  • 滴滴出品(TinyID)
  • 百度 (Uidgenerator)
  • 美团(Leaf)

UUID

UUID, 自不必多说, 简单好用, 全球任何机器执行下都唯一

执行后, 生成一条类似订单号的字符串 c2b8c2b9e46c47e3b30dca3b0d447718

缺点是:

  • 字符过长, 占用大量存储空间
  • 字符串是无序的, 对于查询, 排序的性能影响很大

数据库自增ID

数据库的 auto_increment 自增ID完全可以充当分布式ID

需要一个单独的MySQL实例用来生成ID, 在业务量不是很大时使用比较方便

但不推荐在业务量大的情况下使用这种方式, 单机数据库无法承受足够大的压力

数据库多主模式

既然一台无法达成效果, 那么就多加一台。

但是会存在一个问题: 生成重复的ID怎么办?

解决问题也有, 给每一个MySQL实例设置不同的步长, 区分开来, 就可以了

但随着业务增长, 机器也可能会逐步累加, 每增加一次, 就要连带着以往的Mysql实例配置的ID步长都修改

不方便扩容

号段模式

号段模式是当下分布式ID生成器的主流实现方式之一,号段模式可以理解为从数据库批量的获取自增ID,每次从数据库取出一个号段范围

例如 (1,1000] 代表1000个ID,具体的业务服务将本号段,生成1~1000的自增ID并加载到内存。表结构如下:

1
2
3
4
5
6
7
8
CREATE TABLE id_generator (
id int(10) NOT NULL,
max_id bigint(20) NOT NULL COMMENT '当前最大id',
step int(20) NOT NULL COMMENT '号段的布长',
biz_type int(20) NOT NULL COMMENT '业务类型',
version int(20) NOT NULL COMMENT '版本号',
PRIMARY KEY (`id`)
)

biz_type :代表不同业务类型

max_id :当前最大的可用id

step :代表号段的长度

version :是一个乐观锁,每次都更新version,保证并发时数据的正确性

等这批号段ID用完,再次向数据库申请新号段,对 max_id 字段做一次update操作,

update max_id= max_id + step

update成功则说明新号段获取成功,新的号段范围是 (max_id ,max_id + step]

由于多业务端可能同时操作,所以采用版本号 version 乐观锁方式更新

这种分布式ID生成方式不强依赖于数据库,不会频繁的访问数据库,对数据库的压力小很多。

基于Redis模式

Redis也同样可以实现,原理就是利用 redisincr 命令实现ID的原子性自增。

redis 实现需要注意一点,要考虑到 redis 持久化的问题。 redis 有两种持久化方式 RDBAOF

  • RDB 会定时打一个快照进行持久化,假如连续自增但redis没及时持久化,而这会Redis挂掉了,重启Redis后会出现ID重复的情况。
  • AOF 会对每条写命令进行持久化,即使Redis挂掉了也不会出现ID重复的情况,但由于incr命令的特殊性,会导致Redis重启恢复的数据时间过长。

基于雪花算法(Snowflake)模式

雪花算法(Snowflake)是twitter公司内部分布式项目采用的ID生成算法,

开源后广受国内大厂的好评,在该算法影响下各大公司相继开发出各具特色的分布式生成器。

Snowflake生成的是Long类型的ID,一个Long类型占8个字节,每个字节占8比特,也就是说一个Long类型占64个比特。

Snowflake ID组成结构:

正数位(占1比特)+ 时间戳(占41比特)+ 机器ID(占5比特)+ 数据中心(占5比特)+ 自增值(占12比特),

总共64比特组成的一个Long类型。

  • 第一个bit位(1bit):Java中long的最高位是符号位代表正负,正数是0,负数是1,一般生成ID都为正数,所以默认为0。
  • 时间戳部分(41bit):毫秒级的时间,不建议存当前时间戳,而是用(当前时间戳 - 固定开始时间戳)的差值,可以使产生的ID从更小的值开始;41位的时间戳可以使用69年,(1L << 41) / (1000L * 60 * 60 * 24 * 365) = 69年
  • 工作机器id(10bit):也被叫做 workId,这个可以灵活配置,机房或者机器号组合都可以。
  • 序列号部分(12bit),自增值支持同一毫秒内同一个节点可以生成4096个ID

Nginx负载均衡策略

当一台服务器的单位时间内的访问量越大时,服务器压力就越大,大到超过自身承受能力时,服务器就会崩溃。

为了避免服务器崩溃,让用户有更好的体验,我们通过负载均衡的方式来分担服务器压力。

负载均衡方式:

  • 轮询
  • 权重(weight)
  • ip哈希分配(ip_hash)
  • URL哈希分配(hash)
  • 最少连接(least_conn)
  • 响应时间(fair)

参考链接

轮询

每个请求按 时间顺序逐一分配 到不同的后端服务器,如果后端服务器挂了,能自动剔除。

1
2
3
4
upstream taobao {
server 192.168.0.14:8081;
server 192.168.0.15:8082;
}

权重(weight)

通过配置权重,指定轮询几率,权重和访问比率成正比,用于应用服务器性能不均的情况

1
2
3
4
upstream tmall {
server 192.168.0.17 weight=3;
server 192.168.0.18 weight=7;
}

ip哈希分配(ip_hash)

每个请求按访问ip的hash结果分配,这样每个访客固定访问一个应用服务器,可以解决session共享的问题。

使用IPv4地址前3个字节或者IPv6的整个地址用来计算哈希值。

1
2
3
4
5
upstream tmall {
ip_hash;
server 192.168.0.17:88;
server 192.168.0.18:80;
}

URL哈希分配(hash)

按访问url的hash结果来分配请求,使每个url定向到同一个后端服务器,后端服务器为缓存时比较有效。

1
2
3
4
5
6
upstream tmall {
hash $request_uri;
hash_method crc32;
server 192.168.0.17:88;
server 192.168.0.18:80;
}

最少连接(least_conn)

选取活跃连接数与权重weight的比值最小者为下一个处理请求的server:

原理相关链接: nginx负载均衡指令least_conn的真正含义

1
2
3
4
5
upstream tmall {
least_conn;
server 192.168.0.17:88;
server 192.168.0.18:80;
}

响应时间(fair)

按后端服务器的响应时间来分配请求,响应时间短的优先分配。

1
2
3
4
5
upstream taobao {
fair;
server 192.168.0.14:8081;
server 192.168.0.15:8082;
}

upstream参数

1
2
3
4
5
6
7
upstream taobao {
server 192.168.72.49:9090 down;
server 192.168.72.49:8080 weight=2;
server 192.168.72.49:6060 max_conns=800;
server 192.168.72.49:7070 backup;
server 192.168.72.49:8010 max_fails=3 fail_timeout=30s;
}
参数 描述 例子
server 反向服务地址 加端口 127.0.0.1:8010
weight 权重, 默认值为1 weight=5
max_fails 失败多少次 认为主机已挂掉则,踢出 max_fails=3
fail_timeout max_fails次失败后,暂停的时间。 fail_timeout=30s
backup 备用服务 表示备用, 压力较低
max_conns 允许最大连接数 max_conns=800
slow_start 当节点恢复,不立即加入, 防止刚刚恢复的服务器被大量连接超载失败 slow_start=30s
down 表示当前server暂时不参与负载