面试阿里后的总结

来源:互联网 发布:nginx java应用 编辑:程序博客网 时间:2024/06/07 06:00
毕业从事java开发工作4年,被别人面试过好多次,也面试过别人,感觉人跟人的差距可以好大,有的人工作没几年,但技术广度和深度都很够;有的人工作近10年,好多基础原理都不明白。今年一个月内面了3次阿里天猫3个不同部门,全在首轮电面挂了,好打击,也感觉好失败,浪费了不少机会总结了一下,技术广度是够了,但技术深度不够,但感觉还不够扎实,尤其某些技术细节了解得不够透彻看的书够多,但都不够深入,有不少没有亲自去实践,说白了就是懒,技术人员需要不断努力学习看技术书是比较烧脑的一个过程,技术能力不是你工作多少年决定的,而是你学了多少决定的推荐一些书给各位<<深入理解计算机系统>> 这本书很好啊,神器啊,值得深读<<深入理解Java虚拟机>> 周志明 <<数据结构和算法>> java版<<并发编程艺术>> 阿里技术专家写的<< 亿级流量网站架构核心技术>> 开涛哥的<<springboot实战教程>>   快速上手<<redis源码分析>>   <<高性能MySQL>>现在云技术是趋势,hadoop我觉得还是必须要学的<<hadoop权威指南>>下面随便写了点被面的知识点,技术要工作之后不断深究,不能偷懒。消息队列描述:消息队列中间件是分布式系统中重要的组件作用:异步处理,应用解耦,流量削锋和消息通讯。例子:注册-发送邮件      订单系统,库存系统      抢购-放入消息队列-异步批量处理      日志处理常用的:rabbitmq,rocketmq,kafaka非主流的:redis消息队列主要四大问题:生产失败,消息丢失,消息重复消费如何处理,消息顺序性生产者-> 队列-> 消费者生产失败可以重发加个3次确认机制消息丢失可以同步持久化到硬盘,当性能会降低消息重复客户端可以根据id自己做去重处理比较简单有效的实现消息顺序性的方式就是单线程生产者+单线程消费者+每个消费线程对应一个单独队列, 排除消息丢失的情况,可以做到严格有序。消息队列的投递方式可以分为push和pull2种,一种模型的某些场景下的优点,在另一些场景就可能是缺点。无论是push还是pull,都存在各种的利弊。push的优点就是及时性,缺点就是受限于消费者的消费能力,可能造成消息的堆积,broker会不断给消费者发送不能处理的消息。pull的优点的就是主动权掌握在消费方,可以根据自己的消息速度进行消息拉取,缺点就是消费方不知道什么时候可以获取的最新的消息,会有消息延迟和忙等。发布和订阅主动推,和自己拉去,先进后出,先进先出缓存服务端缓存,客户端缓存,广域网缓存-cdn服务端缓存:jvm缓存,堆外缓存,分布式缓存,本地硬盘缓存,静态化客户端缓存:浏览器缓存,app客户端缓存jvm缓存 分布式缓存 redis缓存redis 3.0支持集群高可用快速选主策略。例如zookepper数据分主从备份负载均衡:负载均衡,失败重试,健康检查,动态切换限流降级:降级预警,配置中心,断融机制,读写服务降级隔离:冷热数据隔离,读写隔离,动静隔离超时和重试预测和预案缓存雪崩使用全局互斥锁,当缓存失效,节点从db获取数据 load进缓存,再获取原有的失效时间基础上增加一个随机值,防止同时失效,集体穿透到数据库缓存永远不过期,但要定时刷新使用断容器组件hystrix,具有降级策略key-value存储系统,数据都是缓存在内存中Memcached区别:它支持存储的value类型相对更多               redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件redis3.0集群默认是3主3从,槽16384当查找某个key不在所在节点会返回所在的节点名提高可用性和实时性,没法实时强一致性,只保证最终一致性持久化到硬盘,有同步和异步,看产品要求线程两种实现方式:继承Thread类、实现Runnable接口wait():释放占有的对象锁,线程进入等待池,释放cpu,而其他正在等待的线程即可抢占此锁,获得锁的线程即可运行程序。而sleep()不同的是,线程调用此方法后,会休眠一段时间,休眠期间,会暂时释放cpu,但并不释放对象锁。也就是说,在休眠期间,其他线程依然无法进入此代码内部。休眠结束,线程重新获得cpu,执行代码。wait()和sleep()最大的不同在于wait()会释放对象锁,而sleep()不会!notify(): 该方法会唤醒因为调用对象的wait()而等待的线程,其实就是对对象锁的唤醒,从而使得wait()的线程可以有机会获取对象锁。调用notify()后,并不会立即释放锁,而是继续执行当前代码,直到synchronized中的代码全部执行完毕,才会释放对象锁。JVM则会在等待的线程中调度一个线程去获得对象锁,执行代码。需要注意的是,wait()和notify()必须在synchronized代码块中调用。newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行synchronized 都是可以重入互斥锁:可以支持一个线程对锁的重复获取monitorenter和monitorexitlock区别:自旋锁lock要自己加锁去锁,一定要在finally里面去锁Synchronized锁非公平锁 lock可以设置成公平锁但这样性能较差lock锁绑定多个条件,一个ReentrantLock对象可以同时绑定对个对象。lock原理lock它通过一个int类型的状态变量state和一个FIFO队列volatile 去掉编译期间优化重排序,直接从主内存获取值,而不是线程工作内存ReentrantReadWriteLock可重入读写锁(读写锁的一个实现)两者都有lock,unlock方法。写写,写读互斥;读读不互斥。可以实现并发读的高效线程安全代码CAS交换并且比较,java有原子类AtomicInteger乐观锁 AtomicStampedReference 解决ABA问题BIO NIO AIOBIO 一个Socket链接一个线程,消耗大,同步堵塞, 类似酒店里面的包厢专厢服务员 NIO的最重要的地方是当一个连接创建后,不需要对应一个线程,这个连接会被注册到多路复用器上面,所以所有的连接只需要一个线程就可以搞定NIO 一个线程或者多个处理多个Socket,同步非堵塞 ,酒店里面的大厅 服务员AIO 异步非堵塞 操作系统主动通知应用程序,类似  酒店订餐,然后顾客先去玩,菜好了,酒点会打电话通知当进行读写操作时,只须直接调用API的read或write方法即可。这两种方法均为异步的,对于读操作而言,当有流可读取时,操作系统会将可读的流传入read方法的缓冲区,并通知应用程序同步阻塞IO:在此种方式下,用户进程在发起一个IO操作以后,必须等待IO操作的完成,只有当真正完成了IO操作以后,用户进程才能运行。JAVA传统的IO模型属于此种方式!同步非阻塞IO:在此种方式下,用户进程发起一个IO操作以后边可返回做其它事情,但是用户进程需要时不时的询问IO操作是否就绪,这就要求用户进程不停的去询问,从而引入不必要的CPU资源浪费。其中目前JAVA的NIO就属于同步非阻塞IO。异步阻塞IO:此种方式下是指应用发起一个IO操作以后,不等待内核IO操作的完成,等内核完成IO操作以后会通知应用程序,这其实就是同步和异步最关键的区别,同步必须等待或者主动的去询问IO是否完成,那么为什么说是阻塞的呢?因为此时是通过select系统调用来完成的,而select函数本身的实现方式是阻塞的,而采用select函数有个好处就是它可以同时监听多个文件句柄,从而提高系统的并发性! 异步非阻塞IO:在此种模式下,用户进程只需要发起一个IO操作然后立即返回,等IO操作真正的完成以后,应用程序会得到IO操作完成的通知,此时用户进程只需要对数据进行处理就好了,不需要进行实际的IO读写操作,因为真正的IO读取或者写入操作已经由内核完成了。linux提供select/poll,进程通过将一个或多个fd传递给select或poll系统调用,阻塞在select;这样select/poll可以帮我们侦测许多fd是否就绪。但是select/poll是顺序扫描fd是否就绪,而且支持的fd数量有限。linux还提供了一个epoll系统调用,epoll是基于事件驱动方式,而不是顺序扫描,当有fd就绪时,立即回调函数rollback;mysql的sql优化合理的表结构大表查询去掉表关联充分利用索引字段explan 检查mysql语句mysql一主多从双主多从,但只从一主插入数据,另一组备份keepalived+VIP 虚拟ip动态切换MyISAM 不支持事务,行级锁,还有外键索引MyISAM Merge引擎:这种类型是MyISAM类型的一种变种。合并表是将几个相同的MyISAM表合并为一个虚表。常应用于日志和数据仓innerDB 支持事务,行级锁,外键索引4 memory(heap):这种类型的数据表只存在于内存中。它使用散列索引,所以数据的存取速度非常快。因为是存在于内存中,所以这种类型常应用于临时表中。5 archive:这种类型只支持select 和 insert语句,而且不支持索引。常应用于日志记录和聚合分析方面。速度较快mysql 半同步复制,和异步复制。Mybatis:1:使用连接池,datasource,在驱动并连接的这个过程中优化并解耦  JDBC第一步其实从效率角度来看是不合适的,因为无论什么数据库都不可能支撑随机和庞大的连接数,而且不可避免的存在连接浪费的情况,Mybatis就封装了这些优化的方法。2:统一sql存取到XML  如果代码写在java块中,在团队合作中很可能出现两个交叉业务的代码使用类似的sql语句,而开发人员的工作本身没有交集,那就代表sql语句肯定是无法复用的。而且对sql的修改,就代表着对java文件的修改,需要重新编译和打包部署(比如常见的状态值更改,sql修改随着业务变化必然存在修改)。  mybatis将sql统一存取到xml中,就算存在业务交叉,但因为统一配置的缘故,sql在xml中一目了然,两个跨team的程序员可以看到对方的sql,来判断自己是否需要重用。并且使用xml配置可以减少代码编译。  还有就是在java中拼写长sql太恶心了。3:参数和结果集映射  sql的方式需要传入参数,如果存在多条件“或类型”的查询(列表查询的查询条件允许空),那就代表你必须传参进行sql拼接,就算使用xml的方式也不行。要么每个业务独立配置xml中的sql,要么还是写入java代码中,或者以工具的方式进行自动拼接。  Mybatis使用映射的方式,方便model管理参数,同时以解析器的方式将参数动态拼接到sql(sqlmaper里那些标签),由于是model映射,连查询结果都可以统一映射,方便取出和运算。而且mybatis对查询结果集进行了缓存处理,使得重复查询进一步进行了优化。4:对多重复sql进行复用封装  比如模板方法,将常用sql模块化,直接调用。比如通用的save和getID之类的,只有表名和字段名有变化。


原创粉丝点击