elasticsearch性能優化筆記(1)—— 程序層面

要對系統的ES的寫入性能作優化,第一個想到的就是讀取ip的代碼。java

需求描述:系統會根據每條document的ip,找到一個表示行政區域的code,供地理圖的渲染使用。而實際IP有40多億,寫出來的json文件有7個G,太扯...python

目前是兩種方案,一種是ipip提供的二進制文件和sdk,1秒大概查10萬條,速度夠了,但並不能精確到縣;mysql

一種是找到到縣的數據,寫到mysql裏,由於在一個範圍內的ip地區相同,所以壓縮下來大概是12M條數據,查詢速度是1秒1萬左右。sql

 

結合兩種,把mysql裏的數據寫成二進制數據,ip爲4位unsigned int(在java裏是8位long),code爲4位int,簡單計算一下1200w條大體100MB的數據,加載到內存大體幾秒就能夠json

 

開始操做:數組

創建二進制文件(python):dom

sql = "select * from ip_code limit %d, 10000" % i
cursor.execute(sql)
area_data = cursor.fetchone()
while area_data:
    file.write(struct.pack('I', area_data[0]))
    file.write(struct.pack('i', area_data[4]))
    area_data = cursor.fetchone()

 

struct爲python將類型轉化爲byte的庫,I表示無符號int,i表示int,area_data[0]和area_data[4]分別爲ip和區域codeeclipse

 

加載測試(java):jvm

import java.io.BufferedInputStream;
import java.util.ArrayList;
import java.util.Random;

public class IpCode {
   public static ArrayList<Long> ips = new ArrayList<Long>();
   public static ArrayList<Integer> codes = new ArrayList<Integer>();
   public static int len = 0;
   public static int find(long ip){
      int l=0,r=len-1;
      int mid;
      while(l <= r){
         mid = (l+r)/2;
         if(ip == ips.get(mid)){
            return codes.get(mid);
         }
         else if(ip > ips.get(mid)){
            if(mid == len-1 || ip < ips.get(mid+1)){
               return codes.get(mid);
            }
            else{
               l = mid + 1;
            }
         }
         else{
            if(mid == 0 || ip > ips.get(mid-1)){
               return codes.get(mid);
            }
            else{
               r = mid - 1;
            }
         }
      }
      return -1;
   }
   public static void main(String[] args){
      // TODO Auto-generated method stub

      long startTime=System.currentTimeMillis();   //獲取開始時間
        long totalMem = Runtime.getRuntime().totalMemory();
        long maxMem = Runtime.getRuntime().maxMemory();
        long freeMem = Runtime.getRuntime().freeMemory();
        System.out.println("導入前內存檢測");
        System.out.println(totalMem);
        System.out.println(maxMem);
        System.out.println(freeMem);
      byte b[] = new byte[1024];
      int count;
      try {

         long x=0;
         int y=0;
         BufferedInputStream bin = (BufferedInputStream)(new IpCode().getClass().getResourceAsStream( "/ip_code_final.dat" ));
         while((count=bin.read(b))!=-1){
            for(int i=0;i<count;i+=8){
               x = (long)(b[i] & 0xFF) |
                     (long)(b[i+1] & 0xFF) << 8 |
                     (long)(b[i+2] & 0xFF) << 16 |
                     (long)(b[i+3] & 0xFF) << 24;
               y = b[i+4] & 0xFF |
                  (b[i+5] & 0xFF) << 8 |
                  (b[i+6] & 0xFF) << 16 |
                  (b[i+7]& 0xFF) << 24;
               ips.add(x);
               codes.add(y);
               len++;
            }
         }
            totalMem = Runtime.getRuntime().totalMemory();
            maxMem = Runtime.getRuntime().maxMemory();
            freeMem = Runtime.getRuntime().freeMemory();
           System.out.println("導入後內存檢測");
           System.out.println(totalMem);
           System.out.println(maxMem);
           System.out.println(freeMem);
           System.out.println(String.format("數組長度爲%d", len));
           System.out.println(String.format("最後一條數據ip爲%d,區域代碼爲%d", x, y));
           bin.close();
           long endTime=System.currentTimeMillis(); //獲取結束時間
           System.out.println("程序運行時間: "+(endTime-startTime)+"ms");

           // 計算查詢時間
           long max=3758095360L,min=16777472L;
           long all_time = 0;
           for(int i=0;i<100000;i++){
              long ii = min + (((long) (new Random().nextDouble() * (max - min))));
              startTime=System.currentTimeMillis(); //獲取結束時間
              int code = find(ii);
              all_time += System.currentTimeMillis() - startTime;
           }
           System.out.println("搜索10萬條時間: "+all_time+"ms");
      } catch (Exception e) {
         // TODO Auto-generated catch block
         e.printStackTrace();
      } catch(java.lang.OutOfMemoryError ee){
         ee.printStackTrace();
      }
   }
}

 

運行結果:性能

java heap OOM........

因此要調大一下jvm的內存

eclipse => run => run configurations => Arguments => VM arguments

添加-Xms1024m -Xmx1024m

再運行:

導入前內存檢測
128974848
1908932608
126895344
導入後內存檢測
1103101952
1908932608
473296336
數組長度爲12945927
最後一條數據ip爲3758095360,區域代碼爲150100
程序運行時間: 6461ms
搜索10萬條時間: 61ms

 

這個速度就很是理想了,考慮以後把其它必要信息也加入,理論上不會有太多耗能

相關文章
相關標籤/搜索