前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >基于SpringBoot的微服务架构与K8S容器部署实践

基于SpringBoot的微服务架构与K8S容器部署实践

作者头像
小熊学Java
发布于 2024-06-18 08:12:10
发布于 2024-06-18 08:12:10
32000
代码可运行
举报
文章被收录于专栏:全栈学习之路全栈学习之路
运行总次数:0
代码可运行

前不久作为架构师完成了某知名快消企业的一个业务中台建设。系统上线后,经历了双十一活动的流量高峰,整体运行稳定。最近有空,便将此次架构的思路,心得稍作整理在这篇博客中分享一下。不会深入每一个技术细节,而是把用到的技术、框架、工具做一个简单的回顾,作为日后的参考。

业务架构

业务架构方面,该系统作为业务中台,主要负责客户资产管理,包括客户的卡、券以及其他虚拟资产。通过对外暴露标准restful接口的方式提供服务。服务的调用方包括自有渠道的app、小程序,以及合作伙伴渠道,包括招行、阿里等。而系统本身也会通过服务网关去调用公司内部的其他业务系统接口,如通过客户中心接口同步会员信息等。

根据目前的统计,这个业务中台,每日的服务调用量在700万次左右,有活动时也会超过1000万次。而大部分交易,发生在上班、午休以及下午3点左右(下午茶)的时间段内。

由于涉及到客户业务细节,这里对业务架构就不做详细说明了。

技术架构

这个案例中采用了基于SpringBoot的微服务架构。结合企业自身的基础架构设施,进行K8S容器化部署,并采用Kong API Gateway对各业务中台暴露的API接口进行统一管理。

Kong API Gateway

随着微服务架构在企业中的流行,原来大而全的系统被拆分为粒度较小的中台,而系统中的大部分功能则被以restful API形式提供的服务所取代,这使得IT系统能够更加快速地响应业务变化带来的挑战,但同时随着服务的增加,如何有效管理这些服务却成为难题。

在一些中小型项目中,我们一般都会采用Spring Cloud的技术栈,并选择Spring Cloud Gateway来作服务网关。然而,对于一些大型企业,则需要全局考虑服务的治理,网关性能,以及其他扩展功能。

在这个案例中,企业使用了Kong作为API网关。中台将需要开放外部使用的API,通过网关控制台进行注册,添加证书,生成Auth Key供关联方使用。

Kong具有以下一些特性,能够很好地满足大型组织对于服务网关的需求:

  • 开源(本案例中使用的是Kong的企业版,提供了原厂服务)
  • 亚毫秒级的响应延迟,得益于基于Nginx与OpenResty带来的超高性能
  • 单节点25K TPS
  • 认证、授权、限流、数据转换(此案例中会员ID被添加到请求头中)、日志、统计分析

应用架构

整个系统采用java开发后端以及vue开发前端,应用部分共分为4个服务组件,全部进行容器化部署,并通过Ingress Controller负载均衡对外暴露服务:

  • 资产服务:提供客户资产相关的服务接口
  • 资产消费者服务:MQ监听服务,异步处理资产相关请求
  • 控制台服务:资产管理运维类服务接口,供控制台前端使用
  • 控制台前端服务:使用Vue开发的控制台前端应用(如下图)

SpringBoot

除控制台前端外,其他三个组件均采用目前主流的java微服务框架SpringBoot 2.3.4开发(考虑到稳定性,未使用最新的2.4版本)。

本案例中,通过开发应用框架,实现了系统中数据表达形式的统一,以及标准的据转换、校验、消息绑定、错误处理等功能。架构师需要对应用框架负责,简明、高效、统一的应用框架,能够提升开发效率,产出标准一致的代码,保证交付质量。

应用框架不在本文的讨论范围内,而以下一些技巧或第三方包,却在我们构建大多数SpringBoot应用中得到使用。

####定制MyBatis 数据层框架采用MyBatis,在大型应用中MyBatis能够帮助程序员更好地控制数据层交互,并进行调优。一般可以在applicaion.yml中配置MyBatis,但当我们需要让MyBatis支持更多定制特性(如:多数据库支持)时,可以通过定义SqlSessionFactory bean来实现。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制

java
复制代码
    @Bean
    public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
        SqlSessionFactoryBean sfb = new SqlSessionFactoryBean();
        sfb.setDataSource(dataSource);
        sfb.setVfs(SpringBootVFS.class);
        Properties props = new Properties();
        props.setProperty("dialect", dataConfiguration.getDialect());
        props.setProperty("reasonable", String.valueOf(dataConfiguration.isPageReasonable()));
        PageHelper pagePlugin = new PageHelper();
        pagePlugin.setProperties(props);
        Interceptor[] plugins = {pagePlugin};
        sfb.setPlugins(plugins);

        ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();

        sfb.setMapperLocations(resolver.getResources("classpath*:mappers/"+ dataConfiguration.getDialect()+"/*.xml"));
        sfb.setTypeAliasesPackage("com.xxx.bl.core.data.model");

        SqlSessionFactory factory = sfb.getObject();
        factory.getConfiguration().setMapUnderscoreToCamelCase(true);
//        factory.getConfiguration().addInterceptor(new CoreResultSetHandler());
        factory.getConfiguration().setCallSettersOnNulls(dataConfiguration.isCallSettersOnNulls());
        return factory;
    }
使用logback日志组件

采用logback日志框架,可以在logback配置文件中指定针对不同的Spring profile在不同的环境中采用不同的日志级别,并采用不同的appender。同时引入spring-cloud-starter-sleuth依赖,通过设置traceId,使整个请求全链路上的所有日志打印出一致的traceId,大大方便了各系统间生产问题的协同排查。另外,采用异步方式记录日志,也有利于降低IO阻塞。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制

xml
复制代码
   <springProfile name="stg">
        <root level="error">
            <appender-ref ref="STDOUT"/>
            <appender-ref ref="SAVE-ERROR-TO-FILE-STG"/>
        </root>
        <logger name="org.xxx" level="error" additivity="false">
            <appender-ref ref="STDOUT"/>
            <appender-ref ref="ASYNC-SAVE-TO-FILE-STG"/>
        </logger>        
    </springProfile>
    <springProfile name="prod">
        <root level="error">
            <appender-ref ref="STDOUT"/>
            <appender-ref ref="SAVE-ERROR-TO-FILE-PROD"/>
        </root>
        <logger name="org.xxx" level="error" additivity="false">
            <appender-ref ref="ASYNC-SAVE-TO-FILE-PROD"/>
        </logger>
    </springProfile>
SSL加密及密码安全

全链路传输加密已成为企业安全中必不可少的措施。通过在classpath中引入CA颁发(也可以使用自签)的jks证书,并在application配置文件中进行简单配置,便可实现SpringBoot应用的SSL加密。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制

yml
复制代码
  ssl:
    enabled: true
    key-store: classpath:xxx.net.jks
    key-store-type: JKS
    key-store-password: RUIEIoUD
    key-password: RUIEIoUD
    require-ssl: true

密码以明文形式存放在配置文件中,也是不安全的。你可以jasypt加密配置文件中使用到的密码,或者直接使用Key-Vault方案,比如本案例中会分别在微软云环境中使用Azure Key Vault或本地IDC中使用Cyberark Conjur方案。

###同步与异步服务 我们并没有使用Spring Webflux来支持reactive特性,因为,这会增加开发复杂度,并且Webflux虽然改善了Web容器阻塞机制,但并不能从根本上解决高并发请求到来时的阻塞问题。

在这个案例中,通过搭建了3个节点的RabbitMq镜像集群,作为消息中间件,并通过应用框架的支持,实现了服务的同步异步切换功能。我们将对外提供的服务注册到数据库中,在应用启动时,读入redis缓存。当请求到来时,通过API code判断该请求的响应模式:同步或异步。如果是同步请求则直接处理,而如果是异步请求,则发送到RabbitMq中,再由经过封装的消费者组件进行异步消费,最终达到削峰的目的。

对于开发人员来说,他们只需要关注服务的业务逻辑开发,由应用框架统一处理服务的同步,异步切换,消息发送或失败时的异常处理,以及死信队列的维护等工作。

Dockerfile

案例中的四个组件需要实现容器化部署,分别为SpringBoot应用与Vue应用创建Dockerfile。

典型的SpringBoot应用Dockerfile如下,一般情况下大型组织会构建私有镜像仓库,通过私有仓库拉取镜像的速度更快,能够节省CICD的时间。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制

docker
复制代码
FROM openjdk:11-jre
#FROM cargo.xxx.net/library/openjdk:11-jre
ARG JAR_FILE=console-service/build/libs/*.jar
COPY ${JAR_FILE} app.jar
EXPOSE 9002
EXPOSE 9003
ENTRYPOINT [ "java", "-jar", "/app.jar" ]

vue应用的Dockerfile如下,同样添加了SSL证书,进行传输加密:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制

docker
复制代码
FROM cargo.xxx.net/library/nginx:stable-alpine
COPY /dist /usr/share/nginx/html/console
COPY nginx.conf /etc/nginx/nginx.conf
ARG KEY_FILE=stg.xxx.net.key
ARG PEM_FILE=stg.xxx.net.pem
COPY ${KEY_FILE} /etc/ssl/certs/cert.key
COPY ${PEM_FILE} /etc/ssl/certs/cert.pem
EXPOSE 80
CMD [ "nginx", "-c", "/etc/nginx/nginx.conf", "-g", "daemon off;" ]

编写dockerfile时有以下一些注意事项:

  • 基础镜像:尽可能推荐选择官方镜像
  • 选择大小适中的版本:如果选择的基础镜像过大,启动后需要消耗更多的资源,影响系统性能。如果太小,则可能缺失关键功能。
  • 利用缓存:将dockerfile中不易变动的内容写在dockerfile最前。

##数据库架构 在账户数据上亿,交易数据几百亿的系统,需要采用分库分表方案。本案例中,采用了MyCat+MySQL的数据库架构方案。采用mycat代理Master与Slave,可灵活进行主从切换。Slave可作为Master热备,也同时可作为读库,实现读写分离。备库除作为准实时的备份外,也可作为运维库或提供大数据平台数据抽取。

同时采用1主2从1备的双机房设计

  • Master到Slave使用半同步方案,保证从库数据一致性
  • Master异常时,通过mycat切换至Slave,Slave转换为新Master
  • Master异常恢复后,先将原Master设置为Slave,数据同步完成后,再切换回正式Master

mycat高可用

mycat采用k8s容器化运行,使用k8s service来实现mycat的负载均衡,达到mycat的集群的高可用。若mycat容器节点异常,应用自动连接到另外的mycat节点上。

对数据库的大量操作是读操作,一般占到所有操作70%以上。所以做读写分离还是很有必要的,如果不做读写分离,那么从库也是一种很大的浪费。mycat通过配置很容易做到读写分离,在从库进行读操作,提升资源利用率,在主库进行写操作,减低主库压力。

分库分表

  • 垂直分库:按照功能划分,把数据分别放到不同的数据库和服务器。例如:账户、资产、交易等业务领域不同的数据分别放在不同的库中,分散压力、减少相互影响、降低耦合,独立模块独立发布
  • 水平分库:在垂直分库不能满足要求时,再对模型进行水平的 切分,将同一实体,不同范围的数据分散到不同库中,保持单库数量和压力,提升连接数,达到横向扩展的目的。

冷热数据方案

热数据缓存
  • 对于高频使用的热数据,如经常使用App的客户信息等,适当增加数据库query cache,提升数据库查询性能。
  • 在应用层使用redis等内存缓存部分高频使用数据,降低请求响应时间,增加系统流畅度,提升客户体验。
  • 进行读写分离,使用从库提供数据查询的服务,提升从库硬件资源利用率,降低主库读压力,增加主库写性能。提升整体效率。
冷数据归档
  • 对于使用频率很低或基本不使用的冷数据,如历史交易、历史卡券等,进行数据的归档,提升数据库的性能。
  • 也可提供使用频率较低的历史交易查询功能,使用备库提供服务。
  • 对于交易类数据建议按日期进行分库分表,每日交易分为一片或多片,对于历史交易如1年前交易进行定期迁移和归档,提升数据库性能。

DEVOPS与K8S容器化部署

####DEVOPS流水线 本案例中,通过基于jenkins的CICD平台,将应用代码从github代码库获取,使用gradle进行构建(前端使用npm构建),通过dockerfile打成镜像后,部署到K8S容器平台。

在进行持续集成的过程中,同时加入了安全检查,合规检查以及单元测试(SpringBoot应用使用JUnit,Vue前端应用使用Jest测试框架)的步骤,以保证每一次发布的质量。###ConfigMap ConfigMap用于将应用的配置信息与程序的分离,这种方式不仅可以实现应用程序被的复用,而且还可以通过不同的配置实现更灵活的功能。本案例中,SpringBoot应用在K8S部署时,便将application.yml文件以ConfigMap文件的形式进行挂载。需要注意,SpringBoot会优先读取classpath下的配置文件,因此需要在打出springboot应用jar包时,先将配置文件排除,并通过容器启动命令参数来制定挂载的应用配置文件。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制

ini
复制代码
-spring.profiles.active=prod
-spring.config.location=/config/application.yml

###K8S容器部署 在K8S部署平台,可以为每一个服务指定初始的资源,以及节点数量配置。比如我们为SpringBoot应用初始配置,2core 4g的资源配置,节点数量则为20个。

根据需要我们可以采用滚动方式对pod数量进行伸缩。而不会引起服务不可用的情况。

另外,我们也可以利用弹性伸缩,基于某些关键指标,如容器的CPU使用量作为阈值,来触发容器进行弹性伸缩。在这个案例中,通过弹性伸缩机制,在上班以及中午业务高峰时间段内,将更多pod提供给业务服务组件,而在晚上,则会将pod从业务组件收回,提供给需要跑批处理以及异步消费的服务组件。

运维与监控

ELK

ELK是一套解决方案而不是一款软件, 三个字母分别是三个软件产品的缩写。E代表Elasticsearch,负责日志的存储和检索;L代表Logstash, 负责日志的收集,过滤和格式化;K代表Kibana,负责日志的展示统计和数据可视化

Dynatrace

Dynatrace可能是目前最优秀的应用性能管理工具(APM),它既能监控基础设施如服务器,K8S容器,又能自动发现并监控在容器内运行的动态微服务,了解它们如何执行、相互之间如何通信,还能立即检测出性能不佳的微服务。在我们的案例中,通过定制dashboard添加我们所需要关注的监控数据。

Dynatrace还能自动识别服务,并提供更精细的检测数据,为开发或运维人员定位问题,带来了极大的帮助。

一些思考

  • 数据库分库分表方案带来的代码侵入问题:MyCat+MySQL虽然在物理上实现了分库分表,但对于开发来说带来了侵入性问题,需要为分片键进行特殊的表结构设计,在进行查询时也需要额外考虑分片键的使用,以提升查询效率。其他的如事务的处理,由于分库的关系,我们不再依赖事务,而是通过数据最终一致性,以及错误补偿等方式进行处理。
  • 未来数据库的选型:MyCat+MySQL给数据库运维增加了复杂性,而未来针对超大数据量级的应用,在硬件资源允许的情况下,可以考虑转向如:TiDB这样的NewSQL方案进行替代。
  • JVM优化:应用上线后,在高并发情况下曾偶发Long GC问题,通过分析dump文件,优化内存使用,进行了解决。另外,对于内存变化较大的应用,也可以考虑使用jdk13,并开启ZGC。
  • 缓存优化:案例中通过redis缓存服务配置信息,每次服务响应时都需要读取redis,这给redis造成了不小的压力,通过引入Guava cache,在本地建立缓存副本实现多级缓存,并设定合理的失效时间,能够显著降低对redis的压力。
  • 通过应用框架实现低代码:在应用框架上的投资是非常值得的,通过将共性问题集中在应用框架中解决,可以在一定程度上实现低代码平台的特性。开发人员也能更专注于业务逻辑的实现。
  • 开发管理:通过让每位开发人员充分理解应用框架,并形成解决同类问题的统一Pattern,能够明显提高开发效率,减少低质量代码的产生。
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2024-06-13,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 小熊学Java 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
微服务架构实战:云服务环境与Docker部署工具
完成微服务的开发之后,必须为其提供-一个合 适的分布式环境进行最终的部署和发布,才能充分发挥微服务架构的优势。这个环境首先应该是安全可靠的,并且是可以进行任意扩展的分布式环境。其次,它的基础设施应该是配备齐全的,并且稳定可靠、可扩展。这些基础设施包括数据库管理系统、文件管理系统、消息服务系统等服务,以及自动化测试和持续交付等工具。
愿天堂没有BUG
2022/10/28
7200
微服务架构实战:云服务环境与Docker部署工具
一起来学SpringBoot | 第三篇:SpringBoot日志配置
SpringBoot 内部采用的是 CommonsLogging进行日志记录,但在底层为 JavaUtilLogging、 Log4J2、 Logback 等日志框架提供了默认配置 。
battcn
2018/08/03
6880
一起来学 SpringBoot 2.x | 第三篇:SpringBoot 日志配置
摘要: 原创出处 http://blog.battcn.com/2018/04/23/springboot/v2-config-logs/ 「唐亚峰」欢迎转载,保留摘要,谢谢!
芋道源码
2019/10/29
1.3K0
基于 Docker 的微服务架构实践
基于 Docker 的容器技术是在2015年的时候开始接触的,两年多的时间,作为一名 Docker 的 DevOps,也见证了 Docker 的技术体系的快速发展。本文主要是结合在公司搭建的微服务架构的实践过程,做一个简单的总结。希望给在创业初期探索如何布局服务架构体系的 DevOps,或者想初步了解企业级架构的同学们一些参考。
烂猪皮
2018/08/03
2.6K0
基于 Docker 的微服务架构实践
springboot中使用logback
Springboot默认集成的就是logback,logback相对来说是优秀于log4j的,log4j2也是参考了logback的设计。本篇就是来看看如何使用logback。
天涯泪小武
2019/01/17
5020
从单体应用,微服务,容器化,小团队的微服务架构演进之路
微服务是否适合小团队是个见仁见智的问题。回归现象看本质,随着业务复杂度的提高,单体应用越来越庞大,就好像一个类的代码行越来越多,分而治之,切成多个类应该是更好的解决方法,所以一个庞大的单体应用分出多个小应用也更符合这种分治的思想。当然微服务架构不应该是一个小团队一开始就该考虑的问题,而是慢慢演化的结果,谨慎过度设计尤为重要。
搜云库技术团队
2019/10/17
1.7K0
SpringBoot日志详解使用include
一共有7个微服务,其中每一个微服务各自都有4个这样logback-spring-{active}.xml文件。
半月无霜
2024/02/04
2840
SpringBoot日志详解使用include
springboot 之日志配置
一直没机会做spring生态圈的框架,公司选择的是一些小众的微服务,鉴于此考虑,丰富自己的技术栈,花了两天时间从网上各网站上学习了springboot一些基础知识。 本章只介绍springboot微服务的默认日志配置,logback组件。
felixxue
2022/12/30
2920
springboot 之日志配置
SpringBoot | SpringBoot 是如何实现日志的?
说到日志框架不得不说门面模式。门面模式,其核心为外部与一个子系统的通信必须通过一个统一的外观对象进行,使得子系统更易于使用。用一张图来表示门面模式的结构为:
JavaFish
2019/10/18
6920
SpringBoot | SpringBoot 是如何实现日志的?
04_SpringBoot中日志的配置和使用
spring boot 默认会加载 classpath:logback-spring.xml 或者 classpath:logback-spring.groovy。
全栈程序员站长
2022/07/05
3860
04_SpringBoot中日志的配置和使用
SpringBoot 日志
市面上的日志框架: JUL、JCL、Jboss-logging、logback、log4j、log4j2、slf4j ...
jwangkun
2021/12/23
2830
SpringBoot 日志
基于K8S的容器云平台如何部署微服务?
K8S是第一个将“一切以服务为中心,一切围绕服务运转”作为指导思想的创新型产品,它的功能和架构设计自始至终都遵循了这一指导思想,构建在K8S上的系统不仅可以独立运行在物理机、虚拟机集群或者企业私有云上,也可以被托管在公有云中。
小小科
2018/10/22
7.8K1
基于K8S的容器云平台如何部署微服务?
【SpringBoot】在SpringBoot中集成日志收集
效果圖 日志框架选择 Springboot 日志管理配置logback-spring.xml application.yml配置 spring: application: name: be
瑞新
2020/12/07
6860
【SpringBoot】在SpringBoot中集成日志收集
SpringBoot日志配置详情
在所有的项目中,日志是必不可少的,为了高效清晰的查找日志,可以配置日志输出的等级和格式。
半月无霜
2023/03/03
1.4K0
SpringBoot日志配置详情
SpringBoot日志框架
日志框架的出现是为了更好的控制软件运行记录的信息,如果使用大量的System.out.println("")将无法有效的控制输出,市面上常见的日志框架有: JUL、JCL、Jboss-logging、logback、log4j、log4j2、slf4j…
HaC
2020/12/30
7890
SpringBoot日志框架
SpringBoot配置logback
spring boot 默认会加载 classpath:logback-spring.xml 或者 classpath:logback-spring.groovy。
崔笑颜
2020/06/08
3.4K0
浅谈微服务架构、容器技术与K8S
如果在诸多热门云计算技术诸如容器、微服务、DevOps、OpenStack等之中,找出一个最火的方向,那么可能非微服务莫属。尽管话题炙手可热,但对传统行业来说,微服务落地和方法论目前处于起步阶段。
嘉为蓝鲸
2018/12/21
2.6K0
Kubernetes(K8s) —— 容器编排管理技术
kubeadm 是官方社区推出的一个用于快速部署 kubernetes 集群的工具,这个工具 能通过两条指令完成一个 kubernetes 集群的部署:
时间静止不是简史
2021/08/12
15.4K1
Kubernetes(K8s) —— 容器编排管理技术
微服务技术栈选型手册
2014年可以认为是微服务1.0的元年,当年有几个标志性事件,一是Martin Fowler在其博客上发表了“Microservices”一文,正式提出微服务架构风格;二是Netflix微服务架构经过多年大规模生产验证,最终抽象落地形成一整套开源的微服务基础组件,统称NetflixOSS,Netflix的成功经验开始被业界认可并推崇;三是Pivotal将NetflixOSS开源微服务组件集成到其Spring体系,推出Spring Cloud微服务开发技术栈。
爱撸猫的杰
2019/03/28
1.2K0
微服务技术栈选型手册
《ArchSummit:从珍爱微服务框架看架构演进》
今年的ArchSummit的主题是“数字化转型下的架构升级”,主要聚焦:云原生、研效提升、IoT 系统架构、微服务架构、低代码系统、出海业务架构、人工智能与机器学习、企业数字化转型、前端 Serverless 研发体系、金融领域数字化转型、大数据实践与应用等领域。
后台技术汇
2022/11/08
5930
《ArchSummit:从珍爱微服务框架看架构演进》
相关推荐
微服务架构实战:云服务环境与Docker部署工具
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验