大型Java项目架构演进

大型Java项目架构演进过程

1. All-In-One (所有服务在一台服务器上):

   也就是所有的服务都在同一个服务器上,包括应用服务器、文件服务器和数据库

6e96d67e9ab768800dfaaeeefc4cfb9ede1.jpg

2. 各服务分别部署在不同的服务器上

    随着用户越来越多,访问量越来越大,硬盘、CPU、内存等硬件开始吃紧,一台服务器已经无法满足需求,这个时候就需要将不同的服务部署在多个服务器上,给应用服务(Application server)配置更好的内存和cpu,给数据库服务器配置更好,更大,更快的硬盘。

e53071a73710771400b59420b38ea5aff69.jpg

3. 添加缓存服务器:

    随着访问的并发越来越高,为了缩短接口的访问时间,提高访问性能。

    同时发现,我们的很多业务数据不需要每次都从数据库中获取,于是我们使用缓存来进行数据缓存,提高访问速度。

    (80%的业务集中在20%的数据上,即2--8原则)

342c34ab5fa3ddadf8f00c80ba391d7734d.jpg

    在这里缓存又可以分为  本地缓存远程缓存。 同时,远程缓存又有两种情形:单机缓存分布式集群缓存

    使用该架构需要思考和解决的问题:

        1. 哪种业务特点的数据需要进行缓存

        2. 哪些数据适合进行本地缓存,哪些数据适合进行远程缓存

        3. 分布式缓存在扩容时会遇到什么问题,如果解决

        4. 分布式缓存的算法都有哪几种,各有什么优缺点

 

4. 增加负载均衡器,服务器均衡:

    随着访问的QPS(每秒查询率)不断的提高,服务器的处理能力(例如Tomcat)可能就会出现瓶颈,虽然也可以购买更加强大的硬件,但总会有上限,而且这个成本到了后期会出现指数级的增长,这个时候就需要做一个服务器的集群,通过负责均衡服务器来实现服务集群访问。

6b67860f4bff2fa0819501bef3585ea8636.jpg

    这个时候需要考虑的问题:

        1. 负责均衡的调度策略都有哪些,各有什么优缺点,各适合什么场景。

         调度策略: 轮训、权重、地址散列(包含:源ip散列 和 目的ip散列)、最少连接、加权最少连接

        2. session的管理问题

            同一用户可能第一次登陆的是A服务器,那么session信息是保存在A服务器上的,第二次可能访问的是B服务器,这个时候B服务器上并没有该用户的session信息,这时就涉及到了session管理的问题问题。

        方式1. 可以使用 Session Sticky(粘滞会话)

            56492eb4da8c94c50514f4ca811574486e9.jpg

            实现原理:对于同一连接中的数据包,负载均衡会将其进行一个转化,然后转发至后端固定的服务器上进行处理。也就像上图所示,Browser1每次都会访问Application1这个服务器。这个方案解决了session的共享问题。但是同时又有缺点:1. 如果Application1进行了重启,那么保存在其上的信息将会全部消失,2. 负载均衡器成为了一个有状态的服务器,要实现容灾会有麻烦。

            方式2.  Session Copy

6abad3882e840d1898c1aa8eee275c7baf8.jpg

    实现原理:Application之间会copy自身保存的session到其他服务器上,使得用户通过负载均衡不论将请求发送至哪个Application,该Application都有该用户的session信息。缺点:1. 由于Application之间要不断的同步session信息,可能造成带宽不够的问题。2. 当大量用户在线的时候,Application会占用大量的内存,不适合做大规模集群。

方式3. 基于cookie

6ca677ce6331c44744ee957602914f4a507.jpg

        实现原理:用户携带含有session信息的cookie去访问Application。缺点:1. cookie的长度是有限制的  2. cookie保存在浏览器上,安全性是一个问题。

    方式4. 使用session服务器

f65ee7a06d9191839b63f4a34f729298a76.jpg

    实现原理:所有用户的session信息都统一保存在session server中。缺点:1. session server是个单点的,如何解决该server的单点,保证其高可用性  

5. 数据库的读写分离:

    当用户量达到一定量的时候,数据库的读写操作的都是同一个数据库,这个时候数据库就成为了一个瓶颈,这个时候就可以进行数据库的读写分离

37b2414622e8d8e7aa64962f402edf5aa59.jpg

        包含主库和从库,同时应用要接入多数据源,并且通过统一的数据访问模型进行数据访问,数据库读写分离将所有的读操作全部引入到Slave这个数据库中,将所有的写操作全部引入到Master这个数据库中,同时由于进行了读写数据分离,我们在应用中实现了数据访问模块,使得上层写代码的人不知道数据读写分离的情况,这样我们多数据源的读写对业务代码就没有了侵入。

        这个时候引申的问题就有:1. 如何支持多数据源,2. 如何封装对业务没有侵入,3. 如何使用目前项目使用的ORM框架完成底层的读写分离,4. 是否需要更换ORM,又各有什么优缺点,如何取舍。

        当数据量非常大的时候,数据库的读写分离又会遇到一下问题:1. 主库和从库在同步的时候,有没有延时;如果我们将主库和从库进行了夸机房部署,那么在跨机房数据传输的时候,延时更是一个问题。2. 应用对数据源的路由问题

 6. 曾加了CDN和反向代理服务器:

    为了提高服务器,又增加了CDN 和反向代理服务器。使用CDN可以很好的解决不同地区访问速度的问题;反向代理则可以缓存用户的资源

99d0637a834fc737cd7bb19e141c268dad4.jpg

 

 7. 文件服务器改为了分布式文件服务器:

6c1353293de0e059e6a80c60aed9dbbfb65.jpg

    需要考虑的问题:1. 如何不影响已部署在线上的业务访问(不能出现某个图片不能访问了),2. 是否需要业务部门帮忙清洗数据 3. 是否需要备份服务器 4. 是否需要重新做域名解析等等。

8. 数据库分表:

    数据量大的时候,数据的增删改查又出现了瓶颈,这个时候我们选择使用专库专用的方式,进行数据的垂直拆分,相关的业务都使用自己专有的库。

e786a8bb5e35f094763127312601e19ba97.jpg

    需要考虑的问题:1. 跨业务的事物,夸库的事物 (可以考虑分布式事物,或者去掉事物,或者不追求强事物),2. 夸库的join怎么实现

9. 数据库分表

    随着访问量过大,业务量过大,可能出现某个业务的数据库的数据达到了单个数据库的瓶颈,这个时候就要考虑进行数据库的水平拆分(将同一个表的数据拆分到两个数据库中)

b6a136367b1827c82fc98d4360304b7fde1.jpg

        需要考虑的问题:1. sql路由的问题(假设查询某个用户,如何确定用户在哪个数据库中)2. 主见的策略会有所不同 3 分页的问题

10. 添加了搜索引擎和NoSql服务器

        假如发现我们应用服务器上的搜索量飙升,或者因为我们对外做了一个推广,这个时候我们将Application中的搜索功能单独拆分出来,做了一个搜索引擎,同时部分场景可以使用NoSql提高性能,同时我们开发一个统一的数据访问模块,这个某块下面连着数据库集群、搜索引擎、还有NoSql,解决上层应用开发的数据源问题。

79af0e45454ee47cb1394536e118396f4c2.jpg

 

 

转载于:https://my.oschina.net/Declan/blog/2222455