高大哥的武器库中到底有哪些呢?
无状态
如果设计是无状态的,去session化的,应用更容易水平扩展。实际场景可以让系统是无状态的,配置文件或配置中心去形成干扰变成有状态的
系统拆分
为啥要做系统拆分,暂且按下不表。通常可以从几个维度去做系统拆分:
a 系统维度-- :按照系统功能/业务拆分,比如商品系统、购物车、结算、订单系统等
b 功能维度-- : 对一个系统进行功能再拆分,比如,优惠券系统可以拆分为后台券创建系统、领券系统、用券系统等
c 读写维度-- : 商品系统,交易的各个系统都会读取数据,读的量大于写,因此可以拆分成商品写服务、商品读服务;读服务可以考虑使用缓存提升性能;写的量太大时,需要考虑分库分表
服务化
首先,判断是不是只需要简单的单点远程服务调用,单机不行集群是不是就可以解决?
其次,在客户端注册多台机器并使用Nginx进行负载均衡是不是就可以解决?
其次,随着调用方越来越多,应该考虑使用服务自动注册和发现(如Dubbo使用ZooKeeper)。
其次还要考虑服务的分组/隔离,比如系统访问量太大导致整个服务打挂,因此需要为不同的调用方提供不同的服务分组隔离访问。
后期随着调用量的增加还要考虑服务的限流、黑白名单等
总结:进程内服务→单机远程服务→集群手动注册服务→自动注册和发现服务→服务的分组/隔离/路由→服务治理如限流/黑白名单
最后死神三大杀招:消息队列(解耦、异步、削峰),缓存银弹,并发化
三大杀招对应的手段分别是队列术,各个层次的缓存和池化技术,异步并发多线程
- 队列术
队列,在数据结构中是一种线性表,从一端插入数据,然后从另外一端删除数据。
在我们的系统中,不是所有的处理都要实时的返回结果,不是所有的请求都必须实时反馈结果给用户,不是所有的请求都必须一次性处理成功,保证最终一致性,不需要强一致性。此时我们可以使用队列,
但使用队列的过程中,需要考虑消息丢失如何处理?(一般来说有些消息队列有重试机制,达到重试次数还未成功,会通知给生产者失败,同时生产者需要对失败的消息做持久化延后处理并做相关告警。)
消息重复消费如何处理?(业务系统保证消费是幂等的)
- 异步线程
电商系统,首页,活动页,商详页,乃至结算页,这些页面大多是调用多个其他服务获取数据、拼装数据,聚合返回给到前端,而系统之间调用可以通过HTTP接口调用(HttpClient),SOA服务(dubbo,thrift)等实现。
在java中,如使用tomcat,一个请求会分配一个线程去处理,该线程负责获取数据,拼装数据或模板,然后返回给前端。在同步调用获取数据接口的情况下,整个线程是一直被占用并阻塞的。如果有大量这种请求,每个请求占用一个线程,但线程一直处于阻塞状态,这样会降低系统的吞吐量。 而这应该有更好的解决方案,异步/协程,而java是不支持携程的,但可以采用异步来达到目的。目前大部分Java框架(HttpAsyncClient,Dubbo,Thrift)都支持。
- 缓存
缓存,让数据更接近于使用者,目的是让访问速度更快。工作机制是先从缓存中读取数据,如果没有,再从慢速设备上读取实际数据并同步到缓存。
那些经常读取的数据、频繁访问的数据、热点数据、I/O瓶颈数据、计算昂贵的数据、符合5分钟法则和局部性原理的数据都可以进行缓存。如CPU→L1/L2/L3→内存→磁盘就是一个典型的例子,CPU需要数据时先从L1读取,如果没有找到,则查找L2/L3读取,如果没有,则到内存中查找,如果还没有,会到磁盘中查找。
还有比如用过Maven的读者都应该知道,加载依赖的时候,先从本机仓库找,再从本地服务器仓库找,最后到远程仓库服务器找。另外还有京东的物流为什么那么快?他们在各地都有分仓库,如果该仓库有货物,那么送货的速度是非常快的。