RxLoaron's Blog

Stay Hungry,Stay Foolish

1.对比 Exception 和 Error,运行时异常与一般异常的区别

– 尽量不要捕获类似 Exception 这样的通用异常,而是应该捕获特定异常
– 不要生吞(swallow)异常。

2.fnal、fnally、fnalize 的不同
3.强引用、软引用、弱引用、幻象引用的区别
4.String、StringBufer、StringBuilder 的区别
5.反射、动态代理原理
6.int、Integer 的区别
7.Vector、ArrayList、LinkedList 的区别,熟悉集合框架、源码
8.Hashtable、HashMap、TreeMap 的不同,熟悉 HashMap 源码
9.集合的线程安全问题? ConcurrentHashMap 如何实现高效地线程安全?
10.IO 方式、NIO 如何实现多路复用?
11.Java 文件拷贝的几种方式?
12.接口、抽象类的区别?
13.常用的设计模式、常用框架中的设计模式
14.synchronized、ReentrantLock 的区别
理解锁膨胀、降级;理解偏斜锁、自旋锁、轻量级锁、重量级锁
15.

  1. 微服务

    • 一组小的服务
    • 独立的进程
    • 轻量级通信
    • 基于业务能力
    • 独立部署

    • 无集中式管理
  2. 利弊

      • 强模块化边界
      • 可独立部署
      • 技术多样性
      • 分布式复杂性
      • 最终一致性
      • 运维复杂性
      • 测试复杂性

运维团队应该运用什么手段来应对这些运维复杂性?

  1. 康威法则和微服务

classloader 机制
异步 IO 模型
IO 缓冲区移动
NIO Selector
集合框架源码
MVCC
IO 多了复用
Redis 文件事件处理器,Reactor 模式
缓存数据库一致性
AspectJ
mybatis 批量更新返回组件列表

消息模型

  • 队列模型
  • 发布-订阅模型(Publish-Subscribe Pattern)

队列模式和发布 - 订阅模式是并存的,有些消息队列同时支持这两种消息模型,比如 ActiveMQ。对比这两种模型,生产者就是发布者,消费者就是订阅者,队列就是主题,并没有本质的区别。它们最大的区别其实就是,一份消息数据能不能被消费多次的问题。

如何利用事务消息实现分布式事务

消息队列中的“事务”,主要解决的是消息生产者和消息消费者的数据一致性问题。
一个严格意义的事务实现,应该具有 4 个属性:原子性、一致性、隔离性、持久性。这四个属性通常称为 ACID 特性。
比较常见的分布式事务实现有 2PC(Two-phase Commit,也叫二阶段提交)、TCC(Try-Confirm-Cancel) 和事务消息。
事务消息适用的场景主要是那些需要异步更新数据,并且对数据实时性要求不太高的场景。
在 RocketMQ 中的事务实现中,增加了事务反查的机制来解决事务消息提交失败的问题。

如何确保消息不会丢失

分布式链路追踪系统
利用消息队列的有序性来验证是否有消息丢失
如果对消息的可靠性要求非常高,可以通过配置 Broker 参数来避免因为宕机丢消息。在收到消息后,将消息写入磁盘后再给 Producer 返回确认响应,这样即使发生宕机,由于消息已经被写入磁盘,就不会丢失消息,恢复后还可以继续消费。例如,在 RocketMQ 中,需要将刷盘方式 flushDiskType 配置为 SYNC_FLUSH 同步刷盘。
编写消费代码时需要注意的是,不要在收到消息后就立即发送消费确认,而是应该在执行完所有消费业务逻辑之后,再发送消费确认。

  • 在生产阶段,你需要捕获消息发送的错误,并重发消息。
  • 在存储阶段,你可以通过配置刷盘和复制相关的参数,让消息写入到多个副本的磁盘上,来确保消息不会因为某个 Broker 宕机或者磁盘损坏而丢失。
  • 在消费阶段,你需要在处理完全部消费业务逻辑之后,再发送消费确认。

如何处理消费过程中的重复消息

用幂等性解决重复消息问题,一般解决重复消息的办法是,在消费端,让消费消息的操作具备幂等性。
几种常用的设计幂等操作的方法

  • 利用数据库的唯一约束实现幂等
  • 为更新的数据设置前置条件
  • 记录并检查操作

消息积压如何处理

在消息的收发两端,我们的业务代码怎么和消息队列配合,达到一个最佳的性能。
要保证消费端的消费性能要高于生产端的发送性能,这样的系统才能健康的持续运行。
能导致积压突然增加,最粗粒度的原因,只有两种:要么是发送变快了,要么是消费变慢了。

开源代码该如何入手

  • 通过文档来了解开源项目
    通过看文档,快速地掌握这个软件整体的结构,它有哪些功能特性,它涉及到的关键技术、实现原理和它的生态系统等等。
  • 用以点带面的方式来阅读源码
    带着问题去读源码,最好是带着问题的答案去读源码。你每次读源码之前,确定一个具体的问题。

如何使用异步设计提升系统性能

异步思想就是,当我们要执行一项比较耗时的操作时,不去等待操作结束,而是给这个操作一个命令:“当操作完成后,接下来去执行什么。”

如何实现高性能的异步网络传输

序列化与反序列化:通过网络传输结构化的数据

序列化实现的时候,需要综合考虑数据可读性,实现复杂度,性能和信息密度这四个因素。

传输协议:应用程序之间对话的语言

在传输数据的的时候,首先要解决的就是断句问题。对于传输层来说,收到的数据是什么样的?就是一段一段的字节,但是,因为网络的不确定性,你收到的分段并不一定是我们发出去的分段。

  • 分隔符
  • 预置长度

所谓的单工通信就是,任何一个时刻,数据只能单向传输,一个人说的时候,另外一个人只能听。HTTP1 协议
在实际上设计协议的时候,一般不关心顺序,只要需要确保请求和响应能够正确对应上就可以了。这个问题可以这样解决:发送请求的时候,给每个请求加一个序号,这个序号在本次会话内保证唯一,然后在响应中带上请求的序号,这样就可以把请求和响应对应上了。这样就解决了双工通信的问题

“使用 ID 来标识请求与响应对应关系”的方法,是一种比较通用的实现双工通信的方法,可以有效提升数据传输的吞吐量。

内存管理:避免内存溢出和频繁的垃圾回收

垃圾回收完成后,还需要进行内存碎片整理,将不连续的空闲内存移动到一起,以便空出足够的连续内存空间供后续使用

垃圾回收是不可控的,而且是无法避免的。但是,可以通过一些方法来降低垃圾回收的频率,减少进程暂停的时长。使用过被丢弃的对象才是垃圾回收的目标,所以,我们需要想办法在处理大量请求的同时,尽量少的产生这种一次性对象。
对于需要频繁使用,占用内存较大的一次性对象,我们可以考虑自行回收并重用这些对象,来减轻垃圾回收的压力。

Kafka 如何实现高性能 IO

使用批量消息提升服务端处理能力
使用顺序读写提升磁盘 IO 性能
利用 PageCache 加速消息读写
ZeroCopy:零拷贝技术

缓存策略:使用缓存减少磁盘 IO

选择只读缓存还是读写缓存?唯一的区别就是,在更新数据的时候,是否经过缓存。
读写缓存的这种设计,它天然就是不可靠的,是一种牺牲数据一致性换取性能的设计。

正确使用锁保护共享数据,协调异步线程

锁的原理是:任何时间都只能有一个线程持有锁,只有持有锁的线程才能访问被锁保护的资源。
如果能不用锁,就不用锁;如果不确定是不是应该用锁,那也不要用锁。加锁和解锁过程都是需要 CPU 时间的,这是一个性能的损失。
只有在并发环境中,共享资源不支持并发访问,或者说并发访问共享资源会导致系统错误的情况下,才需要使用锁。
使用读写锁要兼顾性能和安全性

用硬件同步原语(CAS)替代锁

硬件同步原语(Atomic Hardware Primitives)是由计算机硬件提供的一组原子操作,我们比较常用的原语主要是 CAS 和 FAA 这两种。

数据压缩:时间换空间的游戏

数据压缩不仅能节省存储空间,还可以用于提升网络传输性能。
压缩它的本质是资源的置换,是一个时间换空间,或者说是 CPU 资源换存储资源的游戏。
在选择压缩算法的之前,用系统的样例业务数据做一个测试,可以帮助找到最合适的压缩算法。
如果要对流数据进行压缩,那必须把流数据划分成多个帧,一帧一帧的分段压缩。

1.确保所有表都有主键
当缺少主键,容易引起数据重复、数据不一致、查询缓慢等问题。
如果不希望非键列出现重复数据,在列上定义唯一索引以保证其完整性。

2.避免存储冗余数据
数据库规范化的目标是消除冗余数据,并在处理数据时最小化资源消耗。
通过消除冗余数据,避免插入、更新和删除时出现异常。
通过消除冗余数据,尽量减少数据的不一致性。

3.消除重复数据组
记住一个原则:列昂贵,行更宜

4.每列只存储一个属性
正确的表设计是为每个属性分配单独的列,当列包含多个属性时,搜索和分组即使有可能做,也会是极其困难的。
对于某些应用程序,有过滤列中的某部分数据(如地址或电话号码)的需求,这可能会决定列的粒度级别。
当需要重新把属性组合成报表或打印清单时,使用连接。

5.理解为什么存储计算列通常有害无益
许多数据库系统允许你在创建表时定义计算列,但应该注意性能影响,特别是在使用非确定表达式或函数的时候。
计算列会对数据库系统产生额外的开销,只有当利大于弊的时候才考虑使用它。
当不能使用索引时,使用视图来做计算通常可以作为在表里创建计算列的替代方法。

6.定义外键以确保引用完整性
由于外键约束会降低数据库的性能,大部分互联网应用程序为了追求速度,并不设置外键约束,而是仅靠应用程序自身来保证逻辑的正确性。这种情况下,外键仅仅是一个普通的列,只是它起到了外键的作用而已。

7.确保表间关系的合理性
业务是衡量数据建模是否正确的标准,并且还需要考虑应用程序的设计,
通常这有点难度,人们更倾向于使用应用程序来驱动数据模型设计,而实际应该是恰好相反的。
在现实项目中,选择不同的数据模型可能导致应用程序设计的重大变化,这些变化可能会影响应用程序的开发成本与上线时间。
再三斟酌,为了简化关系模型而合并包含相似宇段的表是否真的有意义。
在建模之前,检查你处理的数据是否是结构化数据,如果是半结构化的,则要做特殊的处理。

8.当第三范式不够时,采用更多范式

0%