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.

graph LR U(User Request) -->|input| A[Agent Core] A -->|analyse| B[Planning] B -->|action plan| A A -->|invoke| C[Tools] A <-->|context| D[Memory] A -->|response| U
  • 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


graph LR A[Perception] --> B(Planning) B -->|Policy| C[Action] C -.->|Observation| A

graph LR A[Hard] -->|Text| B(Round) B --> C{Decision} C -->|One| D[Result 1] C -->|Two| E[Result 2] D -->|Feedback| F[Feedback] E -->|Feedback| F[Feedback] F -.-> A

sequenceDiagram Alice->>John: Hello John, how are you? loop HealthCheck John->>John: Fight against hypochondria end Note right of John: Rational thoughts! John-->>Alice: Great! John->>Bob: How about you? Bob-->>John: 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%