JVM
常规
- 画一张图展示 Xmx、Xms、Xmn、Meta、DirectMemory、Xss 这些内存参数的关系。
进阶
从Classloader到模块化,动态加载的插件机制。
- 使用自定义Classloader机制,实现xlass的加载。
- 实现xlass打包的xar(类似class文件打包的jar)的加载:xar里是xlass。
- 基于自定义Classloader实现类的动态加载和卸载:需要设计加载和卸载。
- 基于自定义Classloader实现模块化机制:需要设计模块化机制。
- 使用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