LaserStream的gRPC服务基于Yellowstone接口,并通过历史重放、多节点故障转移和完全托管环境等功能加以增强。
LaserStream使用开源的gRPC协议,确保没有供应商锁定,并与现有的gRPC实现最大限度兼容。
您可以直接使用 @yellowstone-grpc 进行连接,或者使用性能优化的 Helius LaserStream SDK 来获得额外的优势,包括更高的吞吐量、自动重连、订阅管理、错误处理等。
LaserStream SDK比JavaScript Yellowstone客户端快40倍 了解我们如何使用Rust Core与零拷贝NAPI绑定来最大化JavaScript SDK的性能
性能提示 :如果您在使用LaserStream连接时遇到任何延迟或性能问题,请参考故障排除部分 以了解常见原因和解决方案。
压缩 :我们强烈不建议使用 gZip 压缩,推荐使用 zstd 。gZip 的压缩和解压速度非常慢,会成为流处理的瓶颈。zstd 提供类似的压缩比,同时提供显著更快的压缩和解压带宽。未来将不再支持 gZip。
终端节点和地区
LaserStream 在全球多个地区提供。
选择离您的应用程序最近的终端节点以获得最佳性能:
Mainnet LaserStream 终端节点
地区 位置 终端节点 ewr 纽瓦克,新泽西(纽约附近) https://laserstream-mainnet-ewr.helius-rpc.compitt 匹兹堡,美国(中部) https://laserstream-mainnet-pitt.helius-rpc.comslc 盐湖城,美国(西海岸) https://laserstream-mainnet-slc.helius-rpc.comlax 洛杉矶,美国(西海岸) https://laserstream-mainnet-lax.helius-rpc.comlon 伦敦,欧洲 https://laserstream-mainnet-lon.helius-rpc.comams 阿姆斯特丹,欧洲 https://laserstream-mainnet-ams.helius-rpc.comfra 法兰克福,欧洲 https://laserstream-mainnet-fra.helius-rpc.comtyo 东京,亚洲 https://laserstream-mainnet-tyo.helius-rpc.comsgp 新加坡,亚洲 https://laserstream-mainnet-sgp.helius-rpc.com
Devnet LaserStream 终端节点
网络 位置 终端节点 Devnet 纽瓦克,新泽西(纽约附近) https://laserstream-devnet-ewr.helius-rpc.com
网络和地区选择 :
对于 生产应用 ,选择最靠近服务器的 mainnet 终端节点以获得最佳性能(例如,如果在欧洲部署,请使用阿姆斯特丹 (ams) 或法兰克福 (fra))
对于 测试 ,使用:https://laserstream-devnet-ewr.helius-rpc.com。
快速入门
创建新项目
mkdir laserstream-grpc-demo
cd laserstream-grpc-demo
npm init -y
安装依赖项
npm install helius-laserstream
npm install --save-dev typescript ts-node
npx tsc --init
获取您的 API 密钥
从 Helius Dashboard 生成密钥。 此密钥将作为 LaserStream 的身份验证令牌。 计划要求 :LaserStream devnet 需要开发者或商务计划 。LaserStream mainnet 需要专业计划。
创建订阅脚本
创建 index.ts ,如下所示: import { subscribe , CommitmentLevel , LaserstreamConfig , SubscribeRequest } from 'helius-laserstream'
async function main () {
const subscriptionRequest : SubscribeRequest = {
transactions: {
client: {
accountInclude: [ 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA' ],
accountExclude: [],
accountRequired: [],
vote: false ,
failed: false
}
},
commitment: CommitmentLevel . CONFIRMED ,
accounts: {},
slots: {},
transactionsStatus: {},
blocks: {},
blocksMeta: {},
entry: {},
accountsDataSlice: [],
// Optionally, you can replay missed data by specifying a fromSlot:
// fromSlot: '224339000'
// Note: Currently, you can only replay data from up to 216000 slots in the past (24 hours).
};
// Replace the values below with your actual LaserStream API key and endpoint
const config : LaserstreamConfig = {
apiKey: 'YOUR_API_KEY' , // Replace with your key from https://dashboard.helius.dev/
endpoint: 'https://laserstream-mainnet-ewr.helius-rpc.com' , // Choose your closest region
}
await subscribe ( config , subscriptionRequest , async ( data ) => {
console . log ( data );
}, async ( error ) => {
console . error ( error );
});
}
main (). catch ( console . error );
替换您的API密钥并选择您的区域
在index.ts中,更新config对象:
您的实际API密钥来自Helius Dashboard
离您的服务器位置最近的LaserStream端点
const config : LaserstreamConfig = {
apiKey: 'YOUR_ACTUAL_API_KEY' , // Replace with your key from Helius Dashboard
endpoint: 'https://laserstream-mainnet-fra.helius-rpc.com' , // Example: Frankfurt mainnet
// For devnet: endpoint: 'https://laserstream-devnet-ewr.helius-rpc.com'
}
网络和区域选择示例:
用于生产(Mainnet) :
欧洲:使用fra(法兰克福)、ams(阿姆斯特丹)或lon(伦敦)
美国东部:使用ewr(纽约)
美国西部:使用slc(盐湖城)或lax(洛杉矶)
亚洲:使用tyo(东京)或sgp(新加坡)
用于开发(Devnet) :
使用https://laserstream-devnet-ewr.helius-rpc.com
运行并查看结果
每当一个confirmed令牌交易涉及TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA时,您将在控制台中看到数据。
订阅请求
在订阅请求中,您需要包含以下常规参数:
历史重播: 您可以选择在主SubscribeRequest对象中包含一个fromSlot: string字段,以便从特定槽开始重播数据。目前,支持重播过去最多216,000个槽(24小时)的数据。
const subscriptionRequest : SubscribeRequest = {
commitment: CommitmentLevel . CONFIRMED ,
accountsDataSlice: [],
transactions: {},
accounts: {},
slots: {},
blocks: {},
blocksMeta: {},
entry: {},
}
接下来,您需要指定要订阅的数据过滤器,如帐户、区块、槽或交易。
为槽位更新定义过滤器。您使用的键(例如,mySlotLabel)是此特定过滤器配置的用户定义标签 ,这使您可以根据需要定义多个命名配置(尽管通常只需一个即可)。 slots : {
// mySlotLabel is a user-defined name for this slot update filter configuration
mySlotLabel : {
// filterByCommitment: true => Only broadcast slot updates at the specified subscribeRequest commitment
filterByCommitment : true
// interslotUpdates: true allows receiving updates for changes occurring within a slot, not just new slots.
interslotUpdates : true
}
},
为账户数据更新定义过滤器。您使用的键(例如,tokenAccounts)是此特定过滤器配置的用户定义标签 。 如果所有字段为空,则广播所有账户。否则:
字段作为逻辑AND 操作。
数组内的值作为逻辑OR 操作(除非在filters内,它们作为逻辑AND 操作)。
accounts : {
// tokenAccounts is a user-defined label for this account filter configuration
tokenAccounts : {
// Matches any of these public keys (logical OR)
account : [ "9SHQTA66Ekh7ZgMnKWsjxXk6DwXku8przs45E8bcEe38" ],
// Matches owners that are any of these public keys
owner : [ "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" ],
// Filters - all must match (AND logic)
filters : [
{ dataSize: 165 },
{
memcmp: {
offset: 0 ,
data: { base58: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" }
}
}
]
}
},
为交易更新定义过滤器。您使用的键(例如,myTxSubscription)是此特定过滤器配置的用户定义标签 。 如果所有字段为空,则广播所有交易。否则:
字段操作为逻辑AND 。
数组内的值被视为逻辑OR (除了 accountRequired,必须全部匹配)。
transactions : {
// myTxSubscription is a user-defined label for this transaction filter configuration
myTxSubscription : {
vote : false ,
failed : false ,
signature : "" ,
// Transaction must include at least one of these public keys (OR)
accountInclude : [ "86xCnPeV69n6t3DnyGvkKobf9FdN2H9oiVDdaMpo2MMY" ],
// Exclude if it matches any of these
accountExclude : [],
// Require all accounts in this array (AND)
accountRequired : []
}
},
为区块更新定义过滤器。你使用的键(例如,myBlockLabel)是此特定过滤器配置的用户定义标签 。 blocks : {
// myBlockLabel is a user-defined label for this block filter configuration
myBlockLabel : {
// Only broadcast blocks referencing these accounts
accountInclude : [ "86xCnPeV69n6t3DnyGvkKobf9FdN2H9oiVDdaMpo2MMY" ],
includeTransactions : true ,
includeAccounts : false ,
includeEntries : false
}
},
订阅分类帐条目。您使用的键(例如,entrySubscribe)是此订阅的用户定义标签 。目前,没有可用的条目过滤器;所有条目都被广播。 entry : {
entrySubscribe : {}
},
代码示例(LaserStream SDK)
Slot Updates
Account Updates
Transaction Updates
Blocks
Block Metadata
条目
import { subscribe , CommitmentLevel , LaserstreamConfig , SubscribeRequest } from 'helius-laserstream'
async function main () {
const subscriptionRequest : SubscribeRequest = {
transactions: {},
commitment: CommitmentLevel . CONFIRMED ,
accounts: {},
slots: {
slot: { filterByCommitment: true },
},
transactionsStatus: {},
blocks: {},
blocksMeta: {},
entry: {},
accountsDataSlice: [],
};
const config : LaserstreamConfig = {
apiKey: 'YOUR_API_KEY' , // Replace with your key
endpoint: 'https://laserstream-mainnet-ewr.helius-rpc.com' , // Choose your closest region
}
await subscribe ( config , subscriptionRequest , async ( data ) => {
console . log ( data );
}, async ( error ) => {
console . error ( error );
});
}
main (). catch ( console . error );
import { subscribe , CommitmentLevel , LaserstreamConfig , SubscribeRequest } from 'helius-laserstream'
async function main () {
const subscriptionRequest : SubscribeRequest = {
accounts: {
accountSubscribe: {
account: [ "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" ], // USDC mint account
owner: [],
filters: []
}
},
accountsDataSlice: [],
commitment: CommitmentLevel . CONFIRMED ,
slots: {},
transactions: {},
transactionsStatus: {},
blocks: {},
blocksMeta: {},
entry: {}
};
const config : LaserstreamConfig = {
apiKey: 'YOUR_API_KEY' , // Replace with your key
endpoint: 'https://laserstream-mainnet-ewr.helius-rpc.com' , // Choose your closest region
}
await subscribe ( config , subscriptionRequest , async ( data ) => {
console . log ( data );
}, async ( error ) => {
console . error ( error );
});
}
main (). catch ( console . error );
import { subscribe , CommitmentLevel , LaserstreamConfig , SubscribeRequest } from 'helius-laserstream'
async function main () {
const subscriptionRequest : SubscribeRequest = {
transactions: {
client: {
accountInclude: [ 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA' ],
accountExclude: [],
accountRequired: [],
vote: false ,
failed: false
}
},
commitment: CommitmentLevel . CONFIRMED ,
accounts: {},
slots: {},
transactionsStatus: {},
blocks: {},
blocksMeta: {},
entry: {},
accountsDataSlice: [],
};
const config : LaserstreamConfig = {
apiKey: 'YOUR_API_KEY' , // Replace with your key
endpoint: 'https://laserstream-mainnet-ewr.helius-rpc.com' , // Choose your closest region
}
await subscribe ( config , subscriptionRequest , async ( data ) => {
console . log ( data );
}, async ( error ) => {
console . error ( error );
});
}
main (). catch ( console . error );
import { subscribe , CommitmentLevel , LaserstreamConfig , SubscribeRequest } from 'helius-laserstream'
async function main () {
const subscriptionRequest : SubscribeRequest = {
entry: {},
accounts: {},
accountsDataSlice: [],
slots: {},
blocks: {
blocks: {
accountInclude: []
}
},
blocksMeta: {},
transactions: {},
transactionsStatus: {},
commitment: CommitmentLevel . CONFIRMED ,
};
const config : LaserstreamConfig = {
apiKey: 'YOUR_API_KEY' , // Replace with your key
endpoint: 'https://laserstream-mainnet-ewr.helius-rpc.com' , // Choose your closest region
}
await subscribe ( config , subscriptionRequest , async ( data ) => {
console . log ( data );
}, async ( error ) => {
console . error ( error );
});
}
main (). catch ( console . error );
import { subscribe , CommitmentLevel , LaserstreamConfig , SubscribeRequest } from 'helius-laserstream'
async function main () {
const subscriptionRequest : SubscribeRequest = {
entry: {},
accounts: {},
accountsDataSlice: [],
slots: {},
blocks: {},
blocksMeta: {
blockmetadata: {}
},
transactions: {},
transactionsStatus: {},
commitment: CommitmentLevel . CONFIRMED ,
};
const config : LaserstreamConfig = {
apiKey: 'YOUR_API_KEY' , // Replace with your key
endpoint: 'https://laserstream-mainnet-ewr.helius-rpc.com' , // Choose your closest region
}
await subscribe ( config , subscriptionRequest , async ( data ) => {
console . log ( data );
}, async ( error ) => {
console . error ( error );
});
}
main (). catch ( console . error );
import { subscribe , CommitmentLevel , LaserstreamConfig , SubscribeRequest } from 'helius-laserstream'
async function main () {
const subscriptionRequest : SubscribeRequest = {
entry: {
entrySubscribe: {} // Subscribe to all entries
},
accounts: {},
accountsDataSlice: [],
slots: {},
blocks: {},
blocksMeta: {},
transactions: {},
transactionsStatus: {},
commitment: CommitmentLevel . CONFIRMED ,
};
const config : LaserstreamConfig = {
apiKey: 'YOUR_API_KEY' , // Replace with your key
endpoint: 'https://laserstream-mainnet-ewr.helius-rpc.com' , // Choose your closest region
}
await subscribe ( config , subscriptionRequest , async ( data ) => {
console . log ( data );
}, async ( error ) => {
console . error ( error );
});
}
main (). catch ( console . error );
SDK 选项
我们为多种编程语言提供官方 SDK:
对于其他语言或自定义实现,您可以直接使用 Yellowstone gRPC proto 文件 来生成您偏好的语言的 gRPC 客户端。
疑难解答 / 常见问题
问:我的 LaserStream 连接出现延迟或性能缓慢的问题。这可能是什么原因?
答: LaserStream 连接的性能问题通常由以下原因造成:
JavaScript 客户端缓慢 :JavaScript 客户端可能因为处理过多的消息或消耗过多的带宽而滞后。考虑更精准地过滤您的订阅以减少消息量,切换到 LaserStream JavaScript SDK ,或尝试使用其他语言。
本地带宽有限 :大量订阅可能会使带宽有限的客户端负担过重。监控您的网络使用情况,考虑升级您的连接或减少订阅范围。
地理距离 :较长的网络路径增加了延迟和数据包丢失。使用靠近您服务器的端点 。对于高延迟连接,增加网络读取缓冲区大小(可以提高 5 倍以上的带宽):
sudo sysctl -w net.core.rmem_max= 67108864 net.ipv4.tcp_rmem="4096 87380 67108864"
要在重启后保持生效,添加到 /etc/sysctl.conf:
net.core.rmem_max =67108864
net.ipv4.tcp_rmem =4096 87380 67108864
增加 HTTP/2 流窗口大小到 64MB 以防止流控瓶颈:
// Rust (tonic)
Channel :: from_static ( "https://laserstream-mainnet-ewr.helius-rpc.com" )
. initial_stream_window_size ( 1024 * 1024 * 64 ) // 64MB window
. connect ()
. await ? ;
客户端处理瓶颈 :确保您的消息处理逻辑经过优化,不会长时间阻塞主线程。
调试客户端延迟 :为帮助您调试客户端,我们构建了一个工具来测试从您的节点到 Laserstream gRPC 服务器的最大带宽。要使用它运行:cargo install helius-laserstream-bandwidth
helius-laserstream-bandwidth --laserstream-url $LASERSTREAM_URL --api-key $API_KEY
输出返回您的服务器与Laserstream服务器之间的最大网络容量。最低需要10MB/s来订阅所有交易数据,80MB/s来订阅所有账户数据。我们建议至少具备要求容量的2倍以获得最佳性能。
A: 请确认您的API密钥和端点是正确的,并且您的网络允许到指定端点的出站gRPC连接。检查Helius状态页面 是否有任何正在进行的事件。
A: 请仔细检查过滤器部分描述的逻辑运算符(AND/OR)。确保公钥是正确的。检查您请求中指定的承诺级别。
Q: 我可以在一个请求中订阅多种类型的数据(例如,账户和交易)吗?
A: 可以,您可以在同一个SubscribeRequest对象中,在多个键下定义过滤器配置(例如,accounts, transactions)。
A: 我们不实现消费者组。相反,LaserStream提供团队所需的相同结果:恢复、重放和多节点可靠性,而无需协调层(以及随之而来的延迟/开销)。我们认为对于大多数工作负载来说,消费者组是不必要的,并且它们增加了延迟和操作开销。例如,单个LaserStream gRPC连接可以发出高达10倍Solana的交易+账户数据,大多数客户端订阅一个小的、经过过滤的片段。在这种情况下使用消费者组会消耗性能余地并引入另一个故障点。