日常低级错误

最近发布了一个日常,直接导致系统响应时间变慢了两倍,系统load增长了4倍,还好由于PV不是很大,系统没出什么问题,但是如果这个系统是公司的主系统,承担大部分的流量的话,估计系统就挂了,现在想想有点后怕,把这次故障的过程记录下来。

 

故障的起因很简单,我需要提供一个根据本地ip获取地址的接口,这里我调用了公司统一的一个底层地址接口,代码如下

	String clientIp = rundata.getRequest().getRemoteAddr();//用户IP地址
			ITbip tbip = new TbipImpl();
			tbip.setEncode("gbk"); //设置所采用的编码,参数支持"gbk"或"utf8",默认为gbk。
			tbip.init();
			IpInfoEntity ipInfo = tbip.getIpInfo(clientIp);
			String regin = ipInfo.getRegion();
			String city = ipInfo.getCity();
			context.put("regin",regin);
			context.put("city",city);

 这个接口上去以后,系统性能马上就下来了,问题定位倒很容易,就这么几行代码,主要的性能消耗点就在tbip.init()这个方法,里面的代码如下:

public void init() throws IOException {
		String resFile = "";
		if (this.encode.equals("gbk")) {
			resFile = "/ipdata_geo_isp_code.txt.gbk";
		} else {
			resFile = "/ipdata_geo_isp_code.txt.utf8";
		}
		InputStream is = this.getClass().getResourceAsStream(resFile);
		BufferedReader br = new BufferedReader(new InputStreamReader(is));
		String line = "";
		
		while ((line = br.readLine()) != null) {
			int position1 = line.indexOf(",");
			int position2 = line.indexOf(",", position1+1);
			int position3 = line.indexOf(",", position2+1);
			int position4 = line.indexOf(",", position3+1);
		
			IpSegInfoEntity ipSegInfoEntity = new IpSegInfoEntity();
			
			ipSegInfoEntity.setLipStart(Long.parseLong(line.substring(0, position1)));
			ipSegInfoEntity.setLipEnd(Long.parseLong(line.substring(position1+1, position2)));
			ipSegInfoEntity.setDetail(line.substring(position4+1));	
			
			//System.out.println(ipSegInfoEntity);

			ipSegEntityList.add(ipSegInfoEntity);
		}
		br.close();
	}

 可以看到,这段代码就是读取一个ip地址对应关系的文件,然后把它读入到内存中,可以想像,这个文件可以有多大,大概是25M的样子,就是因为这个init方法,导致每次请求这个接口的时候,内存就会消耗掉25M左右。因此导致系统频繁GC,导致请求响应变慢,请求变慢,导致运行队列过长,从而导致load上升等等问题。解决方法很简单,在系统刚启动的时候,把文件放入到内存中就行了

 

 

教训:1:每次调用别人的接口,要看仔细demo,否则容易被误导,这次的错误代码就是参照demo写的,因此就有问题了

         2:碰到init方法的时候千万注意,因为有可能里面会有很复杂的逻辑,很有可能调用一次就够了,调用多次的话,就会有性能问题

 

你可能感兴趣的:(日常低级错误)