高并发架构相关概念
并发:在操作系统中,是指一个时间段中有几个程序都处于已启动运行到运行完毕之间,且这几个程序都是在同一个处理机上运行,但任一个时刻点上只有一个程序在处理机上运行;在互联网时代,所讲的并发,高并发通常是指并发访问,也就是在某个时间点,有多少个访问同时到来。通常一个系统的日PV在千万以上,有可能是一个高并发的系统。有的公司完全不走技术路线,全靠机器堆,这不在讨论范围内。
QPS:每秒钟请求或者查询的数量,在互联网领域,指每秒响应请求数(指HTTP请求);并发连接数是系统同时处理的请求数量
吞吐量:单位时间内处理的请求数量(通常由QPS与并发数决定)
响应时间:从请求发出到收到响应花费的时间。例如系统处理一个HTTP请求需要100ms。
PV:综合浏览量(page view),即页面浏览量或者点击量,一个访客在24小时内访问的页面数量;同一个人浏览网站同一页面,只记作一次PV
UV:独立访客(unique visitor),即一定时间范围内相同访客多次访问网站,只计算为一个独立访客
带宽:计算带宽大小需关注两个指标,峰值流量和页面的平均大小
日网站带宽=PV/统计时间(换算到s)*平均页面大小(单位KB)*8;峰值一般是平均值的倍数,根据实际情况来定
峰值每秒请求数(QPS)=(总PV数*80%)/(6小时秒数*20%);80%的访问量集中在20%的时间
压力测试:测试能承受的最大并发,测试最大承受的QPS值
常用性能测试工具:ab,wrk,http_load,web_bench,siege,apache jmeter;ab全称是apache benchmark,apache官方推出的工具,创建多个并发访问线程,模拟多个访问者同时对某一trl地址进行访问,它的测试目标是基于url的,因此既可以用来测试apache的负载能力,也可以测试nginx,lighthttp,tomcat,IIS等其它web服务器的压力;ab的使用:模拟并发请求100次,总共请求5000次,ab -c 100 -n 5000 待测试网站;测试机器与被测试机器分开,不要对线上服务做压力测试,观察测试工具ab所在机器,以及被测试的前端机的CPU,内存,网络等都不超过最高限度的75%
QPS达到极限:随着QPS的增长,每个阶段需要根据实际情况来进行优化,优化的方案也与硬件条件、网络带宽息息相关;QPS达到50,可以称之为小型网站,一般的服务器就可以应付;QPS达到100,假设关系型数据库的每次请求在0.01s完成,假设单页面只有一个SQL查询,那么100QPS意味着1s完成100次请求,但是此时并不能保证数据库查询能完成100次,数据库缓存层,数据库的负载均衡;QPS达到800,假设使用百兆带宽,意味着网站出口的实际带宽是8M左右,假设每个页面只有10k,在这个并发条件下,百兆带宽已经吃完,CDN加速,负载均衡;QPS达到1000,假设使用memcache缓存数据库查询数据,每个页面对memcache的请求远大于直接对db的请求,memcache的悲观并发数在2w左右,但有可能在之前内网带宽已经吃光,表现出不稳定,静态HTML缓存;QPS达到2000,这个级别下,文件系统访问锁都成为了灾难,做业务分离,分布式存储
高并发解决方案案例
流量优化:防盗链处理
前端优化:减少HTTP请求,合并css或js,添加异步请求,启用浏览器缓存和文件压缩,CDN加速,建立独立图片服务器,
服务端优化:页面静态化,并发处理,队列处理
数据库优化:数据库缓存,分库分表,分区操作,读写分离,负载均衡
web服务器优化:负载均衡,nginx反向代理,7,4层LVS软件
盗链:在自己的页面上展示一些并不在自己服务器上的内容,获得他人服务器上的资源地址,绕过别人的资源展示页面,直接在自己的页面上向最终用户提供此内容,常见的是小站盗用大站的图片,音乐,视频,软件等资源,通过盗链的方法可以减轻自己服务器的负担,因为真实的空间和流量均是来自别人的服务器
防盗链:防止别人通过一些技术手段绕过本站的资源展示页面,盗用本站的资源,让绕开本站资源展示页面的资源链接失效,可以大大减轻服务器及带宽的压力
工作原理:通过请求头中的referer或者签名,网站可以检测目标网页访问的来源网页,如果是资源文件,则可以跟踪到显示它的网页地址,一旦检测到来源不是本站即进行阻止或者返回制定的页面,通过计算签名的方式,判断请求是否合法,如果合法则显示,否则返回错误信息
实现方法:referer:nginx模块ngx_http_referer_module用于阻挡来源非法的域名请求,nginx指令valid_referers none | blocked | server_names | string...,none表示referer来源头部为空的情况,blocked表示referer来源头部不为空,但是里面的值被代理或者防火墙删除了,这些值都不以http://或者https://开头,server_names表示referer来源头部包含当前的server_names,全局变量$invalid_referer。不能彻底防范,只能提高门槛。也可以针对目录进行防盗链。
//在nginx的conf中配置 location ~.*\.(gif|jpg|png|flv|swf|rar|zip)$ { valid_referers none blocked zi.com *.zi.com; if($invalid_referer) { #return 403; rewrite ^/ http://www.zi.com/403.jpg; } }
传统防盗链遇到的问题:伪造referer:可以使用加密签名解决
加密签名:使用第三方模块HttpAccessKeyModule实现Nginx防盗链。accesskey on|off 模块开关,accesskey_hashmethod md5|sha-1 签名加密方式,accesskey_arg GET参数名称,accesskey_signature 加密规则,在nginx的conf中设置
location ~.*\.(gif|jpg|png|flv|swf|rar|zip)$ { accesskey on; accesskey_hashmethod md5; accesskey_arg sign; accesskey_signature "jason$remote_addr"; } ';
性能黄金法则:只有10%-20%的最终用户响应时间花在接收请求的HTML文档上,剩下的80%-90%时间花在HTML文档所引用的所有组件(img,script,css,flash等)进行的HTTP请求上。
如何改善:改善响应时间的最简单途径就是减少组件的数量,并由此减少HTTP请求的数量
HTTP连接产生的开销:域名解析--TCP连接--发送请求--等待--下载资源--解析时间
疑问:DNS缓存,查找DNS缓存也需要时间,多个缓存就要查找多次有可能缓存会被清除;Keep-Alive,HTTP1.1协议规定请求只能串行发送,前面的一个请求完成才能开始下个请求
减少HTTP请求的方式:图片地图:允许在一个图片上关联多个URL,目标URL的选择取决于用户单击了图片上的哪个位置,以位置信息定位超链接,把HTTP请求减少为一个,可以保证设计的完整性和功能的齐全性,使用map和area标签;
CSS Sprites:CSS精灵,通过使用合并图片,通过指定css的background-image和background-position来显示元素。图片地图与css精灵的响应时间基本上相同,但比使用各自独立图片的方式要快50%以上
合并脚本和样式表:使用外部的js和css文件引用的方式,因为这要比直接写在页面中性能要更好一点;独立的一个js比用多个js文件组成的页面载入要快38%;把多个脚本合并为一个脚本,把多个样式表合并为一个样式表
图片使用base64编码减少页面请求数:采用base64的编码方式将图片直接嵌入到网页中,而不是从外部载入
HTTP缓存机制:如果请求成功会有三种情况:200 from cache:直接从本地缓存中获取相应,最快速,最省流量,因为根本没有向服务器进行请求;304 not modified:协商缓存,浏览器在本地没有命中的情况下请求头中发送一定的校验数据到服务端,如果服务端数据没有改变浏览器从本地缓存响应,返回304,快速,发送的数据很少,只返回一些基本的响应头信息,数据量很小,不发送实际响应体;200 OK:以上两种缓存全部失败,服务器返回完整响应,没有用到缓存,相对最慢。
浏览器认为本地缓存可以使用,不会去请求服务端。相关header:pragma:HTTP1.0时代的遗留产物,该字段被设置为no-cache时,会告知浏览器禁用本地缓存,即每次都向服务器发送请求;expires:HTTP1.0时代用来启用本地缓存的字段,浏览器与服务器的时间无法保持一致,如果时间差距大,就会影响缓存结果;cache-control:HTTP1.1针对expires时间不一致的解决方案,告知浏览器缓存过期的时间间隔而不是时刻,即使具体时间不一致,也不影响缓存的管理;可以设置的值:no-store:禁止浏览器缓存响应;no-cache:不允许直接使用本地缓存,先发起请求和服务器协商;max-age=delta-seconds:告知浏览器该响应本地缓存有效的最长期限,以秒为单位;优先级:pragma >cache-control > expires。当浏览器没有命中本地缓存,如本地缓存过期或者响应中声明不允许直接使用本地缓存,那么浏览器肯定会发起服务端请求;
服务端会验证数据是否修改,如果没有通知浏览器使用本地缓存。相关header:last-modified:通知浏览器资源的最后修改时间;if-modified-since:得到资源的最后修改时间后,会将这个信息通过它提交到服务器做检查,如果没有修改,返回304状态码;ETag:HTTP1.1推出,文件的指纹标识符,如果文件内容修改,指纹会改变;if-none-match:本地缓存失效,会携带此值去请求服务端,服务端判断该资源是否改变,如果没有改变,直接使用本地缓存,返回304
缓存策略的选择:适合缓存的内容:不变的图像,如logo,图标等,js,css静态文件,可下载的内容,媒体文件;建议使用协商缓存:html文件,经常替换的图片,经常修改的js,css文件,js和css文件的加载可以加入文件的签名来拒绝缓存,如a.css?签名或a.签名.js;不建议缓存的内容:用户隐私等敏感数据,经常改变的api数据接口
nginx配置缓存策略:
本地缓存配置:add_header指令:添加状态码为2xx和3xx的响应头信息,add_header name value [always];,可以设置Pragma/Expires/Cache-Control,可以继承;expires指令:通知浏览器过期时长,expires time;,为负值时表示Cache-Control: no-cache;,当为正或者0时,就表示Cache-Control: max-age=指定的时间;;当为max时,Cache-Control设置到10年;
协商缓存相关配置:Etag指令:指定签名;etag on|off;,默认是on
前端代码和资源的压缩:让资源文件更小,加快文件在网络中的传输,让网页更快的展现,降低带宽和流量开销;压缩方式:js,css,图片,html代码的压缩,Gzip压缩。js代码压缩:一般是去掉多余的空格和回车,替换长变量名,简化一些代码写法等,代码压缩工具很多UglifyJS(压缩,语法检查,美化代码,代码缩减,转化)、YUI Compressor(来自yahoo,只有压缩功能)、Closure Compiler(来自google,功能和UglifyJS类似,压缩的方式不一样),有在线工具tool.css-js.com,应用程序,编辑器插件。css代码压缩:原理和js压缩原理类似,同样是去除空白符,注释并且优化一些css语义规则等,压缩工具CSS Compressor(可以选择模式)。html代码压缩:不建议使用代码压缩,有时会破坏代码结构,可以使用Gzip压缩,当然也可以使用htmlcompressor工具,不过转换后一定要检查代码结构。img压缩:一般图片在web系统的比重都比较大,压缩工具:tinypng,JpegMini,ImageOptim。Gzip压缩:配置nginx服务,gzip on|off,gzip_buffers 32 4K|16 8K #缓冲(在内存中缓存几块?每块多大),gzip_comp_level [1-9] #推荐6 压缩级别(级别越高,压的越小,越浪费CPU计算资源),gzip_disable #正则匹配UA 什么样的uri不进行gzip,gzip_min_length 200 #开始压缩的最小长度,gzip_http_version 1.0|1.1 #开始压缩的http协议版本,gzip_proxied #设置请求者代理服务器,该如何缓存内容,gzip_types text/plain applocation/xml #对哪些类型的文件用压缩,gzip_vary on|off #是否传输gzip压缩标志。其他工具:自动化构建工具Grunt。
CDN:Content Delivery Network,内容分发网络,尽可能避开互联网上有可能影响数据传输速度和稳定性的瓶颈和环节,使内容传输的更快更稳定;在网络各处放置节点服务器所构成的在现有的互联网基础之上的一层智能虚拟网络;CDN系统能够实时的根据网络流量和各节点的连接,负载情况以及到用户的距离和响应时间等综合信息将用户的请求重新导向离用户最近的服务节点上。本地cache加速,提高了企业站点(尤其含有大量img和静态页面站点)的访问速度;跨运营商的网络加速,保证不同网络的用户都得到良好的访问质量;远程访问用户根据DNS负载均衡技术智能自动选择cache服务器;自动生成服务器的远程Mirror cache服务器,远程用户访问时从cache服务器上读数据,减少远程访问的带宽,分担网络流量,减轻原站点web服务器负载等功能;广泛分布的CDN节点加上节点之间的只能智能冗余机制,可以有效的预防黑客入侵
CDN的工作原理:传统访问:用户在浏览器输入域名发起请求--解析域名获取服务器IP地址--根据IP地址找到对应的服务器--服务器响应并返回数据;使用CDN访问:用户发起请求--智能DNS的解析(根据IP判断地理位置,接入网类型,选择路由最短和负载最轻的服务器)--取得缓存服务器IP--把内容返回给用户(如果缓存中有)--向源站发起请求--将结果返回给用户--将结果存入缓存服务器
CDN适用场景:站点或者应用中大量静态资源的加速分发,如css,js,img和html;大文件下载;直播网站等
CDN的实现:BAT等都有提供CDN服务,可用LVS做4层负载均衡;可用nginx,Varnish,Squid,Apache TrafficServer做7层负载均衡和cache;使用squid反向代理,或者nginx等的反向代理
独立的必要性:分担web服务器的I/O负载-将耗费资源的图片服务分离出来,提高服务器的性能和稳定性;能够专门的图片服务器进行优化-为图片服务设置有针对性的缓存方案,减少带宽成本,提高访问速度;提高网站的可扩展性-通过增加图片服务器,提高图片吞吐能力
采用独立域名:原因:同一域名下浏览器的并发连接数有限制,突破浏览器连接数的限制;由于cookie的原因,对缓存不利,大部分web cache都只缓存不带cookie的请求,导致每次的图片请求都不能命中cache
独立后的问题:如何进行图片上传和图片同步:NFS共享方式;利用FTP同步
将现有PHP等动态语言的逻辑代码生成为静态HTML文件,用户访问动态脚本重定向到静态HTML文件的过程。对实时性要求不高的页面比较适合。原因:动态脚本通常会做逻辑计算和数据查询,访问量越大,服务器压力越大;访问量大时可能会造成CPU负载过高,数据库服务器压力过大;静态化可以降低逻辑处理压力,降低数据库服务器查询压力
静态化的实现方式:
使用模板引擎:可以使用smarty的缓存机制生成静态HTML缓存文件;$smarty->cache-dir = $ROOT."/cache";//缓存目录,$smarty->caching=true;//是否开启缓存,$smarty->cache_lifetime="3600";//缓存时间,$smarty->display(string template[, string cache_id[, string compile_id]]);,$smarty->clear_all_cache();//清除所有缓存,$smarty->clear_cache('a.html');//清除指定的缓存,$smarty->clear_cache('a.html', $art_id);//清除同一个模板下的指定缓存号的缓存
利用ob系列的函数:ob_start():打开输出控制缓冲,ob_ge_contents():返回输出缓冲区内容,ob_clean():清空输出缓冲区,ob_end_flush():冲刷出(送出)输出缓冲区内容并关闭缓冲,可以判断文件的inode修改时间,判断是否过期使用filectime函数
Memcache
memcache是一套分布式的高速缓存系统,由LiveJournal的Brad Fitzpatrick开发,但目前被许多网站使用以提升网站的访问速度,尤其对于一些大型的、需要频繁访问数据库的网站访问速度提升效果十分显著 [1] 。这是一套开放源代码软件,以BSD license授权发布。
MemCache的工作流程如下:先检查客户端的请求数据是否在memcached中,如有,直接把请求数据返回,不再对数据库进行任何操作;如果请求的数据不在memcached中,就去查数据库,把从数据库中获取的数据返回给客户端,同时把数据缓存一份到memcached中(memcached客户端不负责,需要程序明确实现);每次更新数据库的同时更新memcached中的数据,保证一致性;当分配给memcached内存空间用完之后,会使用LRU(Least Recently Used,最近最少使用)策略加上到期失效策略,失效数据首先被替换,然后再替换掉最近未使用的数据。 [2]
Memcache是一个高性能的分布式的内存对象缓存系统,通过在内存里维护一个统一的巨大的hash表,它能够用来存储各种格式的数据,包括图像、视频、文件以及数据库检索的结果等。简单的说就是将数据调用到内存中,然后从内存中读取,从而大大提高读取速度。
Memcache是danga的一个项目,最早是LiveJournal 服务的,最初为了加速 LiveJournal 访问速度而开发的,后来被很多大型的网站采用。
Memcached是以守护程序(监听)方式运行于一个或多个服务器中,随时会接收客户端的连接和操作。
Redis
redis是一个key-value存储系统。和Memcached类似,它支持存储的value类型相对更多,包括string(字符串)、list(链表)、set(集合)、zset(sorted set --有序集合)和hash(哈希类型)。这些数据类型都支持push/pop、add/remove及取交集并集和差集及更丰富的操作,而且这些操作都是原子性的。在此基础上,redis支持各种不同方式的排序。与memcached一样,为了保证效率,数据都是缓存在内存中。区别的是redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,并且在此基础上实现了master-slave(主从)同步。
Redis 是一个高性能的key-value数据库。 redis的出现,很大程度补偿了memcached这类key/value存储的不足,在部 分场合可以对关系数据库起到很好的补充作用。它提供了Java,C/C++,C#,PHP,JavaScript,Perl,Object-C,Python,Ruby,Erlang等客户端,使用很方便。 [1]
Redis支持主从同步。数据可以从主服务器向任意数量的从服务器上同步,从服务器可以是关联其他从服务器的主服务器。这使得Redis可执行单层树复制。存盘可以有意无意的对数据进行写操作。由于完全实现了发布/订阅机制,使得从数据库在任何地方同步树时,可订阅一个频道并接收主服务器完整的消息发布记录。同步对读取操作的可扩展性和数据冗余很有帮助。
redis的官网地址,非常好记,是redis.io。(特意查了一下,域名后缀io属于国家域名,是british Indian Ocean territory,即英属印度洋领地)
目前,Vmware在资助着redis项目的开发和维护。
Redis和Memcache区别
1.Redis是什么
这个问题的结果影响了我们怎么用Redis。如果你认为Redis是一个key value store, 那可能会用它来代替MySQL;如果认为它是一个可以持久化的cache, 可能只是它保存一些频繁访问的临时数据。Redis是REmote DIctionary Server的缩写,在Redis在官方网站的的副标题是A persistent key-value database with built-in net interface written in ANSI-C for Posix systems,这个定义偏向key value store。还有一些看法则认为Redis是一个memory database,因为它的高性能都是基于内存操作的基础。另外一些人则认为Redis是一个data structure server,因为Redis支持复杂的数据特性,比如List, Set等。对Redis的作用的不同解读决定了你对Redis的使用方式。
互联网数据目前基本使用两种方式来存储,关系数据库或者key value。但是这些互联网业务本身并不属于这两种数据类型,比如用户在社会化平台中的关系,它是一个list,如果要用关系数据库存储就需要转换成一种多行记录的形式,这种形式存在很多冗余数据,每一行需要存储一些重复信息。如果用key value存储则修改和删除比较麻烦,需要将全部数据读出再写入。Redis在内存中设计了各种数据类型,让业务能够高速原子的访问这些数据结构,并且不需要关心持久存储的问题,从架构上解决了前面两种存储需要走一些弯路的问题。
2. Redis不可能比Memcache快
很多开发者都认为Redis不可能比Memcached快,Memcached完全基于内存,而Redis具有持久化保存特性,即使是异步的,Redis也不可能比Memcached快。但是测试结果基本是Redis占绝对优势。一直在思考这个原因,目前想到的原因有这几方面。
Libevent。和Memcached不同,Redis并没有选择libevent。Libevent为了迎合通用性造成代码庞大(目前Redis代码还不到libevent的1/3)及牺牲了在特定平台的不少性能。Redis用libevent中两个文件修改实现了自己的epoll event loop(4)。业界不少开发者也建议Redis使用另外一个libevent高性能替代libev,但是作者还是坚持Redis应该小巧并去依赖的思路。一个印象深刻的细节是编译Redis之前并不需要执行./configure。
CAS问题。CAS是Memcached中比较方便的一种防止竞争修改资源的方法。CAS实现需要为每个cache key设置一个隐藏的cas token,cas相当value版本号,每次set会token需要递增,因此带来CPU和内存的双重开销,虽然这些开销很小,但是到单机10G+ cache以及QPS上万之后这些开销就会给双方相对带来一些细微性能差别(5)。
3. 单台Redis的存放数据必须比物理内存小
Redis的数据全部放在内存带来了高速的性能,但是也带来一些不合理之处。比如一个中型网站有100万注册用户,如果这些资料要用Redis来存储,内存的容量必须能够容纳这100万用户。但是业务实际情况是100万用户只有5万活跃用户,1周来访问过1次的也只有15万用户,因此全部100万用户的数据都放在内存有不合理之处,RAM需要为冷数据买单。
这跟操作系统非常相似,操作系统所有应用访问的数据都在内存,但是如果物理内存容纳不下新的数据, 操作系统会智能将部分长期没有访问的数据交换到磁盘,为新的应用留出空间。现代操作系统给应用提供的并不是物理内存,而是虚拟内存(Virtual Memory)的概念。
基于相同的考虑,Redis 2.0也增加了VM特性。让Redis数据容量突破了物理内存的限制。并实现了数据冷热分离。
4. Redis的VM实现是重复造轮子
Redis的VM依照之前的epoll实现思路依旧是自己实现。但是在前面操作系统的介绍提到OS也可以自动帮程序实现冷热数据分离,Redis只需要OS申请一块大内存,OS会自动将热数据放入物理内存,冷数据交换到硬盘,另外一个知名的“理解了现代操作系统(3)”的Varnish就是这样实现,也取得了非常成功的效果。
作者antirez在解释为什么要自己实现VM中提到几个原因(6)。主要OS的VM换入换出是基于Page概念,比如OS VM1个Page是4K, 4K中只要还有一个元素即使只有1个字节被访问,这个页也不会被SWAP, 换入也同样道理,读到一个字节可能会换入4K无用的内存。而Redis自己实现则可以达到控制换入的粒度。另外访问操作系统SWAP内存区域时block进程,也是导致Redis要自己实现VM原因之一。
5. 用get/set方式使用Redis
作为一个key value存在,很多开发者自然的使用set/get方式来使用Redis,实际上这并不是最优化的使用方法。尤其在未启用VM情况下,Redis全部数据需要放入内存,节约内存尤其重要。
假如一个key-value单元需要最小占用512字节,即使只存一个字节也占了512字节。这时候就有一个设计模式,可以把key复用,几个key-value放入一个key中,value再作为一个set存入,这样同样512字节就会存放10-100倍的容量。
这就是为了节约内存,建议使用hashset而不是set/get的方式来使用Redis,详细方法见参考文献(7)。
6. 使用aof代替snapshot
Redis有两种存储方式,默认是snapshot方式,实现方法是定时将内存的快照(snapshot)持久化到硬盘,这种方法缺点是持久化之后如果出现crash则会丢失一段数据。因此在完美主义者的推动下作者增加了aof方式。aof即append only mode,在写入内存数据的同时将操作命令保存到日志文件,在一个并发更改上万的系统中,命令日志是一个非常庞大的数据,管理维护成本非常高,恢复重建时间会非常长,这样导致失去aof高可用性本意。另外更重要的是Redis是一个内存数据结构模型,所有的优势都是建立在对内存复杂数据结构高效的原子操作上,这样就看出aof是一个非常不协调的部分。
其实aof目的主要是数据可靠性及高可用性,在Redis中有另外一种方法来达到目的:Replication。由于Redis的高性能,复制基本没有延迟。这样达到了防止单点故障及实现了高可用。
高并发场景下缓存常见问题
缓存一致性
缓存并发问题
缓存穿透问题
缓存的雪崩现象
请参考我的文章redis一文弄懂
消息队列
消息队列的特性
业务无关:只做消息分发
FIFO:先投递先到达
容灾:节点的动态增删和消息的持久化
性能:吞吐量提升、系统内部通信效率提高
为什么需要消息队列
【生产】和【消费】的速度或稳定性等因素不一致
消息队列的好处
业务解耦
最终一致性
广播
错峰有流控
详情请参考我的文章消息中间件的应用
应用拆分-原则
业务优先
循序渐进
兼顾技术:重构、分层
可靠测试
应用拆分-思考
应用之间通信:RPC(dubbo等)、消息队列
应用之间数据库设计:每个应用都有独立的数据库
避免事务操作跨应用
Dubbo
微服务
应用限流
应用限流-算法
数器法
滑动窗口
漏捅算法
令牌通算法
详情请参考我的文章 构建微服务
数据库切库、分库、分表
数据库瓶颈
单个库数据量太大(1T-2T):多个库
单个数据库服务器压力过大、读写瓶颈:多个库
单个表数据量过大:分表