Spring Boot调用AWS SES发送邮件速度慢的问题求助
Spring Boot调用AWS SES发送邮件耗时远超Python的原因及解决办法
我在Spring Boot中调用AWS SES发送单封邮件耗时约300ms,但用Python调用仅需0.3ms。我的Spring Boot实现参考了一个AWS SES的Spring Cloud示例,下面是Python的示例代码,想请教这种差异的原因以及优化方案。
import boto3 from botocore.exceptions import ClientError import time # 替换为你的发件人地址,必须已在SES验证 SENDER = " <info@researchkernel.org>" # 替换为收件人地址,若账号处于沙箱模式,该地址也需验证 RECIPIENT = "prakritidevverma@gmail.com" # 配置集名称,若不需要可注释 CONFIGURATION_SET = "ConfigSet" # 替换为你使用的AWS区域 AWS_REGION = "us-west-2" # 邮件主题 SUBJECT = "iimjobs.com - Your Personalized Jobfeed" # 纯文本邮件内容 BODY_TEXT = """""" # HTML格式邮件内容 BODY_HTML = """<html> <head></head> <body> <h1>Amazon SES Test (SDK for Python)</h1> <p>This email was sent with <a href='https://aws.amazon.com/ses/'>Amazon SES</a> using the <a href='https://aws.amazon.com/sdk-for-python/'> AWS SDK for Python (Boto)</a>.</p> <p>Delhi is a crowded city. There are very few rich people who travel by their own vehicles. The majority of the people cannot afford to hire a taxi or a three-wheeler. They have to depend on D.T.C. buses, which are the cheapest mode of conveyance. D.T.C. buses are like blood capillaries of our body spreading all over in Delhi. One day I had to go to railway station to receive my uncle. I had to reach there by 9.30 a.m. knowing the irregularity of D.T.C. bus service; I left my home at 7.30 a.m. and reached the bus stop. There was a long queue. Everybody was waiting for the bus but the buses were passing one after another without stopping. I kept waiting for about an hour. I was feeling very restless and I was afraid that I might not be able to reach the station in time. It was 8.45. Luckily a bus stopped just in front of me. It was overcrowded but somehow I managed to get into the bus. Some passengers were hanging on the footboard, so there was no question of getting a seat. It was very uncomfortable. We were feeling suffocated. All of a sudden, an old man declared that his pocket had been picked. He accused the man standing beside him. The young man took a knife out of his pocket and waved it in the air. No body dared to catch him. I thanked God when the bus stopped at the railway station. I reached there just in time.</P> <p>Delhi is a crowded city. There are very few rich people who travel by their own vehicles. The majority of the people cannot afford to hire a taxi or a three-wheeler. They have to depend on D.T.C. buses, which are the cheapest mode of conveyance. D.T.C. buses are like blood capillaries of our body spreading all over in Delhi. One day I had to go to railway station to receive my uncle. I had to reach there by 9.30 a.m. knowing the irregularity of D.T.C. bus service; I left my home at 7.30 a.m. and reached the bus stop. There was a long queue. Everybody was waiting for the bus but the buses were passing one after another without stopping. I kept waiting for about an hour. I was feeling very restless and I was afraid that I might not be able to reach the station in time. It was 8.45. Luckily a bus stopped just in front of me. It was overcrowded but somehow I managed to get into the bus. Some passengers were hanging on the footboard, so there was no question of getting a seat. It was very uncomfortable. We were feeling suffocated. All of a sudden, an old man declared that his pocket had been picked. He accused the man standing beside him. The young man took a knife out of his pocket and waved it in the air. No body dared to catch him. I thanked God when the bus stopped at the railway station. I reached there just in time.</p> </body> </html> """ # 邮件字符编码 CHARSET = "UTF-8" # 创建SES客户端 client = boto3.client('ses',region_name=AWS_REGION) start = time.time() # 尝试发送邮件 try: response = client.send_email( Destination={ 'ToAddresses': [ RECIPIENT, ], }, Message={ 'Body': { 'Html': { 'Charset': CHARSET, 'Data': BODY_HTML, }, 'Text': { 'Charset': CHARSET, 'Data': BODY_TEXT, }, }, 'Subject': { 'Charset': CHARSET, 'Data': SUBJECT, }, }, Source=SENDER, # 若不使用配置集,注释或删除下面一行 # ConfigurationSetName=CONFIGURATION_SET, ) except ClientError as e: print(e.response['Error']['Message']) else: print("Email sent! Message ID:"), print(response['MessageId']) end = time.time() print("time taken : SES : "+ str(end-start))
差异原因分析
- 客户端复用与连接池差异
Python的boto3客户端默认复用连接,初始化开销在脚本启动时一次性完成;而如果Spring Boot代码每次发送都重新创建SES客户端,或者连接池配置不合理,会导致每次请求都要重新建立TCP连接,大幅增加耗时。 - SDK实现与运行时开销
AWS Java SDK的序列化、签名、参数校验等逻辑比Python SDK更重,加上Spring容器的上下文加载、日志拦截等额外处理,会拉长单次调用的总耗时。 - 首次调用预热差异
Spring Boot首次调用时会触发类加载、客户端初始化、凭证加载等一次性操作,而Python脚本的初始化本身更轻量,且调用统计包含了初始化时间但整体耗时仍低。
优化解决办法
复用SES客户端实例
在Spring Boot中把SES客户端配置为单例Bean,避免重复初始化:@Configuration public class AwsSesConfig { @Bean public AmazonSimpleEmailService amazonSimpleEmailService() { return AmazonSimpleEmailServiceClientBuilder.standard() .withRegion(Regions.US_WEST_2) .build(); } }业务类中注入该Bean复用即可。
优化连接池配置
调整AWS Java SDK的HTTP客户端连接池参数,减少连接建立开销:@Bean public AmazonSimpleEmailService amazonSimpleEmailService() { HttpClientConfig httpClientConfig = HttpClientConfig.builder() .maxConnections(50) .connectionTimeout(Duration.ofSeconds(5)) .socketTimeout(Duration.ofSeconds(10)) .build(); return AmazonSimpleEmailServiceClientBuilder.standard() .withRegion(Regions.US_WEST_2) .withHttpClient(ApacheHttpClient.builder().withConfig(httpClientConfig).build()) .build(); }改用异步调用
使用Spring的@Async注解或者AWS的异步客户端AmazonSimpleEmailServiceAsync,让邮件发送逻辑后台执行,避免阻塞主线程,降低接口响应耗时。减少非核心开销
检查并移除邮件发送方法上不必要的日志、拦截器或AOP逻辑,减少额外处理步骤。提前预热客户端
应用启动后,提前调用一次SES的轻量接口(如listIdentities),完成初始化和连接建立,避免首次业务调用的额外开销。
内容的提问来源于stack exchange,提问作者Prakitidev Verma
相关产品推荐
相关产品推荐

