系统响应慢分析案例
响应很慢,这种情况下, 是不是系统资源出现 了瓶颈。所以,先观察 CPU、内存和磁盘 I/O 等的使用情况肯定不会错。 应用程序记录大量日志top ,来观察 CPU 和内存的使用情况 观察 top 的输出,你会发现,CPU0 的使用率非常高,它的系统 CPU 使用率(sys%)为 6%,而 iowait 超过了 90%。这说明 CPU0 上,可能正在运行 I/O 密集型的进程。 进程部分的 CPU 使用情况。python 进程的 CPU 使用率已经 达到了 6%,而其余进程的 CPU 使用率都比较低,不超过 0.3%。看起来 python 是个可疑 进程。记下 python 进程的 PID 号 18940 总内存 8G,剩余内存只有 730 MB,而 Buffer/Cache 占用内 存高达 6GB 之多,这说明内存主要被缓存占用。 CPU 使用率中的 iowait 是一个潜在瓶颈,而内存部分的缓存占比较大 iostat 命令,观察 I/O 的使用情况: 磁盘 sda 的 I/O 使用率已经高达 99%,很可能已经接 近 I&...
消息队列重点问题
参考资料: 从 0 开始带你成为消息中间件实战高手 中华石杉互联网 Java 工程师面试突击(第一季) 重点 一定要在自己的核心链路里做文章,有没有可能一个关键的步骤会失败?如果这个关键步骤失败了,这个时候会怎么样?如果某个步骤没有成功,是不是需要启动后台线程定时扫描进行补偿? 所谓的核心链路,不是说查询链路,即并不是一次请求全部是查询。而是说的是数据更新链路,即一次请求过后会对你的各种核心数据进行更新,同时还会调用其他服务或者系统进行数据更新或者查询,这样的一个链路叫做系统的核心链路。针对这样的系统核心数据链路,你考虑一下有没有哪些环节拖累了性能?你能否通过在系统里打印日志的方式,排查出来核心数据链路中的每个环节的耗时是多长?哪些环节是最耗时的?有没有可能引入MQ技术把一些耗时的步骤做成异步化的方式,来优化核心数据链路的性能?如果可以的话,你应该如何设计这个技术方案?哪些环节同步执行?哪些环节要异步执行? 主动思考能力,随机应变的本事。 如果让你写一个消息队列,该如何进行架构设计?说一下你的思路。从整体了解把握住一个消息队列的架构原理,给出一些关键点出来。技术的基本原理、...
策略设计模式Strategy
Comparable 是被比较对象和比较策略没有解耦 Comparator 是被比较对象和比较策略解耦了,在真正要比较的时候才会定义比较策略。这就是策略模式****(实现比较策略和被比较对象的解耦) 相比于策略模式,非策略模式不符合开闭原则,比如Comparable想要修改比较方法,必须修改实现类的内部。而使用了策略模式的Comparator就不需要 详细版业务逻辑可能有很多方式都可以实现某个具体的功能。例如,按照购买次数对一个用户购买的全部商品进行排序,从而粗略地得知该用户复购率最高的商品,我们可以使用多种排序算法来实现这个功能,例如,归并排序、插入排序、选择排序等。 之前都是if else,新增的时候直接追加 在策略模式中,我们会将每个算法单独封装成不同的算法实现类(这些算法实现类都实现了相同的接口),每个算法实现类就可以被认为是一种策略实现,我们只需选择不同的策略实现来解决业务问题即可,这样每种算法相对独立,算法内的变化边界也就明确了,新增或减少算法实现也不会影响其他算法。 StrategyUser 是算法的调用方,维护了一个 Strategy 对象的引用,用来选择...
系统软件
编译时绑定Compile time binding :给定明确的代码 装载时绑定Load time binding:装载到内存里面不可以再修改 运行时绑定Run time binding:模块不运行就不会加载 链接:不同的二进制文件形成一个单一的可执行文件,编译的时候先生成一个符号表,之后再替换 动态链接:链接推迟到加载时或者运行时,外部模块通过动态链接库装载 装载时动态链接 运行时动态链接:减少装载时的负担,第一次调用的时候需要链接一下,所以第一次比较慢,但是之后就好了,使得程序的模块的更小一些,每次运行不是所有的模块都会调用,但是程序员不能很好的控制动态链接库,安全性不一定好
组合模式Composite
树状结构,有些包含子节点,有些只有自己 文件夹和文件的关系 快递包装和快递内容物的关系 实现 确保应用的核心模型能够以树状结构表示。 尝试将其分解为简单元素和容器。 记住, 容器必须能够同时包含简单元素和其他容器。 声明组件接口及其一系列方法, 这些方法对简单和复杂元素都有意义。 创建一个叶节点类表示简单元素。 程序中可以有多个不同的叶节点类。 创建一个容器类表示复杂元素。 在该类中, 创建一个数组成员变量来存储对于其子元素的引用。 该数组必须能够同时保存叶节点和容器, 因此请确保将其声明为组合接口类型。实现组件接口方法时, 记住容器应该将大部分工作交给其子元素来完成。 最后, 在容器中定义添加和删除子元素的方法。记住, 这些操作可在组件接口中声明。 这将会违反_接口隔离原则_, 因为叶节点类中的这些方法为空。 但是, 这可以让客户端无差别地访问所有元素, 即使是组成树状结构的元素。 注意下面实现中,容器实现的时候除了自己的增加和删除方法,继承自父接口的方法都是尽量去调用自己的孩子节点去处理,调用孩子节点的同样的方法,因为他的孩子也一定实现了这个方法。 1234567891...
缓存和数据库数据的一致性
缓存与数据库双存储双写,你只要是双写,就一定会有数据一致性的 问题 Redis 的 qps 可以达到 10 万每秒,对于一般体量的互联网公司,一台机器就够了。但不论是什么业务,都不得不面对一个棘手的问题:那就是 Redis 和源数据的一致性问题。 对高可用、成本、一致性的权衡,进入到了特事特办的场景,甚至要考虑基础设施 读多写少的情况加入缓存提高性能,如果写多读多的情况又不能容忍缓存数据不一致,那 就没必要加缓存了,可以直接操作数据库。放入缓存的数据应该是对实时性、一致性要求不是很高的数据。切记不要为了用缓存,同时又要保证绝对的一致性做大量的过度设计和控制,增加系统复杂性! 整个架构的演进和推演过程与需求息息相关,你需要掌握“推演”能力,并用实践去证明你的方案。 没有最好的设计,只有最合适的设计,和模板化的思考问题的思路。 一致性问题来源缓存:读、写、更新、删除,这些操作可能失败; 数据库:读、写、更新、删除,这些操作可能失败。 getFromDB(key) getFromRedis(key) putToDB(key,value) putToRedis(key,va...
系统监控与应用监控
很多应用都是等到用户抱怨响应慢了,或者系统崩 溃了后,才发现系统或者应用程序的性能出现了问题。虽然最终也能发现问题,但显然,这 种方法是不可取的,因为严重影响了用户的体验。要解决这个问题,就要搭建监控系统,把系统和应用程序的运行状况监控起来,并定义一系列的策略,在发生问题时第一时间告警通知。 监控系统要涵盖系统的整体资源使用情况,比如我们前面讲过的 CPU、内 存、磁盘和文件系统、网络等各种系统资源。不仅可以将系统资源的瓶颈快速暴露出 来,还可以借助监控的历史,事后追查定位问题。 而从应用程序来说,监控系统要涵盖应用程序内部的运行状态,这既包括进程的 CPU、磁盘 I/O 等整体运行状况,更需要包括诸如接口调用耗时、执行过程中的错误、内部对象的 内存使用等应用程序内部的运行状况。 系统监控USE 法指标分类专门用于性能监控的 USE(Utilization Saturation and Errors) 法。USE 法把系统资源的性能指标,简化成了三个类别,即**使用率、饱和度以及错误数**。 使用率,表示资源用于服务的时间或容量百分比。100% 的使用率,表示容量已经...
网络知识总结
processon processon 基于网络层,结合 Linux 系统的网络协议栈和网络收发流程。分析和定位网络瓶颈。定位出网络性能瓶颈后,根据瓶颈所在的协议层,进行优化。从应用程序、套接字、传输层、网络层再到链路层等,对每个层次进行逐层优化。 无法使用协议优化的时候,可以考虑,使用 DPDK 等用户态方式,绕过内核协议栈;或者,使用 XDP,在网络包进入内核协议栈前进行处理。 性能指标和工具 各层性能优化获得网络基准测试报告,然后通过相关性能工具,定位出网络性能瓶颈。再 接下来的优化工作 应用程序–主要对网络 I/O 和进程自身工作模型的优化。 网络 I/O 的角度 I/O 多路复用技术 epoll,主要用来取代 select 和 poll。是解决 C10K 问题的关键 使用异步 I/O(Asynchronous I/O,AIO)。AIO 允许应用程序同时发起很多 I/O 操作,而不用等待这些操作完成。等到 I/O 完成后,系统会用事件通知的方式,告诉应 用程序结果。不过,AIO 的使用比较复杂...
装饰者模式Decorator
简单版防止类爆炸 类继承是会造成耦合度很高 用聚合代替继承,和代理不一样的是主动权在谁手里,聚合是主动的,自己知道的,代理是被动,自己甚至不知道 Component:抽象被装饰组件,定义都有哪些功能。 ConcreteComponent:抽象被装饰组件实现类 Decorator:抽象****装饰器,不一定是接口,它持有一个Component对象实例的引用,定义一个与抽象被装饰组件一致的接口; ConcreteDecorator:具体****装饰器,负责实现装饰器角色定义的功能。 详细版我们在做一个产品的时候,可能并没有考虑到新需求的场景,此时就需要为某些组件添加新的功能来满足这些需求。 如果要符合开放-封闭的原则,我们最好不要直接修改已有的具体实现类,因为会破坏其已有的稳定性。 继承,在某些场景下是不可行的,例如,要覆盖的方法被 final 关键字修饰了,那么在 Java 的语法中就无法被覆盖。使用继承方案的另一个缺点就是整个继承树的膨胀,例如,当新需求存在多种排列组合或是复杂的判断时,那就需要写非常多的子类实现。 应该尽量多地使用组合方式进行扩展,尽量少使用继承方式进行扩...
群发红包系统
业务流程发红包 输入金额以及人数 创建红包订单(订单ID,金额,份数) 调用支付系统 红包订单支付之后红包就发出去了 钱先拆好(行锁分散,加大并发) 抢红包 抢红包业务群,检测当前是否有剩余钱 没有剩余直接返回,有剩余就将请求转发到Redis里面的list(先来先服务),同时将请求发到mq启动一个延时任务(对账作用),之后有一个worker调度中心监听Redis,也就是消费队列里面的消息。 抢红包业务群会阻塞轮询worker调度中心是否抢到红包,之后返回给用户,这个过程用户看来是同步的,只是在后端用Redis的list实现了简单排下队异步。 拆红包 抢到红包之后,计算红包的金额,计算更新剩余的红包的余额。 分支1:返回给用户 分支2:将拆红包的流水写到数据库里面(MQ异步记账) 红包结算(异常结算池) 红包入账 业务特点 个数少,人数少:小系统 个数多,人数少:美团。饿了么红包 个数多,人数大:微信群红包 个数少,人数多:春晚红包 设计思路 数据量大:分库分表 避免所有请求都到达DB:Redis 并发请求量大:Redis高可用 + 分布式ID + 消息队列 抢红包的...