首页 存档 技术 查看内容

谈谈互联网后端基础设施

2018-3-30 13:00 |来自: 互联网 252 0

摘要: 对于一个互联网企业,后端服务是必不可少的一个组成部分。抛开业务应用来说,往下的基础服务设施做到哪些才能够保证业务的稳定可靠、易维护、高可用呢? 纵观整个互联网技术体系再结合公司的目前状况,个人认为必不 ...

对于一个互联网企业,后端服务是必不可少的一个组成部分。抛开业务应用来说,往下的基础服务设施做到哪些才能够保证业务的稳定可靠、易维护、高可用呢?


纵观整个互联网技术体系再结合公司的目前状况,个人认为必不可少或者非常关键的后端基础技术/设施如下图所示:




这里的后端基础设施主要指的是应用在线上稳定运行需要依赖的关键组件/服务等。开发或者搭建好以上的后端基础设施,一般情况下是能够支撑很长一段时间内的业务的。此外,对于一个完整的架构来说,还有很多应用感知不到的系统基础服务,如负载均衡、自动化部署、系统安全等,并没有包含在本文的描述范围内。


Api网关


在移动app的开发过程中,通常后端提供的接口需要以下功能的支持:


  • 负载均衡

  • api访问权限控制

  • 用户鉴权


一般的做法,使用nginx做负载均衡,然后在每个业务应用里做api接口的访问权限控制和用户鉴权,更优化一点的方式则是把后两者做成公共类库供所有业务调用。但从总体上来看,这三种特性都属于业务的公共需求,更可取的方式则是集成到一起作为一个服务,既可以动态地修改权限控制和鉴权机制,也可以减少每个业务集成这些机制的成本。这种服务就是Api网关(http://blog.csdn.net/pzxwhc/article/details/49873623),可以选择自己实现,也可以使用开源软件实现,如Kong。如下图所示:




但是以上方案的一个问题是由于所有api请求都要经过网关,它很容易成为系统的性能瓶颈。因此,可以采取的方案是:去掉api网关,让业务应用直接对接统一认证中心,在基础框架层面保证每个api调用都需要先通过统一认证中心的认证,这里可以采取缓存认证结果的方式避免对统一认证中心产生过大的请求压力。


业务应用和后端基础框架


业务应用分为:在线业务应用和内部业务应用。


  • 在线业务应用:直接面向互联网用户的应用、接口等,典型的特点就是:请求量大、高并发、高可用、对故障的容忍度低。

  • 内部业务应用:这个是面向公司内部的应用。比如,内部数据管理平台、广告投放平台等。相比起在线业务应用,其特点: 数据保密性高、压力小、并发量小、允许故障的发生。


业务应用基于后端的基础框架开发,针对Java后端来说,应该有的几个框架如下:


  • MVC框架:从十年前流行的Struts1、2到现在最为推崇的SpringMVC、Jersey以及国人开发的JFinal、阿里的WebX等等,这些框架尤其是后面流行的这些都是各有千秋的。选型的主要因素是看你的团队是否有一个对某框架能够做二次开发、定制的人在。很多时候,针对这些通用的框架,你是需要做一些特定的开发才能满足特定的需求的。比如,很多团队传递参数使用的都是UnderScore的命名法(下划线连接单词),但是Java中确是使用LowCamel命名的。对于SpringMVC,可以通过注解的alias来指定,但这样需要对每一个参数都要指定alias有点效率太低,此外ModelAttribute也不支持别名,更好的方式是在框架层面统一对参数做Camel命名的转换达到目的。

  • IOC框架:ioc带来的好处无须多言。目前Java中最为流行的Spring自诞生就天然支持IOC。

  • ORM框架:MyBatis是目前最为流行的orm框架。此外,Spring ORM中提供的JdbcTemplate也很不错。当然,对于分库分表、主从分离这些需求,一般就需要实现自己的ORM框架来支持了,像阿里的tddl、当当的sharding-jdbc(从datasource层面解决了分库分表、读写分离的问题,对应用透明、零侵入)。此外,为了在服务层面统一解决分库分表、主从分离、主备切换、缓存、故障恢复等问题,很多公司都是有自己的数据库中间件的,比如阿里的Cobar、360的Atlas、网易的DDB,还有官方提供的MySQL Proxy以及开源的MyCat、kingshard和收费的oneproxy。目前,线上有一定规模使用的应该是kingshard,当然如果不缺钱也可以上oneproxy。

  • 缓存框架:缓存框架主要指的是对redis、memcached这些缓存服务器的操作统一封装,一般使用Spring的RedisTemplate即可,也可以使用jedis做自己的封装,支持客户端分布式方案、主从等。

  • JavaEE应用性能检测框架:对于线上的JavaEE应用,需要有一个统一的框架集成到每一个业务中检测每一个请求、方法调用、jdbc连接、redis连接等的耗时、状态等。jwebap是一个可以使用的性能检测工具,但由于其已经很多年没有更新,有可能的话建议基于此项目做二次开发。


一般来说,以上几个框架即可以完成一个后端应用的雏形。


对于这些框架来说,最为关键的是根据团队技术构成选择最合适的,有能力开发自己的框架则更好。此外,这里需要提供一个后端应用的模板或生成工具(如maven的archetype)给团队成员使用,可以让大家在开发新的应用的时候,迅速的生成雏形应用,而无需再做一些框架搭建的重复性劳动。


缓存、数据库、搜索引擎、消息队列


缓存、数据库、搜索引擎、消息队列这四者都是应用依赖的后端基础服务,他们的性能直接影响到了应用的整体性能,有时候你代码写的再好也许就是因为这些服务导致应用性能无法提升上去。


缓存


如缓存五分钟法则所讲:如果一个数据频繁被访问,那么就应该放内存中。这里的缓存就是一种读写效率都非常高的存储方案,能够应对高并发的访问请求,通常情况下也不需要持久化的保证。但相对其他存储来说,缓存一般是基于内存的,成本比较昂贵,因此不能滥用。


缓存可以分为:本地缓存和分布式缓存。


  • 本地缓存:主要指的是内存中的缓存机制。在Java中,Google Guava中就提供了本地缓存的实现机制。当然使用java的ConncurrentHashMap你也可以实现自己的本地缓存方案。

  • 分布式缓存:指的单独的缓存服务。几年前比较流行的是memcached,但其只是一个KV的存储,支持的数据结构太少。现在最为流行的就是Redis,能够支持丰富的数据结构,基于事件驱动的单线程非阻塞IO也能够应对高并发的场景。集群方案除了官方的redis cluster, 目前比较流行的还有豌豆荚的codis、twitter的twemproxy。


对于缓存的使用,需要注意以下几点:


  • 缓存的失效机制:当给某一个key设置了有效期,那么缓存何时对此key进行删除呢?一般来说会有以下几种方式:

  • 守护进程定时去扫描key,找到已经失效的key,然后删除

  • 读取key的时候先去判断key是否失效,如果失效则删除并返回空。

  • 缓存的淘汰机制:是当缓存内存达到上限时如何删除缓存中的key。Redis提供了以下数据淘汰策略:

  • volatile-lru:从已设置过期时间的数据集中挑选最近最少使用的数据淘汰

  • volatile-ttl:从已设置过期时间的数据集中挑选将要过期的数据淘汰

  • volatile-random:从已设置过期时间的数据集中任意选择数据淘汰

  • allkeys-lru:从数据集中挑选最近最少使用的数据淘汰

  • allkeys-random:从数据集中任意选择数据淘汰

  • no-enviction(驱逐):禁止驱逐数据


对于其具体的实现机制,可以参考《Redis设计与实现》一书


  • 缓存的更新机制: 通常来说有四种方式:Cache aside, Read through, Write through, Write behind caching,具体的可见陈皓大神的这篇总结:缓存更新的套路。

  • 缓存的服务过载保护:缓存的服务过载指的是由于缓存失效,而引起后端服务的压力骤增,进一步产生雪崩效应。这个现象和缓存更新是相关的,采取何种策略在缓存失效的时候去更新缓存直接决定了服务过载的保护机制。通常的分为客户端和服务端的应对方案。前者的方案有:基于超时的简单模式、基于超时的常规模式、基于刷新的简单模式、基于刷新的常规模式、基于刷新的续费模式。后者的方案则是很常见的流量控制和服务降级。具体的可以看美团技术团队总结的这篇文章:Cache应用中的服务过载案例研究。


数据库


数据库是后端开发中非常常见的一个服务组件。对于数据库的选型,要根据业务的特点和数据结构的特点来决定。


从存储介质上,数据库可以分为:


  • 内存数据库: 数据主要存储在内存中,同时也可以采取措施对数据进行持久化到硬盘中。如Redis、H2DB的内存模式。对于这种数据库,由于内存成本昂贵,因此一定要做好存储的量化分析、容量预估,防止内存不足造成服务不可用。

  • 硬盘数据库:数据存储在硬盘上的这种数据库是最为常见的。MySQL、Oracle、Postgresql、HBASE、H2DB、SqlLite等等都是硬盘数据库。此外,SSDB是基于SSD硬盘的KV数据库,支持的数据接口很丰富,是Redis的另外一个选择。


从存储数据类型、数据模式上,数据库可以分为:


  • 关系型数据库:MySQL、Oracle、Postgresql都是关系型数据库的,是采用关系模型(关系模型指的就是二维表格模型,而一个关系型数据库就是由二维表及其之间的联系所组成的一个数据组织)来组织数据的数据库。

  • 非关系型数据库:非关系型数据库是相对关系型数据库来讲的。以键值对存储,且结构不固定,每一个元组可以有不一样的字段,每个元组可以根据需要增加一些自己的键值对,这样就不会局限于固定的结构,可以减少一些时间和空间的开销。但是,其没有关系型数据库那种严格的数据模式,并不适合复杂的查询以及需要强事务管理的业务。非关系型数据库又可以分为:

  • KV数据库:主要以(key,value)键值对存储数据的数据库。以Redis、RocksDB(levelDB)、SSDB为代表。

  • 文档数据库:总体形式上也是键值对的形式,但是值里面又可以有各种数据结构:数组、键值对、字符串等等。以mongodb、couchdb为代表。

  • 列数据库:也叫作稀疏大数据库,一般是用来存储海量数据的。相对于行数据库,这种数据库是以列为单位存储数据在介质上的。以Hbase、Cassendra为代表。


和数据库相关的一个很重要的就是数据库的索引。有一种说法是:“掌握了索引就等于掌握了数据库”。暂且不去评判此说法是否真的准确,但索引的确关系着数据库的读写性能。需要对数据库的索引原理做到足够的了解才能更好的使用各种数据库。通常来说,Mysql、Oracle、Mongodb这些都是使用的B树作为索引,是考虑到传统硬盘的特点后兼顾了读写性能以及范围查找需求的选择,而Hbase用得LSM则是为了提高写性能对读性能做了牺牲。


搜索引擎


搜索引擎也是后端应用中一个很关键的组件,尤其是对内容类、电商类的应用,通过关键词、关键字搜索内容、商品是一个很常见的用户场景。比较成熟的开源搜索引擎有Solr和Elasticsearch,很多中小型互联网公司搜索引擎都是基于这两个开源系统搭建的。它们都是基于Lucence来实现的,不同之处主要在于termIndex的存储、分布式架构的支持等等。


对于搜索引擎的使用,从系统熟悉、服务搭建、功能定制,需要花费较长时间。在这个过程中,需要注意以下问题:


  • 搜索引擎与公司现有数据系统的集成。现有的持久化、供搜索的数据的载体是什么, 如何让搜索引擎在全量和增量建索引过程中无缝集成原来的数据载体,才能发挥搜索引擎自身的实时性, 水平扩展性(性能与容量和机器数量成正比)等优势。

  • 和数据库一样,对搜索引擎的索引机制也需要做到深入的了解。


更为详细的对于搜索引擎的工程化实践可以参考有zan工程师的这篇文章:有zan搜索引擎实践(工程篇)


另外,搜索引擎还可以用在数据的多维分析上,就是GrowingIO、MixPanel中的可以任意维度查询数据报表的功能。当然,druid也许是一个更好的实现多维分析的方案,官方也有其与es的比较:http://druid.io/docs/latest/comparisons/druid-vs-elasticsearch.html。


消息队列


软件的组织结构,从开始的面向组件到SOA、SAAS是一个逐渐演变的过程。而到了今天微服务盛行的时代,你都不好意思说自己的系统只是单一的一个系统而没有解耦成一个个service。当然,小的系统的确没有拆分的必要性,但一个复杂的系统拆成一个个service做微服务架构确实是不得不做的事情。


那么问题就来了,service之间的通信如何来做呢?使用什么协议?通过什么方式调用?都是需要考虑的问题。


先抛开协议不谈,service之间的调用方式可以分为同步调用以及异步调用。同步调用的方式无需多说,那么异步调用是怎么进行的呢?一种很常见的方式就是使用消息队列,调用方把请求放到队列中即可返回,然后等待服务提供方去队列中去获取请求进行处理,然后把结果返回给调用方即可(可以通过回调)。


异步调用就是消息中间件一个非常常见的应用场景。此外,消息队列的应用场景还有以下:


  • 解耦:一个事务,只关心核心的流程,需要依赖其他系统但不那么重要的事情,有通知即可,无须等待结果。

  • 最终一致性:指的是两个系统的状态保持一致,要么都成功,要么都失败,可以有一定的延迟,只要最终达到一致性即可。

  • 广播:这是消息队列最基本的功能。生产者只需要发布消息,无须关心有哪些订阅者来消费消息。

  • 错峰与流控:当上下游系统处理能力不同的时候就需要类似消息队列的方式做为缓冲区来隔开两个系统。


目前主流的消息队列软件,主要有以下几种:


  • ActiveMQ:Java中最为简单的消息队列,是对JMS的实现,没有规定消息的顺序、安全、重发等特性。

  • RabbitMQ:是对AMQP协议的实现,对于消息的顺序性、安全、重发等都做了很好的支持。比较适合不允许数据丢失、有事务需求的业务场景下的消息传输。

  • Kafka:是基于Log的消息队列,底层依赖于文件的顺序读取,是append-only的。适合对数据丢失不敏感、强调性能的一些海量日志传输场景中。是最近几年大数据领域很火的一个技术。

  • ZeroMQ:是一个网络编程的Pattern库,将常见的网络请求形式(分组管理,链接管理,发布订阅等)模式化、组件化,简而言之socket之上、MQ之下。对于MQ来说,网络传输只是它的一部分,更多需要处理的是消息存储、路由、Broker服务发现和查找、事务、消费模式(ack、重投等)、集群服务等。


文件存储


不管是业务应用、依赖的后端服务还是其他的各种服务,最终还是要依赖于底层文件存储的。通常来说,文件存储需要满足的特性有:可靠性、容灾性、稳定性,即要保证存储的数据不会轻易丢失,即使发生故障也能够有回滚方案,也要保证高可用率。在底层可以采用传统的RAID作为解决方案,再上一层,目前hadoop的hdfs则是最为普遍的分布式文件存储方案,当然还有NFS、Samba这种共享文件系统也提供了简单的分布式存储的特性。


此外,如果文件存储确实成为了应用的瓶颈或者必须提高文件存储的性能从而提升整个系统的性能时,那么最为直接和简单的做法就是抛弃传统机械硬盘,用SSD硬盘替代。像现在很多公司在解决业务性能问题的时候,最终的关键点往往就是SSD。这也是用钱换取时间和人力成本最直接和最有效的方式。在数据库部分描述的SSDB就是对LevelDB封装之后,利用SSDB的特性的一种高性能KV数据库。


至于HDFS,如果要使用上面的数据,是需要通过hadoop的。类似xx on yarn的一些技术就是将非hadoop技术跑在hdfs上的解决方案(当然也是为了使用MR)。


统一认证中心


统一认证中心,主要是对app用户、内部用户、app等的认证服务,包括


    声明:文章版权归原作者所有 部分文章转自互联网 如有侵权请联系 [邮箱地址] 删除

    路过

    雷人

    握手

    鲜花

    鸡蛋

    相关分类

    返回顶部