0x01 写在前面的话
这几年来,随着中国互联网的不断发展,各种新型技术和框架层出不穷。作为一名Java 软件开发工程师,在外企的这两年来,也许日子过得太过于安逸,导致不知外面世界已发生了怎样翻天覆地的变化。如今走出来,看到外面的世界,才发现自己的技术已经落后了好多。
而近些年来,越来越多的线上线下培训机构也不断造就了越来越多的程序员,这就导致我们程序员这个行业所受到的压力和挑战也越来越大。但是我们应该都明白,一味地恐惧于压力是没有什么用的,我们能做的唯有通过不断学习,改变自己,增强自己的专业本领,才能在竞争之中不被打倒,才能达到我们不被淘汰甚至加薪的愿望。所以在接下来的日子里,我会与大家一起共同学习了解新型技术和框架。
0x02 微服务和分布式
众所周知,微服务和分布式在如今的码农界,火热到几乎无人不知,无人不晓的地步。但是你有没有好奇过为什么它会突然出现并变得这么火热呢?
为什么会出现微服务和分布式?
其实在最开始学习微服务和分布式的时候,我对这个问题也一直百思不得其解,所以也导致我学习起来感觉很吃力,直到后来才偶然发现这个问题从架构的角度去思考这个问题,便豁然开朗了,学习起来也轻松了很多。
想要弄清楚这个问题,我们就不得不了解下企业级架构的演变。
在码农界,企业应用使用的架构最开始是这样的:
1. 企业架构设计之原始版
特点:
- 单节点
- 几乎无容灾
- 负载能力低
- 维护简单
- 问题???
应用程序中任意一个模块一旦出现问题,整个应用的所有功能就全部停止服务了。
为了改善这种架构存在的问题,人们最开始想到的办法是通过建立服务器集群。
类似这个样子:
这样我们有了多个备用服务器,一旦一个服务器坏掉,我们只需要切换下另外一个服务器便可以继续提供服务。
架构继续演进,人们慢慢发现浏览器的请求一般包括html/css/js 和API请求数据库数据,访问量小还好说,但是一旦访问量大了,服务端就会感到压力很大,为了减轻负载的压力,人们思考,将html/css/js 的请求和API的请求进行分离,设计了一个叫做Nginx 的服务器来专门处理html/css/js 的请求。
这便是企业架构之动静分离版
2. 企业架构设计之动静分离版
这种特点:
- Nginx 访问静态资源
- Nginx负载均衡
- 应用分离
- 依赖框架
- 存在安全性低问题
- 存在Session持久化问题
问题:???
上面我们可以看出,动静分离架构存在Session 持久化问题,那么问题来了
1什么是session 持久化?
web服务器通常将那些暂时不活动但未超时的HttpSession对象转移到文件系统或数据库中保存,服务器要使用他们时再将他们从文件系统或数据库中装载入内存,这种技术称为Session的持久化。
2.为什么session 需要持久化?
Session是存储在服务器端的,客户端访问了某个能开启会话功能的资源, web服务器就会创建一个与该客户端对应的HttpSession对象,每个HttpSession对象都要站用一定的内存空间。如果在某一时间段内访问站点的用户很多,web服务器内存中就会积累大量的HttpSession对象,消耗大量的服务器内存,即使用户已经离开或者关闭了浏览器,web服务器仍要保留与之对应的HttpSession对象,在他们超时之前,一直占用web服务器内存资源。
我们考虑下这种情况,某用户登陆我们的网站,与我们的服务器建立了一个session 连接,由于服务器更新或者升级,服务器不得不重启下,session 突然失效,用户需不需要重新登陆? 再比如用户重复“打开访问我们的网站然后再关闭浏览器“这个操作,在时间较短的情况下,session 会重复创建,那么是不是也会对服务器的性能造成影响。
查看详情
于是程序员们设计了Memcached, Redis 等缓存数据库来解决这个问题,这就是企业架构之缓存版。
3.企业架构之缓存版
特点:
- 大量使用缓存
- Nginx 接受Https
- Session持久化
- 存在一致性问题
- 存在缓存失效问题
这种架构,使用了Redis、Memcached 高速缓存,一般支持key-value 形式的查询,相当于传统数据库来说,它的性能非常好,它可以达到每秒六万以上的查询量。
引用高速缓存来提升服务的性能,高速缓存的使用分为三种情况,
- 第一种情况 基于请求的查询,当Http请求过来之后,应用先去查询高速缓存是否存在结果,如果没有结果,应用再去数据库中查询出来返回给用户并写入到高速缓存中。
- 第二种情况 基于查询结果的缓存,当请求过来后,在查询数据库之前,先根据条件查询高速缓存,如果查询到结果,再封装返回给用户,如果查询不到,就从数据库中查询出来并写入到缓存里,再返回给用户。
- 第三种情况 利用高速缓存来做session会话持久,在上一版动静分离版中,由于部署了 多台机器,由于一台机器不能访问另外一台机器的
session,所以将session公共存储到高速缓存中,然后http请求过来之后,根据session的id从高速缓存中查询对应的结果。相当于把session持久化在高速缓存中。
由于缓存版中大量使用了高速缓存,数据库和高速缓存之间没有同步机制,如果在查询高速缓存的时候,数据库中有更新,但是没有及时更新到高速缓存中,那么用户查询到的结果还是之前的结果。就会存在一致性的问题。
这时虽然在一定程度上很大改进了, 但这种单体架构仍然存在一些痛点:
痛点一:项目过于臃肿
当大大小小的功能模块都集中在同一个项目中的时候,整个项目必然变得十分臃肿,让开发者难以维护。
痛点二:资源无法隔离
各个模块依赖于同样的数据库,内存资源,一旦某个模块功能使用不当,这个系统整体崩溃。
痛点三:无法灵活扩展
打个比方,假设我们有一个电商项目,有订单模块,支付模块,用户模块,聊天模块,一旦支付模块出现问题,其他模块都没有任何问题的情况下,由于这是一个整体web应用,我们部署服务器集群的时候,就不得不把订单模块,支付模块,用户模块,聊天模块全部都部署上。
然而我们实际想要的只是多部署几个备用的比较重要容易出错的支付模块。
随着服务化的兴起,越来越多企业将大型程序按照功能和业务拆分开来,分离成很多个小应用来提供服务,这就是分布式服务版。
4.企业架构之分布式服务
特点
- 小型机虚拟化
- 请求处理与业务分离
- 应用服务化
- 同步异步拆分
- 数据库读写分离
- 运维难度大大增加
分布式服务在保证功能不变的前提下,将应用拆分为前端web应用和后台服务。后台服务根据业务不同拆分为若干个子应用,这些若干个子应用共同提供服务,web应用调用这些服务和用户打交道。此时,web应用就不会包括太多底层的功能。不同的服务封装起来,组成一个业务逻辑。
web应用怎么才能调用到另外一台机器上的服务呢?此时就需要使用我们的分布式服务框架,或者企业服务总线等技术来将其他机器提供的服务通过远程调用来访问这些服务。
做的比较完善的分布式服务框架,比如Dubbo都可以提供服务路由,负载均衡,调用统计,等一些功能,更方便管理整个集群上的服务。同时,拆分之后,应用的数量会增加很多,每个应用的负载相应地就会没有之前那么多。这时候我们需要对之前用来部署web应用的小型机进行虚拟化,简单来讲,就是在小型机上安装若干个虚拟机,将应用部署在虚拟机之中,或者部署在云服务器中。
这个版本还有个特性就是大量使用了第三方的中间件,比如,消息中间件ActiveMQ,调度中间件 tbschedule,以及集群管理监控的平台
.使用消息中间件可以将大量的异步操作发送到消息中间件中,后台服务均匀地消费这些消息,避免了访问时的峰值对于整个数据库压力的影响。同时,拆分了异步的操作能够提升服务的吞吐量,避免大量的耗时操作影响用户。
同时,还增加了数据库的读写分离,配置多个读库来和主库同步,将所有的查询都映射到读库上,避免了数据库写入时对数据读取造成影响。
设置读库还有个好处,在主库挂了情况下,进行读写切换,瞬间将读库切换成主库。使得正常的业务不受影响。
但是由于服务器的增多,第三方中间件的部署,以及数据库主从等,比之前多了很多需要监控的机器,对于服务器的部署必须能自动化运行,而且必须能实时监控,异常发生时能及时通知,对于运维增加了难度。
分布式服务版的瓶颈在于如果出现高并发的时候,对某些应用的压力会非常大,而某台虚拟机的负载 就会非常高,有可能导致整个的小型机都会受到影响。为了更好地负载压力和分配服务器的资源,于是便出现了弹性计算。
5. 企业架构之弹性计算
首先用引用一个概念,就是容器级别的虚拟化。简单来说不需要部署分配多个虚拟机,而是采用docker 这种容器级的虚拟化系统,将应用部署到docker容器之中。容器级别的虚拟化可以理解为就像web应用部署到tomcat之中一样。使用容器级别的虚拟化,能够使得服务器的资源可以实时分配。
假设一个场景,在监控到web应用的压力负载增加到百分之七十以上的时候,使用脚本能够新增一系列的docker容器,再将应用启动起来。 这些操作能在秒级的情况下,瞬间增加了许多服务器的资源,来满足负载。当负载下降的时候,就停止应用,将docker容器也停止,能够节省服务器的资源来给其他服务使用。
这个版本增加了基于Hadoop的日志收集平台,在应用产生应用日志之后,使用日志收集平台,将日志写入Hadoop集群,不用再担心日志在docker容器之中,停止之后日志丢失。同时,能够对日志做查询。
同样,Hadoop在处理离线资源的时候,一般是在晚上,这个时候的应用负载都很低,可以控出很多服务器的资源,我们在处理Hadoop任务之前,可以用docker新增很多节点,再来计算。
同时,还有一个好处就是能够快速复制节点,在某部分机房有问题的时候,能够快速在另外一个机房复制出大量应用,高效解决了,异地容灾的问题。
这个版本的数据库使用,和之前也不再一样,应用不再直接和数据库打交道而是使用了数据库中间件。例如淘宝的TDDL,对于开发来说,不需要在配置中配置读写分离,而是只是配置和中间件的连接。用数据库中间件来路由表,包括单表被水平拆分之后,使用数据库中间件来做集合,或者路由到具体的表中。
将数据库的管理,和应用的开发人员隔离开来,更加简化了应用对数据库操作。开发人员不再担心,随着数据量的增加,对数据库的压力,同时,中间件还能配置将数据库中的数据同步到Hadoop集群之中,再配置一些离线任务。
使用Hadoop来计算,计算的结果保存在Hadoop之中。再用中间件去读取Hadoop的计算结果,再写入到数据库。使用中间件,来对数据库的数据源进行处理,生成更高效的数据来节省数据库的资源。
原文链接