Docker常用命令总结

查看docker服务端和客户端版本
# docker version

查看docker容器信息,显示 Docker 系统信息,包括镜像和容器数。
# docker info

帮助命令
# docker –help

查看docker进程
docker ps
[参数列表]
-l 返回最后的容器的状态
-a 看所有容器包括已经停止的容器

从服务器拉取镜像
# docker pull  

列出本地所有镜像
# docker images
# docker image prune // 删除所有悬虚镜像

存储镜像
# docker save 

载入镜像
# docker load 

删除容器
# docker rmi 

将已终止容器启动
# docker start 

停止正在运行的容器
# docker stop

命令来停止容器或然后再启动容器。
# docker restart

提交本地修改容器
# docker commit 

查看docker容器信息
# docker inspect <容器名>

查看容器
# docker container ls  //查看所有运行的容器
# docker container prune  //删除所有的停止的运行的容器

查看数据卷
# docker volume
# docker volume prune //删除所有停止使用的数据卷

查看docker的宿主机端口映射容器端口
# docker port <容器名>

查看docker 系统镜像、容器、数据卷使用情况
# docker sytem df  

从宿主机进入docker容器
docker exec -it <容器id> bash
docker exec -it <容器id> sh
docker exec -it <容器id> bash
docker exec -it <容器id> sh

物理机和容器之间复制命令如下:
容器复制文件到物理机:docker cp <容器名称>:<容器目录> <物理机目录>
物理机复制文件到容器:docker cp <物理机目录> <容器名称>:<容器目录>
eg:docker cp channelWeb:/opt/tomcat/apache-tomcat-7.0.75/webapps/channel-web.war /home/app/

查看docke容器内日志
# docker logs -f –tail=100  <容器名>

查看docker各容器CPU占用情况
# ctop

运行docker虚拟机
# docker run –name <虚拟机别名> –rm -p <宿主机端口:虚拟机端口>  –network  <自定义网络>  <镜像名称>
[参考资料]
[参数列表]
-t 选项让Docker分配一个伪终端(pseudo-tty)并绑定到容器的标准输入上,
-i 则让容器的标准输入保持打开。
-d 让 Docker 容器在后台以守护态(Daemonized)形式运行
-v 标记来创建一个数据卷并挂载到容器里。在一次 run 中多次使用可以挂载多个数据卷。用户也可以通过 :ro 指定为只读。
-p 标示来指定端口。

进入容器 
# docker exec -it <容器名称> bash

导出容器快照
# docker export 

导入容器快照
# docker import 

《RabbitMQ 实战指南》读书笔记

RabbitMQ的模型架构介绍
可以把消息传递的过程想象成:当你将一个包裹送到邮局,邮局会暂存并最终将邮件通过邮递员送到收件人的手上, RabbitMQ 就好比由邮局、邮箱和邮递员组成的一个系统。
  • producer:生产者(发件人),消息的投递方
  • broker:消息中间件的中间节点(邮局,也可以看作一台Rabbit MQ服务器)
  • exchange:交换器(中分拣员),它根据分发规则,匹配查询表中的routing key,分发消息到queue中去。
  • queue:队列(收件人查收信件时的邮箱)
  • routingkey:路由键(填写在包裹上的地址),在某些情形下, RoutingKey 与BindingKey 可以看作同一个东西。
  • bing:绑定(???),通过绑定将exchange和queue关联起来,某些情况下会分配一个bandingkey(direct、topic)
  • bandingkey:绑定键(于包裹的目的地)
  • comsumer:消费者(收件人),消息的消费方
Exchange分类
  • fanout(广播,一对多)、不用配置RoutingKey 和 BandingKey,交换器会无视BindingKey将消息路由到所有绑定到该交换器的队列中。
  • direct(直连,一对一)、RoutingKey 和 BandingKey 必须相同,消息才能正常发送到queue
  • topic(主题,模糊,一对多)、RoutingKey 和 BandingKey 做模糊匹配,两者不是相同的
  • headers(基本上不用)
Routingkey中可以包含两种通配符
  • “.”  字符串分割符
  • “#” 通配任何零个或多个word
  • “*” 通配任何单个word

connection 和 channel 之间的关系
Connection 可以用来创建多个Channel 实例,但是Channel 实例不能在线程问共享,应用程序应该为每一个线程开辟一个Channel 。某些情况下Channel 的操作可以并发运行,但是在其他情况下会导致在网络上出现错误的通信帧交错,同时也会影响友送方确认( publisherconfrrm)机制的运行,所以多线程问共享Channel 实例是非线程安全的RabbitMQ 采用类似NIO的做法,选择TCP 连接复用,不仅可以减少性能开销便于管理。同时RabbitMQ 可以确保每个线程的私密性,就像拥有独立的连接一样。当每个信道的流量不是很大时,复用单一的Connection 可以在产生性能瓶颈的情况下有效地节省TCP 连接资源。

每个线程把持一个信道(channel),所以信道复用了Connection 的TCP 连接。当信道本身的流量很大时,这时候多个信道复用一个Connection 就会产生性能瓶颈,进而使整体的流量被限制了。此时就需要开辟多个Connection ,将这些信道均摊到这些Connection 中,Connection 可以用来创建多个Channel 实例,但是Channel 实例不能在线程问共享,应用程序应该为每一个线程开辟一个Channel 。某些情况下Channel 的操作可以并发运行,但是在其他情况下会导致在网络上出现错误的通信帧交错,同时也会影响友送方确认( publisher confrrm)机制的运行,所以多线程问共享Channel 实例是非线程安全的。


AMQP 生产者发送消息流程
AMQP 消费者发送消息流程

高级参数
  • mandatory 参数
  • alternate-exchange 备份交换机
  • 过期时间 TTL
    • 设置消息ttl:x-message-ttl
    • 设置队列ttl:x-expires
  • 死信队列 x-dead-letter-exchange
  • 延迟队列,没有直接支持,通过DLX 和TTL 模拟出延迟队列的功能。
  • 优先级队列 x-max-priority

MyBaits常见问题总结


1、mybaits中使用小于号

【错误分析】
如过在mybatis中使用<>&等字符,配置文件中会提示如下错误
The content of elements must consist of well-formed character data or markup.
【解决方法】
方法一   如果是在动态语句中,则需要转换

符号:

方法二 (推荐), 此时特殊符号不进行解析

【参考资料】



2、mybatis 可以返回map类型对象

注意:resultMap  和 resultType 区别



3、mybaits 查询sql中in的写法



4、mybatis 查询like 正规写法

正确方法一:

正确方法二:
like “%”#{name}”%”
错误方法
like ‘%”#{name}”%’
【参考资料】

MySQL数据join不走索引问题排查

【问题场景】

有个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连接查询的时候,如果编码不一致,就不走索引了

Java程序员面试题(高级篇)(一)

1、ThreadLocal 特性

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

2、jvm内存区域划分

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

3、类加载过程,classload机制

加载:将class文件字节流按照虚拟机所需的格式存储在元数据区
  • 通过类的全限定名获取定义此类的二进制字节流
  • 将这个字节流所有代表静态存储数据结构转化为元数据区(方法区)的运行时结构
  • 在内存中生成一个代表这个类的java.lang.Class对象,作为元数据区这个类的访问入口
验证:确保class文件字节流中信息符合虚拟机的要求,且不会危害虚拟机自身安全
  • 文件格式校验:验证字节流是否符合Class文件格式规范,并且能被当前版本的虚拟机处理
  • 元数据校验:对字节码进行语义分析,以保证描述的信息符合java语言规范
  • 字节码校验:对过数据流和控制流分析确定程序的语言是合法的符合逻辑的
  • 符号引用校验:校验在虚拟机中的符号引用转化为直接引用是否正常执行
准备:为类变量(仅包括被statis修饰的变量,不包括实例变量)分配内存并设置变量初始值。
解析:将常量池中符号引用替换为直接引用的过程。
初始化:执行类构造器<cinit>()方法,初始化实例对象。

使用:可以使用对象
卸载:对象内存内存回收

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 后调整堆大小带来的压力。