??xml version="1.0" encoding="utf-8" standalone="yes"?>սֽ:C++博客 - սƵ2019|սع//www.pppqb.icu/xiaoxiaoling/zh-cnMon, 23 Sep 2019 15:10:52 GMTMon, 23 Sep 2019 15:10:52 GMT60博客搬至CSDN - սƵ2019|սع//www.pppqb.icu/xiaoxiaoling/archive/2019/01/29/216224.htmlclclclclTue, 29 Jan 2019 02:39:00 GMT//www.pppqb.icu/xiaoxiaoling/archive/2019/01/29/216224.html//www.pppqb.icu/xiaoxiaoling/comments/216224.html//www.pppqb.icu/xiaoxiaoling/archive/2019/01/29/216224.html#Feedback0//www.pppqb.icu/xiaoxiaoling/comments/commentRss/216224.html//www.pppqb.icu/xiaoxiaoling/services/trackbacks/216224.html博客搬至CSDN

clcl 2019-01-29 10:39 发表评论
]]>
epoll那些事儿 - սƵ2019|սع//www.pppqb.icu/xiaoxiaoling/archive/2018/07/14/215782.htmlclclclclSat, 14 Jul 2018 03:17:00 GMT//www.pppqb.icu/xiaoxiaoling/archive/2018/07/14/215782.html//www.pppqb.icu/xiaoxiaoling/comments/215782.html//www.pppqb.icu/xiaoxiaoling/archive/2018/07/14/215782.html#Feedback0//www.pppqb.icu/xiaoxiaoling/comments/commentRss/215782.html//www.pppqb.icu/xiaoxiaoling/services/trackbacks/215782.htmlET和LT:   
   LT一般用在单U程?/span>
   ET和EPOLLONESHOT配合用在多线E共享一个epoll环境下,EPOLLONESHOT标记触发q的事g从epoll中移除,下次必须重新注册Q用来防止多U程同时取到同一个socket的事件生冲H?/span>

epoll_wait W三个参?取事件数量:
   单线E模型当然尽可能一ơ多取一些效率高Q多U程Z防止一个线E把所有事件取完其他线E饥饿,ACE实现是只?个?/span>

错误处理Q?/span>
   EAGIN | EINTR | EWOULDBLOCK 重试?/span>
   EPOLLERR | EPOLLHUP | EPOLLRDHUP 断开q接?/span>

惊群Q?/span>
   默认pȝ都会有这问题Q据说新pȝ有修复不q还是处理一下比较好Q一般解x案是同时只有一个线E等待acceptQ可以单独线EacceptQ将q接在分l其他工作线E。nginx是多q程模型Q用了Z׃n内存的互斥锁Q得同时只有一个工作进E的epoll含有accept的socketQ通过q种方式实现q接C的负载均衡(q接数少的工作进E得到accept锁的概率高)?br />
   Z避免大数据量ioӞet模式下只处理一个fd,其他fd被饿ȝ情况发生。linux可以在fd联系到的l构Q一般都会自己封装一个包含fd和读写缓冲的l构体)中增加ready位,然后epoll_wait触发事g之后仅将其置位ؓready模式Q然后在下边轮询ready fd列表?/span>


epoll实现Q? 
   epoll内部用了一个红黑树记录d的socketQ用了一个双向链表接收内核触发的事g?/span>

   注册的事件挂载在U黑树中(U黑树的插入旉效率是logNQ其中n为树的高??/span>

   挂蝲的事件会与设?|卡)驱动建立回调关系Q也是_当相应的事g发生时会调用q个回调Ҏ。这个回调方法在内核中叫ep_poll_callback,它会发生的事gd到rdlist双链表中?/span>

   使用mmap映射内存Q减内核态和用户态的不同内存地址I间拯开销?/span>每次注册新的事g到epoll中时Q会把fd拯q内核,通过内核于用L间mmap同一块内?/span>保证了只会拷贝一ơ。(q回的时候不需要拷贝,select要)

   执行epoll_ctlӞ除了把socket攑ֈU黑树上Q还会给内核中断处理E序注册一个回调函敎ͼ告诉内核Q如果这个句柄的中断CQ就把它攑ֈ准备qAlist链表里。所以,当一个socket上有数据CQ内核在把网卡上的数据copy到内怸后就把socket插入到准备就l链表里了。链表又是通过mmap映射的空_所以在传递给用户E序的时候不需要复Ӟq也是ؓ什么比select效率高的原因Qepoll_waitq回的只是就l队列,不需要轮?不需要复制完成的事g列表QselectQpoll实现需要自׃断轮询所有fd集合Q直到设备就l)?/span>

   epoll_wait最后会查socketQ如果是 LTQƈ且这些socket上确实有未处理的事gӞ又把该句柄放回到刚刚清空的准备就l链表了QLT比ET低效的原因)?/span>

 

可见Q如果没有大量的I闲Q无效连接,epoll效率不比select高?/span>

试数据Q仅是刚接触go的时候好奇做的参考意义的试Q:  

   同样的环境,echo服务器测q发ioQ单U程epoll qps:45000左右Q每q接/协程 goQ?50000多,多线EepollQ开6个epollQ每个epoll开8U程Q一?8U程Q:qps 70000多?/span>

 




clcl 2018-07-14 11:17 发表评论
]]>
tcp/udpQsocket那些事儿 - սƵ2019|սع//www.pppqb.icu/xiaoxiaoling/archive/2018/07/13/215781.htmlclclclclFri, 13 Jul 2018 07:49:00 GMT//www.pppqb.icu/xiaoxiaoling/archive/2018/07/13/215781.html//www.pppqb.icu/xiaoxiaoling/comments/215781.html//www.pppqb.icu/xiaoxiaoling/archive/2018/07/13/215781.html#Feedback0//www.pppqb.icu/xiaoxiaoling/comments/commentRss/215781.html//www.pppqb.icu/xiaoxiaoling/services/trackbacks/215781.html概念 Q?
   tcp和udpQ连接和无连接都是协议,是共享物理介质的传输数据的应用程序之间的U定。面向连接的协议l护了segment的状态和ơ序?br />
故障 :
      默认无keep aliveQ?/span>
拔网U或?/span>由器崩溃Q发送端时Q重?2ơ大U?分钟Q后攑ּQ接收端读errorno ETIMEOUTQ如果没有读则要{到下一ơ写p|sigpipe。如果中间\由器无法转发则向源端发?ICMP 目标L不可达?/span>
E序退出(包括崩溃Q: E序退出和正常调用 close无法区分Q都会返回FIN表示退出,如果一端退出,
      另一端: 1.W一ơ写合法Q接收到fin后还是能l箋发送数据)W二ơ写的时候发现连接不存在Q得?RST RESET错误 2.ȝ时候得? conn reset错误Ql写则被SIGPIPE信号中止Q程序退出?/span>
L宕机Q?宕机后无法通过FIN通知ҎQ对方会l箋重传直到timeout。如果超时前宕机的主机重启了Q此时收到重传的L没有q接记录Q向源返回rstQ发送端得到ECONNRESET错误Q如果发送端在读得到 conn reset错误Ql写则被SIGPIPE信号中止Q程序退出?/span>
开启keep alive情况下:
如果E序崩溃q回fin Q?如果L可达但程序不存在Q主机重启)Q则响应RStQ源端得到ECONNRESET 错误?/span>
如果Ҏ没有对keep alive响应ACK 或者RSTQ源端TIMEOUTQ?/span>重试9ơ,每次间隔75U,定时?时时后的11.25分钟Q?/span>以程序自己做心蟩q是必要的?/span>

l节Q?br />
tcp写操作:
用户态拷贝到内核态写~冲区后q回Q只q回明显错误Qsocket无效或缓冲区无效。媄响的因素有:发送窗口,拥塞H口Q写~冲区大,Nagle?/span>
tcp是提高带宽利用率的协议,每次发送們֐mss大小Q同时不能大于对端指定的大小Q发送窗口)Qtcp只考虑了网l中路由器缓冲区耗尽情况Q也是tcp的限Ӟ所以有拥塞H口和慢启动Qؓ了防止网l拥塞(自律的协议)每次发送的不能大于Ҏ指定的(发送窗口)和自q自己限制的(拥塞H口Q?br />

    

慢启动:一开始指数的增加拥塞窗口,C个门阀值后变成U性的Q?之后每次时都把门阀值降低到原来一半(q且rtod,TCP时计算是RTOx2Q这栯l丢三次包就变成RTOx8了,十分恐?/span>Q,拥塞H口讄?重新开始慢启动Q指数增加Q。一切都是ؓ了让路由器有旉处理U压的缓册Ӏ(所以不适用于频J断开q接的移动网l,q也是ؓ什么以前的下蝲工具开多条tcp传输速度更快的原因)?/span>

Nagle法Q第一ơ(此时没有{待ack认Q空闲连接)发送小包成功,W二ơl发?Q哪怕发送窗口,拥塞H口都很大,之前的包没有ack认依旧不让发直到收C前的 ack认?/span>

shutdown和close的区?

close只是递减引用计数Q?shutdown的半关闭会媄响所有的q程?/span>

shutdown how=0 关闭读,Mq回eof
shutdown how=1 关闭写,M写会出错Q将~冲区的发送完后会发送fin表示没有数据了,
收到Ҏ发送的finQrecv会返??/span>
listen 的第二个参数制定的是全连接队列大(acceptQ?br />
time_wait和close_wait
time_wait 出现在主动close方,Z防止新连接收到旧链接的数据包Q?数量?/span>可以通过讄内核参数~短旉降低数|2mslQ。可以通过 SO_LINGER关闭?/span>
close_wait 出现在被动close方,数量高一般因为性能或者bug在收到fin后没有调用close?br />
SO_REUSEADDR
用于E序崩溃后重启,解决地址被占用问题(time_waitQ,另一个用途是开两个服务Q第一个制定地址Q第二个指定INADDR_ANY 通配地址Q如果客Lq接的是制定地址一样会到第一个socket上?br />      对于l定于同一地址端口l合上的UDP socketQkernel试在它们之间^均分配收到的数据包;对于l定于同一地址端口l合上的TCP监听socketQkernel试在它们之间^均分配收到的q接hQ调用accept()Ҏ所得到的请求)?/span>

Nagle和gqack的问题:
发送端数据未发送完Q被nagle止发送(必须{待接收端的ackQ也是没有未确认的包才允许发送)Q此时接收端ack被gq发送(希望ack和数据一起发送提高带宽利用率Q而发送方数据未发送完D接收端无法回复,双方死锁?/span>
已连接的UDPQ?/span>
tcp的connect是开始三ơ握手,远E的ip端口l定到socketQ而bind是绑定本地的ip端口?/span>
udp没有三次握手QconnectUa是本地行为,远E的ip端口l定到socket上?/span>
已连接的udp可以不用sendtoQsendto会先socket和目的地址q接Q然后发送数据后再断开Q而已q接的已l绑定地址可以用writeQ提高效率(资料昄暂时q接断开所用的旉是传输udp数据的三分之一Q还是很可观的)。异步错误的接收Q用sendto发送完pȝ没有记录了Q应用程序无法接收之后icmpq回的错误?/span>
接收端已q接udp的好处: 可以标识哪个socket是哪个用P另外q可以独占连接,再另一个地方调用recvfrom指定相同地址会返回ECONNREFUSEDQ因为此q接已经被绑定?/span>


clcl 2018-07-13 15:49 发表评论
]]>
初识cdn - սƵ2019|սع//www.pppqb.icu/xiaoxiaoling/archive/2018/05/09/215630.htmlclclclclWed, 09 May 2018 15:57:00 GMT//www.pppqb.icu/xiaoxiaoling/archive/2018/05/09/215630.html//www.pppqb.icu/xiaoxiaoling/comments/215630.html//www.pppqb.icu/xiaoxiaoling/archive/2018/05/09/215630.html#Feedback0//www.pppqb.icu/xiaoxiaoling/comments/commentRss/215630.html//www.pppqb.icu/xiaoxiaoling/services/trackbacks/215630.html   工作上虽然和cdn没关pM是技术方向还是很多相g处的Q例如:负蝲均衡Q缓存,分布式,路由{?/span>
   cdn单的说就是个复杂的大~存Q由于目标用P包括源和端)q泛直接D了其复杂性,遍布q节点多则需要分负载甚臌l织Q应用繁杂则需要分\由,提速则需要缓存,E_则需要监控调度,Z透明则需要各U映?/span>
   ׃接入面广和网l的复杂性,不可能让客户端直接面ҎQ于是就有了专门接入客户端的边缘服务?l,q些边缘服务器和后端的调度,监控Q源服务器通讯。既然是~存?/span>涉及到数据一致性的问题Q?/span>最单的是各接入端的边~服务器在需要的时候到后台拉取Q或者更的他们之间可以相互拉取,甚至后台调度提前推送?/span>
   边缘接收到请求后首当其冲的问题就是对h的内?“d?/span>”?#8220;怎么?/span>”Q想要知道内容的位置Q一般缓存的实现不外乎就是统一C个目录服务器找,或者广播所有自q道的节点问一圈,更高效的Ҏ是将hurl哈希后直接找到目的地址Q当然只要是~存都会q期也就有TTL的概c?#8220;怎么?#8221;的方式多U多P׃互联|web服务居多ZDNS的\׃用最q泛Q缺Ҏ客户端和中点会~存Q更新需要一定时间。HTTP重定向,URL改写Q也有直接在|络讑֤路由器上做,直接在\p中保持\径。这些方法在cdnq个庞杂的系l中Ҏ需要用,例如边缘服务器ؓ了接收到客户端的h可以使用dns重定向,然后再用哈希或者url改写转发到后端的源?nbsp;
   现如今的|络内容有许多是动态生成的Q对q些无法提前~存的内容可以直接略q只存静态内容(分段~存Q,l装的时候发送回客户端或者直接赋予边~服务器生成动态内容的能力Q边~计)当然q对|页的制作有规范?/span>
   面向大众的服务都有潮汐效应,在热ҎD늚讉K量是qx的几十上癑ր(Ҏ二八理论Q?0%的问题都是在20%的地方出现的Q热点访问量也是大多讉K部分数据,如果能提前将热点~存于各边缘服务器最直接有效Q,如果有自适应的动态调整功能整个服务会健壮很多。边~服务器是离用户最q的Q可以将每个节点看成l,l长监控负蝲自适应的添加删除组员(~存服务器)以及更新dnsQ不允许l员跨组拉数据。当然如果客L之间可以使用P2P怺取数据也是一个办法?nbsp;  
   当前出现了基于流媒体的cdnQ视频内容分发在后端以文件的形式传输Q适合传输的格式更高效Q,到边~服务器再以的形式和客L传输Q不需要全部传完即可开始播放)。同时也要综合考虑时段需求,视频~码{略也很重要?/span>

clcl 2018-05-09 23:57 发表评论
]]>
关于dpdk 的思?/title><link>//www.pppqb.icu/xiaoxiaoling/archive/2017/02/05/214651.html</link><dc:creator>clcl</dc:creator><author>clcl</author><pubDate>Sun, 05 Feb 2017 06:08:00 GMT</pubDate><guid>//www.pppqb.icu/xiaoxiaoling/archive/2017/02/05/214651.html</guid><wfw:comment>//www.pppqb.icu/xiaoxiaoling/comments/214651.html</wfw:comment><comments>//www.pppqb.icu/xiaoxiaoling/archive/2017/02/05/214651.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>//www.pppqb.icu/xiaoxiaoling/comments/commentRss/214651.html</wfw:commentRss><trackback:ping>//www.pppqb.icu/xiaoxiaoling/services/trackbacks/214651.html</trackback:ping><description><![CDATA[<p><br /></p><p><span style="mso-spacerun:'yes';font-family:宋体;mso-bidi-font-family:'Times New Roman';font-size:10.5000pt;">dpdk是通过许多不同的纬度来加速包处理的,其中主要包括Q?/span></p><p> </p><p><span style="mso-spacerun:'yes';font-family:宋体;mso-bidi-font-family:'Times New Roman';font-size:10.5000pt;">hugepage大页内存(q程使用的是虚拟地址Q一般页?4k)能映的虚拟地址I间有限Q用大能减少换页ơ数提高cache命中Q通过mmap把大|到用户态的虚拟地址I间有用qmmap的都知道q是实现׃n内存的手D,所以dpdkq支持多q程׃n内存)</span></p><p> </p><p><span style="mso-spacerun:'yes';font-family:宋体;mso-bidi-font-family:'Times New Roman';font-size:10.5000pt;">cache预取 (每次预读当前数据盔R前后的数?Q批量操作数据,cache line寚w(通过费一点内存将要操作的数据寚w)</span></p><p> </p><p><span style="mso-spacerun:'yes';font-family:宋体;mso-bidi-font-family:'Times New Roman';font-size:10.5000pt;">接管了网卡用h驱动用轮询而不是网卡中?/span></p><p> </p><p><span style="mso-spacerun:'yes';font-family:宋体;mso-bidi-font-family:'Times New Roman';font-size:10.5000pt;">网卡rx tx队列映射到用h空间实现真正的零拷贝(传统堆栈臛_也得一ơ拷贝,因ؓ队列I间在内核而内核和用户态用不同的地址I间Q?传统堆栈Z支持通用性,例如ipx{其他网l,包处理q程分了很多层次Q层之间的接口标准统一数据l构需要{换,无Ş中带来了巨大的成本,如osi七层模型而实用的是tcp/ip四层模型</span><span style="mso-spacerun:'yes';font-family:宋体;mso-bidi-font-family:'Times New Roman';font-size:10.5000pt;">)</span></p><p> </p><p><span style="mso-spacerun:'yes';font-family:宋体;mso-bidi-font-family:'Times New Roman';font-size:10.5000pt;">U程l定cpu</span></p><p> </p><p><span style="mso-spacerun:'yes';font-family:宋体;mso-bidi-font-family:'Times New Roman';font-size:10.5000pt;">支持NUMAQ不同的core属于不同的nodeQ每个node有自qmempool减少冲突</span></p><p> </p><p><span style="mso-spacerun:'yes';font-family:宋体;mso-bidi-font-family:'Times New Roman';font-size:10.5000pt;">无锁环Ş队列(冲突发生时也是一ơcas的开销)</span></p><p> </p><p><span style="mso-spacerun:'yes';font-family:宋体;mso-bidi-font-family:'Times New Roman';font-size:10.5000pt;">dpdk通过tools/dpdk-setup.sh的脚本,通过~译、挂载内核模块, l定|卡Q先把网卡ifconfig downQ,讄hugepage后就可以使用了?/span></p><p> </p><p> </p><p><span style="mso-spacerun:'yes';font-family:宋体;mso-bidi-font-family:'Times New Roman';font-size:10.5000pt;">在内核模块igb加蝲Ӟ会注册pci讑֤驱动</span></p><p><span style="mso-spacerun:'yes';font-family:宋体;mso-bidi-font-family:'Times New Roman';font-size:10.5000pt;">static struct pci_driver igbuio_pci_driver = {</span></p><p><span style="mso-spacerun:'yes';font-family:宋体;mso-bidi-font-family:'Times New Roman';font-size:10.5000pt;"> </span><span style="mso-spacerun:'yes';font-family:宋体;mso-bidi-font-family:'Times New Roman';font-size:10.5000pt;">.name = "igb_uio",</span></p><p><span style="mso-spacerun:'yes';font-family:宋体;mso-bidi-font-family:'Times New Roman';font-size:10.5000pt;"> </span><span style="mso-spacerun:'yes';font-family:宋体;mso-bidi-font-family:'Times New Roman';font-size:10.5000pt;">.id_table = NULL,</span></p><p><span style="mso-spacerun:'yes';font-family:宋体;mso-bidi-font-family:'Times New Roman';font-size:10.5000pt;"> </span><span style="mso-spacerun:'yes';font-family:宋体;mso-bidi-font-family:'Times New Roman';font-size:10.5000pt;">.probe = igbuio_pci_probe,</span></p><p><span style="mso-spacerun:'yes';font-family:宋体;mso-bidi-font-family:'Times New Roman';font-size:10.5000pt;"> </span><span style="mso-spacerun:'yes';font-family:宋体;mso-bidi-font-family:'Times New Roman';font-size:10.5000pt;">.remove = igbuio_pci_remove,</span></p><p><span style="mso-spacerun:'yes';font-family:宋体;mso-bidi-font-family:'Times New Roman';font-size:10.5000pt;">};</span></p><p> </p><p><span style="mso-spacerun:'yes';font-family:宋体;mso-bidi-font-family:'Times New Roman';font-size:10.5000pt;">在绑定网卡时Q会调用igbuio_pci_probeQ用用h驱动uio接管|卡(中断处理、mmap映射讑֤内存到用L?</span></p><p><span style="mso-spacerun:'yes';font-family:宋体;mso-bidi-font-family:'Times New Roman';font-size:10.5000pt;">pȝ启动Ӟbios会将讑֤ȝ地址信息记录?sys/bus/pci/devicesQdpdkE序启动时会去这里扫描pci讑֤Q根据不同类型的NIC有对应的初始化流E。在后面配置队列的时候会把用h的队列内存地址通过g指o交给NICQ从而实现零拯?/span></p><p><img src="//www.pppqb.icu/images/cppblog_com/xiaoxiaoling/囄1.png" width="790" height="772" alt="" /><br /></p><p> </p><p><span style="mso-spacerun:'yes';font-family:宋体;mso-bidi-font-family:'Times New Roman';font-size:10.5000pt;">如果</span><span style="mso-spacerun:'yes';font-family:宋体;mso-bidi-font-family:'Times New Roman';font-size:10.5000pt;">NIC收到包,会做标记Q轮询的时候通过标记取数据包</span></p><p><span style="mso-spacerun:'yes';font-family:宋体;mso-bidi-font-family:'Times New Roman';font-size:10.5000pt;">while (nb_rx < nb_pkts) {</span></p><p><span style="mso-spacerun:'yes';font-family:宋体;mso-bidi-font-family:'Times New Roman';font-size:10.5000pt;"> </span><span style="mso-spacerun:'yes';font-family:宋体;mso-bidi-font-family:'Times New Roman';font-size:10.5000pt;"> </span><span style="mso-spacerun:'yes';font-family:宋体;mso-bidi-font-family:'Times New Roman';font-size:10.5000pt;">/*</span></p><p><span style="mso-spacerun:'yes';font-family:宋体;mso-bidi-font-family:'Times New Roman';font-size:10.5000pt;"> </span><span style="mso-spacerun:'yes';font-family:宋体;mso-bidi-font-family:'Times New Roman';font-size:10.5000pt;"> </span><span style="mso-spacerun:'yes';font-family:宋体;mso-bidi-font-family:'Times New Roman';font-size:10.5000pt;"> * The order of operations here is important as the DD status</span></p><p><span style="mso-spacerun:'yes';font-family:宋体;mso-bidi-font-family:'Times New Roman';font-size:10.5000pt;"> </span><span style="mso-spacerun:'yes';font-family:宋体;mso-bidi-font-family:'Times New Roman';font-size:10.5000pt;"> </span><span style="mso-spacerun:'yes';font-family:宋体;mso-bidi-font-family:'Times New Roman';font-size:10.5000pt;"> * bit must not be read after any other descriptor fields.</span></p><p><span style="mso-spacerun:'yes';font-family:宋体;mso-bidi-font-family:'Times New Roman';font-size:10.5000pt;"> </span><span style="mso-spacerun:'yes';font-family:宋体;mso-bidi-font-family:'Times New Roman';font-size:10.5000pt;"> </span><span style="mso-spacerun:'yes';font-family:宋体;mso-bidi-font-family:'Times New Roman';font-size:10.5000pt;"> * rx_ring and rxdp are pointing to volatile data so the order</span></p><p><span style="mso-spacerun:'yes';font-family:宋体;mso-bidi-font-family:'Times New Roman';font-size:10.5000pt;"> </span><span style="mso-spacerun:'yes';font-family:宋体;mso-bidi-font-family:'Times New Roman';font-size:10.5000pt;"> </span><span style="mso-spacerun:'yes';font-family:宋体;mso-bidi-font-family:'Times New Roman';font-size:10.5000pt;"> * of accesses cannot be reordered by the compiler. If they were</span></p><p><span style="mso-spacerun:'yes';font-family:宋体;mso-bidi-font-family:'Times New Roman';font-size:10.5000pt;"> </span><span style="mso-spacerun:'yes';font-family:宋体;mso-bidi-font-family:'Times New Roman';font-size:10.5000pt;"> </span><span style="mso-spacerun:'yes';font-family:宋体;mso-bidi-font-family:'Times New Roman';font-size:10.5000pt;"> * not volatile, they could be reordered which could lead to</span></p><p><span style="mso-spacerun:'yes';font-family:宋体;mso-bidi-font-family:'Times New Roman';font-size:10.5000pt;"> </span><span style="mso-spacerun:'yes';font-family:宋体;mso-bidi-font-family:'Times New Roman';font-size:10.5000pt;"> </span><span style="mso-spacerun:'yes';font-family:宋体;mso-bidi-font-family:'Times New Roman';font-size:10.5000pt;"> * using invalid descriptor fields when read from rxd.</span></p><p><span style="mso-spacerun:'yes';font-family:宋体;mso-bidi-font-family:'Times New Roman';font-size:10.5000pt;"> </span><span style="mso-spacerun:'yes';font-family:宋体;mso-bidi-font-family:'Times New Roman';font-size:10.5000pt;"> </span><span style="mso-spacerun:'yes';font-family:宋体;mso-bidi-font-family:'Times New Roman';font-size:10.5000pt;"> */</span></p><p><span style="mso-spacerun:'yes';font-family:宋体;mso-bidi-font-family:'Times New Roman';font-size:10.5000pt;"> </span><span style="mso-spacerun:'yes';font-family:宋体;mso-bidi-font-family:'Times New Roman';font-size:10.5000pt;"> </span><span style="mso-spacerun:'yes';font-family:宋体;mso-bidi-font-family:'Times New Roman';font-size:10.5000pt;">rxdp = &rx_ring[rx_id];</span></p><p><span style="mso-spacerun:'yes';font-family:宋体;mso-bidi-font-family:'Times New Roman';font-size:10.5000pt;"> </span><span style="mso-spacerun:'yes';font-family:宋体;mso-bidi-font-family:'Times New Roman';font-size:10.5000pt;"> </span><span style="mso-spacerun:'yes';font-family:宋体;mso-bidi-font-family:'Times New Roman';font-size:10.5000pt;">staterr = rxdp->wb.upper.status_error;</span></p><p><span style="mso-spacerun:'yes';font-family:宋体;mso-bidi-font-family:'Times New Roman';font-size:10.5000pt;"> </span><span style="mso-spacerun:'yes';font-family:宋体;mso-bidi-font-family:'Times New Roman';font-size:10.5000pt;"> </span><span style="mso-spacerun:'yes';font-family:宋体;mso-bidi-font-family:'Times New Roman';font-size:10.5000pt;">if (! (staterr & rte_cpu_to_le_32(E1000_RXD_STAT_DD)))</span></p><p><span style="mso-spacerun:'yes';font-family:宋体;mso-bidi-font-family:'Times New Roman';font-size:10.5000pt;"> </span><span style="mso-spacerun:'yes';font-family:宋体;mso-bidi-font-family:'Times New Roman';font-size:10.5000pt;"> </span><span style="mso-spacerun:'yes';font-family:宋体;mso-bidi-font-family:'Times New Roman';font-size:10.5000pt;"> </span><span style="mso-spacerun:'yes';font-family:宋体;mso-bidi-font-family:'Times New Roman';font-size:10.5000pt;">break;</span></p><p><span style="mso-spacerun:'yes';font-family:宋体;mso-bidi-font-family:'Times New Roman';font-size:10.5000pt;"> </span><span style="mso-spacerun:'yes';font-family:宋体;mso-bidi-font-family:'Times New Roman';font-size:10.5000pt;"> </span><span style="mso-spacerun:'yes';font-family:宋体;mso-bidi-font-family:'Times New Roman';font-size:10.5000pt;">rxd = *rxdp;</span></p><p><span style="mso-spacerun:'yes';font-family:宋体;mso-bidi-font-family:'Times New Roman';font-size:10.5000pt;">发包的轮询就是轮询发包结束的g标志位,g发包完成会写回标志位Q驱动发现后再释攑֯应的描述W和~冲块?/span></p><p> </p><p><span style="mso-spacerun:'yes';font-family:宋体;mso-bidi-font-family:'Times New Roman';font-size:10.5000pt;">KNI</span></p><p><span style="mso-spacerun:'yes';font-family:宋体;mso-bidi-font-family:'Times New Roman';font-size:10.5000pt;">通过创徏一个虚拟网卡,收到的包丢l协议栈</span></p><p><span style="mso-spacerun:'yes';font-family:Calibri;mso-bidi-font-family:'Times New Roman';font-size:10.5000pt;"> /* 发送skb到协议栈 */</span></p><p><span style="mso-spacerun:'yes';font-family:Calibri;mso-bidi-font-family:'Times New Roman';font-size:10.5000pt;">            /* Call </span><span style="mso-spacerun:'yes';font-family:宋体;mso-bidi-font-family:'Times New Roman';font-size:10.5000pt;">netif</span><span style="mso-spacerun:'yes';font-family:Calibri;mso-bidi-font-family:'Times New Roman';font-size:10.5000pt;"> interface */</span></p><p><span style="mso-spacerun:'yes';font-family:Calibri;mso-bidi-font-family:'Times New Roman';font-size:10.5000pt;">            </span><span style="mso-spacerun:'yes';font-family:宋体;mso-bidi-font-family:'Times New Roman';font-size:10.5000pt;">netif</span><span style="mso-spacerun:'yes';font-family:Calibri;mso-bidi-font-family:'Times New Roman';font-size:10.5000pt;">_receive_skb(skb);</span></p><p> </p><p><span style="mso-spacerun:'yes';font-family:宋体;mso-bidi-font-family:'Times New Roman';font-size:10.5000pt;">POWER </span></p><p><span style="mso-spacerun:'yes';font-family:宋体;mso-bidi-font-family:'Times New Roman';font-size:10.5000pt;">在负载小的时候没有必要用轮询模式,q时可以打开|卡中断 使用eventfd  epoll通知用户?/span></p><p> </p><p><span style="mso-spacerun:'yes';font-family:宋体;mso-bidi-font-family:'Times New Roman';font-size:10.5000pt;">Ring</span></p><p><span style="mso-spacerun:'yes';font-family:宋体;mso-bidi-font-family:'Times New Roman';font-size:10.5000pt;">无锁环Ş队列的核心就是操作头引,先将头尾索引赋给临时变量Q再把尾索引往后蟩n个位|,利用cas判断头如果还是在原来的位|就指向֐则就重复q个q程Q然后在操作中间跌的n个元素就是安全的了,此时头尾索引应该指向同一个位|,如果不同应该是有别的U程也在操作Q重复等待即可?q里有个l节Q烦引是只加不减的,因ؓ是环形队列烦引又是unsigned 32bitsQ所以每ơ取数据前把索引模队列长?1Q?uint32_t mask;           /**< Mask (size-1) of ring. */卛_</span><span style="mso-spacerun:'yes';font-family:宋体;mso-bidi-font-family:'Times New Roman';font-size:10.5000pt;">)</span></p><p> </p><p><span style="mso-spacerun:'yes';font-family:宋体;mso-bidi-font-family:'Times New Roman';font-size:10.5000pt;">Windows下用vmware虚拟机的时候出现EAL: Error</span><span style="mso-spacerun:'yes';font-family:Calibri;mso-bidi-font-family:'Times New Roman';font-size:10.5000pt;"> reading from file descriptor</span><span style="mso-spacerun:'yes';font-family:宋体;mso-bidi-font-family:'Times New Roman';font-size:10.5000pt;">Q根据网上的说法打了patchq是不行Q后来尝试挂载内核模块的时候不加蝲vfio模块可以了</span></p><p> </p><img src ="//www.pppqb.icu/xiaoxiaoling/aggbug/214651.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="//www.pppqb.icu/xiaoxiaoling/" target="_blank">clcl</a> 2017-02-05 14:08 <a href="//www.pppqb.icu/xiaoxiaoling/archive/2017/02/05/214651.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Redis解析 - սƵ2019|սع//www.pppqb.icu/xiaoxiaoling/archive/2017/01/24/214634.htmlclclclclTue, 24 Jan 2017 10:13:00 GMT//www.pppqb.icu/xiaoxiaoling/archive/2017/01/24/214634.html//www.pppqb.icu/xiaoxiaoling/comments/214634.html//www.pppqb.icu/xiaoxiaoling/archive/2017/01/24/214634.html#Feedback0//www.pppqb.icu/xiaoxiaoling/comments/commentRss/214634.html//www.pppqb.icu/xiaoxiaoling/services/trackbacks/214634.html

Redis是工作中很常用的Q这里将比较普遍使用的结构研I了下做个备忘?/span>

 

hash

实现和dnspod的dataset半斤八两Q本质上是个二维数组Q通过key哈希作ؓ一l的下表Q第二维的数l存相同哈希的元素,查找使用遍历的方式,所以这里redis做了优化Q当满条g的时?数组数量太大)会进行rehashQ动态扩大桶的数量来减少最后一l遍历的ơ数.

函数名称

作用

复杂?/span>

dictCreate

创徏一个新字典

O(1)

dictResize

重新规划字典的大?/span>

O(1)

dictExpand

扩展字典

O(1)

dictRehash

对字典进行N步渐q式Rehash

O(N)

_dictRehashStep

对字典进?步尝试Rehash

O(N)

dictAdd

d一个元?/span>

O(1)

dictReplace

替换l定key的value?/span>

O(1)

dictDelete

删除一个元?/span>

O(N)

dictRelease

释放字典

O(1)

dictFind

查找一个元?/span>

O(N)

dictFetchValue

通过key查找value

O(N)

dictGetRandomKey

随机q回字典中一个元?/span>

O(1)

 

字典l构

typedef struct dict {

    // cd特定函数

    dictType *type;

    // U有数据

    void *privdata;

    // 哈希?/span>

    dictht ht[2];

    // rehash 索引

    // ?rehash 不在q行Ӟgؓ -1

    int rehashidx; /* rehashing not in progress if rehashidx == -1 */

    // 目前正在q行的安全P代器的数?/span>

    int iterators; /* number of iterators currently running */

} dict;

q里哈希表有两个Q一般都用ht[0]Q当需要rehash的时候会创徏一个比ht[0]大的 2 ?N ơ方的ht[1]Q然后渐q式的将数据dictEntryU过?除了定时的rehashQ在每次操作哈希表时都会_dictRehashStep)Q完成后ht[1]替换ht[0]

 

zset

zset本质是list,只不q每个元素都有若q个指向后span长的指针Q这L单的设计大大提高了效率,使得可以比拟q二叉树,查找、删除、插入等操作都可以在Ҏ期望旉内完成,Ҏq树,跌表的实现要简单直观很多?/span>

 

 

/* ZSETs use a specialized version of Skiplists */

/*

 * 跌表节?/span>

 */

typedef struct zskiplistNode {

    // 成员对象

    robj *obj;

    // 分?/span>

    double score;

    // 后退指针

    struct zskiplistNode *backward;

    // ?/span>

    struct zskiplistLevel {

        // 前进指针

        struct zskiplistNode *forward;

        // 跨度

        unsigned int span;

    } level[];

} zskiplistNode;

 

/*

 * 跌?/span>

 */

typedef struct zskiplist {

    // 表头节点和表节?/span>

    struct zskiplistNode *header, *tail;

    // 表中节点的数?/span>

    unsigned long length;

    // 表中层数最大的节点的层?/span>

    int level;

} zskiplist;

 

/*

 * 有序集合

 */

typedef struct zset {

 

    // 字典Q键为成员,gؓ分?/span>

    // 用于支持 O(1) 复杂度的按成员取分值操?/span>

    dict *dict;

    // 跌表,按分值排序成?/span>

    // 用于支持q_复杂度ؓ O(log N) 的按分值定位成员操?/span>

    // 以及范围操作

    zskiplist *zsl;

 

} zset;

 

虽然q种方式排序查找很快Q但是修改的话就得多做些工作?/span>

 

/* Delete an element with matching score/object from the skiplist.

 *

 * 从蟩跃表 zsl 中删除包含给定节?score q且带有指定对象 obj 的节炏V?/span>

 *

 * T_wrost = O(N^2), T_avg = O(N log N)

 */

int zslDelete(zskiplist *zsl, double score, robj *obj)

 

intset

typedef struct intset {  

uint32_t encoding; //所使用cd的长度,4\8\16  

uint32_t length; //元素个数  

int8_t contents[]; //保存元素的数l?/span>  

} intset;  

 

intset其实是数组Q有序、无重复C存多个整数|查找用的是二分查?* T = O(log N)Q添加的话在扑ֈ对应的数l中应该存在的位子后使用memmove向后UdIZ填补(当然需要先realloc预分配空?Q同理删除也是用memmove向前Ud

 

set

当用整数时Q用intsetQ否则用哈希表

 

 

其他的关于网l事件处理,epollQ回调,拆包都和正常使用差不多,关于错误处理EINTR(pȝ调用期间发生中断)和EAGAIN l箋重试而如果是EPOLLHUP或EPOLLERR则让io该读读该写写Q有错处理就是了?/span>

 

 



clcl 2017-01-24 18:13 发表评论
]]>
dnspod解析 - սƵ2019|սع//www.pppqb.icu/xiaoxiaoling/archive/2017/01/23/214630.htmlclclclclMon, 23 Jan 2017 07:14:00 GMT//www.pppqb.icu/xiaoxiaoling/archive/2017/01/23/214630.html//www.pppqb.icu/xiaoxiaoling/comments/214630.html//www.pppqb.icu/xiaoxiaoling/archive/2017/01/23/214630.html#Feedback0//www.pppqb.icu/xiaoxiaoling/comments/commentRss/214630.html//www.pppqb.icu/xiaoxiaoling/services/trackbacks/214630.html 

 

dns的递归解析q程q是挺繁琐的Q要知道一个域名可能有cname、ns 而请求的cname、ns可能q有cname、nsQ如果按照线性的处理每个h那逻辑变成毛U团?/span>

dnspod的处理还是挺巧妙的,通过一个公q数据集dataset所有域名对应的a、cname、ns{类型的数据作ؓ单独的条目存入,当有需要某个域名的信息时先去dataset找,找不到在加入qlisth根,有专门的U程不间断的qlist轮询dataset找(q里只要ơ数允许Q没得到惌的结果就轮询所有qlist到dataset找虽然可以简化逻辑分离的彻底但是会是个性能瓉Q后面有ҎQ当根返回以后只是简单的记?通常是一个域名的cname、ns或者a)存入dataset(而不是l流E,因ؓҎq个q回是cnameq是ns或者a处理不同逻辑复杂Q而这样处理对于用到相同域名的hq有优化作用)Q剩下的工作交给那边不间断轮询的U程

 

Dnspod主要?个runQ若q个U程Q组?/span>

 

run_sentinel  监听53端口接收客户端请求,请求放到队列中

run_fetcher   从队列中取出hQ根据qname取得最后一UcnameQ查看本地dataset 是否有记录,如果有则q回Q没有则该h攑օqlist?/span>

 

run_quizzer    

1.不间断的遍历qlistQ只要状态ؓPROCESS_QUERY?/span>dataset中没有的向对应的根发送请求?/span>

2.通过epoll{待根返回,解析q回的数据加?dataset

3.查记录的ttlQ在记录加入dataset时还会将q些记录以红黑树的Ş式组lv来,取得ttl最早到期的Q将其放入qlist中等待刷斎ͼ注意q里不是删除Q如果收不到不返回则该记录一直存?/span>

 

关于dataset的实?/span>

dataset是用哈希表实现的,本质上是个二l数l,域名哈希成一个|模上数组的数量作Z标,扑ֈ对应的数l接着遍历查找Q根据需要可以扩大数l的数量提升性能?/span>

 

我们的优化手D?/span>

之前提到dnspod的qlist会不间断轮询Q属于主动查询,Ҏ能有不的影响Q这里我们采取的做法是被?cM回调的方?Q我们将h的域名和cd分类Q相同的攑֜一l,当dataset找不到向根发求后我们q不每次d轮询Q而是在等到应{后Q触发该域名和类型的hl,让他们根据自q逻辑C一步(一般是先找该域名的最后一UcnameQ根据这个cname查是否存在他的对应请求类型的记录Q一般是a或者nsQ如果没有,则找q个cname的nsQ?/span>

 

以上可以看出dataset很重要,负蝲也不,q经帔R要ƈ发访问,q里我们每次接收到根的回复后Q除了将记录的答案加qdatasetQ还创徏一个时的datasetQ只存该ơ回复的信息Q在后面的流E会优先到这里去找,没有的再找dataset?/span>



clcl 2017-01-23 15:14 发表评论
]]>
Network Stack Specialization for Performance - սƵ2019|սع//www.pppqb.icu/xiaoxiaoling/archive/2017/01/22/214625.htmlclclclclSun, 22 Jan 2017 10:01:00 GMT//www.pppqb.icu/xiaoxiaoling/archive/2017/01/22/214625.html//www.pppqb.icu/xiaoxiaoling/comments/214625.html//www.pppqb.icu/xiaoxiaoling/archive/2017/01/22/214625.html#Feedback0//www.pppqb.icu/xiaoxiaoling/comments/commentRss/214625.html//www.pppqb.icu/xiaoxiaoling/services/trackbacks/214625.html阅读全文

clcl 2017-01-22 18:01 发表评论
]]>
cegui 0.7 渲染改动 - սƵ2019|սع//www.pppqb.icu/xiaoxiaoling/archive/2010/04/27/113741.htmlclclclclTue, 27 Apr 2010 12:56:00 GMT//www.pppqb.icu/xiaoxiaoling/archive/2010/04/27/113741.html//www.pppqb.icu/xiaoxiaoling/comments/113741.html//www.pppqb.icu/xiaoxiaoling/archive/2010/04/27/113741.html#Feedback2//www.pppqb.icu/xiaoxiaoling/comments/commentRss/113741.html//www.pppqb.icu/xiaoxiaoling/services/trackbacks/113741.html一直想用ceguiQ但是没Z用,只是抽空看其代码

最q听朋友?.7 debug下数提?00多,挺惊讶的Q重新到久违了的官网上下?.7.1

看了下渲染的实现(GL)

首先Q添加了GeometryBuffer玩意Q得每个window保存了属于自q点和纹理信?/p>

然后在RenderingSurface中有GeometryBuffer队列Q得每个拥有AutoRenderingSurface属性的window有属于自q队列(默认只有FrameWindow才有)

而在drawself中执行的则是先通过looknfeelQ把需要渲染的信息丢到每个部g自己的GeometryBuffer里,然后把GeometryBuffer丢到RenderingSurface的队列中(一般ؓ

FrameWindow的GeometryBuffer队列Q每个面板就有自q渲染队列?

要知道以往都是只有一个队列的Q要渲染啥直接往里塞???br>q样一改就不必每个部件有更改都要全部重新清空渲染?/p>


再往后就是把每个H口队列里的GeometryBuffer渲染到各自的RenderingSurface表面上,q里要注意的是ƈ不是渲染到屏q上而是表面上,cegui在这里用了渲染到纹理,GL

用的是fbo实现的?/p>

注意RenderingSurface只有两个来源Q一是通过讄AutoRenderingSurface属性,另一个就是RenderingRoot了,RenderingRoot只有一个,在render中,通过W一个来源的?/p>

用的是fbo的渲染,而第二个来源则直接渲染到屏幕了?/p>

所有的q些执行完后可以渲染到屏幕了,通过RenderingRoot执行Q注意这里的RenderingRoot中的RenderTarget和之前的不一Pq里用的是OpenGLViewportTarget而不?/p>

OpenGLFBOTextureTarget?br>



clcl 2010-04-27 20:56 发表评论
]]>
[转]理解Ҏ - սƵ2019|սع//www.pppqb.icu/xiaoxiaoling/archive/2009/10/25/99425.htmlclclclclSun, 25 Oct 2009 09:15:00 GMT//www.pppqb.icu/xiaoxiaoling/archive/2009/10/25/99425.html//www.pppqb.icu/xiaoxiaoling/comments/99425.html//www.pppqb.icu/xiaoxiaoling/archive/2009/10/25/99425.html#Feedback0//www.pppqb.icu/xiaoxiaoling/comments/commentRss/99425.html//www.pppqb.icu/xiaoxiaoling/services/trackbacks/99425.html阅读全文

սƵ2019 2009-10-25 17:15 发表评论
]]>