龙空技术网

超全的面试知识点总结(研发体系知识点)

玄明Hanko 2018

前言:

此时同学们对“gateoneajaxterm”大概比较关切,咱们都想要分析一些“gateoneajaxterm”的相关知识。那么小编也在网上搜集了一些对于“gateoneajaxterm””的相关内容,希望各位老铁们能喜欢,我们一起来学习一下吧!

一、基础1.1 操作系统1.1.1 基本知识

1.1.2 常见Linux命令1.2 Java基础1.2.1 Hashmap

JDK1.7中

使用一个Entry数组来存储数据,用key的hashcode取模来决定key会被放到数组里的位置,如果hashcode取模后的结果相同,那么这些key会被定位到Entry数组的同一个格子里,这些key会形成一个链表;这样数据遍历时间就过长。

1.7中hashmap使用的是头插法

JDK1.8中

使用一个Node数组来存储数据,但是这个Node可能是链表结构,也可能是红黑树结构;如果插入的元素key的hashcode值相同,那么这些key也会被定位到Node数组的同一个格子里,如果不超过8个使用链表存储,超过8个,会将链表转换为红黑树

1.8中hashmap使用的是使用尾插法.

1.2.2 ConcurrentHashmap

主要是支持安全的多线程的读写

1.2.3 Spring Bean加载过程1.2.4 多线程CAS

CAS(Compare and swap 比较并交换) 一种CPU指令级的操作,保证数据一致性。内存值V、预期值A(备份值)、新值B V=A 更新值。在多线程情况下保证值的一致性。

1.2.5 equals(值相等) ==(引用相等)

java对象分为基础类型(8大基础类型 int short float long double byte char)与引用类型

基础类型 equals ==相同均为值相等引用类型(string) equals源代码中可以看到:

JDK自带的equals有两种,针对Object对象及String对象

1、String中的equals

==判断是否相等,相等直接返回true->再判断是否为string,否直接返回false->true,继续判断对象length->循环判断char是否相等

2、Object中的equals

直接return (this == obj),一般业务对象比较要改造equals方法

1.3 网络

1.3.1 Httpshttps单向加密(数字信封)

核心为公钥加密,私钥解密

https双向身份验证

在单向身份验证基础上增加服务器端对客户端的证书验证

1.3.2 TCP

【问题1】为什么需要三次握手?

相对UDP,TCP是可靠的通讯协议,是全双工通信。TCP三次握手的关键在于,序列号seq的交换确认,因为对于客户端和服务端来说,双方序列号的确认是可靠传输的关键。1、2步握手只能确定发送方发和收正常,并不能确定接收方也是发和收正常,增加了第3次握手,才能保证接收方也是发和收都正常。

【问题2】为什么连接的时候是三次握手,关闭的时候却是四次挥手?

由于服务器端回复已经响应完毕,此时客户端并不是立刻就收完了,所以服务器处于半关闭状态,等客户端完全处理完,收到通知后才完全关闭,固为4次。

【问题3】怎么简单描述三次握手,四次挥手?**

就像是C与S发微信一样

三次握手:C与S

C:我要给你发数据了

S:好的,我准备好了,你发吧

C:好的,收到

四次挥手:C与S

C:我的数据发完了

S:好的,我听到了,我看看收完了没

S:好的,已经收完了,你关闭吧

C:好的,已经关闭了

1.3.3 Http2.0优点

相对http1.x性能提升(二进制分帧、多路复用、头部压缩)

目前很多平台已开始使用http2.0

如 zhihu taobao google github juejin 等,可以打开F12看到协议这列为"h2"

1.3.4 Websocket

一般客户端向服务器发送请求后服务器会回应响应。但服务器不会主动向客户端发送请求。响应式的方式可以解决此类问题。当然传统的方式也可以达到相同的效果比如:轮询、http长连接。

1.3.5 Http Code1.4 JVM1.4.1 jvm内存模型

为了屏蔽各种硬件和操作系统对内存访问的差异,java定义了JVM内存模型

主内存->工作内存->线程

java内存模型和java运行时数据区域的关系:主内存对应着java堆和方法区,工作内存对应着java栈。

1.4.2 jvm运行时内存

1.4.3 GCGC种类GC三种收集方法:

标记清除、标记整理、复制算法

标记清除:先标记,标记完毕之后再清除,效率不高,会产生碎片

标记整理:标记完毕之后,让所有存活的对象向一端移动

复制算法:分为 8:1 的 Eden 区和 survivor 区,就是上面谈到的 YGC

GC收集器

CMS G1

1.4.4 类加载过程1.4.5 常见问题全局变量与局部变量在内存中的区别局部变量存储在栈中全局变量(java中无全局变量概念,java中叫成员变量)

成员变量均存储在方法区中,J_VM只是定义了方法这个概念,并没有定义它的具体组成_

1、jdk1.7方法区(习惯上把永久代叫方法区)

2、jdk1.8方法区(由元数据区+堆组成),其中字符串常量池被放在堆中

_

jdk1.7的永久代在jdk1.8中去掉并换成元数据区

1.5 多线程1.5.1 数据共享

1、多线程如何共享数据

线程代码相同,即runnable中的代码一致,这样可以直接共享

/** * 卖票处理 * @author yang */public class SellTicket {      //卖票系统,多个窗口的处理逻辑是相同的    public static void main(String[] args) {        Ticket t = new Ticket();        new Thread(t).start();        new Thread(t).start();    }}/** * 将属性和处理逻辑,封装在一个类中 * @author yang */class Ticket implements Runnable{    private int ticket = 10;    public synchronized void run() {        while(ticket>0){            ticket--;            System.out.println("当前票数为:"+ticket);        }    }}作者:那时年少轻狂链接:来源:慕课网本文原创发布于慕课网 ,转载请注明出处,谢谢合作
线程代码不相同,即runnable中的代码不一致,Runnable1 Runnable2,利用一个对象,把runnable中的方法封装到这个对象中去,数据也在这个对象中
public class MultiThreadShareData {    public static void main(String[] args) {        ShareData data = new ShareData();        new Thread(new MyRunnable1(data)).start();        new Thread(new MyRunnable2(data)).start();    }}class MyRunnable1 implements Runnable {    private ShareData data;    public MyRunnable1(ShareData data) {        this.data = data;    }    public void run() {        data.decrement();    }}class MyRunnable2 implements Runnable {    private ShareData data;    public MyRunnable2(ShareData data) {        this.data = data;    }    public void run() {        data.increment();    }}class ShareData {    private int j = 10;    public synchronized void increment() {        j++;        System.out.println("线程:" + Thread.currentThread().getName() + "加操作之后,j = " + j);    }    public synchronized void decrement() {        j--;        System.out.println("线程:" + Thread.currentThread().getName() + "加操作之后,j = " + j);    }}作者:那时年少轻狂链接:来源:慕课网本文原创发布于慕课网 ,转载请注明出处,谢谢合作

2、父子线程如果共享数据

通过 interitableThreadLocal实现共享

1.5.2 synchronized与lock区别

总结:建议使用synchronized,在jdk1.5之前lock优于synchronized,但在jdk1.5之后对synchronized进行了优化,后面在性能方面基本与lock一样且使用简单(有作者说"synchronized是亲生的,jdk还是会一直优化他不会让lock优于它")。

1.5.3 线程池(实现与原理)

ThreadPoolExecutor
1.6 设计模式1.6.1 概述

可以发现,设计模式好像都是类似的。越看越感觉都着不多。其实都是类似面向接口编程的一种体现,只不过侧重点不一样或者说要体现的结果不一样。

1.6.2 使用场景问题一:应对可能变化的对象实现方案:间接创建模式:工厂模式问题二:为请求指定相应的操作(类似请假审批,不同时长对应不同职位的审批人)

方案:程序根据请求动态选择操作

模式:责任链模式1.6.3 具体说明1、策略模式策略模式说明

一个行为型模式,包含多个行为或职责的业务,通过策略模式简化

public class StrategyContext {    Strategy strategy;    public StrategyContext(Strategy strategy) {        this.strategy = strategy;    }    /**     *      */    public int context(int a, int b) {        return strategy.operator(a,b);    }}

策略模式的核心为StrategyContext上下文类,持有strategy对象,在context完成操作。

测试类

public class StrategyContextTest {    public static void main(String[] args) {        Strategy strategy;        strategy = new OperationAdd();        StrategyContext strategyContext = new StrategyContext(strategy);        strategy.operator(5,2);    }}
策略模式实践如何使用策略模式解决大量使用if else 或大量switch问题

策略模式+反射

策略模式后好像使用都还是要用if else来决定调用哪个类,所以在引入策略模式后,在上下文类还要增加反射。

public class StrategyContext {    Strategy strategy;    public StrategyContext(String type) throws Exception {        Class clazz = Class.forName(type);        this.strategy = (Strategy) clazz.newInstance();    }    /**     *      */    public int context(int a, int b) {        return strategy.operator(a,b);    }

当然这里的type可以用个枚举来解决。感觉代价非常大是不是没必要,不过代码的可读性还是增强了。

p.s. 在框架里策略模式中的Context一般不会直接出现,类似spring中直接在使用时就通过注解给设置了

_

2、装饰器模式

描述:原接口Shape不变,方法数量不变,在方法实现中增加修饰

场景:

场景一:一个类功能简单,满足不了我们的需求

场景二:给原方法增加日志功能,不改变原方法,新的实现类去实现此功能,带入的对象为接口对应

特点

原接口Shape不动,增加新的装饰类ShapeDecorator原方法名不变,只是增加或修饰此方法体ColorShapeDecorator装饰类持有原对象,只是增加了修饰

public class ColorShapeDecorator extends ShapeDecorator {    public ColorShapeDecorator(Shape shape) {        super(shape);    }    @Override    public void draw() {        setColor();        shape.draw();    }    private void setColor() {       //设置画图颜色    }}

3、适配器模式

描述:原接口不变,增加方法数量

场景:

场景一:原接口不变,在基础上增加新的方法。

场景二:接口的抽象方法很多,不想一一实现,使用适配器模式继承原实现类,再实现此接口

适配器模式适合需要增加一个新接口的需求,在原接口与实现类基础上需要增加新的接口及方法。类似原接口只能method01方法,需求是增加method02方法,同时不再使用之前接口类。

新接口

public interface Targetable {    /**     *      */    public void method01();    /**     *      */    public void method02();}

原接口实现类

public class Source {    public void method01() {        // TODO implement here    }}

适配器类,用于实现新接口。继承原实现类,同时实现新接口。

public class Adapter extends Source implements Targetable {    /**     *      */    public void method02() {        // TODO implement here    }}

测试类

public class AdapterTest {    public static void main(String[] args) {        Targetable targetable = new Adapter();        targetable.method01();        targetable.method02();    }}

4、代理模式

一个类代表另一个类的功能

场景:

场景一:不改变原方法,对原方法增加耗时的计算

场景二:rpc远程调用,client端进行动态代理类似耗时计算一样,用户不用关心client的具体实现

分类静态代理模式动态代理模式说明

静态代理模式

/** * 与适配器模式的区别,适配器模式主要改变所考虑对象的接口, * 而代理模式不能改变所代理类的接口。与装饰器模式的区别, * 装饰器模式是为了增强功能,代理模式是为了加以控制 */public class ProxySigntureService implements SigntureService {    private SigntureService signatureService;    /**     * Default constructor     */    public ProxySigntureService(SigntureService signatureService) {        this.signatureService = signatureService;    }    public void sign() {        //控制对这个对象的访问        // 实现电子签名    }}
动态代理模式
public class DynamicProxySignatureService implements InvocationHandler {    private Object obj;    public DynamicProxySignatureService(Object obj) {        this.obj = obj;    }    @Override    public Object invoke(Object proxyObj, Method method, Object[] objects)            throws Throwable {        return method.invoke(obj,objects);    }}

参考文章:

5、单例模式

保证被创建一次,节省系统开销。

1)单例实现方式

饿汉式懒汉式懒汉式+Synchronized双重校验静态内部类枚举(推荐方式)

2)实现代码

饿汉式

package com.hanko.designpattern.singleton;/** * 饿汉式 (饿怕了,担心没有吃,所以在使用之前就new出来) *优点:实现简单,安全可靠 *缺点:在不需要时,就已实例化了 * @author hanko * @version 1.0 * @date 2020/9/14 18:50 */public class HungrySingleton {    //特点一 静态私有变量 直接初始化    private static HungrySingleton instance = new HungrySingleton();    //特点二 构造函数私有    private HungrySingleton(){    }    public static HungrySingleton getInstance(){        return instance;    }    public void doSomething(){        //具体需要实现的功能    }}
懒汉式
package com.hanko.designpattern.singleton;/** * 懒汉式(非常懒,所以在要使用时再去new) *优点:简单 *缺点:存在线程安全问题 * @author hanko * @version 1.0 * @date 2020/9/14 18:50 */public class SluggardSingleton {    //特点一 静态私有变量,先不初始化    private static SluggardSingleton instance;    //特点二 构造函数私有    private SluggardSingleton(){    }    //特点三 null判断,没有实例化就new    public static SluggardSingleton getInstance(){        if(instance == null){            instance = new SluggardSingleton();        }        return instance;    }    public void doSomething(){        //具体需要实现的功能    }}
懒汉式+Synchronized
package com.hanko.designpattern.singleton;/** * 懒汉式(非常懒,所以在要使用时再去new) *优点:简单 *缺点:存在线程安全问题 * @author hanko * @version 1.0 * @date 2020/9/14 18:50 */public class SluggardSingleton {    //特点一 静态私有变量,先不初始化    private static SluggardSingleton instance;    //特点二 构造函数私有    private SluggardSingleton(){    }    //特点三 null判断,没有实例化就new    public static synchronized SluggardSingleton getInstance(){        if(instance == null){            instance = new SluggardSingleton();        }        return instance;    }    public void doSomething(){        //具体需要实现的功能    }}
双重校验
package com.hanko.designpattern.singleton;/** * 双重校验 *对懒汉式单例模式做了线程安全处理增加锁机制 * volatile变量级 * synchronized 类级 * @author hanko * @version 1.0 * @date 2020/9/15 9:53 */public class DoubleCheckSingleton {    //特点一 静态私有变量,增加volatile变量级锁    private static volatile DoubleCheckSingleton instance;    //特点二 构造函数私有    private DoubleCheckSingleton(){    }    //特点三 双重null判断  synchronized类级锁    public static DoubleCheckSingleton getInstance(){        if (instance == null){            synchronized(DoubleCheckSingleton.class){                if (instance == null){                    instance = new DoubleCheckSingleton();                }            }        }        return instance;    }}
静态内部类
package com.hanko.designpattern.singleton;/** * 内部静态类方式 *优点:静态内部类不会在InnerStaticSingleton类加载时加载, * 而在调用getInstance()方法时才加载 *缺点:存在反射攻击或者反序列化攻击 * @author hanko * @version 1.0 * @date 2020/9/15 10:03 */public class InnerStaticSingleton {    //特点一:构造函数私有    private InnerStaticSingleton(){    }    //特点二:静态内部类    private static class InnerSingleton{        private static InnerSingleton instance = new InnerSingleton();    }    public InnerSingleton getInstance(){        return InnerSingleton.instance;    }    public void doSomething(){        //do Something    }}
枚举(推荐方式)
package com.hanko.designpattern.singleton;/** * 枚举实现单例简单安全 * * @author hanko * @version 1.0 * @date 2020/9/14 19:01 */public enum EnumSingleton {    INS;    private Singleton  singleton;    EnumSingleton() {        singleton = new Singleton();    }    public void doSomething(){          singleton...         //具体需要实现的功能    }}EnumSingleton.INS.doSomething();
6、工厂模式

(简单工厂、抽象工厂):解耦代码。

简单工厂:用来生产同一等级结构中的任意产品,对于增加新的产品,无能为力。

工厂方法:用来生产同一等级结构中的固定产品,支持增加任意产品。

抽象工厂:用来生产不同产品族的全部产品,对于增加新的产品,无能为力;支持增加产品族。

参考文章:

7、观察者模式

定义了对象之间的一对多的依赖,这样一来,当一个对象改变时,它的所有的依赖者都会收到通知并自动更新。

8、外观模式

提供一个统一的接口,用来访问子系统中的一群接口,外观定义了一个高层的接口,让子系统更容易使用。

9、状态模式

允许对象在内部状态改变时改变它的行为,对象看起来好像修改了它的类。与策略模式类似,策略模式侧重点在一个事的不同实现方式抽离出来,而状态模式是一个事的不同状态抽离出来(开始、进行中、结束),每次状态完成自己的业务逻辑。

总结:

适配器模式(原功能不变,增加新功能)、装饰器模式(装饰原功能)、代理模式(控制原功能)策略模式侧重点在一个事的不同实现方式抽离出来,而状态模式是一个事的不同状态抽离出来(开始、进行中、结束),每次状态完成自己的业务逻辑。二、数据存储2.1 缓存2.1.1 缓存类型本地缓存分布式缓存多级缓存(本地+分布式)2.1.2 淘汰策略FIFO淘汰最早数据LRU最近最少使用(存的最久、用的最少)

使用LinkedHashMap实现LRU

1)LinkedHashMap被get过的元素会自动放在尾项

2)LinkedHashMap链表被删除不用补位

LFU2.1.3 缓存实现LRUCache(通过LinkedHashMap本地实现)MemcacheRedisMongoDB2.1.4 缓存穿透、击穿、雪崩

1、缓存穿透 (缓存、DB均无,穿透)

简述

缓存穿透是指查询一个一定不存在的数据,由于缓存是不命中时被动写的,并且出于容错考虑,如果从存储层查不到数据则不写入缓存,这将导致这个不存在的数据每次请求都要到存储层去查询,失去了缓存的意义。在流量大时,可能DB就挂掉了,要是有人利用不存在的key频繁攻击我们的应用,这就是漏洞。

解决方案

有很多种方法可以有效地解决缓存穿透问题,最常见的则是采用布隆过滤器,将所有可能存在的数据哈希到一个足够大的bitmap中,一个一定不存在的数据会被 这个bitmap拦截掉,从而避免了对底层存储系统的查询压力。另外也有一个更为简单粗暴的方法(我们采用的就是这种),如果一个查询返回的数据为空(不管是数 据不存在,还是系统故障),我们仍然把这个空结果进行缓存,但它的过期时间会很短,最长不超过五分钟。

2、缓存击穿(缓存无、DB有,击穿)

简述

对于一些设置了过期时间的key,如果这些key可能会在某些时间点被超高并发地访问,是一种非常“热点”的数据。这个时候,需要考虑一个问题:缓存被“击穿”的问题,这个和缓存雪崩的区别在于这里针对某一key缓存,前者则是很多key。

缓存在某个时间点过期的时候,恰好在这个时间点对这个Key有大量的并发请求过来,这些请求发现缓存过期一般都会从后端DB加载数据并回设到缓存,这个时候大并发的请求可能会瞬间把后端DB压垮。

解决方案

1)使用互斥锁(mutex key)

业界比较常用的做法,是使用mutex。简单地来说,就是在缓存失效的时候(判断拿出来的值为空),不是立即去load db,而是先使用缓存工具的某些带成功操作返回值的操作(比如Redis的SETNX或者Memcache的ADD)去set一个mutex key,当操作返回成功时,再进行load db的操作并回设缓存;否则,就重试整个get缓存的方法。

SETNX,是「SET if Not eXists」的缩写,也就是只有不存在的时候才设置,可以利用它来实现锁的效果。在redis2.6.1之前版本未实现setnx的过期时间,所以这里给出两种版本代码参考:

2) "提前"使用互斥锁(mutex key):

在value内部设置1个超时值(timeout1), timeout1比实际的memcache timeout(timeout2)小。当从cache读取到timeout1发现它已经过期时候,马上延长timeout1并重新设置到cache。然后再从数据库加载数据并设置到cache中。伪代码如下:

3) "永远不过期":

这里的“永远不过期”包含两层意思: (1) 从redis上看,确实没有设置过期时间,这就保证了,不会出现热点key过期问题,也就是“物理”不过期。(2) 从功能上看,如果不过期,那不就成静态的了吗?所以我们把过期时间存在key对应的value里,如果发现要过期了,通过一个后台的异步线程进行缓存的构建,也就是“逻辑”过期 从实战看,这种方法对于性能非常友好,唯一不足的就是构建缓存时候,其余线程(非构建缓存的线程)可能访问的是老数据,但是对于一般的互联网功能来说这个还是可以忍受。

3、缓存雪崩(一批过期的key)

简述

缓存雪崩是指在我们设置缓存时采用了相同的过期时间,导致缓存在某一时刻同时失效,请求全部转发到DB,DB瞬时压力过重雪崩。

解决方案

缓存失效时的雪崩效应对底层系统的冲击非常可怕。大多数系统设计者考虑用加锁或者队列的方式保证缓存的单线程(进程)写,从而避免失效时大量的并发请求落到底层存储系统上。一个简单方案就是将缓存失效时间分散开(过期时间错开),比如我们可以在原有的失效时间基础上增加一个随机值,比如1-5分钟随机,这样每一个缓存的过期时间的重复率就会降低,就很难引发集体失效的事件。

2.2 Redis

1、支持数据类型

String Hash List Set ZSet

大多数我们会把数据序列化成json也就是string存储zset可以实现排行榜

2、分布式锁

1)Redis实现分布式锁面临的主要问题

就是能否保证分布式锁的原子性,主要体现在以下两点:

未释放误释放

2)详细说明

a、未释放

过期未释放

b、误释放

业务未完成,由于过时被释放被其它线程释放

3)实现方案

手动实现(setnx-expire) 如果不存在写入,如果存在就不写手动实现升级版(set ex px nx)RedissonSpringboot LockRegistry(推荐)

p.s. 手动实现方案需程序解决以上两问题,使用第三方的客户端或组件一般自带解决以上问题

3、单线程的redis为什么快

内存读写单线程无线程切换采用了非阻塞I/O多路复用机制2.3 MySQL2.31. MySql调优

先引用一张图片

目录图

1、SQL语句优化

开启慢查询功能

vim /etc/my.cnf[mysqld]slow-query-log = on # 开启慢查询功能slow_query_log_file = /data/slow-query.log # 慢查询日志存放路径与名称long_query_time = 5 # 查询时间超过5s的查询语句log-queries-not-using-indexes = on # 列出没有使用索引的查询语句

1)查看所有日志状态: show variables like '%quer%';

2)查看慢查询状态:show variables like 'show%'

分析SQL语句

MySql内部函数explain(查询sql的执行计划),explain返回各列的含义

table:显示这一行的数据是关于哪张表的type:这是重要的列,显示连接使用了何种类型。从最好到最差的连接类型为const、eq_reg、ref、range、index 和ALLpossible_keys:显示可能应用在这张表中的索引。如果为空,没有可能的索引。key:实际使用的索引。如果为NULL,则没有使用索引。keyjen:使用的索引的长度。在不损失精确性的情况下,长度越短越好ref:显示索引的哪一列被使用了,如果可能的话,是一个常数rows: MYSQL认为必须检查的用来返回请求数据的行数
子查询优化

子查询尽量不用或改成join

group by 优化

group by 尽量使用索引字段

limit 优化

给查询语句增加limit

2、索引优化

重复索引冗余索引检查重复及冗余索引的工具删除不用的索引

3、数据库结构优化

选择合适的数据类型表的范式化表的反范式化的使用表的垂直拆分(列拆分)表的水行拆分(行拆分)

4、配置优化

操作系统配置

1)缓存池大小

2)打开文件限制

MySQL配置

1)innodb缓冲池内存占用大小

2)innodb_buffer_pool_instances 缓冲池个数

3)innodb_log_buffer_size 缓冲的大小

4)innodb IO配置

5、服务器硬件优化

CPU 多核硬盘 raid0 raid1 raid5增加硬盘IO速度2.3.2 MySql基础问题

InnoDB myisam区别innodb支持事务、myisam不支持事务innodb不支持全文索引、myisam支持全文索引,查询性能较快innodb行级锁、myisam表级锁

三、搜索引擎

3.1 倒排索引

何为倒排索引?首先要了解索引表:由关键词为key,关键词位置属性为value组成的一张表。由于该表不是由key来确定value值,而是由value的属性值来确定key的位置,所以称为倒排索引,带有倒排索引的文件称为倒排文件。通俗的讲倒排索引就好比书的目录,通过目录咱们可以准确的找到相应的数据。下面对lucene倒排索引的结构与算法进行介绍。使用场景

倒排索引服务于es查询操作,对数据的聚合,排序则需要使用正排索引,下面我们介绍正排索引。

3.2 ES

Elasticsearch

3.3 热点分析(词频统计)

方案一、基于ElasticSearch方式方案二、基于Spark方式方案三、基于Python方式

方案一、基于ElasticSearch方式

详见文章,里面列举了各种ElasticSearch的实现样例。主要是通过ES的fielddata做聚合或调取termvector两种方式实现,当然调用方式比较多http requset、highclient、springboot data repository、elasticsearch resttemplate等调用方式

方案二、基于Spark方式

Spark是基于内存的分布式计算组件,Spark官方提供了JavaWordCount的demo,详见以下文章

方案三、基于Python方式

如果你只能实现简单的数据词频统计,python是最的方式,几行代码就可以搞定

text = "http requset highclient springboot"data = text.lower().split()words = {}for word in data:    if word not in words:        words[word] = 1    else:        words[word] = words[word] + 1result = sorted(words.items(), reverse=True)print(result)

参考文章 :

四、大数据sparkhivehadoop五、安全SQL注入XSS注入(跨站脚本攻击)CSRF(跨域攻击)六、服务架构6.1 微服务架构第一代微服务架构

springcloud dubbo

第二代微服务架构

service mesh

未来的微服务架构与技术栈

6.2 SpringCloud

网关 zuul/gateway

服务注册发现 eureka/nacos/consul

配置中心 configserver/nacos/apollo

熔断降级 hystrix/sentinel

监控 springbootadmin

链路器 sleuth+zipkin

6.3 Dubbo支持哪些协议

http dubbo rmi hessian webservice

dubbo的几种角色

注册中心

zookeeper

dubbo有哪几种配置方式

xml 注解 properties API

序列化

hessian dubbo fastjson java自带序列化

七、性能调优7.1 Java项目性能调优7.1.1 jstat jconsole7.1.2 Xrebel7.1.3 Arthas7.1.3.1 常用命令cpu占用过高

thread

死锁

thread -b

内存泄漏

dashboard

方法耗时及跟踪

trace

看源代码

jad

查看函数的参数/返回值/异常信息

watch com.Welfare batchQuerySku "{params}"

发现异常并查看异常

tt -t com.UserServiceImpl check //记录方法调用信息

tt -i 1001 //上面指令发现异常后,查看异常

tt -i 1001 -p //重新调用,重现异常

查看、更新类成员变量值

ognl '@com.Arthas@hashSet' //查看

ognl '@com.Arthas@hashSet.add("test")' //更新

7.1.3.2 项目实战针对web项目,可以跟踪servlet类

trace org.springframework.web.servlet.DispatcherServlet *
跟踪后通过watch查看出入参(发现执行的controller类)
watch  org.springframework.web.method.support.InvocableHandlerMethod doInvoke  "{params,returnObj}"
记录方法调用信息
tt -t com.wdbyte.arthas.service.UserServiceImpl mysql

通过tt -t 查看到index,然后通过index重复调用

tt -i 1001 -p
最后通过tt -i 与 trace重复配合,定位出性能消耗八、部署、集成JekinsSonarquberDockerPodmanK8s九、项目过程

项目中的问题及解决方案

9.1 架构方面

1、传统架构改造成微服务架构

微服务拆分时,数据库问题

问题说明:微服务拆分后,对应的数据库也会进行拆分。也就是原本很简单功能一个查询就解决,拆分后就得跨多个微服务查询。如果其中一张表数据较少可以代码循环的方式解决,如果每个微服务的数据都比较多就比较麻烦。

方案一:使用视图,通过视图把两个库的中表进行关联。当然这样也就违避微服务的解耦

方案二:临时表或缓存,通过临时表或缓存构建临时关联数据,使用完就清理

方案三:数据冗余,牺牲空间换时间。类似索引,牺牲索引空间换查询速度。

建议使用方案三

微服务拆分粒度

微服务粒度问题,多次讨论拆分架构。拆分是一个迭代的过程,别试着一步到位拆成很细,一开始千万别拆太细

十、项目实战10.1 排行榜方案一:mysql order by

互联网用户数据过大,排行榜性能较差

方案二:redis

redis zset 数据结构为 id、score、member。下面是具体实现的步骤

1)插入数据

zadd game 90 tomzadd game 92 samzadd game 95 hanko

2)获取范围内的排名

zrange game 0 -1 withscores //开始到集合结束的从小到大列表,-1代表结束

zrevrange game 0 -1 withscores //开始到集合结束的从大到小列表

3)获取某用户的排名

zrank game hanko

zrevrank game hanko

10.2 秒杀系统10.2.1 秒杀系统特点秒杀时大量用户会在同一时间同时进行抢购,网站瞬时访问流量激增。秒杀一般是访问请求数量远远大于库存数量,只有少部分用户能够秒杀成功。秒杀业务流程比较简单,一般就是下订单减库存。10.2.2 秒杀系统设计理念

限流: 鉴于只有少部分用户能够秒杀成功,所以要限制大部分流量,只允许少部分流量进入服务后端。

削峰:对于秒杀系统瞬时会有大量用户涌入,所以在抢购一开始会有很高的瞬间峰值。高峰值流量是压垮系统很重要的原因,所以如何把瞬间的高流量变成一段时间平稳的流量也是设计秒杀系统很重要的思路。实现削峰的常用的方法有利用缓存和消息中间件等技术。

p.s. 削峰主要是把并行请求变为串行请求

异步处理:秒杀系统是一个高并发系统,采用异步处理模式可以极大地提高系统并发量,其实异步处理就是削峰的一种实现方式。

内存缓存:秒杀系统最大的瓶颈一般都是数据库读写,由于数据库读写属于磁盘IO,性能很低,如果能够把部分数据或业务逻辑转移到内存缓存,效率会有极大地提升。

10.2.3 具体方案前端

后台

后台技术选型

10.3 抢红包

十一、团队管理

目标(目标清晰)、计划、职责(职责明确)、制度(赏罚分明)

1、木桶法则

注重团队中的薄弱环节

一只沿口不齐的木桶,它盛水的多少,不在于木桶上那块最长的木板,而在于木桶上最短的那块木板。要使木桶多盛水(提高水桶的整体效应),需要的不是去增加最长的那块木板长度,而是下工夫依次补齐木桶上最短的那些木板,这就是管理上有名的“木桶”法则。企业管理也是如此,要提高企业的效益,就必须狠抓薄弱环节,否则单位的整体工作就会受到影响。人们常说“取长补短”,即取长的目的是为了补短,只取长而不补短,就很难提高工作的整体效应。项目管理者联盟

2、羊群效应

提升自己的判断力,不盲目跟风

羊群效应是指人们经常会收到多数人的影响,而跟从大众的思想或行为,也被称为“从众效应”。羊群是一种很散乱的组织,平时在一起也是盲目地左冲右撞,一旦有一头羊动起来,其他的养也会不假思索地一哄而上,全然不顾前面可能有狼或者不远处有更好的草。因此,就是比喻人都有一种从众心理,从众心理很容易导致盲从,而盲从往往会使人陷入骗局或遭到失败。

3、“热炉”法则:

规章制度面前人人平等

热炉”法则不仅形象地阐述了规章制度的权威性,而且活灵活现地描述了惩处所需掌握的原则:(1)热炉火红,不用手去摸也知道炉子是热的,是会灼伤人的,这就是惩处的警告性原则。领导者要经常对下属进行规章制度教育,警告或劝戒不要触犯规章制度,否则会受到惩处。(2)每当碰到热炉,肯定会被火灼伤,这就是规章制度的权威性。也就是说只要触犯单位的规章制度,就一定会受到惩处。(3)当你碰到热炉时,立即就被灼伤,这就是惩处的即时性原则。惩处必须在错误行为发生后立即进行,决不拖泥带水,决不能有时间差,以达到及时改正错误行为的目的。(4)不管是谁碰到热炉,都会被灼伤,这就是规章制度的公平性原则。

4、“金鱼缸”法则:

增加管理的透明度

金鱼缸是玻璃做的,透明度很高,不论从哪个角度观察,里面的情况都一清二楚,这就是管理上的“金鱼缸”法则。“金鱼缸”法则运用到管理中,就是要求领导者必须增加规章制度和各项工作的透明度。各项规章制度和工作有了透明度,领导者的行为就会置于员工的监督之下,就会有效地防止领导者滥用权力,从而强化领导者的自我约束机制。同时,员工在履行监督义务的同时,自身的主人翁意识和责任感得到极大的提升,而敬业、爱岗和创新的精神也必将得到升华。

5、“南风”法则

真诚温暖员工

也称“温暖”法则,源于法国作家拉封丹写过的一则寓言:北风和南风比威力,看谁能把行人身上的大衣脱掉。北风首先吹得人寒冷刺骨,结果行人为了抵御北风的侵袭,便把大衣裹得紧紧的。南风则徐徐吹动,顿时风和日丽,行人觉得温暖如春,随之开始解开纽扣,继而脱掉大衣,最终南风获得了胜利。这则寓言形象地说明一个道理:温暖胜于严寒、柔性胜于刚性。领导者在管理中运用“南风”法则,就是要尊重和关心员工,以员工为本,多点“人情味”,少点官架子,尽力解决员工日常生活中的实际困难,使员工真正感觉到领导者给予的温暖,从而激发他们工作的积极性。

6、“刺猬”法则:

保持适当的距离更有利于管理

刺猬”法则讲的是:两只困倦的刺猬,由于寒冷而拥在一起。可因为各自身上都长着刺,刺得对方怎么也睡不舒服。于是它们离开了一段距离,但又冷得受不了,于是凑到一起。几经折腾,两只刺猬终于找到了一个合适的距离,既能互相获得对方的温暖又不致于被扎。“刺猬”法则就是管理和人际交往中的“心理距离效应”。心理学研究认为:领导者要搞好工作,就应该与员工保持亲密关系,这样做可以获得他们的尊重。与员工保持一定的心理距离,不仅可以避免员工之间的嫉妒和紧张,而且可以减少他们的恭维、奉承、行贿等行为,防止与员工称兄道弟、吃喝不分,并在工作中丧失原则。事实上,雾里看花,水中望月,给人的是“距离美”的感觉,管理上也是如此。一个原本很受员工敬佩的领导者,往往由于与员工“亲密无间”,就会使自己的缺点显露无遗,结果在不知不觉中丧失了严肃性,不利于对其更进一步的管理。另外,“刺猬”法则还启示我们,彼此间的亲密协作是必不可少的,员工之间、管理者与员工之间、管理者之间,尽管每个人都有其特点和个性,但各自为战在工作中却是不可取的,“独木难成林”、众人划桨开大船就是这个道理。线务局的工作千头万绪,各位局领导、中层干部、管理人员,各区域局、各部室都要各司其职、各负其责、立足本岗、发挥作用,同时也要注意分工不分家、补台不包办、到位不越位,切实形成合力、发挥团队作用。

7、“青蛙原理”

时刻保持危机意识

关于“问题管理”有个著名的“青蛙原理”,说的是如果把一只青蛙扔进沸水中,青蛙肯定会马上跳出来。但是如果把一只青蛙放入冷水中逐渐加温,青蛙则会在不知不觉中丧失跳出去的能力,直至被热水烫死。这个原理是用来形容企业中存在的两种性质的问题,即显性问题和隐性问题。人们对显性问题的反应就如同青蛙对沸水的反应一样,会马上采取相应的措施,及时地将其扼杀在萌芽状态;而隐性问题由于自身的隐匿性,不易被发现,往往是等到发现时,已经对企业酿成了严重的损失。这就启示我们,很多线路障碍都是一些不起眼的小问题日积月累的结果,有客观的,但是也有主观的,跟我们的部分线务员在巡回或随工配合中的麻痹大意有关,听任一些小问题长期自由发展,最终酿成了影响线路通畅的大祸。“冰冻三尺,非一日之寒”,因此我们要时刻关注潜在的问题,而不是等小问题变大了、危机降临了再临时抱佛脚。

8、鲶鱼效应

竞争是提高效率的法宝

鲶鱼效应”来自一个古老的传说:一个小渔村的渔民靠到深海捕捉沙丁鱼(一种比较懒的鱼)为生。但由于捕鱼点距离陆地比较远,渔民捕的鱼运回渔村时,往往死掉大半,很难卖出好价钱。只有一个渔翁,他运回陆地的鱼,都是活的,总能卖出好价钱,但是他从来不让人看他的鱼舱。直到他死后,好奇的村民才发现,原来他的鱼舱里总是放着一条鲶鱼。由于鲶鱼是以捕食沙丁鱼为生,所以鲶鱼在鱼舱里会不停地追逐沙丁鱼,结果一些老弱的沙丁鱼被吃掉,但其他的沙丁鱼由于总在不停游动,所以都活着到岸。而其他渔船所捕的沙丁鱼静止不动,结果一大半都会死掉。这个传说告诉我们一个浅显的道理:“生于忧患、死于安乐”,如果一个企业缺少活力与竞争意识,没有生存的压力,就如同“沙丁鱼”一样,在“鱼舱”里混吃混喝,必然会被日益残酷的市场竞争所淘汰。一个员工也是如此,长期安于现状、不思进取,必然会成为时代的弃儿。

领导者要成为“鲶鱼”,有句俗话叫“兵熊熊一个,将熊熊一窝”。一家公司或一个部门,如果领导缺乏激情,要想手下的人有激情,那是白日做梦。最常见的情况是,领导工作不在状态,员工必然上行下效,人浮于事,缺乏创新和主动性,日复一日,年复一年,必然成了一潭死水。反之则是“强将手下无弱兵”。如果领导者本身是一条充满活力的“鲶鱼”,那么,通过整顿纪律,规范制度,改造流程,合理配置岗位和人、财、物,就能将那些无能的“沙丁鱼”吃掉、赶走,使有能耐的“沙丁鱼”得到正面的激励,从而使整个机构呈现欣欣向荣的景象。因此,作为领导者,如果自己的公司没有激情,首先不要怪员工,而是要去反思自己是不是有激情。只有自己先成为“鲶鱼”,才能影响员工,才能使整个组织的活力都被调动起来,从而使集体的力量更加强大,克敌制胜。

9、“走动式”管理

这种管理方式属于最典型的柔性管理,目的很明确,就是要求企业的管理层要经常深入到基层和员工群众中去,体察民意、了解实情,与员工打成一片,从而增强领导层的亲和力和企业的凝聚力,激发员工的自豪感、自信心,起到上下一心、团结一致、共同进步的理想效果。“走动式”管理启示我们:一个整天忙忙碌碌、足不出户的领导决不是好领导,而事无巨细、事必躬亲的领导也不是好领导,只有削掉“椅子背儿”,从办公室中解放出来、深入基层与员工群众中去,才能取得事半功倍的效果。

10、破窗效应

及时矫正和补救正在发生的问题

一个房子如果窗户破了,没有人去修补,隔不久,其它的窗户也会莫名其妙的被人打破 ; 一面墙,如果出现一些涂鸦没有清洗掉,很快的,墙上就布满了乱七八糟,不堪入目的东西。一个很干净的地方,人会不好意思丢垃圾,但是一旦地上有垃圾出现之后,人就会毫不犹疑的抛,丝毫不觉羞愧 。这真是很奇怪的现象

11、马云的管理之道

“目标清晰(目标量化+计划),职责明确,赏罚分明(制度),超越伯乐。”

十二、消息队列12.1 RabbitMQ12.1.1 消息模式点对点模式 Direct 绑定一个queue扇形模式 Fanout 绑定多个queue主题模式 Topic 绑定多个queue,同时增加topic 通配符 * #12.1.2 有序性

单个queue有序

12.1.3 ACKbasicAck 手动确认basicReject 重新放回队列12.1.4 事务TransactionMQProducer12.2 RocketMQ12.2.1 消息模式集群消费模式(默认模式) 同一group+topic 多个消费者,通过负载均衡策略消费广播模式 topic通配符

_RocketMq在topic基础上可以增加tag进一步筛选

12.2.2 有序性

同一个Queue中有序,原理就是使用MessageQueueSelector(两种实现随机与哈希)

生产者

rocketMQTemplate.syncSendOrderly

设置相同的hashKey使消息发送至同一个queue中,保证消息有序

消费者

consumeMode设置成ConsumeMode.ORDERLY

@Component@RocketMQMessageListener(topic = "topic-lcf1", selectorExpression = "tag1", consumerGroup = "luchunfeng1",consumeMode = ConsumeMode.ORDERLY)public class Consumer implements RocketMQListener<String> {    private static final Logger logger = LoggerFactory.getLogger(Consumer.class);    @Override    public void onMessage(String s) {        logger.info(s);    }}

12.2.3 ACK

//CONSUME_SUCCESS 消费成功

//RECONSUME_LATER 消费失败,需要稍后重新消费

ConsumeConcurrentlyStatus.RECONSUME_LATER

12.2.4 事务RabbitTransactionManager12.2.5 ACL

ACL是access control list的简称,俗称访问控制列表。访问控制,基本上会涉及到用户、资源、权限、角色等

12.3 Kafka12.3.1 消息模式点对点模式发布/订阅模式12.3.2 有序性

单个partition有序,生产者发送消息指定partition

12.3.3 ACK

生产者到kafka服务器

ack=1,producer只要收到一个分区副本成功写入的通知就认为推送消息成功了。ack=0,producer发送一次就不再发送了,不管是否发送成功。ack=-1,producer只有收到分区内所有副本的成功写入的通知才认为推送消息成功了。

消费者手动提交

consumer.commitSync()

12.3.4 事务用户只需要在 Producer 的配置中配置 transactional.id,通过 initTransactions() 初始化事务状态信息,再通过 beginTransaction() 标识一个事务的开始,然后通过 commitTransaction()abortTransaction() 对事务进行 commit 或 abort

十三、技术栈

微服务:SpringCloud/Dubbo、Gateway、Eureka/Nacos/Consul、 ConfigServer/Apollo、Hystrix/Sentinel

分布式:SLB、LVS、KeepAlived、LCN/Seata、ELK/ES等; 缓存:Java本地缓存、Memcached、Redis、MongoDB;

消息:RabbitMQ、RocketMQ、Kafka等

存储:Minio/Fastdfs、 MySQL(MybatisPlus)、Oracle、DB2、SQL Server等

测试:Jmeter、Loadrunner、JUnit、MockServer、Mockjs

监控:Arthas、XRebel、Jconsole、Jvisualvm、MAT

自动化:Jenkins、Nexus、GIT、Sonaqube、Maven、Gradle;

项目管理:TAPD(敏捷)、Redmine、禅道、Jira、Worktile(OKR)等;

设计:常用设计模式、UML、PowerDesinger

前端:JavaScript、Jquery、Ajax、Nodejs、Vue 等;

后台:SpringSecurityOauth2/Shiro、okHttp、Swagger/Knife4j 、对称/非对称加密(SM2)等;

大数据:熟悉 Spark、Hive、Hadoop(hdfs、hbase);

容器:Nginx/Tomcat/Jetty、Docker/Podman、WebLogic、Websphere等;

其它:Python、Activiti 、以太坊

十四、其它可用性(SLA)、可靠性()可用性

可用性指系统在给定时间内可以正常工作的概率,通常用SLA(服务等级协议,service level agreement)指标来表示。

这是这段时间的总体的可用性指标。

可靠性

可靠性相关的几个指标如下:

MTBF(Mean Time Between Failure)

即平均无故障时间,是指从新的产品在规定的工作环境条件下开始工作到出现第一个故障的时间的平均值。

MTBF越长表示可靠性越高,正确工作能力越强 。

MTTR(Mean Time To Repair)

即平均修复时间,是指可修复产品的平均修复时间,就是从出现故障到修复中间的这段时间。

MTTR越短表示易恢复性越好。

MTTF(Mean Time To Failure)

即平均失效时间。系统平均能够正常运行多长时间,才发生一次故障。

系统的可靠性越高,平均无故障时间越长。

标签: #gateoneajaxterm