浅谈消息队列及常见的分布式消息队列中间件

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

背景

分布式消息队列中间件是是大型分布式系统不可缺乏的中间件,经过消息队列,应用程序能够在不知道彼此位置的状况下独立处理消息,或者在处理消息前不须要等待接收此消息。因此消息队列主要解决应用耦合、异步消息、流量削锋等问题,实现高性能、高可用、可伸缩和最终一致性架构。消息队列已经逐渐成为企业应用系统内部通讯的核心手段,当前使用较多的消息队列有 RabbitMQ、RocketMQ、ActiveMQ、Kafka、ZeroMQ、MetaMQ 等,而部分数据库如 Redis、MySQL 以及 PhxSQL 也可实现消息队列的功能。前端

在平常学习与开发过程当中,消息队列做为系统不可缺乏的中间件,显得十分的重要。在现代云架构中,应用程序被分解为多个规模较小且更易于开发、部署和维护的独立构建块。消息队列可为这些分布式应用程序提供通讯和协调。而本人也在工做的过程当中,前先后后后接触到了 Kafka、RabbitMQ 两款消息队列。因此,本系列文章也主要以 RabbitMQ 和 Kafka 两款典型的消息中间件来作分析。本文是该系列的开篇,主要讲解消息队列的概述、特色等,而后对消息队列使用场景进行分析,最后对市面上比较常见的消息队列产品进行技术对比。python

 

消息队列概述

消息队列(Message Queue,简称 MQ)是指利用高效可靠的消息传递机制进行与平台无关的数据交流,并基于数据通讯来进行分布式系统的集成。经过提供消息传递和消息排队模型,它能够在分布式环境下提供应用解耦、弹性伸缩、冗余存储、流量削峰、异步通讯、数据同步等等功能,其做为分布式系统架构中的一个重要组件,有着举足轻重的地位。消息队列是构建分布式互联网应用的基础设施,经过 MQ 实现的松耦合架构设计能够提升系统可用性以及可扩展性,是适用于现代应用的最佳设计方案。算法

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

消息队列特色

为何要用消息队列?

经过异步处理提升系统性能

讲解该特色以前,咱们先了解一下同步架构和异步架构的区别:数据库

  • 同步调用:是指从请求的发起一直到最终的处理完成期间,请求的调用方一直在同步阻塞等待调用的处理完成。后端

  • 异步调用:是指在请求发起的处理过程当中,客户端的代码已经返回了,它能够继续进行本身的后续操做,而不须要等待调用处理完成,这就叫作异步调用。安全

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

如上图,在不使用消息队列服务器的时候,用户的请求数据直接写入数据库,在高并发的状况下数据库压力剧增,使得响应速度变慢。可是在使用消息队列以后,用户的请求数据发送给消息队列以后当即 返回,再由消息队列的消费者进程从消息队列中获取数据,异步写入数据库。因为消息队列服务器处理速度快于数据库(消息队列也比数据库有更好的伸缩性),所以响应速度获得大幅改善。服务器

经过以上分析咱们能够得出消息队列具备很好的削峰做用的功能——即经过异步处理,将短期高并发产生的事务消息存储在消息队列中,从而削平高峰期的并发事务。举例:在电子商务一些秒杀、促销活动中,合理使用消息队列能够有效抵御促销活动刚开始大量订单涌入对系统的冲击。以下图所示:网络

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

由于用户请求数据写入消息队列以后就当即返回给用户了,可是请求数据在后续的业务校验、写数据库等操做中可能失败。所以使用消息队列进行异步处理以后,须要适当修改业务流程进行配合,好比用户在提交订单以后,订单数据写入消息队列,不能当即返回用户订单提交成功,须要在消息队列的订单消费者进程真正处理完该订单以后,甚至出库后,再经过电子邮件或短信通知用户订单成功,以避免交易纠纷。这就相似咱们平时手机订火车票和电影票。多线程

下降系统耦合性

咱们知道若是模块之间不存在直接调用,那么新增模块或者修改模块就对其余模块影响较小,这样系统的可扩展性无疑更好一些。架构

咱们最多见的事件驱动架构相似生产者消费者模式,在大型网站中一般用利用消息队列实现事件驱动结构。以下图所示:

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

消息队列使利用发布 - 订阅模式工做,消息发送者(生产者)发布消息,一个或多个消息接受者(消费者)订阅消息。从上图能够看到消息发送者(生产者)和消息接受者(消费者)之间没有直接耦合,消息发送者将消息发送至分布式消息队列即结束对消息的处理,消息接受者从分布式消息队列获取该消息后进行后续处理,并不须要知道该消息从何而来。对新增业务,只要对该类消息感兴趣,便可订阅该消息,对原有系统和业务没有任何影响,从而实现网站业务的可扩展性设计。

消息接受者对消息进行过滤、处理、包装后,构形成一个新的消息类型,将消息继续发送出去,等待其余消息接受者订阅该消息。所以基于事件(消息对象)驱动的业务架构能够是一系列流程。

另外为了不消息队列服务器宕机形成消息丢失,会将成功发送到消息队列的消息存储在消息生产者服务器上,等消息真正被消费者服务器处理后才删除消息。在消息队列服务器宕机后,生产者服务器会选择分布式消息队列服务器集群中的其余服务器发布消息。

使用消息队列带来的一些问题?

  • 系统可用性下降:系统可用性在某种程度上下降,为何这样说呢?在加入 MQ 以前,你不用考虑消息丢失或者说 MQ 挂掉等状况,可是,引入 MQ 以后你就须要如何保证消息队列的高可用。

  • 系统复杂性提升:加入 MQ 以后,你须要保证消息没有被重复消费、处理消息丢失的状况、保证消息传递的顺序性等等问题,系统复发性提升。

  • 一致性问题:消息队列带来的异步确实能够提升系统响应速度。可是,万一消息的真正消费者并无正确消费消息怎么办?这样就会致使数据不一致的状况。

JMS VS AMQP

JMS

Java 消息服务(Java Message Service,JMS)应用程序接口是一个 Java 平台中关于面向消息中间件(MOM)的 API,用于在两个应用程序之间,或分布式系统中发送消息,进行异步通讯。JMS 的客户端之间能够经过 JMS 服务进行异步的消息传输。JMS PI 是一个消息服务的标准或者说是规范,容许应用程序组件基于 JavaEE 平台建立、发送、接收和读取消息。它使分布式通讯耦合度更低,消息服务更加可靠以及异步性。点对点与发布订阅最初是由 JMS 定义的。这两种模式主要区别或解决的问题就是发送到队列的消息可否重复消费。

JMS 规范目前支持两种消息模型:点对点(point to point,queue)和发布 / 订阅(publish/subscribe,topic)。

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

点对点(P2P)模型

消息生产者向消息队列中发送了一个消息以后,只能被一个消费者消费一次。点对点(P2P)使用队列(Queue)做为消息通讯载体;知足生产者与消费者模式,一条消息只能被一个消费者使用,未被消费的消息在队列中保留直到被消费或超时。

Queue 实现了负载均衡,一个消息只能被一个消费者接受,当没有消费者可用时,这个消息会被保存直到有 一个可用的消费者,一个 queue 能够有不少消费者,他们之间实现了负载均衡, 因此 Queue 实现了一个可靠的负载均衡。

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

特色:

  • 每一个消息只用一个消费者;

  • 发送者和接受者没有时间依赖;

  • 接受者确认消息接受和处理成功。

发布 / 订阅(Pub/Sub)模型

消息生产者向频道发送一个消息以后,多个消费者能够从该频道订阅到这条消息并消费。发布订阅模型(Pub/Sub) 使用主题(Topic)做为消息通讯载体,相似于广播模式;发布者发布一条消息,该消息经过主题传递给全部的订阅者,在一条消息广播以后才订阅的用户则是收不到该条消息的。

Topic 实现了发布和订阅,当你发布一个消息,全部订阅这个 Topic 的服务都能获得这个消息,因此从 1 到 N 个订阅者都能获得一个消息的拷贝, 只有在消息代理收到消息时有一个有效订阅时的订阅者才能获得这个消息的拷贝。

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

特色:

  • 每一个消息能够有多个订阅者;

  • 客户端只有订阅后才能接收到消息;

  • 持久订阅和非持久订阅。

注意:

  1. 发布者和订阅者有时间依赖:接受者和发布者只有创建订阅关系才能收到消息;

  2. 持久订阅:订阅关系创建后,消息就不会消失,无论订阅者是否都在线;

  3. 非持久订阅:订阅者为了接受消息,必须一直在线。当只有一个订阅者时约等于点对点模型。

点对点(P2P)模型与发布 / 订阅(Pub/Sub)模型应用

  • 点对点模型:主要用于一些耗时较长的、逻辑相对独立的业务。

好比说发送邮件这样一个操做。由于发送邮件比较耗时,并且应用程序其实也并不太关心邮件发送是否成功,发送邮件的逻辑也相对比较独立,因此它只须要把邮件消息丢到消息队列中就能够返回了,而消费者也不须要关心是哪一个生产者去发送的邮件,它只须要把邮件消息内容取出来之后进行消费,经过远程服务器将邮件发送出去就能够了。并且每一个邮件只须要被发送一次。因此消息只被一个消费者消费就能够了。

  • 发布订阅模型:如新用户注册这样一个消息,须要使用按主题发布的方式。

好比新用户注册,一个新用户注册成功之后,须要给用户发送一封激活邮件,发送一条欢迎短信,还须要将用户注册数据写入数据库,甚至须要将新用户信息发送给关联企业的系统,好比淘宝新用户信息发送给支付宝,这样容许用户能够一次注册就能登陆使用多个关联产品。一个新用户注册,会把注册消息发送给一个主题,多种消费者能够订阅这个主题。好比发送邮件的消费者、发送短信的消费者、将注册信息写入数据库的消费者,跨系统同步消息的消费者等。

AMQP

AMQP(advanced message queuing protocol)在 2003 年时被提出,最先用于解决金融领不一样平台之间的消息传递交互问题。顾名思义,AMQP 是一种协议,更准确的说是一种 binary wire-level protocol(连接协议)。这是其和 JMS 的本质差异,AMQP 不从 API 层进行限定,而是直接定义网络交换的数据格式。这使得实现了 AMQP 的 provider 自然性就是跨平台的。意味着咱们可使用 Java 的 AMQP provider,同时使用一个 python 的 producer 加一个 rubby 的 consumer。

在 AMQP 中,消息路由(message routing)和 JMS 存在一些差异,在 AMQP 中增长了 Exchange 和 binding 的角色。producer 将消息发送给 Exchange,binding 决定 Exchange 的消息应该发送到那个 queue,而 consumer 直接从 queue 中消费消息。

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

AMQP 提供五种消息模型:①Direct Exchange;②Fanout Exchange;③Topic Exchange;④Headers Exchange;⑤System Exchange。本质来说,后四种和 JMS 的 pub/sub 模型没有太大差异,仅是在路由机制上作了更详细的划分。

JMS 与 AMQP 对比

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

总结:

  • AMQP 为消息定义了线路层(wire-level protocol)的协议,而 JMS 所定义的是 API 规范。在 Java 体系中,多个 client 都可以经过 JMS 进行交互,不须要应用修改代码,可是其对跨平台的支持较差。而 AMQP 自然具备跨平台、跨语言特性。

  • JMS 支持 TextMessage、MapMessage 等复杂的消息类型;而 AMQP 仅支持 byte[] 消息类型(复杂的类型可序列化后发送)。

  • 因为 Exchange 提供的路由算法,AMQP 能够提供多样化的路由方式来传递消息到消息队列,而 JMS 仅支持 队列 和 主题 / 订阅 方式两种。

消息队列推拉模型

Push 推消息模型:消息生产者将消息发送给消息队列,消息队列又将消息推给消息消费者。

Pull 拉消息模型:消费者请求消息队列接受消息,消息生产者从消息队列中拉该消息。

 

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

RabbitMQ

RabbitMQ 实现了 AQMP 协议,AQMP 协议定义了消息路由规则和方式。生产端经过路由规则发送消息到不一样 queue,消费端根据 queue 名称消费消息。此外 RabbitMQ 是向消费端推送消息,订阅关系和消费状态保存在服务端。

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

Kafka

Kafka 只支持消息持久化,消费端为拉模型,消费状态和订阅关系由客户端端负责维护,消息消费完后不会当即删除,会保留历史消息。所以支持多订阅时,消息只会存储一份就能够了。同一个订阅组会消费 topic 全部消息,每条消息只会被同一个订阅组的一个消费节点消费,同一个订阅组内不一样消费节点会消费不一样消息。

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

 

 

 

消息队列使用场景

异步处理:实现异步处理,提高处理性能

对一些比较耗时的操做,能够把处理过程经过消息队列进行异步处理。这样作能够推迟耗时操做的处理,使耗时操做异步化,而没必要阻塞客户端的程序,客户端的程序在获得处理结果以前就能够继续执行,从而提升客户端程序的处理性能。非核心流程异步化,减小系统响应时间,提升吞吐量。

例如:短信通知、终端状态推送、App 推送、用户注册等。

解耦:可使生产者和消费者的代码实现解耦合

能够多个生产者发布消息,多个消费者处理消息,共同完成完整的业务处理逻辑,可是它们的不须要直接的交互调用,没有代码的依赖耦合。在传统的同步调用中,调用者代码必需要依赖被调用者的代码,也就是生产者代码必需要依赖消费者的处理逻辑代码,代码须要直接的耦合,而使用消息队列,这两部分的代码不须要进行任何的耦合。由于耦合程度越低的代码越容易维护,也越容易进行扩展。

好比新用户注册,若是用传统同步调用的方式,那么发邮件、发短信、写数据库、通知关联系统这些代码会和用户注册代码直接耦合起来,整个代码看起来就是完成用户注册逻辑后,后面必然跟着发邮件、发短信这些代码。若是要新增一个功能,好比将监控用户注册状况,将注册信息发送到业务监控系统,就必需要修改前面的代码,至少增长一行代码,发送注册信息到监控系统,咱们知道,任何代码的修改均可能会引发 bug。

而使用分布式消息队列实现生产者和消费者解耦合之后,用户注册之后,不须要调用任何后续处理代码,只须要将注册消息发送到分布式消息队列就能够了。若是要增长新功能,只须要写个新功能的消费者程序,在分布式消息队列中,订阅用户注册主题就能够了,不须要修改原来任何一行代码。

流量削峰和流控:能够平衡流量峰值,削峰填谷

当上下游系统处理能力存在差距的时候,利用消息队列作一个通用的 “漏斗”,进行限流控制。在下游有能力处理的时候,再进行分发。

使用消息队列,即使是访问流量持续的增加,系统依然能够持续地接收请求。这种状况下,虽然生产者发布消息的速度比消费者消费消息的速度快,可是能够持续的将消息归入到消息队列中,用消息队列做为消息的缓冲,所以短期内,发布者不会受到消费处理能力的影响。

在访问高峰,用户的并发访问数可能超过了系统的处理能力,因此在高峰期就可能会致使系统负载过大,响应速度变慢,更严重的可能会致使系统崩溃。这种状况下,经过消息队列将用户请求的消息归入到消息队列中,经过消息队列缓冲消费者处理消息的速度。

消息的生产者它有高峰有低谷,可是到了消费者这里,只会按照本身的最佳处理能力去消费消息。高峰期它会把消息缓冲在消息队列中,而在低谷期它也仍是使用本身最大的处理能力去获取消息,将前面缓冲起来、来不及及时处理的消息处理掉。那么,经过这种手段能够实现系统负载消峰填谷,也就是说将访问的高峰消掉,而将访问的低谷填平,使系统处在一个最佳的处理状态之下,不会对系统的负载产生太大的冲击。

举个例子:用户在支付系统成功结帐后,订单系统会经过短信系统向用户推送扣费通知。短信系统可能因为短板效应,速度卡在网关上(每秒几百次请求),跟前端的并发量不是一个数量级。因而,就形成支付系统和短信系统的处理能力出现差别化。

然而用户晚上个半分钟左右收到短信,通常是不会有太大问题的。若是没有消息队列,两个系统之间经过协商、滑动窗口等复杂的方案也不是说不能实现。但系统复杂性指数级增加,势必在上游或者下游作存储,而且要处理定时、拥塞等一系列问题。并且每当有处理能力有差距的时候,都须要单独开发一套逻辑来维护这套逻辑。因此,利用中间系统转储两个系统的通讯内容,并在下游系统有能力处理这些消息的时候,再处理这些消息,是一套相对较通用的方式。

易伸缩:可让系统得到更好的伸缩性

耗时的任务能够经过分布式消息队列,向多台消费者服务器并行发送消息,而后在不少台消费者服务器上并行处理消息,也就是说能够在多台物理服务器上运行消费者。那么当负载上升的时候,能够很容易地添加更多的机器成为消费者。

例如:用户上传文件后,经过发布消息的方式,通知后端的消费者获取数据、读取文件,进行异步的文件处理操做。那么当前端发布更多文件的时候,或者处理逻辑比较复杂的时候,就能够经过添加后端的消费者服务器,提供更强大的处理能力。

隔离失效机器以及自我修复:失败隔离和自我修复

由于发布者不直接依赖消费者,因此分布式消息队列能够将消费者系统产生的错误异常与生产者系统隔离开来,生产者不受消费者失败的影响。当在消息消费过程当中出现处理逻辑失败的时候,这个错误只会影响到消费者自身,而不会传递给消息的生产者,也就是应用程序能够按照原来的处理逻辑继续执行。

因此,这也就意味着在任什么时候候均可以对后端的服务器执行维护和发布操做。能够重启、添加或删除服务器,而不影响生产者的可用性,这样简化了部署和服务器管理的难度。

日志处理

日志处理是指将消息队列用在日志处理中,好比 Kafka 的应用,解决大量日志传输和缓冲的问题。日志采集客户端,负责日志数据采集,定时写受写入 Kafka 队列;Kafka 消息队列,负责日志数据的接收,存储和转发;日志处理应用,订阅并消费 kafka 队列中的日志数据。

消息队列技术对比

  • ActiveMQ 是 Apache 出品的、采用 Java 语言编写的彻底基于 JMS1.1 规范的面向消息的中间件,为应用程序提供高效的、可扩展的、稳定的和安全的企业级消息通讯。不过因为历史缘由包袱过重,目前市场份额没有后面三种消息中间件多,其最新架构被命名为 Apollo,号称下一代 ActiveMQ,有兴趣的同窗可行了解。

  • RabbitMQ 是采用 Erlang 语言实现的 AMQP 协议的消息中间件,最初起源于金融系统,用于在分布式系统中存储转发消息。RabbitMQ 发展到今天,被愈来愈多的人承认,这和它在可靠性、可用性、扩展性、功能丰富等方面的卓越表现是分不开的。主要特色是性能好,社区活跃,可是 RabbitMQ 用 Erlang 开发,咱们的应用不多用 Erlang,因此不便于二次开发和维护。

  • Kafka 是由 LinkedIn 公司采用 Scala 语言开发的一个分布式、多分区、多副本且基于 zookeeper 协调的分布式消息系统,现已捐献给 Apache 基金会。它是一种高吞吐量的分布式发布订阅消息系统,以可水平扩展和高吞吐率而被普遍使用。目前愈来愈多的开源分布式处理系统如 Cloudera、Apache Storm、Spark、Flink 等都支持与 Kafka 集成。

  • RocketMQ 是阿里开源的消息中间件,目前在 Apache 孵化,使用纯 Java 开发,具备高吞吐量、高可用性、适合大规模分布式系统应用的特色。RocketMQ 思路起源于 Kafka,但并非简单的复制,它对消息的可靠传输及事务性作了优化,目前在阿里集团被普遍应用于交易、充值、流计算、消息推送、日志流式处理、binglog 分发等场景,支撑了阿里屡次双十一活动。

  • ZeroMQ 是基于 C 语言开发,号称史上最快的消息队列。ZeroMQ 是一个消息处理队列库,可在多线程、多内核和主机之间弹性伸缩,虽然大多数时候咱们习惯将其纳入消息队列家族之中,可是其和前面的几款有着本质的区别,ZeroMQ 自己就不是一个消息队列服务器,更像是一组底层网络通信库,对原有的 Socket API 上加上一层封装而已。

总结:

  • ActiveMQ 的社区算是比较成熟,可是较目前来讲,ActiveMQ 的性能比较差,并且版本迭代很慢,不推荐使用。

  • RabbitMQ 在吞吐量方面虽然稍逊于 Kafka 和 RocketMQ ,可是因为它基于 erlang 开发,因此并发能力很强,性能极其好,延时很低,达到微秒级。可是也由于 RabbitMQ 基于 erlang 开发,因此国内不多有公司有实力作 erlang 源码级别的研究和定制。若是业务场景对并发量要求不是过高(十万级、百万级),那这四种消息队列中,RabbitMQ 必定是你的首选。若是是大数据领域的实时计算、日志采集等场景,用 Kafka 是业内标准的,绝对没问题,社区活跃度很高,绝对不会黄,况且几乎是全世界这个领域的事实性规范。

  • RocketMQ 阿里出品,Java 系开源项目,源代码咱们能够直接阅读,而后能够定制本身公司的 MQ,而且 RocketMQ 有阿里巴巴的实际业务场景的实战考验。RocketMQ 社区活跃度相对较为通常,不过也还能够,文档相对来讲简单一些,而后接口这块不是按照标准 JMS 规范走的有些系统要迁移须要修改大量代码。还有就是阿里出台的技术,你得作好这个技术万一被抛弃,社区黄掉的风险,那若是大家公司有技术实力我以为用 RocketMQ 挺好的

  • kafka 最初设计时就是针对互联网的分布式、高可用应用场景而设计,因此其特色其实很明显,就是仅仅提供较少的核心功能,可是提供超高的吞吐量,ms 级的延迟,极高的可用性以及可靠性,并且分布式能够任意扩展。同时 kafka 最好是支撑较少的 topic 数量便可,保证其超高吞吐量。kafka 惟一的一点劣势是有可能消息重复消费,那么对数据准确性会形成极其轻微的影响,在大数据领域中以及日志采集中,这点轻微影响能够忽略这个特性自然适合大数据实时计算以及日志收集。

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=