Category Archives: Web

基于SpringCloud的微服务架构演变史?

导读
一段时期以来 “微服务架构 ”一直是一个热门词汇,各种技术类公众号或架构分享会议上,关于微服务架构的讨论和主题也都非常多。对于大部分初创互联网公司来说,早期的单体应用结构才是最合适的选择,只有当业务进入快速发展期,在系统压力、业务复杂度以及人员扩展速度都快速上升的情况下,如何快速、稳妥有序的将整个互联网软件系统升级成微服务架构,以满足业务发展需要及技术组织的重新塑造,才是进行微服务架构的最主要的动力,否则空谈微服务架构是没有意义的。

而一旦决定将整个应用体系按照微服务架构体系进行升级,就需要有组织有计划的进行业务系统、基础架构、运维体系等多个方面的升级配套。而另一个比较尴尬的现实是,一般业务发展进入到需要进行微服务架构层面的时候,业务发展往往又都是非常迅猛的,这种业务快速发展和增长的压力往往又会给整个技术团队带来非常大的挑战,因为此时你需要取舍,是简单方案快速支撑呢?还是选择适当长远一点的方案?当然这种情况大部分是技术细节方面的问题,掌控的“度”大部分情况是掌握在具体的工程师手中。

而如何整体上确保应用体系及组织结构向微服务时代快速、有序的跨越,是一件十分考验团队能力以及架构管理水平的事。能做到80分已然算优秀了,因为这是有其客观规律的!

作者自身亲历了一个快速发展的互联网公司从单体应用~以SpringCloud为技术栈的微服务架构体系的全过程。本文将主要从技术角度与大家探讨如何利用SpringCloud进行微服务架构拆分,以及在这个过程中一点自己的思考。水平有限,不足之处还请包涵!
系统架构演变概述


在公司业务初创时期,面对的主要问题是如何将一个想法变成实际的软件实现,在这个时候整个软件系统的架构并没有搞得那么复杂,为了快速迭代,整个软件系统就是由“App+后台服务”组成,而后台服务也只是从工程角度将应用进行Jar包的拆分。此时软件系统架构如下:

而此时整个软件系统的功能也比较简单,只有基本的用户、订单、支付等功能,并且由于业务流程没有那么复杂,这些功能基本耦合在一起。而随着App的受欢迎程度(作者所在的公司正好处于互联网热点),所以App下载量在2017年迅猛增长,在线注册人数此时也是蹭蹭往上涨。

随着流量的迅猛增长,此时整个后台服务的压力变得非常大,为了抗住压力只能不断的加机器,平行扩展后台服务节点。此时的部署架构如下:

通过这种方式,整个软件系统抗住了一波压力,然而系统往往还是会偶尔出点事故,特别是因为api中的某个接口性能问题导致整个服务不可用,因为这些接口都在一个JVM进程中,虽然此时部署了多个节点,但因为底层数据库、缓存系统都是一套,所以还是会出现一挂全挂的情况。

另一方面,随着业务的快速发展,以往相对简单的功能变得复杂起来,这些功能除了有用户看得见的、也会包括很多用户看不见的,就好像百度搜索,用户能看见的可能只是一个搜索框,但是实际上后台对应的服务可能是成百上千,如有些增长策略相关的功能:红包、分享拉新等。还有些如广告推荐相关的变现功能等。

此外,流量/业务的增长也意味着团队人数的迅速增长,如果此时大家开发各自的业务功能还是用一套服务代码,很难想象百十来号人,在同一个工程在叠加功能会是一个什么样的场景。所以如何划分业务边界、合理的进行团队配置也是一件十分迫切的事情了!

为了解决上述问题,适应业务、团队发展,架构团队决定进行微服务拆分。而要实施微服务架构,除了需要合理的划分业务模块边界外,也需要一整套完整的技术解决方案。

在技术方案的选择上,服务拆分治理的框架也是有很多,早期的有如WebService,近期的则有各种Rpc框架(如Dubbo、Thirft、Grpc)。而Spring Cloud则是基于Springboot提供的一整套微服务解决方案,因为技术栈比较新,并且各类组件的支撑也非常全面,所以Spring Cloud就成为了首选。

经过一系列的重构+扩展,整个系统架构最终形成了以app为中心的一套微服务软件系统,结构如下:

到这里,整个软件系统就基于SpringCloud初步完成了微服务体系的拆分。支付、订单、用户、广告等核心功能抽离成独立的微服务,与此同时各自微服务对应的数据库也按照服务边界进行了拆分。

在完成服务的拆分以后,原来功能逻辑之间的代码调用关系,转换成了服务间网络的调用关系,而各个微服务需要根据各自所承载的功能提供相应的服务,此时服务如何被其他服务发现并调用,就成了整个微服务体系中比较关键的部分,使用过Dubbo框架的同学知道,在Dubbo中服务的注册&发现是依赖于Zookeeper实现的,而在SpringCloud中我们是通过Consul来实现。另外在基于SpringCloud的架构体系中,提供了配置中心(ConfigServer)来帮助各个微服务管理配置文件,而原本的api服务,随着各个功能的抽离,逐步演变成前置网关服务了。

聊到这里,基于SpringCloud我们进行了微服务拆分,而在这个体系结构中,分别提到了Consul、ConfigServer、网关服务这几个关键组件,那么这几个关键组件具体是如何支撑这个庞大的服务体系的呢?

SpringCloud关键组件

Consul

Consul是一个开源的,使用go语言开发的注册中心服务。它里面内置了服务发现与注册框架、分布一致性协议实现、健康检查、Key/Value存储、多数据中心等多个方案。在SpringCloud框架中还可以选择Eurke作为注册中心,这里之所以选择Consul主要原因在于Consul对异构的服务的支持,如:grpc服务。

事实上,在后续的系统架构演进中,在某些服务模块进一步向子系统化拆分的过程中,就采用了grpc作为子系统服务间的调用方式。例如,支付模块的继续扩张,对支付服务本身又进行了微服务架构的拆分,此时支付微服务内部就采用了grpc的方式进行调用,而服务注册与发现本身则还是依赖于同一套Consul集群。

此时的系统架构演进如下:

原有微服务架构中的模块服务在规模达到一定程度或复杂性达到一定程度后,都会朝着独立的体系发展,从而将整个微服务的调用链路变的非常长,而从Consul的角度看,所有的服务又都是扁平的。

随着微服务规模的越来越大,Consul作为整个体系的核心服务组件,在整个体系中处于关键的位置,一旦Consul挂掉,所有的服务都将停止服务。那么Consul到底是什么样服务?其容灾机制又该如何设计呢?

要保证Consul服务的高可用,在生产环境Consul应该是一个集群(关于Consul集群的安装与配置可以参考网络资料),这是毫无疑问的。而在Consul集群中,存在两种角色:Server、Client,这两种角色与Consul集群上运行的应用服务并没有什么关系,只是基于Consul层面的一种角色划分。实际上,维持整个Consul集群状态信息的还是Server节点,与Dubbo中使用Zookeeper实现注册中心一样,Consul集群中的各个Server节点也需要通过选举的方式(使用GOSSIP协议、Raft一致性算法,这里不做详细展开,在后面的文章中可以和大家单独讨论)来选举整个集群中的Leader节点来负责处理所有查询和事务,并向其他节点同步状态信息。

Client角色则是相对无状态的,只是简单的代理转发RPC请求到Server节点,之所以存在Client节点主要是分担Server节点的压力,作一层缓冲而已,这主要是因为Server节点的数量不宜过多,因为Server节点越多也就意味着达成共识的过程越慢,节点间同步的代价也就越高。对于Server节点,一般建议3-5台,而Client节点则没有数量的限制,可以根据实际情况部署数千或数万台。事实上,这也只是一种策略,在现实的生产环境中,大部分应用只需要设置3~5台Server节点就够了,作者所在的公司一套生产集群中的Consul集群的节点配置就是5个Server节点,并没有额外再设置Client节点。

另外,在Consul集群中还有一个概念是Agent,事实上每个Server或Client都是一个consul agent,它是运行在Consul集群中每个成员上的一个守护进程,主要的作用是运行DNS或HTTP接口,并负责运行时检查和保持服务信息同步。我们在启动Consul集群的节点(Server或Client)时,都是通过consul agent的方式启动的。例如:

consul agent -server -bootstrap -syslog \
-ui \
-data-dir=/opt/consul/data \
-dns-port=53
-recursor=10.211.55.3
-config-dir=/opt/consul/conf
 \
-pid-file=/opt/consul/run/consul.pid \
-client=10.211.55.4 \
-bind=10.211.55.4 \
-node=consul-server01 \
-disable-host-node-id &

以实际的生产环境为例,Consul集群的部署结构示意图如下:

实际生产案例中并没有设置Client节点,而是通过5个Consul Server节点组成的集群,来服务整套生产集群的应用注册&发现。这里有细节需要了解下,实际上5个Consul Server节点的IP地址是不一样的,具体的服务在连接Consul集群进行服务注册与查询时应该连接Leader节点的IP,而问题是,如果Leader节点挂掉了,相应的应用服务节点,此时如何连接通过Raft选举产生的新Leader节点呢?难道手工切换IP不成?

显然手工切换IP的方式并不靠谱,而在生产实践中,Consul集群的各个节点实际上是在Consul Agent上运行DNS(如启动参数中红色字体部分),应用服务在连接Consul集群时的IP地址为DNS的IP,DNS会将地址解析映射到Leader节点对应的IP上,如果Leader节点挂掉,选举产生的新Leader节点会将自己的IP通知DNS服务,DNS更新映射关系,这一过程对各应用服务则是透明的。

通过以上分析,Consul是通过集群设计、Raft选举算法,Gossip协议等机制来确保Consul服务的稳定与高可用的。如果需要更高的容灾级别,也可以通过设计双数据中心的方式,来异地搭建两个Consul数据中心,组成一个异地灾备Consul服务集群,只是这样成本会更高,这就看具体是否真的需要了。

ConfigServer(配置中心)

配置中心是对微服务应用配置进行管理的服务,例如数据库的配置、某些外部接口地址的配置等等。在SpringCloud中ConfigServer是独立的服务组件,它与Consul一样也是整个微服务体系中比较关键的一个组件,所有的微服务应用都需要通过调用其服务,从而获取应用所需的配置信息。

随着微服务应用规模的扩大,整个ConfigServer节点的访问压力也会逐步增加,与此同时,各个微服务的各类配置也会越来越多,如何管理好这些配置文件以及它们的更新策略(确保不因生产配置随意改动而造成线上故障风险),以及搭建高可用的ConfigServer集群,也是确保微服务体系稳定很重要的一个方面。

在生产实践中,因为像Consul、ConfigServer这样的关键组件,需要搭建独立的集群,并且部署在物理机而不是容器里。在上一节介绍Consul的时候,我们是独立搭建了5个Consul Server节点。而ConfigServer因为主要是http配置文件访问服务,不涉及节点选举、一致性同步这样的操作,所以还是按照传统的方式搭建高可用配置中心。具体结构示意图如下:

我们可以单独通过git来管理应用配置文件,正常来说由ConfigSeever直接通过网络拉取git仓库的配置供服务获取就可以了,这样只要git仓库配置更新,配置中心就能立刻感知到。但是这样做的不稳定之处,就在于git本身是内网开发用的代码管理工具,如果让线上实时服务直接读取,很容易将git仓库拉挂了,所以,我们在实际的运维过程中,是通过git进行配置文件的版本控制,区分线上分支/master与功能开发分支/feature,并且在完成mr后还需要手工(通过发布平台触发)同步一遍配置,过程是将新的master分支的配置同步一份到各个configserver节点所在主机的本地路径,这样configserver服务节点就可以通过其本地目录获取配置文件,而不用多次调用网络获取配置文件了。

而另一方面,随着微服务越来越多,git仓库中的配置文件数量也会越来越多。为了便于配置的管理,我们需要按照一定的组织方式来组织不同应用类型的配置。在早期所有的应用因为没有分类,所以导致上百个微服务的配置文件放在一个仓库目录,这样一来导致配置文件管理成本增加,另外一方面也会影响ConfigServer的性能,因为某个微服务用不到的配置也会被ConfigServer加载。

所以后期的实践是,按照配置的层次关系进行组织,将公司全局的项目配置抽象到顶层,由ConfigServer默认加载,而其他所有的微服务则按照应用类型进行分组(通过git项目空间的方式分组),相同的应用放在一个组,然后这个组下单独设立一个名为config的git仓库来存放这个组下相关微服务的配置文件。层次结构如下:

这样应用加载配置的优先级就是“本地配置->common配置->组公共配置->项目配置”这样的顺序。例如某服务A,在项目工程的默认配置文件(“bootstrap.yml/application.yml”)中配置了参数A,同时也在本地项目配置“application-production.yml”配置了参数B,而与此同时,ConfigServer中的common仓库下的配置文件“application.yml/application-production.yml”又分别存在参数C、参数D,同时有个组叫“pay”,其下的默认配置文件“application.yml/application-production.yml”存在参数E、参数F,具体项目pay-api又存在配置文件“pay-api-production.yml”其覆盖了common仓库中参数C、参数D的值。那么此时如果该应用以“spring.profiles.active=production”的方式启动,那么其能获取到的配置参数(通过链接访问:http://{spring.cloud.config.uri}/pay-api-production.yml)就是A、B、C、D、E、F,其中C、D的参数值为pay-api-production.yml中最后覆盖的值。

而对于ConfigServer服务本身来说,需要按照这样的组织方式进行配置类型匹配,例如上述的例子中,假设还存在finance的配置仓库,而pay组下的服务访问配置中心的时候,是不需要finance空间下的配置文件的,所以ConfigServer可以不用加载。这里就需要在ConfigServer服务配置中进行一些配置。具体如下:

spring:
  application:
    name: @project.artifactId@
    version: @project.version@
    build: @buildNumber@
    branch: @scmBranch@
  cloud:
    inetutils:
      ignoredInterfaces:
        - docker0
    config:
      server:
        health.enabled: false
        git:
          uri: /opt/repos/config
          searchPaths: 'common,{application}'
          cloneOnStart: true
          repos:
            pay:
                pattern: pay-*
                cloneOnStart: true
                uri: /opt/repos/example/config
                searchPaths: 'common,{application}'
            finance:
                pattern: finance-*
                cloneOnStart: true
                uri: /opt/repos/finance/config
                searchPaths: 'common,{application}'

通过在ConfigServer服务本身的application.yml本地配置中,设置其配置搜索方式,来实现这样的目的。

网关服务&服务熔断&监控

通过上面两小节的内容,我们相对详细地介绍了基于SpringCloud体系中比较关键的两个服务组件。然而在微服务架构体系中,还有很多关键的问题需要解决,例如,应用服务在Consul中部署了多个节点,那么调用方如何实现负载均衡?

关于这个问题,在传统的架构方案中是通过Nginx实现的,但是在前面介绍Consul的时候只提到了Consul的服务注册&发现、选举等机制,并没有提到Consul如何在实现服务调用的负载均衡。难道基于SpringCloud的微服务体系中的应用服务都是单节点在提供服务,哪怕即使部署了多个服务节点?事实上,我们在服务消费方通过@EnableFeignClients注解开启调用,通过@FeignClient(“user”)注解进行服务调用时,就已经实现了负载均衡,为什么呢?因为,这个注解默认是会默认开启Robbin代理的,而Robbin是实现客户端负载均衡的一个组件,通过从Consul拉取服务节点信息,从而以轮询的方式转发客户端调用请求至不同的服务端节点来实现负载均衡。而这一切都是在消费端的进程内部通过代码的方式实现的。这种负载方式寄宿于消费端应用服务上,对消费端存在一定的代码侵入性,这是为什么后面会出现Service Mesh(服务网格)概念的原因之一,这里就不展开了,后面有机会再和大家交流。

另一需要解决的关键问题是服务熔断、限流等机制的实现,SpringCloud通过集成Netflix的Hystrix框架来提供这种机制的支持,与负载均衡机制一样也是在消费端实现。由于篇幅的关系,这里也不展开了,在后面的文章中有机会再和大家交流。

此外还有Zuul组件来实现API网关服务,提供路由分发与过滤相关的功能。而其他辅助组件还有诸如Sleuth来实现分布式链路追踪、Bus实现消息总线、Dashboard实现监控仪表盘等。由于SpringCloud的开源社区比较活跃,还有很多新的组件在不断的被集成进来,感兴趣的朋友可以持续关注下!

微服务之运维形态

在微服务体系结构下,随着服务数量大量的增长,线上的部署&维护的工作量会变得非常大,而如果还采用原有的运维模式的话,就能难满足需要了。此时运维团队需要实施Devops策略,开发自动化运维发布平台,打通产品、开发、测试、运维流程,关注研发效能。

另外一方面也需要推进容器化(Docker/Docker Swarm/k8s)策略,这样才能快速对服务节点进行伸缩,这也是微服务体系下的必然要求。

微服务泛滥问题

这里还需要注意一个问题,就是实施微服务架构后,如何在工程上管控微服务的问题。盲目的进行微服务的拆分也不是一件很合理的事情,因为这会导致整个服务调用链路变得深不可测,对问题排查造成难度,也浪费线上资源。

重构问题

在早期单体架构方式向微服务架构的转变过程中,重构是一个非常好的方式,也是确保服务规范化,业务系统应用架构合理化的很重要的手段。但是,一般来说,在快速发展阶段也就意味着团队规模的迅速增长,短时间内如何让新的团队有事可做也是一件非常考验管理水平的事情,因为如果招了很多人,并且他们之间呈现一种过渡的竞争状态的话,就会出现让重构这件事变得有些功利的情况,从而导致重构不彻底、避重就轻,导致表象上看是很高大上的微服务架构,而业务系统实际上比较烂的情况。

另外,重构是在一定阶段后作出的重要决策,不仅仅是重新拆分,也是对业务系统的重新塑造,所以一定要考虑好应用软件的系统结构以及实施它们所需要付出的成本,切不可盲目!

后记

基于SpringCloud的微服务架构体系,通过集成各种开源组件来为整个体系服务支持,但是在负载均衡、熔断、流量控制的方面需要对服务消费端的业务进程进行侵入。所以很多人会认为这不是一件很好的事情,于是出现了Service Mesh(服务网格)的概念,Service Mesh的基本思路就是通过主机独立Proxy进行的部署来解耦业务系统进程,这个Proxy除了负责服务发现和负载均衡(不在需要单独的注册组件,如Consul)外,还负责动态路由、容错限流、监控度量和安全日志等功能。

而在具体的服务组件上目前主要是 Google/IBM 等大厂支持和推进的一个叫做Istio的ServiceMesh 标准化工作组。具体关于Service Mesh的知识,在后面的内容中再和大家交流。以上就是本文的全部内容,由于作者水平有限,还请多多包涵!

from:https://mp.weixin.qq.com/s/NHVJCmVUXcAb_pAXxT8mHA

HTTP 的前世今生

作为互联网通信协议的一员老将,HTTP 协议走到今天已经经历了三次版本的变动,现在最新的版本是 HTTP2.0,相信大家早已耳熟能详。今天就给大家好好介绍一下 HTTP 的前世今生。

HTTP/0.9

HTTP 的最早版本诞生在 1991 年,这个最早版本和现在比起来极其简单,没有 HTTP 头,没有状态码,甚至版本号也没有,后来它的版本号才被定为 0.9 来和其他版本的 HTTP 区分。HTTP/0.9 只支持一种方法—— Get,请求只有一行。

  1. GET /hello.html

响应也是非常简单的,只包含 html 文档本身。

  1. <HTML>
  2. Hello world
  3. </HTML>

当 TCP 建立连接之后,服务器向客户端返回 HTML 格式的字符串。发送完毕后,就关闭 TCP 连接。由于没有状态码和错误代码,如果服务器处理的时候发生错误,只会传回一个特殊的包含问题描述信息的 HTML 文件。这就是最早的 HTTP/0.9 版本。

HTTP/1.0

1996 年,HTTP/1.0 版本发布,大大丰富了 HTTP 的传输内容,除了文字,还可以发送图片、视频等,这为互联网的发展奠定了基础。相比 HTTP/0.9,HTTP/1.0 主要有如下特性:

  •  请求与响应支持 HTTP 头,增加了状态码,响应对象的一开始是一个响应状态行
  •  协议版本信息需要随着请求一起发送,支持 HEAD,POST 方法
  •  支持传输 HTML 文件以外其他类型的内容

一个典型的 HTTP/1.0 的请求像这样:

  1. GET /hello.html HTTP/1.0
  2. User-Agent:NCSA_Mosaic/2.0(Windows3.1)
  3. 200 OK
  4. Date: Tue, 15 Nov 1996 08:12:31 GMT
  5. Server: CERN/3.0 libwww/2.17
  6. Content-Type: text/html
  7. <HTML>
  8. 一个包含图片的页面
  9. <IMGSRCIMGSRC=“/smile.gif”>
  10. </HTML>

HTTP/1.1

在 HTTP/1.0 发布几个月后,HTTP/1.1 就发布了。HTTP/1.1 更多的是作为对 HTTP/1.0 的完善,在 HTTP1.1 中,主要具有如下改进:

  •  可以复用连接
  •  增加 pipeline:HTTP 管线化是将多个 HTTP 请求整批提交的技术,而在传送过程中不需先等待服务端的回应。管线化机制须通过永久连接(persistent connection)完成。浏览器将HTTP请求大批提交可大幅缩短页面的加载时间,特别是在传输延迟(lag/latency)较高的情况下。有一点需要注意的是,只有幂等的请求可以使用 pipeline,如 GET,HEAD 方法。
  •  chunked 编码传输:该编码将实体分块传送并逐块标明长度,直到长度为 0 块表示传输结束, 这在实体长度未知时特别有用(比如由数据库动态产生的数据)
  •  引入更多缓存控制机制:如 etag,cache-control
  •  引入内容协商机制,包括语言,编码,类型等,并允许客户端和服务器之间约定以最合适的内容进行交换
  •  请求消息和响应消息都支持 Host 头域:在 HTTP1.0 中认为每台服务器都绑定一个唯一的 IP 地址,因此,请求消息中的URL并没有传递主机名(hostname)。但随着虚拟主机技术的发展,在一台物理服务器上可以存在多个虚拟主机(Multi-homed Web Servers),并且它们共享一个 IP 地址。因此,Host 头的引入就很有必要了。
  •   新增了 OPTIONS,PUT, DELETE, TRACE, CONNECT 方法

虽然 HTTP/1.1 已经优化了很多点,作为一个目前使用最广泛的协议版本,已经能够满足很多网络需求,但是随着网页变得越来越复杂,甚至演变成为独立的应用,HTTP/1.1 逐渐暴露出了一些问题:

  •  在传输数据时,每次都要重新建立连接,对移动端特别不友好
  •  传输内容是明文,不够安全
  •  header 内容过大,每次请求 header 变化不大,造成浪费
  •  keep-alive 给服务端带来性能压力

为了解决这些问题,HTTPS 和 SPDY 应运而生。

HTTPS

HTTPS 是以安全为目标的 HTTP 通道,简单讲是 HTTP 的安全版,即 HTTP 下加入 SSL 层,HTTPS 的安全基础是 SSL,因此加密的详细内容就需要 SSL。

HTTPS 协议的主要作用可以分为两种:一种是建立一个信息安全通道,来保证数据传输的安全;另一种就是确认网站的真实性。

HTTPS 和 HTTP 的区别主要如下:

  •  HTTPS 协议使用 ca 申请证书,由于免费证书较少,需要一定费用。
  •  HTTP 是明文传输,HTTPS 则是具有安全性的 SSL 加密传输协议。
  • HTTP 和 HTTPS使用的是完全不同的连接方式,用的端口也不一样,前者是 80,后者是 443。

SPDY

其实 SPDY 并不是新的一种协议,而是在 HTTP 之前做了一层会话层。

在 2010 年到 2015 年,谷歌通过实践一个实验性的 SPDY 协议,证明了一个在客户端和服务器端交换数据的另类方式。其收集了浏览器和服务器端的开发者的焦点问题,明确了响应数量的增加和解决复杂的数据传输。在启动 SPDY 这个项目时预设的目标是:

  •  页面加载时间 (PLT) 减少 50%。
  •  无需网站作者修改任何内容。
  •  将部署复杂性降至最低,无需变更网络基础设施。
  •  与开源社区合作开发这个新协议。
  •  收集真实性能数据,验证这个实验性协议是否有效。

为了达到降低目标,减少页面加载时间的目标,SPDY 引入了一个新的二进制分帧数据层,以实现多向请求和响应、优先次序、最小化及消除不必要的网络延迟,目的是更有效地利用底层 TCP 连接。

HTTP/2.0

时间来到 2015 年,HTTP/2.0 问世。先来介绍一下 HTTP/2.0 的特点吧:

  •  使用二进制分帧层:在应用层与传输层之间增加一个二进制分帧层,以此达到在不改动 HTTP 的语义,HTTP 方法、状态码、URI 及首部字段的情况下,突破HTTP1.1 的性能限制,改进传输性能,实现低延迟和高吞吐量。在二进制分帧层上,HTTP2.0 会将所有传输的信息分割为更小的消息和帧,并对它们采用二进制格式的编码,其中 HTTP1.x 的首部信息会被封装到 Headers 帧,而我们的 request body 则封装到 Data 帧里面。

  •  多路复用:对于 HTTP/1.x,即使开启了长连接,请求的发送也是串行发送的,在带宽足够的情况下,对带宽的利用率不够,HTTP/2.0 采用了多路复用的方式,可以并行发送多个请求,提高对带宽的利用率。

  •  数据流优先级:由于请求可以并发发送了,那么如果出现了浏览器在等待关键的 CSS 或者 JS 文件完成对页面的渲染时,服务器却在专注的发送图片资源的情况怎么办呢?HTTP/2.0 对数据流可以设置优先值,这个优先值决定了客户端和服务端处理不同的流采用不同的优先级策略。
  •  服务端推送:在 HTTP/2.0 中,服务器可以向客户发送请求之外的内容,比如正在请求一个页面时,服务器会把页面相关的 logo,CSS 等文件直接推送到客户端,而不会等到请求来的时候再发送,因为服务器认为客户端会用到这些东西。这相当于在一个 HTML 文档内集合了所有的资源。
  •  头部压缩:使用首部表来跟踪和存储之前发送的键值对,对于相同的内容,不会再每次请求和响应时发送。

可以看到 HTTP/2.0 的新特点和 SPDY 很相似,其实 HTTP/2.0 本来就是基于 SPDY 设计的,可以说是 SPDY 的升级版。

但是 HTTP/2.0 仍有和 SPDY 不同的地方,主要有如下两点:

  •  HTTP2.0 支持明文 HTTP 传输,而 SPDY 强制使用 HTTPS。
  •  HTTP2.0 消息头的压缩算法采用 HPACK,而非 SPDY 采用的 DEFLATE。

from:http://developer.51cto.com/art/201811/586932.htm

微信小程序开发资源汇总

QQ交流群

目录

推荐

置顶

官方文档

工具

  • WePY ★12k+ – 支持组件化的小程序开发框架
  • mpvue ★11k+ – 基于 Vue.js 的小程序开发框架,从底层支持 Vue.js 语法和构建工具体系
  • Taro ★3.9k – 使用 React 的方式开发小程序的框架,同时支持生成多端应用
  • Labrador ★1.5k – 支持 ES6/7 的微信小程序组件化开发框架
  • wept ★1.8k – 微信小程序实时运行环境
  • wafer ★1.6k – 快速构建具备弹性能力的微信小程序
  • wechat_web_devtools ★600+ – Linux 下微信开发者工具
  • minapp ★400+ – TypeScript 版小程序开发框架(兼容原生小程序代码)
  • tina ★300+ – 轻巧的渐进式微信小程序框架
  • xpmjs ★100+ – 微信小程序云端增强 SDK
  • WeApp-Workflow ★100+ – 基于 Gulp 的微信小程序前端开发工作流
  • gulp-wxa-copy-npm – 微信小程序 gulp 插件,解决 npm 包管理和 babel-runtime
  • weact – 用 JSX 快速开发小程序
  • socket.io-mp-client – 微信小程序 socket.io 客户端
  • wxa – 方便的小程序开发框架
  • px2rpx – Px 转 Rpx 在线工具
  • wxml-parser – JavaScript WXML parser
  • weappx – 基于 redux 的数据层管理框架
  • weapp-start – 基于插件机制的开发脚手架,改善原生小程序开发体验
  • Egret Wing – 支持微信小程序实时预览的 IDE
  • wxapp-graphql – 小程序GraphQL客户端

插件

教程

视频教程

文章

组件

Demo

from:https://github.com/justjavac/awesome-wechat-weapp

中国互联网20年简史(1998-2018),告诉你本质是什么、规律是什么

我先说说互联网三大支柱:

1、内容:新闻&文学、音乐&视频

2、社区+内容

3、游戏

4、电子商务

我们来简单回顾一下中国互联网20年。咱们先从1998年开始。

一、1998年:内容门户元年

1998年2月,张朝阳正式成立搜狐。给中国产业带来了VC风险投资、CXO职业经理人团队,让中国老百姓认知了中国互联网。

1998年,四通利方和北美华人网华渊网合并,成立新浪网。给中国产业带来了并购、创始人被踢出团队。

1997年,网易成立。1998年推出网易免费电子邮件服务。

显然,这是内容门户之年。

虽然1998年腾讯也成立了,但显然大家都没注意到它。但最后四大门户是:搜狐、新浪、网易、腾讯。

还有一家公司成立,那就是在线网络游戏公司:联众,出自希望公司UCDOS软件团队。

你看,内容门户+BBS论坛社区+IM+游戏,在20年前,就同时出现了。中国互联网主航道,都基本出现。

二、1999年:电子商务元年

内容门户大热到极点。连联想都做了一个FM365。更别说还有中华网、TOM网、多来米这些富家子弟玩的。这些显然都是后知后觉了。

1999年11月,当当B2C成立,标品卖书,客单价也低,正好做启蒙。1999年,阿里巴巴B2B也成立了,搞黄页,帮助中国小商品制造出口走向国际。

1999年还成立了一家当时没人知道的公司:携程。

1999年还成立了一家公司:51job,网上找工作。其实招聘的本质是:黄页信息,只不过这个黄页不是企业信息,而是个人简历信息。

这是中国电子商务的开始。他们真是先知先觉。

三、2000年:内容门户上市年

网易、搜狐、新浪都在纳斯达克上市。这才短短3年时间。

2000年1月,百度成立。

四、2001年:移动手机元年

美国互联网投资泡沫破裂,也影响了中国。很多后来进入者都纷纷转型去开发企业软件,因为他们熟悉互联网、熟悉当时火热的Web开发技术和JAVA开发技术,所以他们一开始就做供应链互联网平台。当时中国企业软件商还在纷纷用VB/PB/DELPHI开发局域网企业内部管理软件呢。

但是在前几年互联网资本的推动下,基础设施:通信&数据传输网络也在迅猛发展。诺基亚在这一年市值逼近2500亿美金,中国出现国产手机热,以波导为代表,IT厂商联想也介入进来,家电厂商海尔也介入,电话座机厂商步步高(Vivo和Oppo的母公司)也介入。

五、2002年:移动手机内容SP元年

2002年,中国移动和中国联通的手机终于能短信互通了。好不容易2000年上市的三大门户都熬的受不了,想寻找到立刻变现的业务。

彩铃、短信报热。网易首先抓住这个机遇(嘿嘿,大家可以另外寻找网易和张静君和广州电信局的渊源)。中国互联网企业做SP业务开始了,尤其是把网上的新闻和段子通过短信传播。

六、2003年:网络游戏元年

2003年7月,盛大公司发布传奇世界游戏,引发了中国网络游戏热。随后,九城、完美时空、巨人等等公司跟进,造就了中国很多赚的盆满钵满的网络游戏公司。这个行当也给中国积累了大量的产品经理、制作人、美工人才、音效人才、3D技术、网络技术。

七、2004年:中国互联网第一波集中上市收割年

2004年,移动手机内容SP厂商:空中网、掌上灵通网,上市。

2004年,垂直金融内容门户公司:金融界,上市

2004年,社区+IM+游戏厂商腾讯上市。

2003年12月(相当于2004年了吧),中国电子商务第一个公司:携程,上市。携程。从1999年中国电子商务开始元年,到2003年,这才短短4年时间。

2004年,泛电商人才招聘网:51job上市。

2004年,网上卖机票电商网:E龙上市。

2004年,网络游戏厂商:盛大,上市。

从1998年算来,到2004年,6年时间,中国互联网开始了第一波收割热潮。

八、2005年:Web2.0社区内容元年

2005年,超女最火的一届出现:李宇春、张靓颖、何洁。大众用短信投票引爆全国。这是民众的、互动的狂欢。

2005年,新浪博客发布。

2005年3月,豆瓣成立。这是一个点评的网站。

2005年12月,58同城成立,这是一个个人黄页发布的网站。

额外,搜索引擎公司:百度,在这一年上市了。

七、2006年:网络视频内容元年

2006年,六间房视频网成立。2006年,李善友的酷六网成立。2006年,优酷网成立。2006年,Google并购Youtube网。

另外,2005年4月,土豆网成立。2005年,迅雷公司正式成立。2005年,VeryCD(电驴下载)公司正式成立。这都是和视频电影的崛起有关联的。

过去大家只能看文字图片内容网站,做图片钻展广告。现在有了更直观的视频网站,而且每部电影都可以贴片做广告了。

但是并不代表文字内容网站失落,相反,中国网络文学崛起,你看:2006年,天下霸唱开始写鬼吹灯引爆盗墓类小说、2006年当年明月开始写明朝那些事儿引爆写史类小说,2006年月关开始写回到明朝当王爷引爆穿越类小说。

2006年,其实还有一个大混战,就是楼宇广告大战。成立于2003年的分众传媒,2005年上市,2006年并购了聚众传媒、框架传媒。

八、2007年:电子商务高速成长年

2007年,阿里巴巴B2B业务在香港上市。

但是大家也别忘了,2007年8月,中关村一个经营了快10年的拥有11家线下店铺IT硬件批发零售商,融了一笔钱,开始关闭自己的线下店,专注高速发展线上电商自营零售,那就是京东。

2007年,Yes!PPG成立,主打自创品牌的男士商务休闲服装。2007年,模仿Yes!PPG的凡客诚品也成立了。这是中国自创品牌的电子商务公司,集:研发设计、供应链采购、委托加工、质量控制、商品电商零售、仓储物流配送于一体。

2007年,也是中国快捷酒店大战的一年。如家、汉庭、锦江之星、7天、莫泰、格林豪泰、布丁、桔子酒店…,好多好多。

悄悄另外说一句:2007年,iPhone上市了,大内存、高速CPU、高速WIFI网络、大屏幕、多点触摸输入操作,这几乎是和过去的智能手机有天壤差别:小内存、小屏幕、GPRS联网、笔触输入或键盘输入。中国移动互联网暗示着要大规模爆发了。

九、2008年:智能手机元年

2008年,是中国互联网的十周年。但是这一年也暗示着,中国PC Web互联网即将开始走向最高峰,最高峰也意味着下一个时代已经在悄然启动。

2008年,Google正式发行Android操作系统。

2008年,Apple发布iPhone3G手机,最最关键的是,智能手机的高利润盈利模式、流量口模式出现了:App Store。想想百度收购91,其实也想占领智能移动互联网的入口,没想到独立的应用商店根本不存在活路,全被智能手机厂商在底层釜底抽薪了,人家有小米应用商店、华为应用商店…,全是硬件+软件一体化的。

2008年,山寨手机热啊。在联发科一体化MTK模组的支持下,在华强北电子零件集散批发、深圳电子代工场云集的支撑下,中国人制造手机的门槛被放到最低。

十、2009年:交战年

2009年,新浪微博发布显然是最显眼的。随后,各大内容门户网站纷纷发布类微博产品服务。微博,120个字,类似短信使用体验却可以带图片(比短信好),可以关注名人还可以评论互动(不像QQ得双向关注),也可以随手转发。

除了微博这种类互联网手机上的多媒体短信产品大战,这一年整个互联网界都不平静。

淘宝发布购物搜索,屏蔽百度爬虫。当然,微软也发布了Bing搜索引擎来PKGoogle搜索引擎。

腾讯和搜狗针对输入法进行诉讼。因为输入法在用户需求探知、弹窗引流、输入汉字导流方面具有很高的入口杀伤力。

网络游戏《魔兽》的代理运营权,也在九城、网易之间拉锯。

还有2008年很火的基于QQ社交网络关系的页游:偷菜,开心网和千橡开心网也进行了诉讼。

为什么2009年如此不平静?就是因为PC Web互联网进入成熟期,产业要开始高度集中,要进行整合,不可避免要咔咔作响。

2009年,中国三大运营商均获得3G牌照,移动互联网眼看着眼看着要来临了。

十一、2010:电商爆发年

2010年大家最记忆犹新的肯定是百团大战,大量团购网站出现,尤其以2010年3月美团成立为标志。中国电子商务:衣食住行,衣,有淘宝;食开始了,就是这些团购网;住,有曾经的如家快捷酒店大战,也有58的租房二手房黄页广告聚焦房产行业大战;行,有过去的携程、E龙、同程、去哪儿大战。除了衣是实物零售业外,其他食住行都是服务电商业,即:在网上吸引消费者流量,在网上获得优惠折扣,在网上下订单,甚至在网上进行支付,然后在线下进行到场消费。

2010年,在衣这个事情上,还有一个轰动的事,那就是淘宝双十一热。但这已经其实是第二届了(第一届是2009年双11),但就如超女一样,也是第一届举办完了大部分人都不知道,第二届才引爆。双11对于淘宝的意义非常大。而京东,在2010年也迎来了爆发式增长:开放POP平台、一线城市极速达、收购网银在线介入金融业务。而且京东主动发起了图书大战,直指当当老大哥(当当可谓是中国互联网最早的电商零售)。还有一家发源于手册邮寄购买最终爆发于电商的服装零售公司:麦考林,也在2010年上市了,成为了第一家上市的电子商务零售公司(2007年阿里巴巴B2B业务上市。)

1999年,中国电商元年;2007年,中国电商成长年;2010年,中国电商爆发年。

当然,在PCWeb纯互联网领域,2010年也发生了一件非常大的事情,就好像两个黑洞碰撞一样巅峰对决,那就是3Q大战。2010年11月21日,在工信部、网信办的协调下,两个公司达成和解,不互相封杀卸载对方的软件。中国PC 互联网终于走到了尽头。就好像红巨星要爆炸要产生超新星是一样一样的。从1998年开始的PC Web互联网,走到了2008年智能手机元年,2009年互联网产业整合交战,最终在2010年3Q大战最高巅峰对决中收场。

再想想中国移动互联网,2008年是智能手机元年,今年是2018年,也十年了,今年的大战是腾讯集团和今日头条的大战。相信到2020年,也会如超新星一样,那时候是什么互联网呢?已经有了ADSL宽带PC Web 互联网和4G 移动 App互联网,难道那时候在5G的引导下,会出现万物互联网?

4G移动App互联网,以移动智能手机为主产业,那5G万物互联网,什么是主产产业呢?难道是智能汽车?

十二、2011:中国移动互联网元年

这一年,有两个重要级产品出现,一个是智能手机:小米和MIUI OS出现,一个是原生移动IM:微信出现。

智能手机硬件、Andriod操作系统、应用商店、IM通信,这种组合层次颇值得人寻味。在万物互联网时代会不会出现的最初超级应用也是这样?

其实早在2G GPRS时代,在2008年,手机QQ已经很多人使用了,但是微信出现了,手机QQ没落了。微信的出现正好和iPhone成为智能手机事实标准是同步的。从iPhone开始,过去手机是五花八门各种样子各种功能,尤其在山寨手机之时到达最高潮,然后在iPhone带动下,全世界的手机都变成一模一样的大体模样了。也就是说,都是大屏幕、无键盘。微信的崛起第一步就是:语音消息、手机通讯录导入、摇一摇周边。你看,全是原生应用了手机的独特特性。大家在思考万物互联网的时候也应该这样思考,要充分应用硬件的独特特性,而不是把大象装在冰箱里(比如很多人把企业管理软件精简功能做成App)。

十三、2012年:中国移动互联网发展年

这一年,中国手机网民数量超过了电脑上网网民数量(其实2013年中国政府才要求运营商强力推4G)。

这一年,中国移动互联网高速发展,大家都纷纷把自己的PC Web互联网的功能翻新成App版本。

华为、锤子也正式宣布进入智能手机领域。360和海尔也联合推出超级战舰手机。就连腾讯也谨慎的做了一个手机ROM。大家纷纷想从智能手机硬件、智能路由器和DNS、OS、应用商店、通信IM超级APP,一层层地釜底抽薪。

十四、2013:中国移动互联网爆炸年

3年啊,同志们。太快了,怪不得劳模雷军说:现在就连睡觉都觉得是浪费。

这一年,小米开始构建自己的智能产品生态,发布了好几款智能产品。这一年,乐视智能电视发布,乐视开始引爆江湖。

在这一年有两个关键事件决定了这一年是移动互联网爆炸年。一个是微信发布了游戏流量入口、打飞机小游戏狂潮掀起了移动游戏App的热潮。移动互联网,怎么能够少了游戏这一个半边天呢。微信在这一年还发布了公众号。没有媒体人的卷入,就不可能有大影响力大声音。微信也是在这一年狂发展的。

另外一个大事件就是,也就是从这一年开始,BAT们都开始做好自己的主流超级流量App,大力发展Open API开放平台,大力做投资并购。中国移动互联网为什么发展的这么快,关键就是有三大要素:超级流量、Open API和平台、资本投资和并购进入山头帮派时代。同志们,这句话要标红啊。这是过去中国互联网界从未有过的事情啊。这是中国互联网的并购年,其中最大的收购案就是百度以18.5亿美金收购91无线。

十五、2014:中国企业服务元年

在这一年,中国电商出现了一件大事:京东、阿里纷纷上市。京东和阿里占据中国线上B2C零售80%市场份额,构成了真正的双子星结构。这种市场结构,意味着这个市场已经成为寡头市场。现在再进入这个市场,不可能再出现第三巨头了,从第三名到最后一名,所有加总才能占据最多20%市场。从目前来看,就连拼多多这种拼团模式、云集微店众包销售模式,也只能成诸侯而不能成王。

虽然说,云计算创业三小龙:Ucloud、七牛、青云,都是2010-2011间成立的。但是,中国企业服务投资规模第一波热潮却真正来自2014年。其实不说2006年Amazon发布AWS,就说阿里云,也是在2009年10月写下第一行代码,2012年做天猫聚石塔项目,2013年换帅胡晓明开始高速发展。而中国IaaS云计算的高潮,还要等到2016年,那一年,所有互联网大佬、所有中国系统集成商大佬都已经进入IaaS公有云和私有云的市场。不过很多人却还后知后觉,直到2015年中国企业服务投资最高潮,很多人才匆忙杀入了这个行业,才匆忙升级要做SaaS软件。

这一年还有件事,就是菜鸟网络在这年成立了。菜鸟网络不搞仓库不买卡车不跑运输不招业务人员,但是菜鸟网络凭借淘宝天猫的订单流量、凭借自己的大数据建模技术,来做到智能的仓储物流调度,抽取中间的调度佣金。这本质上是电商+企业服务的混合体。

这一年还有件事,是滴滴的快速崛起。滴滴后来被人们笑话段子都演变成了滴滴模式(拼多多拼团也是种模式、团购秒杀倒计时也是种模式),什么滴滴打人、滴滴代喝、滴滴代嫁等等,哈哈哈。但是,滴滴代驾、滴滴拼车业务真的出现了。滴滴的核心是:根据地理位置(智能手机独特特性)、根据业务大数据和用户画像,智能匹配最合适的打车人和出租车,抽取中间的调度佣金。这本质也是电商+企业服务的混合体。

也就是说,智能调度匹配抽佣金,这个模式,会在中国业务+IT服务的各行各业中,都会形成落地的业务场景。这就是一种经过验证的以技术为本的商业模式。这个模式,非常值得中国企业服务商去探索借鉴思考。

十六、2015:中国互联网金融元年

这一年,在中央的大众创业万众创新的推动下,互联网金融开始热潮。当然,中国电子商务要高速发展,没有金融的支撑也是不能更快更大的发展。

所以这一年,P2P热、众筹热、消费贷热、供应链金融热都起来了。

但更突出的是:微信支付和支付宝支付开始大战。大家纷纷通过各种扫街、发起补贴活动,到处贴二维码,可以扫码支付。现在,就连买菜买鸡蛋夹肉饼,都可以用手机扫码。这种便捷性是全世界最领先的。

十七、2016年:智能元年

这一年,直播热崛起。但是这种直播和过去最早YY的直播还不一样。现在的直播最关键应用了实时美颜技术、虚拟AR技术。

这一年,从支付宝AR找福字、美颜App自带兔子耳朵虚拟表情开始,就发现今年的不一样了。那就是现实和虚拟的实时结合。

所以这一年,也带动了AR、VR设备热。也带动了人工智能技术热,先从人脸识别开始。

直播热从娱乐很快扩展到了电商,从虚拟送礼盈利走向推荐商品带货盈利。这也造就了2016年的微商热。这不同于过去的微商拼命加5000人拼命加群拼命发朋友圈鸡汤发微商广告的模式。这一年的微商都在实时美颜直播技术中统统成为了网红。

直播打赏热(这里也有上一年移动支付大战红包大战的功劳),也渐渐带动了另外一个正经事:知识网红(如罗振宇)+知识付费(如得到)。

这一年,还出现了共享单车大战,最后连颜色都不够用了。这里面最有名的论战就是马化腾和朱啸虎的言战,焦点是谁能笑到最后。马化腾认为是一定要是智能设备,如智能车锁,这显然是技术派的看法。而朱啸虎代表运营派,也就是说:最成熟的产品和消费习惯,最广阔的市场,用资本轰开。现在,朱啸虎的OfO陷入尴尬境地,朱啸虎后来都暗示服了软,显然,智能才是核心。

十八、2017年:新零售元年

2017年说什么热,那必须是新零售。新零售的本质是用智能传感设备、人工智能技术,实现线下数据收集和线上电商是一样的效果。大家切记切记。

虽然说,有人把新零售看做是线下,用正规企业运营方法再重做一次,就如同当年如家他们用资本+企业标准运营管理方法重塑中国快捷酒店业一样。

技术派:无人零售商店、无人货架&货柜、智能购物车、智能称重台、人脸识别进门、人脸识别自动支付

运营派:生鲜、生鲜+餐饮堂食、连锁便利店、中央厨房供应链….

十九、2018年:

2018年,中国互联网金融热已经过去了3年。今年卷土重来的是:区块链。创建X币项目、发币上交易所市,成了主流割韭菜模式。看不清看不清。

在去年直播热、直播技术、直播打赏普及成熟的基础上,快手、抖音短视频热崛起。但是这种短视频又和过去的移动视频热不一样。因为除了技术流畅、打赏付费习惯成熟外,现在抖音又多了附近、朋友、互动。这简直是下一代社交网络的潜力啊。怪不得腾讯今天上半年从收购到打击抖音到内部赛马做了N多短视频App,根源就在于此。

我过去就说过,QQ发源于台式机拨号上网文字时代,微信发源于智能手机4G上网语音时代,那么下一代社交网络工具一定是基于万物互联5G上网视频时代。

从2008年智能手机元年开始算起,今年也已经十年了。智能手机移动互联网时代也要高潮地结束了。今年,小米也要在港交所上市了。

一个时代即将结束(还有2年最后的两个黑洞大碰撞,我猜是腾讯集团和今日头条集团),那么我们在今年,确实应该多静下来思考思考,几个好友坐下来重新回归历史一片空白该想想了、放开脑洞发散性讨论讨论了。

下一代主流硬件是什么?下一代主流OS是什么?

下一代主流社交网络工具是什么?下一代搜索是什么(是视觉识别和语音交互吗)?

下一代内容是什么样子的?比如说新闻、文学、视频、音乐…。

下一代游戏是什么样子的(是ARVR吗)?

下一代电子商务是什么样子的?下一代后端企业服务是什么样子的?

这里边,有你吗?

下一代商业模式的核心要素是什么?除了:流量、资本、技术和数据以及开放平台外,还有什么新的要素?

from:https://mp.weixin.qq.com/s/X195WPlHz6IyMyg-lpc9Yg

微服务化之缓存的设计

本文章为《互联网高并发微服务化架构实践》系列课程的第五篇

前四篇为:

微服务化的基石——持续集成

微服务的接入层设计与动静资源隔离

微服务化的数据库设计与读写分离

微服务化之无状态化与容器化

在高并发场景下,需要通过缓存来减少数据库的压力,使得大量的访问进来能够命中缓存,只有少量的需要到数据库层。由于缓存基于内存,可支持的并发量远远大于基于硬盘的数据库。所以对于高并发设计,缓存的设计时必不可少的一环。

一、为什么要使用缓存

为什么要使用缓存呢?源于人类的一个梦想,就是多快好省的建设社会主义。

多快好省?很多客户都这么要求,但是作为具体做技术的你,当然知道,好就不能快,多就没法省。

可是没办法,客户都这样要求:

这个能不能便宜一点,你咋这么贵呀,你看人家都很便宜的。(您好,这种打折的房间比较靠里,是不能面向大海的)

你们的性能怎么这么差啊,用你这个系统跑的这么慢,你看人家广告中说速度能达到多少多少。(您好,你如果买一个顶配的,我们也是有这种性能的)

你们服务不行啊,你就不能彬彬有礼,穿着整齐,送点水果瓜子啥的?(您好,我们兰州拉面馆没有这项服务,可以去对面的俏江南看一下)

这么贵的菜,一盘就这么一点点,都吃不饱,就不能上一大盘么。(您好,对面的兰州拉面10块钱一大碗)

怎么办呢?劳动人民还是很有智慧的,就是聚焦核心需求,让最最核心的部分享用好和快,而非核心的部门就多和省就可以了。

你可以大部分时间住在公司旁边的出租屋里面,但是出去度假的一个星期,选一个面朝大海,春暖花开的五星级酒店。

你可以大部分时间都挤地铁,挤公交,跋涉2个小时从北五环到南五环,但是有急事的时候,你可以打车,想旅游的时候,可以租车。

你可以大部分时间都吃普通的餐馆,而朋友来了,就去高级饭店里面搓一顿。

在计算机世界也是这样样子的,如图所示。

越是快的设备,存储量越小,越贵,而越是慢的设备,存储量越大,越便宜。

对于一家电商来讲,我们既希望存储越来越多的数据,因为数据将来就是资产,就是财富,只有有了数据,我们才知道用户需要什么,同时又希望当我想访问这些数据的时候,能够快速的得到,双十一拼的就是速度和用户体验,要让用户有流畅的感觉。

所以我们要讲大量的数据都保存下来,放在便宜的存储里面,同时将经常访问的,放在贵的,小的存储里面,当然贵的快的往往比较资源有限,因而不能长时间被某些数据长期霸占,所以要大家轮着用,所以叫缓存,也就是暂时存着。

二、都有哪些类型的缓存

当一个应用刚开始的时候,架构比较简单,往往就是一个Tomcat,后面跟着一个数据库。

简单的应用,并发量不大的时候,当然没有问题。

然而数据库相当于我们应用的中军大帐,是我们整个架构中最最关键的一部分,也是最不能挂,也最不能会被攻破的一部分,因而所有对数据库的访问都需要一道屏障来进行保护,常用的就是缓存。

我们以Tomcat为分界线,之外我们称为接入层,接入层当然应该有缓存,还有CDN,这个在这篇文章中有详细的描述,微服务的接入层设计与动静资源隔离

Tomcat之后,我们称为应用层,应用层也应该有缓存,这是我们这一节讨论的重点。

最简单的方式就是Tomcat里面有一层缓存,常称为本地缓存LocalCache。

这类的缓存常见的有Ehcache和Guava Cache,由于这类缓存在Tomcat本地,因而访问速度是非常快的。

但是本地缓存有个比较大的缺点,就是缓存是放在JVM里面的,会面临Full GC的问题,一旦出现了FullGC,就会对应用的性能和相应时间产生影响,当然也可以尝试jemalloc的分配方式。

还有一种方式,就是在Tomcat和Mysql中间加了一层Cache,我们常称为分布式缓存。

分布式缓存常见的有Memcached和Redis,两者各有优缺点。

Memcached适合做简单的key-value存储,内存使用率比较高,而且由于是多核处理,对于比较大的数据,性能较好。

但是缺点也比较明显,Memcached严格来讲没有集群机制,横向扩展完全靠客户端来实现。另外Memcached无法持久化,一旦挂了数据就都丢失了,如果想实现高可用,也是需要客户端进行双写才可以。

所以可以看出Memcached真的是设计出来,简简单单为了做一个缓存的。

Redis的数据结构就丰富的多了,单线程的处理所有的请求,对于比较大的数据,性能稍微差一点。

Redis提供持久化的功能,包括RDB的全量持久化,或者AOF的增量持久化,从而使得Redis挂了,数据是有机会恢复的。

Redis提供成熟的主备同步,故障切换的功能,从而保证了高可用性。

所以很多地方管Redis称为内存数据库,因为他的一些特性已经有了数据库的影子。

这也是很多人愿意用Redis的原因,集合了缓存和数据库的优势,但是往往会滥用这些优势,从而忽略了架构层面的设计,使得Redis集群有很大的风险。

很多情况下,会将Redis当做数据库使用,开启持久化和主备同步机制,以为就可以高枕无忧了。

然而Redis的持久化机制,全量持久化则往往需要额外较大的内存,而在高并发场景下,内存本来就很紧张,如果造成swap,就会影响性能。增量持久化也涉及到写磁盘和fsync,也是会拖慢处理的速度,在平时还好,如果高并发场景下,仍然会影响吞吐量。

所以在架构设计角度,缓存就是缓存,要意识到数据会随时丢失的,要意识到缓存的存着的目的是拦截到数据库的请求。如果为了保证缓存的数据不丢失,从而影响了缓存的吞吐量,甚至稳定性,让缓存响应不过来,甚至挂掉,所有的请求击穿到数据库,就是更加严重的事情了。

如果非常需要进行持久化,可以考虑使用levelDB此类的,对于随机写入性能较好的key-value持久化存储,这样只有部分的确需要持久化的数据,才进行持久化,而非无论什么数据,通通往Redis里面扔,同时统一开启了持久化。

三、基于缓存的架构设计要点

所以基于缓存的设计:

1、多层次

这样某一层的缓存挂了,还有另一层可以撑着,等待缓存的修复,例如分布式缓存因为某种原因挂了,因为持久化的原因,同步机制的原因,内存过大的原因等,修复需要一段时间,在这段时间内,至少本地缓存可以抗一阵,不至于一下子就击穿数据库。而且对于特别特别热的数据,热到导致集中式的缓存处理不过来,网卡也被打满的情况,由于本地缓存不需要远程调用,也是分布在应用层的,可以缓解这种问题。

2、分场景

到底要解决什么问题,可以选择不同的缓存。是要存储大的无格式的数据,还是要存储小的有格式的数据,还是要存储一定需要持久化的数据。具体的场景下一节详细谈。

3、要分片

使得每一个缓存实例都不大,但是实例数目比较多,这样一方面可以实现负载均衡,防止单个实例称为瓶颈或者热点,另一方面如果一个实例挂了,影响面会小很多,高可用性大大增强。分片的机制可以在客户端实现,可以使用中间件实现,也可以使用Redis的Cluster的方式,分片的算法往往都是哈希取模,或者一致性哈希。

四、缓存的使用场景

当你的应用扛不住,知道要使用缓存了,应该怎么做呢?

场景1:和数据库中的数据结构保持一致,原样缓存

这种场景是最常见的场景,也是很多架构使用缓存的适合,最先涉及到的场景。

基本就是数据库里面啥样,我缓存也啥样,数据库里面有商品信息,缓存里面也放商品信息,唯一不同的是,数据库里面是全量的商品信息,缓存里面是最热的商品信息。

每当应用要查询商品信息的时候,先查缓存,缓存没有就查数据库,查出来的结果放入缓存,从而下次就查到了。

这个是缓存最最经典的更新流程。这种方式简单,直观,很多缓存的库都默认支持这种方式。

场景2:列表排序分页场景的缓存

有时候我们需要获得一些列表数据,并对这些数据进行排序和分页。

例如我们想获取点赞最多的评论,或者最新的评论,然后列出来,一页一页的翻下去。

在这种情况下,缓存里面的数据结构和数据库里面完全不一样。

如果完全使用数据库进行实现,则按照某种条件将所有的行查询出来,然后按照某个字段进行排序,然后进行分页,一页一页的展示。

但是当数据量比较大的时候,这种方式往往成为瓶颈,首先涉及的数据库行数比较多,而且排序也是个很慢的活,尽管可能有索引,分页也是翻页到最后,越是慢。

在缓存里面,就没必要每行一个key了,而是可以使用Redis的列表方式进行存储,当然列表的长短是有限制的,肯定放不下数据库里面这么多,但是大家会发现其实对于所有的列表,用户往往没有耐心看个十页八页的,例如百度上搜个东西,也是有排序和分页的,但是你每次都往后翻了吗,每页就十条,就算是十页,或者一百页,也就一千条数据,如果保持ID的话,完全放的下。

如果已经排好序,放在Redis里面,那取出列表,翻页就非常快了。

可以后台有一个线程,异步的初始化和刷新缓存,在缓存里面保存一个时间戳,当有更新的时候,刷新时间戳,异步任务发现时间戳改变了,就刷新缓存。

场景3:计数缓存

计数对于数据库来讲,是一个非常繁重的工作,需要查询大量的行,最后得出计数的结论,当数据改变的时候,需要重新刷一遍,非常影响性能。

因此可以有一个计数服务,后端是一个缓存,将计数作为结果放在缓存里面,当数据有改变的时候,调用计数服务增加或者减少计数,而非通过异步数据库count来更新缓存。

计数服务可以使用Redis进行单个计数,或者hash表进行批量计数

场景4:重构维度缓存

有时候数据库里面保持的数据的维度是为了写入方便,而非为了查询方便的,然而同时查询过程,也需要处理高并发,因而需要为了查询方便,将数据重新以另一个维度存储一遍,或者说将多给数据库的内容聚合一下,再存储一遍,从而不用每次查询的时候都重新聚合,如果还是放在数据库,比较难维护,放在缓存就好一些。

例如一个商品的所有的帖子和帖子的用户,以及一个用户发表过的所有的帖子就是属于两个维度。

这需要写入一个维度的时候,同时异步通知,更新缓存中的另一个维度。

在这种场景下,数据量相对比较大,因而单纯用内存缓存memcached或者redis难以支撑,往往会选择使用levelDB进行存储,如果levelDB的性能跟不上,可以考虑在levelDB之前,再来一层memcached。

场景5:较大的详情内容数据缓存

对于评论的详情,或者帖子的详细内容,属于非结构化的,而且内容比较大,因而使用memcached比较好。

五、缓存三大矛盾问题

1、缓存实时性和一致性问题:当有了写入后咋办?

虽然使用了缓存,大家心里都有一个预期,就是实时性和一致性得不到完全的保证,毕竟数据保存了多份,数据库一份,缓存中一份,当数据库中因写入而产生了新的数据,往往缓存是不会和数据库操作放在一个事务里面的,如何将新的数据更新到缓存里面,什么时候更新到缓存里面,不同的策略不一样。

从用户体验角度,当然是越实时越好,用户体验越流畅,完全从这个角度出发,就应该有了写入,马上废弃缓存,触发一次数据库的读取,从而更新缓存。但是这和第三个问题,高并发就矛盾了,如果所有的都实时从数据库里面读取,高并发场景下,数据库往往受不了。

2、缓存的穿透问题:当没有读到咋办?

为什么会出现缓存读取不到的情况呢?

第一:可能读取的是冷数据,原来从来没有访问过,所以需要到数据库里面查询一下,然后放入缓存,再返回给客户。

第二:可能数据因为有了写入,被实时的从缓存中删除了,就如第一个问题中描述的那样,为了保证实时性,当数据库中的数据更新了之后,马上删除缓存中的数据,导致这个时候的读取读不到,需要到数据库里面查询后,放入缓存,再返回给客户。

第三:可能是缓存实效了,每个缓存数据都会有实效时间,过了一段时间没有被访问,就会失效,这个时候数据就访问不到了,需要访问数据库后,再放入缓存。

第四:数据被换出,由于缓存内存是有限的,当使用快满了的时候,就会使用类似LRU策略,将不经常使用的数据换出,所以也要访问数据库。

第五:后端确实也没有,应用访问缓存没有,于是查询数据库,结果数据库里面也没有,只好返回客户为空,但是尴尬的是,每次出现这种情况的时候,都会面临着一次数据库的访问,纯属浪费资源,常用的方法是,讲这个key对应的结果为空的事实也进行缓存,这样缓存可以命中,但是命中后告诉客户端没有,减少了数据库的压力。

无论哪种原因导致的读取缓存读不到的情况,该怎么办?是个策略问题。

一种是同步访问数据库后,放入缓存,再返回给客户,这样实时性最好,但是给数据库的压力也最大。

另一种方式就是异步的访问数据库,暂且返回客户一个fallback值,然后同时触发一个异步更新,这样下次就有了,这样数据库压力小很多,但是用户就访问不到实时的数据了。

3、缓存对数据库高并发访问:都来访问数据库咋办?

我们本来使用缓存,是来拦截直接访问数据库请求的,从而保证数据库大本营永远处于健康的状态。但是如果一遇到不命中,就访问数据库的话,平时没有什么问题,但是大促情况下,数据库是受不了的。

一种情况是多个客户端,并发状态下,都不命中了,于是并发的都来访问数据库,其实只需要访问一次就好,这种情况可以通过加锁,只有一个到后端来实现。

另外就是即便采取了上述的策略,依然并发量非常大,后端的数据库依然受不了,则需要通过降低实时性,将缓存拦在数据库前面,暂且撑住,来解决。

六、解决缓存三大矛盾的刷新策略

1、实时策略

所谓的实时策略,是平时缓存使用的最常用的策略,也是保持实时性最好的策略。

读取的过程,应用程序先从cache取数据,没有得到,则从数据库中取数据,成功后,放到缓存中。如果命中,应用程序从cache中取数据,取到后返回。

写入的过程,把数据存到数据库中,成功后,再让缓存失效,失效后下次读取的时候,会被写入缓存。那为什么不直接写缓存呢?因为如果两个线程同时更新数据库,一个将数据库改为10,一个将数据库改为20,数据库有自己的事务机制,可以保证如果20是后提交的,数据库里面改为20,但是回过头来写入缓存的时候就没有事务了,如果改为20的线程先更新缓存,改为10的线程后更新缓存,于是就会长时间出现缓存中是10,但是数据库中是20的现象。

这种方式实时性好,用户体验好,是默认应该使用的策略。

2、异步策略

所谓异步策略,就是当读取的时候读不到的时候,不直接访问数据库,而是返回一个fallback数据,然后往消息队列里面放入一个数据加载的事件,在背后有一个任务,收到事件后,会异步的读取数据库,由于有队列的作用,可以实现消峰,缓冲对数据库的访问,甚至可以将多个队列中的任务合并请求,合并更新缓存,提高了效率。

当更新的时候,异步策略总是先更新数据库和缓存中的一个,然后异步的更新另一个。

一是先更新数据库,然后异步更新缓存。当数据库更新后,同样生成一个异步消息,放入消息队列中,等待背后的任务通过消息进行缓存更新,同样可以实现消峰和任务合并。缺点就是实时性比较差,估计要过一段时间才能看到更新,好处是数据持久性可以得到保证。

一是先更新缓存,然后异步更新数据库。这种方式读取和写入都用缓存,将缓存完全挡在了数据库的前面,把缓存当成了数据库在用。所以一般会使用有持久化机制和主备的redis,但是仍然不能保证缓存不丢数据,所以这种情况适用于并发量大,但是数据没有那么关键的情况,好处是实时性好。

在实时策略扛不住大促的时候,可以根据场景,切换到上面的两种模式的一个,算是降级策略。

3、定时策略

如果并发量实在太大,数据量也大的情况,异步都难以满足,可以降级为定时刷新的策略,这种情况下,应用只访问缓存,不访问数据库,更新频率也不高,而且用户要求也不高,例如详情,评论等。

这种情况下,由于数据量比较大,建议将一整块数据拆分成几部分进行缓存,而且区分更新频繁的和不频繁的,这样不用每次更新的时候,所有的都更新,只更新一部分。并且缓存的时候,可以进行数据的预整合,因为实时性不高,读取预整合的数据更快。

有关缓存就说到这里,下一节讲分布式事务。

from:https://mp.weixin.qq.com/s/-9wHpKGf7aJSbtShpCcoVg