Arbitrum Nitro交易速度压力测试实战:TPS性能评估全解析

news2024/9/20 6:20:37

Arbitrum Nitro 是一种基于以太坊的 Layer 2 扩展解决方案,旨在提高交易吞吐量并降低交易费用。为了全面评估其性能,我们需要进行了详细的压力测试。本文的目的是回顾一下我在实际测试过程中采用的方法,还有测试的思路。

我们的压力测试主要目标是评估 Arbitrum Nitro 在高负载下的性能,包括每秒交易数(TPS)、交易确认时间等关键指标。

测试原理和机制

测试的原理是通过模拟大量交易请求来测试系统的处理能力。测试过程包括以下几个关键步骤:

  1. 生成测试账户:创建多个钱包地址用于交易测试。

  2. 转账测试:频繁进行转账操作,模拟真实交易场景。

  3. 数据记录与分析:记录每笔交易的开始时间、确认时间和结束时间,并对数据进行分析。

在测试过程中,会记录请求信息,然后下载生成的区块,然后分析交易生成的数据,评估交易的平均处理时间、每秒钟平均处理交易笔数等指标。

代码和执行过程

文中代码只是为了说明测试思路,类似伪代码,实际执行的代码可以自己根据思路实现,也可以联系作者。

1. 生成测试账户和发起交易请求

使用 web3.js 库生成测试账户,并将它们保存到本地 JSON 文件中,同时记录交易数据到 JSONL 文件:

const { Web3 } = require('web3');
const fs = require('fs');
const web3 = new Web3('http://localhost:8545');

// 生成测试账户
const generateAccounts = async (numAccounts) => {
    const accounts = {};
    for (let i = 0; i < numAccounts; i++) {
        const account = web3.eth.accounts.create();
        accounts[account.address] = account.privateKey;
    }
    fs.writeFileSync('wallets.json', JSON.stringify(accounts, null, 2));
};

// 发送交易并记录数据
const sendTransaction = async (from, to, value, privateKey) => {
    const tx = {
        to,
        value,
        gas: 21000,
        nonce: await web3.eth.getTransactionCount(from),
    };
    const signedTx = await web3.eth.accounts.signTransaction(tx, privateKey);
    const startTime = Date.now();
    web3.eth.sendSignedTransaction(signedTx.rawTransaction)
        .on('receipt', (receipt) => {
            const responseTime = Date.now();
            const logEntry = {
                start_time: startTime,
                response_time: responseTime,
                tx_hash: receipt.transactionHash,
            };
            fs.appendFileSync('transactions.jsonl', JSON.stringify(logEntry) + '\n');
        });
};

// 主函数
const main = async () => {
    const accounts = JSON.parse(fs.readFileSync('accounts.json'));
    const mainAccount = '0xYourMainAccount';
    const mainPrivateKey = '0xYourMainPrivateKey';

    for (const [address, privateKey] of Object.entries(accounts)) {
        await sendTransaction(mainAccount, address, web3.utils.toWei('1', 'ether'), mainPrivateKey);
        await sendTransaction(address, mainAccount, web3.utils.toWei('0.001', 'ether'), privateKey);
    }
};

// 生成测试账户并执行主函数
generateAccounts(100).then(() => main());

通过设置要生成的测试账户数量,就可以简单的控制同时发起请求的数量。在发起交易的时候,我们可能会希望能够更精确控制每秒钟发起交易的数量,还有测试的持续时间,可以继续改造,增加并发控制。

另外,为了更好地控制测试速度,我们将转账分成两步,第一步先批量向生成的钱包中转入1-2个ETH,然后压力测试过程中,从生成的钱包地址,用小金额将ETH转回主账号。

改造之后代码如下:

const options = {  duration: 30, // 单位秒  number: 100,  tps: 200,  wait: true,}
async function runStrssTest(accounts, options) {  const startAt = Date.now()  const ctrlDict = {}  while(true) {    if (Date.now() - startAt > options.duration * 1000) {      break    }    
    const sec = Math.floor(Date.now() / 1000)    if (!ctrlDict[sec]) {        ctrlDict[sec] = 0    }    for (const [address, privateKey] of Object.entries(accounts)) {        if (ctrlDict[sec] >= options.tps) {            continue        }        ctrlDict[sec]++        sendTransaction(address, mainAccount, web3.utils.toWei('0.001', 'ether'), privateKey);    }   }}
async function main() {    ...    batchSendBalanceFromMain(mainPrivateKey, accounts)    ...    await runStrssTest(mainAccount, accounts, options)    ...}

并发批量下载区块数据并写入 JSONL 文件

使用 Python 并发下载区块数据,并将其保存到 JSONL 文件中:

import json
import time
import threading
from web3 import Web3
from concurrent.futures import ThreadPoolExecutor
web3 = Web3(Web3.HTTPProvider('http://localhost:8545'))
lock = threading.Lock()

def get_block(block_number):
    try:
        print('get_block', block_number)
        block = web3.eth.get_block(block_number, full_transactions=True)
        return block
    except Exception as e:
        print(f"Error fetching block {block_number}: {e}")
        return None
def format_transaction(tx):
    return {
        'hash': tx.hash.hex(),
        'nonce': tx.nonce,
        'blockHash': tx.blockHash.hex(),
        'blockNumber': tx.blockNumber,
        # ...
        'from': tx['from'],
        'to': tx.to,
        'value': tx.value,
    }
# Formate block data to JSON
def format_block(block):
    block_dict = {
        'number': block.number,
        'hash': block.hash.hex(),
        'nonce': block.nonce.hex(),
        # ...
        'timestamp': block.timestamp,
        'transactions': [format_transaction(tx) for tx in block.transactions],
    }
    return block_dict

def download_block(block_number):
    block = web3.eth.getBlock(block_number, full_transactions=True)
    block_data = {
        'number': block.number,
        'timestamp': block.timestamp,
        'transactions': [tx.hash.hex() for tx in block.transactions]
    }
    with lock:
        with open('blocks.jsonl', 'a') as f:
            f.write(json.dumps(block_data) + '\n')

# download block and write to disk
def download_and_write_blocks(start_block, end_block):
    blocks = []
    with ThreadPoolExecutor(max_workers=20) as executor:
        future_to_block = {executor.submit(get_block, block_number): block_number for block_number in range(start_block, end_block + 1)}
        for future in as_completed(future_to_block):
            block_number = future_to_block[future]
            try:
                block = future.result()
                if block:
                    blocks.append(block)
            except Exception as e:
                print(f"Error in future for block {block_number}: {e}")
    if len(blocks) == 0:
        return
    blocks.sort(key=lambda x: x.number)
    with lock:
        with open("blocks.jsonl", 'a') as f:
            for block in blocks:
                formatted_block = format_block(block)
                f.write(json.dumps(formatted_block) + '\n')

def main(start_block, end_block, batch_size):
    latest_block = web3.eth.block_number
    if start_block > latest_block:
        print("Start block is greater than the latest block on the chain. Exiting.")
        return
    end_block = min(end_block, latest_block)
    for batch_start in range(start_block, end_block + 1, batch_size):
        batch_end = min(batch_start + batch_size - 1, end_block)
        download_and_write_blocks(batch_start, batch_end)

if __name__ == "__main__":
    start_block = 0  # start download block
    end_block = 20000  # end download block
    batch_size = 100  # batch download block size
    main(start_block, end_block, batch_size, json_file)

分析数据并生成图表

使用 Python 读取 JSONL 文件中的交易和区块数据,计算性能指标并生成图表:


import json
import pandas as pd
import plotly.express as px

# 读取 JSONL 文件
def load_jsonl(filename):
    data = []
    with open(filename, 'r') as f:
        for line in f:
            data.append(json.loads(line))
    return data

# 读取交易记录和区块数据
transactions = load_jsonl('transactions.jsonl')
blocks = load_jsonl('blocks.jsonl')

# 将数据转换为 DataFrame
tx_df = pd.DataFrame(transactions)
block_df = pd.DataFrame(blocks)

# 计算每笔交易的执行时间
tx_df['execution_time'] = tx_df['response_time'] - tx_df['start_time']

# 计算每秒发起的交易数
tx_df['start_second'] = (tx_df['start_time'] // 1000) - (tx_df['start_time'].min() // 1000)
tps = tx_df.groupby('start_second').size()

# 计算区块中的交易数
block_tx_count = block_df.explode('transactions').groupby('number').size()

# 生成交易数折线图
fig = px.line(tps, title='每秒发起交易数 (TPS)')
fig.show()

# 生成区块交易数折线图
fig = px.line(block_tx_count, title='每个区块包含的交易数')
fig.show()

通过压力测试和获取收集到的数据,并且生成趋势图的形式,我们可以用图表的方式,可视化的看到在不同的负载情况下,在L2链上进行的交易的趋势变化,有助于理解处理过程中可能出现的瓶颈,从而可以清楚的知道当前部署的Arbitrum链能够处理多少交易,并且根据能力,做出业务决策。

关于测试的思考

通过文章,简单地介绍了,如何使用web3库,使用不同的语言发起交易,下载区块的基本调用流程。

总结这次测试的过程,我觉得最重要的思路是,说是性能评估,其实本质上要做的工作是数据分析,我们只要清晰的定义数据,然后从数据中进行计算,就可以得到相应的指标,计算的过程,就是从原始数据中计算出分组的关键字,然后进行累加的过程。

确定了需要的数据,还有计算指标的过程,剩下的就是从不同的数据源收集数据,为了获得足够数据,有时候可能还要在程序中增加埋点,将需要的信息输出到日志或者数据库中。

整个过程分成几个步骤,首先确定要分析的数据指标、确定之后从数据产生的源头收集数据,收集完数据以后,对数据清洗和转换,然后用转换好的数据,进行分组计算,最后,就可以根据不同的图表和输出的需要,生成结果指标数据集。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1967793.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Docker应用】快速搭建Plik服务结合内网穿透无公网IP远程访问传输文件

文章目录 前言1. Docker部署Plik2. 本地访问Plik3. Linux安装Cpolar4. 配置Plik公网地址5. 远程访问Plik6. 固定Plik公网地址7. 固定地址访问Plik 前言 本文介绍如何使用Linux docker方式快速安装Plik并且结合Cpolar内网穿透工具实现远程访问&#xff0c;实现随时随地在任意设…

页面路由怎么开发

首先删除它自带的页面 新建页面 Composition API 和 Options API 是 Vue.js 中两种不同的组件写法风格&#xff0c;它们用于定义 Vue 组件的结构和逻辑。我用的是Options API 配置路由 将它修改为需要的,按照上面的写法 如果component里面已经加了那么就不需要在上面加这是一种…

C++数据结构重要知识点(4)(map和set封装)

前面我们已经实现了红黑树&#xff0c;接下来我们需要将这个数据结构封装成map和set两个容器&#xff0c;其中很多地方的处理都有一定难度&#xff0c;下面会按照我的思路讲解map的改造 map成员变量如下&#xff0c;如果是第一次看到它&#xff0c;那么一定会很陌生&#xff0…

C高级(学习)2024.8.1

目录 shell命令 数组 数组的赋值 数组的调用 遍历数组 函数 函数的定义方式 函数调用 分文件编程 源文件 头文件 include引用时“”和<>的区别 编译工具 gcc编译工具 gdb调试 make工具 定义 Makefile格式 Makefile管理多个文件 Makefile变量 自定义…

发布NPM包详细流程

制作 首先需要制作一个npm包。 按照以下步骤依次执行。 mkdir my-npm-package cd my-npm-package npm init 相信这一步不需要过多的解释&#xff0c;就是创建了一个文件夹&#xff0c;然后初始化了一下文件夹。 然后在生成的package.json文件夹中更改一下自己的配置&…

Python-docx,修改word编辑时间总计、创建时间、上次修改时间、作者、上次修改者、备注

Python版本3.9&#xff0c;Python-docx版本1.1.2 修改下图中红框内的信息 创建时间、上次修改时间、作者、上次修改者、备注&#xff0c;这些都有接口&#xff0c;调用 import docx from docx import Document from docx.oxml.ns import qn from docx.shared import Inches, …

“2028年互联网上所有高质量文本数据将被使用完毕”

研究公司Epoch AI预测&#xff0c;到2028年互联网上所有高质量的文本数据都将被使用完毕&#xff0c;机器学习数据集可能会在2026年前耗尽所有“高质量语言数据”。研究人员指出&#xff0c;用人工智能(AI)生成的数据集训练未来几代机器学习模型可能会导致“模型崩溃”&#xf…

助力外卖霸王餐系统运营 微客云近期更新汇总

全面助力霸王餐合作运营&#xff0c;给大家汇报下最近微客云更新的内容&#xff0c;说实话近期非常的忙&#xff0c;各种功能上线&#xff0c;各种市场部们反馈的需求&#xff0c;微客云霸王餐招商体系&#xff08;分站&#xff09;自年底上线到现在&#xff0c;不知已更新了多…

2024年8月初AI大赛盛宴来袭!7场赛事等你挑战,最高奖金高达1.4万!

本期为大家带来7场精彩的AI大赛&#xff0c;主要以AI绘画大赛为主打&#xff0c;涵盖1场视频大赛和1场大模型大赛。 其中&#xff0c;以下3场大赛不容错过&#xff0c;分别是“36氪AI PARTNER2024具身智能大会”、“2024年大学生AI艺术季”和“混元万物 LiblibAlx腾讯混元模型…

微型丝杆弯曲:工件精度下降的隐形杀手!

微型丝杆作为精密机械部件&#xff0c;‌其弯曲或变形会对使用它进行加工的工件产生直接影响。在机械加工中&#xff0c;微型丝杆弯曲是一个不容忽视的问题&#xff0c;它会对工件造成多方面的损害。 1、加工精度受损&#xff1a;弯曲会直接导致工具的实际运动轨迹与程序设计的…

从零开始学习网络安全渗透测试之基础入门篇——(五)WEB抓包技术HTTPS协议APP小程序PC应用WEB转发联动

HTTP/HTTPS抓包技术是一种用于捕获和分析网络流量的方法&#xff0c;它可以帮助开发者、测试人员和网络安全专家理解应用程序的网络行为、调试问题、分析性能和识别潜在的安全威胁。 一、抓包技术和工具 &#xff08;一&#xff09;Charles Charles 是一款流行的网络调试代…

leetcode刷题日记-括号生成

题目描述 题目解析 回溯的题目&#xff0c;不过这个两个if我就感觉有点难以理解了&#xff0c;不过仔细的思考了一下&#xff0c;确实考虑到了每个位置的情况&#xff0c;特别是针对右边括号 题目代码 class Solution:def generateParenthesis(self, n: int) -> List[str…

苹果的秘密武器:折叠屏iPhone即将来袭,可能是史上最薄折叠屏?

苹果公司一直以来以其独特的产品设计理念和卓越的技术创新能力而闻名。近期&#xff0c;有关苹果折叠屏iPhone的消息再次引发了业界的高度关注。 据可靠消息源透露&#xff0c;这款备受期待的设备已经结束了实验阶段&#xff0c;预计最早将在2026年与消费者见面。 折叠屏iPhon…

【vue-cli】vue-cli@2源码学习

vue-cli 2 源码 @vue/cli: 3.11.0创建项目 vue create 项目名称 @vue/cli: 2.x.x 创建项目 vue init webpack yhh-project 脚手架初始化项目流程: 下载vue/cli@2 源码 下载完成后初始化 npm i 创建项目 vue init webpack yhh-project vue-init: bin/vue-init #!/usr/bin/e…

大模型数据分析平台 LangSmith 介绍

[​LangSmith​]​ 是 LangChain 自主研发的 LLM 应用程序开发、监控和测试的平台。 LangChain 是一款使用 LLM 构建的首选开源框架&#xff0c;一个链接面向用户程序和 LLM 之间的一个中间层&#xff0c;允许 AI 开发者将像 ​​GPT-4​​ 、文心一言等大型语言模型与外部的计…

springboot依赖之JDBC API手写sql 管理数据库

JDBC API 依赖名称: JDBC API 功能描述: Database Connectivity API that defines how a client may connect and query a database. 数据库连接 API&#xff0c;定义客户端如何连接和查询数据库。 JDBC API 是 Java 标准库的一部分&#xff0c;提供低级别的数据库访问。需要…

基于SpringBoot+Vue的超市进销存系统(带1w+文档)

基于SpringBootVue的超市进销存系统(带1w文档) 基于SpringBootVue的超市进销存系统(带1w文档) 本系统提供给管理员对首页、个人中心、员工管理、客户管理、供应商管理、承运商管理、仓库信息管理、商品类别管理、 商品信息管理、采购信息管理、入库信息管理、出库信息管理、销售…

一次通过PMP考试的学习经验分享

很开心的收到PMI发来的邮件&#xff0c;祝贺我通过了PMP考试。应助教老师的邀请&#xff0c;简单说下我的一些学习备考经验&#xff0c;希望能给即将参加考试的大家带来一些收获。 第一&#xff0c;听基础课&#xff0c;截图做笔记 课程时间对我来说&#xff0c;还是蛮长的。…

MQA(Multi-Query Attention)详解

论文名称&#xff1a;Fast Transformer Decoding: One Write-Head is All You Need 论文地址&#xff1a;https://arxiv.org/abs/1911.02150v1 MQA(Multi-Query Attention)是Google团队在2019年提出的&#xff0c;是MHA (Multi-head Attention&#xff0c;多头注意力机制)的一…

微信运营新助手:自动回复神器,让沟通更高效!

在现代职场中&#xff0c;效率是成功的关键。然而&#xff0c;我们经常会面对大量重复且繁琐的日常任务&#xff0c;消耗宝贵的时间和精力。 今天&#xff0c;我想向大家分享一个强大的微信自动回复神器&#xff0c;它将帮助你高效管理沟通&#xff0c;提升工作效率。 1、自动…