NXP电子元件

rf链表 优化 Golang 分布式行情推送的性能瓶颈

小编 2025-01-19 NXP电子元件 23 0

优化 Golang 分布式行情推送的性能瓶颈

责编 | 张红月出品 | 码农桃花源最近一直在优化行情推送系统,有不少优化心得跟大家分享下。性能方面提升最明显的是时延,在单节点8万客户端时,时延从1500ms优化到40ms,这里是内网mock客户端的得到的压测数据。对于订阅客户端数没有太执着量级的测试,弱网络下单机8w客户端是没问题的。当前采用的是kubenetes部署方案,可灵活地扩展扩容。

架构图

push-gateway 是推送的网关,有这么几个功能:第一点是为了做鉴权;第二点是为了做接入多协议,我们这里实现了websocket, grpc, grpc-web,sse的支持;第三点是为了实现策略调度及亲和绑定等。push-server 是推送服务,这里维护了订阅关系及监听mq的新消息,继而推送到网关。

问题一:并发操作map带来的锁竞争及时延

推送的服务需要维护订阅关系,一般是用嵌套的map结构来表示,这样造成map并发竞争下带来的锁竞争和时延高的问题。

// xiaorui.cc {"topic1": {"uuid1": client1, "uuid2": client2}, "topic2": {"uuid3": client3, "uuid4": client4} ... }已经根据业务拆分了4个map,但是该订阅关系是嵌套的,直接上锁会让其他协程都阻塞,阻塞就会造成时延高。加锁操作map本应该很快,为什么会阻塞?上面我们有说过该map是用来存topic和客户端列表的订阅关系,当我进行推送时,必然是需要拿到该topic的所有客户端,然后进行一个个的send通知。(这里的send不是io.send,而是chan send,每个客户端都绑定了缓冲的chan)解决方法:在每个业务里划分256个map和读写锁,这样锁的粒度降低到1/256。除了该方法,开始有尝试过把客户端列表放到一个新的slice里返回,但造成了 GC 的压力,经过测试不可取。

// xiaorui.ccsync.RWMutexmap[string]map[string]client改成这样m *shardMap.shardMap分段map的库已经推到github[1]了,有兴趣的可以看看。

问题二:串行消息通知改成并发模式

简单说,我们在推送服务维护了某个topic和1w个客户端chan的映射,当从mq收到该topic消息后,再通知给这1w个客户端chan。客户端的chan本身是有大buffer,另外发送的函数也使用 select default 来避免阻塞。但事实上这样串行发送chan耗时不小。对于channel底层来说,需要goready等待channel的goroutine,推送到runq里。下面是我写的benchmark[2],可以对比串行和并发的耗时对比。在mac下效果不是太明显,因为mac cpu频率较高,在服务器里效果明显。串行通知,拿到所有客户端的chan,然后进行send发送。

for _, notifier := range notifiers { s.directSendMesg(notifier, mesg)}并发send,这里使用协程池来规避morestack的消耗,另外使用sync.waitgroup里实现异步下的等待。

// xiaorui.ccnotifiers := []*mapping.StreamNotifier{}// conv slicefor _, notifier := range notifierMap { notifiers = append(notifiers, notifier)}// optimize: direct map structtaskChunks := b.splitChunks(notifiers, batchChunkSize)// concurrent send chanwg := sync.WaitGroup{}for _, chunk := range taskChunks { chunkCopy := chunk // slice replica wg.Add(1) b.SubmitBlock( func() { for _, notifier := range chunkCopy { b.directSendMesg(notifier, mesg) } wg.Done() }, )}wg.Wait()按线上的监控表现来看,时延从200ms降到30ms。这里可以做一个更深入的优化,对于少于5000的客户端,可直接串行调用,反之可并发调用。

问题三:过多的定时器造成cpu开销加大

行情推送里有大量的心跳检测,及任务时间控速,这些都依赖于定时器。go在1.9之后把单个timerproc改成多个timerproc,减少了锁竞争,但四叉堆数据结构的时间复杂度依旧复杂,高精度引起的树和锁的操作也依然频繁。所以,这里改用时间轮解决上述的问题。数据结构改用简单的循环数组和map,时间的精度弱化到秒的级别,业务上对于时间差是可以接受的。Golang时间轮的代码已经推到github[3]了,时间轮很多方法都兼容了golang time原生库。有兴趣的可以看下。

问题四:多协程读写chan会出现send closed panic的问题

解决的方法很简单,就是不要直接使用channel,而是封装一个触发器,当客户端关闭时,不主动去close chan,而是关闭触发器里的ctx,然后直接删除topic跟触发器的映射。

// xiaorui.cc// 触发器的结构type StreamNotifier struct { Guid string Queue chan interface{} closed int32 ctx context.Context cancel context.CancelFunc}func (sc *StreamNotifier) IsClosed() bool { if sc.ctx.Err() == nil { return false } return true}...

问题五:提高grpc的吞吐性能

grpc是基于http2协议来实现的,http2本身实现流的多路复用。通常来说,内网的两个节点使用单连接就可以跑满网络带宽,无性能问题。但在golang里实现的grpc会有各种锁竞争的问题。如何优化?多开grpc客户端,规避锁竞争的冲突概率。测试下来qps提升很明显,从8w可以提到20w左右。可参考以前写过的grpc性能测试[4]。

问题六:减少协程数量

有朋友认为等待事件的协程多了无所谓,只是占内存,协程拿不到调度,不会对runtime性能产生消耗。这个说法是错误的。虽然拿不到调度,看起来只是占内存,但是会对 GC 有很大的开销。所以,不要开太多的空闲的协程,比如协程池开的很大。在推送的架构里,push-gateway到push-server不仅几个连接就可以,且几十个stream就可以。我们自己实现大量消息在十几个stream里跑,然后调度通知。在golang grpc streaming的实现里,每个streaming请求都需要一个协程去等待事件。所以,共享stream通道也能减少协程的数量。

问题七:GC 问题

对于频繁创建的结构体采用sync.Pool进行缓存。有些业务的缓存先前使用list链表来存储,在不断更新新数据时,会不断的创建新对象,对 GC 造成影响,所以改用可复用的循环数组来实现热缓存。

后记

有坑不怕,填上就可以了。参考资料

https://github.com/rfyiamcool/ccmap/blob/master/syncmap.go

https://github.com/rfyiamcool/go-benchmark/tree/master/batch_notify_channel

https://github.com/rfyiamcool/go-timewheel

https://github.com/rfyiamcool/grpc_batch_test

LTE230无线通信基带芯片的设计与应用

摘 要: 在分析LTE230电力无线通信系统的基础上,针对当前LTE230终端平台存在的问题,设计出一种新型的高性能、低成本、低功耗的LTE230无线通信基带芯片。文章详述了该芯片的结构及其关键技术,并结合智能电网配用电业务带宽需求的2种典型应用场景,提出了基于该芯片的终端实现方案。

0 引言

随着国家智能电网的发展,电力业务对通信信道提出了全新、更高的要求。目前智能电网中远程通信主要采用光纤和无线方式。光纤由于受成本、地域等因素的限制,难以实现对配用电通信接入网的全覆盖。无线方式作为光纤通信的有力补充手段,正承载着越来越多的电力通信业务。目前无线方式主要有无线公网和无线专网两种方式。无线公网前期投资少、建设周期短、业务部署和开展快,但随着配用电系统规模的扩大,逐渐暴露出采集成功率低、存在信息安全隐患、不同电力用户优先级无保障等问题。现有的电力无线专网如230数传电台、1 800 MHz无线宽带通信系统存在速率低、覆盖能力较弱、建网和运营成本较高、与电力业务结合能力一般等诸多问题,限制了它们在智能电网中进一步的发展和推广。新型LTE230无线通信系统充分利用低频段覆盖距离远以及4G LTE先进技术的优势,具有大容量、广覆盖、高效率、高安全性等特点,在电力无线专网领域受到越来越多的关注[1]。

1 系统分析

LTE230电力无线通信系统可直接部署在230 MHz电力专用40个授权频点上,符合国家对低频段的技术升级改造政策,当前LTE230电力无线通信专网已经在北京东城区[1]、江苏扬州[2]、浙江海盐[3]等多处开展了试点工作,为电力通信专网建设提供了良好的借鉴意义和示范作用。这些试验网的结构和图1都基本类似。在图1中,业务平台、监控中心及eOMC网管系统为LTE230系统的主站平台;EPC为核心网, eNodeB230为基站;基站和终端通过无线的方式进行数据传输,终端类型主要有四种:配电终端、负控终端、用电信息采集终端(集中器、采集器、智能电表)和视频监控终端。前三种终端承载对通信速率要求较低的小带宽业务,最后一种承载对通信速率要求较高的大带宽业务。这种小带宽与大带宽业务并存,小带宽业务为主[1]是智能电网配用电业务的一个重要特点。

当前这些LTE230试验网终端解决方案基本都是采用业界通用的CPU和DSP,外加FPGA和DDR存储器的板级方案实现的,且针对小带宽业务和大带宽业务采用不同的软硬件平台,这种终端实现方式存在成本高、功耗大、软硬件维护工作量大等问题,极大地限制了LTE230电力无线通信专网的进一步的推广和应用。因此,开发具有高性能、低成本、低功耗的LTE230无线通信基带芯片(简称LTE230芯片),并在此基础上开展芯片终端产品的应用研究,对于推进电力无线通信专网的产业化具有重要意义。

2 芯片设计

针对智能电网配用电业务大、小带宽的特点,在芯片设计须同时考虑高性能和低成本两种终端的需要。

2.1 芯片结构

芯片整体结构如图2所示,采用三级AMBA总线架构:一级为64位的高带宽AXI总线、二级为32位高性能AHB总线、三级为32位低速APB外设总线。

AXI总线是一个矩阵式结构,采用全联通模式。AXI总线上主要的模块有:DSP核、系统DMA、中频IF Enginee、Turbo Decoder硬件加速器、2组嵌入式大容量存储器eDRAM。

AHB总线的设备主要包括中断控制器DSP INTC、BootROM、SPI Flash控制器SPI_FLSCTRL,以及中频、Turbo Decoder和DMA的寄存器配置接口。

APB总线上的设备主要包括SPI_HOSTIF、射频配置接口SPI_RFCFG、以太网接口SPI_MAC、定时器Timer、串口UART、I2C控制器、看门狗WDT、GPIO模块、系统控制单元 SCU、PWM模块。APB总上的各种SPI控制器及串口都支持DMA模式。

2.2 关键技术

芯片内部集成了高性能的DSP处理器,DSP采用哈佛结构,可同时支持4 MAC操作;DSP核内嵌高速TCM和Cache,可有效平滑高速DSP内核和相对低速的eDRAM存储器之间读写操作的访问延迟,使系统整体性能较优。DSP内嵌功耗管理模块PSU(Power Scaling Unit),支持多种功耗管理模式,通过软件指令、外部中断及SCU的控制,可根据应用场景需求快速的在不同的功耗管理之间进行切换,从而满足系统待机、DRX周期、低速及全速运行等场景下的功耗和性能要求。

芯片内置高密度大容量的嵌入式存储器eDRAM,eDRAM接口时序简单,读写延迟小,无需复杂的控制器,面积只有普通SRAM的1/3;另外相比于外置DDR的存储方式,没有IO的功耗损失,BOM成本也较低,故在性能、功耗和成本上都有很好的兼顾。在芯片设计时,考虑系统内存带宽的需求,采用两组片内eDRAM的方式,芯片内的主设备如DSP,若其指令和数据分别存放在不同的eDRAM内,则可并行读取指令和数据,大大缩短了内存访问延迟,提高了系统的性能。此外eDRAM提供了正常读写、Standby、Self Refresh和power down多种功耗模式,可根据系统场景来切换。

230 MHz频段系统资源呈无规则、梳状结构,频点分布离散。芯片独有的中频模块接收来自前端射频芯片出来的数据,由于频谱的不连续性,中频模块将会进行两级混频、下采样及滤波操作,从射频接收的数据中抽取出对应频点的数据,经中频内置的DMA模块经总线送到eDRAM中,同时发送中断通知DSP来做进一步处理。上行链路和下行链路相似,但是一个相反的过程。同时中频模块采用乘法器时分复用的高阶数字滤波器,可对带外的干扰信号进行很好的抑制,以很小电路面积来保证系统的性能。由于芯片支持的TDD模式,收发不会同时进行,故中频模块可在自身收发时序控制下采用数据流驱动的时钟门控技术,动态地开关上下行数据链路的时钟,以达到减少功耗的目的。

LTE230采用和4G LTE相同的物理层信道编解码方式,其物理层下行共享信道PDSCH采用的是Turbo码,Turbo译码算法运算量很大;同时由于LTE230须支持40个离散频点,依靠DSP软译码的方式对MIPS要求太高,故芯片中内置了硬件加速器Turbo Decoder。Turbo Decoder支持链表的数据结构,可在一次配置后进行多个频点、多个码块的译码操作,其间无须DSP干预。

3 芯片应用

针对电力大、小带宽业务的特点,应用LTE230芯片,可开发两类终端产品:LTE通信模块(LTE Communication Module,简称LCM)和用户终端设备(Customer Premises Equipment,简称CPE)[1]。LCM终端强调的是低功耗、低成本、小体积,CPE终端侧重的是高性能。

LCM硬件平台如图3所示,提供UART业务物理接口,支持的频点通常为1~8个,有效数据速率一般为几十千比特每秒到一百多千比特每秒,可满足窄带数传、远程控制通信等低速率的无线通信需求。

CPE硬件平台如图4所示,配备UART、10/100 M自适应以太网等业务物理接口,最大支持40个频点,上、下等峰值速率分别为1.76 Mb/s和0.71 Mb/s,主要用于承载视频监控等高速数据传输。

实际应用中,90%以上的终端数量是LCM,成本和功耗是一个重要的考虑因素,在硬件实现时尽量简单,采用LTE230芯片+射频RF芯片的方案。LTE230芯片的一个串口用于调试,另一个串口用来和电力终端进行数据交换。操作系统和基带处理软件在系统启动时通过BootCode从片外SPI Flash存储器加载到芯片内部的TCM和eDRAM存储器中。LTE230 的DSP运行实时操作系统Nucleus,且其基带处理除物理层(PHY)时域部分 (含载波聚合)是用中频模块硬件电路实现的,其余的物理层的频域处理和比特级/符号级处理、协议层的媒体访问控制(MAC)和无线资源控制(RRC)[4]、网络层的TCP/IP协议、射频前端收发配置以及芯片内外大量设备的管理都是用DSP软件来实现。

在高性能的CPE平台中,支持的数据速率高,单DSP方案无法提高足够的处理能力,故在LCM平台的基础上,外加一个高性能低功耗的基于ARM Cortex M3的 MCU(考虑到市场上MCU的成熟度及内嵌Flash工艺的特殊性,芯片未集成MCU)。LTE230芯片专注于基带物理层的处理,协议层和网络层的处理由MCU来完成。MCU和DSP运行相同实时操作系统,通过SPI控制器交换物理层传输信道(Transport Channels)[4]的数据。MCU内嵌大容量Flash存储器,可用来存储MCU及DSP的整个软件系统,无需外接SPI Flash存储器。在系统初始化时,MCU可在DSP的BootCode配合下,通过SPI接口将DSP所需软件下载到LTE230芯片的TCM和eDRAM存储器中。

4 结论

基于LTE230无线通信基带芯片的LCM和CPE的软硬件平台已进行了初步的原型验证,结果表明,在成本、功耗、软硬系统维护及升级便利性等方面,相比于现有的基于“ADI DSP+FPGA+DDR”的LCM终端平台和基于“TI OMAP处理器+FPGA+DDR”的CPE终端平台,有着明显的优势,这对加速智能电网中LTE230电力无线通信系统的建设有着重要的参考意义。

参考文献

[1] 李金友,闫磊,齐欢,等.基于LTE230系统的电力无线通信专网研究与实践[J].电气技术,2014(1):132-134.

[2] 蔡斌,李雪平,祝峰.LTE230无线宽带通信网络在扬州配网自动化中的研究与应用[J].中国无线电,2013(11):38-41.

[3] 吴文绍.TD-LTE230无线宽带系统在县电力公司中的应用[J].电力信息化,2012,10(11):58-62.

[4] 3GPP TS36.201 Evolved Universal Terrestrial Radio Access(E-UTRA);LTE Physical Layer-General Description[S].2009.

相关问答

在座的好基友 哪位了解,德州挺不错的地插式微喷头,地插式...

[回答]你问我哪家公司做做的比较好,不得不说,是一个非常不错的选择,具有15年专注经验。鑫迪龙灌溉坚持对产品负责、让用户满意,诚信为本,创新是魂'的企业...

猜你喜欢