用了8年MQ!聊聊消息队列的技能选型,哪个最香!

手机软件开发 2024-9-10 09:50:20 67 0 来自 中国
谈起消息队列,心田还是会有些波涛。
消息队列,缓存,分库分表是高并发办理方案三剑客,而消息队列是我最喜欢,也是思考最多的技能。
我想按照下面的四个阶段分享我与消息队列的故事,同时也是对我技能发展履历的回首。

  • 初识:ActiveMQ
  • 进阶:Redis&RabbitMQ
  • 升华:MetaQ
  • 钟情:RocketMQ
1 初识ActiveMQ

1.1 异步&解耦

2011年初,我在一家互联网彩票公司做研发。
我负责的是用户中心体系,提供用户注册,查询,修改等根本功能。用户注册乐成之后,须要给用户发送短信。
由于原来都是面向过程编程,我就把新增用户模块和发送短信模块都揉在一起了。
早先都还好,但问题渐渐的显现出来。

  • 短信渠道不敷稳固,发送短信会到达5秒左右,这样用户注册接口耗时很大,影响前端用户体验;
  • 短信渠道接口发生变革,用户中心代码就必须修改了。但用户中心是焦点体系。每次上线都须要谨小慎微。这种感觉很别扭,非焦点功能影响到焦点体系了。
第一个问题,我可以接纳线程池的方法来做,重要是异步化。但第二个问题却让我束手无措。
于是我向技能司理讨教,他告诉我引入消息队列去办理这个问题。

  • 将发送短信功能单独拆成独立的Job服务;
  • 用户中心用户注册乐成后,发送一条消息到消息队列,Job服务收到消息调用短佩服务发送短信即可。
这时,我才明确: 消息队列最焦点的功能就是异步解耦
1.2 调度中心

彩票体系的业务是比力复杂的。在彩票订单的生命周期里,颠末创建,拆分子订单,出票,算奖等诸多环节。每一个环节都须要不同的服务处置处罚,每个体系都有自己独立的表,业务功能也相对独立。假如每个应用都去修改订单主表的信息,那就会相当杂乱了。
公司的架构师筹划了调度中心的服务,调度中心的职责是维护订单焦点状态机,订单返奖流程,彩票焦点数据天生。


调度中心通过消息队列和出票网关,算奖服务等体系转达和互换信息。
这种筹划在谁人时间青涩的我的眼里,简直就是水滴vs人类舰队,降维打击。
随着我对业务明白的不绝深入,我隐隐以为:“好的架构是轻便的,也是应该易于维护的”。
当彩票业务日均千万生意业务额的时间,调度中心的研发维护职员也只有两个人。调度中心的源码里业务逻辑,日记,代码规范都是极好的。
在我日后的程序人生里,我也会下意识模仿调度中心的编码方式,“不玩奇技淫巧,代码是给人阅读的”。
1.3 重启大法

随着彩票业务的爆炸增长,每天的消息量从30万激增到150~200万左右,齐备看起来好像很平稳。
某一天双色球投注截止,调度中心无法从消息队列中斲丧数据。消息总线处于只能发,不能收的状态下。整个技能团队都处于非常的焦急状态,“要是出不了票,那但是几百万的丧失呀,要是用户中了两个双色球?那但是千万呀”。各人急得像热锅上的蚂蚁。
这也是整个技能团队第一次遇到斲丧堆积的环境,各人都没有履历。
起首想到的是多摆设几台调度中心折务,摆设完成之后,调度中心斲丧了几千条消息后还是Hang住了。这时,架构师只能接纳重启的计谋。你没有看错,就是重启大法。提及来真的很忸怩,但当时真的只能接纳这种方式。
调度中心重启后,斲丧了一两万后又Hang住了。只能又重启一次。来来回回连续20多次,像挤牙膏一样。而且随着出票截止时间的邻近,这种头脑上的告急和恐惊感更加猛烈。终于,通过1小时的手工不绝重启,消息终于斲丧完了。
我当时恰好在读毕玄老师的《分布式java应用根本与实践》,料想是不是线程壅闭了,于是我用Jstack下令查察堆栈环境。果然不出所料,线程都壅闭在提交数据的方法上。
我们立刻和DBA沟通,发现oracle数据库实验了非常多的大事件,每次大的事件实验都须要30分钟以上,导致调度中心的调度出票线程壅闭了。
技能部厥后接纳了如下的方案规避堆积问题:

  • 生产者发送消息的时间,将超大的消息拆分成多批次的消息,淘汰调度中心实验大事件的几率;
  • 数据源设置参数,假如事件实验超过肯定时长,自动抛非常,回滚。
1.4 复盘

Spring封装的ActiveMQ的API非常轻便易用,使用过程中真的非常惬意。
受限于当时彩票技能团队的技能水平和视野,我们在使用ActiveMQ中遇到了一些问题。
高吞吐下,堆积到肯定消息量易Hang住

技能团队发如今吞吐量特别高的场景下,假如消息堆积越大,ActiveMQ有较小几率会Hang住的。
出票网关的消息量特别大,有的消息并不须要立刻斲丧,但是为了规避消息队列Hang住的问题,出票网关斲丧数据的时间,先将消息先长期化到本地磁盘,生本钱地XML文件,然后异步定时实验消息。通过这种方式,我们大幅度提升了出票网关的斲丧速率,根本杜绝了出票网关队列的堆积。
但这种方式感觉也挺怪的,斲丧消息的时间,还要本地再存储一份数据,消息存储在本地,假如磁盘坏了,也有丢消息的风险。
高可用机制待美满

我们接纳的master/slave摆设模式,一主一从,服务器设置是4核8G 。
这种摆设方式可以同时运行两个ActiveMQ, 只允许一个slave毗连到Master上面,也就是说只能有2台MQ做集群,这两个服务之间有一个数据备份通道,使用这个通道Master向Slave单向地数据备份。这个方案在实际生产线上不方便, 由于当Master挂了之后, Slave并不能自动地吸收Client发来的请来,须要手动干预,且要克制Slave再重启Master才气规复负载集群。
另有一些很诡异丢消息的变乱,生产者发送消息乐成,但master控制台查询不到,但slave控制台竟然能查询到该消息。
但斲丧者没有办法斲丧slave上的消息,还得通过人工到场的方式行止理。
2 进阶Redis&RabbitMQ

2014年,我在艺龙网从事红包体系和优惠券体系优化相干工作。
2.1 Redis可以做消息队列吗

旅店优惠券盘算服务使用的是初代流式盘算框架Storm。Storm这里就不具体先容,可以参看下面的逻辑图:

这里我们的Storm集群的水源头(数据源)是redis集群,使用list数据布局实现了消息队列的push/pop功能。

流式盘算的团体流程:

  • 旅店信息服务发送旅店信息到Redis集群A/B;
  • Storm的spout组件从Redis集群A/B获取数据, 获取乐成后,发送tuple消息给Bolt组件;
  • Bolt组件收到消息后,通过运营设置的规则对数据举行洗濯;
  • 末了Storm把处置处罚好的数据发送到Redis集群C;
  • 入库服务从Redis集群C获取数据,存储数据到数据库;
  • 搜索团队扫描数据库表,天生索引。
7.jpg <figcaption style="text-align: center; color: rgb(136, 136, 136); font-family: PingFangSC-Light; font-size: 12px; margin-top: 5px;">storm分析</figcaption>
这套流式盘算服务每天处置处罚千万条数据,处置处罚得还算顺利。但方案在团队内部还是有不同声音:

  • storm的拓扑升级时间,或者优惠券服务重启的时间,偶然出现丢消息的环境。但消息的丢失,对业务来讲没有那么敏感,而且我们也提供了手工革新的功能,也在业务的容忍范围内;
  • 团队须要常常关注Redis的缓存使用量,担心Redis队列堆积, 导致out of memory;
  • 架构师认为搜索团队直接扫描数据库不敷解耦,发起将Redis集群C更换成Kafka,搜索团队从kafka直接斲丧消息,天生索引;
我认为使用Redis做消息队列应该满意如下条件:

  • 容忍小概率消息丢失,通过定时任务/手工触发到达终极划一的业务场景;
  • 消息堆积概率低,有相干的报警监控;
  • 斲丧者的斲丧模子要充足简朴。
2.2 RabbitMQ是管子不是池子

RabbitMQ是用erlang语言编写的。RabbitMQ满意了我的两点需求:

  • 高可用机制。艺龙内部是使用的镜像高可用模式,而且这种模式在艺龙已经使用了较长时间了,稳固性也得到了肯定的验证。
  • 我负责的红包体系里,RabbitMQ每天的吞吐也在百万条消息左右,消息的发送和斲丧都还挺美满。
优惠券服务原使用SqlServer,由于数据量太大,技能团队决定使用分库分表的计谋,使用公司自主研发的分布式数据库DDA。

由于是第一次使用分布式数据库,为了测试DDA的稳固性,我们模仿发送1000万条消息到RabbitMQ,然后优惠券重构服务斲丧消息后,按照用户编号hash到不同的mysql库。
RabbitMQ集群模式是镜像高可用,3台服务器,每台设置是4核8G 。
我们以每小时300万条消息的速率发送消息,最开始1个小时生产者和斲丧者体现都很好,但由于斲丧者的速率跟不上生产者的速率,导致消息队列有积存环境产生。第三个小时,消息队列已堆积了500多万条消息了, 生产者发送消息的速率由最开始的2毫秒激增到500毫秒左右。RabbitMQ的控制台已血溅就地,标红报警。
这是一次偶然中的测试,从测试的环境来看,RabbitMQ很良好,但RabbitMQ对消息堆积的支持并欠好,当大量消息积存的时间,会导致 RabbitMQ 的性能急剧降落
有的朋侪对我讲:“RabbitMQ明显是管子,你非得把他当池子?”
随着整个互联网数据量的激增, 很多业务场景下是允许适当堆积的,只要包管斲丧者可以平稳斲丧,整个业务没有大的颠簸即可。
我心田面越来越信赖:消息队列既可以做管子,也可以当做池子
3 升华MetaQ

Metamorphosis的劈头是我从对linkedin的开源MQ–如今转移到apache的kafka的学习开始的,这是一个筹划很独特的MQ体系,它接纳pull机制,而 不是一样平常MQ的push模子,它大量使用了zookeeper做服务发现和offset存储,它的筹划理念我非常欣赏并附和,猛烈发起你阅读一下它的筹划文档,总体上说metamorphosis的筹划跟它是完全划一的。--- MetaQ的作者庄晓丹
3.1 惊艳斲丧者模子

2015年,我重要从事神州专车订单研发工作。
MetaQ满意了我对于消息队列的理想:“分布式,高吞吐,高堆积”。
MetaQ支持两种斲丧模子:集群斲丧广播斲丧 ,由于从前使用过的斲丧者模子都是用队列模子,当我第一次打仗到这种发布订阅模子的时间还是被惊艳到了。
集群斲丧
9.jpg 订单创建乐成后,发送一条消息给MetaQ。这条消息可以被派单服务斲丧,也可以被BI服务斲丧。
广播斲丧
派单服务在讲订单指派给司机的时间,会给司机发送一个推送消息。推送就是用广播斲丧的模式实现的。
大体流程是:

  • 司机端推送服务是一个TCP服务,启动后,接纳的是广播模式斲丧MetaQ的PushTopic;
  • 司机端会定时发送TCP哀求到推送服务,鉴权乐成后,推送服务会生存司机编号和channel的引用;
  • 派单服务发送推送消息到MetaQ;
  • 推送服务的每一台呆板都会收到该消息,然后判断内存中是否存在该司机的channel引用,若存在,则推送消息。
这黑白常经典的广播斲丧的案例。我曾经研读京麦TCP网关的筹划,它的推送也是接纳雷同的方式。
3.2 激进的消峰

2015年是打车大战硝烟弥漫的一年。
对神州专车来讲,随着订单量的不绝增长,欣喜的同时,性能的压力与日俱增。早晚高峰期,用户打车的时间,常常点击下单常常无相应。在体系层面来看,专车api网关发现大规模超时,订单服务的性能急剧降落。数据库层面压力更大,高峰期一条记载插入竟然须要8秒的时间。
整个技能团队须要尽快提升专车体系的性能,此前已经按照模块领域做了数据库的拆分。但体系的瓶颈依然很显着。
我们筹划了如今看来有点激进的方案:

  • 筹划订单缓存。缓存方案各人要有爱好,我们可以以后再聊,内里有很多可以详聊的点;
  • 在订单的载客生命周期里,订单的修改使用先修改缓存,然后发送消息到MetaQ,订单落盘服务斲丧消息,并判断订单信息是否正常(好比有无乱序),若订单数据无误,则存储到数据库中。
11.jpg 这里有两个细节:

  • 斲丧者斲丧的时间须要次序斲丧,实现的方式是按照订单号路由到不同的partition,同一个订单号的消息,每次都发到同一个partition;[图片上传中...(image-5c6295-1668478881924-1)]
  • 一个保卫任务,定时轮询当前正在举行的订单,当缓存与数据不划一时间,修复数据,并发送报警。
这次优化大大提升订单服务的团体性能,也为厥后订单服务库分库分表以及异构打下了坚固的根本,根据我们的统计数据,根本没有发生过缓存和数据库末了不划一的场景。但这种方案对缓存高可用有较高的要求,还是有点小激进吧。
3.3 消息SDK封装

做过根本架构的同砚大概都有履历:“三方组件会封装一层”,神州架构团队也是将metaq-client封装了一层。
在我的头脑内里,封装一层可以淘汰研发职员使用第三方组件的心智投入,同一技能栈,也就云云了。
直到发生一次不测,我的头脑升级了。那是一天下战书,整个专车服务瓦解较长时间。技能团队发现:"专车使用zookeeper做服务发现。zk集群的leader呆板挂掉了,不绝在选主。"
临时办理后,我们发现MetaQ和服务发现都使用同一套zk集群,而且consumer的offset提交,以及负载平衡都会对zk集群举行大量的写使用。
为了淘汰MetaQ对zk集群的影响,我们的目的是:“MetaQ使用独立的zk集群”。

  • 须要摆设新的zk集群;
  • MetaQ的zk数据须要同步到新的集群;
  • 包管切换到新的集群,应用服务根本无感知。
我很好奇向架构部同砚讨教,他说新的集群已经摆设好了,但须要同步zk数据到新的集群。他在客户端里添加了双写的使用。也就是说:我们除了会写原有的zk集群一份数据,同时也会在新的zk集群写一份。过了几周后,MetaQ使用独立的zk集群这个任务已经完成了。
这一次的履历带给我很大的感慨:“还可以这么玩?” ,也让我思考着:三方组件封装没有想像中那么简朴。
我们可以看下快手消息的SDK封装计谋:

  • 对外只提供最根本的 API,全部访问必须颠末SDK提供的接口。轻便的 API 就像冰山的一个角,除了对外的简朴接口,下面全部的东西都可以升级更换,而不会粉碎兼容性 ;
  • 业务开发起来也很简朴,只要须要提供 Topic(全局唯一)和 Group 就可以生产和斲丧,不消提供环境、NameServer 地点等。SDK 内部会根据 Topic 剖析出集群 NameServer 的地点,然后毗连相应的集群。生产环境和测试环境环境会剖析出不同的地点,从而实现了隔离;
  • 上图分为 3 层,第二层是通用的,第三层才对应具体的 MQ 实现,因此,理论上可以更换为别的消息中心件,而客户端程序不须要修改;
  • SDK 内部集成了热变更机制,可以在不重启 Client 的环境下做动态设置,好比下发路由计谋(更换集群 NameServer 的地点,或者毗连到别的集群去),Client 的线程数、超时时间等。通过 Maven 欺压更新机制,可以包管业务使用的 SDK 根本上是最新的。
3.4 重构MetaQ , 自成体系

我有一个风俗 : "常常找运维,DBA,架构师了解当前体系是否有什么问题,以及他们办理问题的思绪。这样,我就有别的一个视角来审视公司的体系运行环境"。
MetaQ也有他的缺点。

  • MetaQ的下层通讯框架是gecko,MetaQ偶然会出现rpc无相应,应用假死的环境,不太好定位问题;
  • MetaQ的运维本事单薄,只有简朴的Dashboard界面,无法实现自动化主题申请,消息追踪等功能。
有一天,我发现测试环境的一台斲丧者服务器启动后,不绝报链接非常的问题,而且cpu占用很高。我用netstat下令立刻查一下,发现已经创建了几百个链接。出于好奇心,我打开了源码,发现网络通讯框架gecko已经被更换成了netty。我们立刻和架构部的同砚接洽。
我这才明确:他们已经开始重构MetaQ了。我从来没有想过重构一个开源软件,由于隔断我太远了。或者谁人时间,我以为自己的本事还达不到。
厥后,神州自研的消息队列自成体系了,已经在生产环境运行的挺好。
时至今天,我还是很欣赏神州架构团队。他们自研了消息队列,DataLink(数据异构中心件),分库分表中心件等。他们乐意去创新,有勇气去做一个更好的技能产物。
我从他们身上学到很多。
大概在看到他们重构MetaQ的那一刻,我的心田埋下了种子。
4 钟情RocketMQ

4.1 开源的盛宴

2014年,我搜罗了很多的淘宝的消息队列的资料,我知道MetaQ的版本已经升级MetaQ 3.0,只是开源版本还没有放出来。


约莫秋日的样子,我到场了RocketMQ技能群。誓嘉(RocketMQ首创人)在群里说:“迩来要开源了,放出来后,各人赶紧fork呀”。他的这句话发在群里之后,群里都炸开了锅。我更是高兴雀跃,等待着能早日见到阿里自己内部的消息中心件。终于,RocketMQ终于开源了。我如饥似渴想一窥他的风采。
由于我想学网络编程,而RocketMQ的通讯模块remoting底层也是Netty写的。以是,RocketMQ的通讯层是我学习切入的点。
我模仿RocketMQ的remoting写了一个玩具的rpc,这更大大进步我的自负心。恰好,艺龙举行技能创新活动。我想想,要不实验一下用Netty改写下Cobar的通讯模块。于是参考Cobar的源码花了两周写了个netty版的proxy,实在非常粗糙,很多功能不美满。厥后,这次活动颁给我一个鼓励奖,如今想想都很好玩。
由于在神州优车使用MetaQ的关系,我学习RocketMQ也比力得心应手。为了真正去明白源码,我时常会参考RocketMQ的源码,写一些轮子来验证我的学习效果。
固然自己做了一些训练,但不绝没有在业务环境使用过。2018年是我真正使用RocketMQ的一年,也是有所得的一年。
短佩服务
短佩服务应用很广泛,好比用户注册登录验证码,营销短信,下单乐成短信关照等等。最开始筹划短佩服务的时间,我想学习业界是怎么做的。于是把目的锁定在腾讯云的短佩服务上。腾讯云的短佩服务有如下特点:

  • 同一的SDK,后端入口是http/https服务 ,  分配appId/appSecret鉴权;
  • 轻便的API筹划:单发,群发,营销单发,营销群发,模板单发,模板群发。
于是,我参考了这种筹划思绪。

  • 模仿腾讯云的SDK筹划,提供简朴易用的短信接口;
  • 筹划短佩服务API端,吸收发短信哀求,发送短信信息到消息队列;
  • worker服务斲丧消息,按照负载平衡的算法,调用不同渠道商的短信接口;
  • Dashboard可以查察短信发送记载,设置渠道商信息。[图片上传中...(image-8e9d3f-1668478881924-0)]
短佩服务是我真正意义第一次生产环境使用RocketMQ,当短信一条条发出来的时间,还是蛮有成绩感的。
MQ控制台
使用过RocketMQ的朋侪,肯定对上图的控制台很熟悉。当时团队有多个RocketMQ集群,每组集群都须要单独摆设一套控制台。于是我想着:能不能轻微把控制台改造一番,能满意支持多组集群。
于是,撸起袖子干了起来。大概花了20天的时间,我们基于开源的版本改造了能支持多组集群的版本。做完之后,固然能满意我最初的想法,但是做的很粗糙。而且搜狐开源了他们自己的MQCloud ,我看了他们的筹划之后, 以为离一个消息管理平台还很远。
厥后我读了《网易云音乐的消息队列改造之路》,《本日头条在消息服务平台和容灾体系创建方面的实践与思考》这两篇文章,越是心痒难耐,蛮想去做的是一个真正意义上的消息管理平台。不绝没有什么场景和机遇,还是有点痛惜。
迩来看了哈罗单车架构专家梁勇的一篇文章《哈啰在分布式消息管理和微服务管理中的实践》,推荐各人一读。
https://mp.weixin.qq.com/s/N-vd6he4nsZp-G3Plc4m6A
一扇窗子,开始自研组件
厥后,我实验进一步深入使用RocketMQ。

  • 仿ONS风格封装消息SDK;
  • 运维侧平滑扩容消息队列;
  • 生产环境DefaultMQPullConsumer斲丧模式实验
这些做完之后,我们又自研了注册中心、设置中心,任务调度体系。筹划这些体系的时间,从RocketMQ源码里罗致了很多的营养,固然如今看来有很多筹划不美满的地方,代码质量也有待进步,但做完这些体系后,还是大大提升我的自负心。
RocketMQ给我打开了一扇窗子,让我能看到更广阔的Java天下。对我而言,这就是开源的盛宴。
4.2 Kafka: 大数据生态的不可或缺的部门

Kafka是一个拥有高吞吐、可长期化、可水平扩展,支持流式数据处置处罚等多种特性的分布式消息流处置处罚中心件,接纳分布式消息发布与订阅机制,在日记网络、流式数据传输、在线/离线体系分析、及时监控等领域有广泛的应用。
日记同步
在大型业务体系筹划中,为了快速定位问题,全链路追踪日记,以及故障及时预警监控,通常须要将各体系应用的日记会集分析处置处罚。
Kafka筹划初志就是为了应对大量日记传输场景,应用通过可靠异步方式将日记消息同步到消息服务,再通过其他组件对日记做及时或离线分析,也可用于关键日记信息网络举行应用监控。
日记同步重要有三个关键部门:日记收罗客户端,Kafka消息队列以及后端的日记处置处罚应用。

  • 日记收罗客户端,负责用户各类应用服务的日记数据收罗,以消息方式将日记“批量”“异步”发送Kafka客户端。Kafka客户端批量提交和压缩消息,对应用服务的性能影响非常小。
  • Kafka将日记存储在消息文件中,提供长期化。
  • 日记处置处罚应用,如Logstash,订阅并斲丧Kafka中的日记消息,终极供文件搜索服务检索日记,或者由Kafka将消息转达给Hadoop等其他大数据应用体系化存储与分析。
日记同步表示图:
流盘算处置处罚
在很多领域,如股市走向分析、气象数据测控、网站用户举动分析,由于数据产生快、及时性强且量大,您很难同一收罗这些数据并将其入库存储后再做处置处罚,这便导致传统的数据处置处罚架构不能满意需求。Kafka以及Storm、Samza、Spark等流盘算引擎的出现,就是为了更好地办理这类数据在处置处罚过程中遇到的问题,流盘算模子能实如今数据活动的过程中对数据举行及时地捕获和处置处罚,并根据业务需求举行盘算分析,终极把效果生存或者分发给须要的组件。
数据中转枢纽
近10多年来,诸如KV存储(HBase)、搜索(ElasticSearch)、流式处置处罚(Storm、Spark、Samza)、时序数据库(OpenTSDB)等专用体系应运而生。这些体系是为单一的目的而产生的,因其简朴性使得在贸易硬件上构建分布式体系变得更加容易且性价比更高。通常,同一份数据集须要被注入到多个专用体系内。比方,当应用日记用于离线日记分析时,搜索单个日记记载同样不可或缺,而构建各自独立的工作流来收罗每种范例的数据再导入到各自的专用体系显然不切实际,使用消息队列Kafka版作为数据中转枢纽,同份数据可以被导入到不同专用体系中。
下图是美团 MySQL 数据及时同步到 Hive 的架构图,也是一个非常经典的案例。
4.3 怎样技能选型

2018年去哪儿QMQ开源了,2019年腾讯TubeMQ开源了,2020年Pulsar如火如荼。
消息队列的生态是云云的繁荣,那我们怎样选型呢?
我想我们不必范围于消息队列,可以再扩大一下。简朴谈一谈我的看法。
Databases are specializing – the “one size fits all” approach no longer applies ----- MongoDB筹划哲学
第一点:先有场景,然后再有适配这种场景的技能。什么样的场景选择什么样的技能。
第二点:实际通常很复杂,当我们真正做技能选型,并须要落地的时间,技能储备本钱是两个我们须要重点考量的因素。
技能储备

  • 技能团队有无使用这门技能的履历,是否踩过生产环境的坑,以及针对这些坑有没有完备的办理方案;
  • 架构团队是否有成熟的SDK,工具链,乃至是技能产物。
本钱

  • 研发,测试,运维投入人力本钱;
  • 服务器资源本钱;
  • 雇用本钱等。
末了一点是的因素,特别是管理者的因素。每一次大的技能选型考验技能管理者的视野,格局,以及管理智慧。
您需要登录后才可以回帖 登录 | 立即注册

Powered by CangBaoKu v1.0 小黑屋藏宝库It社区( 冀ICP备14008649号 )

GMT+8, 2024-10-19 02:21, Processed in 0.182677 second(s), 35 queries.© 2003-2025 cbk Team.

快速回复 返回顶部 返回列表