Spiga

标签为高可用的文章

B站架构设计6:微服务可观测性设计

2021-09-11 20:14:00

摘要:一、日志 1. 日志级别 Warning: 没人看警告,因为从定义上讲,没有什么出错。也许将来会出问题,但这听起来像是别人的问题。 我们应该尽可能的消除警告级别,它要么是一条信息性消息,要么是一个错误。 参考 Go 语言设计额哲学,所有警告都是错误,其他语言的 warning 都可以忽略,除非 IDE 或者在 CICD 流程中强制他们为 error,然后逼着程序员们尽可能去消除。 同样的,如果想要最终消除 warning 可以记录为 error,让代码作者重视起来。 Fatal,记录消息后,直接调用 os.Exit(1),这意味着: 在其他 goroutine defer 语句不会被执行; 各种 buffers 不会被 flush,包括日志的; 临时文件或者目录不会被移除; 不要使用 fatal 记录日志,而是向调用者返回错误。如果错误一直持续到 main.main。main.main 那就是在退出之前做处理任何清理操作的正确位置。 Error,也有很多人,在错误发生的地方要立马记录日志,尤其要使用 error 级别记录。 处理 error; 把 error 抛给调用者,在顶部打印日志; 如果您选择通过日志记录来处理错误,那么根据定义,它不再是一个错误——您已经处理了它。记录错误的行为会处理错误,因此不再适合将其记录为错误。 err := somethingHard() if err != nil { log.Error(oops, something was too hard, err) return err // what is this, Java ? } if err := planA(); err != nil { log.Infof(could't open the foo file, err) planB() } 这里产生了降级行为,本质属于有损服务,更倾向在这里使用 Warning。 Debug,相信只有两件事你应该记录: 开发人员在开发或调试软件时关心的事情。 用户在使用软件时关心的事情。 显然,它们分别是调试和信息级别。 log.Info 只需将该行写入日志输出。不应该有关闭它的选项,因为用户只应该被告知对他们有用的事情。如果发生了一个无法处理的错误,它就会抛出到 main.ma…… 阅读全文

B站架构设计5:分布式缓存与分布式事务

2021-09-04 10:57:12

摘要:一、缓存选型 1. Memcache memcache 提供简单的 kv cache 存储,value 大小不超过1mb。 memcache 用来存储大文本或者简单的 kv 结构。 memcache 使用了slab 方式做内存管理,存在一定的浪费,如果大量接近的 item,建议调整 memcache 参数来优化每一个 slab 增长的 ratio、可以通过设置 slab_automove slab_reassign 开启memcache 的动态/手动 move slab,防止某些 slab 热点导致内存足够的情况下引发 LRU。 大部分情况下,简单 KV 推荐使用 Memcache,吞吐和相应都足够好。 内存分配方式 每个 slab 包含若干大小为1M的内存页,这些内存又被分割成多个 chunk,每个 chunk 存储一个 item; 在 memcache 启动初始化时,每个 slab 都预分配一个 1M 的内存页,由slabs_preallocate 完成(也可将相应代码注释掉关闭预分配功能)。 chunk 的增长因子由 -f 指定,默认1.25,起始大小为48字节。 内存池有很多种设计,可以参考下: nginx ngx_pool_t,tcmalloc 的设计等等。 2. Redis redis 有丰富的数据类型,支持增量方式的修改部分数据,比如排行榜,集合,数组等。 比较常用的方式是使用 redis 作为数据索引,比如评论的列表 ID,播放历史的列表 ID 集合,关系链列表 ID。 redis 因为没有使用内存池,所以是存在一定的内存碎片,老版本一般会使用 jemalloc 来优化内存分配,需要编译时候使用 jemalloc 库代替 glib 的 malloc 使用。 3. Redis vs Memcache Redis 和 Memcache 最大的区别其实是 redis 单线程(新版本双线程),memcache 多线程,所以 QPS 可能两者差异不大,但是吞吐会有很大的差别,比如大数据 value 返回的时候,redis qps 会抖动下降的的很厉害,因为单线程工作,其他查询进不来(新版本有不少的改善)。 所以建议纯 kv 都走 memcache,比如B站的关系链服务中用了 hashs 存储双向关系,但是也会使用 memcache 档一层来避免 hge…… 阅读全文

B站架构设计4:历史记录架构设计

2021-08-28 13:54:56

摘要:一、功能设计 为了大部分用户的基本功能体验,满足用户需求,例如播放历史查看、播放进度同步等。离线型用户,app 本地保留历史记录数据。 同样的,也要考虑平台化,视频、文章、漫画等业务扩展接入。 变更功能:添加记录、删除记录、清空历史。 读取功能:按照 timeline 返回 top N,点查获取进度信息。 其他功能:暂停/恢复记录,首次观察增加经验等。 历史记录类型的业务,是一个极高 tps 写入,高 qps 读取的业务服务。分析清楚系统的 hot path,投入优化,而不是哪哪都去优化。 二、架构设计 1. 概述 BFF(app-interface、history):历史 BFF 层接受来自外部用户的读请求,依赖其他例如稿件、漫画服务来组装完整的面向历史业务(页面)需要的数据的组合。同时接受来自内部其他业务线的写请求,通常都是业务方自己进行业务 ID 的判定,然后投递到历史服务的 BFF 写接口中。最终 BFF 是打包在 app-interface 大杂烩 BFF 中,考虑到隔离性,读写流量很大,独立成 history BFF 服务。 Service(history-service):服务层,去平台业务的逻辑,专注在历史数据的持久化上(因为对于播放类业务,BFF 专注平台业务数据组织,service 负责数据的读、写、删、清理等操作。播放进度是非常高频同步的,需要考虑性能优化)。 使用 write-back 的思路,把状态数据先入分布式缓存,再回写数据库。 Job(history-job):job 消费上游 kafka 的数据,利用消息队列的堆积能力,对于存储层的差速(消费能力跟不上生产速度时),可以进行一定的数据反压。配合上游 service 批量打包过来的数据持久化。 Upstream(some-app,some-api):整个历史服务还会被一些外部 gRPC 服务所依赖,所以 history 还充当了内网的 gRPC Provider,这些上游服务,使用历史服务的写接口,把自己业务的数据进行持久化。 历史服务最重要的设计,就是批量打包(pipeline)聚合数据。将高频、密集的写请求先入缓存(write-back),批量消费减少对存储的直接压力,类似的设计随处可见。 2. history-service history-ser…… 阅读全文

B站架构设计3:评论系统架构设计

2021-08-21 20:37:54

摘要:一、功能设计 架构设计最重要的就是理解整个产品体系在系统中的定位。搞清楚系统背后的背景,才能做出最佳的设计和抽象。不要做需求的翻译机,先理解业务背后的本质,事情的初衷。 评论系统,往小里做就是视频评论系统,往大里做就是评论平台,可以接入各种业务形态。 发布评论:支持回复楼层、楼中楼。 读取评论:按照时间、热度排序。 删除评论:用户删除、作者删除。 管理评论:作者置顶、后台运营管理**(搜索、删除、审核等)**。 在动手设计前,反复思考,真正编码的时间只有10%。 二、架构设计 1. 概述 BFF(comment):复杂评论业务的服务编排,比如访问账号服务进行等级判定,同时需要在 BFF 面向移动端/WEB场景来设计 API,这一层抽象把评论的本身的内容列表处理(加载、分页、排序等)进行了隔离,关注在业务平台化逻辑上。 Service(comment-service):服务层,去平台业务的逻辑,专注在评论功能的 API 实现上,比如发布、读取、删除等,关注在稳定性、可用性上,这样让上游可以灵活组织逻辑把基础能力和业务能力剥离。 Job(comment-job)消息队列的最大用途是消峰处理 Admin(comment-admin):管理平台,按照安全等级划分服务,尤其划分运营平台,他们会共享服务层的存储层(MySQL、Redis)。运营体系的数据大量都是检索,我们使用 canal 进行同步到 ES 中,整个数据的展示都是通过 ES,再通过业务主键更新业务数据层,这样运营端的查询压力就下方给了独立的 fulltext search 系统。 Dependency(account-service、filter-service):整个评论服务还会依赖一些外部 gRPC 服务,统一的平台业务逻辑在 comment BFF 层收敛,这里 account-service 主要是账号服务,filter-service 是敏感词过滤服务。 架构设计等同于数据设计,梳理清楚数据的走向和逻辑。尽量避免环形依赖、数据双向请求等。 2. comment-service comment-service,专注在评论数据处理(认真想下 Separation of Concerns)。 开始是 comment-service 和 comment 是一层,业务耦合和功能耦合在一起,非常不利…… 阅读全文

B站架构设计2:微服务可用性设计

2021-08-14 15:17:22

摘要:一、隔离 隔离,本质上是对系统或资源进行分割,从而实现当系统发生故障时能限定传播范围和影响范围,即发生故障后只有出问题的服务不可用,保证其他服务仍然可用。 服务隔离:动静分离、读写分离 轻重隔离:核心、快慢、热点 物理隔离:线程、进程、集群、机房 1. 服务隔离 动静分离:小到 CPU 的 cacheline false sharing、数据库 mysql 表设计中避免 bufferpool 频繁过期,隔离动静表,大到架构设计中的图片、静态资源等缓存加速。本质上都体现的一样的思路,即加速/缓存访问变换频次小的。 比如 CDN 场景中,将静态资源和动态 API 分离,也是体现了隔离的思路: 降低应用服务器负载,静态文件访问负载全部通过 CDN。 对象存储存储费用最低。 海量存储空间,无需考虑存储架构升级。 静态 CDN 带宽加速,延迟低。 在比如数据库某张表中有些字段是频繁更新的,而另一些很少发生变化。我们就可以把这张表分成2张表来设计: archive: 稿件表,存储稿件的名称、作者、分类、tag、状态等信息,表示稿件的基本信息。 在一个投稿流程中,一旦稿件创建改动的频率比较低。 archive_stat: 稿件统计表,表示稿件的播放、点赞、收藏、投币数量,比较高频的更新。 随着稿件获取流量,稿件被用户所消费,各类计数信息更新比较频繁。 MySQL BufferPool 是用于缓存 DataPage 的,DataPage 可以理解为缓存了表的行,那么如果频繁更新 DataPage 不断会置换,会导致命中率下降的问题,所以我们在表设计中,仍然可以沿用类似的思路,其主表基本更新,在上游 Cache 未命中,透穿到 MySQL,仍然有 BufferPool 的缓存。 读写分离:主从、Replicaset、CQRS。 2. 轻重隔离 核心隔离:业务按照 Level 进行资源池划分(L0/L1/L2)。 核心/非核心的故障域的差异隔离(机器资源、依赖资源)。 多集群,通过冗余资源来提升吞吐和容灾能力。 快慢隔离:我们可以把服务的吞吐想象为一个池,当突然洪流进来时,池子需要一定时间才能排放完,这时候其他支流在池子里待的时间取决于前面的排放能力,耗时就会增高,对小请求产生影响。 日志传输体系的架构设计中,整个流都会投放到一个 …… 阅读全文

B站架构设计1:微服务概览与治理

2021-08-07 12:22:49

摘要:一、微服务概述 1. 单体架构 尽管也是模块化逻辑,但是最终它还是会打包并部署为单体式应用。其中最主要问题就是这个应用太复杂,以至于任何单个开发者都不可能搞懂它。应用无法扩展,可靠性很低,最终,敏捷性开发和部署变的无法完成。 我们应对的思路:化繁为简,分而治之 2. 微服务起源 大家经常谈论的是一个叫 SOA(面向服务的架构模式),它和微服务又是什么关系?你可以把微服务想成是 SOA 的一种实践。 小即是美:小的服务代码少,bug 也少,易测试,易维护,也更容易不断迭代完善的精致进而美妙。 单一职责:一个服务也只需要做好一件事,专注才能做好。 尽可能早地创建原型:尽可能早的提供服务 API,建立服务契约,达成服务间沟通的一致性约定,至于实现和完善可以慢慢再做。 可移植性比效率更重要:服务间的轻量级交互协议在效率和可移植性二者间,首要依然考虑兼容性和移植性。 3. 微服务定义 围绕业务功能构建的,服务关注单一业务,服务间采用轻量级的通信机制,可以全自动独立部署,可以使用不同的编程语言和数据存储技术。微服务架构通过业务拆分实现服务组件化,通过组件组合快速开发系统,业务单一的服务组件又可以独立部署,使得整个系统变得清晰灵活: 原子服务 独立进程 隔离部署 去中心化服务治理 缺点:基础设施的建设、复杂度高 4. 微服务的不足 Fred Brooks 在30年前写道,“there are no silver bullets”。但凡事有利就有弊,微服务也不是万能的。 微服务应用是分布式系统,由此会带来固有的复杂性。开发者不得不使用 RPC 或者消息传递来实现进程间通信;此外,必须要写代码来处理消息传递中速度过慢或者服务不可用等局部失效问题。 分区的数据库架构,同时更新多个业务主体的事务很普遍。这种事务对于单体式应用来说很容易,因为只有一个数据库。在微服务架构应用中,需要更新不同服务所使用的不同的数据库,从而对开发者提出了更高的要求和挑战。 测试一个基于微服务架构的应用也是很复杂的任务。 服务模块间的依赖,应用的升级有可能会波及多个服务模块的修改。 对运维基础设施的挑战比较大。 5. 组件服务化 传统实现组件的方式是通过库(library),库是和应用一起运行在进程中,库的局部变化意味着整个应用的重新部署。 通过服务来实现组件,意味着将应用拆散为一系列的服务运行在…… 阅读全文

构建高可用应用(十三):高并发高总结

2017-10-22 11:48:21

摘要:高并发系统架构常用案例 通用场景 日用户流量大,但是比较分散,偶尔会有用户高聚的情况; 解决思路 通过服务器架构和代码分流,系统架构设计保证它能够同时并行处理很多请求 场景特征 高并发相关常用的一些指标有响应时间(Response Time),吞吐量(Throughput),每秒查询率 QPS(Query Per Second),每秒事务处理量(TPS),并发用户数等 测试模拟工具 Apache Jmeter 2.Visual Studio性能负载测试 3.Microsoft Web Application Stress Tool 分布式 分布式应用和服务,将分层或者分割后的业务分布式部署,独立的应用服务器,数据库,缓存服务器 当业务达到一定用户量的时候,再进行服务器均衡负载,数据库,缓存主从集群 分布式静态资源,比如:静态资源上传cdn 分布式计算,比如:使用hadoop进行大数据的分布式计算 分布式数据和存储,比如:各分布节点根据哈希算法或其他算法分散存储数据。 缓存 分析:高并发业务接口多数都是进行业务数据的查询,如:商品列表,商品信息,用户信息,红包信息等,这些数据都是不会经常变化,并且持久化在数据库中. 高并发的情况下直接连接从库做查询操作,多台从库服务器也抗不住这么大量的连接请求数(前面说过,单台数据库服务器允许的最大连接数量是有限的)。 结论:缓存将是一个不错的选择。浪费内存。 异步 分析:在高并发业务中如果涉及到数据库操作,主要压力都是在数据库服务器上面,虽然使用主从分离,但是数据库操作都是在主库上操作,单台数据库服务器连接池允许的最大连接数量是有限的 。当连接数量达到最大值的时候,其他需要连接数据操作的请求就需要等待有空闲的连接,这样高并发的时候很多请求就会出现connection time out 的情况 。 结论:异步将是一个不错的选择 分层/隔 1.分层,将系统在横向维度上切分成几个部分,每个部门负责一部分相对简单并比较单一的职责,然后通过上层对下层的依赖和调度组成一个完整的系统. 2.分隔,在纵向方面对业务进行切分,将一块相对复杂的业务分割成不同的模块单元. 3.包装成高内聚低耦合的模块不仅有助于软件的开发维护,也便于不同模块的分布式部署,提高网站的并发处理能力和功能扩展. 比如用户中心可以分割成:账户信息模块,订单模块,充…… 阅读全文

构建高可用应用(十二):负载均衡

2017-09-21 20:54:57

摘要:参考 什么是负载均衡--阿里云 反向代理 内容服务器的替身 如果内容服务器具有必须保持安全的敏感信息,如信用卡号数据库,可在防火墙外部设置一个代理服务器作为内容服务器的替身。 当外部客户机尝试访问内容服务器时,会将其送到代理服务器。 实际内容位于内容服务器上,在防火墙内部受到安全保护。 代理服务器位于防火墙外部,在客户机看来就像是内容服务器。 代理服务器成为安全数据库和可能的恶意攻击之间又一道屏障。 即便这道屏障打破,充其量也仅限于访问单个事务中所涉及的信息。 未经授权的用户无法访问到真正的内容服务器,因为防火墙通路只允许代理服务器有权进行访问。 内容服务器的负载均衡器 可以在一个组织内使用多个代理服务器来平衡各 Web 服务器间的网络负载。 在此模型中,可以利用代理服务器的高速缓存特性,创建一个用于负载平衡的服务器池。 对于客户机发往真正服务器的请求,代理服务器座位中间调停者,将所请求的文档存入高速缓存。 如果有不止一个代理服务器,DNS 采用“循环复用法”选择其 IP 地址,随机地为请求选择路由。 即便是同一个 URL发出请求,所采取的路由每次都可能经过不同的代理服务器。 特征: 内容服务器可以处理更高的负载,并且比其独自工作时更有效率。 适用于处理高用量内容服务器的请求 负载均衡 四层负载均衡 四层负载均衡工作在 OSI 模型的传输层,由于在传输层,只有 TCP/UDP 协议,这两种协议中除了包含源 IP、目标 IP 以外,还包含源端口号及目的端口号。 四层负载均衡服务器在接受到客户端请求后,以后通过修改数据包的地址信息( IP+端口号 )将流量转发到应用服务器 七层负载均衡 七层负载均衡工作在 OSI 模型的应用层,应用层协议较多,常用 HTTP、Radius、DNS 等。 七层负载就可以基于这些协议来负载。 这些应用层协议中会包含很多有意义的内容。 LVS(Linux Virtual Server) 也就是 Linux 虚拟服务器,是一个由章文嵩博士发起的自由软件项目。 使用 LVS 技术要达到的目标是:通过 LVS 提供的负载均衡技术和 Linux 操作系统实现一个高性能、高可用的服务器群集,它具有良好可靠性、可扩展性和可操作性。从而以低廉的成本实现最优的服务性能。 SLB 阿里云当前提供四层和七层的负载均衡服务。 四层采用开源软件L…… 阅读全文

构建高可用应用(十一):架构集群

2017-09-16 10:41:18

摘要:高并发高可用角度架构演进 单机应用(WebSite) 渐渐的随着用户量的增加, 问题:一台服务器已经不够用了,服务器不稳定。挑战:高可用/高并发。 解决方式:于是我们将准备两台服务器搭成集群 简单集群(WebSite) 搭完集群之后,假如原来十个用户访问一台服务器,现在平均开,五个人访问上面的服务器,五个人访问另一个服务器。 用户的体验就会稍微好一点。 好处:简单高可用,假如其中一台服务器挂了,是不影响用户访问的,因为用户可以访问另一台好的服务器 问题:这样做有一个局限性,就是同时存在两个服务器,就会同时存在两个外网IP/域名 。 解决方式:于是我们增加了一个代理服务器,用户不需要记住两个服务器的IP或域名了,只要记住一台(代理服务器)IP就可以 负载均衡集群(WebSite) 增加代理服务器后,用户不需要记住两个服务器的IP或域名了,只要记住一台(代理服务器)IP就可以了。由代理服务器来负责分发用户是访问服务器A还是访问服务器B。用户具体是访问服务器A还是访问服务器B,我们可以通过nginx里面的权重设置来决定的。 好处:服务器高可用,户不需要记住两个服务器的IP或域名了,只要记住一台(代理服务器)IP就可以 问题:这样做不少局限性,数据的存储问题,服务器缺少角色分工,如磁盘损坏,数据是不安全的。 解决方式:于是这里我们使用了JAVA的MVC设计思想,我们将数据进行了抽取,服务器A和服务器B仅负责动态代理的分发,而不负责数据的存储,具体的数据放到数据服务器当中,数据库分离 MVC集群(WebSite) 增加代理服务器后,用户不需要记住两个服务器的IP或域名了,只要记住一台(代理服务器)IP就可以了。由代理服务器来负责分发用户是访问服务器A还是访问服务器B。用户具体是访问服务器A还是访问服务器B,我们可以通过nginx里面的权重设置来决定的。 好处:服务器高可用,户不需要记住两个服务器的IP或域名了,只要记住一台(代理服务器)IP就可以 问题:用户通过代理服务器分发到应用服务器,而应用服务器负责从数据库服务器进行数据的读取和写入。 解决方式:这里是关系型数据库,是遵循原子性、一致性、隔离性、持久性四大特性的;这时候是业务层分离的,即主服务器负责写,从服务器负责读,这就是数据的一致性和主从库读写分离。 数据库集群(DataBase) 用户通过代理服务器分发…… 阅读全文

构建高可用应用(十):信息自动化

2017-09-12 13:17:27

摘要:持续发布/部署需求 持续部署和持续发布[CI/CD]: 复杂软件架构,往往带来更多的地面分层,更多的软件节点。系统的节点发布就会变得很麻烦。特别微服务 系统得持续发布,持续部署就是为了解决这些问题 持续集成: 强调开发人员提交了新代码之后,立刻进行构建、(单元)测试,根据测试结果,我们可以确定新代码和原有代码能否正确地集成在一起 持续交付: 是在持续集成的基础上,将集成后的代码部署到更贴近真实运行环境(类生产环境)中。比如,我们完成单元测试后,可以把代码部署到连接数据库的Staging环境中更多的测试 持续集成 持续集成(Continuous Integration, 持续集成) 持续集成是一种软件开发实践,即团队开发成员经常集成他们的工作,通常每个成员每天至少集成一次,也就意味着每天可能会发生多次集成。每次集成都通过自动化的构建(包括编译,发布,自动化测试)来验证,从而尽早地发现集成错误。 常用的工具:Hudson和Jenkins 持续部署 持续部署(Continuous Delivery,持续交付) 在持续集成的基础上,将集成后的代码部署到更贴近真实运行环境(类生产环境)中。比如,我们完成单元测试后,可以把代码部署到连接数据库的Staging环境中更多的测试。如果代码没有问题,可以继续手动部署到生产环境。 Jenkins实现CD: https://blog.csdn.net/xiangnan10/article/details/80332866?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.nonecasedepth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.nonecase 自动化测试需求 复杂得软件架构,如:PAAS,SAAS,IAAS。过多得分层带来自动化部署,往往也带来自动化测试的需求。 对于自动化,用代码来代替手工,软件测试就是在预设条件下运行系统或应用程序,评估运行结果,预先条件应包括正常条件和异常条件。 Selenium 架构图 自动化运维需求 解决中小形的架构问题: 1.开发人员兼职完成,监控…… 阅读全文