Java NIO框架Netty教程(十二)-并发访问测试(中)

释放双眼,带上耳机,听听看~!

写在前面:对Netty并发问题的测试和解决完全超出了我的预期,想说的东西越来越多。所以才出现这个中篇,也就是说,一定会有下篇。至于问题点的发现,OneCoder也在努力验证中。

继续并发的问题。在《Java NIO框架Netty教程(十一)-并发访问测试(上)》中,我们测试的其实是一种伪并发的情景。底层实际只有一个Channel在运作,不会出现什么无响应的问题。而实际的并发不是这个意思的,独立的客户端,自然就会有独立的channel。也就是一个服务端很可能和很多的客户端建立关系,就有很多的Channel,进行了多次的绑定。下面我们来模拟一下这种场景。


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
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
1/**
2      
3
4      
5
6
7         
8        * Netty并发,多connection,socket并发测试
9      
10
11      
12
13
14         
15        *  
16      
17
18      
19
20
21         
22        * @author lihzh(OneCoder)
23      
24
25      
26
27
28         
29        * @alia OneCoder
30      
31
32      
33
34
35         
36        * @Blog  http://www.coderli.com
37      
38
39      
40
41
42         
43        * @date 2012-8-13 下午10:47:28
44      
45
46      
47
48
49         
50        */
51      
52
53      
54
55
56        public
57         class
58         ConcurrencyNettyMultiConnection {
59      
60
61      
62
63
64             
65      
66
67      
68
69
70            
71        public
72         static
73         void
74         main(String args[]) {
75      
76
77      
78
79
80                
81        final
82         ClientBootstrap bootstrap =  
83        new
84         ClientBootstrap(
85      
86
87      
88
89
90                        
91        new
92         NioClientSocketChannelFactory(
93      
94
95      
96
97
98                                
99        Executors.newCachedThreadPool(),
100      
101
102      
103
104
105                                
106        Executors.newCachedThreadPool()));
107      
108
109      
110
111
112                
113        // 设置一个处理服务端消息和各种消息事件的类(Handler)
114      
115
116      
117
118
119                
120        bootstrap.setPipelineFactory(
121        new
122         ChannelPipelineFactory() {
123      
124
125      
126
127
128                    
129        @Override
130      
131
132      
133
134
135                    
136        public
137         ChannelPipeline getPipeline()  
138        throws
139         Exception {
140      
141
142      
143
144
145                        
146        return
147         Channels.pipeline(
148        new
149         ObjectEncoder(),
150      
151
152      
153
154
155                                
156        new
157         ObjectClientHandler()
158      
159
160      
161
162
163                        
164        );
165      
166
167      
168
169
170                    
171        }
172      
173
174      
175
176
177                
178        });
179      
180
181      
182
183
184                
185        for
186         (
187        int
188         i =  
189        0
190        ; i <  
191        3
192        ; i++) {
193      
194
195      
196
197
198                        
199        bootstrap.connect(
200        new
201         InetSocketAddress(
202        "127.0.0.1"
203        ,  
204        8000
205        ));
206      
207
208      
209
210
211                
212        }
213      
214
215      
216
217
218            
219        }
220      
221
222      
223
224
225        }
226

看到这段代码,你可能会疑问,这是在做什么。这个验证是基于酷壳的文章《Java NIO类库Selector机制解析(上)》。他是基于Java Selector直接进行的验证,Netty是在此之上封装了一层。其实OneCoder也做了Selector层的验证。


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
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
1/**
2      
3
4      
5
6
7         
8        * Selector打开端口数量测试
9      
10
11      
12
13
14         
15        *  
16      
17
18      
19
20
21         
22        * @author lihzh
23      
24
25      
26
27
28         
29        * @alia OneCoder
30      
31
32      
33
34
35         
36        * @blog  http://www.coderli.com
37      
38
39      
40
41
42         
43        */
44      
45
46      
47
48
49        public
50         class
51         ConcurrencySelectorOpen {
52      
53
54      
55
56
57          
58      
59
60      
61
62
63            
64        /**
65      
66
67      
68
69
70             
71        * @author lihzh
72      
73
74      
75
76
77             
78        * @alia OneCoder
79      
80
81      
82
83
84             
85        * @throws IOException  
86      
87
88      
89
90
91             
92        * @throws InterruptedException  
93      
94
95      
96
97
98             
99        * @date 2012-8-15 下午1:57:56
100      
101
102      
103
104
105             
106        */
107      
108
109      
110
111
112            
113        public
114         static
115         void
116         main(String[] args)  
117        throws
118         IOException, InterruptedException {
119      
120
121      
122
123
124                
125        for
126         (
127        int
128         i =  
129        0
130        ; i <  
131        3
132        ; i++) {
133      
134
135      
136
137
138                    
139        Selector selector = Selector.open();
140      
141
142      
143
144
145                    
146        SocketChannel channel = SocketChannel.open();
147      
148
149      
150
151
152                    
153        channel.configureBlocking(
154        false
155        );
156      
157
158      
159
160
161                    
162        channel.connect(
163        new
164         InetSocketAddress(
165        "127.0.0.1"
166        ,  
167        8000
168        ));
169      
170
171      
172
173
174                    
175        channel.register(selector, SelectionKey.OP_READ);
176      
177
178      
179
180
181                
182        }
183      
184
185      
186
187
188                
189        Thread.sleep(
190        300000
191        );
192      
193
194      
195
196
197            
198        }
199      
200
201      
202
203
204        }
205

同样,通过Process Explorer去观察端口占用情况,开始跟酷壳大哥的观察到的效果一样。当不启动Server端,也就是不实际跟Server端建立链接的时候,3次selector open,占用了6个端口。

当启动Server端,进行绑定的时候,占用了9个端口

其实,多的三个,就是实际绑定的8000端口。其余就是酷壳大哥说的内部Loop链接。也就是说,对于我们实际场景,一次链接需要的端口数是3个。操作系统的端口数和资源当然有有限的,也就是说当我们增大这个链接的时候,错误必然会发生了。OneCoder尝试一下3000次的场景,并没有出现错误,不过这么下去出错肯定是必然的。

再看看服务端的情况,

这个还是直接通过Selector连接的时候的服务端的情况,除了两个内部回环端口以外,都是通过监听的8000的端口与外界通信,所以,服务端不会有端口限制的问题。不过,也可以看到,如果对链接不控制,服务端也维持大量的连接耗费系统资源!所以,良好的编码是多么的重要。

回到我们的主题,Netty的场景。先使用跟Selector测试一样的场景,单线程,一个bootstrap,连续多次connect看看错误和端口占用的情况。代码也就是开头提供的那段代码。

看看测试结果,

同样连接后还是占用9个端口。如果手动调用了channle.close()方法,则会释放与8000链接的端口,也就是变成6个端口占用。

增大连续连接数到10000。

首先没有报错,在每次close channel情况下,客户端端口占用情况如图(服务端情况类似)。

可见,并没有像selector那样无限的增加下去。这正是Netty中worker的巨大作用,帮我们管理这些琐碎的链接。具体分析,我们留待下章,您也可以自己研究一下。(OneCoder注:如果没关闭channel,会发现对8000端口的占用,会迅速增加。系统会很卡。)

调整测试代码,用一个线程来模拟一个客户端的请求。


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
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
1/**
2      
3
4      
5
6
7         
8        * Netty并发,多connection,socket并发测试
9      
10
11      
12
13
14         
15        *  
16      
17
18      
19
20
21         
22        * @author lihzh(OneCoder)
23      
24
25      
26
27
28         
29        * @alia OneCoder
30      
31
32      
33
34
35         
36        * @Blog  http://www.coderli.com
37      
38
39      
40
41
42         
43        * @date 2012-8-13 下午10:47:28
44      
45
46      
47
48
49         
50        */
51      
52
53      
54
55
56        public
57         class
58         ConcurrencyNettyMultiConnection {
59      
60
61      
62
63
64             
65      
66
67      
68
69
70            
71        public
72         static
73         void
74         main(String args[]) {
75      
76
77      
78
79
80                
81        final
82         ClientBootstrap bootstrap =  
83        new
84         ClientBootstrap(
85      
86
87      
88
89
90                        
91        new
92         NioClientSocketChannelFactory(
93      
94
95      
96
97
98                                
99        Executors.newCachedThreadPool(),
100      
101
102      
103
104
105                                
106        Executors.newCachedThreadPool()));
107      
108
109      
110
111
112                
113        // 设置一个处理服务端消息和各种消息事件的类(Handler)
114      
115
116      
117
118
119                
120        bootstrap.setPipelineFactory(
121        new
122         ChannelPipelineFactory() {
123      
124
125      
126
127
128                    
129        @Override
130      
131
132      
133
134
135                    
136        public
137         ChannelPipeline getPipeline()  
138        throws
139         Exception {
140      
141
142      
143
144
145                        
146        return
147         Channels.pipeline(
148        new
149         ObjectEncoder(),
150      
151
152      
153
154
155                                
156        new
157         ObjectClientHandler()
158      
159
160      
161
162
163                        
164        );
165      
166
167      
168
169
170                    
171        }
172      
173
174      
175
176
177                
178        });
179      
180
181      
182
183
184                
185        for
186         (
187        int
188         i =  
189        0
190        ; i <  
191        1000
192        ; i++) {
193      
194
195      
196
197
198                    
199        // 连接到本地的8000端口的服务端
200      
201
202      
203
204
205                    
206        Thread t =  
207        new
208         Thread(
209        new
210         Runnable() {
211      
212
213      
214
215
216                        
217        @Override
218      
219
220      
221
222
223                        
224        public
225         void
226         run() {
227      
228
229      
230
231
232                            
233        bootstrap.connect(
234        new
235         InetSocketAddress(
236        "127.0.0.1"
237        ,  
238        8000
239        ));
240      
241
242      
243
244
245                            
246        try
247         {
248      
249
250      
251
252
253                                
254        Thread.sleep(
255        300000
256        );
257      
258
259      
260
261
262                            
263        }  
264        catch
265         (InterruptedException e) {
266      
267
268      
269
270
271                                
272        e.printStackTrace();
273      
274
275      
276
277
278                            
279        }
280      
281
282      
283
284
285                        
286        }
287      
288
289      
290
291
292                    
293        });
294      
295
296      
297
298
299                    
300        t.start();
301      
302
303      
304
305
306                
307        }
308      
309
310      
311
312
313            
314        }
315      
316
317      
318
319
320        }
321

不出所料,跟微博上问我问题的朋友出现的问题应该是一样的:

Write: 973
Write: 974
八月 17, 2012 9:57:28 下午 org.jboss.netty.channel.SimpleChannelHandler
警告: EXCEPTION, please implement one.coder.netty.chapter.eight.ObjectClientHandler.exceptionCaught() for proper handling.
java.net.ConnectException: Connection refused: no further information

这个问题,笔者确实尚未分析出原因,仅从端口占用情况来看,跟前面的测试用例跑出的效果基本类似。应该说明不是端口不足导致的,不过OneCoder尚不敢妄下结论。待研究后,我们下回分解吧:)您有任何想法,也可以提供给我,我来进行验证。

如非特别注明,本站内容均为OneCoder原创,转载请务必注明作者和原始出处。

本文地址:链接地址

给TA打赏
共{{data.count}}人
人已打赏
安全网络

CDN安全市场到2022年价值76.3亿美元

2018-2-1 18:02:50

气候事件

“南玛都”今夜至明晨登陆或擦过台湾

2011-8-28 9:07:33

个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索