Java 的 bean 是什么?
用大白话来说,Java 的 Bean(JavaBean) 就是一个“装属性的小容器”。
你可以把它想象成现实生活中装东西的盒子,比如:
- 一个“人”的 Bean 里装着:名字、年龄、性别;
- 一个“订单”的 Bean 里装着:订单号、下单时间、金额。
特点
属性是私有的(private)
👉 就像盒子外面看不到里面装了啥,不能直接伸手去拿,要通过“开关”来操作。通过 get/set 方法来访问属性
👉 给你配了专门的按钮(getter/setter)来打开盒子取东西或往里面放东西。
比如:public class Person { private String name; // 装了名字 public String getName() { // 按这个按钮可以读名字 return name; } public void setName(String name) { // 按这个按钮可以改名字 this.name = name; } }有无参构造方法
👉 你可以空手创建一个盒子,不需要一开始就把东西放进去。
存在的意义
主要是用来 传递数据。比如:
- 数据库查出来的一行数据,你用一个 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 更快?
- 文档型结构:
MongoDB 存储的是 BSON(二进制 JSON),读取/写入整个文档更快,不像 Oracle 要处理多个表、多个行的关系。 - 无 schema 限制:
插入数据时不校验字段类型、约束等,开销小。 - 天然内存缓存机制:
MongoDB 有自己的内存映射机制,把热数据放内存里,读得更快。 - 水平扩展强:
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 的优势主要体现在以下几方面:
- 读写性能高:Redis 是基于内存的数据库,单线程处理速度极快,适合高并发读写场景;
- 快速响应和低延迟:内存操作通常在微秒级,而 MongoDB 属于磁盘数据库,响应速度会慢几个数量级;
- 适合缓存热点数据:在大数据场景下,可以把高频访问数据放入 Redis 缓存,减轻 MongoDB 的压力;
- 支持多种高效的数据结构:如 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 yes,cluster-config-file,cluster-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 | 看管人员 | 负责让实际状态和你期望的一样 |
是什么?
一句话概括:
Kubernetes 是一个容器编排平台,用来自动化部署、扩展和管理容器化应用。它解决了什么问题:
在生产环境中,手动去部署和管理大量容器非常复杂,k8s 帮我们做了这些事情,比如自动扩容、重启、滚动更新、高可用、服务发现等。核心概念(挑几个你熟的讲):
比如 Pod 是最小部署单位,Deployment 管理副本和更新,Service 提供服务访问,Ingress 控制路由,ConfigMap/Secret 管配置。如果有经验,可以顺带提一嘴:
我用过 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的使用 |