对读写分离思想的思考

工作后一段时间后,慢慢发现读写分离的思想出现过很多。比如在 MySQL 集群中的读写分离,MySQL 引擎 InnoDB 中的 MVCC,以及 JDK 中的 CopyOnWriteArrayList 中都有体现。

一、MySQL 集群读写分离

大多数互联网业务中,往往读多写少,这时候数据库的读会首先成为数据库的瓶颈。如果我们已经优化了 SQL,但是读依旧还是瓶颈时,这时就可以选择“读写分离”架构了。

1、具体实施

  • 集群分为主从库,主库用来写,可以不加索引,提高写效率,丛库追加索引,提高读效率

2、带来的问题

主从架构会剧透延迟性,会带来一致性问题,对实时性要求搞的业务会产生影响

  • 写后立刻读: 在写入数据库之后某个时间内读操作去主库,其他时间去丛库
  • 二次查询:先去丛库读,读不到就去主库读,注意别给主库带来太大写压力
  • 特殊处理:实时性要求搞的业务读写放在主库,次要业务使用读写分离

二、InnoDB 的 MVCC

数据库通常使用锁实现隔离性。最近的锁,锁住资源之后禁止其他资源访问,不论是读还是写都会被排斥,但是在读多写少的情况下,对读进行锁互斥就显得没有必要。于是引入了读写锁,主要对读进行加锁。后来发现并发量还是不够,最终出现了 MVCC(Multi-Version Concurrency Control)即 多版本并发控制

  • MVCC 是 MySQL 引擎 InnoDB 对并发处理的无锁实现

三、CopyOnWriteArrayList

顾名思义,这是一个写时复制的 ArrayList,是线程安全的。发生结构性变化时的时候加锁,此时会创建一个副本数组给其他线程进行读取,变化完成之后再替换之前的数组。因此不能保证实时性,只能保证最终一致性,适合读多写少的情况。

1、源码解析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
public class CopyOnWriteArrayList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable {

final transient Object lock = new Object();

/**
* The array, accessed only via getArray/setArray.
* volatile保证可见性
*/
private transient volatile Object[] array;

/**
* 读的时候不加锁
*/
public E get(int index) {
return elementAt(getArray(), index);
}
@SuppressWarnings("unchecked")
static <E> E elementAt(Object[] a, int index) {
return (E) a[index];
}

/**
* remove的時候先獲取之前的es數組,remove完之后再setArray(newElements);
*/
public E remove(int index) {
synchronized (lock) {
Object[] es = getArray();
int len = es.length;
E oldValue = elementAt(es, index);
int numMoved = len - index - 1;
Object[] newElements;
if (numMoved == 0)
newElements = Arrays.copyOf(es, len - 1);
else {
newElements = new Object[len - 1];
System.arraycopy(es, 0, newElements, 0, index);
System.arraycopy(es, index + 1, newElements, index,
numMoved);
}
setArray(newElements);
return oldValue;
}
}

/**
* TODO 完善此部分
*/
public boolean add(E element) {
synchronized (lock) {
checkForComodification();
CopyOnWriteArrayList.this.add(offset + size, element);
expectedArray = getArray();
size++;
}
return true;
}

}

对读写分离思想的思考
https://polarisink.github.io/20221011/yuque/对读写分离思想的思考/
作者
Areis
发布于
2022年10月11日
许可协议