>>分享流行的Java框架以及开源软件,对孙卫琴的《精通Spring:Java Web开发技术详解》提供技术支持 书籍支持  卫琴直播  品书摘要  在线测试  资源下载  联系我们
发表一个新主题 开启一个新投票 回复文章 您是本文章第 23787 个阅读者 刷新本主题
 * 贴子主题:  你的应用什么时候该拆分到多个容器中? 回复文章 点赞(0)  收藏  
作者:Jacky    发表时间:2018-03-22 23:16:25     消息  查看  搜索  好友  邮件  复制  引用

Docker的最佳实践提出了“一个容器内只运行一个进程”之后,是否需要将应用拆分到多个容器中就成了一个热门话题。本文以一个普通的Java应用作为讨论,从软件设计的角度来介绍为什么要将其拆分到多个容器中。

假设一个标准的Java Web应用包含以下两部分:
1. 基于Struts框架的前端应用;
2. 基于Java EE的后端REST API服务;

这两部分通常运行在同一个容器(如Tomcat)中,相互之间基于REST接口进行交互。类似这种应用,我们应该将其拆分到不同的容器中运行吗?
简单的回答:我们应该将其拆分到不同的容器中,但这需要经过谨慎的考虑。
抛开一些“普适”的原则(如“一个容器只运行一个进程”),我们主要从应用本身和部署策略上进行考虑。
首先,我们抛开具体业务场景,做一些设计思考(Design Thinking):
1. JVM本身支持多线程,因此通常的Java应用程序都运行在一个进程中,以多线程的方式进行并行处理。类似Tomcat这样的容器本身也支持将多个Java应用程序运行在一个Java进程中。
2. 事实上,很多已经容器化的应用,在容器中实际运行时也是多进程的,例如Apache的prefork模块。同时,当前流行的网络应用(如Nginx)大量使用事件驱动和反应器模式,这些设计的方向,都是将IO操作交给内核,将业务逻辑处理交给子进程(线程)。Linux内核非常善于调度子进程,但是这不是诸如Kubernetes、Swarm等容器调度工具擅长的地方。进程(线程)侧重于内核资源的划分,而容器侧重于集群资源的划分。
3. “一个容器只运行一个进程”的原则,更像一种哲学。作为工程师,我们应该从实际出发考虑技术架构和应用逻辑。同时这个“最佳实践”甚至没有获得广泛的赞同,它的传播可能是因为对Unix运作原理缺乏了解导致的。
4. Linux容器(LXC)历史上有很多种形式,其中很多是建议在一个容器中运行多个进程的。Linux容器实质上是clone系统调用、SELinux、cgroup等技术的组合,上层使用LXC或者Docker(libcontainer)对于这些底层技术是不相关的,因为最终都依赖于内核的隔离技术。
5. 进程间交互有多种形式,如套接字、文件、网络等,每种方式都有自己的优缺点。如果考虑将应用拆分到不同容器中,对应用程序内部组件之间的通信方式会有很大影响。
6. 代码、配置和数据的独立性,也对是否能够拆分到不同容器的重要考量。如果应用程序的代码、配置和数据相互独立性比较强,就能够方便的将其拆分成独立的组件,放置到独立的容器中;反之,如果应用内部分层不清,拆分成本会非常高。值得注意的是,我们没有必要为了容器化而对应用做过多的改造,只要能够按照Docker镜像的格式制作成镜像,我们仍然能够享受到Docker带来的便利:方便的分发(利用Docker注册中心)和运行(使用docker run命令)。

上面总结了一些从系统层面看是否需要拆分到多个容器,回到我们的例子:
1. 这两个Java组件功能上相互独立。一个是web前端,一个是API服务。由于它们是完全不同的服务,是否运行在一个JVM(Java进程)中对性能损耗非常小(当然,这只是相对的,因为它们将无法公用堆内存和垃圾回收)。
2. 这两个组件之间使用REST API进行交互,没有使用传统的进程间交互方式(套接字、共享内存等)。
3. web前端和API服务的使用场景不同,针对不同的场景,在运维层面可能需要独立的进行扩容。例如除了web前端之外,API服务还能提供给其他组件使用,因此API服务可能会因为接入方的变化需要独立扩容和缩容。这时候就是充分利用容器编排框架(如Kubernetes、Mesos、Swarm等)能力的时候了。

基于上述三点考虑,我会将这个Java应用的两个组件拆分到独立的容器中。同时建议配合使用诸如Kubernetes的容器编排框架,将两个服务关联到一起。
总结一下我们的“最佳实践”:
如果你的应用代码、配置和数据相对独立,并且有清晰的交互形式,将应用组件拆分到多个容器中是有意义的。




程序猿的技术大观园:www.javathinker.net

  Java面向对象编程-->泛型
  JavaWeb开发-->JSP技术详解(Ⅱ)
  JSP与Hibernate开发-->Java应用分层架构及软件模型
  Java网络编程-->创建非阻塞的HTTP服务器
  精通Spring-->Vue简介
  Vue3开发-->Vue Router路由管理器
  Redis夺命连环11问
  Spring AOP的基本概念和注解
  Spring MVC文件上传与下载
  springMVC:HandlerInterceptor拦截器的使用
  Spring 自动注入的三种方式:byName、byType、constructor
  回字有四种写法,那你知道单例有五种写法吗
  POJO与JavaBean与SpringBean的概念与区别
  Spring Cloud Config 客户端的高可用实现
  Redis用作消息队列
  开发一个Java项目的基本流程
  Spring+JPA+ehcache开启二级本地缓存
  Zabbix后端存储ES的优化实践
  带你逆袭kafka之路
  分布式架构知识体系
  springmvc+ajax异步上传图片
  更多...
 IPIP: 已设置保密
楼主      
该用户目前不在线 nihaota 
  
威望: 0
级别: 新手上路
魅力: 1315
经验: 1315
现金: 2944
发文章数: 243
注册时间: 0001-01-01
 消息  查看  搜索  好友  邮件  复制  引用


讨债公司
发文章时间 2022-10-28 21:50:15
 IPIP: 已设置保密 1 楼     
1页 1条记录 当前第1
发表一个新主题 开启一个新投票 回复文章


中文版权所有: JavaThinker技术网站 Copyright 2016-2026 沪ICP备16029593号-2
荟萃Java程序员智慧的结晶,分享交流Java前沿技术。  联系我们
如有技术文章涉及侵权,请与本站管理员联系。