微服务基础
微服务基础概述微服务的概念最早是在 2014 年由 Martin Fowler 和 James Lewis 共同提出,他们定义了微服务是由单一应用程序构成的小服务,拥有自己的进程与轻量化处理,服务依业务功能设计,以全自动的方式部署,与其他服务使用 HTTP API 通讯。同时,服务会使用最小规模的集中管理 (例如 Docker)技术,服务可以用不同的编程语言与数据库等。
单体应用的痛点:
部署效率低下
团队协作开发成本高
系统高可用性差
线上发布变慢
想要解决上面这些问题,服务化的思想也就应运而生。
用通俗的话来讲,服务化就是把传统的单机应用中通过 JAR 包依赖产生的本地方法调用,改造成通过 RPC 接口产生的远程方法调用。
微服务的优势:
服务拆分粒度更细
服务独立部署
服务独立维护
服务治理能力要求高
总结一下,微服务架构下,主要功能模块:
服务间通信:包括服务治理、负载均衡、服务间调用;
服务容错和异常排查:包括流量整形、降级熔断、调用链追踪;
分布式能力建设:包括微服务网关、分布式事务、消息驱动、分布式配置中心。
服务的发布引用最常见的服务发布和引用的方式有三 ...
dubbo
Dubbo简介Dubbo是一个开源的、高性能的、广泛应用的远程过程调用(RPC)框架,用于在Java中构建分布式系统。它最初由阿里巴巴集团开发,并作为Apache Dubbo项目的一部分后来开源。Dubbo通过提供服务通信、负载均衡、容错等框架来简化分布式应用程序的开发,并且支持HTTP/2、REST、gRPC、JsonRPC、Thrift、Hessian2 等几乎所有主流的通信协议以及Dubbo2、Triple (兼容 gRPC) 高性能协议。
以上是 Dubbo 的工作原理图,从抽象架构上分为两层:服务治理抽象控制面 和 Dubbo 数据面 。
Dubbo模块图:
十层模块的作用:
Dubbo 服务治理
以下是与Dubbo相关的一些关键特点和概念:
地址发现
Dubbo 服务发现具备高性能、支持大规模集群、服务级元数据配置等优势,默认提供 Nacos、Zookeeper、Consul 等多种注册中心适配,与 Spring Cloud、Kubernetes Service 模型打通,支持自定义扩展。
负载均衡
Dubbo 默认提供加权随机、加权轮询、最少活跃请求数优先、最 ...
高并发系统分布式服务方案
高并发系统分布式服务方案服务拆分一体化架构的痛点一体化架构的一些缺陷,这主要体现在以下几个方面:
在技术层面上,数据库连接数可能成为系统的瓶颈:
因为你的系统是按照一体化架构部署的,在部署结构上没有分层,应用服务器直接连接数据库,那么当前端请求量增加,部署的应用服务器扩容,数据库的连接数也会大增。
一体化架构增加了研发的成本抑制了研发效率的提升:
当如此多的小团队共同维护一套代码和一个系统时,在配合的过程中就会出现问题,例如交流、代码冲突等问题。
对于系统的运维也会有很大的影响:
当你的系统扩充到几十万行甚至上百万行代码的时候,一次构建的过程包括编译、单元测试、打包和上传到正式环境,花费的时间可能达到十几分钟,并且任何小的修改,都需要构建整个项目,上线变更的过程非常不灵活。
微服务化例如最开始的社区业务系统,对数据库进行了垂直分库分为用户库、内容库和互动库。但是由于系统是一体化的,每个模块都会直接与数据库相连接。
其实可以把各个模块的逻辑部署成一个单独的服务,这样就可以直接服务之间相互调用。(也可以将公共服务拆分为单独的服务,增加重用性)
服务拆分原则:
做到单一服 ...
消息队列延迟问题
消息延迟问题消息延迟监控监控消息的延迟有两种方式:
使用消息队列提供的工具,通过监控消息的堆积来完成;
利用消息队列实现提供的监控工具,例如Kafka中提供的“kafka-consumer-groups.sh
第三方监控工具:JMX
通过生成监控消息的方式来监控消息的延迟情况。
编写并启动一个监控程序,将监控消息定时地循环写入到消息队列中,消息的内容可以是生成消息的时间戳并且也会作为队列的消费者消费数据。
业务处理程序消费到这个消息时直接丢弃掉,而监控程序在消费到这个消息时就可以和这个消息的生成时间做比较,如果时间差达到某一个阈值就可以向我们报警。
减少消息延迟想要减少消息的处理延迟,我们需要在消费端和消息队列两个层面来完成。
消费端
在消费端的目标是提升消费者的消息处理能力:
优化消费代码提升性能:
注意消费线程空转,如果经常发生空转,可以设置固定或者步长递增的等待时间例如10ms~100ms。
增加消费者的数量。
如果想kafka一样一个 Topic(话题)可以配置多个 Partition(分区),一个分区只能由一个消费者消费,则可以让消费者收到了消息之 ...
CDN静态资源加速
CDN静态资源加速概述一般在我们的系统中存在着大量的静态资源请求:
对于移动 APP 来说,这些静态资源主要是图片、视频和流媒体信息;
对于 Web 网站来说,则包括了 JavaScript 文件、CSS 文件、静态 HTML 文件等等
一般这些静态资源是部署在Nginx 等 Web 服务器上,由于请求量大常常占据了很高的带宽,这时会出现访问速度慢带宽被占满影响动态请求的问题;所以对于静态资源也需要考虑对其进行访问加速的问题。
所以我们考虑在业务服务器的上层增加一层特殊的缓存,用来承担绝大部分对于静态资源的访问,这一层特殊缓存的节点需要遍布在全国各地,这样可以让用户选择最近的节点访问。这就是CDN。
CDN关键技术CDN的全称是Content Delivery Network,即内容分发网络。其基本思路是尽可能避开互联网上有可能影响数据传输速度和稳定性的瓶颈和环节,使内容传输得更快、更稳定。
CDN的关键技术在于两点:
如何将用户的请求映射到 CDN 节点上;
如何根据用户的地理位置信息选择到比较近的节点。
如何让用户的请求到达 CDN 节点
这就需要依靠 DNS 来帮我们解 ...
缓存的读写策略
缓存的读写策略Cache Aside(旁路缓存)策略这个策略数据以数据库中的数据为准,缓存中的数据是按需加载的。它可以分为读策略和写策。
读策略步骤:
从缓存中读取数据;
如果缓存命中,则直接返回数据;
如果缓存不命中,则从数据库中查询数据;
查询到数据后,将数据写入到缓存中,并且返回给用户。
写策略步骤:
更新数据库中的记录;
删除缓存记录(必须在更新数据库后面)。
这样的读写策略能解决大部分并发更新时缓存数据不一致的问题也正说明他不适用于写入频繁的场景,但是还是会出现一种问题
例如:用户数据在缓存中不存在,请求 A 读取数据时从数据库中查询到年龄为 20,在未写入缓存中时另一个请求 B 更新数据。它更新数据库中的年龄为 21,并且清空缓存。这时请求 A 把从数据库中读到的年龄为 20 的数据写入到缓存中,造成缓存和数据库数据不一致。
如果你的业务对缓存命中率有严格的要求,那么可以考虑两种解决方案:
一种做法是在更新数据时也更新缓存,只是在更新缓存前先加一个分布式锁解决并发问题。
另一种做法同样也是在更新数据时更新缓存,只是给缓存加一个较短的过期时间。
Read/Wr ...
缓存概述
缓存概述什么是缓存缓存,是一种存储数据的组件,它的作用是让对数据的请求更快地返回。
实际上,凡是位于速度相差较大的两种硬件之间,用于协调两者数据传输速度差异的结构,均可称之为缓存。
例如:
操作系统的快速转换表:TLB(Translation Lookaside Buffer)
HTTP的协商缓存
缓存分类静态缓存:这种缓存只能针对静态数据来缓存,一般通过生成静态 HTML 文件来实现静态缓存并在 Nginx 上部署静态缓存可以减少对于后台应用服务器的压力。
分布式缓存:例如Redis、Memcached等就是典型的分布式缓存。性能强劲,并且可以通过分布式方案突破单机限制。
热点本地缓存:热点本地缓存主要部署在应用服务器的代码中(如 HashMap,Guava Cache 或者是 Ehcache 等),因为它们和应用程序部署在同一个进程中,优势是不需要跨网络调度,速度极快,所以用于阻挡热点查询对于分布式缓存节点或者数据库的压力。(但是由于会有多台应用服务器,数据更新无法更新删除缓存,所以有效期很短秒级或者分钟级)
利用NoSQL优化数据库
利用NoSQL数据库当系统中某业务的数据已经无法用分库分表来解决的时候,就应该考虑是否需要利用NoSQL数据库来补充传统关系型数据库了。因为它有着天生分布式的能力,能够提供优秀的读写性能,可以很好地补充传统关系型数据库的短板。但是只是互补关系不能完全替代。
提高写入性能数据库系统大多使用的是传统的机械磁盘,对于机械磁盘的访问方式有两种:一种是随机 IO;另一种是顺序 IO。
以 MySQL 的 InnoDB 存储引擎来说,更新 binlog、redolog、undolog 都是在做顺序 IO,而更新 datafile 和索引文件则是在做随机 IO,而为了减少随机 IO 的发生,关系数据库已经做了很多的优化,比如说写入时先写入内存,然后批量刷新到磁盘上,但是随机 IO 还是会发生。
而NoSQL大多是直接写入内存,为了持久化会做顺序IO以日志形式写入磁盘。它们的核心思想就是将随机 IO 变成顺序的 IO,从而提升写入的性能。
场景补充例如商品的搜索场景,如果直接使用传统数据库的模糊查询,性能是根据无法接受的。这个时候就可以使用NoSQL来进行场景补充例如:开源组件 Elasticsear ...
MySQL分库分表
分库分表系统正在持续不断地发展,注册的用户越来越多,数据库中存储的数据也越来越多。
会遇到的问题:
这时即使你使用了索引,索引占用的空间也随着数据量的增长而增大,数据库就无法缓存全量的索引信息,那么就需要从磁盘上读取索引数据,就会影响到查询的性能了。
数据量的增加也占据了磁盘的空间,数据库在备份和恢复的时间变长。
不同模块的数据,比如用户数据和用户关系数据,全都存储在一个主库中,一旦主库发生故障,所有的模块都会受到影响。
这些问题都是数据库的写入请求量大造成的性能和可用性方面的问题,一般采取的措施就是对数据进行分片即分库分表。
为什么要分库分表:
如果数据库已经到了写瓶颈怎么办?要么优化写操作,要么分库。
对于写瓶颈来说,分区表可以缓解问题,而读写分离几乎没有效果,比如频繁地增删改操作。
如果数据库已经到了读瓶颈怎么办?要么优化读操作,要么加从库,要么分库或分表。
对于硬件瓶颈来说,读写分离、分区表基本上也解决不了,比如写操作引发的网络带宽问题。
一般非必要不进行分库分表,大致要求如下:
单表数据超过1000w
单表数据文件大小超过20GB
方案分为:
单库多表:有 ...
MySQL读写分离
主从读写分离大部分系统的访问模型是读多写少,读写请求量的差距可能达到几个数量级。
因此,我们优先考虑数据库如何抵抗更高的查询请求,那么首先你需要把读写流量区分开,因为这样才方便针对读流量做单独的扩展(但是不易太对IO线程消耗太大,一般一个主库最多挂 3~5 个从库),这就是我们所说的主从读写分离。从库也可以当成一个备库来使用,以避免主库故障导致数据丢失。
主从读写分离有两个技术关键点:
一个是数据的拷贝,我们称为主从复制;
在主从分离的情况下,我们如何屏蔽主从分离带来的访问数据库方式的变化,让开发像是在使用单一数据库一样。
主从复制以MySQL的主从复制为例,MySQL 的主从复制是依赖于 binlog 的,主从复制就是将 binlog 中的数据从主库传输到从库上,一般这个过程是异步的,即主库上的操作不会等待 binlog 同步的完成。
同步完整流程:
一个事务日志同步的完整过程是这样的:
在备库B上通过change master命令,设置主库A的IP、端口、用户名、密码,以及要从哪个位置开始请求binlog,这个位置包含文件名和日志偏移量。
在备库B上执行start s ...