在业务量越来越大的时候,系统访问量同时大了起来,这个时候就要考虑系统如果处理高并发的请求。
性能
性能的话分为两个,一个是应用,一个是数据库。单个应用的性能提升上去了,那集群的整体性能提升作用会更大。
应用就是我们的代码优化,比如算法的优化,代码的设计方式,jvm的优化。
数据库就是sql的优化,比如表结构怎么建,索引怎么建,sql语句怎么写等方面。
这些规范可以参考阿里巴巴Java开发手册
拆分
架构演进之路和数据库演进之路提到了为了提高系统并发处理能力,对应用和数据库进行了水平拆分和垂直拆分。
应用层
对应用的拆分会有以下几个问题:
- 分布式事务:在单机应用中,我们的订单服务和库存服务是一起的,通过数据库的ACID来保证事务,但是拆分后,就没办法通过数据库的ACID来了,所以要如何保证分布式事务?常用的有2PC/3PC、TCC、Saga
- 分布式锁:在分布式系统下,java提供的各自锁已经没办法处理这些共享资源的并发问题,所以要如何保证分布式锁呢?常用的有数据库加锁、zookeeper加锁、redis加锁、etcd加锁。
- 分布式作业调度:一个定时任务部署多份,比如ABC,如何保证他们的定时任务不重复执行?比如常用的有elastic-job、xxl。
数据库
对数据库拆分会有以下几个问题:
- 读写分离:如何保证数据的一致性。
- 分库分表:分布式下的主键是怎么生成的、分库分表后怎么跨库分页、分库分表是怎么做的?分库分表的中间件有哪些(mycat、sharding-jdbc)。
负载均衡
在高可用中,我们提到了冗余,但是仅仅只是当master挂了slave顶上去用,那这个资源就很浪费了,所以我们就想,通过负载均衡让多个服务同时启用,既达到了高可用的目的,也用于处理高并发的请求。
但并不是多个服务一起用他就等于可以处理高并发的,比如mysql的主从,由于是异步更新的,所以salve的数据总是延迟于master的,如果强一致性要求高的话,就不能用了。如果强一致性没什么要求的话可以用,类似的reidis也一样。
所以无状态对于高并发来说,就很重要了。当请求量一上来,我们就做多个节点就好了。比如我们用nginx做负载均衡,压力上来了,就多加几个tomcat加入集群就好了,只是我们要考虑到,在这种情况下,session要如何处理?
负载均衡常用的硬件和软件如下:
- 硬件:F5
- 软件:nginx、apache、lvs、haproxy
均衡策略(见dubbo)如下:
- Random LoadBalance:随机,按权重设置随机概率。
- RoundRobin LoadBalance:* 轮询,按公约后的权重设置轮询比率。
- LeastActive LoadBalance:最少活跃调用数,相同活跃数的随机,活跃数指调用前后计数差。
- ConsistentHash LoadBalance: 一致性 Hash,相同参数的请求总是发到同一提供者。
缓存
缓存对于读服务来说,是抗流量的银弹。但是如何用好缓存,也是很重要的。比如我们引入了redis,我们必须保证redis是高可用(redis - 哨兵(高可用)、redis - 集群(一))的,不然reidis挂了怎么办。我们同样也要保证redis的高并发,要让他扛得住流量(redis - 主从(高性能))。我们要保证reids挂了可以快速恢复(redis - 持久化)。引入redis,我们要考虑数据库和reids的数据一致性(缓存的数据一致性)。我们要考虑到缓存雪崩了怎么办,缓存穿透了怎么办。
消息队列
消息队列的主要几个场景有异步、解耦、流量削峰。
跟redis一样,我们同样也要保证消息队列的高可用,比如ActiveMQ - MasterSlave、RabbitMQ集群、RabbitMQ故障转移。ActiveMQ - 消息可靠性、RabbitMQ - 发送方的可靠性、RabbitMQ - 消息确认为了保证消息的可靠性,发送方或者第三方中间件会重复发送消息,我们要保证接收方的幂等性,这个幂等性可以参考接口幂等设计。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。