• [优秀实践] swap分区过小导致系统异常案例总结
    1. 问题现象在某数据库测试的时候发现执行linux基础命令报错:-bash: fork: Cannot allocate memory重启后,问题不再出现。与此同时,客户也反馈测试过程中会经常出现数据库进程少了的现象。 2. 问题分析网上碰到的问题都是说是由于进程数满了,这个可能性不大,因为系统的进程最大数已经设置成32768了,已经很大了。由于出现问题后,无法执行命令查看系统状态。首先想到的办法是查看message日志。通过BMC登录后,收集到message日志查看后发现有crash的现象:从日志上可以看出,系统内存不够用了,所以kill了数据库进程,这也能够解释得了客户发现的数据库进程变少的现象了。从这个日志往上看,发现了另外一个关键信息:可以看出swap空间已经被用光了,出发了OOM,导致了系统出现了异常。对比这次测试跟之前的测试,数据库使用的内存大小都是一样的,发现这次开辟的SWAP空间较小。之前的SWAP分区有150G,而这次才开了4G,在内存紧张的情况下,很容易就出现了OOM。3. 解决方法由于客户不愿意修改数据库内存,认为当前的数据库内存配置是最优的,所以我们动态调整了SWAP分区大小。创建空文件# dd if=/dev/zero of=/home/swap bs=1G count=200挂载到swap空间mkswap /home/swap加载swap空间/sbin/swapon /home/swap以上命令重启后会失效,如果想让修改永久生效则需要修改配置:设置开机自动挂载,修改/etc/fstab/home/swap                       swap                    swap    defaults        0 0 按照这个方式修改后,再也没有出现过此问题了。
  • [优秀实践] 裸盘IO优化案例分享
    1 问题背景同一型号SSD裸盘性能测试,4k随机读写测试(单jobs、iodepth为32),TaiShan200服务器性能不符合预期,需要进行调优。 2 原因分析执行测试命令,分析TaiShan系统表现,发现fio线程cpu占用较低,对fio进程绑核后性能表现等没有变化;将fio测试进程增加到4个,使用4个cpu测试,iops提升很小,cpu占用率更低,说明cpu没到瓶颈。iostat分析,TaiShan的await保持在58,也就是IO请求从下发到完成的耗时较长,由于是裸盘测试不经过文件系统,所以可能与cpu的超频、驱动实现有关。分析热点函数,发现TaiShan的tick_nohz_idle_enter,tick_nohz_idle_exit两个函数cpu占用较高,尝试给系统启动命令加上nohz=off,加上后此两个热点函数消失,但是性能只有小幅提升。在iBMC排查raid配置,发现TaiShan的测试盘一个盘自己组了raid0,为排除影响将磁盘raid模式调整为jbod直通模式,性能没有提升。测试前erase硬盘除去脏数据可能导致的不同程度写放大影响,性能还是没有提升。更换TaiShan测试盘,排除硬件本身差异,性能没有提升。TaiShan使用华为高性能SAS SSD盘测试,4k随机读写iops比当前使用的测试盘高几倍,cpu占用很高,确认主要瓶颈不在cpu。Blktrace工具分析IO请求具体的耗时占比,发现D2C占比高达99%,确认耗时主要在驱动和硬件。D2C表示IO请求被driver提交给硬件,经过HBA、电缆(光纤、网线等)、交换机(SAN或网络)、最后到达存储设备,设备完成IO请求之后再把结果发回这段路径的耗时。lsscsi发现TaiShan服务器有expander芯片。通过raid卡管理工具确认,测试盘接在expander背板,expander背板与raid卡相接,也就是IO请求先下发到raid卡,raid卡发送到expander芯片,expander芯片再发送到硬盘,理论上expander芯片会带来性能损耗。家里实验室验证硬盘背板带expander芯片和不带expander芯片场景下4k随机读写性能,的确有较大差距。3 解决方案调整TaiShan硬盘方面硬件配置,选用不带expander芯片的硬盘背板型号。4 总结裸盘IO由于不经过文件系统,io路径短,如果硬盘性能低不能使cpu达到瓶颈,则在其他硬件配置一致的情况下不同cpu测试性能是持平的;如果硬盘属于高性能硬盘,cpu占用极高,则需通过添加测试进程数,增加使用的cpu个数以达到硬盘瓶颈。需要注意的是,裸盘测试需要确保对比机器的硬盘接入方式是相同的,比如都是cpu直出、都是raid卡直通、都接在expander硬盘背板上;确保raid配置是相同的,比如都是raid1或者都是jbod模式
  • [优秀实践] 虚拟化场景IO性能优化案例分享
    1 问题背景虚拟机(8C16G)裸盘(预分配80G)fio 4k随机写测试(4jobs,iodepth为32)TaiShan 200服务器性能不符合预期,需要进行调优。 2 原因分析执行测试命令,观察TaiShan服务器表现:物理机上,发现kvm进程cpu占用较高,进一步分析发现TaiShan上kvm线程200+;虚拟机上,TaiShan cpu0占用率很高,其中软中断占比高的不合理。怀疑是虚拟机实现方式的问题,发现TaiShan虚拟机测试磁盘类型为virtio-scsi-device(可以使用virtio-block-device,block设备比scsi设备IO路径稍微短些),且当前测试使用的qemu版本较低,可能还不支持armv8新特性。修改TaiShan虚拟机启动参数,将测试盘类型调整为virtio-block-device,性能有小幅提升,物理机上kvm线程数从200+降低到80以内,虚拟机上cpu0的软中断也较低到合理范围,但系统占用又变得很高,说明kvm线程和软中断高是磁盘类型导致,此时是cpu瓶颈。无法给TaiShan虚拟机指定cpu asimd特性,显示参数错误。将虚拟机vcpu一对一绑核,关闭irqbalance,给fio测试程序绑核,几乎没有性能提升。开启大页内存,没有性能提升。分析fio系统调用,发现clock_gettime系统调用耗时有时达到2ms,耗时很高,此客户机操作系统为3,更换为centos7.7,fio系统调用看不到clock_gettime函数,但是性能没有提升。使用原生0.0版本测试,性能有一定提升;进一步重新编译qemu,加上对native aio的支持,性能提升较大。此时,虚拟机上仍然是cpu0 占用特别高,物理机上观测一个vcpu线程cpu占用特别高,qemu主线程cpu占用不高。尝试给磁盘配置iothread卸载qemu主线程压力、对磁盘添加write-cache=on和ioeventfd =on等属性、排查TaiShan物理机上对应SSD的性能表现,没有性能提升。将物理机上SSD的调度策略由默认的cfq调整为noop,性能有一定提升。使用7开始对virtio-blk支持的新特性multiqueues磁盘多队列,性能有较大提升,虚拟机上单个cpu占用特别高的问题解决了。进一步优化,将TaiShan iommu模式配置为passthrough,性能有进一步提升。3 解决方案使用新版qemu如0.0或更高版本,guest os版本也尽量高点使用virtio-blk磁盘多队列特性虚拟机异步io模式配置为native若虚拟化场景无需使用磁盘、网卡直通或SRIOV特性,则可关闭SMMU。4 总结虚拟化场景IO测试,IO路径较长,且不同类型磁盘IO路径也不同。首先需要确认磁盘bus类型(scsi、ide、virtio),保证使用的磁盘文件的协议(nfs、iscsi、本地挂载)是一致的,保证磁盘文件在对应物理机上创建的规则是一样的(预分配、缓存特性等)。如果判断是单核瓶颈,可以尝试使用磁盘多队列特性(针对virtio-blk设备,对qemu、geust操作系统版本有要求);如果是qemu主线程占用高,可以考虑开启iothread分担压力(可能影响动态迁移特性,需调研);设置磁盘异步调用为native会有性能提升,不过也有一定的使用限制(不能用于sparse images,否则在文件系统元数据需要更新时会导致qemu threads阻塞),需了解使用需求。实际测试中,瓶颈分析需要结合虚拟机和物理机两者的系统表现,因为虚拟机的cpu、io等占用信息不一定是真实的(存在vcpu等kvm线程本身被调度和阻塞的问题等)。
  • [技术干货] web场景-Varnish调优
    1.1 Varnish简介Varnish是一款高性能的反向代理缓存服务器,通过缓存静态资源,在基于Web的业务场景可提升站点10+倍的性能,目前仍是CDN(Content Delivery Network)的一个重要实现方案。1.2 Varnish物理机调优1.2.1 Varnish配置参数调优目的:通过调优Varnish的配置文件,可以有效的提高服务器的性能。方法:配置varnish的配置文件/usr/local/varnish/config/default.vcl中的default,vcl_recv,vcl_backend_response,vcl_pipe,vcl_pass,vcl_hash,vcl_hit,vcl_miss,vcl_deliver模块。配置项说明default配置通信IP及端口vcl_recv用于接收和处理请求;当请求到达varnish,通过判断请求的数据来决定如何处理请求vcl_backend_response获得后端主机的响应后调用vcl_pipe用于将请求直接传递至后端主机,并将后端响应原封不动返回给客户端vcl_pass用于将请求直接传递给后端主机,但后端主机的响应并不缓存,而是直接返回给客户端vcl_hash在vcl_recv调用后为请求创建一个hash值时,调用。此hash值将作为varnish中hash表的keyvcl_hit在缓存中找到请求的内容后自动调用vcl_miss在缓存中没有找到请求的内容后自动调用。用于判断是否需要从后端服务器获取内容vcl_deliver将在缓存中找到的请求的内容发送给客户端前调用1.2.2 Varnish亲和性配置目的:对varnish进程进行绑核并启动。方法:以物理机1P场景为例,使用numactl设置CPU与内存的亲和性。numactl -C 0-2,4-10,12-18,20-26,28-34,36-42,44-47 --membind=0,1 /usr/local/varnish/sbin/varnishd -P /tmp/varnish.pid -a :12345 -T 127.0.0.1:6082 -s malloc,100GB -f /usr/local/varnish/config/default.vcl -t 600 -p thread_pool_max=5000 -p thread_pools=10 -p thread_pool_destroy_delay=3 -p timeout_idle=75 -p thread_pool_min=700参数名称参数说明-C进程绑定的CPU core--membind分配进程的内存,其中0,1表示分配的内存在node0和node1上-PVarnish进程pid文件存放路径-a表示Varnish对httpd的监听地址及端口-T设定 varnish 的 telnet 管理地址及其端口-s指定 varnish 缓存存放的方式,常用的方式有:“-s file,<dir_or_file>,<size>”。-f指定 varnish 的配置文件位置-t指定默认的TTL值-p thread_pool_max每个线程池创建的最大线程数-p thread_pools设置线程池个数-p thread_pool_destroy_delay摧毁线程的延迟时间,也就是摧毁之前需要犹豫一下,这个犹豫的时间-p timeout_idle设置保持链接的空闲时长-p thread_pool_min每个线程池创建的最小线程数 
  • [技术干货] web场景-squid调优
    1.1 Squid简介Squid是一个高性能的代理缓存服务器,通过缓存和重用经常请求的网页,减少了带宽并缩短了响应时间。1.2 Squid物理机调优1.2.1 Squid亲和性调优目的:通过调优Squid的配置文件,可以有效的提高服务器的性能。方法:对squid进程进行绑核并启动。在/usr/local/squid/etc/squid.conf中配置cpu_affinity_map参数:workers 43cpu_affinity_mapprocess_numbers=1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38, 39,40,41,42,43,44,45,46,47,48cores=1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37, 38,39,40,41,42,43,44,45,46,47,48Squid启动参数说明参数说明Workers启动的进程数cpu_affinity_map process_numbers进程与CPU的对应关系,如上配置,表示squid的启动的1-48个进程分别对应着1-48号CPU步骤2   一路CPU上启动一个Squid实例。             /usr/local/squid/sbin/squid -s                如需启动两个Squid实例,需新建配置文件squid_2.conf,执行如下命令启动第二个实例:        /usr/local/squid/sbin/squid -f /usr/local/squid/etc/squid_2.conf
  • [技术干货] 异步编程
    什么时候用异步编程在前端编程中(甚至后端有时也是这样),我们在处理一些简短、快速的操作时,例如计算 1 + 1 的结果,往往在主线程中就可以完成。主线程作为一个线程,不能够同时接受多方面的请求。所以,当一个事件没有结束时,界面将无法处理其他请求。现在有一个按钮,如果我们设置它的 onclick 事件为一个死循环,那么当这个按钮按下,整个网页将失去响应。为了避免这种情况的发生,我们常常用子线程来完成一些可能消耗时间足够长以至于被用户察觉的事情,比如读取一个大文件或者发出一个网络请求。因为子线程独立于主线程,所以即使出现阻塞也不会影响主线程的运行。但是子线程有一个局限:一旦发射了以后就会与主线程失去同步,我们无法确定它的结束,如果结束之后需要处理一些事情,比如处理来自服务器的信息,我们是无法将它合并到主线程中去的。为了解决这个问题,JavaScript 中的异步操作函数往往通过回调函数来实现异步任务的结果处理。回调函数回调函数就是一个函数,它是在我们启动一个异步任务的时候就告诉它:等你完成了这个任务之后要干什么。这样一来主线程几乎不用关心异步任务的状态了,他自己会善始善终。实例function print() {    document.getElementById("demo").innerHTML="RUNOOB!";}setTimeout(print, 3000);尝试一下 »这段程序中的 setTimeout 就是一个消耗时间较长(3 秒)的过程,它的第一个参数是个回调函数,第二个参数是毫秒数,这个函数执行之后会产生一个子线程,子线程会等待 3 秒,然后执行回调函数 "print",在命令行输出 "RUNOOB!"。当然,JavaScript 语法十分友好,我们不必单独定义一个函数 print ,我们常常将上面的程序写成:实例setTimeout(function () {    document.getElementById("demo").innerHTML="RUNOOB!";}, 3000);尝试一下 »注意:既然 setTimeout 会在子线程中等待 3 秒,在 setTimeout 函数执行之后主线程并没有停止,所以:实例setTimeout(function () {    document.getElementById("demo1").innerHTML="RUNOOB-1!";}, 3000);document.getElementById("demo2").innerHTML="RUNOOB-2!";console.log("2");尝试一下 »这段程序的执行结果是:RUNOOB-1!RUNOOB-2!异步 AJAX除了 setTimeout 函数以外,异步回调广泛应用于 AJAX 编程。有关于 AJAX 详细请参见:https://www.runoob.com/ajax/ajax-tutorial.htmlXMLHttpRequest 常常用于请求来自远程服务器上的 XML 或 JSON 数据。一个标准的 XMLHttpRequest 对象往往包含多个回调:实例var xhr = new XMLHttpRequest(); xhr.onload = function () {    // 输出接收到的文字数据    document.getElementById("demo").innerHTML=xhr.responseText;} xhr.onerror = function () {    document.getElementById("demo").innerHTML="请求出错";} // 发送异步 GET 请求xhr.open("GET", "https://www.runoob.com/try/ajax/ajax_info.txt", true);xhr.send();尝试一下 »XMLHttpRequest 的 onload 和 onerror 属性都是函数,分别在它请求成功和请求失败时被调用。如果你使用完整的 jQuery 库,也可以更加优雅的使用异步 AJAX:实例$.get("https://www.runoob.com/try/ajax/demo_test.php",function(data,status){    alert("数据: " + data + "\n状态: " + status);});尝试一下 »
  • [运维管理] 巡检后发现dentry内存的告警需要怎么排查时那个进程导致的?
    【操作步骤&问题现象】执行slabtop -o 2>/dev/null | grep "dentry" | awk '{print $(NF-1)}'命令,检查Dentry内存超过10GB(排查频繁操作大量文件的进程,找出问题根因,解决dentry占用内存问题),怎么排查是那个进程导致的?
  • [技术干货] CCUCS问题之poll轮询获取消息数量不正确
    问题描述:某局点在测试客户侧连接上在线坐席,坐席侧发送消息后(经确认都发送成功),客户侧通过poll轮询接口只能获取到部分消息内容。           1.客户侧与坐席侧通过connect接口成功连接,客户开启poll接口轮询。频率为每次请求成功后间隔1秒再次调用。           2.坐席侧连续发送多条消息(测试时以文本消息为主),客户侧多次出现丢消息的情况。(坐席侧发送六七条文本消息,客户侧只能接收到两三条)           3.成功接入之后的几秒内发送的第一条消息丢消息概率较高;连续发送消息中间的消息丢失概率较高。           4.检查ccucs日志时发现轮询接口经常出现org.springframework.web.context.request.async.AsyncRequestTimeoutException: null这类异常报错           5.尝试调整调用接口的超时时长,原设定1000ms,曾调整至3000ms,效果不太明显。且对客户侧界面端会有卡顿影响,最终调回。           6.poll调用返回时也常出现短时间内返回同一个结果串(场景:坐席发送一条消息后,紧接着又发送一条,poll接口一直返回第一条消息的内容。坐席测发送第三条消息时,poll接口直接返回第三天条消息的内容,偶发出现第三条也不推送。直接返回空)  问题分析:1.坐席侧发送的消息可以看一下icd库中的tSocialMessage表,发了几条消息就应该有几条记录,确认已经发送了消息               2.确认poll轮询是使用单线程在跑,使用多线程去轮询获取事件会存在事件被其他线程获取走了的情况,导致消息接收不完全。
  • [其他] Dms agent进程在长时间运行(4-5个月后)占用内存过多,导致内核无法分配内存,进程异常
    【问题现象】         Dms agent进程在长时间运行(4-5个月后)占用内存过多,导致内核无法分配内存,进程异常。【问题版本】         所有使用DMS,内核版本为810 、811的版本都涉及。         包含:HCS 8.0.2版本,HCS 8.0.3版本,HCSO 0130,0430,0730。【问题根因】  进程缓存信息占用【恢复方案】Kill  agent_service.py对应的的进程。
  • [技术干货] [2.1x设计器]请检查57889端口是否被占用类问题解决方法。
    在某些电脑安装完设计器后,去拾取网页元素或者点击录制器,在设计器右上角有如下提示,有时重启电脑也解决不了这个问题。原因分析: 这机器使用的这个端口被其本地的其他程序占用了,导致studio就用不了这个接口了。解决方法:法一、简单快速的方法是本地电脑新建一个用户,环境是干净的,使端口都是空闲的。法二、使用cmd命令查找到相应的程序并做杀进程使端口空闲先来。1、退出WeAutomate设计器2、打开一个cmd窗口,并输入netstat -ano | findstr 578893、根据查询出来的PID(上图红框所示),查询进程,可以看到是哪个程序,这个可以略过tasklist|findstr 53764、使用taskkill杀掉进程,注意替换查询到的PID号码taskkill /pid 5376 -t -f基本既可以解决“请检查57889端口是否被占用类问题”如有解决不了的情况请大家留言。
  • [交流吐槽] nginx配置文件
    RPCRPC和RESTful都是远程调用接口,那么它们之间到底有什么区别的呢?我以前一直傻傻分不清楚,直到我看了周志明老师写的《凤凰架构:构建可靠的大型分布式系统》我才理清了它们之间的区别,怕自己忘了,特意做下笔记。RPC(Remote Procedure Call,RPC),即远程过程调用,最近几年频繁被各种论坛,文章,课程提及,乍一看还以为是什么牛逼的新技术,其实在计算机科学中已经存在超过四十年时间,是个不折不扣的“老古董”。RPC出现的最初目的,就是为了让计算机能够与调用本地方法一样去调用远程方法。我们先来看一下计算机是如何调用本地方的,我抄录了书中的例子:// Caller : 调用者,代码里的main()// Callee : 被调用者,代码里的println()// Call Site : 调用点,即发生方法调用的指令流位置// Parameter : 参数,由Caller传递给Callee的数据,即“hello world”// Retval : 返回值,由Callee传递给Caller的数据,如果方法能够正常结束,它是void,如果方法异常完成,它是对应的异常public static void main(String[] args) {    System.out.println("hello world");}123在完全不考虑编译器优化的前提下,程序运行至调用println()方法输出hello world这行时,计算机(物理机或者虚拟机)要完成以下几项工作。传递方法参数:将字符串hello world的引用地址压栈。确定方法版本:根据println()方法的签名,确定其执行版本。这其实并不是一个简单的过程,无论是编译时静态解析,还是运行时动态分派,都必须根据某些语言规范中明确定义的原则,找到明确的Callee,“明确”是指唯一的一个Callee,或者有严格优先级的多个Callee,譬如不同的重载版本。执行被调方法:从栈中弹出Parameter的值或引用,并以此为输入,执行Callee内部的逻辑。这里我们只关心方法是如何调用的,而不关心方法内部具体是如何执行的。返回执行结果:将Callee的执行结果压栈,并将程序的指令流恢复到Call Site的下一条指令,继续向下执行。我们再来考虑如果println()方法不在当前进程的内存地址空间中会发生什么问题。不难想到,这样会至少面临两个直接的障碍。首先,第一步和第四步所做的传递参数、传回结果都依赖于栈内存,如果Caller与Callee分属不同的进程,就不会拥有相同的栈内存,此时将参数在Caller进程的内存中压栈,对于Callee进程的执行毫无意义。其次,第二步的方法版本选择依赖于语言规则,如果Caller与Callee不是同一种语言实现的程序,方法版本选择就将是一项模糊的不可知行为。我们暂时忽略第二个问题,假设Caller和Callee是使用同一种语言实现的。那么两个进程之间该如何交换数据呢?这就是“进程间通信”(Inter-Process Communication,IPC)要解决的问题。进程间通信几种解决方案:管道(Pipe)或者具名管道(Named Pipe)管道类似于两个进程间的桥梁,可通过管道在进程间传递少量的字符流或字节流。普通管道只用于有亲缘关系的进程(由一个进程启动的另外一个进程)间的通信,具名管道摆脱了普通管道没有名字的限制,除具有管道的所有功能外,它还允许无亲缘关系的进程间的通信。管道典型的应用就是命令行中的“|”操作符,譬如:ps -ef | grep javaps与grep都有独立的进程,以上命令就是通过管道操作符“|”将ps命令的标准输出连接到grep命令的标准输入上。信号(Signal)信号用于通知目标进程有某种事件发生。除了进程间通信外,进程还可以给进程自身发送信号。信号的典型应用是kill命令,譬如:kill -9 pid以上命令即表示由Shell进程向指定PID的进程发送SIGKILL信号。信号量(Semaphore)信号量用于在两个进程之间同步协作手段,它相当于操作系统提供的一个特殊变量,程序可以在上面进行wait()和notify()操作。消息队列(Message Queue)以上三种方式只适合传递少量消息,POSIX标准中定义了可用于进程间数据量较多的通信的消息队列。进程可以向队列添加消息,被赋予读权限的进程还可以从队列消费消息。消息队列克服了信号承载信息量少、管道只能用于无格式字节流以及缓冲区大小受限等缺点,但实时性相对受限。共享内存(Shared Memory)允许多个进程访问同一块公共内存空间,这是效率最高的进程间通信形式。原本每个进程的内存地址空间都是相互隔离的,但操作系统提供了让进程主动创建、映射、分离、控制某一块内存的程序接口。当一块内存被多进程共享时,各个进程往往会与其他通信机制,譬如与信号量结合使用,来达到进程间同步及互斥的协调操作。本地套接字接口(IPC Socket)消息队列与共享内存只适合单机多进程间的通信,套接字接口则是更普适的进程间通信机制,可用于不同机器之间的进程通信。套接字(Socket)起初是由UNIX系统的BSD分支开发出来的,现在已经移植到所有主流的操作系统上。出于效率考虑,当仅限于本机进程间通信时,套接字接口是被优化过的,不会经过网络协议栈,不需要打包拆包、计算校验和、维护序号和应答等操作,只是简单地将应用层数据从一个进程复制到另一个进程,这种进程间通信方式即本地套接字接口(UNIX Domain Socket),又叫作IPC Socket。RPC要解决的三个问题如何表示数据这里的数据包括传递给方法的参数和方法执行之后的返回值。也就是说一个进程把参数传给另一个进程,或者从另一个进程获取返回值,数据格式怎么表示的问题。你可能会觉得很奇怪,比如用Java语言写的程序,传递String,int等类型不就行了吗?对于进程内的方法调用,使用同一种语言的数据类型,比如双方的程序都用Java语言写的,这样调用自然没有问题。但是,如果调用方是用Java语言写的,被调用方是C语言写的,他们的数据类型定义的都不一样,该如何兼容呢?就算双方都用同一种语言写的,比如C语言,但是在不同的硬件指令集、不同的操作系统下,同样的数据类型也完全可能有不一样的表现细节,譬如数据宽度、字节序列的差异等等。那该怎么办呢?说来也简单,就是先把双方要交流的数据先转化成大家都认识的中间格式,然后再将中间格式数据转化成自己所用语言的数据类型,听起来是不是很熟悉?没错,这就是序列化与反序列化。我以前学Java的时候,学到序列化与反序列化就很纳闷?参数为什么要序列化呢?直接传不就行了吗?原来是要考虑不同语言、硬件、操作系统的情况。每种RPC协议都有对应的序列化协议,例如:ONC RPC的外部数据表示(External Data Representation,XDR)CORBA的通用数据表示(Common Data Representation,CDR)Java RMI的Java对象序列化流协议(Java Object Serialization Stream Protocol)gRPC的Protocol BuffersWeb Service的XML序列化众多轻量级RPC支持的JSON序列化看到Web Service的XML序列化特别有感触,以前在用Web Service的时候,我很奇怪为什么要用xml费这么大劲去描述一个个字段,一个个参数,原来是为了让不同的语言都能识别。如何传递数据两个程序之间如何传递数据,也就是互相操作,交互数据,除了序列化与反序列化之外还需要考虑:异常、超时、安全、认证、授权、事务等等,都可能产生双方需要交换信息的需求。在计算机科学中,专门有一个名词“Wire Protocol”来表示这种两个Endpoint之间交换这类数据的行为,常见的Wire Protocol如下:Java RMI的Java远程消息交换协议(Java Remote Message Protocol,JRMP,也支持RMI-IIOP)CORBA的互联网ORB间协议(Internet Inter ORB Protocol,IIOP,是GIOP协议在IP协议上的实现版本)DDS的实时发布订阅协议(Real Time Publish Subscribe Protocol,RTPS)Web Service的简单对象访问协议(Simple Object Access Protocol,SOAP)如果要求足够简单,双方都是HTTP Endpoint,直接使用HTTP协议也是可以的(如JSON-RPC)除了传递数据,RPC 还有更吸引人的地方,它真正强大的地方是它的治理功能,比如连接管理、健康检测、负载均衡、优雅启停机、异常重试、业务分组以及熔断限流等等。如何表示方法确定表示方法在本地方法调用中并不是太大的问题,编译器或者解释器会根据语言规范,将调用的方法签名转换为进程空间中子过程入口位置的指针。不过一旦要考虑不同语言,事情又立刻麻烦起来,每种语言的方法签名都可能有差别,所以“如何表示同一个方法”“如何找到对应的方法”还是需要一个统一的跨语言的标准才行。这个标准可以非常简单,譬如直接给程序的每个方法都规定一个唯一的、在任何机器上都绝不重复的编号,调用时压根不管它是什么方法、签名是如何定义的,直接传这个编号就能找到对应的方法。这种听起既粗鲁又寒碜的办法,还真的就是DCE/RPC当初准备的解决方案。虽然最终DCE还是弄出了一套与语言无关的接口描述语言(Interface Description Language,IDL),成为此后许多RPC参考或依赖的基础(如CORBA的OMG IDL),但那个唯一的绝不重复的编码方案UUID(Universally Unique Identifier)也被保留且广为流传开来,并被广泛应用于程序开发的方方面面。类似地,用于表示方法的协议还有:Android的Android接口定义语言(Android Interface Definition Language,AIDL)CORBA的OMG接口定义语言(OMG Interface Definition Language,OMG IDL)Web Service的Web服务描述语言(Web Service Description Language,WSDL)JSON-RPC的JSON Web服务协议(JSON Web Service Protocol,JSON-WSP)以上RPC中的三个基本问题,全部都可以在本地方法调用过程中找到对应的解决方案。RPC的设计始于本地方法调用,尽管早已不再追求实现与本地方法调用完全一致的目的,但其设计思路仍然带有本地方法调用的深刻烙印,抓住两者间的联系来类比,对我们更深刻地理解RPC的本质会很有帮助。为了解决上面的三个问题,每个RPC的产品解决问题的角度不同,有的着重于简单性,有的希望能支持更多的语言达到普适性,有的看中高性能。现在,已经相继出现过RMI(Sun/Oracle)、Thrift(Facebook/Apache)、Dubbo(阿里巴巴/Apache)、gRPC(Google)、Motan1/2(新浪)、Finagle(Twitter)、brpc(百度/Apache)、.NET Remoting(微软)、Arvo(Hadoop)、JSON-RPC 2.0(公开规范,JSON-RPC工作组)等难以穷举的协议和框架。这些RPC功能、特点不尽相同,有的是某种语言私有,有的支持跨越多种语言,有的运行在应用层HTTP协议之上,有的直接运行于传输层TCP/UDP协议之上,但并不存在哪一款是“最完美的RPC”。今时今日,任何一款具有生命力的RPC框架,都不再去追求大而全的“完美”,而是以某个具有针对性的特点作为主要的发展方向。同时这也导致了我们的选择困难症,更是催生出了一大堆网络文章和课程,来讲解各RPC的优缺点,什么时候能有一个RPC的王者出来统一天下呢?RESTREST源于Roy Thomas Fielding在2000年发表的博士论文“Architectural Styles and the Design of Network-based Software Architectures”,此文的确是REST的源头。REST(Representational State Transfer,表征状态转移),这个名字听起来很晦涩,什么叫“表征”、什么东西的“状态”、从哪“转移”到哪?我们要理解REST就要先理解什么是HTTP,再配合一些实际例子来对两者进行类比,以更清楚地了解REST,你会发现REST实际上是“HTT”(Hypertext Transfer)的进一步抽象,两者的关系就如同接口与实现类的关系一般。超文本(或超媒体)“超文本(或超媒体)”是一种“能够对操作进行判断和响应的文本(或声音、图像等)”,这个概念在20世纪60年代提出时应该还属于科幻的范畴,但是今天大众已经完全接受了它,互联网中一段文字可以点击、可以触发脚本执行、可以调用服务端已毫不稀奇。下面我们继续尝试从“超文本”或者“超媒体”的含义来理解什么是“表征”以及REST中的其他关键概念,这里使用一个具体事例将其描述如下:资源(Resource)譬如你现在正在阅读一篇名为《REST设计风格》的文章,这篇文章的内容本身(你可以将其理解为蕴含的信息、数据)称之为“资源”。无论你是通过阅读购买的图书、浏览器上的网页还是打印出来的文稿,无论是在电脑屏幕上阅读还是在手机上阅读,尽管呈现的样子各不相同,但其中的信息是不变的,你所阅读的仍是同一份“资源”。表征(Representation)当你通过浏览器阅读此文章时,浏览器会向服务端发出“我需要这个资源的HTML格式”的请求,服务端向浏览器返回的这个HTML就被称为“表征”,你也可以通过其他方式拿到本文的PDF、Markdown、RSS等其他形式的版本,它们同样是一个资源的多种表征。可见“表征”是指信息与用户交互时的表示形式,这与我们软件分层架构中常说的“表示层”(Presentation Layer)的语义其实是一致的。状态(State)当你读完了这篇文章,想看后面是什么内容时,你向服务端发出“给我下一篇文章”的请求。但是“下一篇”是个相对概念,必须依赖“当前你正在阅读的文章是哪一篇”才能正确回应,这类在特定语境中才能产生的上下文信息被称为“状态”。我们所说的有状态(Stateful)抑或是无状态(Stateless),都是只相对于服务端来说的,服务端要完成“取下一篇”的请求,要么自己记住用户的状态,如这个用户现在阅读的是哪一篇文章,这称为有状态;要么由客户端来记住状态,在请求的时候明确告诉服务端,如我正在阅读某某文章,现在要读它的下一篇,这称为无状态。也就是说,由服务端来记录用户的状态就叫有状态;由客户端记录状态,并把它传到服务端的叫做无状态。转移(Transfer)无论状态是由服务端还是由客户端来提供,“取下一篇文章”这个行为逻辑只能由服务端来提供,因为只有服务端拥有该资源及其表征形式。服务端通过某种方式,把“用户当前阅读的文章”转变成“下一篇文章”,这就被称为“表征状态转移”。REST的一条核心原则是“统一接口(Uniform Interface)”,REST希望开发者面向资源编程,希望软件系统设计的重点放在抽象系统该有哪些资源,而不是抽象系统该有哪些行为(服务)上。这条原则你可以类比计算机中对文件管理的操作来理解,管理文件可能会涉及创建、修改、删除、移动等操作,这些操作数量是可数的,而且对所有文件都是固定、统一的。如果面向资源来设计系统,同样会具有类似的操作特征,由于REST并没有设计新的协议,所以这些操作都借用了HTTP协议中固有的操作命令来完成。统一接口也是REST最容易陷入争论的地方,基于网络的软件系统,到底是面向资源合适,还是面向服务更合适,这个问题恐怕在很长时间里都不会有定论,也许永远都没有。但是,已经有一个基本清晰的结论是:面向资源编程的抽象程度通常更高。抽象程度高带来的坏处是距离人类的思维方式往往会更远,而好处是通用程度往往会更好。用这样的语言去诠释REST,还是有些抽象,下面以一个例子来说明:譬如,对于几乎每个系统都有的登录和注销功能,如果你理解成登录对应于login()服务,注销对应于logout()服务这样两个独立服务,这是“符合人类思维”的;如果你理解成登录是PUT Session,注销是DELETE Session,这样你只需要设计一种“Session资源”即可满足需求,甚至以后对Session的其他需求,如查询登录用户的信息,就是GET Session而已,其他操作如修改用户信息等也都可以被这同一套设计囊括在内,这便是“抽象程度更高”带来的好处。如果想要在架构设计中合理恰当地利用统一接口,建议系统应能做到每次请求中都包含资源的ID,所有操作均通过资源ID来进行;建议每个资源都应该是自描述的消息;建议通过超文本来驱动应用状态的转移。REST绑定于HTTP协议。面向资源编程不是必须构筑在HTTP之上,但REST是,这是缺点,也是优点。因为HTTP本来就是面向资源设计的网络协议,纯粹只用HTTP(而不是SOAP over HTTP那样再构筑协议)带来的好处是无须考虑RPC中的Wire Protocol问题,REST将复用HTTP协议中已经定义的概念和相关基础支持来解决问题。HTTP协议已经有效运作了三十年,其相关的技术基础设施已是千锤百炼,无比成熟。而坏处自然是,当你想去考虑那些HTTP不提供的特性时,便会彻底束手无策。HTTP协议中已经提前约定好了一套“统一接口”,它包括GET、HEAD、POST、PUT、DELETE、TRACE、OPTIONS七种基本操作,任何一个支持HTTP协议的服务器都会遵守这套规定,对特定的URI采取这些操作,服务器就会触发相应的表征状态转移。REST接口很容易理解,举个具体例子,假设一个商城用户中心的接口设计:用户资源会拥有多个不同的下级的资源,譬如若干条短消息资源、一份用户资料资源、一辆购物车资源,购物车中又会有自己的下级资源,譬如多本图书资源。你很容易在程序接口中构造出这些资源的集合关系与层次关系,而且这些关系是符合人们长期在单机或网络环境中管理数据的经验的。相信你不需要专门阅读接口说明书,就能轻易推断出获取用户icyfenix的购物车中的第2本书的REST接口应该表示为:GET /users/icyfenix/cart/2。再来举几个列子:GET /books:列出所有书籍POST /books:新建一本书GET /books/ID:获取某个指定书籍的信息PUT /books/ID:更新某本书籍的信息(提供该书籍的全部信息)PATCH /books/ID:更新某本指定书籍的信息(提供该书籍的部分信息)DELETE /books/ID:删除某本书
  • [其他] DDL慢之系统表索引后置问题
    问题现象业务中DDL偶发或频繁执行变慢,ms级->s级劣化排查方法1、抓DDL慢时部分CN/DN的进程堆栈gstack cn_pid/dn_pid > stack.log2、分析进程中高频栈cat stack.log | grep "#2  0x00" |awk '{print $4}'| sort -rn |uniq -c | sort -rn如searchCatCache/systable_beginscan/heap_getnext几个函数高频出现则进行后续索引后置排查3、查系统表索引偏移1)拼接需要查询的语句select 'execute direct on (' || node_name || ') ''select ctid,oid,relname from pg_class where oid in(2662,2659,2679,2687,2655,2693,2701)'';' from pgxc_node;select 'execute direct on (' || node_name || ') ''select ctid,attrelid,attname from pg_attribute where attrelid in(2662,2659,2679,2687,2655,2693,2701)'';' from pgxc_node;2)执行1中拼接的语句若存在例如上述这种ctid中位置超过10w的情况,则基本确认为此问题触发场景vacuum/vacuum full系统表(pg_class、pg_attribute等)解决方案升级对应8.0\8.1新补丁版本后对系统表做vacuum full操作
  • [云计算周刊] 云计算如何推动广电行业多元融合进程?
    随着5G、移动互联网、云计算等新技术的出现,加速了各行各业的数字化转型,传统媒体在新技术的驱动下迎来了新一轮的技术变革。广电媒体行业在采、编、存、管、发各个环节,都迫切需要更专业化、智能化的媒体处理、管理平台,以提高内容生产力。传统媒体“单一渠道采集、封闭式生产、点对面单向传播”的运作模式,向“全媒体汇聚、共平台生产、多渠道分发”的新型传播方式转变。且云平台能够成为标准化、模块化、开放性的业务支撑平台,服务能力灵活组合,可自助调度资源,调整服务策略,业务迁移能够做到平滑无修改。目前,广电行业持续快速发展需要解决以下几个关键需求:存储性能:需要实现海量非结构化文件的存储,并确保存储性能不随文件数增长而性能下降。可扩展性:电视台每天产生的大量节目素材和成片等数据需要存储容量,并要求能够根据业务量可以方便扩展。备份容灾:多媒体内容成为广电行业重要的数字资产,为了应对文件、数据丢失或损坏等可能出现的意外情况,数据需要进行备份容灾。业务应用:传统系统业务流程繁复、单一、适配能力差,重型业务流程无法适应互联网环境下快速、简洁、多样化、高适应性的需求。有孚网络凭借着以北京、上海、深圳为中心,涵盖京津冀、长三角、粤港澳大湾区等重要热点区域的数据中心布局,能够满足融媒体数据管理过程中超大规模的存储需求。针对传统广电传媒行业的转型中的各项IT痛点,分布式结构自带良好的扩展性,支持存储PB级存储容量和千亿级文件数集中管理的有孚专有存储云平台,满足单机故障不影响业务,带伤运行不降速的需求,支持服务与容量双扩展,存储性能随总体容量线性提升,有效解决海量数据的存储和高速计算的问题。有孚网络通过对象存储访问接口将媒体数据安全、快速存储在对象存储中,提供更高的持续读写性能,文件迁移效率以及更高的扩展性。同时,能够在数据处理中完成图片压缩、缩略、裁剪、转格式,及音视频转码、水印、抽帧、拼接等处理。在数据安全方面,有孚专有存储云依托自建数据中心,提供纯物理环境,大大增长了数据的安全保密性。此外,用户无需投入额外的设备或进行特殊的网络配置,直接采用VPN或专线多种组网方式的数据通道建立,通过VPN或专线,可连接云端到用户自有云计算数据中心。不同于传统的文件/块的数据存储,以图片、视频为主的非结构化数据在数据保护方面具有其特性。有孚专有存储云采用分布式存储架构,可跨设备存储、实时数据同步,同时还支持云上两地三中心灾备方案在,主节点系统发生灾难时,容灾系统保障数据安全,保证客户数据万无一失。在保障成本可控的前提下,以CDN、专线、SD-WAN、EIP线路场景化定义网络,提供兼顾专网、公网、云上下的高性能网络,保障从采集、收录,到管理、分发,打破地域限制的高效、安全协作;内容生产商云剪辑服务,与内容服务商视频点播、直播服务场景直接融合,形成视频生产,录制、剪辑、转码,存储管理,分发加速于一体的高效闭环视频服务体系,高效生产快速传播。传统媒体要想更好地发挥自身优势,需要综合利用各方资源,结合云计算及大数据时代的技术创新,走上多元融合的数字化发展之路。有孚网络丰富的云计算数据中心资源、安全的同城/异地灾备方案、完善的分布式环网、资深的客户服务团队,能够为融媒体数据管理提供有效解决方案,有孚网络将持续助力融媒体内容产品升级。
  • [应用开发] 【MDC300F】【CAN】canfd使用method发送大量数据问题
    【功能模块】使用canfd通路配置来支持can【操作步骤&问题现象】1、canfd的通路配置可以兼容can,配置canfd 的channel 8为250k接收整车报文,channel 9 为500k 接收摄像头报文,channel 5为500k 向外转发整车部分报文,channel 11为500k 向外转发摄像头报文2、channel 9 接收摄像头频率为100ms 70帧数据,程序中开启了一个发送线程,对报文进行简单处理之后,使用method向channel11发送3、channel 8 接收整车报文频率为100ms 30帧数据,程序中开启了另外的发送线程,对报文进行简单处理之后,使用method向channel 5发送4、程序运行一段时间之后,异常退出另外:文档中指出“CAN下发数据频率最高100Hz”,意思是1s最多发送100帧数据吗?【日志信息】(可选,上传日志内容或者附件)2019/04/20 02:45:42.823489   99047406 002 ECU1 CAN- INTM log info V 2 [setup console output in DLT back-end. return-code: 0]2019/04/20 02:45:42.826178   99047432 000 ECU1 CAN- CM-- log info V 1 [CM version is: 2.43]2019/04/20 02:45:42.827396   99047445 001 ECU1 CAN- CM-- log info V 1 [RT_DDS_URI is set with RT_DDS_URI=/home/mdc/merlin/canfd_abstract/Debug/etc/dds.xml]2019/04/20 02:45:42.827740   99047448 002 ECU1 CAN- CM-- log info V 1 [SOMEIP_CONFIG_FILE is set with SOMEIP_CONFIG_FILE=/home/mdc/merlin/canfd_abstract/Debug/etc/vsomeip.json]2019/04/20 02:46:38.764639   99606817 003 ECU1 CAN- CM-- log warn V 1 [The same sessionId already exists in sessionId list,and the old one will be replaced by new one]2019/04/20 02:46:38.861858   99607789 004 ECU1 CAN- CM-- log warn V 1 [The same sessionId already exists in sessionId list,and the old one will be replaced by new one]2019/04/20 02:46:38.889568   99608066 005 ECU1 CAN- CM-- log warn V 1 [The same sessionId already exists in sessionId list,and the old one will be replaced by new one]2019/04/20 02:46:38.921894   99608389 006 ECU1 CAN- CM-- log warn V 1 [The same sessionId already exists in sessionId list,and the old one will be replaced by new one]2019/04/20 02:46:38.931948   99608490 007 ECU1 CAN- CM-- log warn V 1 [The same sessionId already exists in sessionId list,and the old one will be replaced by new one]2019/04/20 02:46:38.941968   99608590 008 ECU1 CAN- CM-- log warn V 1 [The same sessionId already exists in sessionId list,and the old one will be replaced by new one]2019/04/20 02:46:38.958648   99608757 009 ECU1 CAN- CM-- log warn V 1 [The same sessionId already exists in sessionId list,and the old one will be replaced by new one]2019/04/20 02:46:38.991940   99609090 010 ECU1 CAN- CM-- log warn V 1 [The same sessionId already exists in sessionId list,and the old one will be replaced by new one]。。。。。。。。segmentation fault然后程序异常退出
  • [交流吐槽] RDB的优点
    RDB 是一个非常紧凑(compact)的文件,它保存了 Redis 在某个时间点上的数据集。 这种文件非常适合用于进行备份: 比如说,你可以在最近的 24 小时内,每小时备份一次 RDB 文件,并且在每个月的每一天,也备份一个 RDB 文件。 这样的话,即使遇上问题,也可以随时将数据集还原到不同的版本。RDB 非常适用于灾难恢复(disaster recovery):它只有一个文件,并且内容都非常紧凑,可以(在加密后)将它传送到别的数据中心,或者亚马逊 S3 中。RDB 可以最大化 Redis 的性能:父进程在保存 RDB 文件时唯一要做的就是 fork 出一个子进程,然后这个子进程就会处理接下来的所有保存工作,父进程无须执行任何磁盘 I/O 操作。RDB 在恢复大数据集时的速度比 AOF 的恢复速度要快
总条数:805 到第
上滑加载中