「Serverless云开发72变」Serverless邮件推送系统实现

本文涉及的产品
Serverless 应用引擎免费试用套餐包,4320000 CU,有效期3个月
函数计算FC,每月15万CU 3个月
简介: Java 作为历年开发者使用榜前列的编程语言。因其丰富的生态圈被众多开发者说熟知。现如今,随着Serverless的不断推广,Java函数计算也逐渐走向开发者的视野。最近在负责系统服务支撑功能的编写。在剥离完邮件服务后。考虑到其支撑系统的特性以及与业务系统的特殊关系。就想着使用阿里云函数计算去将其从系统中剥离,从而降低系统负载。邮件推送系统主要包含推送 校验码 结果信息三种场景。本文主要是对业务迁移到函数计算下的业务的分析与思考。

我的场景选择和思考


场景选择


某WEB网站在用户注册成功后,会发一封欢迎邮件,通过函数计算把邮件内容定制成模板,每次触发,每次执行都是幂等无状态。因为做过对应业务,对阿里的对应的文档比较熟悉,且有部分实现代码。所以就是选择了这个业务场景。


思考


第一次选择函数计算去做对应的业务场景实现,个人在场景选择上比较谨慎。由于之前做过SpringCloud项目对阿里云邮件服务的整合,并完成了注册后邮件推送的代码逻辑实现,所以我就在思考把传统代码实现搬到云上使用函数计算来实现的可行性。


在原来的SpringCloud项目实现中,我主要使用了Redis MySQL 阿里云SDK集成等服务。首先就要考虑的就是阿里云函数计算JavaSDK对阿里云自己的SDK以及其他的第三方SDK的支持程度。我先找宁中大佬询问了阿里云函数计算 Java SDK对MySQL的支持后(可行的),就坚定了可以将原有代码设计转移到云上的决心。


系统设计与代码实现

系统设计


首先我设计的这个邮件推送系统主要包括以下的职能:


  1. 完成注册结果的推送
  2. 完成邮件校验码的发送
  3. 完成订阅者的定期邮件推送


对于一般的邮件系统来说,上述三条应该包含了大多数的业务场景,因此我主要围绕上述三点进行论述。由于系统用的是函数计算,且对于邮件系统来说,业务逻辑其实并不是过分的复杂,所以尽量轻量化的去做代码实现,减少重消耗的服务的引入。


我在做技术选择的时候(做SpringCloud的邮件服务的时候),参考了多家的邮件服务,为什么选择阿里云呢,其实是接口文档给的比较充足且具备可视化及统计服务。考虑到系统的稳定性,所以采用了阿里云的邮件推送服务。然后为了考虑扩展性我采用了上传HTML模板然后在用代码对预留关键字进行修改的形式去做代码的自定义处理。其实主要的也就是这两块 具体的分析我将在服务依赖中一一讲解。


服务依赖


该系统为Maven项目所以对依赖的管理较为方便 ,我主要使用的几个组件


  1. 阿里云邮件服务SDK
  2. Redis
  3. Mybatis
  4. FastJson
  5. Junit
  6. slf4j


使用阿里云邮件SDK的原因我已经在上面做了阐述,下面我主要讲一下Redis MySQL的使用。先说一下MySQL,有人会问不就是发送一个邮件吗,写几个模板丢到项目代码里面代码指一下不就好了。这样说也没什么问题,确实是可以这样实现。但是存在一个问题,假如模板格式发生了变动,那么整个代码也就需要改动。这样的话对于扩展性来说就显得相当不利了,还有就是SDK中的配置很多,每种邮件都会有自己不同的参数配置 ,假若如此,每个都在代码中申明其实问题和上面一样,对于修改与维护相当不利。所以我将其抽取出来 做成了两个类 1、SmtpConfig(存储配置) 2、SmtpTemplate(存储模板)。这两个类的代码实现,可以在我后面贴的码云链接里面找到。在这两个类的设计中我采用了充血模式,将部分对象封装业务以及对应的核心数据处理业务放到了实体类当中。大家有兴趣的可以在代码中查看一下,希望能提出宝贵的意见。


还有人会说你说使用MySQL是为了代码的维护性,那Redis是怎么一回事呢。这也和你之前说的轻量化也不符合啊。回答这个问题我们还要回到业务上面,对于邮件推送和验证码发送场景,邮件的频繁发送合理吗。显然不合理,连续的随意发送和有可能会使你的发送地址被邮件接收方标记成垃圾邮件。还有就是验证码发送场景,其实不只是验证码发送出去就了结的,其实还包含了校验的逻辑,所以使用Redis的原因其实大家就了解了。


其实还有一个原因:做缓存 从上面可知 我的模板是放在MySQL里面的以一个OSS链接的形式做的 ,那么每次调用的时候就需要请求OSS链接拿到对应的模板然后在进行解析。然后再替换对应的预设字段进行发送。从日常使用中大家都知道字符串替换的速度其实很快但是,文件的解析则需要根绝网络的速度来决定,并且将文件读成一个String串其实也很麻烦。所以我在第一次读取该模板后将原先的读取好的子串信息放入到Redis中 在第二次调用同一模板时则直接从Redis里面取数据,假如三天之后这个模板还是没有再被调用,则说明该模板并不常有,比较偏,所以就从Redis自动删除(预设时间3天)这样的话执行损耗就可以从300ms降低到100ms左右。


解耦思维


在代码发送前,其实需要做一些状态检查和一些条件拦截的操作。假如光使用Ifelse做简单的代码实现,则代码可读性和代码扩展性就会降低。我之前读过阿里大佬张建飞(大飞哥)的书,对其写的Cola框架有过一定的了解,所以我使用了其中的责任链模式以及其对异常处理的一些实现。


 首先看一下责任链设计


/*** @author mac_zyj*  一分钟内不能重复发送短信规则*/publicclassEmailOneMinNotRepeatFilterimplementsFilter<Map<String,Object>> {
privatefinalLoggerlogger=LoggerFactory.getLogger(EmailOneMinNotRepeatFilter.class);
privatestaticfinalStringSMS_ERROR_MESSAGE="请不要一分钟内重复发送";
privateRedisUtilsredisService=newRedisUtils();
@OverridepublicvoiddoFilter(Map<String, Object>contextMap, FilterInvokernextFilter) {
StringemailAddress= (String) contextMap.get("emailAddress");
StringrepeatCheckKey=emailAddress+SmtpServiceConstants.REPEAT_CHECK;
if(null!=redisService.get(repeatCheckKey)){
logger.warn("SmsException with error code,error message");
thrownewBizException(SMS_ERROR_MESSAGE);
        }
nextFilter.invoke(contextMap);
    }
}


上面的代码主要是做的重复发送的校验,若不存在重复情况则进行下一个条件校验若存在重复情况则进行异常抛出。返回错误信息。其余的情况也如此:例如 一定时间内过多的发送 同Ip发送次数过多等 都可以在后面进行追加具体使用如下


privatefinalFilterChainfilterChain=FilterChainFactory.buildFilterChain(
EmailOneMinNotRepeatFilter.class,
EmailSendTooMuchFilter.class    );
@OverridepublicvoidsendEmailCode(StringtoAddress, Stringcode)   {
//先执行拦截操作Map<String,Object>content=newHashMap<>(16);
content.put("emailAddress",toAddress);
filterChain.doFilter(content);
        ...........
}


项目不足与展望


 在上述文字和代码实现中 ,我完成了部分代码的实现(只完成了验证码发送场景),还有一部分由于时间原因并没有来得及进行编码,所以也有一些遗憾。还有就是对于数据库存储邮件模板的问题,是不是最优解也有待商榷。在后续的时间里,我会在码云上完善上述案例争取覆盖我之前说的其余的 没有实现的场景,并且优化现有的代码,希望大家多多帮助。提出宝贵的意见。


代码实现


我把代码上传到了码云上面 https://gitee.com/zhuyongjie1212/serverless-email

后续计划逐步完善上面所说的不足,并不断更新。也请有兴趣的大佬提出宝贵的意见,大家互相进步。


小结


  在阿里云 云开发平台的这次活动中,通过对具体的业务场景进行分析。对代码的设计与实现使我对Serverless云开发有了更深的认识与理解,特别是对于Java函数计算的使用,使我了解到了对于Java这种老牌开发语言在处理传统业务场景之外的使用,对我扩充技术栈具有一定的帮助。

  另外,感谢阿里云云开发平台给了我这个参与活动的机会,使我有机会和大家分享我对Serverless云开发的理解和具体的使用。大家可以访问云开发平台的官网(http://workbench.aliyun.com/)。那里有更多的Serverless上云的实践,云开发平台是一个可以满足开发者、研发团队完全基于「云+浏览器」就能完成日常开发工作的环境,它的设计理念是使自己成为团队大协同中的一环,它会跟阿里云诸多研发能力和工具进行集成,籍由更强大的阿里研发生态,为用户提供更大的协同研发可能,比如您在使用云开发平台的时候,可以根据您的需要,主动选择去开通使用项目管理、需求管理、文档管理等其他服务。


同时,为了帮助用户提供一个无缝应用阿里云服务的环境,云开发平台会跟阿里云的诸多云产品进行集成,随时为用户的使用而准备;您可以在云开发平台创建基于各种场景解决方案的应用,并为每个应用选用不同的云服务,这些云服务会开通在您的阿里云主账号之下,您主动开通的各种云资源会按照您的使用,正常地计量计费。


云开发平台鼓励所有的场景解决方案尽可能多的基于阿里云的 Serverless 类型产品去提供服务。Serverless 类型的产品都具有实时弹性以及按量付费的特征,这可以帮助到商业化研发团队,以尽可能低的成本去实现自己的商业价值。


背景知识


什么是函数计算


  函数计算是事件驱动的全托管计算服务。使用函数计算,您无需采购与管理服务器等基础设施,只需编写并上传代码。函数计算为您准备好计算资源,弹性地、可靠地运行任务,并提供日志查询、性能监控和报警等功能。


  借助函数计算,您可以快速构建任何类型的应用和服务,并且只需为任务实际消耗的资源付费。


Java函数计算


  函数计算支持Java8运行环境。Java语言由于需要编译后才可以在JVM虚拟机中运行。和Python、Node.js这类脚本型语言不同,Java语言有以下限制:


  不支持上传代码:仅支持上传已经开发完成、编译打包后的ZIP包或JAR包。函数计算不提供Java的编译能力。

  不支持在线编辑:由于不支持上传代码,所以不支持在线编辑代码,仅能看到通过页面上传或OSS上传两种方法提交代码。

事件函数接口

  您在使用Java编程时,必须要实现函数计算提供的接口类,对于事件入口函数目前有两个预定义接口可以选择。这两个预定义接口分别是:


StreamRequestHandler


  以流的方式接受调用输入event和返回执行结果,您需要从输入流中读取调用函数时的输入,处理完成后把函数执行结果写入到输出流中来返回。


PojoRequestHandler


  通过泛型的方式,您可以自定义输入和输出的类型,但是输入和输出的类型必须是POJO类型。


常见业务场景


  1. IoT应用:设备端通过函数计算来订阅天气信息和空气质量,设备和设备之间无依赖,执行过程中无需记录状态,获取到第三方数据即可返回。
  2. WEB应用:某WEB网站在用户注册成功后,会发一封欢迎邮件,通过函数计算把邮件内容定制成模板,每次触发,每次执行都是幂等无状态。
  3. 图片处理:基于OSS的事件触发,当用户上传的图片转入到某Bucket中后,自动触发函数岁图片进行可定制化处理
  4. 音频转换文字处理:当用户通过语音来发出某些指令的时候,可以通过函数计算来触发阿里云的ET公开API获取到音频转换成文字的方式。



还没有使用过Serverless云开发?

现在花3分钟体验新手任务即领10元阿里云无门槛代金券。

720X150x.png

本文参加Serverless云开发的有奖征文活动,已经获得作者授权

相关文章
|
20天前
|
监控 安全 Serverless
"揭秘D2终端大会热点技术:Serverless架构最佳实践全解析,让你的开发效率翻倍,迈向技术新高峰!"
【10月更文挑战第23天】D2终端大会汇聚了众多前沿技术,其中Serverless架构备受瞩目。它让开发者无需关注服务器管理,专注于业务逻辑,提高开发效率。本文介绍了选择合适平台、设计合理函数架构、优化性能及安全监控的最佳实践,助力开发者充分挖掘Serverless潜力,推动技术发展。
49 1
|
1月前
|
监控 Serverless 云计算
探索Serverless架构:开发的未来趋势
【10月更文挑战第5天】Serverless架构,即无服务器架构,正逐渐成为云计算领域的热点。它允许开发者构建和运行应用程序而无需管理底层服务器。本文介绍了Serverless架构的基本概念、核心优势及挑战,并展示了其在事件驱动编程、微服务架构和数据流处理等场景中的应用。通过优化冷启动、使用外部存储等实战技巧,开发者可以更好地利用Serverless架构提升开发效率和应用性能。随着技术的成熟,Serverless将在未来软件开发中扮演重要角色。
|
3月前
|
前端开发 小程序 Serverless
异步任务处理系统问题之阿里云函数计算FC的应用场景有哪些
异步任务处理系统问题之阿里云函数计算FC的应用场景有哪些
|
3月前
|
前端开发 大数据 数据库
🔥大数据洪流下的决战:JSF 表格组件如何做到毫秒级响应?揭秘背后的性能魔法!💪
【8月更文挑战第31天】在 Web 应用中,表格组件常用于展示和操作数据,但在大数据量下性能会成瓶颈。本文介绍在 JavaServer Faces(JSF)中优化表格组件的方法,包括数据处理、分页及懒加载等技术。通过后端分页或懒加载按需加载数据,减少不必要的数据加载和优化数据库查询,并利用缓存机制减少数据库访问次数,从而提高表格组件的响应速度和整体性能。掌握这些最佳实践对开发高性能 JSF 应用至关重要。
70 0
|
3月前
|
存储 设计模式 运维
Angular遇上Azure Functions:探索无服务器架构下的开发实践——从在线投票系统案例深入分析前端与后端的协同工作
【8月更文挑战第31天】在现代软件开发中,无服务器架构因可扩展性和成本效益而备受青睐。本文通过构建一个在线投票应用,介绍如何结合Angular前端框架与Azure Functions后端服务,快速搭建高效、可扩展的应用系统。Angular提供响应式编程和组件化能力,适合构建动态用户界面;Azure Functions则简化了后端逻辑处理与数据存储。通过具体示例代码,详细展示了从设置Azure Functions到整合Angular前端的全过程,帮助开发者轻松上手无服务器应用开发。
29 0
|
4月前
|
运维 Serverless API
Serverless 应用引擎使用问题之如何开发HTTP服务
阿里云Serverless 应用引擎(SAE)提供了完整的微服务应用生命周期管理能力,包括应用部署、服务治理、开发运维、资源管理等功能,并通过扩展功能支持多环境管理、API Gateway、事件驱动等高级应用场景,帮助企业快速构建、部署、运维和扩展微服务架构,实现Serverless化的应用部署与运维模式。以下是对SAE产品使用合集的概述,包括应用管理、服务治理、开发运维、资源管理等方面。
|
3月前
|
Kubernetes Serverless 调度
异步任务处理系统问题之在阿里云函数计算平台上用户提交异步任务的问题如何解决
异步任务处理系统问题之在阿里云函数计算平台上用户提交异步任务的问题如何解决
|
4月前
|
域名解析 运维 Serverless
函数计算产品使用问题之设置最大实例数为1和最大并发数为20,当请求数量超过20时,系统会如何处理
阿里云Serverless 应用引擎(SAE)提供了完整的微服务应用生命周期管理能力,包括应用部署、服务治理、开发运维、资源管理等功能,并通过扩展功能支持多环境管理、API Gateway、事件驱动等高级应用场景,帮助企业快速构建、部署、运维和扩展微服务架构,实现Serverless化的应用部署与运维模式。以下是对SAE产品使用合集的概述,包括应用管理、服务治理、开发运维、资源管理等方面。
|
3月前
|
存储 缓存 中间件
Serverless 架构问题之FaaSNet系统的工作如何解决
Serverless 架构问题之FaaSNet系统的工作如何解决
40 0
|
3月前
|
监控 Serverless Go
Golang 开发函数计算问题之Go 语言中切片扩容时需要拷贝原数组中的数据如何解决
Golang 开发函数计算问题之Go 语言中切片扩容时需要拷贝原数组中的数据如何解决

热门文章

最新文章

相关产品

  • 函数计算