0%

背景

实现跨数据库数据的联邦查询需求,我主要负责整合需要的数据和表,另一个同时负责Redis里扩展模块。

解法设计

技术架构图

alt text

时序图

alt text

经历了一轮裁员后,焦虑了,想着提升提升自己。

英语虽然说一直在学,但是没有很严格的要求自己。刚好借着这波伤害把英语严格要求起来。

知识星球

专门开了个知识星球,就弄给英语相关的,同时也在公众号上把英语记录起来。

旨在学习英语,只包含英语学习相关的内容。

我日常学习英语的方式:

  1. 早晨7点半起床,送完孩子后开始听力20~30分钟
  2. 晚上下班写一篇英文学习的公众号20~30分钟
  3. 跟chatgpt用英文交流10~20分钟,可以选择一个小场景也可以根据白天学习的内容自由发挥

学习工具:

  1. 参考资料:
    1. https://vvyst0z7tes.feishu.cn/wiki/HQuawZepyiwNiNkImw6c00IXnmc?from=from_copylink
    2. https://1000h.org/
  2. 播客(纯英文的),youtobe music,apple 播客
  3. chatgpt
  4. LongMan Dictionary

公众号

遇见系列 第五篇

现场的应用A pod一段时间就会重启,用k8s命令看pod是因为超出limits。

查看了gc日志。因为使用的是G1回收器

让我详细解释G1 GC的工作流程:

内存分区:

整个堆内存被划分为大小相等的Region(默认2048个)
Region大小是2的幂次方,范围从1MB到32MB
每个Region可以是Eden、Survivor、Old或Humongous区
Humongous区专门用于存储大于Region大小一半的对象

GC周期的四个主要阶段:

a) 初始标记(Initial Mark)- STW:

标记所有直接从GC Roots可达的对象
这个阶段需要Stop-The-World(STW)
通常和年轻代收集同时进行
时间很短

b) 并发标记(Concurrent Mark):

遍历整个堆的对象图
标记所有可达的对象
与应用程序并发执行
使用SATB(Snapshot-At-The-Beginning)算法
记录标记期间的引用变化

c) 最终标记(Final Mark)- STW:

处理并发标记阶段遗留的SATB缓冲区
完成最终的标记工作
需要STW,但时间较短

d) 筛选回收(Live Data Counting and Evacuation)- STW:

计算各个Region的垃圾比例
根据用户期望的停顿时间建立回收集合
优先回收价值最大的Region(垃圾最多)
将存活对象复制到新的Region
清空旧Region

特殊处理:

a) 年轻代收集:

当Eden区满时触发
只关注年轻代Region
存活对象复制到Survivor区或老年代

b) 混合收集:

同时回收年轻代和部分老年代Region
根据全局并发标记的结果
老年代Region按垃圾收集价值排序

优化机制:

a) Remembered Sets(Rsets):

记录跨Region的引用关系
每个Region都有一个RSet
避免全堆扫描

b) Collection Sets(CSets):

需要被回收的Region集合
基于垃圾占比和期望停顿时间选择

正常GC流程:

Young GC:回收年轻代Region
并发标记周期:标记整个堆的存活对象
混合回收:回收年轻代和部分老年代Region

Full GC触发条件:

并发标记完成之前就出现内存分配失败
回收后的空间仍不足以支持下一次Young GC(空间担保失败)
混合回收后仍无法满足内存需求
Humongous对象分配失败

Full GC的特点:

必须Stop-The-World(STW)
对整个堆进行压缩和整理
单线程执行,停顿时间长
会明显影响应用程序性能

Full GC后的处理:

如果Full GC后内存足够,应用继续运行
如果Full GC后内存仍然不足,抛出OutOfMemoryError

避免Full GC的建议:

合理设置堆内存大小
调整并发标记的触发阈值
适当调整Region大小
控制大对象的产生
及时进行并发标记,避免内存耗尽

Full GC在G1中的具体执行步骤:

  1. 标记阶段(Marking Phase):
  • 进入STW阶段,停止所有用户线程
  • 从GC Roots开始进行全堆标记
  • 标记所有存活对象
  • 使用单线程进行标记,效率较低
  1. 清理阶段(Cleanup Phase):
  • 清理所有未被标记的对象(垃圾对象)
  • 回收空的Region
  • 重置各种元数据信息(RSet等)
  • 计算所有Region的存活对象信息
  1. 压缩阶段(Compaction Phase):
  • 对存活对象进行压缩整理
  • 将存活对象复制到新的Region
  • 按照新的分代布局重新整理对象
  • 更新对象引用关系
  • 释放旧的Region
  • 重建RSet等辅助数据结构

特点:

  • 整个过程完全STW
  • 单线程执行,性能较差
  • 会对整个堆内存进行处理
  • 会导致较长时间的停顿
  • 会破坏原有的分代结构,需要重新构建

触发Full GC通常意味着:

  • 内存分配压力过大
  • 并发收集来不及回收内存
  • 可能需要调整GC参数或应用程序代码

如何管理自我

成大事无捷径

笨功夫才是真功夫,没有快乐学习这一说法

如何平衡工作和生活

有所逼
有所专

  • 临事静对猛虎,事了闲看落花。
    有所规
  • 要立规矩,既要规范自己也要规范别人。
  • 你要让周围的人知道并遵守,久而久之,会享受到它带给你的福利。
  • 有所规划,多做计划。

有所贪

  • 早做夜思,以求有济。
  • 用平常心处世,用进取心做事。

真正的猛人

怎么区分是不是真正的猛人

  • 看他的凶猛是对自己还是对他人

    • 真正的猛人,对他人的要求自己肯定能做到甚至做得更好。
  • 从事情来判断。真正的猛人,他的凶猛和决绝是对事的。

    • 真正的猛人把事放在人之前,而不是看对自己爽不爽。
  • 真的猛人追求不一样

    • 经常说起的自律、怎么如履薄冰等而不是吹牛,自己怎么怎么厉害

猛人修炼方法:敬、恒

三不朽:立言、立功、立德

  • 敬:是敬天悯人,尊重常识和积累,尊重事,不走捷径。
  • 恒:在对事上坚持投入时间和精力,长期主义。

做自己熟悉的行业

  1. 做擅长的事容易成
  2. 在主业做到顶尖
    1. 先知道100个关键词
    2. 找到三五个专家,跟他们谈上半天到一天。
    3. 找到三五本专著,仔细的看完。
    4. 价值最大化

掌控情绪

如何对待妒忌和贪婪

  1. 不害人
  2. 要宽容

如何战胜自己,战胜逆境

  1. 看脚下
    1. 现金流
    2. 核心“上下游”
  2. 不断行
    1. 把自己稳定之后,不要停止努力,无论是在生活上还是在工作上。
    2. 多做推功揽过。
    3. 做一分算一分,在一日撑一日。
  3. 莫存顺逆
    1. 不要两分的看所谓的逆境。无论顺逆都是生活的一部分,都是正常的日子。

如何战胜自己,战胜逆境

  1. 真正的高手都有破局思维
    1. 在逆境中要考虑事在人为。

有时候“不努力”是种正确的战略

  1. 战略方面,重要的是要认命

  2. 从战术的角度,有时候需要你收敛

    1. 如果你有太强的目的性,很有可能遭到别人的反感。
    2. 你有可能跑的太快,遭到别人的妒忌。
    3. 长期过分努力做事,会遭到非常严重的抵抗。
  3. 不着急缓称王,是一种正确的态度。

可以不屠龙,但不能不磨剑。
能打仗、能力站、能快跑的时候,请力战快跑成事。
获得某个细分领域最多的知识和最高的智慧。

选择不仅仅是断舍离

养成好习惯

摒弃”身心灵“,在现实中修行

  1. 如何在现实中修行,珍惜每一个不舒服和难受。
  2. 真正的修行是忍耐、自强。

以笨拙为本分,求仁得仁

怎么通过拯救睡眠实现人生逆袭

分清欲望和志向

  1. 如何管理欲望

    1. 尊重欲望,尊重自己的好胜心
    2. 中庸
  2. 构建自己的乐园

如何应对年龄危机

  1. 锻炼好身体
  2. 在一个好身体的基础上,持续修炼。
  3. 衰年变法
  4. 做减法,减少无效社交。
  5. 减少日常花销
  6. 认怂,退居二线
  7. 回归生活

人人都该懂战略

什么事战略:战略是一套完整的行动方案。这套完整的行动方案包括:何处竞争、如何竞争、何时竞争

  1. 小公司通常不用做
  2. 为什么要做战略:上下同欲,少走弯路。
  3. 大处着眼,小处着手。

领导力

  1. 是否能成事,能够持续多成事。

  2. 抓大放小,容人,定方向,这是种小公司的领导力构成。

  3. 终极领导力,最终还是看个人的能力,危机时,只有自己靠得住,靠不了其他人。

    1. 团队在强只是辅助
  4. 不着急、不害怕、不要脸

    1. 不着急:对时间
    2. 不害怕:对结果
    3. 不要脸:对评价

职场沟通规范

多条理,少大言

  1. 倾听

    1. 在表达自己之前,先问三个问题:
      1. 你对于这个问题是怎么想的?
      2. 为什么这么想?
      3. 有没有其它解决办法?
  2. 在倾听的基础上,理解别人的诉求

    1. 了解清楚背景,站在对方的角度
  3. 开放

    1. 不要预设答案,不要预设解决方案。
  4. 平等

  5. 多条理

    1. 金字塔原则
  6. 少大言

    1. 越具体越好。
      1. 情况是怎么样的?原因是什么?结论是什么?希望解决的具体的措施是什么?
  7. 创造一个良好的职场沟通环境

  8. 就事论事

    1. 避免情绪化
  9. 可长可短

    1. 沟通时间
  10. 职场沟通多讲事实,少讲个人喜好。

  11. 交流时不要庞杂。

    1. 交流就交流,别看手机之类的
    2. 也不要在比较累的时候
    3. 找对方最好交流的状态
  12. 在职场交流中减少使用口头禅

  13. 在职场中交流少情绪化。

    1. 记住如果这股火撒出去,一定是对这件事情有害的。把火压下去,用更低更缓慢的声调来讲。

带团队的四条铁律

    1. 平时做不到的,战时一定也做不到。
    1. 从团队成员出发,知道他们在想什么,放手让团队去做。
  1. 势力

    1. 大局、实战
  2. 理想

算法与数据结构 第一篇
最近在看《数据结构与算法分析-第三版》,记录下解惑时刻。
  1. 指数
  2. 对数
  3. 取模
  4. 阶乘
  5. 归纳法
    1. 基准值
    2. 归纳假设
  6. 反证法
    1. 假设定理不成立,然后证明该假设导致已知的性质不成立。
  7. 递归

场景

处理了一个现场问题,现场部署了多个agent但是就一个agent离线。

agent是部署在单独的服务器A上,且使用docker部署,该agent需要与另外一台服务器B通信,当前的状态即是无法通信。

agent->docker->服务器A->….->服务器B

思路

先搞清楚请求要从agent到服务器B是个什么过程,找出其中的关键环节,逐个排查。

容器B中的某个服务程序(比如web服务器)需要向服务器C发送数据。它会调用socket接口,传入目标地址等信息来生成数据包。
数据包被传递给容器B的网络堆栈。该堆栈会为数据包添加上以太网头(包含源MAC、目标MAC等),然后发送到容器的虚拟接口veth pair。
veth pair会将数据包传递给Docker主机的网络命名空间。这里包含一个Bridge接口docker0。
docker0收到数据包后,查找路由表,确定应该通过主机的物理接口eth0发送。
数据包被传递至主机的网络协议栈,这里会为数据包添加物理层头信息(比如Ethernet II头)。
添加完头信息的数据包通过主机的物理接口eth0发送出去。
数据包到达主机所在物理网络的交换机,交换机根据MAC地址转发到路由器。
路由器剥离二层头信息,查找三层信息,确定应向ISP上的默认网关发送。
在各个ISP路由器之间,重复着提取IP头,查询路由表,转发的过程。
最终数据包到达服务器C,服务器C的网络栈处理数据包,将其传递给目标服务。

在Docker容器的网络中,还存在一个默认网关,它是容器访问外部网络的桥梁。

当容器B的网络栈处理数据包时,会查看目标IP是否在容器内网段:

如果目标IP在容器内网段,则直接通过veth pair发送给docker0。
如果目标IP不在容器内网段,则需要先发送给容器的默认网关。
容器的默认网关其实是一个在主机网络命名空间内的虚拟接口,IP地址属于docker0子网,比如172.17.0.1。

所以数据包的流程可以补充为:

容器B网络栈 -> 容器默认网关(172.17.0.1) -> docker0 -> eth0

默认网关负责帮助容器正确地将数据包发送到外部网络,从而实现网络访问。

可能的问题点

  1. 容器内默认路由未正确设置
    容器需要有默认网关来路由外部网络的访问。如果默认路由未设置或设置错误,可能导致容器内无法访问外部网络。

  2. docker0桥接问题
    docker0是连接容器和主机网络的桥梁。如果docker0配置错误,无法正确转发容器的数据包,会造成网络访问故障。

  3. 容器访问外部网络规则问题
    可能由于iptables等防火墙规则错误配置,导致容器无法访问外部特定网络或端口。

  4. 容器网络命名空间隔离问题

排查

查了下agent所在的服务器与主业务是能telnet通的,但是进入agent容器内部则不行,不管是ping还是curl都不行。

首先怀疑容器的网络配置可能存在问题。检查容器的网络设置,先后检查了iptables、DNS、检查默认路由都没有异常。又因为容器外能访问,且该agent与其它2、3个agent属于同一个子网下,所以也侧面证明了,服务器的网络配置确实没问题。

那接下来基本确定是docker网络配置的问题了。

基于nsenter,验证网络问题,发现确实存在网络问题,ping docker默认网关不通。

现场反馈更新过agent的网络地址,随即检查daemon.json 、docker-compose.yml文件

发现docker-compose.yml内定义的subnet为16为子网掩码,而daemon.json为24位子网掩码,

因为16比24的IP范围大,这种情况下,容器获得的IP地址可能不在docker-compose网络的子网范围内,从而无法连接到该网络,造成网络通信失败。

解决方案:

将docker-compose.yml和docker daemon中的子网掩码设置为相同。例如都使用24位子网掩码。

最近处理一个现场故障,现象是系统用一段时间就会变得很慢,clickhouse会重启,etcd发生长时间起不来,业务日志有代码报错。

总结下来大体发现如下几个问题:

  • clickhouse变慢、重启
  • 业务代码报空指针
  • etcd长时间起不来

业务代码问题先给到业务方进行排查,我们先看clickhouse和etcd问题

clickhouse变慢、重启

因为对于基础组件都没开系统日志,所以只能从观察系统的指标开始,通过netdata,发现clickhouse会不断的打到峰值

所以先从clickhouse查起,因为没有开日志,所以就从clickhoue提供的系统表开始查起

我们找了下官方资料,先锁定了如下几张表

  • system.query_log
  • system.query_thread_log
  • system.metrics
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
-- 查看可疑的sql
SELECT
address,
event_time,
client_hostname,
read_rows,
result_rows,
query_duration_ms
FROM system.query_log
WHERE event_date = '2023-09-09'
-- 查看执行sql最多的来源
SELECT
address,
COUNT(*) AS query_count
FROM system.query_thread
WHERE event_date = '2023-09-09' AND peak_memory_usage > 0
GROUP BY address;
-- 查看消耗内存最大的来源
SELECT
address,
SUM(peak_memory_usage) AS total_peak_memory
FROM system.query_thread
WHERE event_date = '2023-09-09' AND peak_memory_usage > 0
GROUP BY address;


最近处理一个现场,80端口正常开放,但是从外部curl无法访问,pod内部是没问题的

初步判断时k8s内部的转发出了问题

https://www.tkng.io/services/clusterip/dataplane/iptables/
https://kubernetes.io/blog/2022/09/07/iptables-chains-not-api/
https://dustinspecker.com/posts/iptables-how-kubernetes-services-direct-traffic-to-pods/
https://medium.com/swlh/manage-iptables-firewall-for-docker-kubernetes-daa5870aca4d
https://livebook.manning.com/concept/kubernetes/iptable
https://serenafeng.github.io/2020/03/26/kube-proxy-in-iptables-mode/
https://jimmysong.io/en/blog/understanding-iptables/
https://blog.csdn.net/cloudvtech/article/details/79728920