后端+数据库


Java 的 bean 是什么?

用大白话来说,Java 的 Bean(JavaBean) 就是一个“装属性的小容器”。

你可以把它想象成现实生活中装东西的盒子,比如:

  • 一个“人”的 Bean 里装着:名字、年龄、性别;
  • 一个“订单”的 Bean 里装着:订单号、下单时间、金额。

特点

  1. 属性是私有的(private)
    👉 就像盒子外面看不到里面装了啥,不能直接伸手去拿,要通过“开关”来操作。

  2. 通过 get/set 方法来访问属性
    👉 给你配了专门的按钮(getter/setter)来打开盒子取东西或往里面放东西。
    比如:

    public class Person {
        private String name;  // 装了名字
    
        public String getName() {  // 按这个按钮可以读名字
            return name;
        }
    
        public void setName(String name) {  // 按这个按钮可以改名字
            this.name = name;
        }
    }
  3. 有无参构造方法
    👉 你可以空手创建一个盒子,不需要一开始就把东西放进去。

存在的意义

主要是用来 传递数据。比如:

  • 数据库查出来的一行数据,你用一个 Bean 来装;
  • 前端传给后端的数据,用 Bean 来接;
  • 不同系统之间通信,用 Bean 来打包成一个数据对象。

Java 里如何创建线程?

法一:继承 Thread

public class MyThread extends Thread {
    @Override
    public void run() {
        System.out.println("线程正在运行:" + Thread.currentThread().getName());
    }

    public static void main(String[] args) {
        MyThread t1 = new MyThread();
        t1.start(); // 启动线程,不是调用 run()
    }
}
  • 重写 run() 方法写线程逻辑。
  • start() 启动线程(不是 run(),否则只是普通方法调用)。

法二:实现 Runnable 接口(更常用)

public class MyRunnable implements Runnable {
    @Override
    public void run() {
        System.out.println("线程正在运行:" + Thread.currentThread().getName());
    }

    public static void main(String[] args) {
        Thread t1 = new Thread(new MyRunnable());
        t1.start();
    }
}
  • 线程逻辑写在 run() 里。
  • 可以避免单继承限制(你还能继承其他类)。

法三:使用匿名类或 Lambda(推荐写法)

public class Main {
    public static void main(String[] args) {
        // 匿名类方式
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("线程运行中:" + Thread.currentThread().getName());
            }
        });

        // Lambda 方式(JDK 8+)
        Thread t2 = new Thread(() -> {
            System.out.println("Lambda线程运行:" + Thread.currentThread().getName());
        });

        t1.start();
        t2.start();
    }
}

补充知识点

  • run() 是线程要执行的逻辑;start() 是启动线程的入口。
  • 一个 Thread 实例只能调用一次 start()
  • 多线程执行是并发的,顺序无法保证。

前台与中台的数据对比工具

这个工具分成两个模块:schema 比对 和 数据比对。
schema 比对会解析两个系统的接口结构,提取字段信息(名、类型、精度等)并用自定义字段映射解决命名不一致问题。
数据比对模块则是对同一笔交易的多系统数据进行字段级比对,输出字段差异。CLI 工具的形式方便集成到日常开发和治理流程中。

制作的起因

数据口径对齐”是数据分析、报表、管理等工作中常见的一个术语,它指的是:

在多个数据来源、系统、团队或分析维度中,统一数据统计的口径、标准和计算方式,以确保数据的一致性、可比性和准确性。

📌 举个通俗的例子:

假设你是公司的数据分析师,你要统计“月活跃用户数”。

  • A 部门按“登录过系统”的用户算;
  • B 部门按“浏览页面超过 3 次”的用户算;
  • C 部门按“有下单行为”的用户算。

虽然大家都说“月活跃用户”,但口径(也就是计算标准)不同,结果自然也不同。这时就需要“对齐数据口径”:

  • 大家统一确定:比如“月活跃用户”定义为“30 天内至少登录一次”的用户。
  • 各部门、各系统都按照这个标准来统计。
  • 最终报表就能对得上,不会“公说公有理,婆说婆有理”。

为什么数据口径对齐很重要?

  • 避免部门扯皮(你说涨了我说跌了)
  • 保证报表一致(老板问数据时不会出错)
  • 提升决策质量(基于一致标准的数据,才能信得过)
  • 方便自动化统计报表系统建设

业务分析、报表开发、数据治理或者跨部门沟通时听到“数据口径对齐”,大概率就是在强调“我们先把统计标准统一一下,否则后面的数据比不起来”。


oracle 和 mongoDB 有什么区别

Oracle MongoDB
传统的关系型数据库 新型的非关系型数据库(NoSQL)
用表格(表、行、列)存数据 用类似 JSON 的文档存数据

其中,mongoDB 有单个 document(也就是一条记录)不能超过 16MB。如果你需要存储更大的数据,可以考虑:1. 使用 GridFS,专门用于存储大文件(如图片、视频等)2. 将数据拆分成多个文档(例如分段存储)

一般来说,MongoDB 的读写速度更快,尤其是在大数据量、结构灵活、无复杂事务的场景下。
但如果涉及复杂查询、事务一致性要求高,Oracle 更适合。

为啥 MongoDB 更快?

  1. 文档型结构
    MongoDB 存储的是 BSON(二进制 JSON),读取/写入整个文档更快,不像 Oracle 要处理多个表、多个行的关系。
  2. 无 schema 限制
    插入数据时不校验字段类型、约束等,开销小。
  3. 天然内存缓存机制
    MongoDB 有自己的内存映射机制,把热数据放内存里,读得更快。
  4. 水平扩展强
    MongoDB 容易做分片(sharding),读写可并行处理;而 Oracle 分布式支持复杂且成本高。

那 Oracle 是不是就慢?

也不是。

Oracle 是为“数据一致性”和“复杂事务”设计的,比如:

  • 银行转账这种需要同时改多张表、强事务控制的场景;
  • 对 SQL 查询优化支持非常强(执行计划、索引、多表连接等);
  • 支持非常复杂的分析和聚合操作。

但这些保证是以牺牲写入速度为代价的。

对比

项目 MongoDB Oracle
写入速度 快 ✅ 慢(要事务和约束)
读取速度 快(读文档) ✅ 慢一点(解析表结构)
查询复杂度 支持有限 支持强大 ✅
一致性 弱一些 强 ✅

MongoDB 在不需要复杂事务、结构灵活的情况下读写非常快,特别适合日志、缓存、实时数据这类场景。而 Oracle 虽然写入速度慢些,但更适合要求强一致性、复杂 SQL 查询的业务,比如金融、银行系统。两者各有优势,取决于业务需求。


MongoDB 改用 Redis?

方面 Redis 优势 MongoDB 特点
性能 内存操作,极快的读写速度(>10 万 QPS) 基于磁盘,读写延迟较高(~毫秒级)
并发处理 单线程 + I/O 多路复用,处理高并发更稳定 支持多线程,但在高并发下响应抖动较大
数据结构 提供丰富数据结构(Hash、Set、ZSet 等) 类似 JSON 的 BSON 文档结构,通用性更强
使用场景 缓存、计数器、排行榜、限流等实时场景 业务数据持久化、复杂查询、二级索引等
数据容量 受限于内存大小(可做持久化) 支持海量数据存储(TB 级别)
查询能力 不支持复杂查询、关联查询 支持复杂的多条件查询、聚合等

面试中简洁高效地表达

在数据量很大的情况下,使用 Redis 相较于 MongoDB 的优势主要体现在以下几方面:

  1. 读写性能高:Redis 是基于内存的数据库,单线程处理速度极快,适合高并发读写场景;
  2. 快速响应和低延迟:内存操作通常在微秒级,而 MongoDB 属于磁盘数据库,响应速度会慢几个数量级;
  3. 适合缓存热点数据:在大数据场景下,可以把高频访问数据放入 Redis 缓存,减轻 MongoDB 的压力;
  4. 支持多种高效的数据结构:如 Hash、List、Set、SortedSet,适合排行榜、计数器等需求。

不过 Redis 是内存数据库,不适合存储所有数据,通常与 MongoDB 搭配使用,即“冷热数据分离”策略。所以,在数据量大且读写频繁的场景下,使用 Redis 可以大幅提升系统性能,MongoDB 则适合长期存储和复杂查询,实际生产中一般是两者搭配使用,而不是完全替换。


Redis 基础知识

Redis 是什么?有什么优点?

  • 内存中的高性能Key-Value存储系统
  • 支持多种数据结构:字符串、列表、集合、有序集合、哈希
  • 高性能:读写速度高达 10 万 QPS
  • 持久化分布式支持、丰富数据结构

Redis 数据类型?应用场景?

数据类型 命令示例 应用场景
String SET,GET 缓存对象、计数器、限流标志
List LPUSH,RPOP 消息队列、时间线
Hash HSET,HGET 存储对象(如用户信息)
Set SADD,SISMEMBER 标签、去重、社交关注
ZSet ZADD,ZRANGE 排行榜、优先队列
Bitmap SETBIT,BITCOUNT 活跃用户统计
HyperLogLog PFADD,PFCOUNT 近似去重统计(UV)
Geo GEOADD,GEORADIUS 地理位置相关应用
Stream XADD,XREAD 消息流(Kafka 替代)

Redis 的持久化机制有哪些?区别?

方式 特点 场景
RDB 定期快照保存 启动恢复快,数据不完整
AOF 每次写操作记录 更安全但日志大,恢复慢
混合持久化(默认) RDB + AOF 各取所长

RDB 和 AOF 可以一起用吗?

  • 可以,一般同时启用
  • 恢复时优先加载 AOF 更完整

内存管理与淘汰策略

Redis 内存满了怎么办?

  • 设置 maxmemory
  • 启用淘汰策略(如 LRU)

Redis 有哪些淘汰策略?

noeviction(默认)/ allkeys-lru / volatile-lru
allkeys-random / volatile-random / volatile-ttl
  • volatile-*:仅作用于设置了 TTL 的键
  • allkeys-*:作用于所有键
  • noeviction:直接报错,不淘汰

Redis 集群

Redis 组网结构(部署架构)

1. 单机模式

  • 最简单,适用于开发环境或数据量小的业务。
  • 缺点:无高可用、无扩展性

2. 主从复制(Master-Slave)

  • 一个主节点写,多个从节点读。
  • 从节点通过 replicaof(或旧版本的 slaveof)命令同步数据。
  • 读写分离,提高读性能
  • 缺点:主节点挂掉后,需要手动切换主从

3. Sentinel 哨兵模式

  • 基于主从结构,增加了哨兵(Sentinel)来监控主节点。
  • 主节点宕机时,哨兵会自动选举新的主节点,实现自动故障转移(高可用)
  • 不支持自动分片(水平扩展)。

4. Redis Cluster 集群模式

  • 分布式部署,数据按 slot(0~16383)哈希槽自动分布到多个主节点。
  • 每个主节点可以有多个从节点。
  • 支持数据的分片、自动 failover、高可用
  • 客户端需要支持 Redis Cluster 协议。

搭建方式

1. 单机部署

redis-server /path/to/redis.conf

2. 主从搭建(示例)

  • slaveof 127.0.0.1 6379(在配置文件中或命令行执行)

3. Sentinel 哨兵部署

  • 配置 sentinel.conf 文件(监听主节点 IP/端口、投票数量等)
sentinel monitor mymaster 127.0.0.1 6379 2
  • 启动:
redis-sentinel sentinel.conf

4. Redis Cluster 搭建

  • 启动多个实例,配置不同端口
  • 指定 cluster-enabled yescluster-config-filecluster-node-timeout
  • 使用 redis-cli --cluster create 命令构建集群

Redis 如何实现高可用?

  • 主从复制(主写从读)
  • 哨兵模式(Sentinel,自动故障转移)
  • Redis Cluster(分布式分片)

Redis 主从复制原理?

  • 从节点通过 replicaof 向主节点发起同步
  • 首次全量同步 + 后续增量复制
  • 异步复制,主节点挂了数据可能丢失

哨兵(Sentinel)做了什么?

  • 监控主节点状态
  • 故障时自动选主
  • 通知客户端更新主节点地址

Redis Cluster 是什么?怎么分片?

  • Redis 的分布式集群方案
  • 将 key 映射到 16384 个 slot 上
  • 节点根据 slot 范围分配数据
  • 支持自动故障转移和水平扩展

数据湖

这个项目更适合用队列去 data lake 替代 MongoDB,并发量也大

解析

面对高并发的数据写入或读取场景,可能每秒有成百上千的请求或者数据流入。
更适合用队列去 data lake:

  • 先通过队列(如 Kafka、RabbitMQ、SQS 等)收集数据
  • 再异步地写入到一个 data lake(如 Amazon S3、HDFS、Delta Lake 等)而不是直接将这些高并发数据写入 MongoDB

优势

MongoDB 是一个 NoSQL 数据库,适合某些实时场景,但它不擅长:

  • 超高并发写入(尤其是规模化的数据采集/日志系统);
  • 长期存储大体量数据(存储成本高);
  • 分析型查询(如大数据批处理、数据科学);

而 Data Lake 的优点在于:

MongoDB Data Lake
面向文档,适合结构化/半结构化数据 适合非结构化或大规模数据
适合中等体量、实时系统 适合批量数据分析或归档
实时读写能力强,但不擅长横向扩展高写入 结合队列异步写入,可应对更大并发和吞吐
成本相对高 存储成本低、可扩展性强

架构

客户端 / 业务系统
        |
    写入消息
        ↓
    队列系统(如 Kafka)
        ↓
 异步消费者(如 Flink / Spark Streaming)
        ↓
   写入 Data Lake(如 S3 / Delta Lake)

相比之下,你当前可能是:

客户端 → 直接写 MongoDB(瓶颈 + 风险)

采用“流式队列 + 异步写入 Data Lake”确实是更主流、健壮的架构。


K8S

ecs = openshift ≈ k8s
我们使用的 ECS 是在 k8s 的基础上做了一些升级,比如权限、安全方面,还有一些特殊的 api,可以视为 k8s pro

Kubernetes 是一个用于容器编排的平台,主要解决的是在多台机器上如何自动部署、扩展和管理容器应用。我理解它最大的价值在于“自动化”和“稳定性”——比如我可以只声明我需要 3 个副本,它就能自动帮我创建和维护,如果某个容器挂了还能自动重启。我用过 Deployment 管理服务副本,也写过 Service 和 Ingress 做服务暴露和路径路由,基本操作都是通过 YAML 配置 + kubectl 来完成的。

角色 类比 功能
Pod 打包好的应用+环境 最小的部署单位,通常包着一个或多个容器
Node 一台机器 Pod 是跑在 Node 上的
Deployment 保姆合同(告诉你要几个副本) 管理 Pod 的副本数量、更新策略
Service 门卫(分发请求) 提供稳定的访问入口,做负载均衡
ConfigMap / Secret 配置文件/小纸条 存配置/密码,不写死在代码里
Ingress 高级门卫(带路由规则) 管理外部请求进来的路径、域名
Scheduler 调度器(安排谁跑哪儿) 选择哪台 Node 来跑你的 Pod
Controller 看管人员 负责让实际状态和你期望的一样

是什么?

  1. 一句话概括:
    Kubernetes 是一个容器编排平台,用来自动化部署、扩展和管理容器化应用。

  2. 它解决了什么问题:
    在生产环境中,手动去部署和管理大量容器非常复杂,k8s 帮我们做了这些事情,比如自动扩容、重启、滚动更新、高可用、服务发现等。

  3. 核心概念(挑几个你熟的讲):
    比如 Pod 是最小部署单位,Deployment 管理副本和更新,Service 提供服务访问,Ingress 控制路由,ConfigMap/Secret 管配置。

  4. 如果有经验,可以顺带提一嘴:
    我用过 k8s 部署过 XX 项目,遇到过一些滚动更新失败、Pod 崩溃自动重建的问题,熟悉基本的 YAML 配置和 kubectl 操作。

基本组件

Kubernetes 的组件主要分为三类:

  • 控制平面组件,比如 kube-apiserver、etcd、scheduler、controller-manager,负责整体调度和管理;
  • 节点组件,比如 kubelet、kube-proxy 和容器运行时,负责在具体节点上运行容器;
  • 资源对象部分,比如 Deployment、Service、Ingress、ConfigMap 等,是我们通过 YAML 定义的工作负载和配置。

Control Plane:

组件名 作用
kube-apiserver 所有操作的“总大门”,API 请求入口
etcd 配置数据库,所有集群状态都存在这里
kube-scheduler “调度员”,决定 Pod 应该跑在哪个节点上
kube-controller-manager 运行各种控制器,确保实际状态符合预期
cloud-controller-manager 跟云厂商打交道(如 AWS、GCP 资源)

Node Components:

组件名 作用
kubelet 节点的“管家”,接收调度命令、负责 Pod 运行
kube-proxy 管理网络规则,让 Pod 之间/对外通信通畅
container runtime 比如 Docker / containerd,负责运行容器

资源对象(工作负载类):

对象 作用
Pod 最小的运行单元,一个或多个容器打包
ReplicaSet 保证 Pod 的数量一致
Deployment 管理 ReplicaSet,支持滚动更新/回滚
StatefulSet 跑有状态服务的,比如数据库
DaemonSet 每个节点都跑一个副本,比如日志收集器
Job 一次性任务,完成即结束
CronJob 定时任务

资源对象(网络与服务类):

对象 作用
Service 提供稳定访问入口,做负载均衡
Ingress 做 HTTP 层的路由控制,比如域名、路径匹配
NetworkPolicy 控制哪些 Pod 能访问哪些服务(类似防火墙)

资源对象(配置类):

对象 作用
ConfigMap 存配置信息,比如参数
Secret 存敏感信息,比如密码、证书
Volume/PVC 给容器挂盘(持久化数据)

Helm

Helm 在 Kubernetes 生态中非常重要,尤其是做部署、管理复杂应用的时候几乎是标配。你可以把 Helm 理解成 Kubernetes 的“包管理工具”,类似于:Ubuntu 里的 apt;Node.js 里的 npm;Python 里的 pip

是什么?

Helm 就是一个“模板工具 + 应用商店”,用来打包、分发、安装 Kubernetes 应用。

它可以帮你:

  • 把很多零散的 YAML 文件组织成一个包(叫 chart)
  • 用模板语法(go template)生成不同环境下的配置
  • 一条命令就安装、升级、卸载一整个复杂应用(比如 MySQL、Prometheus、ArgoCD)

解决了什么问题?

原生 K8s 使用 YAML 文件部署,比较啰嗦+难维护

  • 一个应用可能包含十几个 YAML(Pod、Service、Ingress、Secret、ConfigMap…)
  • 如果部署到不同环境(测试、预发、生产),你要改一堆参数
  • 想要版本管理、回滚更难

Helm 帮你:

Helm 能做什么? 类比/用途
打包一套 K8s 应用配置 类似 zip 一个项目包
用模板生成 YAML 相同代码适配不同环境,比如数据库密码不同
一条命令安装、升级、卸载 helm install,upgrade,uninstall
支持回滚 helm rollback,回退到旧版本
可以引用开源 Chart 仓库 像用 npm 一样复用别人的成果

核心概念

名称 说明
Chart 一个 Helm 应用包,包含模板、变量、说明文档
Release 安装后生成的实例(可多个)
Values 配置参数(会替换模板里的变量)
Template 使用 go-template 写的 YAML 模板

可能的面试题

问题 面试官想考什么
什么是 Helm?它解决了什么问题? 你是否理解 Helm 在 K8s 生态中的作用
Helm 和 K8s 的原生 YAML 有什么区别? 是否明白模板化的优势
Helm Chart 是什么?结构有哪些? 是否能读懂/维护 Chart 包结构
什么是 Release?什么是 Values 文件? 是否能理解 Helm 安装和参数控制机制
问题 面试官想考什么
你在项目中是如何使用 Helm 的?部署了哪些服务? 是否有实际使用经验
你有没有写过自定义的 Chart?如何管理多个环境? 是否能写 Chart 而不是只用别人写的
升级 Helm Release 时出现过什么问题?怎么解决? 是否经历过真实场景的坑
Helm 是怎么处理配置参数的?能否动态传值? 是否了解values.yaml--set的使用

文章作者: Citrus
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Citrus
  目录