一、数据库-单表1千万数据,未来1年还会增⻓多500万,性能⽐较慢,说下你的优化思路
答案:
思路
- 千万不要⼀上来就说分库分表,这个是最忌讳的事项
- ⼀定要根据实际情况分析,两个⻆度思考 - 不分库分表 - - 软优化 - - - 数据库参数调优
- - - 分析慢查询SQL语句,分析执⾏计划,进⾏sql改写
和程序改写
- - - 优化数据库索引结构
- - - 优化数据表结构优化
- - - 引⼊NOSQL和程序架构调整 - - 硬优化 - - - 提升系统硬件(更快的IO、更多的内存):带宽、
CPU、硬盘
- 分库分表 - - 根据业务情况⽽定,选择合适的分库分表策略(没有通
⽤的策略)
- - - 外卖、物流、电商领域
- - 先看只分表是否满⾜业务的需求和未来增⻓
- - - 数据库分表能够解决单表数据量很⼤的时,数据查询
的效率问题,
- - - ⽆法给数据库的并发操作带来效率上的提⾼,分表
的实质还是在⼀个数据库上进⾏的操作,受数据库
IO性能的限制
- - 如果单分表满⾜不了需求,再分库分表⼀起
结论
- 在数据量及访问压⼒不是特别⼤的情况,⾸先考虑缓存、读
- 写分离、索引技术等⽅案如果数据量极⼤,且业务持续增⻓快,再考虑分库分表⽅案
二、描述Kafka消息队列Topc、Partition、副本、Group的概念和作⽤
答案:
Topic
每条发布到Kafka集群的消息都有⼀个类别,这个类别被称为
Topic,主题的意思
Partition分区
kafka数据存储的基本单元,topic中的数据分割为⼀个或多个
partition,每个topic⾄少有⼀个partition,是有序的
⼀个Topic的多个partitions, 被分布在kafka集群中的多个
server上
消费者数量 <=⼩于或者等于Partition数量
Replication 副本(备胎)
同个Partition会有多个副本replication ,多个副本的数据是
⼀样的,当其他broker挂掉后,系统可以主动⽤副本提供服
务
默认每个topic的副本都是1(默认是没有副本,节省资源),
也可以在创建topic的时候指定
如果当前kafka集群只有3个broker节点,则replication
factor最⼤就是3了,如果创建副本为4,则会报错
基于消费者组可以实现:
基于队列的模型:所有消费者都在同⼀消费者组⾥,每条消
息只会被⼀个消费者处理
基于发布订阅模型:消费者属于不同的消费者组,假如每个
消费者都有⾃⼰的消费者组,这样kafka消息就能⼴播到所有
消费者实例上
三、⾼并发Java开发⾥⾯线程池-ThreadPoolTaskExecutor 和ThreadPoolExecutor的区别
答案:
线程池种类
ThreadPoolExecutor,这个类是JDK中的线程池类,继承⾃
Executor,⾥⾯有⼀个execute()⽅法,⽤来执⾏线程,线程
池主要提供⼀个线程队列,队列中保存着所有等待状态的线
程,避免了创建与销毁的额外开销
ThreadPoolTaskExecutor,是spring包下的,是Spring为我
们提供的线程池类 Spring异步线程池的接⼝类是
TaskExecutor,本质还是 java.util.concurrent.Executor
开发的时候spring会先搜索TaskExecutor类型的bean或者名字为 taskExecutor的Executor类型的bean,*
所以我们最好来⾃定义⼀个线程池,加⼊Spring IOC容器⾥⾯,即可覆盖现有的进⾏调优
```@Configuration
@EnableAsyncpublic class ThreadPoolTaskConfig {
@Bean("threadPoolTaskExecutor")
public ThreadPoolTaskExecutor
threadPoolTaskExecutor(){
ThreadPoolTaskExecutor
threadPoolTaskExecutor = new
ThreadPoolTaskExecutor();
//线程池创建的核⼼线程数,线程池维护线程的最少数量,
即使没有任务需要执⾏,也会⼀直存活
//如果设置allowCoreThreadTimeout=true(默认
false)时,核⼼线程会超时关闭
threadPoolTaskExecutor.setCorePoolSize(4);
//最⼤线程池数量,当线程数>=corePoolSize,且任务队列
已满时。线程池会创建新线程来处理任务
//当线程数=maxPoolSize,且任务队列已满时,线程池会拒
绝处理任务⽽抛出异常
threadPoolTaskExecutor.setMaxPoolSize(8);
//缓存队列(阻塞队列)当核⼼线程数达到最⼤时,新任务会
放在队列中排队等待执⾏
threadPoolTaskExecutor.setQueueCapacity(124);
//当线程空闲时间达到keepAliveTime时,线程会退出,直
到线程数量=corePoolSize //允许线程空闲时间60秒,当maxPoolSize的线程在空闲
时间到达的时候销毁
//如果allowCoreThreadTimeout=true,则会直到线程
数量=0
threadPoolTaskExecutor.setKeepAliveSeconds(30);
//spring 提供的 ThreadPoolTaskExecutor 线程
池,是有setThreadNamePrefix() ⽅法的。
//jdk 提供的ThreadPoolExecutor 线程池是没有
setThreadNamePrefix() ⽅法的
threadPoolTaskExecutor.setThreadNamePrefix("⼩滴课堂
Spring⾃带Async前缀:");
threadPoolTaskExecutor.setWaitForTasksToCompleteOnSh
utdown(true);
// rejection-policy:当pool已经达到max size的时候,如何
处理新任务
// CallerRunsPolicy():交由调⽤⽅线程运⾏,⽐如 main 线
程;如果添加到线程池失败,那么主线程会⾃⼰去执⾏该任务,不会等
待线程池中的线程去执⾏
//AbortPolicy():该策略是线程池的默认策略,如果线程池队列满
了丢掉这个任务并且抛出RejectedExecutionException异常。
//DiscardPolicy():如果线程池队列满了,会直接丢掉这个任务并
且不会有任何异常//DiscardOldestPolicy():丢弃队列中最⽼的任务,队列满了,
会将最早进⼊队列的任务删掉腾出空间,再尝试加⼊队列
threadPoolTaskExecutor.setRejectedExecutionHandler(n
ew ThreadPoolExecutor.CallerRunsPolicy());
threadPoolTaskExecutor.initialize();
return threadPoolTaskExecutor;
}
}
//使⽤实战, 启动类可以不加@EnableAsync,改上⾯加
@Async("threadPoolTaskExecutor") ```