memcached演练(2) 访问memcached服务

简介:

通过上节《memcached演练(1) 搭建memcached服务》,已经成功在linux虚拟机上安装了memcached服务,并设置了自启动。

1
2
STAT version 1.4.29
Mem:          1891

主要内容

  • 使用telnet命令行工具,操作memcached服务

  • 使用java spymemcached工具访问memcached服务

  • 监控插入不同数据量的数据,响应时间

  • 监控memcached主机繁忙&清闲对比情况

  • 调整memcached的内存指标,插入相同的数据量的数据,什么情况下性能最高

1.使用telnet命令行工具,操作memcached服务

1.1 验证set&add添加命令

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
[hadoop@hadoop1 ~]$  ps  -ef | grep  memcached
nobody    2047     1  1 07:27 ?        00:08:59  /usr/local/memcached/bin/memcached  -d -p 11211 -u nobody -m 64 -c 1024 -P  /var/run/memcached/memcached .pid
hadoop    9037  6485  0 16:59 pts /0     00:00:00  grep  memcached
#连接
[hadoop@hadoop1 ~]$ telnet 127.0.0.1 11211
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is  '^]' .
#获取key1的值
get key1
VALUE key1 0 4
abcd
END
#调用set命令,为一个已存在的key赋值成功
set  key1 0 0 4
1234
STORED
get key1
VALUE key1 0 4
1234
END
#调用set命令,为一个已存在的key赋值失败
add key1 0 0 4
abcd
NOT_STORED
get key1
VALUE key1 0 4
1234
END

结论:add和set命令虽然都可以添加数据,但两者使用上存在区别,set可以为已存在的key赋值,而add命令不可以。

1.2 验证get&gets获取命令

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
#获取1个键值
get key1
VALUE key1 0 4
1234
END
#获取1个键值
get key2
VALUE key2 0 4
word
END
#同时获取2个键值
get key1 key2
VALUE key1 0 4
1234
VALUE key2 0 4
word
END
---------------------------------------------
gets key1
VALUE key1 0 4 7695009
1234
END
gets key2
VALUE key2 0 4 7695010
word
END
gets key1 key2
VALUE key1 0 4 7695009
1234
VALUE key2 0 4 7695010
word
END
 
#gets命令返回比get命令,多了1个"不知名数字"
#修改key1的值
set  key1 0 0 5
world
STORED
#确认变化
get key1
VALUE key1 0 5
world
END
#不知名数字从7695009变为7695011
gets key1
VALUE key1 0 5 7695011
world
END
#key2值没有变化,所以不知名数字也没有变
gets key2
VALUE key2 0 4 7695010
word
END
#再次修改key1的值
set  key1 0 0 3
old
STORED
#用增加了1
gets key1 
VALUE key1 0 3 7695012
old
END

结论gets命令比get命令,多返回的数字,类似数据库中的“变更版本号似的”,而且这个版本号是在各键值之间共享。

1.3测试下incr &decr命令

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
#某key不存在情况
incr  seq  1
NOT_FOUND
 
set  seq  0 0 1
1
STORED
get  seq  1
VALUE  seq  0 1
1
END
incr  seq  1
2
...
get  seq
VALUE  seq  0 1
4
END
gets  seq
VALUE  seq  0 1 7695016
4
END
incr  seq  1
5
#调用incr 命令,增加变更版本号
gets  seq
VALUE  seq  0 1 7695017
5
END
 
incr  seq  10
15
decr  seq  1
14
#不允许为负数
decr  seq  -1
CLIENT_ERROR invalid numeric delta argument
decr  seq  10
4
#最小值为0
decr  seq  10
0
#有最大值限制
decr  seq  10000000000000000000000
CLIENT_ERROR invalid numeric delta argument
set  seq2 0 0 1
a
STORED
#如果键值非数字,会报错
incr seq2 1
CLIENT_ERROR cannot increment or decrement non-numeric value

通过实验验证:incr&decr命令,影响key的长度;最小值为0;增量可变化;必须作用在数字上;命令参数不允许为负数值。

1.4更新命令 append&preppend&replace

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
set  updkey 0 0 5
world
STORED
get updkey
VALUE updkey 0 5
world
END
#在后面添加字符
append updkey 0 0 5
hello
STORED
get updkey
VALUE updkey 0 10
worldhello
#在前面添加字符
prepend updkey 0 0 10
1234567890
STORED
gets updkey
VALUE updkey 0 20 7695030
1234567890worldhello
END
#更改有效时间为1
prepend updkey 0 1 1
#一段时间后,还存在(说明更新操作不会影响有效时间)
get updkey
VALUE updkey 0 22
1u1234567890worldhello
END
#什么都不添加
prepend updkey 0 0 0
 
STORED
#虽然没有变更值,但变更版本号也发生了变化
gets updkey
VALUE updkey 0 22 7695037
1u1234567890worldhello
#replace命令
replace updkey 0 10 1
m
STORED
 
get updkey
VALUE updkey 0 1
m
END
#replace命令变更了有效时间
gets updkey
END

结论:prepend 与append命令作用类似,一个在从前面添加字符,一个在后面追加字符。每一次行为,都会影响版本号;不会影响原来的有效时间;replace命令,不仅可以修改数据,而且可以变更有效时间。

还有其他一些指令,就不玩了。


2.使用java spymemcached工具访问memcached服务

2.1 引入依赖

1
2
3
4
5
< dependency >
     < groupId >net.spy</ groupId >
     < artifactId >spymemcached</ artifactId >
     < version >2.11.5</ version >
</ dependency >

2.2 客户端工具类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package  com.nap.memcachedexample.service;
import   net.spy.memcached.MemcachedClient;
import  java.io.IOException;
import  java.net.InetSocketAddress;
 
/**
  * Created by Administrator on 2016/8/7.
  */
public  class  MemcachedUtil {
     private  static  MemcachedClient cachedClient =  null ;
     static  {
         try  {
             cachedClient =  new  MemcachedClient( new  InetSocketAddress( "192.168.163.146" , 11211 ));
         catch  (IOException e) {
             e.printStackTrace();
         }
     }
     public  static  MemcachedClient getSpyMemcachedClient(){
         return  cachedClient;
     }
}

2.2 测试对象

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
Employee.java  
package  com.nap;
import  org.apache.commons.lang.builder.ToStringBuilder;
import  java.io.Serializable;
import  java.util.*;
public  class  Employee  implements  Serializable{
     private  long  empNo;
     private  String name;
     private  Date birthDate;
     private  int  age;
     private  double  salary;
     private  List<String> favoriteFoods;
     public  String getName() {
         return  name;
     }
 
     public  void  setName(String name) {
         this .name = name;
     }
 
     public  Date getBirthDate() {
         return  birthDate;
     }
 
     public  long  getEmpNo() {
         return  empNo;
     }
 
     public  void  setEmpNo( long  empNo) {
         this .empNo = empNo;
     }
 
     public  void  setBirthDate(Date birthDate) {
         this .birthDate = birthDate;
     }
 
     public  int  getAge() {
         return  age;
     }
 
     public  void  setAge( int  age) {
         this .age = age;
     }
 
     public  double  getSalary() {
         return  salary;
     }
 
     public  void  setSalary( double  salary) {
         this .salary = salary;
     }
 
     public  List<String> getFavoriteFoods() {
         return  favoriteFoods;
     }
 
     public  void  setFavoriteFoods(List<String> favoriteFoods) {
         this .favoriteFoods = favoriteFoods;
     }
     public  String toString(){
         return  ToStringBuilder.reflectionToString( this );
     }
}
--------------------------------------------------------------------------------------
EmployeeFactory.java 
package  com.nap;
import  com.nap.memcachedexample.service.MemcachedUtil;
import  net.spy.memcached.MemcachedClient;
import  net.spy.memcached.internal.OperationFuture;
import  org.apache.commons.lang.RandomStringUtils;
import  java.util.ArrayList;
import  java.util.Calendar;
import  java.util.List;
import  java.util.Random;
import  java.util.concurrent.ExecutionException;
public  class  EmployeeFactory {
     static  MemcachedClient mcc = MemcachedUtil.getSpyMemcachedClient();
     public  static  final  String EMPNOSEQ =  "empnoseq" ;
 
     static {
         Object cacheSeq = mcc.get( "empnoseq" );
         if (cacheSeq== null ){
             OperationFuture<Boolean> seqFuture = mcc.set(EMPNOSEQ,  900 "0" );
             try  {
                 if (seqFuture.get()){
                     System.out.println( "set status: ok" );
                 }
             catch  (InterruptedException e) {
                 e.printStackTrace();
             catch  (ExecutionException e) {
                 e.printStackTrace();
             }
         }
     }
 
     /**
      * 构造测试对象(一个对象大约40B)
      * @return
      */
     public  static  Employee newEmployee(){
         long  empNo = MemcachedUtil.getSpyMemcachedClient().incr( "empnoseq" , 1 );
         Calendar cal = Calendar.getInstance();
         Employee emp =  new  Employee();
         emp.setEmpNo(empNo);
         emp.setAge( new  Random().nextInt( 80 ));
         emp.setName(RandomStringUtils.randomAlphabetic( 15 ));
         cal.set(Calendar.MONTH,  new  Random().nextInt( 30 ));
         cal.set(Calendar.DAY_OF_YEAR,  new  Random().nextInt( 366 ));
         emp.setBirthDate(cal.getTime());
         emp.setSalary( new  Random().nextFloat());
         List<String> foods =  new  ArrayList<String>();
         for ( int  j= 0 ;j<  new  Random().nextInt( 10 );j++){
             foods.add( "foods_" +RandomStringUtils.randomAlphabetic( 10 ));
         }
         emp.setFavoriteFoods(foods);
         return  emp;
     }
}


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
package  com.nap;
import  com.nap.memcachedexample.service.MemcachedUtil;
import  junit.framework.TestCase;
import  net.spy.memcached.MemcachedClient;
import  java.util.concurrent.ExecutionException;
public  class  SpyMemcachedClientTest   extends  TestCase
{
     //测试set
     public  void  testAddBean()  throws  ExecutionException, InterruptedException {
         MemcachedClient mcc = MemcachedUtil.getSpyMemcachedClient();
         Employee emp = EmployeeFactory.newEmployee();
         System.out.println(emp);
         String key =  "emp_"  + emp.getEmpNo();
         System.out.println(key);
         mcc.set(key,  19000 , emp);
         // Shutdowns the memcached client
         mcc.shutdown();
     }
     //测试get
     public  void  testGetBean()  throws  ExecutionException, InterruptedException {
         MemcachedClient mcc = MemcachedUtil.getSpyMemcachedClient();
         Object o = mcc.get( "emp_1" );
         System.out.println(o);
         // Shutdowns the memcached client
         mcc.shutdown();
     }
}

telnet输出结果

1
2
3
4
5
6
get emp_1
VALUE emp_1 1 345
srcom.nap.Employee
favoriteFoodstLjava /util/List ;LnametLjava /lang/String ;xpetLjava /util/Date ;L
 
                                                         ?佚U

通过结果分析,通过客户端已经成功保存了。


3.监控插入不同数据量的数据,响应时间

存储单位转换器

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
package  com.nap;
    
public  enum  SizeConverter {  
     /** 转换任意单位的大小, 返回结果会包含两位小数但不包含单位. */ 
     Arbitrary {  
         @Override 
         public  String convert( float  size) {  
             while  (size >  1024 ) {  
                 size /=  1024 ;  
             }  
             return  String.format(FORMAT_F, size);  
         }  
     },  
        
     // -----------------------------------------------------------------------  
     // 有单位  
     /** 转换单位为B的大小, 返回结果会包含两位小数以及单位. 如: 1024B->1KB, (1024*1024)B->1MB */ 
     B {  
         @Override 
         public  String convert( float  B) {  
             return  converter( 0 , B);  
         }  
     },  
     /** 转换单位为B的大小, 返回结果会包含两位小数以及单位. */ 
     KB {  
         @Override 
         public  String convert( float  KB) {  
             return  converter( 1 , KB);  
         }  
     },  
     /** 转换单位为MB的大小, 返回结果会包含两位小数以及单位. */ 
     MB {  
         @Override 
         public  String convert( float  MB) {  
             return  converter( 2 , MB);  
         }  
     },  
     /** 转换单位为GB的大小, 返回结果会包含两位小数以及单位. */ 
     GB {  
         @Override 
         public  String convert( float  GB) {  
             return  converter( 3 , GB);  
         }  
     },  
     /** 转换单位为TB的大小, 返回结果会包含两位小数以及单位. */ 
     TB {  
         @Override 
         public  String convert( float  TB) {  
             return  converter( 4 , TB);  
         }  
     },  
        
     // -----------------------------------------------------------------------  
     // trim没单位  
     /** 转换任意单位的大小, 返回结果小数部分为0时将去除两位小数, 不包含单位. */ 
     ArbitraryTrim {  
         @Override 
         public  String convert( float  size) {  
             while  (size >  1024 ) {  
                 size /=  1024 ;  
             }  
    
             int  sizeInt = ( int ) size;  
             boolean  isfloat = size - sizeInt >  0 .0F;  
             if  (isfloat) {  
                 return  String.format(FORMAT_F, size);  
             }  
             return  String.format(FORMAT_D, sizeInt);  
         }  
     },  
        
     // -----------------------------------------------------------------------  
     // trim有单位  
     /** 转换单位为B的大小, 返回结果小数部分为0时将去除两位小数, 会包含单位. */ 
     BTrim {  
         @Override 
         public  String convert( float  B) {  
             return  trimConverter( 0 , B);  
         }  
     },  
     /** 转换单位为KB的大小, 返回结果小数部分为0时将去除两位小数, 会包含单位. */ 
     KBTrim {  
         @Override 
         public  String convert( float  KB) {  
             return  trimConverter( 1 , KB);  
         }  
     },  
     /** 转换单位为MB的大小, 返回结果小数部分为0时将去除两位小数, 会包含单位. */ 
     MBTrim {  
         @Override 
         public  String convert( float  MB) {  
             return  trimConverter( 2 , MB);  
         }  
     },  
     /** 转换单位为GB的大小, 返回结果小数部分为0时将去除两位小数, 会包含单位. */ 
     GBTrim {  
         @Override 
         public  String convert( float  GB) {  
             return  trimConverter( 3 , GB);  
         }  
     },  
     /** 转换单位为TB的大小, 返回结果小数部分为0时将去除两位小数, 会包含单位. */ 
     TBTrim {  
         @Override 
         public  String convert( float  TB) {  
             return  trimConverter( 4 , TB);  
         }  
     };  
     /*** 
      * <p> 将指定的大小转换到1024范围内的大小. 注意该方法的最大单位为PB, 最小单位为B,  
      * 任何超出该范围的单位最终会显示为**. </p> 
      *  
      * @param size 要转换的大小, 注意是浮点数, 不要以整形的方式传入, 容易造成溢出. 
      *         (如: 1024*1024*1024*1024*1024会溢出, 使结果为0, 因为它先将结果以int相乘后再转换为float;  
      *         而1024.0F*1024.0F*1024.0F*1024.0F*1024.0F就不会溢出) 
      * @return 
      */ 
     abstract  public  String convert( float  size);  
        
     // -----------------------------------------------------------------------  
     // 单位转换  
        
     private  static  final  String[] UNITS =  new  String[] {  
         "B" "KB" "MB" "GB" "TB" "PB" "**" 
     };  
        
     private  static  final  int  LAST_IDX = UNITS.length- 1 ;  
        
     private  static  final  String FORMAT_F =  "%1$-1.2f" ;  
     private  static  final  String FORMAT_F_UNIT =  "%1$-1.2f%2$s" ;  
        
     private  static  final  String FORMAT_D =  "%1$-1d" ;  
     private  static  final  String FORMAT_D_UNIT =  "%1$-1d%2$s" ;  
        
     // -----------------------------------------------------------------------  
     private  static  String converter( int  unit,  float  size) {  
         int  unitIdx = unit;  
         while  (size >  1024 ) {  
             unitIdx++;  
             size /=  1024 ;  
         }  
         int  idx = unitIdx < LAST_IDX ? unitIdx : LAST_IDX;  
         return  String.format(FORMAT_F_UNIT, size, UNITS[idx]);  
     }  
        
     private  static  String trimConverter( int  unit,  float  size) {  
         int  unitIdx = unit;  
         while  (size >  1024 ) {  
             unitIdx++;  
             size /=  1024 ;  
         }  
    
         int  sizeInt = ( int ) size;  
         boolean  isfloat = size - sizeInt >  0 .0F;  
         int  idx = unitIdx < LAST_IDX ? unitIdx : LAST_IDX;  
         if  (isfloat) {  
             return  String.format(FORMAT_F_UNIT, size, UNITS[idx]);  
         }  
         return  String.format(FORMAT_D_UNIT, sizeInt, UNITS[idx]);  
     }  
        
     // -----------------------------------------------------------------------  
     public  static  String convertBytes( float  B,  boolean  trim) {  
         return  trim ? trimConvert( 0 , B,  true ) : convert( 0 , B,  true );  
     }  
        
     public  static  String convertKB( float  KB,  boolean  trim) {  
         return  trim ? trimConvert( 1 , KB,  true ) : convert( 1 , KB,  true );  
     }  
        
     public  static  String convertMB( float  MB,  boolean  trim) {  
         return  trim ? trimConvert( 2 , MB,  true ) : convert( 2 , MB,  true );  
     }  
        
     /*** 
      * <p> 存储大小单位间的转换. 注意该方法的最大单位为PB, 最小单位为B,  
      * 任何超出该范围的单位最终会显示为**. </p> 
      *  
      * @param unit 从哪个单位开始 
      * @param size 存储大小, 注意是float, 不要以整形的形式传入, 否则会溢出(如:1024*1024这种, 
      * 它是先将1024*1024作为int相乘再转换为float的, 如果值过大的话就会溢出了,  
      * 所以这么写1024.0F*1024.0F) 
      * @param withUnit 返回的结果字符串是否带有对应的单位 
      * @return 
      */ 
     private  static  String convert( int  unit,  float  size,  boolean  withUnit) {  
         int  unitIdx = unit;  
         while  (size >  1024 ) {  
             unitIdx++;  
             size /=  1024 ;  
         }  
         if  (withUnit) {  
             int  idx = unitIdx < LAST_IDX ? unitIdx : LAST_IDX;  
             return  String.format(FORMAT_F_UNIT, size, UNITS[idx]);  
         }  
         return  String.format(FORMAT_F, size);  
     }  
        
     /*** 
      * <p> 存储大小单位间的转换, 如果转换后小数部分为0, 则去除小数部分.  
      * 注意该方法的最大单位为PB, 最小单位为B, 任何超出该范围的单位最终会显示为**. </p> 
      *  
      * @param unit 从哪个单位开始 
      * @param size 存储大小, 注意是float, 不要以整形的形式传入, 否则会溢出(如:1024*1024这种, 
      * 它是先将1024*1024作为int相乘再转换为float的, 如果值过大的话就会溢出了,  
      * 所以这么写1024.0F*1024.0F) 
      * @param withUnit 返回的结果字符串是否带有对应的单位 
      * @return 
      */ 
     private  static  String trimConvert( int  unit,  float  size,  boolean  withUnit) {  
         int  unitIdx = unit;  
         while  (size >  1024 ) {  
             unitIdx++;  
             size /=  1024 ;  
         }  
    
         int  sizeInt = ( int ) size;  
         boolean  isfloat = size - sizeInt >  0 .0F;  
         if  (withUnit) {  
             int  idx = unitIdx < LAST_IDX ? unitIdx : LAST_IDX;  
             if  (isfloat) {  
                 return  String.format(FORMAT_F_UNIT, size, UNITS[idx]);  
             }  
             return  String.format(FORMAT_D_UNIT, sizeInt, UNITS[idx]);  
         }  
    
         if  (isfloat) {  
             return  String.format(FORMAT_F, size);  
         }  
         return  String.format(FORMAT_D, sizeInt);  
     }
 
     public  static  void  main(String[] args) {
         System.out.println(SizeConverter.BTrim.convert(1029000f));
     }
}


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class SpyMemcachedClientTest  extends TestCase{
// 逻辑非常简单,仅仅批量插入数量数据,经过估算一个Employee 对象,一般为40B。
public void testBatchAddBean() throws ExecutionException, InterruptedException {
     MemcachedClient mcc = MemcachedUtil.getSpyMemcachedClient();
     long startTime=System.currentTimeMillis();
     int size=10000000;
     for  (int i=0;i<size;i++){
         Employee emp = EmployeeFactory.newEmployee();
         System.out.println(emp);
         mcc. set ( "emp_"  + emp.getEmpNo(), 19000, emp);
     }
 
     long endTime=System.currentTimeMillis();
     System.out.println( "保存对象" +size+ "数据大小" +SizeConverter.BTrim.convert(size*40.0f)+ ";共耗时:" +(endTime-startTime));
     //  Shutdowns the memcached client
     mcc. shutdown ();
}
}

结论(memcached服务内存参数为64m,每次测试前最好执行下flush,降低换入换出影响)

数据量
数据大小
耗时(ms)
1000
39.06KB 1191
10000 390.63KB 3155
20000 781.25KB
5142
30000
1.14MB 7057
40000
1.53MB
8611
50000 1.91MB 10611
100000
3.81MB 19594
500000 19.07MB
89549



通过分析得知,当数据量为10000-20000左右时,单位时间保存的数据最多。

(0.32 kb/ms,降至0.26kb/s)



4.监控memcached主机繁忙&清闲对比情况

由于仅仅考虑写入情况,暂时不需要考虑命中率其他情况。主要记录以下指标

(暂时不考虑内存使用情况,IO等待)

4.1CPU利用率

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
[root@hadoop1 ~] # sar -u 2 100 
Linux 2.6.32-358.el6.i686 (hadoop1)     08 /07/2016       _i686_  (1 CPU)
 
07:06:47 PM     CPU     %user     % nice    %system   %iowait    %steal     %idle
07:06:49 PM     all      0.50      0.00      0.50      0.00      0.00     98.99
07:06:51 PM     all      0.00      0.00      0.51      0.00      0.00     99.49
07:06:53 PM     all      0.00      0.00      0.50      0.00      0.00     99.50
07:06:55 PM     all      0.00      0.00      0.50      0.50      0.00     99.00
---------------start-------------------------------
07:06:57 PM     all      0.00      0.00      5.18      0.00      0.00     94.82
07:06:59 PM     all      0.58      0.00     41.62      0.00      0.00     57.80
07:07:01 PM     all      0.00      0.00     61.69      0.00      0.00     38.31
07:07:03 PM     all      0.65      0.00     65.36      0.00      0.00     33.99
07:07:05 PM     all      0.62      0.00     70.19      0.00      0.00     29.19
07:07:07 PM     all      1.23      0.00     69.14      0.00      0.00     29.63
07:07:09 PM     all      0.00      0.00     70.55      0.00      0.00     29.45
07:07:11 PM     all      0.00      0.00     70.19      0.00      0.00     29.81
07:07:13 PM     all      0.00      0.00     70.81      0.00      0.00     29.19
07:07:15 PM     all      0.00      0.00     70.89      0.00      0.00     29.11
07:07:17 PM     all      0.00      0.00     71.52      0.00      0.00     28.48
07:07:19 PM     all      0.00      0.00     71.60      0.00      0.00     28.40
07:07:21 PM     all      1.27      0.00     69.43      0.00      0.00     29.30
07:07:23 PM     all      0.00      0.00     70.13      0.00      0.00     29.87
07:07:25 PM     all      0.66      0.00     69.74      0.00      0.00     29.61
07:07:27 PM     all      0.00      0.00     71.34      0.00      0.00     28.66
07:07:29 PM     all      1.85      0.00     69.75      0.00      0.00     28.40
07:07:31 PM     all      0.00      0.00     70.81      0.00      0.00     29.19
07:07:33 PM     all      0.00      0.00     70.89      0.00      0.00     29.11
07:07:35 PM     all      0.00      0.00     41.48      0.00      0.00     58.52
-------------------end-----------------------------------------
07:07:37 PM     all      0.00      0.00      0.50      0.00      0.00     99.50
07:07:39 PM     all      0.00      0.00      0.50      0.00      0.00     99.50

在核心级别(kernel)运行所使用 CPU 总时间的百分比突然提升了40%-70%。

相对来说,用户级别的CPU 总时间百分比变化不大。这一点有点出乎意料。

输出项说明:

CPU all 表示统计信息为所有 CPU 的平均值。
%user 显示在用户级别(application)运行使用 CPU 总时间的百分比。
%nice 显示在用户级别,用于nice操作,所占用 CPU 总时间的百分比。
%system 在核心级别(kernel)运行所使用 CPU 总时间的百分比。
%iowait 显示用于等待I/O操作占用 CPU 总时间的百分比。
%steal 管理程序(hypervisor)为另一个虚拟进程提供服务而等待虚拟 CPU 的百分比。
%idle 显示 CPU 空闲时间占用 CPU 总时间的百分比。


4.2换页情况

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
sar -B
06:59:29 PM  pgpgin /s  pgpgout /s    fault /s   majflt /s   pgfree /s  pgscank /s  pgscand /s  pgsteal /s     %vmeff
 
06:59:35 PM      0.00      0.00     15.50      0.00     53.00      0.00      0.00      0.00      0.00
06:59:37 PM      0.00      0.00     15.58      0.00     53.27      0.00      0.00      0.00      0.00
06:59:39 PM      0.00      0.00     15.58      0.00     53.27      0.00      0.00      0.00      0.00
-----start-----------
06:59:41 PM      0.00      0.00     16.76      0.00     61.62      0.00      0.00      0.00      0.00
06:59:43 PM      0.00      0.00    123.78      0.00    111.59      0.00      0.00      0.00      0.00
06:59:45 PM      0.00      0.00     20.25      0.00     92.64      0.00      0.00      0.00      0.00
06:59:47 PM      0.00     22.78     20.89      0.00     94.30      0.00      0.00      0.00      0.00
06:59:49 PM      0.00      0.00     24.84      0.00    105.73      0.00      0.00      0.00      0.00
06:59:51 PM      0.00      0.00     19.02      0.00     92.02      0.00      0.00      0.00      0.00
06:59:53 PM      0.00      0.00     19.50      0.00     93.08      0.00      0.00      0.00      0.00
06:59:55 PM      0.00      0.00     19.38      0.00     95.00      0.00      0.00      0.00      0.00
06:59:57 PM      0.00      0.00    128.12      0.00    123.75      0.00      0.00      0.00      0.00

由于缺少必要的查询操作,换页监控,感觉意义不大。


输出项说明:

pgpgin/s 每秒钟从磁盘读入的系统页面的 KB 总数
pgpgout/s 每秒钟向磁盘写出的系统页面的 KB 总数
fault/s 系统每秒产生的页面失效(major + minor)数量
majflt/s 系统每秒产生的页面失效(major)数量


4.3上下文切换次数(提高了2个数量级)

1
2
3
4
5
6
7
8
9
10
11
[root@hadoop1 ~] # sar -w 2 100
Linux 2.6.32-358.el6.i686 (hadoop1)     08 /07/2016       _i686_  (1 CPU)
 
06:57:10 PM    proc /s    cswch /s
06:57:12 PM      0.00  14627.04
06:57:14 PM      0.00  14884.81
06:57:16 PM      0.62  14411.11
06:57:18 PM      0.00   1530.41
06:57:20 PM      0.00    118.00
06:57:22 PM      0.00    121.61
06:57:24 PM      0.00    118.09

4.4队列的长度

1
2
3
4
5
6
7
8
9
sar -q
06:10:01 PM   runq-sz  plist-sz   ldavg-1   ldavg-5  ldavg-15
06:20:01 PM         0       230      0.00      0.00      0.00
06:30:01 PM         0       230      0.00      0.00      0.00
06:40:01 PM         0       230      0.00      0.00      0.00
06:50:01 PM         0       230      0.00      0.00      0.00
07:00:01 PM         0       232      0.00      0.00      0.00
07:10:01 PM         0       230      0.00      0.00      0.00
Average:            0       228      0.00      0.00      0.00

基本上没什么变化,可以说明瓶颈不再CPU上。

输出项说明:

runq-sz 运行队列的长度(等待运行的进程数)
plist-sz 进程列表中进程(processes)和线程(threads)的数量
ldavg-1 最后1分钟的系统平均负载(System load average)
ldavg-5 过去5分钟的系统平均负载
ldavg-15 过去15分钟的系统平均负载


5.调整memcached的内存指标,测试性能


数据量
数据量大小

64m 响应时间

(ms)

128m 响应时间

(ms)

512m响应时间
1000 39.06KB 1191
761
753
10000
390.63KB 3155 3116 3168
20000
781.25KB 5142
4965 4978
30000
1.14MB
7057 6893 6829
40000
1.53MB 8611
8629 8725
50000
1.91MB 10611

10660

10334
100000 3.81MB 19594
19984 19760

结论:发现一个奇怪问题。数据量到了40000时,内存大的反而效率低(多次测试,结果不太稳定,这种情况经常发生)。

个人真有点摸不着头脑了,有清楚麻烦告知下。

我分别对比了换入换出指标,CPU利用率情况等,均没有发现能引起注意的地方。难道是网络问题?

本文由于缺少查询操作,所以未考虑命中率,在以后调优演练时补上。

---------------------------

The End

memcached 正常使用了。接下来,借助memcached实现tomcat集群效果




本文转自 randy_shandong 51CTO博客,原文链接:http://blog.51cto.com/dba10g/1835429,如需转载请自行联系原作者

相关文章
|
网络性能优化 数据中心 云计算
IT知识百科:什么是城域以太网?
【2月更文挑战第1天】
364 2
IT知识百科:什么是城域以太网?
|
5月前
|
人工智能 自然语言处理 API
阿里云百炼xWaytoAGI共学课DAY1 - 必须了解的企业级AI应用开发知识点
本课程旨在介绍阿里云百炼大模型平台的核心功能和应用场景,帮助开发者和技术小白快速上手,体验AI的强大能力,并探索企业级AI应用开发的可能性。
|
4月前
|
机器学习/深度学习 自然语言处理 Serverless
DeepSeek 快速体验,魔搭+函数计算一键部署模型上云
对于期待第一时间在本地进行使用的用户来说,尽管 DeepSeek 提供了从 1.5B 到 70B 参数的多尺寸蒸馏模型,但本地部署仍需要一定的技术门槛。对于资源有限的用户进一步使用仍有难点。为了让更多开发者第一时间体验 DeepSeek 模型的魅力,Modelscope 社区 DeepSeek-R1-Distill-Qwen 模型现已支持一键部署(SwingDeploy)上函数计算 FC 服务,欢迎开发者立即体验。
390 13
|
11月前
|
Docker 容器
docker ps --no-trunc 与 docker ps
docker ps --no-trunc 与 docker ps
144 1
|
8月前
|
人工智能 自然语言处理 搜索推荐
通义灵码:AI辅助开发工具的新范式
在大模型时代,阿里云的通义灵码作为AI辅助开发工具,通过提高开发效率、简化协作和降低成本,重塑了软件开发的核心要素。通义灵码基于大模型和自然语言处理技术,实时辅助代码编写、调试和优化,提供个性化支持,显著提升了开发体验。未来,AI将在软件开发中发挥更大作用,通义灵码将继续引领这一变革。
215 0
通义灵码:AI辅助开发工具的新范式
|
10月前
|
机器学习/深度学习 人工智能 自动驾驶
深度学习在图像识别中的应用与挑战
【8月更文挑战第9天】随着人工智能的飞速发展,深度学习技术已成为推动现代科技革新的关键力量。特别是在图像识别领域,深度学习模型凭借其强大的特征提取能力和分类精度,已广泛应用于面部识别、自动驾驶等多个场景。本文将探讨深度学习在图像识别中的具体应用实例,分析当前面临的主要挑战,并预测未来发展趋势。
57 4
|
SQL Java 关系型数据库
【Spring Boot+Thymeleaf+MyBatis+mysql】实现电子商务平台实战(附源码)持续更新~~ 包括sql语句、java、html代码
【Spring Boot+Thymeleaf+MyBatis+mysql】实现电子商务平台实战(附源码)持续更新~~ 包括sql语句、java、html代码
329 1
|
人工智能 缓存 算法
【AI 孙燕姿 | AI 音色克隆】RVC 使用图文教程:无难度男女换声(伪音)、 AI 孙燕姿
根据本文,可以很简单实现:音乐干声分离:背景音(BGM)与人声(干声)的分离;训练个人音色模型:作为模仿其他干声素材的音色数据;男女换声(伪音):基于异性干声素材,进行实时转化声音为异性声音;AI 唱歌:仅作基础的模拟演唱,仍需进行调音等等操作,才可以达到完美;音色融合:不同音色的特征融合出一个全新的音色
5787 3
【AI 孙燕姿 | AI 音色克隆】RVC 使用图文教程:无难度男女换声(伪音)、 AI 孙燕姿
|
人工智能 算法 数据可视化
国内首发可视化智能调优平台,小龙带你玩转KeenTune UI
KeenTune 再次带来开源重磅特性——新增第五大组件:keentune-ui。
国内首发可视化智能调优平台,小龙带你玩转KeenTune UI
|
测试技术 网络安全 数据安全/隐私保护
树莓派开发笔记(十四):入手研华ADVANTECH工控树莓派UNO-220套件(三):使用研发自带系统测试rtc、gpio、232和485套件接口
树莓派开发笔记(十四):入手研华ADVANTECH工控树莓派UNO-220套件(三):使用研发自带系统测试rtc、gpio、232和485套件接口
树莓派开发笔记(十四):入手研华ADVANTECH工控树莓派UNO-220套件(三):使用研发自带系统测试rtc、gpio、232和485套件接口