JVM

常规

  • 画一张图展示 Xmx、Xms、Xmn、Meta、DirectMemory、Xss 这些内存参数的关系。

进阶

从Classloader到模块化,动态加载的插件机制。

  1. 使用自定义Classloader机制,实现xlass的加载。
  2. 实现xlass打包的xar(类似class文件打包的jar)的加载:xar里是xlass。
  3. 基于自定义Classloader实现类的动态加载和卸载:需要设计加载和卸载。
  4. 基于自定义Classloader实现模块化机制:需要设计模块化机制。
  5. 使用xar作为模块,实现xar动态加载和卸载:综合应用前面的内容。

NIO

常规

  • 使用 GCLogAnalysis.java 对比串行 / 并行 / CMS / G1。

  • 使用压测工具(wrk 或 sb),压测 gateway-server-0.0.1-SNAPSHOT.jar。

  • netty实现后端 http 访问。

  • netty实现过滤器。

  • netty实现路由。

进阶

实现一个http 文件服务器和一个ftp文件服务器。

  • 实现文件列表展示:http直接网页展示列表即可。ftp支持cd、ls命令。
  • 实现文件上传下载:http上传不需要支持multi-part,直接post文件内容即可。ftp只需要支持主动模式或被动模式的一种。
  • 支持断点续传:http下载需要实现range,上传需要自己设计服务器端的分片方式并记录。ftp需要实现retr,stor,rest命令。
  • 实现多线程文件上传下载:基于断点续传,需考虑客户端分片方式,多线程调度。
  • 实现爬虫爬取前面实现的服务器上所有文件:需要考虑html解析,记录多个文件的传输进度,位置等。

多线程&并发

常规

  • 思考有多少种方式,在 main 函数启动一个新线程,运行一个方法,拿到这个方法的返回值后,退出主线程
  • 列举常用的并发操作 API 和工具类,简单分析其使用场景和优缺点。
  • 思考:什么是并发?什么是高并发?实现高并发高可用系统需要考虑哪些因素,对于这些你是怎么理解的?
  • 思考:还有哪些跟并发类似 / 有关的场景和问题,有哪些可以借鉴的解决办法。
  • 多线程和并发相关知识体系。

进阶

  • 基于基本类型和数组,实现ArrayList/LinkedList,支持自动扩容和迭代器

  • 基于基本类型和数组和List,HashMap/LinkedHashMap功能,处理hash冲突和扩容

  • 考虑List和Map的并发安全问题,基于读写锁改进安全问题

  • 考虑List和Map的并发安全问题,基于AQS改进安全问题

  • 编写测试代码比较它们与java-util/JUC集合类的性能和并发安全性

  • 实现一个订单处理Service,模拟处理100万订单。

  • 使用多线程方法优化订单处理,对比处理性能

  • 使用并发工具和集合类改进订单Service,对比处理性能

  • 使用分布式集群+分库分表方式处理拆分订单,对比处理性能

  • 使用读写分离和分布式缓存优化订单的读性能

spring&orm

  • 使 Java 里的动态代理,实现一个简单的 AOP。

  • 写代码实现 Spring Bean 的装配,方式越多越好(XML、Annotation 都可以)。

  • 实现一个 Spring XML 自定义配置,配置一组 Bean,例如:Student/Klass/School。

  • 将网关的 frontend/backend/filter/router 线程池都改造成 Spring 配置方式;

  • 基于 AOP 改造 Netty 网关,filter 和 router 使用 AOP 方式实现;

  • 基于前述改造,将网关请求前后端分离,中级使用 JMS 传递消息;

  • 尝试使用 ByteBuddy 实现一个简单的基于类的 AOP;

  • 尝试使用 ByteBuddy 与 Instrument 实现一个简单 JavaAgent 实现无侵入下的 AOP。

  • 总结一下,单例的各种写法,比较它们的优劣。

  • maven/spring 的 profile 机制,都有什么用法?

  • 总结 Hibernate 与 MyBatis 的各方面异同点。

  • 实现自动配置和 Starter。

  • MyBatis-generator 的用法和原理,自定义 TypeHandler 处理复杂类型。

  • 研究JDBC 接口和数据库连接池,掌握它们的设计和用法:

    • 1)使用 JDBC 原生接口,实现数据库的增删改查操作。
    • 2)使用事务,PrepareStatement 方式,批处理方式,改进上述操作。
    • 3)配置 Hikari 连接池,改进上述操作。
  • 基于 AOP 和自定义注解,实现 @MyCache(60) 对于指定方法返回值缓存 60 秒。

  • 自定义实现一个数据库连接池,并整合 Hibernate/Mybatis/Spring/SpringBoot。

  • 基于 MyBatis 实现一个简单的分库分表 + 读写分离 + 分布式 ID 生成方案。

  • 设计模式,思考如何用设计模式解决问题。

  • 深入了解 Google 和 Alibaba 编码规范。

数据库

  • 基于电商交易场景(用户、商品、订单),设计一套简单的表结构。

  • 尝试对各种数据库测试 100 万订单数据的增删改查性能。

  • 尝试对 MySQL 不同引擎下测试 100 万订单数据的增删改查性能。

  • 模拟 1000 万订单数据,测试不同方式下导入导出(数据备份还原)MySQL 的速度,包括 jdbc 程序处理和命令行处理。思考和实践,如何提升处理效率。

  • 对 MySQL 配置不同的数据库连接池(DBCP、C3P0、Druid、Hikari),测试增删改查 100 万次,对比性能,生成报告。

  • 插入 100 万订单模拟数据,测试不同方式的插入效率

  • 插入 1000 万订单模拟数据,测试不同方式的插入效

  • 使用不同的索引或组合,测试不同方式查询效率

  • 调整测试数据,使得数据尽量均匀,模拟 1 年时间内的交易,计算一年的销售报表:销售总额,订单数,客单价,每月销售量,前十的商品等等(可以自己设计更多指标)

  • 尝试自己做一个 ID 生成器(可以模拟 Seq 或 Snowflake)

  • 尝试实现或改造一个非精确分页的程序

  • MySQL配置异步复制,半同步复制、组复制

  • 读写分离 - 动态切换数据源版本 1.0

  • 读写分离 - 数据库框架版本 2.0

  • 读写分离 - 数据库中间件版本 3.0

  • 配置 MHA,模拟 master 宕机

  • 配置 MGR,模拟 master 宕机

  • 配置 Orchestrator,模拟 master 宕机,演练 UI 调整拓扑结构

分库分表&分布式事务

  • 分析前面设计的表,是否可以做垂直拆分

  • 设计对前面的订单表数据进行水平分库分表,拆分2个库,每个库16张表并在新结构在演示常见的增删改查操作。

  • 模拟1000万的订单单表数据,迁移到上面的分库分表中

  • 重新搭建一套4个库各64个表的分库分表,将上面的数据迁移到新分库

  • 列举常见的分布式事务,简单分析其使用场景和优缺点。

  • 基于 hmily TCC 或 ShardingSphere 的 Atomikos XA 实现一个简单的分布式事务应用 demo

  • 基于 ShardingSphere narayana XA 实现一个简单的分布式事务 demo。

  • 基于 seata 框架实现 TCC 或 AT 模式的分布式事务 demo。

  • 设计实现一个简单的 XA 分布式事务框架 demo,只需要能管理和调用 2 个 MySQL 的本地事务即可,不需要考虑全局事务的持久化和恢复、高可用等。

  • 设计实现一个 TCC 分布式事务框架的简单 Demo,需要实现事务管理器,不需要实现全局事务的持久化和恢复、高可用等。

  • 设计实现一个 AT 分布式事务框架的简单 Demo,仅需要支持根据主键 id 进行的单个删改操作的 SQL 或插入操作的事务。

RPC&微服务

  • 实现简单的Protocol Buffer/Thrift/gRPC(选任一个)远程调用demo。
  • 实现简单的WebService-Axis2/CXF远程调用demo。
  • 改造自定义RPC的程序:
    • 1)尝试将服务端写死查找接口实现类变成泛型和反射
    • 2)尝试将客户端动态代理改成AOP,添加异常处理
    • 3)尝试使用Netty+HTTP作为client端传输方式

升级自定义RPC的程序:

  • 1)尝试使用压测并分析优化RPC性能

  • 2)尝试使用Netty+TCP作为两端传输方式

  • 3)尝试自定义二进制序列化

  • 4)尝试压测改进后的RPC并分析优化

  • 5)尝试将fastjson改成xstream

  • 6)尝试使用字节码生成方式代替服务端反射

  • 按dubbo-samples项目的各个demo学习具体功能使用。

  • 结合dubbo+hmily,实现一个TCC外汇交易处理:

    • 1)用户A的美元账户和人民币账户都在A库,使用1美元兑换7人民币;
    • 2)用户B的美元账户和人民币账户都在B库,使用7人民币兑换1美元;
    • 3)设计账户表,冻结资产表,实现上述两个本地事务的分布式事务。

尝试扩展Dubbo

  • 1)自定义序列化,实现Dubbo的序列化扩展;

  • 2)实现Dubbo的RPC扩展;

  • 3)在Dubbo的filter机制上,实现REST权限控制,可参考dubbox;

  • 4)实现一个自定义Dubbo的Cluster/Loadbalance扩展,如果一分钟内调用某个服务提供者超过10次,则拒绝提供服务直到下一分钟;

  • 5)整合Dubbo+Sentinel,实现限流功能;

  • 6)整合Dubbo与Skywalking,实现全链路性能监控。

  • rpcfx1.1: 给自定义RPC实现简单的分组(group)和版本(version)。

  • rpcfx2.0: 给自定义RPC实现:

    • 1)基于zookeeper的注册中心,消费者和生产者可以根据注册中心查找可用服务进行调用(直接选择列表里的最后一个)。
    • 2)当有生产者启动或者下线时,通过zookeeper通知并更新各个消费者,使得各个消费者可以调用新生产者或者不调用下线生产者。
  • 在2.0的基础上继续增强rpcfx实现:

    • 1)3.0: 实现基于zookeeper的配置中心,消费者和生产者可以根据配置中心配置参数(分组,版本,线程池大小等)。
    • 2)3.1:实现基于zookeeper的元数据中心,将服务描述元数据保存到元数据中心。
    • 3)3.2:实现基于etcd/nacos/apollo等基座的配置/注册/元数据中心。
  • 在3.2的基础上继续增强rpcfx实现:

    • 1)4.0:实现基于tag的简单路由;
    • 2)4.1:实现基于Weight/ConsistentHash的负载均衡;
    • 3)4.2:实现基于IP黑名单的简单流控;
    • 4)4.3:完善RPC框架里的超时处理,增加重试参数;
  • 在4.3的基础上继续增强rpcfx实现:

    • 1)5.0:实现利用HTTP头跨进程传递Context参数(隐式传参);
    • 2)5.1:实现消费端mock一个指定对象的功能(Mock功能);
    • 3)5.2:实现消费端可以通过一个泛化接口调用不同服务(泛化调用);
    • 4)5.3:实现基于Weight/ConsistentHash的负载均衡;
    • 5)5.4:实现基于单位时间调用次数的流控,可以基于令牌桶等算法;
  • 压测5.4,并分析调优。

缓存

  • Redis的各种基本数据结构和命令。

  • 分别基于jedis,RedisTemplate,Lettuce,Redission实现redis基本操作的demo,可以使用spring-boot集成上述工具。

  • spring集成练习:

    • 1)实现update方法,配合@CachePut
    • 2)实现delete方法,配合@CacheEvict
    • 3)将示例中的spring集成Lettuce改成jedis或redisson。
  • 基于Redis封装分布式数据操作:

    • 1)在Java中实现一个简单的分布式锁;
    • 2)在Java中实现一个分布式计数器,模拟减库存
  • 基于Redis的PubSub实现订单异步处理

  • 基于其他各类场景,设计并在示例代码中实现简单demo:

    • 1)实现分数排名或者排行榜;
    • 2)实现全局ID生成;
    • 3)基于Bitmap实现id去重;
    • 4)基于HLL实现点击量计数。
    • 5)以redis作为数据库,模拟使用lua脚本实现前面课程的外汇交易事务。
  • 升级改造项目:

    • 1)实现guava cache的spring cache适配;
    • 2)替换jackson序列化为fastjson或者fst,kryo;
    • 3)对项目进行分析和性能调优。
  • 以redis作为基础实现上个模块的自定义rpc的注册中心。

  • 配置 redis 的主从复制,sentinel 高可用,Cluster 集群

  • redission 的各种功能

  • hazelcast 的各种功能

  • 搭建 hazelcast 3 节点集群,写入 100 万数据到一个 map,模拟和演 示高可用

MQ

  • 搭建ActiveMQ服务,基于JMS,写代码分别实现对于queue和topic的消息生产和消费

  • 基于数据库的订单表,模拟消息队列处理订单:

    • 1)一个程序往表里写新订单,标记状态为未处理(status=0);
    • 2)另一个程序每隔100ms定时从表里读取所有status=0的订单,打印一下订单数据,然后改成完成status=1;
    • 考虑失败重试策略,考虑多个消费程序如何协作。
  • 将上述订单处理场景,改成使用ActiveMQ发送消息处理模式。

  • 搭建ActiveMQ的network集群和master-slave主从结构。

  • 基于ActiveMQ的MQTT实现简单的聊天功能或者Android消息推送。

  • 搭建RabbitMQ,用Java代码实现简单的AMQP协议操作。

  • 搭建RabbitMQ集群,重新实现前面的订单处理。

  • 使用Apache Camel打通上述ActiveMQ集群和RabbitMQ集群,实现所有写入到ActiveMQ上的一个队列q24的消息,自动转发到RabbitMQ。

  • 压测ActiveMQ和RabbitMQ的性能

  • 搭建一个3节点Kafka集群,测试功能和性能;实现spring kafka下对kafka集群的操作

  • 安装kafka-manager工具,监控kafka集群状态。

  • Kafka各种生产者和消费者特性。

  • Kafka金融领域实战:在证券或者外汇、数字货币类金融核心交易系统里,对于订单的处理,大概可以分为收单、定序、撮合、清算等步骤。其中我们一般可以用mq来实现订单定序,然后将订单发送给撮合模块。

    • 1)收单:请实现一个订单的rest接口,能够接收一个订单Order对象;
    • 2)定序:将Order对象写入到kafka集群的order.usd2cny队列,要求数据有序并且不丢失;
    • 3)撮合:模拟撮合程序(不需要实现撮合逻辑),从kafka获取order数据,并打印订单信息,要求可重放, 顺序消费, 消息仅处理一次。
  • 基于内存Queue实现生产和消费API

    • 1)创建内存Queue,作为底层消息存储
    • 2)定义Topic,支持多个Topic
    • 3)定义Producer,支持Send消息
    • 4)定义Consumer,支持Poll消息
  • 去掉内存Queue,设计自定义Queue,实现消息确认和消费offset

    • 1)自定义内存Message数组模拟Queue。
    • 2)使用指针记录当前消息写入位置。
    • 3)对于每个命名消费者,用指针记录消费位置。
  • 拆分broker和client(包括producer和consumer)

    • 1)将Queue保存到web server端
    • 2)设计消息读写API接口,确认接口,提交offset接口
    • 3)producer和consumer通过httpclient访问Queue
    • 4)实现消息确认,offset提交
      • 单机
      • 集群
    • 5)实现consumer从offset增量拉取
  • 考虑实现消息过期,消息重试,消息定时投递等策略

  • 考虑批量操作,包括读写,可以打包和压缩

  • 考虑消息清理策略,包括定时清理,按容量清理等

  • 考虑消息持久化,存入数据库,或WAL日志文件,或BookKeeper

  • 考虑将spring mvc替换成netty下的tcp传输协议

  • 对接各种技术(各条之间没有关系,可以任意选择实现)

    • 1)考虑封装 JMS 1.1 接口规范
    • 2)考虑实现 STOMP 消息规范
    • 3)考虑实现消息事务机制与事务管理器
    • 4)对接Spring
    • 5)对接Camel或Spring Integration
    • 6)优化内存和磁盘的使用

终极挑战

  • 秒杀系统的设计和实现Demo