Java架构知识(更新中)
2020-05-20 17:33:46 0 举报
AI智能生成
java技术大全220/05/18(更新中)
作者其他创作
大纲/内容
java编程思想
面向对象
继承与多态
初始jvm虚拟机
class与反射
Jvm虚拟机
JVM整体架构
类加载器
运行时数据区
程序计数器
栈帧
局部变量表
操作数栈
动态连接
完成出口
本地方法表
堆
方法区
执行引擎
Jvm参数
版本号
次版本号
静态常量池
常量池大小:如果没有常量池为0 所以常量池下计数从1开始数
常量池组成部分
tag:通过这个u1的数字查询对应的常量类型
index:对应class文件中的#数字
长度不固定的名称
类元数据
类访问标志
access_flags
用于保存class已经interface的访问标志,public,privateprotected
类索引
用于确定该类的全限定名
父类索引
用于确定父类的全限定名
ps:索引都指向常量池中对应的常量
成员变量
用于保存class中的所有成员变量
访问标志
变量名索引
变量属性
魔数ca fe ba be
方法
表格形式存储
方法访问标志位
方法名索引
方法描述索引
变量属性
属性
属性用于保存class成员变量或者方法的详细持有信息
每个field或者method中都可以包含一个属性表
属性由多个属性表组成,每个属性表包含一种特定类型的属性.
类加载器
把静态class文件加载到内存区域
ClassLoader c =new ClassInit.class.getClassLoader();
BootStrap ClassLoader
该类复制加载\lib\目录下的类加载到虚拟机内存中,用来加载java的核心类
,此类加载器并不继承java.lang.classloader,不能被java程序调用
代码是使用C++编写的,是虚拟机自身的一部分
Extendsion ClassLoader
扩展类加载器
该类负责加载\lib\ext目录下的类库
用来加载java的扩展库
开发这可以直接使用这个类加载器
Application ClassLoader
应用程序类加载器
该类加载器负责加载用户类路径下的类库,
一般我们编写的java类都是由这个类加载器加载
这个ClassLoader中的getSystemClassLoader方法的返回值,所以也被称为系统类加载器
一般情况下这就是系统默认的类加载器
双亲委派模型
优点:java的类随着它的加载器有了优先级关系
比如:Object类,无论哪个加载器都要加载这个类,因此由父类加载器来加载
所有加载器的加载Object类的请求都会汇聚到同一个层级,就不会导致多个Object类出现了
钻石依赖
一个程序依赖了两个不同版本的软件包
java通过不同的类加载器实现加载不同版本的软件包
内存分配机制
所有线程共享的
方法区
用于存储已被虚拟机加载的类信息,常量,静态变量,编译器编译后的代码等数据
类型的完整有效名
类的直接父类完整有效名
类型的修饰符
类型的常量池
域信息
方法信息
除了常量外的所有静态变量
堆
对于大多数应用来说,java堆是java虚拟机所管理的内存中最大的一块
java堆是被所有线程共享的一块内存区域,虚拟机启动时创建
此内存区域唯一目的就是存放对象实例,几乎所有的对象实例都在这里分配内存
OutOfMemoryError异常,如果在堆中没有内存完成实例分配,并且堆无法再扩展时.
线程隔离的数据区
当jvm每遇到一个线程时,就会为他创建程序计数器,虚拟机栈,本地方法栈,当线程终止时,内存会释放
程序计数器
程序计数器可以被看作是当前线程所执行的字节码的位置指示器
在虚拟机模型里,字节码指示器是通过改变程序计数器的值来指定下一条要实现的指令.
java虚拟机是通过轮流切换并分配处理器来实现的,所以每条线程都需要一个记录下一条指令的计数器,所以程序计数器是线程私有的.
虚拟机栈
代码中每个方法在执行的同时,都会创建一个栈帧用于存储局部变量表,操作数栈,动态连接,方法出口等信息.每一个方法调用直至执行完成的过程,都对应一个栈帧在虚拟机中入栈到出栈的过程
局部变量表存放了编译期间可知的各种基本数据类型
JVM对这个区域规定了两种异常情况,如果线程请求的栈深大于虚拟机所允许的深度,将抛出StatackOverFlowError
如果虚拟机可以动态扩展,如果扩展时无法申请倒足够的内存,会抛出OutOfMemoryError
本地方法栈
本地方法栈是虚拟机用到Native方法时,开辟的栈。
栈区
栈是先进后出的:最先进来的是main函数
虚拟机只会对java栈执行两种操作,出栈和入栈,先入栈的最后出栈
栈中存放的局部变量表是
分支主题
内存回收GC
当栈运行完成时,jvm会直接销毁栈的信息,也就是说引用已经回收了,堆中的对象还存在,这就需要垃圾回收机制来执行回收对象.
对什么区域进行回收
堆
堆中主要是对象存放的区域
当没有引用指向该对象时,就会执行回收
引用计数
给对象添加一个引用计数器,每当对这个对象进行一次引用,计数器就加1
每当引用失效的时候,引用计数器就减
当引用计数器等于0的时候,表示这个对象不会在被引用
可达性分析
引用计数器来判断对象是否已"死",而可达性分析是判断对象是否还活着
通过一系列GCroots对象作为起点进行搜索,如果GCroots和一个对象之间没有可达路径,则该对象不可达并标记一次,当有两次标记时,该对象会被判定为可回收对象.
在java语言中,可作为GC root的对象有以下四种
1虚拟机栈
2.方法区静态属性引用对象
3.方法区中常量引用的对象
4.本地方法栈(Native)引用对象
最终判定
当第一次判定可达性分析算法为不可达时,会进行第一次标记并进行筛选,筛选对象是否有必要执行finalze方法,当对象没有覆盖该方法或者已经执行时,虚拟机将这两种情况都视为"没有必要执行"并进行回收
第二次标记,如果这个对象被判定为有必要执行finalze方法时,那么这个对象会被放在一个队列中,并在稍后由jvm虚拟机建立的finalze线程中执行
Finalize()方法是对象脱逃死亡命运的最后一次机会,稍后GC将对F-Queue中的对象进行第二次小规模标记,如果对象要在finalize()中成功拯救自己----只要重新与引用链上的任何的一个对象建立关联即可,譬如把自己赋值给某个类变量或对象的成员变量,那在第二次标记时它将移除出“即将回收”的集合。
引用
强引用
强引用是使用最普遍的引用。如果一个对象具有强引用,那垃圾回收器绝不会回收它。当内存空间不足,Java虚拟机宁愿抛出OutOfMemoryError错误,使程序异常终止,也不会靠随意回收具有强引用的对象来解决内存不足的问题。
强引用也就是我们常用的new
软引用
如果一个对象只具有软引用,则内存空间足够,垃圾回收器就不会回收它;如果内存空间不足了,就会回收这些对象的内存。只要垃圾回收器没有回收它,该对象就可以被程序使用。软引用可用来实现内存敏感的高速缓存
软引用可以和一个引用队列(ReferenceQueue)联合使用,如果软引用所引用的对象被垃圾回收器回收,Java虚拟机就会把这个软引用加入到与之关联的引用队列中。
它可通过SoftReference类实现。
弱引用
弱引用对象会在下一次GC时被回收,也就是说不管内存富不富裕,当GC时都会回收弱引用。
它可通过WeakReference类实现。
虚引用
虚引用不会改变对象的生存时间,它只是让对象在被GC时能收到一个系统通知。
方法区
栈是线程私有的,栈只会在运行结束时销毁.
回收算法
标记-清除算法
该算法分为标记和清除阶段;首先标记所有要回收的对象,然后一起清除
缺点:空间连续性低,如果要分配大容量对象,会出现空间不够用的情况
效率不高;清除和标记效率都低
复制算法
将内存分为大小相等的两块,每次只使用其中的一块,当一块用完了,就将活着的对象复制到另外一个上面.
缺点内存缩小了一半,内存利用率太低
标记整理算法
标记整理算法过程与标记清除算法一样
但后续步骤并不是直接对可回收对象进行清理,而是让所有存活对象都想一段移动,然后清理掉端边界以外的内存
分代收集算法
一般java堆分为新生代和老年代,这样就可以根据各个年代的特点采用最适当的收集算法
新生代:新生代大多数对象都是"朝生夕死",只有少量存活,所以选用复制算法,只需要付出少量存活对象的复制成本就可以完成收集
老年代中,因为对象存活率高,没有额外空间对它进行分配担保,就必须使用标记清理或标记整理算法来进行回收
垃圾收集器分类
MinorGC
针对新生代
Serial收集器:
新生代采用:复制算法,暂停所有用户线程,单线程操作
老年代采用标记-整理算法,暂停所以用户线程
ParNew收集器:
新生代采用复制算法,暂停所有用户线程,多线程操作
老年代采用标记-整理算法,暂停所有用户线程
server首选的新生代收集器
老年代无力
ParallelScavenge
并行多线程收集器.它和parnew的区别是,用户可以控制GC时用户线程停顿时间
-xx+userparallelgc
parallelScavenge关注点:可控的吞吐量
吞吐量计算公式:运行用户代码时间/(运行用户代码时间+垃圾收集时间)
停顿时间越短就越适合需用与用户交互的程序,良好的响应速度能提升用户体验,而高吞吐量则可以高效率的利用cpu时间,尽快的完成程序运算任务
适用场景:后台计算不需要太多交互
MajorGC
针对老年代
MajorGC的时候会同时执行MinorGC,但当新生代收集器是ParallelScavenge不会执行MinorGC
SerialOld收集器
Serial收集器的老年版本,它同样是一个单线程收集器,采用标记-整理算法,这个收集器的主要意义在于给client模式下的虚拟机使用
ParallelOd收集器
ParallelOld是ParallelScavenge收集器的老年代版本,使用多线程和标记-整理算法
这个收集器从jdk1.6开始提供
coucurrentMarkSweep收集器
适用场景:互联网站或web服务器
CMS收集器是一种以获取最短回收停顿时间为目标的收集器.
CMS收集器是基于标记-清除算法实现的.整个过程分为4个步骤
初始标记
初始标记会进行STW暂停时间
这个过程从垃圾回收的"根对象"开始,只扫描到能够和"根对象"直接关联的对象,并作标记
这个过程只标记了一次所以执行速度快
并发标记
在初始标记的基础上继续向下溯源标记.
此阶段是并发阶段,应用线程也在并发执行,用户不会感受到停顿
并发预清理
并发处理
这个阶段,虚拟机查找在执行并发标记阶段新进入老年代的对象
减少下一个阶段线程停止的时间
重新标记
重新标记会二次进行STW
收集器线程扫描在CMS堆中剩余的对象,扫描从跟对象向下溯源并处理对象关联.
并发消理
清理对象
并发执行
并发重置
这个阶段,重置CMS收集器的数据结构,等待下一次垃圾回收
分支主题
缺点
用的是清理,不会整理压缩堆空间.因此CMS不在采用指针,而是把未分配的空间汇成列表,当JVM分配对象空间时,会搜索列表找到足够大的空间Hold住这个对象
需要更多cpu:回收线程默认为(CPU数量+3)/4
需要更大的堆空间,因为CMS标记阶段应用程序的线程还在执行,那么为了保证CMS回收完堆之前还有空间分配给正在运行的应用程序,需要一部分预留空间
因此CMS不会在老年代满的时候才开始收集,而是在默认为老年代使用68%时就开始行动了.
FUllGC
fullGC针对老年代
=MajorGC+MinorGC
其他fullGC
G1收集器
G1算法将堆划分为若干个区域,但它仍然属于分代收集器
新生代的垃圾收集依然采用暂停所有线程的方式,将存活对象拷贝到老年代或者Survivor空间
老年代也分成很多区域,G1收集器通过从一个区域复制到另外一个区域,完成了清理工作,这就意味着完成了堆的压缩,也就不会有CMS内存碎片的问题存在了
G1提供了两种模式
youngGC
扫描跟GCRoots
更新RememberSet,记录回收对象的数据结构
检测RememberSet 哪些数据要从新生到老年
拷贝对象,要么往幸存代要么往老年代
清理工作
MixedG1
初始标记:主要利用了常规的年轻代垃圾回收暂停
跟区域扫描:在初始标记的年轻代存活区扫描对老年代的引用,并标记被引用的对象.只有完成该阶段后,才能开始下一次 STW 年轻代垃圾回收。
并发标记 GC 在整个堆中查找可访问的(存活的)对象。该阶段与应用程序同时运行,可以被 STW 年轻代垃圾回收中断。
最终标记(Remark,STW)该阶段是 STW 回收,帮助完成标记周期。G1 GC 清空 SATB 缓冲区,跟踪未被访问的存活对象,并执行引用处理。
清除垃圾在这个最后阶段,G1 GC 执行统计和 RSet 净化的 STW 操作。在统计期间,G1 GC 会识别完全空的区域和可供进行混合垃圾回收的区域。清理阶段在将空白区域重置并添加到空闲列表时为部分并发。注意完全空的region不会被加到CSet,都在这个阶段直接回收了。
配套机制
jdk1.7-1.8默认回收器:Parallel Scavenge+Parallel Old
JDK1.9是G1
大对象直接进入老年代
JVM内存区域示意图
分支主题
分支主题
SafePoint
垃圾回收器都有个阶段需要暂停所有线程对内存对象引用关系网络的更新,这个机制称为safePoint
抢先式中断
STW=stop the world
主动中断.
没有执行到安全点的用户线程,继续跑直到safepoint
缺点:Thread.sleep wait
主动中断
当GC需要中断线程时,不直接对线程操作,仅仅设置一个标志,各个线程执行时主动去轮询这个标志,当发现中断标志位真时就自己中断挂起
子主题 2
安全区域
安全点的衍生概念
安全点以后的一段区域都是安全的
垃圾回收机制不会主动进行回收,只有当内存不足时才会进行,因为回收内存也会消耗内存,所以只在必要时候进行
JVM调优
-Xms
启动时占用内存大小.
-XX:SuivivorRatio
控制eden区大小
eden:S0:S1=SurvivorRatio:1:1
100m*(SurvivorRatio/(SurvivorRatio+1+1))
尽量把GC控制在MinorGC
-Xmn 100m
Xmn区大小为100m
Xmn为eden+Survivor0+Survivor1
Xmn内存分配为 总内存*(Survivor/(Survivor+S0(默认值1)+S1(默认值1))
-XX PretenureSizeThreshold=n
可以令大于这个设置值的对象直接在老年代分配
只能用于ParNewGC和Serial这两款收集器
MaxTenuringThreshold
一个对象经历多少次GC进入老年代
默认值5
对象年龄的动态判断
如果Survivor空间中相同年龄所有对象大小的总和大于Survivor空间的一半,年龄大于或等于可以直接进入老年代,无需等到MaxTenuringThreshold要求年龄
空间分配担保
检查老年代最大可用的连续空间是否大于历次晋升到老年代对象的平均大小
如果大于,将尝试进行一次minorGC
如果小于,或者设置不允许冒险,那这时也要改为进行一次FullGC
流程图
a.在minorGC之前,检查老年代最大可用连续空间是否大于新生代所有对象的大小
大于执行minorGC
空间不够,检查HandlePromotion是否开启
没有开启,执行FUllGC
开启,检查老年代最大可用连续空间是否大于历次晋升到老年代对象的平均大小
大于,试着执行minorGC
小于执行FUllGC
保证尽量减少FUllGC频率
-Xss
指设定每个线程的堆栈大小
需要根据系统查看每个线程大约需要多少内存,可能会有多少个线程同时运行
-Xmx
整个设定程序运行期间最大可占用内存大小
如果程序运行需要占用更多的内存,超出设定值,就会抛出OutOfMemory异常
内存分配与回收策略
内存分配策略
Eden区
新生小对象进入Eden区
Survivor0区
Survivor1
总称Xmn
老年代
大对象直接进入老年代
长期存活的对象进入老年代
动态对象年龄判定
如果在Survivior空间中相同年龄所有对象大小的总和大于Survivor空间的一半,年龄大于或等于该年龄的对象就可以直接进入老年代
JVM监控
java的bin目录除了java.exe以外还有一些jdk自带的工具
jps
功能:显示正在运行的虚拟机进程
参数
-q:只显示LVMID,省略主类信息(LVMID本地虚拟机进程唯一编号)
-l:显示虚拟机启动进程时传递给main()的参数
-m 显示类全面,如果是jar显示jar路径
-v显示虚拟机启动时的jvm参数
可以jps -lmv 一起使用
用于查询进程编号,以执行后续排查
jstat
功能:显示本地或者远程虚拟机进程中的类装载,内存,垃圾收集,jit编译等参数,是定位虚拟机性能问题的首选工具
参数
-class
监视类装载/卸载数量、总空间以及耗费的时间
loaded
加载class的数量
bytes
class字节的大小
unloaded
未加载class的数量
bytes
未加载class的字节大小
time
加载时间
jinfo
可以在jvm运行时通过该工具增加打印的日志
jmap
-dump
用于生成heap dump 文件,使用 -XX +HeapDumpOnOutOfMermoryError
格式 -dump:[live,]live为是否只生成存活的对象
Memory Analyzer Tool 用于分析MAT
-histo
显示堆中对象的统计信息
permstat
显示永久代内存状态
-heap
显示堆详细信息
jsatck
功能:用于生成虚拟机当前时刻的线程快照
用法[-命令选项]
-f:输出请求不被响应时,强制输出线程堆栈信息
-l除堆栈信息外,附加显示关于锁的信息
-m如果涉及本地方法调用,则显示c/c+的堆栈
Jconse
图形化检测工具
JVM调优
1.合理的编写程序
2.充分并合理的使用硬件资源
3.合理地进行jvm调优
非堆内存的释放
堆外内存
文件句柄
文件IO如果太大,导致JVM宕机
限制文件大小
异步方式
socket句柄
限制一台服务器吞吐量
子主题 2
数据连接
堆内存
大对象
避免使用大对象
尽量减少大对象的生存时间(朝生夕死)
bigObj obj=new bigObj();
obj=null;
提高大对象进入老年代的门槛
降低FullGC频次
重启服务器
一个定时任务触发FullGC
SLA服务等级协议
尽量使用32位版本
目前64位版本效率没有32高
32位最大可用内存4g
64版本内存有接近100g内存
一线互联网的做法
虚拟机或者docker拆分内存
使用CMS垃圾回收器
GC短暂停:适合对于延时要求较高的网络请求
缺点:用的是标记+清除算法,内存碎片多
因此MinorGC用ParNew
虚拟机执行策略
判断是否是热点代码,如果是热点代码就编译执行,不是就解释执行
基于采样的热点判定
虚拟机主动周期性检查各个线程栈顶,若某个方法经常出现在栈顶
优点:实现简单
缺点:很难精确一个方法的热度
基于计数器的热点判定
每个方法都有一个计数器,超过一定次数就是热点方法
方法调用计数器:在client模式下的阈值是1500次,server是10000次
回边计数器:主要统计方法中循环体代码执行次数
编译执行
JIT编译器:及时编译器
Hotspot:热点技术,常用方法直接编译成机器码,省去每次编译的时间
完全编译成机器码
完全编译的话时间久,1g项目两三个小时编译时间
解释执行
解析器
翻译一行,执行一行,启动快,整体效率低
方法调用
方法调用不等同于方法执行
该阶段唯一能确定的是任务就是确定调用哪一个方法
非虚方法
类加载是时候就会把符号引用解析为该方法的直接引用,在解析class阶段就可以确定唯一调用的版本
静态方法
jvm虚拟机中为invokestatic
私有方法
实例构造器
jvm中为invokespecial
父类方法
虚方法
除去final和非虚方法,其他方法称为虚方法
虚函数调用jvm中为invokevirtual
子主题 3
虚拟机动态分派机制
虚方法表(vtabel)
使用虚方法表索引来代替元数据查找以提高性能
如果是class文件需要一层一层在常量表找下去影响性能,所以直接把虚方法放在一张表里,然后去虚方法表检索
itable是接口方法表,也是类似的
类加载器收到请求
委派给父类加载器
搜索自己能否加载该类
自己加载该类
交给子类加载
多线程与高并发
基础概念
什么是线程
进程:一个应用程序,启动以后就是一个进程
一个进程里面最小的基础概念就是线程
线程生命周期
分支主题
线程常用方法
.sleep
睡眠,当前线程暂停一段时间,让给别的线程去运行
.yield
当前线程停止下来进入等待队列,cpu重新选择执行线程
.join
调用join的线程开始执行,当前线程等待调用join的线程运行完了再执行
.getState
获取线程状态
创建线程的3种方法
继承Thread类创建线程
定义Thread类的子类
重写runn()方法
实现Runnable接口创建线程
定义Runnable接口的实现类
重写run()方法
使用Callable和future创建线程
和Runnable接口不一样,callable提供了一个call方法作为线程执行体
call方法功能比run要强大
JAVA5提供了Future接口来代表Callale接口里call()方法的返回值,并且为Future接口提供了一个实现类FutureTask,
Call方法可以有返回值
call方法可以声明抛出异常
匿名类创建线程
启动线程的五种方式
并发编程
锁
可重入锁
当一个线程获取到锁以后,应该是可以重新进入该锁中
当一个线程获取到锁以后,被其他线程抢了cpu资源,其他线程全部进不去,此时抢到锁的线程应该是能够重新进入锁中而不是跟其他线程一样需要重新获取锁.否则从结构上来说就是死锁了
synchronized
上锁关键字
用于线程资源安全
synchronized(this)
锁对象,可以直接写synchronized方法
实现原理
synchronized一共有三把锁
偏向锁
偏向锁,并不是一把锁
而是在锁类信息上增加一个该线程id,表明这个id已经有人在用了
当有另一个锁进入时,锁会升级成自旋锁
自旋锁
自旋锁是有线程自己去查询的
当有一个以上的线程要使用公共资源时,会启动自旋锁,由线程自己去尝试上锁
如果上锁失败会休眠一段时间重新尝试。
当有大量线程进入自旋锁状态时,每个线程都去自己检查会消耗大量cpu资源
此时会升级成重量级锁
重量级锁
有线程超过10次自旋,或者自旋线程数超过CPU核数的一半
由操作系统来进行分配锁,所有线程挂起,进入等待队列,等待操作系统调度。
Thread
多线程
JAVA5新增线程包
自由主题
Set
HashSet
底层结构是HashMap(无序唯一)
存入的时候把值放在key上
如何来保证元素唯一性
hashCode
判断当前hashcode位置是否有元素
equals
相同hashcode则调用equals方法进行比较是否相等
可以存入null
重写put方法
在原hashmapput上通过比对返回值是否等于null来判断是否重复
即便是已经有重复值了还是会进行一次插入
TreeSet
底层数据结构是红黑树。(唯一,有序)
因为要排序来确定插入元素位置所以插入效率低
取出元素需要循环来取因此效率也低
好处是,map有顺序,可以按照重写后的排序依据来排序
不允许有null值
TreeSet中的元素必须实现Comparable接口并重写compareTo()方法
自然排序
比较器排序
通过重写元素的compareTo方法来进行元素比较
TreeSet内部封装了一个TreeMap
实现原理
将值存入TreeMap的Key
返回值的oldValue是否等于null,如果等于null则非重复插入
HashLinkedSet
底层是LinkedHashMap
性能比HashSet好,但是插入时性能稍微逊色于HashSet。
同时使用链表维护元素的次序
可以根据插入顺序排序或者访问顺序排序
Queue
算法
红黑树
红黑树简介
一个具有平衡性的二叉树
节点有红色或者黑色两种颜色
红黑树特点
节点是红色或者黑色的
根节点是黑色的
每个叶子节点都是黑色的空节点
每个红色节点两个叶子节点都是黑色的
每一个节点到根的路径上都不能有两个相连的红色节点
从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点
树介绍
根节点
位于结构的最上层的节点
有且只有一个
叶子节点
每一个节点下一层的节点都可以称为叶子节点
红黑树的特性
红黑数与平衡二叉平衡树的区别
红黑树放弃了完全平衡,只要求大致平衡,使得在与二叉树时间复杂度相差不大的情况下,保证每次最多只需要三次旋转就能达到平衡,实现简单
平衡二叉树追求绝对平衡,未达到绝对的平衡导致旋转次数未知,实现麻烦
Spring
RedisSon
Spring-boot
Zookeeper
架构
单一架构
所有功能都部署在一个jar或war中
存在问题
代码耦合
无法针对不同模块进行优化
无法水平扩展
并发能力差
垂直架构
多个服务器同时处理请求
优点
系统拆分实现了流量分担
可以针对不同模块进行优化
方便水平扩展
系统间相互独立
缺点
负载均衡复杂
服务之间相互调用,如果一个宕机需要手动修改
分布式架构
根据服务内容具体拆分成模块
优点
高并发
高可用
高容错
缺点
异步通讯
架构复杂
负载均衡
服务
OOP
面向对象编程
AOP
面向切面
SOA
面向服务
特点
单一职责
微服务中每一个服务都对应唯一的业务,做的单一职责
微
拆分粒度很小
面向服务
每个服务都要对外暴露API,并不关心服务的具体实现
自治
每个服务间相互独立,互不干扰
团队独立
技术独立
前后端分离
数据库分离
部署独立
docker
中央仓库地址
官方仓库(最全)
hub.docker.com
国内仓库
http://hub.daocloud.io/
局域网仓库(最快)
/etc/docker/deamon.json添加配置
{registry- mirrors": ["https://registry. docker -cn. com"],
"insecure- registries" : [" ip:port" ]}
重启两个服务
daemon -reload
restart docker
CI、CD
指定部署项目
CI
CI介绍
continuous intergration 持续集成
编写代码时,完成一个功能后,立即提交代码到git仓库中,并将项目重新构建并测试
快速发现错误
防止代码偏离分支
Gitlib
gitlib是一个运行git的软件
gitlib用于搭建私人服务器
收藏
0 条评论
下一页