Hong's Notes

High Performance, High Availability and Scalable Architecture, ML, AI and Big Data

What are LLM-based AI Agents?

An LLM-based AI agent is an intelligent system that uses large language models (like GPT-4) to perform tasks autonomously, including perceiving the environment, reasoning about it, making decisions, and executing actions. Unlike traditional chatbots, these agents can plan tasks, take actions using external tools, and handle multi-step problems. It aims to enable people to perform and handle professional or complex tasks in a highly automated manner using natural language, driven by LLM technology, thereby freeing up personnel energy to the greatest extent.

Core Components of an AI Agent

LLM-based agents usually rely on a modular architecture that gives the LLM the support it needs to operate autonomously. The typical agent is composed of a few key components.

input

analyse

action plan

invoke

context

response

User Request

Agent Core

Planning

Tools

Memory

  • Agent Core: At the heart of the agent is the LLM itself (for example, GPT-4, Claude, or an open-source model like LLaMA 2). This core interprets the user’s input and generates the agent’s responses. On its own, the LLM is very powerful at understanding language and reasoning, but it’s essentially reactive (it responds to prompts without taking additional actions). In an agent setup, the LLM core is augmented with surrounding logic so it can be more proactive, meaning it needs other components to interface with the outside world and handle complex tasks.
Read more »

Mermaid Examples

Below are the examples of different types of Mermaid graph.

All Available Types

Mermaid Syntax

Mermaid Examples


Policy

Observation

Perception

Planning

Action


Text

One

Two

Feedback

Feedback

Hard

Round

Decision

Result 1

Result 2

Feedback


BobJohnAliceBobJohnAliceloop[HealthCheck]Rational thoughts!Hello John, how are you?Fight against hypochondriaGreat!How about you?Jolly good!
Read more »

kafka-0.10.0 是官方出的最新稳定版本,提供了大量新的 feature,具体可见这里,本文主要分析 kafka-0.10-0 的源码结构和启动过程。

源码结构

kafka-0.10.0 的源码可以从 github 上 fork 一份,在源码目录下执行./gradlew idea 生成 idea 项目,然后导入 idea 即可。这中间需要使用 gradle 进行依赖包的下载,导入后可以看到其源码结构如下图所示:

包括几大重要模块:

  • clients 主要是 kafka-client 相关的代码,包括 consumer、producer,还包括一些公共逻辑,如授权认证、序列化等。
  • connect 主要是 kafka-connect 模块的代码逻辑,Kafka connect 是 0.9 版本增加的特性,支持创建和管理数据流管道。通过它可以将大数据从其它系统导入到 Kafka 中,也可以从 Kafka 中导出到其它系统,比如数据库、elastic search 等。
  • core 模块是 kafka 的核心部分,主要包括 broker 的实现逻辑、producer 和 consumer 的 javaapi 等。
  • streams 模块主要是 kafka-streaming 的实现,提供了一整套描述常见流操作的高级语言 API(比如 joining, filtering 以及 aggregation 等),我们可以基于此开发流处理应用程序。
Read more »

问题出现

测试 storm 集群为 0.9.4 版本,前段时间出现 supervisor 进程挂掉,而其上 work 进程仍然运行的诡异情况,通过日志看到 supervisor 进程挂掉之前出现以下异常:

问题排查过程

很明显,是 commons-io 包的 FileUtils 工具类抛出的异常,原因是在调用 commons-io 包的 FileUtils 工具类做 move directory 操作时,目的文件夹已存在。

查看调用代码(supervisor.clj 的第 374 行),是调用 download-storm-code 方法从 nimbus 下载 topology 的代码,并且 download-storm-code 方法中做代码下载前加了锁避免并发写文件。

果然,这里没有判断 stormroot 文件夹是否已存在,是个 bug,具体可见这个 issue:https://issues.apache.org/jira/browse/STORM-805

这个问题在 0.9.5 版本中随着 STORM-130 一起修复了,代码如下:

但这里有三个问题:

  1. 在调用 download-storm-code 方法前,代码中已做判断是否已下载 topology 代码,若已下载就不会调用 download-storm-code 方法了。为何进入这个方法后,做 move directory 操作时,代码却已经下载好了呢?

  2. storm 的历史发布版本有很多,为何 0.9.4 版本里会出现这个不该出现的问题,0.9.4 相对老的版本是不是做了什么修改?

  3. 为何抛出异常后,supervisor 进程就这么直接退出了?太弱了吧。。

Read more »

问题现象

线上两台 java 后台服务每次上线后再过段时间,就出现 swap 空间使用率较高的现象,而 jvm 内存使用和垃圾回收情况则很正常。相关图表如下:

图中,每次上线后过一段时间,swap 空间使用量会出现一个陡增,并随时间推移逐渐增加,期间会出现小幅度下降。

首先,从操作系统层面分析,swap 空间使用较高,说明是系统物理内存不够用从而发生内存页交换,将部分内存数据搬至虚拟内存空间,也就是 swap 空间。但究竟是什么原因引起物理内存不足呢?因为 Jvm 堆大小是固定的,所以推断是因堆外内存占用空间较大引起。

于是,使用 jmap -histo:live 把进程中的对象信息 dump 出来,dump 信息如下:

确实发现存在大量 DirectByteBuffer 对象,这说明内存中确实有大量引用了堆外内存的对象没有被回收!

同时,内存中也对应存在着大量的 sun.misc.Cleaner 和 java.nio.DirectByteBuffer$Deallocator 对象。这两个类是用于回收堆外内存的。Cleaner 对象是在 DirectByteBuffer 的构造函数中创建,其中封装了回收堆外内存的逻辑,Cleaner 执行 clean 资源的操作是通过启动 Deallocator 线程实现的,这个线程把 DirectByteBuffer 对象引用的堆外内存做回收。

那么问题来了:

  1. 为什么 DirectByteBuffer 对象没有被回收?

  2. 怎么做才能让 DirectByteBuffer 对象能被及时回收?

问题分析

Read more »

简介

提交进入 Storm 运行的 topology 实际上是一个有向无环图(DAG),其中的节点是由 spout 和 bolt 组成,边则可以理解为消息从一个节点到传输到另一个节点的过程。对于 spout 产生的 tuple,只有在 topology 上处理完毕后,才认为这个 tuple 被 storm 可靠处理。

Storm 提供了可靠处理消息(storm 中的通用名叫 tuple)的框架,我们在写一个 topology 程序时,若需要保证 spout 产生的消息的可靠处理,需要做到两点:

第一是 spout/bolt 每生成一个新的 tuple 都告诉 storm 一下(其中 spout 发出的 tuple 有个 id 叫 rootId),从而让 storm 能够追踪 rootId 和每个衍生 tuple 的处理状态。

第二是每个 tuple 被下游 bolt 处理完毕后,无论处理成功或失败,也再告诉 storm 一下,从而让 storm 知道是否需要 spout 重新发送 rootId。

做了这两件事,storm 就能知道这个 tuple 是否被处理完毕。如果是处理成功了的,就说明最初从 spout 发出的 tuple(rootId)已在 topology 中处理完毕,无需 spout 重新发送。如果是处理失败的,storm 则会告知 spout 重新发送 rootId 这个 tuple。

在程序中实现消息可靠处理

那在写一个 topology 时,我们该如何做上面提到的两件事呢?

Read more »

环境准备

系统:mac osx
软件:Node.js,npm,git,hexo
具体安装以及 git 与 github 打通的配置就不详述了,可以 google 到各种方法。

hexo 命令

hexo init <folder>              #表示执行 init 命令初始化 hexo 到你指定的目录
以下命令需要在 <folder> 目录下执行:
hexo generate    # 自动根据当前目录下文件,生成静态网页
hexo server        # 运行本地服务

启动服务后,就可以通过访问 http://localhost:4000 来看看效果了。
接下来,可以使用以下命令来创建一篇新博文:
hexo new “test blog 1”
创建一个名为 test blog 1 的博客页面,对应的 md 文件路径是 <folder>/source/_posts\test blog 1.md

接下来就可以在这个 md 文件中写文章了,我使用的是 MacDown 来编辑 md 文件,支持实时查看页面效果,还是挺好用的。

发布博客

文章写好后,通过以下方式发布到 github 上。
1. 编辑./_config.yml 文件,修改以下部分,配置本地内容同步至 github:

deploy:
  type: git
  repository: git@github.com:maohong/maohong.github.io.git
  branch: master

2. 执行 hexo generate (hexo g) 生成 html 内容
3. 执行 hexo deploy (hexo d) 讲更新内容发布至 guthub

然后就可以访问主页查看效果了,可以使用 github 帐户名.github.io 进行访问,也可以设置个性域名。

问题描述

在测试 spark on yarn 时,发现一些内存分配上的问题,具体如下。

在 $SPARK_HOME/conf/spark-env.sh 中配置如下参数:

SPARK_EXECUTOR_INSTANCES=4 在 yarn 集群中启动的 executor 进程数

SPARK_EXECUTOR_MEMORY=2G 为每个 executor 进程分配的内存大小

SPARK_DRIVER_MEMORY=1G 为 spark-driver 进程分配的内存大小

执行 $SPARK_HOME/bin/spark-sql –master yarn,按 yarn-client 模式启动 spark-sql 交互命令行(即 driver 程序运行在本地,而非 yarn 的 container 中),日志显示的关于 AppMaster 和 Executor 的内存信息如下:

日志显示,AppMaster 的内存是 896MB,其中包含了 384MB 的 memoryOverhead;启动了 5 个 executor,第一个的可用内存是 530.3MB,其余每个 Executor 的可用内存是 1060.3MB。

到 yarnUI 看下资源使用情况,共启动了 5 个 container,占用内存 13G,其中一台 NodeManager 启动了 2 个 container,占用内存 4G(1 个 AppMaster 占 1G、另一个占 3G),另外 3 台各启了 1 个 container,每个占用 3G 内存。

再到 sparkUI 看下 executors 的情况,这里有 5 个 executor,其中 driver 是运行在执行 spark-sql 命令的本地服务器上,另外 4 个是运行在 yarn 集群中。Driver 的可用 storage memory 为 530.3MB,另外 4 个都是 1060.3MB(与日志信息一致)。

那么问题来了:

  1. Yarn 为 container 分配的最小内存由 yarn.scheduler.minimum-allocation-mb 参数决定,默认是 1G,从 yarnUI 中看确实如此,可为何 spark 的日志里显示 AppMaster 的实际内存是 896-384=512MB 呢?384MB 是怎么算出来的?

  2. spark 配置文件里指定了每个 executor 的内存为 2G,为何日志和 sparkUI 上显示的是 1060.3MB?

  3. driver 的内存配置为 1G,为何 sparkUI 里显示的是 530.3MB 呢?

  4. 为何 yarn 中每个 container 分配的内存是 3G,而不是 executor 需要的 2G 呢?

问题解析

进过一番调研,发现这里有些概念容易混淆,整理如下,序号对应上面的问题:

Read more »

基础环境

  • IDE 开发环境:intelliJIdea
  • JDK1.7 64bit
  • intelliJIdea 安装 maven 插件,配置好仓库源
  • intelliJIdea 安装 clojure 插件 Cursive(需要注册并获取一个 license,否则只能使用 30 天)
  • 如果需要自己创建 clojure 项目进行开发,需要安装 leiningen,下载地址

源码获取

从 github checkout 代码到本地即可,https://github.com/apache/storm.git

我这里编译的是我们目前正在用的 0.10.0 版本的代码。

导入 idea 及编译

打开 idea,新建 project,从源码导入,如下:

导入后,idea 会自动根据 pom.xml 下载相关依赖包,部分依赖包如果下载不到,需要手动添加。完成后,可以看到 project 的 module 如下图所示:

Read more »
0%