提高UDP交互性能

这是一篇个人认为非常非常厉害的文章,取自这里。讲述了如何提升UDP流的处理速率,但实际涉及的技术点不仅仅限于UDP。这篇文章中涉及的技术正好可以把前段时间了解的知识串联起来。作者:Toshiaki Makita

讲述内容

  • 背景
  • 提升网络性能的基本技术
  • 如何提升UDP性能

作者介绍

Toshiaki Makita

  • NTT开源软件中心的Linux内核工程师
  • NTT集团公司的技术支持
  • 内核网络子系统的活跃补丁提交者

背景

因特网上UDP事务

  • 使用UDP的服务

    • DNS
    • RADIUS
    • NTP
    • SNMP等
  • 被大量网络服务提供商使用

以太网带宽和交互

  • 以太网带宽演进:

    • 10M -> 100M -> 1G -> 10G -> 40G -> 100G -> ...
    • 10G(或更大)的NIC在商用服务器上越来越普遍
  • 10G网络上的交互:
    • 最小报文的场景下:最大 14,880,952 个报文/s (最小的以太帧为64字节+ preamble+IFG 20bytes = 84 bytes = 672 bits,10,000,000,000 / 672 = 14,880,952)
    • 难以在单个服务器中处理

需要处理多少交互

  • UDP 负载大小

    • DNS

      • A/AAAA请求:40~字节
      • A/AAAA响应:100~字节
    • RADIUS
      • Access-Request:70~字节
      • Access-Accept:30~字节
      • 通常带有100个字节的属性
    • 大部分场景下为100个字节
  • 10G网络上100字节数据的交互
    • 最大7,530,120次交互/s (100 bytes + IP/UDP/Ether headers 46bytes + preamble+IFG 20bytes = 166 bytes = 1328 bits

      ,即10,000,000,000 / 1328 = 7,530,120)
    • 即使在少于最短的报文的情况下,但仍具有挑战性

提升网络性能的基本技术

TSO/GSO/GRO

  • 报文分割/聚合

  • 减少报文在服务中的处理

  • 适用于TCP 字节流(使用UDP隧道的TCP也可以)

  • 不适用于UDP数据报(除了UFO,其他都依赖物理NICs)

    • UDP在数据报之间有明确的界限
    • 不能分割/聚合报文

TSO/GSO用于发送报文时,将上层聚合的数据进行分割,分割为不大于MTU的报文;GRO在接受侧,将多个报文聚合为一个数据,上送给协议栈。总之就是将报文的处理下移到了网卡上,减少了网络栈的负担。

RSS

  • 在多核服务器上扩展了网络接收侧的处理
  • RSS本身是一个NIC特性
    • 将报文分发到一个NIC中的多个队列上
    • 每个队列都有一个不同的中断向量(不同队列的报文可以被不同的核处理)
  • 可以运用于TCP/UDP
  • 通常10G的NICs会支持RSS

RSS是物理网卡支持的特性,可以将NIC的多个队列映射到多个CPU核上进行处理,增加处理的效率,减少CPU中断竞争。

启用RSS的NIC的性能

  • 100字节UDP交互性能

    • 使用简单的echo多线程(线程数与核数相同,每个线程运行recvfrom()sendto()服务器进行测试
    • OS:内核4.6.3(RHEL 7.2环境)
    • 具有20个核心和10G NIC的中型商用服务器:
      • NIC:Intel 82599ES (含RSS, 最大64 个队列)
      • CPU:Xeon E5-2650 v3 (2.3 GHz 10 cores) * 2 sockets,禁用超线程
    • 结果:270,000 transactions/s (tps) (大概 360Mbps)
      • 10G带宽使用了3.6%

如何提升

确认瓶颈

  • sar -u ALL -P ALL 1

  • softirq仅在NUMA的Node0上运行,为什么?

    • 尽管可以为20个核提供足够(64个)的队列

可以在/proc/zoneinfo中查看NUMA的node信息。使用mpstat也可以看到类似的现象,%irq表示硬中断,%soft表示软中断。

RSS下的softirq

  • RSS会将报文分发到接收队列

  • 每个队列的中断目的地由/proc/irq/<irq>/smp_affinity确定

    RSS会将报文分发到不同的队列,smp_affinity会设置中断亲和性,将不同队列产生的中断上送给不同的CPU核。

  • 通常由irqbalance设置smp_affinity

校验smp_affinity

  • smp_affinity

  • irqbalance仅使用了Node 0(核0-4, 10-14),如何修改?

检查affinity_hint

  • 一些NIC驱动提供了affinity_hint

  • affinity_hint是均匀分布的

  • 为了显示该hint,可以在irqbalance(通过/etc/sysconfig/irqbalance)中添加"-h exact"选项

修改irqbalance选项

  • 添加"-h exact"并重启irqbalance服务

  • 可以看到irqs分布到了所有的核上。

  • sar -u ALL -P ALL 1

  • 虽然irqs看起来分布均匀,但16~19核却没有分配softirq

检查rx-queue状态

  • ethtool -S

    $ ethtool -S ens1f0 | grep 'rx_queue_.*_packets'
    rx_queue_0_packets: 198005155
    rx_queue_1_packets: 153339750
    rx_queue_2_packets: 162870095
    rx_queue_3_packets: 172303801
    rx_queue_4_packets: 153728776
    rx_queue_5_packets: 158138563
    rx_queue_6_packets: 164411653
    rx_queue_7_packets: 165924489
    rx_queue_8_packets: 176545406
    rx_queue_9_packets: 165340188
    rx_queue_10_packets: 150279834
    rx_queue_11_packets: 150983782
    rx_queue_12_packets: 157623687
    rx_queue_13_packets: 150743910
    rx_queue_14_packets: 158634344
    rx_queue_15_packets: 158497890
    rx_queue_16_packets: 4
    rx_queue_17_packets: 3
    rx_queue_18_packets: 0
    rx_queue_19_packets: 8
  • 可以看到RSS并没有将报文分发给队列16~19

RSS 间接表

  • RSS有一个间接表,用于确定分发的报文所属的队列

  • 可以使用ethtool -x命令查看(虚拟环境可能不支持)

  • 可以看到仅使用了015的接收队列,并没有使用1619的队列

  • 使用所有的0~19的队列

    # ethtool -X ens1f0 equal 20
    Cannot set RX flow hash configuration: Invalid argument
  • 间接表中该NIC的最大接收队列数为16,因此不能使用20个队列

    • 虽然有64个接收队列
  • 使用RPS替代

    • RSS的软件仿真

使用RPS

  • 现在给接收队列69上的流分配CPU69 和16~19,这两组CPU都位于Node1

    • rx-queue 6 -> core 6, 16

    • rx-queue 7 -> core 7, 17

    • rx-queue 8 -> core 8, 18

    • rx-queue 9 -> core 9, 19

# echo 10040 > /sys/class/net/ens1f0/queues/rx-6/rps_cpus
# echo 20080 > /sys/class/net/ens1f0/queues/rx-7/rps_cpus
# echo 40100 > /sys/class/net/ens1f0/queues/rx-8/rps_cpus
# echo 80200 > /sys/class/net/ens1f0/queues/rx-9/rps_cpus
  • sar -u ALL -P ALL 1

  • 此时软中断的分布几乎是均匀的

RSS & affinity_hint & RPS

  • 多亏了affinity_hint 和RPS,现在可以将流均匀地分发到不同的CPU核上。

  • 性能变化:

    • Before: 270,000 tps (大概 360Mbps)
    • After: 17,000 tps (大概 23Mbps)

    变的更差了。。

  • 可能的原因是软中断太多导致的

    • 软中断几乎占了100%的CPU
    • 需要更好地分析手段

分析软中断

  • perf

    • 内核树分析工具
    • 通过CPU采样定位热点
  • 举例:perf record -a -g -- sleep 5

    • 每5秒将结果输出到perf.data文件
  • 火焰图

  • CPU0的火焰图(结果经过了过滤)

    • X轴:CPU消耗
    • Y轴:调用深度

  • queued_spin_lock_slowpath:锁竞争

  • udp_queue_rcv_skb:要求socket锁

socket锁竞争

  • echo服务器在一个特定端口上仅绑定了一个socket

  • 每个内核的softirq同时将报文推入socket队列

  • 最终导致socket锁竞争

避免锁竞争

  • 使用SO_REUSEPORT选项分割sockets

    • 该选项在内核3.9引入,默认使用流(报文首部)哈希来选择socket

  • SO_REUSEPORT允许多个UDP socket绑定到相同的端口上

    • 在每个报文排队时选择一个套接字

      int on = 1;
      int sock = socket(AF_INET, SOCK_DGRAM, 0);
      setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(on));
      bind(sock, ...);

      SO_REUSEPORT的介绍可以参考这篇文章

使用SO_REUSEPORT

  • sar -u ALL -P ALL 1

  • 此时软中断消耗的CPU就比较合理了,从下面火焰图可以看到中断处理消耗的CPU缩短了

  • 性能变化

    • RSS: 270,000 tps (大概 360Mbps)
    • +affinity_hint+RPS: 17,000 tps (大概 23Mbps)
    • +SO_REUSEPORT: 2,540,000 tps (大概 3370Mbps)
  • 进一步分析:

  • 可以看到,仍然有socket锁竞争。SO_REUSEPORT默认使用流哈希来选择队列,不同的CPU核可能会选择相同的sockets,导致竞争。

避免socket锁竞争

  • 根据CPU核号选择socket

    • 通过SO_ATTACH_REUSEPORT_CBPF/EBPF实现
    • 在内核4.5引入上述功能

  • 此时软中断之间不再产生竞争

  • 用法可以参见内核源码树中的例子:tools /testing/selftests /net /reuseport_bpf_cpu.c

  • 启用SO_ATTACH_REUSEPORT_EPBF前后的火焰图如下,可以看到中断消耗的CPU更少了

  • 性能变化:

    • RSS: 270,000 tps (approx. 360Mbps)
    • +affinity_hint+RPS: 17,000 tps (大概 23Mbps)
    • +SO_REUSEPORT: 2,540,000 tps (大概 3370Mbps)
    • +SO_ATTACH_...: 4,250,000 tps (大概 5640Mbps)

固定用户线程

  • 用户线程数:sockets数 == 1:1,但不一定与软中断处于同一CPU核

  • 将用户现场固定到相同的核,获得更好的缓存亲和性。可以使用cgroup, taskset, pthread_setaffinity_np()等方式

  • 性能变化

    • RSS: 270,000 tps (approx. 360Mbps)
    • +affinity_hint+RPS: 17,000 tps (大概 23Mbps)
    • +SO_REUSEPORT: 2,540,000 tps (大概 3370Mbps)
    • +SO_ATTACH_...: 4,250,000 tps (大概 5640Mbps)
    • +Pin threads: 5,050,000 tps (大概 6710Mbps)

输出方向的锁

  • 到目前为止解决的问题都处在接收方向上
  • 发送方向是否有锁竞争?

Tx队列

  • 内核具有Qdisc(默认的Qdisc为pfifo_fast)
  • 每个Qdisc都连接到NIC的tx队列
  • 每个Qdisc都有自己的锁

Tx队列的锁竞争

  • Qdisc默认通过流哈希进行选择
  • 因此可能会发送锁竞争

  • 但并没有在输出方向上看到锁竞争,为什么?

避免Tx队列的锁竞争

  • 这是因为ixgbe(Intel 10GbE NIC驱动)可以自动设置XPS

  • XPS允许内核选择根据CPU核号选择Tx队列(Qdisc)

  • 因此发送方向没有锁竞争

XPS的影响如何

  • 禁用XPS

    # for ((txq=0; txq<20; txq++)); do
    > echo 0 > /sys/class/net/ens1f0/queues/tx-$txq/xps_cpus
    > done
    • Before: 5,050,000 tps (大概 6710Mbps)
    • After: 1,086,000 tps (大概 1440Mbps)

    可见有近5倍的性能差距,且从火焰图看,产生了大量锁竞争

重新启用XPS

  • 启动XPS。XPS的工作方式其实与RPS类似

    # echo 00001 > /sys/class/net/<NIC>/queues/tx-0/xps_cpus
    # echo 00002 > /sys/class/net/<NIC>/queues/tx-1/xps_cpus
    # echo 00004 > /sys/class/net/<NIC>/queues/tx-2/xps_cpus
    # echo 00008 > /sys/class/net/<NIC>/queues/tx-3/xps_cpus
    ...
  • 尽管ixgbe可以自动设置XPS,但并不是所有的驱动都可以

  • 确保配置了xps_cpus

优化单个核 1

  • 为了完全利用多核,并避免竞争,性能达到了5,050,000 tps (大概 6710Mbps)
  • 为了进一步提高性能,需要降低单个核的开销

  • 可以看到默认启用了GRO,并消耗了4.9%的CPU时间。

  • GRO并不适用于UDP(UDP隧道除外,如VXLAN)

  • 为UDP服务禁用GRO

    # ethtool -K <NIC> gro off
  • 警告:

    • 如果关注TCP性能,则不能禁用GRO功能

      • 禁用GRO会导致TCP接收吞吐量降低
    • 在KVM 虚拟化管理系统上也不要禁用GRO
      • GRO提高了隧道协议流量以及虚拟机管理程序上的guest TCP流量的吞吐量

禁用GRO

  • 性能变化

    • RSS (+XPS): 270,000 tps (大概 360Mbps)

    • +affinity_hint+RPS: 17,000 tps (大概 23Mbps)

    • +SO_REUSEPORT: 2,540,000 tps (大概 3370Mbps)

    • +SO_ATTACH_...: 4,250,000 tps (大概 5640Mbps)

    • +Pin threads: 5,050,000 tps (大概 6710Mbps)

    • +Disable GRO: 5,180,000 tps (大概 6880Mbps)

优化单个核 2

  • 可以看到执行了iptables相关的操作

    • 此时并不需要任何iptables
  • iptables消耗了3%的CPU

  • 由于iptables是内核加载的模块,即使用户不需要任何规则,它内部也会消耗一部分CPU

  • 即使不添加任何规则,某些发行版也会加载iptables模块

  • 如果不需要iptables,则卸载该模块

    # modprobe -r iptable_filter
    # modprobe -r ip_tables
  • 性能变化

    • RSS (+XPS): 270,000 tps (大概 360Mbps)

    • +affinity_hint+RPS: 17,000 tps (大概 23Mbps)

    • +SO_REUSEPORT: 2,540,000 tps (大概 3370Mbps)

    • +SO_ATTACH_...: 4,250,000 tps (大概 5640Mbps)

    • +Pin threads: 5,050,000 tps (大概 6710Mbps)

    • +Disable GRO: 5,180,000 tps (大概 6880Mbps)

    • +Unload iptables: 5,380,000 tps (大概 7140Mbps)

优化单个核3

  • 在接收路径上,FIB查询了两次。每次消耗1.82%~的CPU时间。其中以此用于校验源IP地址:

    • 反向路径过滤器
    • 本地地址校验
  • 如果不需要源校验,则可以忽略

    # sysctl -w net.ipv4.conf.all.rp_filter=0
    # sysctl -w net.ipv4.conf.<NIC>.rp_filter=0
    # sysctl -w net.ipv4.conf.all.accept_local=1
  • 性能变化

    • RSS (+XPS): 270,000 tps (大概 360Mbps)

    • +affinity_hint+RPS: 17,000 tps (大概 23Mbps)

    • +SO_REUSEPORT: 2,540,000 tps (大概 3370Mbps)

    • +SO_ATTACH_...: 4,250,000 tps (大概 5640Mbps)

    • +Pin threads: 5,050,000 tps (大概 6710Mbps)

    • +Disable GRO: 5,180,000 tps (大概 6880Mbps)

    • +Unload iptables: 5,380,000 tps (大概 7140Mbps)

    • +Disable validation: 5,490,000 tps (大概 7290Mbps)

优化单个核4

  • 当大量处理报文时,Audit消耗的CPU会变大。大概消耗2.5%的CPU时间

  • 如果不需要audit,则禁用

    # systemctl disable auditd
    # reboot
  • 性能变化

    • RSS (+XPS): 270,000 tps (大概 360Mbps)

    • +affinity_hint+RPS: 17,000 tps (大概 23Mbps)

    • +SO_REUSEPORT: 2,540,000 tps (大概 3370Mbps)

    • +SO_ATTACH_...: 4,250,000 tps (大概 5640Mbps)

    • +Pin threads: 5,050,000 tps (大概 6710Mbps)

    • +Disable GRO: 5,180,000 tps (大概 6880Mbps)

    • +Unload iptables: 5,380,000 tps (大概 7140Mbps)

    • +Disable validation: 5,490,000 tps (大概 7290Mbps)

    • +Disable audit: 5,860,000 tps (大概 7780Mbps)

优化单个核5

  • IP ID字段计算(__ip_select_ident)消耗的CPU比较多,消耗大概4.82%的CPU

  • 该字段用于解决特定环境下的问题

    • 如果很多客户端使用了相同的IP地址

      • 原子操作会造成缓存竞争
    • 如果不使用隧道协议,很可能看不到如此大量的CPU消耗
  • 如果真的碰到这种问题

    • 只有在不发送大于MTU的报文时才可以跳过它

      • 虽然非常严格

        int pmtu = IP_PMTUDISC_DO;
        setsockopt(sock, IPPROTO_IP, IP_MTU_DISCOVER, &pmtu, sizeof(pmtu));
  • 性能变化

    • RSS (+XPS): 270,000 tps (大概 360Mbps)

    • +affinity_hint+RPS: 17,000 tps (大概 23Mbps)

    • +SO_REUSEPORT: 2,540,000 tps (大概 3370Mbps)

    • +SO_ATTACH_...: 4,250,000 tps (大概 5640Mbps)

    • +Pin threads: 5,050,000 tps (大概 6710Mbps)

    • +Disable GRO: 5,180,000 tps (大概 6880Mbps)

    • +Unload iptables: 5,380,000 tps (大概 7140Mbps)

    • +Disable validation: 5,490,000 tps (大概 7290Mbps)

    • +Disable audit: 5,860,000 tps (大概 7780Mbps)

    • +Skip ID calculation: 6,010,000 tps (大概 7980Mbps)

超线程

  • 目前还没有启用超线程

  • 启用之后的逻辑核为40个

    • 物理核为20个
  • 需要给40个核配置RPS

    • 提示:最大可用的接收队列为16
  • 启用超线程,并在所有的接收队列上设置RPS

    • queue 0 -> core 0, 20

    • queue 1 -> core 1, 21

    • ...

    • queue 10 -> core 10, 16, 30

    • queue 11 -> core 11, 17, 31

    • ...

  • 性能变化

    • RSS (+XPS): 270,000 tps (大概 360Mbps)

    • +affinity_hint+RPS: 17,000 tps (大概 23Mbps)

    • +SO_REUSEPORT: 2,540,000 tps (大概 3370Mbps)

    • +SO_ATTACH_...: 4,250,000 tps (大概 5640Mbps)

    • +Pin threads: 5,050,000 tps (大概 6710Mbps)

    • +Disable GRO: 5,180,000 tps (大概 6880Mbps)

    • +Unload iptables: 5,380,000 tps (大概 7140Mbps)

    • +Disable validation: 5,490,000 tps (大概 7290Mbps)

    • +Disable audit: 5,860,000 tps (大概 7780Mbps)

    • +Skip ID calculation: 6,010,000 tps (大概 7980Mbps)

    • +Hyper threading: 7,010,000 tps (大概 9310Mbps)

  • 猜测,如果更多的rx队列可能会获得更好的性能

更多热点1

  • Tx Qdisc锁(_raw_spin_lock)的消耗比较严重
  • 没有竞争,但出现了很多原子操作
  • 在Linux netdev社区中进行优化

更多热点2

  • slab内存申请和释放
  • 在Linux netdev社区中进行优化

其他挑战

  • UDP服务器的环境为guest
  • Hypervisor可能使CPU饱和或丢弃报文

总结

  • 对于100字节的数据,可以达到几乎10G的速率

    • 从:270,000 tps (approx. 360Mbps)
    • 到:7,010,000 tps (approx. 9310Mbps)
  • 提高UDP性能

    • 应用(最关键)

      • 实现SO_REUSEPORT
      • 实现SO_ATTACH_REUSEPORT_EBPF/CBPF
      • 对TCP监听socket同样有效
    • OS设置

      • 检查smp_affinity

      • 如果rx队列不足,则使用RPS

      • 确保配置了XPS

      • 考虑如下降低单核开销的方法

        • Disable GRO

        • Unload iptables

        • Disable source IP validation

        • Disable auditd

  • 硬件

    • 如果可能,使用具有足够RSS接收队列的NICs(如核数相同的队列)

Boost UDP Transaction Performance的更多相关文章

  1. TCP/UDP端口列表

    http://zh.wikipedia.org/wiki/TCP/UDP%E7%AB%AF%E5%8F%A3%E5%88%97%E8%A1%A8 TCP/UDP端口列表     本条目可通过翻译外语维 ...

  2. TCP/UDP 常用端口列表

    计算机之间依照互联网传输层TCP/IP协议不同的协议通信,都有不同的对应端口.所以,利用短信(datagram)的UDP,所采用的端口号码不一定和采用TCP的端口号码一样.以下为两种通信协议的端口列表 ...

  3. TCP/UDP端口列表(WIKIpedia)

    计算机之间依照互联网传输层TCP/IP协议不同的协议通信,都有不同的对应端口.所以,利用短信(datagram)的UDP,所采用的端口号码不一定和采用TCP的端口号码一样.以下为两种通信协议的端口列表 ...

  4. always NetWork Performance measure Tools

    1,iperf key feature:Measuring TCP and UDP BandWidth Performance Iperf features; *TCP .Measure bandwi ...

  5. Folly: Facebook Open-source Library Readme.md 和 Overview.md(感觉包含的东西并不多,还是Boost更有用)

    folly/ For a high level overview see the README Components Below is a list of (some) Folly component ...

  6. JDK16关于TCP和UDP的优化

    文章转自belaban.blogspot.com Double your performance: virtual threads (fibers) and JDK 15/16!If you use ...

  7. (转)TCP注册端口号大全

    分类: 网络与安全 cisco-sccp 2000/tcp Cisco SCCPcisco-sccp 2000/udp Cisco SCCp# Dan Wing <dwing&cisco ...

  8. LoadRunner面试题

    在LoadRunner中为什么要设置思考时间和pacing 答: 录制时记录的是客户端和服务端的交互,如果要精确模拟 用户的行为,那么客户操作客户端时花费了很多时间要怎么模拟呢?录入 填写提交的内容, ...

  9. 网络-05-端口号-F5-负载均衡设-linux端口详解大全--TCP注册端口号大全备

    [root@test1:Standby] config # [root@test1:Standby] config # [root@test1:Standby] config # [root@test ...

随机推荐

  1. JavaScript封装一个函数效果类似内置方法concat()

    JavaScript封装一个函数效果类似内置方法concat() 首先回忆concat()的作用: concat() 方法用于连接两个或多个数组.该方法不会改变现有的数组,而仅仅会返回被连接数组的一个 ...

  2. MySQL索引结构之B+树索引(面)

    首先要明白索引(index)是在存储引擎(storage engine)层面实现的,而不是server层面.不是所有的存储引擎都支持所有的索引类型.即使多个存储引擎支持某一索引类型,它们的实现和行为也 ...

  3. Android10_原理机制系列_Binder机制

    前言 Binder 从java到c++到kernel,涉及的内容很多,很难在一篇文章中说清楚.这篇主要是自我记录,方便后续查询并拆分总结的. 因为涉及的的确非常多,不能面面俱到,所以可能一些地方感觉比 ...

  4. Python:利用Entrez库筛选下载PubMed文献摘要

    一个不是学生物的孩子来搞生物,当真是变成了一块废铁啊,但也是让我体会到了一把生物信息的力量. 废话不多说,开整! 任务:快速高效从PubMed上下载满足条件的文献PMID.标题(TI).摘要(AB). ...

  5. 应届生应聘阿里,腾讯,美团90%会被问到的Netty面试题!史上最全系列!

    1.BIO.NIO 和 AIO 的区别? BIO:一个连接一个线程,客户端有连接请求时服务器端就需要启动一个线程进行处理.线程开销大.伪异步 IO:将请求连接放入线程池,一对多,但线程还是很宝贵的资源 ...

  6. 用大白话讲大数据HBase,老刘真的很用心(1)

    老刘今天复习HBase知识发现很多资料都没有把概念说清楚,有很多专业名词一笔带过没有解释.比如这个框架高性能.高可用,那什么是高性能高可用?怎么实现的高性能高可用?没说! 如果面试官听了你说的,会有什 ...

  7. Java进阶专题(十七) 系统缓存架构设计 (上)

    前言 ​ 我们将先从Redis.Nginx+Lua等技术点出发,了解缓存应用的场景.通过使用缓存相关技术,解决高并发的业务场景案例,来深入理解一套成熟的企业级缓存架构如何设计的.本文Redis部分总结 ...

  8. 【linux】串口通讯工具-minicom简介+简单操作

    目录 前言 简介 尝试运行 配置 minicom 运行 minicom minicom 其它操作 前言 windows 上有不少的串口通信工具了,今天介绍一个linux下的一个串口通信工具-minic ...

  9. nginx负载均衡配置详解

    已经了解了负载均衡的常用算法:轮询,加权轮询,热备等... 接下来就看看具体怎么配置. upstream配置是写一组被代理的服务器地址,然后配置负载均衡的算法. upstream mysvr{ ser ...

  10. Codeforces Round #488 by NEAR (Div. 2)

    A 开个桶记录是否出现即可. 时间复杂度 \(O\left(n+m\right)\). B 按能力值从小到大依次加入,然后维护前 \(k\) 大的金币数即可. 时间复杂度 \(O\left(n\log ...