100万并发连接服务器笔记之Java Netty处理1M连接会怎么样

【网络编程】一文搞定Netty,打造单机百万连接测试! 一文搞定Netty,打造单机百万连接测试! 阅读详情

五 100万并发连接服务器笔记之Java Netty处理1M连接会怎么样

2014年05月21日 14:13:56 mergerly 阅读数:20545

前言

每一种该语言在某些极限情况下的表现一般都不太一样,那么我常用的Java语言,在达到100万个并发连接情况下,会怎么样呢,有些好奇,更有些期盼。
这次使用经常使用的顺手的netty NIO框架(netty-3.6.5.Final),封装的很好,接口很全面,就像它现在的域名 netty.io,专注于网络IO。
整个过程没有什么技术含量,浅显分析过就更显得有些枯燥无聊,准备好,硬着头皮吧。

测试服务器配置

运行在VMWare Workstation 9中,64位Centos 6.2系统,分配14.9G内存左右,4核。
已安装有Java7版本:

 
  1. java version "1.7.0_21"

  2. Java(TM) SE Runtime Environment (build 1.7.0_21-b11)

  3. Java HotSpot(TM) 64-Bit Server VM (build 23.21-b01, mixed mode)

在/etc/sysctl.conf中添加如下配置:

 
  1. fs.file-max = 1048576

  2. net.ipv4.ip_local_port_range = 1024 65535

  3. net.ipv4.tcp_mem = 786432 2097152 3145728

  4. net.ipv4.tcp_rmem = 4096 4096 16777216

  5. net.ipv4.tcp_wmem = 4096 4096 16777216

  6.  
  7. net.ipv4.tcp_tw_reuse = 1

  8. net.ipv4.tcp_tw_recycle = 1

在/etc/security/limits.conf中添加如下配置:

 
  1. * soft nofile 1048576

  2. * hard nofile 1048576

测试端

测试端无论是配置还是程序和以前一样,翻看前几篇博客就可以看到client5.c的源码,以及相关的配置信息等。

服务器程序

这次也是很简单呐,没有业务功能,客户端HTTP请求,服务端输出chunked编码内容。

入口HttpChunkedServer.java:

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465
 

package com.test.server;

 

import static org.jboss.netty.channel.Channels.pipeline;

 

import java.net.InetSocketAddress;

import java.util.concurrent.Executors;

 

import org.jboss.netty.bootstrap.ServerBootstrap;

import org.jboss.netty.channel.ChannelPipeline;

import org.jboss.netty.channel.ChannelPipelineFactory;

import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;

import org.jboss.netty.handler.codec.http.HttpChunkAggregator;

import org.jboss.netty.handler.codec.http.HttpRequestDecoder;

import org.jboss.netty.handler.codec.http.HttpResponseEncoder;

import org.jboss.netty.handler.stream.ChunkedWriteHandler;

 

public class HttpChunkedServer {

private final int port;

 

public HttpChunkedServer(int port) {

this.port = port;

}

 

public void run() {

// Configure the server.

ServerBootstrap bootstrap = new ServerBootstrap(

new NioServerSocketChannelFactory(

Executors.newCachedThreadPool(),

Executors.newCachedThreadPool()));

 

// Set up the event pipeline factory.

bootstrap.setPipelineFactory(new ChannelPipelineFactory() {

public ChannelPipeline getPipeline() throws Exception {

ChannelPipeline pipeline = pipeline();

 

pipeline.addLast("decoder", new HttpRequestDecoder());

pipeline.addLast("aggregator", new HttpChunkAggregator(65536));

pipeline.addLast("encoder", new HttpResponseEncoder());

pipeline.addLast("chunkedWriter", new ChunkedWriteHandler());

 

pipeline.addLast("handler", new HttpChunkedServerHandler());

return pipeline;

}

});

 

bootstrap.setOption("child.reuseAddress", true);

bootstrap.setOption("child.tcpNoDelay", true);

bootstrap.setOption("child.keepAlive", true);

 

// Bind and start to accept incoming connections.

bootstrap.bind(new InetSocketAddress(port));

}

 

public static void main(String[] args) {

int port;

if (args.length > 0) {

port = Integer.parseInt(args[0]);

} else {

port = 8080;

}

 

System.out.format("server start with port %d \n", port);

new HttpChunkedServer(port).run();

}

}

view rawHttpChunkedServer.java hosted with ❤ by GitHub

唯一的自定义处理器HttpChunkedServerHandler.java:

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
 

package com.test.server;

 

import static org.jboss.netty.handler.codec.http.HttpHeaders.Names.CONTENT_TYPE;

import static org.jboss.netty.handler.codec.http.HttpMethod.GET;

import static org.jboss.netty.handler.codec.http.HttpResponseStatus.BAD_REQUEST;

import static org.jboss.netty.handler.codec.http.HttpResponseStatus.METHOD_NOT_ALLOWED;

import static org.jboss.netty.handler.codec.http.HttpResponseStatus.OK;

import static org.jboss.netty.handler.codec.http.HttpVersion.HTTP_1_1;

 

import java.util.concurrent.atomic.AtomicInteger;

 

import org.jboss.netty.buffer.ChannelBuffer;

import org.jboss.netty.buffer.ChannelBuffers;

import org.jboss.netty.channel.Channel;

import org.jboss.netty.channel.ChannelFutureListener;

import org.jboss.netty.channel.ChannelHandlerContext;

import org.jboss.netty.channel.ChannelStateEvent;

import org.jboss.netty.channel.ExceptionEvent;

import org.jboss.netty.channel.MessageEvent;

import org.jboss.netty.channel.SimpleChannelUpstreamHandler;

import org.jboss.netty.handler.codec.frame.TooLongFrameException;

import org.jboss.netty.handler.codec.http.DefaultHttpChunk;

import org.jboss.netty.handler.codec.http.DefaultHttpResponse;

import org.jboss.netty.handler.codec.http.HttpChunk;

import org.jboss.netty.handler.codec.http.HttpHeaders;

import org.jboss.netty.handler.codec.http.HttpRequest;

import org.jboss.netty.handler.codec.http.HttpResponse;

import org.jboss.netty.handler.codec.http.HttpResponseStatus;

import org.jboss.netty.util.CharsetUtil;

 

public class HttpChunkedServerHandler extends SimpleChannelUpstreamHandler {

private static final AtomicInteger count = new AtomicInteger(0);

 

private void increment() {

System.out.format("online user %d\n", count.incrementAndGet());

}

 

private void decrement() {

if (count.get() <= 0) {

System.out.format("~online user %d\n", 0);

} else {

System.out.format("~online user %d\n", count.decrementAndGet());

}

}

 

@Override

public void messageReceived(ChannelHandlerContext ctx, MessageEvent e)

throws Exception {

HttpRequest request = (HttpRequest) e.getMessage();

if (request.getMethod() != GET) {

sendError(ctx, METHOD_NOT_ALLOWED);

return;

}

 

sendPrepare(ctx);

increment();

}

 

@Override

public void channelDisconnected(ChannelHandlerContext ctx,

ChannelStateEvent e) throws Exception {

decrement();

super.channelDisconnected(ctx, e);

}

 

@Override

public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e)

throws Exception {

Throwable cause = e.getCause();

if (cause instanceof TooLongFrameException) {

sendError(ctx, BAD_REQUEST);

return;

}

}

 

private static void sendError(ChannelHandlerContext ctx,

HttpResponseStatus status) {

HttpResponse response = new DefaultHttpResponse(HTTP_1_1, status);

response.setHeader(CONTENT_TYPE, "text/plain; charset=UTF-8");

response.setContent(ChannelBuffers.copiedBuffer(

"Failure: " + status.toString() + "\r\n", CharsetUtil.UTF_8));

 

// Close the connection as soon as the error message is sent.

ctx.getChannel().write(response)

.addListener(ChannelFutureListener.CLOSE);

}

 

private void sendPrepare(ChannelHandlerContext ctx) {

HttpResponse response = new DefaultHttpResponse(HTTP_1_1, OK);

response.setChunked(true);

response.setHeader(HttpHeaders.Names.CONTENT_TYPE,

"text/html; charset=UTF-8");

response.addHeader(HttpHeaders.Names.CONNECTION,

HttpHeaders.Values.KEEP_ALIVE);

response.setHeader(HttpHeaders.Names.TRANSFER_ENCODING,

HttpHeaders.Values.CHUNKED);

 

Channel chan = ctx.getChannel();

chan.write(response);

 

// 缓冲必须凑够256字节,浏览器端才能够正常接收 ...

StringBuilder builder = new StringBuilder();

builder.append("<html><body><script>var _ = function (msg) { parent.s._(msg, document); };</script>");

int leftChars = 256 - builder.length();

for (int i = 0; i < leftChars; i++) {

builder.append(" ");

}

 

writeStringChunk(chan, builder.toString());

}

 

private void writeStringChunk(Channel channel, String data) {

ChannelBuffer chunkContent = ChannelBuffers.dynamicBuffer(channel

.getConfig().getBufferFactory());

chunkContent.writeBytes(data.getBytes());

HttpChunk chunk = new DefaultHttpChunk(chunkContent);

 

channel.write(chunk);

}

}

view rawHttpChunkedServerHandler.java hosted with ❤ by GitHub

启动脚本start.sh

12
 

set CLASSPATH=.

nohup java -server -Xmx6G -Xms6G -Xmn600M -XX:PermSize=50M -XX:MaxPermSize=50M -Xss256K -XX:+DisableExplicitGC -XX:SurvivorRatio=1 -XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:+CMSParallelRemarkEnabled -XX:+UseCMSCompactAtFullCollection -XX:CMSFullGCsBeforeCompaction=0 -XX:+CMSClassUnloadingEnabled -XX:LargePageSizeInBytes=128M -XX:+UseFastAccessorMethods -XX:+UseCMSInitiatingOccupancyOnly -XX:CMSInitiatingOccupancyFraction=80 -XX:SoftRefLRUPolicyMSPerMB=0 -XX:+PrintClassHistogram -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintHeapAtGC -Xloggc:gc.log -Djava.ext.dirs=lib com.test.server.HttpChunkedServer 8000 >server.out 2>&1 &

view rawstart.sh hosted with ❤ by GitHub

达到100万并发连接时的一些信息

每次服务器端达到一百万个并发持久连接之后,然后关掉测试端程序,断开所有的连接,等到服务器端日志输出在线用户为0时,再次重复以上步骤。在这反反复复的情况下,观察内存等信息的一些情况。以某次断开所有测试端为例后,当前系统占用为(设置为list_free_1):

 
  1. total used free shared buffers cached

  2. Mem: 15189 7736 7453 0 18 120

  3. -/+ buffers/cache: 7597 7592

  4. Swap: 4095 948 3147

通过top观察,其进程相关信息

 
  1. PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND

  2. 4925 root 20 0 8206m 4.3g 2776 S 0.3 28.8 50:18.66 java

在启动脚本start.sh中,我们设置堆内存为6G。

ps aux|grep java命令获得信息:

  root      4925 38.0 28.8 8403444 4484764 ?     Sl   15:26  50:18 java -server...HttpChunkedServer 8000

RSS占用内存为4484764K/1024K=4379M

然后再次启动测试端,在服务器接收到online user 1023749时,ps aux|grep java内容为:

  root      4925 43.6 28.4 8403444 4422824 ?     Sl   15:26  62:53 java -server...

查看当前网络信息统计

 
  1. ss -s

  2. Total: 1024050 (kernel 1024084)

  3. TCP: 1023769 (estab 1023754, closed 2, orphaned 0, synrecv 0, timewait 0/0), ports 12

  4.  
  5. Transport Total IP IPv6

  6. * 1024084 - -

  7. RAW 0 0 0

  8. UDP 7 6 1

  9. TCP 1023767 12 1023755

  10. INET 1023774 18 1023756

  11. FRAG 0 0 0

通过top查看一下

 
  1. top -p 4925

  2. top - 17:51:30 up 3:02, 4 users, load average: 1.03, 1.80, 1.19

  3. Tasks: 1 total, 0 running, 1 sleeping, 0 stopped, 0 zombie

  4. Cpu0 : 0.9%us, 2.6%sy, 0.0%ni, 52.9%id, 1.0%wa, 13.6%hi, 29.0%si, 0.0%st

  5. Cpu1 : 1.4%us, 4.5%sy, 0.0%ni, 80.1%id, 1.9%wa, 0.0%hi, 12.0%si, 0.0%st

  6. Cpu2 : 1.5%us, 4.4%sy, 0.0%ni, 80.5%id, 4.3%wa, 0.0%hi, 9.3%si, 0.0%st

  7. Cpu3 : 1.9%us, 4.4%sy, 0.0%ni, 84.4%id, 3.2%wa, 0.0%hi, 6.2%si, 0.0%st

  8. Mem: 15554336k total, 15268728k used, 285608k free, 3904k buffers

  9. Swap: 4194296k total, 1082592k used, 3111704k free, 37968k cached

  10.  
  11. PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND

  12. 4925 root 20 0 8206m 4.2g 2220 S 3.3 28.4 62:53.66 java

四核都被占用了,每一个核心不太平均。这是在虚拟机中得到结果,可能真实服务器会更好一些。 因为不是CPU密集型应用,CPU不是问题,无须多加关注。

系统内存状况

 
  1. free -m

  2. total used free shared buffers cached

  3. Mem: 15189 14926 263 0 5 56

  4. -/+ buffers/cache: 14864 324

  5. Swap: 4095 1057 3038

物理内存已经无法满足要求了,占用了1057M虚拟内存。

查看一下堆内存情况

 
  1. jmap -heap 4925

  2. Attaching to process ID 4925, please wait...

  3. Debugger attached successfully.

  4. Server compiler detected.

  5. JVM version is 23.21-b01

  6.  
  7. using parallel threads in the new generation.

  8. using thread-local object allocation.

  9. Concurrent Mark-Sweep GC

  10.  
  11. Heap Configuration:

  12. MinHeapFreeRatio = 40

  13. MaxHeapFreeRatio = 70

  14. MaxHeapSize = 6442450944 (6144.0MB)

  15. NewSize = 629145600 (600.0MB)

  16. MaxNewSize = 629145600 (600.0MB)

  17. OldSize = 5439488 (5.1875MB)

  18. NewRatio = 2

  19. SurvivorRatio = 1

  20. PermSize = 52428800 (50.0MB)

  21. MaxPermSize = 52428800 (50.0MB)

  22. G1HeapRegionSize = 0 (0.0MB)

  23.  
  24. Heap Usage:

  25. New Generation (Eden + 1 Survivor Space):

  26. capacity = 419430400 (400.0MB)

  27. used = 308798864 (294.49354553222656MB)

  28. free = 110631536 (105.50645446777344MB)

  29. 73.62338638305664% used

  30. Eden Space:

  31. capacity = 209715200 (200.0MB)

  32. used = 103375232 (98.5863037109375MB)

  33. free = 106339968 (101.4136962890625MB)

  34. 49.29315185546875% used

  35. From Space:

  36. capacity = 209715200 (200.0MB)

  37. used = 205423632 (195.90724182128906MB)

  38. free = 4291568 (4.0927581787109375MB)

  39. 97.95362091064453% used

  40. To Space:

  41. capacity = 209715200 (200.0MB)

  42. used = 0 (0.0MB)

  43. free = 209715200 (200.0MB)

  44. 0.0% used

  45. concurrent mark-sweep generation:

  46. capacity = 5813305344 (5544.0MB)

  47. used = 4213515472 (4018.321487426758MB)

  48. free = 1599789872 (1525.6785125732422MB)

  49. 72.48054631000646% used

  50. Perm Generation:

  51. capacity = 52428800 (50.0MB)

  52. used = 5505696 (5.250640869140625MB)

  53. free = 46923104 (44.749359130859375MB)

  54. 10.50128173828125% used

  55.  
  56. 1439 interned Strings occupying 110936 bytes.

老生代占用内存为72%,较为合理,毕竟系统已经处理100万个连接。

再次断开所有测试端,看看系统内存(free -m)

 
  1. total used free shared buffers cached

  2. Mem: 15189 7723 7466 0 13 120

  3. -/+ buffers/cache: 7589 7599

  4. Swap: 4095 950 3145

记为list_free_2。

list_free_1和list_free_2两次都释放后的内存比较结果,系统可用物理已经内存已经降到7589M,先前可是7597M物理内存。
总之,我们的JAVA测试程序在内存占用方面已经,最低需要7589 + 950 = 8.6G内存为最低需求内存吧。

GC日志

我们在启动脚本处设置的一大串参数,到底是否达到目标,还得从gc日志处获得具体效果,推荐使用GCViewer。

GC事件概览:
gc_eventdetails

其它:
gc_total_1 gc_total_2 gc_total_3

总之:

  • 只进行了一次Full GC,代价太高,停顿了12秒。
  • PartNew成为了停顿大户,导致整个系统停顿了41秒之久,不可接受。
  • 当前JVM调优喜忧参半,还得继续努力等

小结

Java与与Erlang、C相比,比较麻烦的事情,需要在程序一开始就得准备好它的堆栈到底需要多大空间,换个说法就是JVM启动参数设置堆内存大小,设置合适的垃圾回收机制,若以后程序需要更多内存,需停止程序,编辑启动参数,然后再次启动。总之一句话,就是麻烦。单单JVM的调优,就得持续不断的根据检测、信息、日志等进行适当微调。

  • JVM需要提前指定堆大小,相比Erlang/C,这可能是个麻烦
  • GC(垃圾回收),相对比麻烦,需要持续不断的根据日志、JVM堆栈信息、运行时情况进行JVM参数微调
  • 设置一个最大连接目标,多次测试达到顶峰,然后释放所有连接,反复观察内存占用,获得一个较为合适的系统运行内存值
  • Eclipse Memory Analyzer结合jmap导出堆栈DUMP文件,分析内存泄漏,还是很方便的
  • 想修改运行时内容,或者称之为热加载,默认不可能
  • 真实机器上会有更好的反映

吐槽一下:
JAVA OSGI,相对比Erlang来说,需要人转换思路,不是那么原生的东西,总是有些别扭,社区或商业公司对此的修修补补,不过是实现一些面向对象所不具备的热加载的企业特性。

测试源代码,下载just_test。

Netty实战三-如何让单机下Netty支持百万长连接?,java语法基础实验 毕竟工作也这么久了 ,除了途虎一轮,也七七八八面试了不少大厂,像阿里、饿了么、美团、滴滴这些面试过程就不一一写在这篇文章上了。我会整理一份详细的面试过程及大家想知道的一些问题细节。 阅读详情

相关推荐

【原创理论】Stochastic Coupled Dyadic System (SCDS):一个用于两性关系动力学建模的随机耦合系统框架

基于二人爱情耦合系统动力学、稳定性与最优策略的综合性理论的数值模拟与分析

weixin_44695861的博客 1134

用Netty实现单机百万TCP长连接

一 服务实现模型 单机百万连接有多种方式, 这里采用一个netty server 占用8888 端口,用客户端机器模拟百万客户端连接 模拟实现的方式 以下是示意图 如果一台客户端模拟3万个连接,那么100万连接,大致需要33台主机,找到33台主机的确是个困难,但是这种模型定下来,能够先实现若干台主机模拟连接也行,毕竟模型定了,剩下的只是客户主机数量的问题。 二...

jackhu专栏 2万+

解决PubMed卡在“正在检查浏览器”页面的完整排查指南

DNS解析是将域名转换为IP地址的基础网络服务,其稳定性和准确性直接影响网站访问。当DNS服务器响应缓慢或返回异常结果时,可能导致客户端与服务器建立连接时出现偏差,从而触发网站的安全验证机制,例如Cloudflare等安全服务提供的浏览器环境检查。这一机制旨在防御恶意流量,但偶尔也会误拦截正常访问。在生物医学信息检索领域,PubMed作为核心文献数据库,其稳定访问对科研工作流至关重要。针对因DNS或本地缓存问题导致的‘正在检查浏览器’页面卡顿,通过刷新DNS缓存、更换为Google Public DNS或C

weixin_29597551的博客 3638

1、netty百万连接设计及优化

理论上系统内存有多少就可以打开多少的文件描述符,但是在实际中内核是会做相应的处理,一般最大打开文件数会是系统内存的10%(以KB来计算),称之为系统级限制。这个数字可以通过 cat /proc/sys/fs/file-max 或者 sysctl -a | grep fs.file-max 命令查看。:用户打开文件描述符默认是1024,文件描述符范围1-65535,这个数字可以通过 ulimit -n查看,可以在65535范围内调整。

爱欧米 4128

【部署】Ubuntu 24.04.4虚拟机下部署OpenClaw

OpenClaw是一款基于AI的智能助手工具,本文详细介绍了在Ubuntu 24.04.4系统上的三种安装方法。推荐使用一键安装脚本(curl -fsSL https://openclaw.ai/install.sh | bash),自动完成Node.js检测、CLI安装和引导配置。对于开发者,提供了从源码构建的详细步骤,包括环境准备、依赖安装和构建流程。文章还包含常见问题解决方案(如sharp构建错误处理)以及后续维护建议(更新、配置检查和日志查看)。安装完成后,用户可通过终端TUI或Web UI进行初始

海兰 1万+

第六部分:VTK进阶(第182章 体素化与隐式建模)

本文系统介绍了基于点云构建有符号距离场(SDF)的核心原理与VTK实现方法。主要内容包括:1)SDF的基本概念与算法原理,通过体素网格隐式表达几何表面;2)关键参数配置指南,如体素分辨率、边界范围和影响半径的选择;3)点云法向估计、SDF计算与等值面提取的完整工作流程;4)常见问题解决方案与性能优化建议。文中提供了详细的C++代码示例,展示从随机点云生成SDF并重建曲面的完整过程,特别强调了法向估计、参数调优和后处理等关键环节。该方法适用于点云表面重建、几何处理等应用场景。

仰望星空的博客 528

如何让单机下Netty支持百万长连接?

如果要支持百万长连接,需要有很多的工作要做。

Cover_sky的博客 2223

学Simulink——基于Simulink的Buck-Boost变换器双闭环PI+抗饱和设计建模示例

本文详细介绍了基于Simulink的非反相Buck-Boost变换器双闭环控制设计方法。针对Buck-Boost变换器特有的右半平面零点(RHPZ)和控制挑战,提出了电压-电流双闭环PI控制架构,并集成抗积分饱和机制。通过Simulink建模,实现了主电路、电流内环PI、电压外环PI、PWM及占空比限幅等模块的搭建,验证了在输入电压跌落(20V→10V)和负载突变(2A→4A)等场景下的稳定性能。仿真结果表明,输出电压波动小于0.35V,恢复时间快于1ms,电感电流有效限幅。文章还讨论了工程实践要点和扩展方

xiaoheshang_123的博客 318

五 100万并发连接服务器笔记之Java Netty处理1M连接会怎么样

前言 每一种该语言在某些极限情况下的表现一般都不太一样,那么我常用的Java语言,在达到100万个并发连接情况下,会怎么样呢,有些好奇,更有些期盼。 这次使用经常使用的顺手的netty NIO框架(netty-3.6.5.Final),封装的很好,接口很全面,就像它现在的域名 netty.io,专注于网络IO。 整个过程没有什么技术含量,浅显分析过就更显得有些枯燥无聊,准备好,硬着头皮吧

mergerly的专栏 2万+

概率质量函数(PMF)、概率密度函数(PDF)、累积分布函数(CDF)

1.概率分布函数(Probability Distribution Functions) 笔记来源:Probability Distribution Functions (PMF, PDF, CDF) 1.1 离散型:PMF和CDF 1.2 连续型:PDF和CDF 累积分布函数的导数 === 概率密度函数的函数值 dF(x)dx=f(x) \frac{dF(x)}{dx}=f(x) dxdF(x)​=f(x) 概率密度函数与 xxx 轴围成的面积 === 累积分布函数的函数值 ∫−∞xf(x)d

一个搬运知识的笨小孩 3万+

图像处理 | 基于matlab的多尺度Retinex(MSR)和自适应直方图均衡化(CLAHE)算法联合的低照度图像增强(附代码)

本文介绍了一种基于多尺度Retinex(MSR)和CLAHE的低照度图像增强算法。算法首先对图像进行多尺度Retinex处理,通过不同尺度的高斯核去除光照影响;然后采用CLAHE算法进行对比度增强。Matlab实现展示了算法流程,包含灰度转换、多尺度Retinex增强和CLAHE处理。实验结果显示,该方法能有效提升低照度图像的可见性,增强细节表现。最后提出了改进建议,包括引入深度学习方法和优化参数选择。

尘世冰封的专栏 952

【Java】NIO框架Netty——100万并发连接服务器资源消耗测试

前言 每一种该语言在某些极限情况下的表现一般都不太一样,那么我常用的Java语言,其比较有名的NIO框架有:mina,netty和Grizzly,在达到100万个并发连接情况下,会怎么样呢,有些好奇,更有些期盼。这次使用经常使用的顺手的netty NIO框架(netty-3.6.5.Final),封装的很好,接口很全面,就像它现在的域名 netty.io,专注于网络IO。整个过程没有什么技术含量

封宸落宇的专栏 1万+

SAP Fiori Elements 扩展实战:UI 层扩展、OData 服务扩展、CDS 视图增强及全流程案例

UI 层扩展主要关注在不修改标准生成界面的基础上,自定义用户界面元素和交互逻辑。典型需求包括:在现有 Fiori Elements 界面上添加新的字段(如表格列或表单项)、增加自定义按钮并绑定操作、以及通过控制器扩展加入事件处理等。无论在 RAP 还是传统 BOPF 架构下,前端 UI 扩展通常采用 SAPUI5 提供的**扩展点(Extension Points)和控制器扩展(Controller Extension)**机制来安全地插入自定义代码。下面分别说明两种后端架构下 UI 扩展的实现方式。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 902

基于netty实现websocket高并发服务

1.WebScoket简述 WebSocket是一种在单个TCP连接上进行全双工通信的协议。 WebSocket使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在WebSocket API中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。 websocket协议本身是构建在http协议之上的升级协议,客户端首先向服务...

zk1z23456789的博客 5万+

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

Netty 长连接服务【转】

原文章地址:https://www.cnblogs.com/zrbfree/p/6344367.html 推送服务 还记得一年半前,做的一个项目需要用到 Android 推送服务。和 iOS 不同,Android 生态中没有统一的推送服务。Google 虽然有 Google Cloud Messaging ,但是连国外都没统一,更别说国内了,直接被墙。 所以之前在 Android 上做推送大...

无人境域 451

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

上一篇: MapReduce shuffle过程剖析及调优
下一篇: 利用Hive进行数据分析
王树民
博客等级 码龄10年 912粉丝 560原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值