【问题场景】

有个30多行的大SQL执行效率特别慢,问题集中在一个子查询上,开始没有建索引,可是发现索引都创建了,不走索引,大SQL简化一下,提出不走索引的部分,如下图所示

简单点,有三张表需要关联查询,关联关系如下

A表

B表 关联 A.col = B.id

C表 关联 B.col = C.id

问题出在 B表 关联 A.col = B.id,为啥?执行计划就是不走id主键,C表 关联 B.col = C.id都可以正常走

【解决思路】

1、尝试单表查询,验证索引是否正常 试了一下单表查询B是可以走主键索引,正常,排出索引问题

2、尝试优化SQL 修改了一下SQL,将left join 分别改为inner join,join和子查询,几种方式都不能走索引,排出优化可能

3、尝试在其他环境执行

发现在其他环境下可以正常,走索引,说明不是SQL的问题,排出SQL问题。

TMD !!! 到底哪出问题

既然有环境可以,肯定是哪里配置有问题,慢慢对比一下,于是从表结构,索引创建方式,逐一排查,还是没有发现问题。

没有思路了,困意来袭,下班回家,明日再战


新的一天开始,没办法,在baidu继续搜搜,“SQL 不走索引”

忽然间发现了一篇文章 https://www.cnblogs.com/jarjune/articles/7912722.html

启发了我,是不是两张表的编码方式不一样呢,有思路来,开搞,哈哈 ……

先看表的编码,哇塞,uft8mb4

再看字段的编码,神马,uft8mb4

我们默认都是uft8,谁干的,我的刀呢 …… 修改了表的编码和字段的编码方式,终于可以正常走索引了

【总结】

  • 对于大SQL,不要抱着大西瓜跑步,轻装上路。精确定位问题,简化问题,逐步缩小范围
  • 在一两个人开发的时候,大家都熟悉规范,使用默认的编码方式,一般会忽略编码方式不同的问题,所以团队开发要注意遵守规范
  • 在使用join连接查询的时候,如果编码不一致,就不走索引了

1、ThreadLocal 特性

  • ThreadLocal存放的值是线程封闭,线程间互斥的,主要用于线程内共享一些数据,避免通过参数来传递
  • 在Thread类中有一个Map,用于存储每一个线程的变量的副本。
  • 线程的角度看,每个线程都保持一个对其线程局部变量副本的隐式引用,只要线程是活动的并且 ThreadLocal 实例是可访问的;在线程消失之后,其线程局部实例的所有副本都会被垃圾回收
  • 对于多线程资源共享的问题,同步机制采用了“以时间换空间”的方式,而ThreadLocal采用了“以空间换时间”的方式(ThreadLocal的缺点时占用了较多的空间。)

2、jvm内存区域划分

  • 运行时数据区包括:虚拟机栈区,堆区,方法区,本地方法栈,程序计数器
  • 虚拟机栈区 :也就是我们常说的栈区,线程私有,存放基本类型,对象的引用和 returnAddress ,在编译期间完成分配。
  • 堆区 , JAVA 堆,也称 GC 堆,所有线程共享,存放对象的实例和数组, JAVA 堆是垃圾收集器管理的主要区域。
  • 方法区 :所有线程共享,存储已被虚拟机加载的类信息,常量,静态变量,即时编译器编译后的代码等数据。这个区域的内存回收目标主要是针对常量池的对象的回收和对类型的卸载。
  • 程序计数器 :线程私有,每个线程都有自己独立的程序计数器,用来指示下一条指令的地址

3、类加载过程,classload机制

  • 五个阶段:加载、验证、准备、解析、初始化

4、类加载器

  • 启动类加载器,c++实现,虚拟机自身的一部分,负载加载JAVA_HOME\lib目录中jar
  • 其他类加载器,java实现,虚拟机外部,全部继承抽线类java.lang.ClassLoader
  • 扩展类加载器,负载加载JAVA_HOME\lib\ext目录中jar
  • 应用程序类加载器,负载加载用户类路径classpath上所有指导的类库 * 自定义类加载器

5、垃圾回收回收算法

  • 两个最基本的java回收算法:复制算法和标记清理算法
  • 复制算法:两个区域A和B,初始对象在A,继续存活的对象被转移到B。此为新生代最常用的算法
  • 标记清理:一块区域,标记可达对象(可达性分析),然后回收不可达对象,会出现碎片,那么引出
  • 标记-整理算法:多了碎片整理,整理出更大的内存放更大的

6、垃圾回收集器

  • Serial New收集器是针对新生代的收集器,采用的是复制算法
  • Parallel New(并行)收集器,新生代采用复制算法,老年代采用标记整理
  • Parallel Scavenge(并行)收集器,针对新生代,采用复制收集算法
  • Serial Old(串行)收集器,新生代采用复制,老年代采用标记整理
  • Parallel Old(并行)收集器,针对老年代,标记整理
  • CMS收集器,基于标记清理
  • G1收集器:整体上是基于标记整理 ,局部采用复制

7、 Java中垃圾回收有什么目的?什么时候进行垃圾回收?

  • 垃圾回收的目的是识别并且丢弃应用不再使用的对象来释放和重用资源。
  • 触发主GC(Garbage Collector,垃圾回收)的条件:
    • 当应用程序空闲时,即没有应用线程在运行时,GC会被调用。
    • Java堆内存不足时,GC会被调用。

8、进行垃圾回收几种类型?

  • 在新生代的Eden区满了,会触发新生代GC(Mimor GC);
  • 经过多次触发新生代GC存活下来的对象就会升级到老年代;
  • 升级到老年代的对象所需的内存大于老年代剩余的内存,则会触发老年代GC(Full GC);
  • 当程序调用System.gc()时也会触发Full GC;

9、线程的几种状态。

  • 在线程的生命周期中,它要经过 新建(New)、就绪(Runnable)、运行(Running)、阻塞(Blocked)和死亡(Dead)5种状态。
  • 尤其是当线程启动以后,它不可能一直”霸占”着CPU独自运行,所以CPU需要在多条线程之间切换,于是线程状态也会多次在运行、阻塞之间切换。

参考资料:https://juejin.im/post/5b10e53b6fb9a01e5b10e9be

10、JVM优化策略

  • 给JVM设置-XX:+HeapDumpOnOutOfMemoryError参数,让JVM碰到OOM场景时输出dump信息。 说明:OOM的发生是有概率的,甚至有规律地相隔数月才出现一例,出现时的现场信息对查错非常有价值。
  • 在线上生产环境,JVM的Xms和Xmx设置一样大小的内存容量,避免在GC 后调整堆大小带来的压力。

1、http请求方式

  • HTTP1.0定义了三种请求方法: GET, POST 和 HEAD方法。
  • HTTP1.1新增了五种请求方法:OPTIONS, PUT, DELETE, TRACE 和 CONNECT 方法。

2、GET 和 POST 区别

3、OSI的7层体系结构

OSI分层 (7层):物理层、数据链路层、网络层、传输层、会话层、表示层、应用层。

4、TCP/IP的体系结构

TCP/IP分层(4层):网络接口层、 网际层、运输层、 应用层。

5、五层协议的体系结构

五层协议 (5层):物理层、数据链路层、网络层、运输层、 应用层。

6、各层协议和作用

物理层:RJ45、CLOCK、IEEE802.3 (中继器,集线器,网关) 数据链路:PPP、FR、HDLC、VLAN、MAC (网桥,交换机) 网络层:IP、ICMP、ARP、RARP、OSPF、IPX、RIP、IGRP、 (路由器) 传输层:TCP、UDP、SPX 会话层:NFS、SQL、NETBIOS、RPC 表示层:JPEG、MPEG、ASII 应用层:FTP、DNS、Telnet、SMTP、HTTP、WWW、NFS 每一层的作用如下: 物理层:通过媒介传输比特,确定机械及电气规范(比特Bit) 数据链路层:将比特组装成帧和点到点的传递(帧Frame) 网络层:负责数据包从源到宿的传递和网际互连(包PackeT) 传输层:提供端到端的可靠报文传递和错误恢复(段Segment) 会话层:建立、管理和终止会话(会话协议数据单元SPDU) 表示层:对数据进行翻译、加密和压缩(表示协议数据单元PPDU) 应用层:允许访问OSI环境的手段(应用协议数据单元APDU)

7、TCP三次握手全过程

  • 客户端发送SYN请求,进入SYN_SEND状态
  • 服务端收到SYN请求,并返回一个ACK应答,并发送一个SYN其请求,服务器进入SYN_RECV状态
  • 客户端收到服务端的SYN请求和ACK应答,发送ACK应答,客户端进入ESTABLISH状态,服务端收到应答后进入ESTABLISH。如果没有收到应答,数据包都会根据TCP的重传机制进行重传。

8、TCP 四次挥手的全过程

  • 客户端发送FIN包,请求断开连接,客户端进入FIN_WAIT1状态
  • 服务端收到FIN包后返回应答,进入CLOSE_WAIT状态
  • 客户端收到FIN的应答后进入FIN_WAIT2状态
  • 服务端发送FIN请求包,进入LAST_ACK状态
  • 客户端收到FIN请求包后,发送应答进入TIME_WAIT状态
  • 服务器收到ACK应答后,进入close状态。

9、IP地址的分类

  • A类地址(1~126):网络号占前8位,以0开头,主机号占后24位。
  • B类地址(128~191):网络号占前16位,以10开头,主机号占后16位。
  • C类地址(192~223):网络号占前24位,以110开头,主机号占后8位。
  • D类地址(224~239):以1110开头,保留位多播地址。
  • E类地址(240~255):以1111开头,保留位今后使用。

注意

(1) 网络号剩余字段全为0的IP地址是保留地址,表示本网络,如00000000+24位主机号

(2) 主机号全为0表示本网络本身,例如202.98.174.0;主机号全为1表示本网络的广播地址,例如202.98.174.255。

(3) 127.X.X.X网络保留做为环路自检地址,该地址表示任意主机本身,目的地址为环路自检地址的IP数据报永远不会出现在任何网络上。

(4) 32位全为1,即255.255.255.255表示整个TCP/IP网络的广播地址;32位全为0,即0.0.0.0表示本网络上的本主机。

(5) 各类地址中,私有IP地址网段:此时,IP地址与子网掩码相与得到网络号

A类:1个A类网段,即10.0.0.0~10.255.255.255

B类:16个B类网段,即172.16.0.0~172.31.255.255

C类:256个C类网段,即192.168.0.0~192.168.255.25

1、 Overload 和 Override 的区别。Overloaded 的方法是否可以改变返回值的类型?

  • 方法的重写 Overriding 和重载 Overloading 是 Java 多态性的不同表现。重写 Overriding 是父类与子类之间多态性的一种表现,重载 Overloading 是一个类中多态性的一种表现。
  • 如果在子类中定义某方法与其父类有相同的名称和参数,我们说该方法被重写 (Overriding)。子类的对象使用这个方法时,将调用子类中的定义,对它而言,父类中的 定义如同被”屏蔽”了。
  • 如果在一个类中定义了多个同名的方法,它们或有不同的参数个数,或有不同的参数类型,则称为方法的重载(Overloading)。
  • Overloaded 的方法是可以改变返 回值的类型。

2、Collection 和 Collections 的区别。

  • Collection 是集合类的上级接口,继承与他的接口主要有 Set 和 List.
  • Collections 是针对集合类的一个帮助类,他提供一系列静态方法实现对各种集合的搜索、排序、线程安全化等操作。

3、java 中有几种类型的流?JDK 为每种类型的流提供了 一些抽象类以供继承,请说出他们分别是哪些类?

  • 字节流,字符流 。
  • 字节流继承于 InputStream OutputStream ,
  • 字符流继承于 InputStreamReader OutputStreamWriter。
  • 在java.io 包中还有许多其他的流,主要是为了提高性能和使用方便。

4、error 和 exception 有什么区别 ?

  • error 表示恢复不是不可能但很困难的情况下的一种严重问题。比如说内存溢出。不可能指望程序能处理这样的情况。
  • exception 表示一种设计或实现问题。也就是说,它表示如果程序运行正常,从不会发生的情况。

5、父类子类多态关系

A派生出子类B,B派生出子类C,并且在java源代码中有如下声明:

  • 类的继承具有传递性,子类可以通过向上转型的方式无条件地赋值给父类对象;
  • 父类通过向下转型赋值给子类时,必须通过强制类型转换。

6、Math中floor、ceil、round方法区别

  • floor: 求小于参数的最大整数。返回double类型 n. 地板,地面 例如:Math.floor(-4.2) = -5.0
  • ceil:求大于参数的最小整数。返回double类型 vt. 装天花板 例如:Math.ceil(5.6) = 6.0
  • round: 对小数进行四舍五入后的结果。返回int类型 例如:Math.round(-4.6) = -5

7、list是一个ArrayList的对象,如何在Iterator遍历的过程中正确并安全的删除一个list中保存的对象?

  • Iterator 支持从源集合中安全地删除对象,只需在 Iterator 上调用 remove() 即可。
  • 这样做的好处是可以避免 ConcurrentModifiedException ,当打开 Iterator 迭代集合时,同时又在对集合进行修改。
  • 有些集合不允许在迭代时删除或添加元素,但是调用 Iterator 的remove() 方法是个安全的做法。

8、jsp中静态include和动态include的区别

  • 静态的include:是jsp的指令来实现的,< %@include file=”xx.html”%> 是共享request请求域,先包含再编译,不检查包含页面的变化。不允许有相同的变量。 是在翻译阶段执行。
  • 动态的include:是jsp动作来实现的, 是不共享request请求域,先编译在包含,是要检查包含页面的变化的。在请求处理阶段执行。

9、Servlet的生命周期可以分为初始化阶段,运行阶段和销毁阶段三个阶段

  • init():仅执行一次,负责在装载Servlet时初始化Servlet对象
  • service() :核心方法,一般HttpServlet中会有get,post两种处理方式。在调用doGet和doPost方法时会构造servletRequest和servletResponse请求和响应对象作为参数。
  • destory():在停止并且卸载Servlet时执行,负责释放资源

10、线程与进程的区别?

  • 地址空间和其它资源:进程间相互独立,同一进程的各线程间共享。某进程内的线程在其它进程不可见。
  • 通信:进程间通信IPC,线程间可以直接读写进程数据段(如全局变量)来进行通信——需要进程同步和互斥手段的辅助,以保证数据的一致性。
  • 调度和切换:线程上下文切换比进程上下文切换要快得多。
  • 在多线程OS中,进程不是一个可执行的实体。

1、自增前置和后置操作符

  • ++i 在程序执行前进行自增
  • i++ 在程序执行完毕后自增

2、String,StringBuilder,StringBuffer 区别

  • String 是不可变类,线程安全的, 对象一旦被创建,字符串的内容将不能被改变。
  • StringBuffer 是可变类,线程安全的,当对象被创建后,仍然可以对字符串的内容进行修改。
  • StringBuilder是可变类,非线程安全的,当对象被创建后,仍然可以对字符串的内容进行修改 。
  • 执行效率:StringBuilder > StringBuffer > String

3、线程中方法

  • wait():使线程暂停执行的方法,如果线程对一个同步对象发出了一个 wait()调用请求,那么该线程会暂停执行,被调对象进入等待状态,直到被唤醒(通常使用 notify()唤醒)或等待时间超时。
  • sleep():使当前运行的线程休眠指定的时间。
  • stop():终止线程的执行,会释放已经锁定的所有的监视资源。
  • suspend():将一个线程挂起(暂停),并且不会自动恢复,必须通过调用对应的resume(),才能使得线程重新进入可执行状态。

4、 Hashtable和HashMap 相同点和区别

相同点:

  • 都是键值对(key-value)形式
  • 都实现了 Map 接口

区别:

  • HashMap允许空(null)键值(key)(注意,最多只允许一条记录的键为null),而Hashtable不允许。
  • Hashtable继承自Dictionary类,而HashMap继承自AbstractMap类。
  • Hashtable 的方法是线程安全的,而 HashMap 不是线程安全的。所以效率上HashMap可能高于Hashtable。
  • 由于Hashtable是线程安全的,没有采用快速失败机制;HashMap是非线程安全,迭代HashMap 采用了快速失败机制。
  • 哈希值的使用不同,HashTable直接使用对象的hashCode。而HashMap重新计算hash值。
  • Hashtable和HashMap它们两个内部实现方式的数组的初始大小和扩容的方式。HashTable中hash数组默认大小是11,增加的方式是 old*2+1。HashMap中hash数组的默认大小是16,而且一定是2的指数。

快速失败(fail-fast)是Java集合的一种错误检测机制。当多个线程对集合进行结构上的改变的操作时,可能会产生 fail-fast事件。例:两个线程(线程1与线程2)当线程1通过 Iterator(迭代器)在遍历集合A中的元素,如果线程2修改了集合A(删除或增加新的元素),这个时程序就会抛出 ConcurrentModificationException 异常,从而产生fail-fast事件。

5、变量名、方法名和数组命名规范

  • 只有由字母,数字,下划线和$组成
  • 并且第一个字符只能是 字母,下滑线或$

6、List<? extends T>List<? super T>区别

  • <? extends T>表示类型的上界,参数化的类型可能是 T 或者 T 的子类。
  • <? super T>表示类型的下界,参数化的类型可能是 T 或者 T 的父类。

7、final,finally 和 finalize 有什么区别

  • final 用于声明属性,方法和类,分别表示属性不可变,方法不可覆盖,类不可继承。
  • finally 是异常处理语句结构的一部分,表示总是执行,try catch finally。
  • finalize 是 Object 类的一个方法,在垃圾收集器执行的时候会调用被回收对象的此方法,可以覆盖此方法提供垃圾收集时的其他资源回收,例如关闭文件等。

8、equals 和==的区别

  • equals 比较引用对象类型内容,对象需要 override 覆写。
  • == 基本类型,比较的是栈内存地址。

9、Java默认序列化如何去做,哪些字段不会被序列化

  • 序列化的实现:将需要被序列化的类实现 Serializable 接口,该接口没有需要实现的方法,默认序列化机制。
  • 使用默认机制,在序列化对象时,不仅会序列化当前对象本身,还会对该对象引用的其它对象也进行序列化,同样地,这些其它对象引用的另外对象也将被序列化,以此类推。所以,如果一个对象包含的成员变量是容器类对象,而这些容器所含有的元素也是容器类对象,那么这个序列化的过程就会较复杂,开销也较大。
  • 对象的默认序列化机制写入的内容是:对象的类,类签名,以及非瞬态和非静态字段的值。
  • static和transient字段不能被序列化。

10、Vector、ArrayList和LinkedList 有什么特点

相同点

  • 都实现了 List 接口(List 接口继承了 Collection 接口),他们都是有序集合,即存储在这两个集合中的元素的位置都是有顺序的,相当于一种动态的数组

不同点

  • ArrayList 是线程序不安全的,它的元素可以通过get/set方法直接访问。
  • Vector 是线程安全的,和ArrayList类似。
  • LinkedList 是线程序不安全的,一个双链表,允许所有元素(包括 null)。在添加和删除元素时具有比ArrayList更好的性能。但在get与set方面弱于ArrayList。当然,这些对比都是指数据量很大或者操作很频繁的情况下的对比。它还实现了 Queue 接口,该接口比List提供了更多的方法,包括 offer()、peek()、poll()等。

参考资料 https://zhuanlan.zhihu.com/p/34828859

1、方法修饰符访问级别

  • public > default > protected > private

2、修饰符的使用范围

3、常见Java容器类型区别

4、接口和抽象类的相同和不同点

相同点:

  • 都不能被实例化
  • 只有在实现或继承后实现类或子类才能实例化

不同点:

  • 关键字:实现接口implements;继承抽象类 extends。
  • 关系:接口可以有多个实现类;抽象类只能有一个继承类。
  • 成员变量:接口只能是public static final修饰的,且必须赋初值;抽象类可以是public,default,protected,private修饰的。
  • 成员方法:接口只能public abstract修饰的;抽象类可以是public abstract的抽象方法,也可以是其他正常方法。

5、Object类中方法

6、原始类型 (8种)

  • 浮点型:float,double(包装类:Float,Double)
  • 布尔型:boolean(包装类:Boolean)
  • 字符型:char(包装类:Character)
  • 数值型:byte,short,int,long(包装类:Byte,Short,Integer,Long)

7、实现多线程的方法

  • 继承Thread类,重写run方法
  • 实现Runnable接口,实现run方法
  • 实现Callable接口,重写call方法

8、什么是不可变量类,包括哪些

  • 不可变类:是指创建实例之后,就不允许修改它的值,只允许读操作
  • 基本类型的包装类:Short, Integer, Long, Float, Double, Byte, Character, Boolean
  • 此外String类等

参考资料: https://www.cnblogs.com/jaylon/p/5721571.html https://www.zhihu.com/question/20618891

9、关键字功能介绍

static

  • 为某特定数据类型或对象分配单一的存储空间,而与创建对象的个数无关。
  • 在不创建对象的情况下,可以通过类来直接调用方法或使用类的属性。
  • 被static修饰的属性(方法)是类的属性(方法),不属于任何对象。

synchronized

  • 主要用来给对象和方法或者代码块加锁,当它锁定一个方法或者一个代码块时,同一时刻最多只有一个线程执行这段代码。

serialize

  • 序列化,将对象的字节序列永久地保存到硬盘上,通常存放在一个文件中。
  • 在网络上传送对象的字节序列。

对象的序列化指的是把对象转换为字节序列的过程。 对象的反序列化指的是把字节序列恢复为对象的过程。

transient

  • 一旦变量被transient修饰,变量将不再是对象持久化的一部分,该变量内容在序列化后无法获得访问。
  • transient关键字只能修饰变量,而不能修饰方法和类。注意,本地变量是不能被transient关键字修饰的。变量如果是用户自定义类变量,则该类需要实现Serializable接口。
  • 被transient关键字修饰的变量不再能被序列化,一个静态变量不管是否被transient修饰,均不能被序列化。

volatile

  • 保证变量对所有的线程的可见性,即当一个线程修改了这个变量的值,新值对于其他线程来说是可以立即得知的。
  • 禁止编译器 指令重排优化。

final

  • 修饰类,表明这个类不能被继承(断子绝孙类)。
  • 修饰方法,这个方法不能被子类重写。
  • 修饰变量,如果是基本数据类型的变量,则其数值一旦被初始化之后便不能更改,如果是引用类型的变量,则在对其初始化之后便不能再让其指向另一个对象。

supper

  • 调用父类的构造方法、父类的方法和属性

this

  • 调用当前对象的某个方法或某个成员时

10、构造方法

  • 类中的构造方法是可以省略的,当省略的时候,编译器会提供一个默认的构造方法以供使用。
  • 构造方法必须与类名相同。
  • 构造方法可以重载,一个类可以定义多个构造方法。
  • 当一个对象被 new的时候必定会调用构造方法。

【问题1】 Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?

【解决】 没有启动 docker 服务,执行启动docker服务 # servcei docker run  

【问题2】 Job for docker.service failed because the control process exited with error code. See “systemctl status docker.service” and “journalctl -xe” for details

【解决】 Docker启动异常的可能原因:

  • 1、内存不够:Docker 启动至少需要2G内存,首先执行free -mh命令查看剩余内存是否足够
  • 2、端口冲突:该docker监听端口已经被其他进程占用,一般此种问题容易出现在新部署的服务,或在原有机器上部署新的后台服务,所以在部署之前应该执行命令检查端口是否已经被占用,如果上线后发现占有则应改为可用端口再重启之。  

【问题3】 默认配置下,如果在 CentOS 使用 Docker CE 看到下面的这些警告信息: WARNING: bridge-nf-call-iptables is disabled WARNING: bridge-nf-call-ip6tables is disabled

【解决】 请添加内核配置参数以启用这些功能。

然后重新加载 sysctl.conf 即可 $ sudo sysctl -p  

【docker 使用注意事项】

  • 1、制作镜像尽量避免使用docker commit命令,原因这样制作的镜像像一个黑盒操作,开发人员不知道里面具体改动了那些内容。 docker commit 可以用于被攻击后记录轨迹
  • 2、docker run 宿主机端口:docker虚拟机端口 注意:在冒号前面的端口为宿主机的端口,后面的为虚拟机端口
  • 3、强烈建议将容器加入自定义的 Docker 网络来连接多个容器,而不是使用 –link 参数。
  • 4、使用docker image prune 可以清除无用的虚悬镜像
  • 5、docker run –name 最好使用name参数配置,给启动的docker镜像起一个名字,否则docker每次回自动给其命名,且每次的名字不 一样。  

【dockerfile 编写注意事项】

  • 1、使用dockerfile制作docker镜像时,同类命令尽量使用&&拼接,减少创建的镜像层数,提高镜像创建速度 注意:docker最大镜像层数127
  • 2、dockerfile中记录使用的cmd命令,会被docker run 后面的执行的命令覆盖
  • 3、dockerfile中ADD命令可以实现自动解压的效果。注意,虽然ADD和COPY都可以复制文件,但建议只有在需要对复制文件进行自动解压时使用add。

使用daocloud 中的国内加速器

在docker上执行上命令,当执行成功后,会自动在/etc/docker/目录下添加daemon.json和key.json

如果生效的话,需要重启docker服务

systemctl restart docker

【参考资料】
https://www.daocloud.io/mirror#accelerator-doc

由于近期用jenkin发版的时候,发现其中重启tomcat发布服务功能总是不能正常生效,所以我想在jenkin中调用自己写的一段shell脚本来完成重启tomcat的工作

 

【问题场景】 在本地开发环境,上传超过2MB的数据都可以成功上传至服务器。但是,在测试环境出现上传超过200K就会失败的问题。 前端使用的是springMVC,中间件使用Nginx + Tomcat

【排查方法】 1、检查不同环境下的spring配置文件中,上传文件大小限制

两个环节的代码都是同样的配置,没有问题,排查spring问题

2、检查两个环境的tomcat配置 conf/server.xml

当maxPostSize<=0时,POST方式上传的文件大小不会被限制。配置一致,排除tomcat配置问题, 注意:maxPostSize参数只有当request的Content-Type为“application/x-www-form-urlencoded”时起作用。 参考资料 https://blog.csdn.net/lafengwnagzi/article/details/72846195

3、检查两个环境的nginx配置

最终发现,测试环境的nginx配置不一致导致,问题定位成功 参考资料 https://blog.csdn.net/bruce128/article/details/9665503

【总结】 需要问题不要着急,先自查,从自己的代码入手。如果代码确认没有问题,就外范围扩大,看一下外部环境是否存在问题,一般情况都可以准确定位。