From 8a81763d0328df82713e776ffe7c7a8cc4bb5e3b Mon Sep 17 00:00:00 2001 From: yanglbme Date: Fri, 30 Nov 2018 17:01:19 +0800 Subject: [PATCH] docs(database): add database-shard.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 如何分库分表?有哪些分库分表中间件?如何垂直拆分?水平拆分? --- README.md | 2 +- docs/high-concurrency/database-shard.md | 105 ++++++++++++++++++++++++ img/database-split-horizon.png | Bin 0 -> 10791 bytes img/database-split-vertically.png | Bin 0 -> 7590 bytes 4 files changed, 106 insertions(+), 1 deletion(-) create mode 100644 docs/high-concurrency/database-shard.md create mode 100644 img/database-split-horizon.png create mode 100644 img/database-split-vertically.png diff --git a/README.md b/README.md index a0545e667..b24cea16d 100644 --- a/README.md +++ b/README.md @@ -67,7 +67,7 @@ - [生产环境中的 Redis 是怎么部署的?](/docs/high-concurrency/redis-production-environment.md) ### 分库分表 -- 为什么要分库分表(设计高并发系统的时候,数据库层面该如何设计)?用过哪些分库分表中间件?不同的分库分表中间件都有什么优点和缺点?你们具体是如何对数据库如何进行垂直拆分或水平拆分的? +- [为什么要分库分表(设计高并发系统的时候,数据库层面该如何设计)?用过哪些分库分表中间件?不同的分库分表中间件都有什么优点和缺点?你们具体是如何对数据库如何进行垂直拆分或水平拆分的?](/docs/high-concurrency/database-shard.md) - 现在有一个未分库分表的系统,未来要分库分表,如何设计才可以让系统从未分库分表动态切换到分库分表上? - 如何设计可以动态扩容缩容的分库分表方案? - 分库分表之后,id 主键如何处理? diff --git a/docs/high-concurrency/database-shard.md b/docs/high-concurrency/database-shard.md new file mode 100644 index 000000000..d3412a67e --- /dev/null +++ b/docs/high-concurrency/database-shard.md @@ -0,0 +1,105 @@ +## 面试题 +为什么要分库分表(设计高并发系统的时候,数据库层面该如何设计)?用过哪些分库分表中间件?不同的分库分表中间件都有什么优点和缺点?你们具体是如何对数据库如何进行垂直拆分或水平拆分的? + +## 面试官心理分析 +其实这块肯定是扯到**高并发**了,因为分库分表一定是为了**支撑高并发、数据量大**两个问题的。而且现在说实话,尤其是互联网类的公司面试,基本上都会来这么一下,分库分表如此普遍的技术问题,不问实在是不行,而如果你不知道那也实在是说不过去! + +## 面试题剖析 +### 为什么要分库分表?(设计高并发系统的时候,数据库层面该如何设计?) +说白了,分库分表是两回事儿,大家可别搞混了,可能是光分库不分表,也可能是光分表不分库,都有可能。 + +我先给大家抛出来一个场景。 + +假如我们现在是一个小创业公司(或者是一个 BAT 公司刚兴起的一个新部门),现在注册用户就 20 万,每天活跃用户就 1 万,每天单表数据量就 1000,然后高峰期每秒钟并发请求最多就 10。天,就这种系统,随便找一个有几年工作经验的,然后带几个刚培训出来的,随便干干都可以。 + +结果没想到我们运气居然这么好,碰上个 CEO 带着我们走上了康庄大道,业务发展迅猛,过了几个月,注册用户数达到了 2000 万!每天活跃用户数 100 万!每天单表数据量 10 万条!高峰期每秒最大请求达到 1000!同时公司还顺带着融资了两轮,进账了几个亿人民币啊!公司估值达到了惊人的几亿美金!这是小独角兽的节奏! + +好吧,没事,现在大家感觉压力已经有点大了,为啥呢?因为每天多 10 万条数据,一个月就多 300 万条数据,现在咱们单表已经几百万数据了,马上就破千万了。但是勉强还能撑着。高峰期请求现在是 1000,咱们线上部署了几台机器,负载均衡搞了一下,数据库撑 1000QPS 也还凑合。但是大家现在开始感觉有点担心了,接下来咋整呢...... + +再接下来几个月,我的天,CEO 太牛逼了,公司用户数已经达到 1 亿,公司继续融资几十亿人民币啊!公司估值达到了惊人的几十亿美金,成为了国内今年最牛逼的明星创业公司!天,我们太幸运了。 + +但是我们同时也是不幸的,因为此时每天活跃用户数上千万,每天单表新增数据多达 50 万,目前一个表总数据量都已经达到了两三千万了!扛不住啊!数据库磁盘容量不断消耗掉!高峰期并发达到惊人的 `5000~8000`!别开玩笑了,哥。我跟你保证,你的系统支撑不到现在,已经挂掉了! + +好吧,所以你看到这里差不多就理解分库分表是怎么回事儿了,实际上这是跟着你的公司业务发展走的,你公司业务发展越好,用户就越多,数据量越大,请求量越大,那你单个数据库一定扛不住。 + +#### 分表 + +比如你单表都几千万数据了,你确定你能扛住么?绝对不行,**单表数据量太大**,会极大影响你的 sql **执行的性能**,到了后面你的 sql 可能就跑的很慢了。一般来说,就以我的经验来看,单表到几百万的时候,性能就会相对差一些了,你就得分表了。 + +分表是啥意思?就是把一个表的数据放到多个表中,然后查询的时候你就查一个表。比如按照用户 id 来分表,将一个用户的数据就放在一个表中。然后操作的时候你对一个用户就操作那个表就好了。这样可以控制每个表的数据量在可控的范围内,比如每个表就固定在 200 万以内。 + +#### 分库 + +分库是啥意思?就是你一个库一般我们经验而言,最多支撑到并发 2000,一定要扩容了,而且一个健康的单库并发值你最好保持在每秒 1000 左右,不要太大。那么你可以将一个库的数据拆分到多个库中,访问的时候就访问一个库好了。 + +这就是所谓的**分库分表**,为啥要分库分表?你明白了吧。 + + +| # | 分库分表前 | 分库分表后 | +|---|---|---| +| 并发支撑情况 | MySQL 单机部署,扛不住高并发 | MySQL从单机到多机,能承受的并发增加了多倍 | +| 磁盘使用情况 | MySQL 单机磁盘容量几乎撑满 | 拆分为多个库,数据库服务器磁盘使用率大大降低 | +| SQL 执行性能 | 单表数据量太大,SQL 越跑越慢 | 单表数据量减少,SQL 执行效率明显提升 | + +### 用过哪些分库分表中间件?不同的分库分表中间件都有什么优点和缺点? +这个其实就是看看你了解哪些分库分表的中间件,各个中间件的优缺点是啥?然后你用过哪些分库分表的中间件。 + +比较常见的包括: + +- cobar +- TDDL +- atlas +- sharding-jdbc +- mycat + +#### cobar +阿里 b2b 团队开发和开源的,属于 proxy 层方案。早些年还可以用,但是最近几年都没更新了,基本没啥人用,差不多算是被抛弃的状态吧。而且不支持读写分离、存储过程、跨库 join 和分页等操作。 + +#### TDDL +淘宝团队开发的,属于 client 层方案。支持基本的 crud 语法和读写分离,但不支持 join、多表查询等语法。目前使用的也不多,因为还依赖淘宝的 diamond 配置管理系统。 + +#### atlas +360 开源的,属于 proxy 层方案,以前是有一些公司在用的,但是确实有一个很大的问题就是社区最新的维护都在 5 年前了。所以,现在用的公司基本也很少了。 + +#### sharding-jdbc +当当开源的,属于 client 层方案。确实之前用的还比较多一些,因为 SQL 语法支持也比较多,没有太多限制,而且目前推出到了 2.0 版本,支持分库分表、读写分离、分布式 id 生成、柔性事务(最大努力送达型事务、TCC 事务)。而且确实之前使用的公司会比较多一些(这个在官网有登记使用的公司,可以看到从 2017 年一直到现在,是有不少公司在用的),目前社区也还一直在开发和维护,还算是比较活跃,个人认为算是一个现在也**可以选择的方案**。 + +#### mycat +基于 cobar 改造的,属于 proxy 层方案,支持的功能非常完善,而且目前应该是非常火的而且不断流行的数据库中间件,社区很活跃,也有一些公司开始在用了。但是确实相比于 sharding jdbc 来说,年轻一些,经历的锤炼少一些。 + +#### 总结 +综上,现在其实建议考量的,就是 sharding-jdbc 和 mycat,这两个都可以去考虑使用。 + +sharding-jdbc 这种 client 层方案的**优点在于不用部署,运维成本低,不需要代理层的二次转发请求,性能很高**,但是如果遇到升级啥的需要各个系统都重新升级版本再发布,各个系统都需要**耦合** sharding-jdbc 的依赖; + +mycat 这种 proxy 层方案的**缺点在于需要部署**,自己运维一套中间件,运维成本高,但是**好处在于对于各个项目是透明的**,如果遇到升级之类的都是自己中间件那里搞就行了。 + +通常来说,这两个方案其实都可以选用,但是我个人建议中小型公司选用 sharding-jdbc,client 层方案轻便,而且维护成本低,不需要额外增派人手,而且中小型公司系统复杂度会低一些,项目也没那么多;但是中大型公司最好还是选用 mycat 这类 proxy 层方案,因为可能大公司系统和项目非常多,团队很大,人员充足,那么最好是专门弄个人来研究和维护 mycat,然后大量项目直接透明使用即可。 + +### 你们具体是如何对数据库如何进行垂直拆分或水平拆分的? + +**水平拆分**的意思,就是把一个表的数据给弄到多个库的多个表里去,但是每个库的表结构都一样,只不过每个库表放的数据是不同的,所有库表的数据加起来就是全部数据。水平拆分的意义,就是将数据均匀放更多的库里,然后用多个库来抗更高的并发,还有就是用多个库的存储容量来进行扩容。 + +![database-split-horizon](/img/database-split-horizon.png) + +**垂直拆分**的意思,就是**把一个有很多字段的表给拆分成多个表**,**或者是多个库上去**。每个库表的结构都不一样,每个库表都包含部分字段。一般来说,会**将较少的访问频率很高的字段放到一个表里去**,然后**将较多的访问频率很低的字段放到另外一个表里去**。因为数据库是有缓存的,你访问频率高的行字段越少,就可以在缓存里缓存更多的行,性能就越好。这个一般在表层面做的较多一些。 + +![database-split-vertically](/img/database-split-vertically.png) + +这个其实挺常见的,不一定我说,大家很多同学可能自己都做过,把一个大表拆开,订单表、订单支付表、订单商品表。 + +还有**表层面的拆分**,就是分表,将一个表变成 N 个表,就是**让每个表的数据量控制在一定范围内**,保证 SQL 的性能。否则单表数据量越大,SQL 性能就越差。一般是 200 万行左右,不要太多,但是也得看具体你怎么操作,也可能是 500 万,或者是 100 万。你的SQL越复杂,就最好让单表行数越少。 + +好了,无论分库还是分表,上面说的那些数据库中间件都是可以支持的。就是基本上那些中间件可以做到你分库分表之后,**中间件可以根据你指定的某个字段值**,比如说 userid,**自动路由到对应的库上去,然后再自动路由到对应的表里去**。 + +你就得考虑一下,你的项目里该如何分库分表?一般来说,垂直拆分,你可以在表层面来做,对一些字段特别多的表做一下拆分;水平拆分,你可以说是并发承载不了,或者是数据量太大,容量承载不了,你给拆了,按什么字段来拆,你自己想好;分表,你考虑一下,你如果哪怕是拆到每个库里去,并发和容量都ok了,但是每个库的表还是太大了,那么你就分表,将这个表分开,保证每个表的数据量并不是很大。 + + +而且这儿还有两种**分库分表的方式**: + +- 一种是按照 range 来分,就是每个库一段连续的数据,这个一般是按比如**时间范围**来的,但是这种一般较少用,因为很容易产生热点问题,大量的流量都打在最新的数据上了。 +- 或者是按照某个字段hash一下均匀分散,这个较为常用。 + +range 来分,好处在于说,扩容的时候很简单,因为你只要预备好,给每个月都准备一个库就可以了,到了一个新的月份的时候,自然而然,就会写新的库了;缺点,但是大部分的请求,都是访问最新的数据。实际生产用 range,要看场景。 + +hash 分发,好处在于说,可以平均分配每个库的数据量和请求压力;坏处在于说扩容起来比较麻烦,会有一个数据迁移的过程,之前的数据需要重新计算 hash 值重新分配到不同的库或表。 \ No newline at end of file diff --git a/img/database-split-horizon.png b/img/database-split-horizon.png new file mode 100644 index 0000000000000000000000000000000000000000..9f13eb81e8c15addd7607f6f8df7b86c3b95ff8a GIT binary patch literal 10791 zcmc(lc{tSn`|qbkiqNMbDYOhi$S&KIk_I9BuE@TJv77o-l)X`e>>@i^vsOZu>`d0N zZ)3^MFr0h(obUOaKh8PV_xhgeT&K%4mzlTM`?cKn^S zt0NEx`r##Y^ay<7wR__wyd878tLK71(4L~a4j^LQGb0ce5a`=CH9g)h40-!#PF5`~ zFDc6{>Rb>!a`NEeOYaT~-Aom^bU`z}{KfeWo2uTxE9dN!di8Hy{Z^27>#qzu)h?bf zbM}%i{$~PX6rEG@JaV-iZAOSNfg$E`iWA*#=?Lv>%n#hAz@*7FFzV;bpY}E5)B^$VSGD@3h^cA zN)ZC#@z)C`1VSLW{UBmQ{&?wsoOE9 z^}jSYe4b=NcdpHLX=!PF`0O&Rh}+w4!_LLI58uCW z(Y^%?d}1^Is{n4$39}SHp=w+l9LMWJR#sOv?Co{L|~=zS*?A6J!yyd-tujcD??bqg8VxU-?{S*4p-Tf^B{9SsXH;Hp#Ji`%ZCj zartz-x2CS{$BLzD1EwH(oTjmHZmeT!}ALw_TJNsojsr{hrqXONvZ?pndeV@#Eu3TwvV8>>kG4{BLEArWX9CB9pPAS2! z;^fJbr`g%_jH|pF!Q7;z47jlChO2$OBbdRFjUrMJMFJGVVPs@fymzms(sNbBx)WKo z(!@)-5lr*FN;(e@4>F@CR{Jy)6Avfn9h|1RdgnxpUd2$Z$?n)0T64 z8Qa$P*Liq(H82=V#AMCxO0$?z{OV``I}abjMyN;;n=#0TZL(m<8L^vDG`}dP5 z%iq~pDBtL}E%qaO#Ys5J8I(Ho)H0y5M@AmV?C-A996Q#Lu(!q~v$r*#+trw^5~mIh z_t?e7sMNvEr%4w#M+0&frsLcV3Ht|UB*0$-zJ2@V3bs7^iYs1CO)VUm;k~&y zN2sY$*U)(T`t@iGTH5sc(H#9^#g2}S^37pyxA|X!Lzn^k#}emrD^M>20&IISwQ|?R z-%EVUbD)r1MKV!vrB#$E&p3Bh|6{@1hnqe{T-?HjWcLxV*n2AJ8p0MW;a#(DkYG35TwDsb z0_g39FteQ>VkDeRBT(YQ9x2FTs{{$>WZTaauK+jg`aN2^zM8OaSmC~eS-&2q!l(D? zwpo2}2gvdIG-_Y3{vC!`bHd!*yd12!7`yKm)_VxyRBKUqHuk4Qc{z#X<+8I-8q0v% z&F>Ketq}u3x&{LaqevZLEzggg`tyR(e!l$cvSD6Z{ixIXRdRosbINtkl~itCUSY5r zanyFBYH-)ANImoFO0z)h{JfpZ?v`^zLV{y%#iC@P!;mEYQ~ZX>M^)MF@5<3ab=`Qp zcV%vC;>A2)^3IFaux9TkVx-@-4CV#8u0KWbMUrV{WxDLXYxg5cT3T8-g>wr(eUc9S zu7L4G}`V2B_;bUWCpbK28y#tOlIUo>dTm$*c++0?kwyy5GVeG!| zVoI0l$w3=Qu!W<*mga4S;J+pxTm{YWY$(fYtV3Y19V4^LHhR-VzJ;Id3kyL z&yPQ(DMw$*>dEZvRA*#j68mh7`91Pgzsjo^={bmUnNqH+ub*?T*@;6^j*23a-b+0xaD4Q|!T7m7gE6KQ_b2ipkI;cGOd;>Y< zPDm#VHa9m=?v`a^YrDRVH{s>rkRK?q@A~oj@(`0Ax*TL;z27#kxZLDR9R&KK`_9e< zreYH|U z*;(%nMbXgkwckk#ao4tymilF6Fs{)M5~d%gl0MZEosyh<3AAPwU$a+?i-^!NG07{o z#oK^C&h=zP*;e-0Xw~?U*G8T(*ud3Zq}g=Fzy7+2mIT|AyLF2ruA0tFQ}YdoU;|mk zd!u{g>odyiDZ;9!r`Ocf)Je>%$(33xyXCzx-;pdI)W6|>FzP5}K5)6FwROhW__zUU zq3f(VK4+Wdk%h(FkUPPx3ggb(1o8K0v~a`v_jtz|vi4HdW<33QiNrG|KKEt3*4n>3 zJrsMozkZiYHZRs^gy{17x6|b0X;m+`__UW4@0x z5uy49ha2PRUG&)}Z_f1Bfo6m|Y+v2qyTTp(xTiQ`>c=ydAcOp1ZC&X(? zOq-mZCVrldk3e#8aS@*}$f~KRgzjxMpm;bq>WT-yKBJ}>fi1*fN$0WW#y-pPcv6mb zmP7e0C!a~RAt;KLo?bL1SZ%LPmnzjjW-+Q)XwgU@n1FAl9z1yPO?-TAl!>2Sib9wy z(YwsDjg5{?dMn!ufta2({T#Xh`y&c-B6tem`>UnS)4LFSH={E&(qq1TlM}Y-zG4UE)|g)@`9sLo=&czwVhZjoG^;$?F{=D zJ2*I47&^;S7Rq!Z-MQd&zec)BbYlcpY#VBSw=z;{pqgFM^#`+=G9+YY1x=qvLza0~ z#;eG4;fKJ3fPwcM0TqOHN+i=84Hkqb>TaUyw`xg!vn>GnY%!@I6r(H{~v> zXD+nG^ScmpN@KvZ!~}$0rdnJ=GqSTqD9WJ+l2I_Q;LvdT^ywnc*tmP<<{zSk%mcSU z5q((|E0Wrib37cFDi=+?+3dBn-ojq%S81Q-yMCS?HjEpI{Ekm5Iv1}HR5FI88Id+p zu1ikY+SytCdN}H8{P3awQ;Pm?<@06D;*!d>T`GtX^>2UiRkku0_TdE)!#5lbec|vA zczr02LE%3s5B{xtQ!=F&&z~QUfYRnXqVky>?ba_w9mD15)Gr&xj;^k2ZEb=`Iduki z*3r>X{9T&x)MoyQ`D5sZ3+Gs!W`A$GArOO~6dx<9-?`(T;+bA&x-4AZonTMpOImBZ z?mYG#tJn#ygE7eIMWD6KlykafT_MC^P4x7(x53`xttt(ztgQ4wN_v+FHK>%dv?(eVX&@pDWaK4;PQLt;!>`rFp5 zXWEk(>Ea+a6~)O7oKX2exvdeV&pb>_hTm?b`2o9P&j zhlF2SgrqUte&*b{oh8dXzbj&58{$woVI5{@X=oH7`DmuR+nDzZX=rGaD%`%kTa zk8j~+j}0AKNlEJDi4)hhlwBsT%dHXdc?4TXpSK}SDV<}nwXvxNMVfIWtrIsf4<3ws zSsij5QE#B!{7qzJwYt7ODG*6@`0(*XLd`x_bnS(|zwz65@3x{|zI=HMazdtcCfp2bVdJL~&2dlv@*TnN`wtCKST3Uwf$|L8lz*8E;4+#|OVxe6AjzjfNnY@lMtD_I51`3&bmvS@=}|LLt`J&~TT_ofedpz|PG4>(Pdzwe>7kQ(K!Y z+%?mA2b3PQvARlo{OHjc10y3NhhS$#buga1xw*NNpLioRwcj3)fhIsP<-?2i^Ya^3 zNiWP?e$ET!;7f=yh6ULDJ>IOWEbQ+YRs{dW)B1_e))$9%7`Rm94NbJP+_LYxkU_YY zSVXMa(?vx^z0au}QczGJ#J_pd?PK}|$$j~9N`A3Dp?;1QXpI8D zD*?zrW_x?Pv$eH#L(dGUM>yT<8Iqfa$7ZEH=@xHtN{XZ8fY)G)B&JwA!R`F%)7_R( z=2f&F|9n+YaM@8T_NV9eWRyU7Z1fMyP&?JkzDJF){x|4A>98TH3l^-0SUIm@Bjy+di9l+V`h;MCMq(Sm}48tbryBUDs$8M(Q`zEkEMqqPC-*Xp|!?%Wv; zkBlr4xN_yAdIfNjECD_~ql;*moLK}87m4rg zo?w@7dXSo$Tvk^0d3kvm3(J-|AKD3lPkIEcj6k>|v2n7dm5B@$VC)6WKQ}+n5jyDE zq&-ya?B=t7{P*tg_oIj}^6ATut{~zLMI<5q7wqSC z9sWRKMsRTOe!(Af1k@-(&|1inw76r(;IF-YRJ(5n(<2wNSG<#fBg7yUQd<|-d)pfX7>lX$KSiN z5`NY6BkGY+QI=lob3G=V`7XzO?Yq+Mos+!8>B>66AboSs^?Y^8x?pUW(YFMfFa`Zc?&?u{Asf5v4#taAYK z;mW>_hX<0BF8-OInVOZq}UVnr*PNc-B(RA!_<=jK{z3xGYO!&(+a1droB_@!p>~Ec3%B4-0f3 zb7+a$WC9z+ZfZ%-=>OMu1)%Ia=q0hr65Xpy@2wBDzS@1t^@DvWxgB$@ZvgQWb@-?#+At52zV%@8?aB=HT=0eZu);KdCRt2*ORs7ApFQ=+o z6ZpxjeCS~}-K&uu)uBn(SJH`;Gc}oRlXsr;fbdjJf57r}bo4CoL~G#g>>w;BS$IM< zN;a7akyx1WZ)40qW`}ta6T@N>@Pt43&&mlY?Iq8k0%4W$(!{wg6yp_f0Kv4>)sr(b zc|zD^^xfRt9HPiGDPhw68?P@b6g{jx64rZw@MnGLs})xk-R5l#O6)r7L(aX8h`5Xv zs<#^b_JTsg&eI2+Javlk#EB71A7uD{QgsZb1nRcz-pB;sc}xYRG%am*C-&Y0M5dvr z7L4F zjV(M_=r4w(Ae@4F%^E_jzdb)zzS=5P3^V}PDa?+7s<1l)1PUjDjNNu+q7mp=`pVwU z5-(6XfvPne@zkVnn{*0SyoVfa4GO1{UsGGl;e=-lsEuZ7@-P@jy5j68h0(hJO#BiTNg+EWT0Z^D*tXPVy zGkuMG8x=*Iigm=;PiLgZQxaTcqiMkmRIxpD;)98)sYrBZDmtRbexO7wj&yUH;x*tr zHr6Xn1u7HGnh z0f7DkialDUtL?zDDQBUR3?i=$Nu}eboVht0y&P@$vHz8S69SeO)H;S_NRZvhyE}w^ zV*o?MC+-N40gCFvUX(mzE8jo5?032!qXxFp-K`0}nF;JAvW4wdbmET=UY9zwpmo)Evt@tm)z3?Bg(0gI~ zK(O9MMy5pzTb9f;x3p+FIPfQ2skrb*BPCHZIRSu6DEnbgs5YYXPkQrA@}RV}BKGEZ zZH)#no z+jTxVX2H&6p`wPeR!(7I4O|g8xeBB7c9$pwHu*gdcGacX!~HRpMuLr_zJE^8gZ)J> zZLlCk((-C=oRR-W=x!ysjRR!vF$&lQd$`1g?;+Wx^JfK)3v%%F4Ki{Kc(xbrc zoBEbl2Ox(czzHo=(`3$jG2Q&+-}HYhqkR^ZWLDUx>`ht@!wx3rY>N$sShoOZ70#{l z-i!gDNP)Eg_zczvPPKGXIi){Id?BYwN{{PwLq$Z;-W`vWiQ zi?g7LzZn_ayLT_5`kZ5B$AVW(DZyv;r`O0+Y9w06(D?;sX?Owi`CoX`!u}t;=~l7U z_WrsC-WBmzT1Y z9landT!=Q%*4B>Ln_`e~kZ^NJVvyzM<_3iMZS~0g`}cVS1fsfT*UGTnAMbmu_vje; zf}CoBFjnu8Y$^Rcz?Ur7A5X|fOtAh>!!OUj3KQAy)&)X1HfCDti(AVwADtTAzDnu3L3K=X{J19YPEKIPVW>S_X#0@n3)=?$GVkpC4>d0z zbto|&FR4#=V8PnBg2f42hC)LRAWkZn7hX|CMH}3WLd?J$GIjEdrw9E&+>o8gyH-|8*EKXK;h?s86BE zIQ#xbsN=;N9v17nb=?!U-d>qxk#zkCFsul(p#L)gRbxcrn2oW`?SMW9Men&1eAJ=0 ztEj4qhoUqa8poyAwRdU%Wv7xHj>>tC_FiRDfCdNM3BDH4U`@-Z8~vW>jyj^ z@RRZ^0N^|5%IVekRZ+SQdY>M>@|;NuXz9%{2&o;l5}d5uPB;RUvjs$A3t-1nBx0U; zmQJ3-CwtYM5J8Kv@2{pxYsfjo^`^JHA<)`^z%#wi87FV~&UlIbU$fyqR;}V{7JMC2 z7J!2N{rbYtK@#@fuoL!Lvs(ReIqcoa%45KrknjnjcKX_swY4J~o10g?D&y{1-gAX` zcmex^UDefpceLC2-1`O1JK*V*$bSX;V;LD4Uh@SFr_Y|9W$F5Dz7NLK4P8LTfFKqB zKdDP@o)W=h#nh8+qApihnxT{R&v+xRTEkJ$ZTk0%rhnS|I01m-k+}Trj>(Bv& zq0isXo+)^I@&O*xJ2NvgFi?^)@_Z@;g4#09tL!X$zeEW%N-LS!*!IlO5Uwi3goGaN zQc(}JP{_mJ;n?u_c;m;M)h>ZAUv6cjmTd$co8j5@Wkt02(Xoikj6>JlHDW>n{|jRO zW0O@ez%21V>aIf}y&AL0c;<}24kVCKXmt;dt$ct-jMNNll_k*X`VoCGa%*b~4>5*@ zo?X_*aopT{ZAS2eLKvGna1y*32e**W$`n-j)5ykI*T~J;uIUgcwz21BeLT`q=T?W7 zTmV+^=MOA6Qc+Xyr)Fl_)P1g3ke44i&B`jX4b!i&The{f8Z1ZqJ|H;wxK067K7RG@ zNd9=JV~B-7_IdeThoDVh0O7$nFf??}+|6xW1LxXj9wjrkw8ZW?^5rSkR<;_Z#J~hA z!KK31-p=Y_ffTtw2L}-ZGv8M@o%#Ivb1n`&ei2T0sE(B&+yKazc^MiSKL~xmY2++~ zA_nLan!f#MA>{@>b;-Rs{lf=FvE4yvb~j_@fBkheBTdHauw(>=Om&!_6S5+K+W=lp zoH)^*o}0TEj`Rg(M$?f2^vn-ch$nS)q&J6OyfqKlk?`5TQBAG=3#ieh)KRy#c$sug zB(m~C@zvqQe$3+FEFqsvB9Vm9^`-?|dO5w}@XKTOf$W?dnKDO$?11NdHFCCzH&6Nk z`svfBWC&}NrS5-rUm9)```%82js1zSfo?n#nueZ!adK&iP+D2JdzoS?=M3)OU;dD) z4$%-EWpR2{2#JV8>mG&LoXuofLtQLjrHskBpuaI=k6-xkUy{oL;QbP@tltOQS@$A^^>-QJ@`t^%&_{b6Z z6YN{gugALu+c8Y&w47&oWn+N?gSp>Lk6D$zR9OuR4z65=-cxDOs@Kplhvr1Ent>ER zG$gRZ{Uu1js3}12n$yS^cPI?Wkd!pbdag`hLAm#@U%QrXa`Wcb+F^Q@-yAf2PE4Sf zI*RI#AFq@rCMNRMKugZgUe5uD>@#4!^yNe#YLWwztvfUPl9FD@H8t2aV6=t-wf6_h z@*tKvLqjbr^39ux_e)+J+}Ex-J%L z3~zW|z~t}0|5k_cw-C8LH&D7%4q%M~bTWd2%J{C~4IOA*>I=dGHV+*xo1w4#Q%GPFBiLzWb(sI2TG$;oMP2WDmh?$wLt`TT|XsY)0$J;%Tw zHX&;}|EbRoFl0@JnBnkcbp5;X%F4>_1BZ_6*0#0f)zPs+(??vBgx`!0;bfxvWmggt zC*^+UZl(>hV_{zlKr(2*mqm(Ry=td<_wJA1@DvLa*d$T}cn>X{iG|`PVDkd$si_kJ z5R3v^y{A>P{;)<|H+0jeky@Y{3_xjj7VT)=mWIi_;Kn*o))R{LbG|~s(q(FDnkLFV zJw1Jf>Fn9-pf$OP+1c}QsN;w@HfUhKpr%s9L1OZz95^MXxYb=%Rmb%oeA3cB9`^PN z2Sj;3O`ix456_>65_y&5EfXUnAB%+32=vm+xGLO;Oq7A0p&!9{Di!wf6lAuvt=^Wc zKt`E$pi|P=SHBAtj3XKTdxcYh^=klTd+fe>h2oMtDAa!X85Y`hEqDw}z()3BlWBpg zt-T!(Nk=~@Uc~#$7hyehz*~W9ddx<1Hb7}HMbCWgK?Jm8AoCR0v++93)}3ckvk!@g zXU4~mGtpuW^(N{NZn?Ry!P(jP`R%o}7AUVrqjvWXzBD;JVkd{Bnq5;ivwZYuV#|+A zs_JRC4$i0=3*@C2F@69r=_VbDT?#W_3Lc*)wg^75^M)ds>0M_>TqTX%Z39C>$oJs1 z@^^Q4y$4R}f?Tmf4?V^Ql$ISGxCm-mvkom96)blD`BL@HA{)e$@ICTQ4Lk={+y%yR zUrTEp1=O4hQn7`P0I#vGP_OMk0B4iJV~)_DFS{-xvNi{))@}`WI>FG$s45-8O}0YO zPtod|R0sq=gr+tSDNE=-4NE6XwqoM!5@daim7rOqLh0?CIkQ=Ygtkl?MWp@x{psCG zgDZ$uhYlTz0B_4Z3JoP8*O~SvaC3J6Jo`~GejfA?^E@9x&h81LtBTsxNQ;QL4sOqD zTppbk?Cl4{jTcB{Ks>?VZ4OXcOPzfJJJwyr|8c1QPg8{d`a8p>J=9filHr}qD0a%H NXnB>}xpEKw{%?-gT9g0) literal 0 HcmV?d00001 diff --git a/img/database-split-vertically.png b/img/database-split-vertically.png new file mode 100644 index 0000000000000000000000000000000000000000..21357328786ecf57dffbe6cd26ef249b1ffc9528 GIT binary patch literal 7590 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 VP{