1.查询接口模块名为xdb;2.查询接口返回字符串;3.增加 apache 授权信息;4.调整基准测试数据来源
This commit is contained in:
parent
0a4d16b434
commit
f053e97b23
|
|
@ -1,5 +1,18 @@
|
||||||
# ip2region xdb erlang 查询客户端
|
# ip2region xdb erlang 查询客户端
|
||||||
|
|
||||||
|
### 简介
|
||||||
|
该bingding以erlang语言实现xdb查询客户端,基于Erlang OTP Application,查询逻辑由ip2region_worker工作进程实现,支持配多个工作进程来进行负载均衡。
|
||||||
|
|
||||||
|
### 应用配置
|
||||||
|
该应用可配置的参数在ip2region.app.src中,如下:
|
||||||
|
``` erlang
|
||||||
|
{env,[
|
||||||
|
{poolargs, [
|
||||||
|
{size, 1}, %% 工作进程默认数量
|
||||||
|
{max_overflow, 5} %% 工作进程最大数量
|
||||||
|
]}
|
||||||
|
]}
|
||||||
|
```
|
||||||
|
|
||||||
### 编译
|
### 编译
|
||||||
|
|
||||||
|
|
@ -12,15 +25,20 @@ $ rebar3 compile
|
||||||
$ rebar3 shell
|
$ rebar3 shell
|
||||||
|
|
||||||
```
|
```
|
||||||
在erlang节点中执行以下指令查询Ip地址信息:
|
在erlang shell中调用xdb:search/1接口查询Ip地址信息, 该接口支持以list格式字符串、bianry格式字符串、tuple和整数表示的IP地址,如下:
|
||||||
```
|
```
|
||||||
1> ip2region:search("1.0.8.0").
|
1> xdb:search("1.0.8.0").
|
||||||
#{city => <<229,185,191,229,183,158,229,184,130>>,
|
[20013,22269,124,48,124,24191,19996,30465,124,24191,24030,
|
||||||
country => <<228,184,173,229,155,189>>,
|
24066,124,30005,20449]
|
||||||
isp => <<231,148,181,228,191,161>>,
|
|
||||||
province => <<229,185,191,228,184,156,231,156,129>>,
|
|
||||||
region => <<>>}
|
|
||||||
2>
|
2>
|
||||||
|
3> io:format("~ts~n", [xdb:search("1.0.8.0")]).
|
||||||
|
中国|0|广东省|广州市|电信
|
||||||
|
io:format("~ts~n", [xdb:search(<<"1.0.8.0">>)]).
|
||||||
|
中国|0|广东省|广州市|电信
|
||||||
|
4> io:format("~ts~n", [xdb:search({1,0,8,0})]).
|
||||||
|
中国|0|广东省|广州市|电信
|
||||||
|
6> io:format("~ts~n", [xdb:search(16779264)]).
|
||||||
|
中国|0|广东省|广州市|电信
|
||||||
```
|
```
|
||||||
|
|
||||||
### 使用方法
|
### 使用方法
|
||||||
|
|
@ -40,7 +58,7 @@ application:ensure_started(ip2region),
|
||||||
......
|
......
|
||||||
```
|
```
|
||||||
|
|
||||||
* 调用ip2region:search/1接口查询IP信息
|
* 调用xdb:search/1接口查询IP信息
|
||||||
```
|
```
|
||||||
......
|
......
|
||||||
|
|
||||||
|
|
@ -57,18 +75,30 @@ $ rebar3 eunit
|
||||||
===> Analyzing applications...
|
===> Analyzing applications...
|
||||||
===> Compiling ip2region
|
===> Compiling ip2region
|
||||||
===> Performing EUnit tests...
|
===> Performing EUnit tests...
|
||||||
=INFO REPORT==== 13-Jan-2023::21:26:15.137021 ===
|
=INFO REPORT==== 17-Jan-2023::11:52:59.920155 ===
|
||||||
XdbFile:/home/admin/erl-workspace/ip2region/binding/erlang/_build/test/lib/ip2region/priv/ip2region.xdb
|
XdbFile:/home/admin/erl-workspace/ip2region/binding/erlang/_build/test/lib/ip2region/priv/ip2region.xdb
|
||||||
...
|
|
||||||
Finished in 0.085 seconds
|
....
|
||||||
3 tests, 0 failures
|
Finished in 0.074 seconds
|
||||||
|
4 tests, 0 failures
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### 基准测试
|
### 基准测试
|
||||||
```
|
```
|
||||||
$ cd benchmarks/
|
$ cd benchmarks/
|
||||||
$ sh ip2region-benchmark.sh
|
$ sh xdb-benchmark.sh
|
||||||
|
===> Verifying dependencies...
|
||||||
|
===> Analyzing applications...
|
||||||
|
===> Compiling ip2region
|
||||||
|
Erlang/OTP 24 [erts-12.3.2.2] [source] [64-bit] [smp:2:2] [ds:2:2:10] [async-threads:1] [jit]
|
||||||
|
|
||||||
|
Eshell V12.3.2.2 (abort with ^G)
|
||||||
|
1> =INFO REPORT==== 17-Jan-2023::11:37:35.631095 ===
|
||||||
|
XdbFile:/home/admin/erl-workspace/ip2region/binding/erlang/_build/default/lib/ip2region/priv/ip2region.xdb
|
||||||
|
|
||||||
|
===> Booted ip2region
|
||||||
|
===> Evaluating: "xdb_benchmark:main(\"../../data/ip.merge.txt\"), init:stop()."
|
||||||
CPU info:
|
CPU info:
|
||||||
model name : AMD EPYC 7K62 48-Core Processor
|
model name : AMD EPYC 7K62 48-Core Processor
|
||||||
cache size : 512 KB
|
cache size : 512 KB
|
||||||
|
|
@ -78,21 +108,21 @@ cores/threads : 2
|
||||||
|
|
||||||
Erlang info:
|
Erlang info:
|
||||||
system_version:Erlang/OTP 24 [erts-12.3.2.2] [source] [64-bit] [smp:2:2] [ds:2:2:10] [async-threads:1] [jit]
|
system_version:Erlang/OTP 24 [erts-12.3.2.2] [source] [64-bit] [smp:2:2] [ds:2:2:10] [async-threads:1] [jit]
|
||||||
load test data use 2.724344s
|
load test data use 4.835593s
|
||||||
|
|
||||||
start run benchmark tests
|
start run benchmark tests
|
||||||
|
|
||||||
search from file:
|
search from file:
|
||||||
ip count:683844,
|
ip count:683844,
|
||||||
total time: 25.56304s,
|
total time: 28.201699s,
|
||||||
search 26751.27840820184 times per second,
|
search 24248.326315375536 times per second,
|
||||||
use 37.381391077497206 micro second per search
|
use 41.23995969841075 micro second per search
|
||||||
|
|
||||||
search from cache:
|
search from cache:
|
||||||
ip count:683844,
|
ip count:683844,
|
||||||
total time: 0.670307s,
|
total time: 0.671801s,
|
||||||
search 1020195.2239794602 times per second,
|
search 1017926.4395259906 times per second,
|
||||||
use 0.9802045495756342 micro second per search
|
use 0.9823892583688677 micro second per search
|
||||||
|
|
||||||
benchmark test finish
|
benchmark test finish
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
|
|
||||||
awk -v FS='|' '{print $1}' ../../../data/ip.merge.txt > test_data.txt
|
|
||||||
|
|
||||||
cd ..
|
|
||||||
|
|
||||||
rebar3 shell --eval="ip2region_benchmark:main(\"./benchmarks/test_data.txt\"), init:stop()."
|
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,5 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
cd ..
|
||||||
|
|
||||||
|
rebar3 shell --eval="xdb_benchmark:main(\"../../data/ip.merge.txt\"), init:stop()."
|
||||||
|
|
@ -1,30 +0,0 @@
|
||||||
|
|
||||||
%%%===============================================================
|
|
||||||
%%% @author leihua <leihua918@sina.com>
|
|
||||||
%%% @doc
|
|
||||||
%%% ip2region xdb 查询客户端
|
|
||||||
%%% Created: 2023-1-13 16:53
|
|
||||||
%%% @end
|
|
||||||
%%%===============================================================
|
|
||||||
-module(ip2region).
|
|
||||||
-include("ip2region.hrl").
|
|
||||||
|
|
||||||
-export([search/1]).
|
|
||||||
|
|
||||||
-spec search(Ip :: tuple() | list() | binary()) -> Result :: {error, Reason::atom()} | map().
|
|
||||||
search(Ip) ->
|
|
||||||
case ip2region_util:ipv4_to_n(Ip) of
|
|
||||||
IntIp when is_integer(IntIp) ->
|
|
||||||
case ets:lookup(?IP2REGION_CACHE, IntIp) of
|
|
||||||
[{_IntIp, Region}] -> Region;
|
|
||||||
_ ->
|
|
||||||
Worker = poolboy:checkout(?IP2REGION_POOL, true, infinity),
|
|
||||||
try
|
|
||||||
ip2region_worker:search(Worker, IntIp)
|
|
||||||
after
|
|
||||||
poolboy:checkin(?IP2REGION_POOL, Worker)
|
|
||||||
end
|
|
||||||
end;
|
|
||||||
Ret ->
|
|
||||||
Ret
|
|
||||||
end.
|
|
||||||
|
|
@ -1,5 +1,9 @@
|
||||||
%%%-------------------------------------------------------------------
|
%%%-------------------------------------------------------------------
|
||||||
%% @doc ip2region public API
|
%% Copyright 2022 The Ip2Region Authors. All rights reserved.
|
||||||
|
%% Use of this source code is governed by a Apache2.0-style
|
||||||
|
%% license that can be found in the LICENSE file.
|
||||||
|
%%
|
||||||
|
%% @doc
|
||||||
%% @end
|
%% @end
|
||||||
%%%-------------------------------------------------------------------
|
%%%-------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,8 @@
|
||||||
%%%-------------------------------------------------------------------
|
%%%-------------------------------------------------------------------
|
||||||
|
%% Copyright 2022 The Ip2Region Authors. All rights reserved.
|
||||||
|
%% Use of this source code is governed by a Apache2.0-style
|
||||||
|
%% license that can be found in the LICENSE file.
|
||||||
|
%%
|
||||||
%% @doc ip2region top level supervisor.
|
%% @doc ip2region top level supervisor.
|
||||||
%% @end
|
%% @end
|
||||||
%%%-------------------------------------------------------------------
|
%%%-------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,12 @@
|
||||||
|
%%%-------------------------------------------------------------------
|
||||||
|
%% Copyright 2022 The Ip2Region Authors. All rights reserved.
|
||||||
|
%% Use of this source code is governed by a Apache2.0-style
|
||||||
|
%% license that can be found in the LICENSE file.
|
||||||
|
%%
|
||||||
|
%% @doc
|
||||||
|
%% ip2region utils
|
||||||
|
%% @end
|
||||||
|
%%%-------------------------------------------------------------------
|
||||||
-module(ip2region_util).
|
-module(ip2region_util).
|
||||||
-export([ipv4_to_n/1]).
|
-export([ipv4_to_n/1]).
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,12 @@
|
||||||
%%%===============================================================
|
%%%-------------------------------------------------------------------
|
||||||
%%% @author leihua <leihua918@sina.com>
|
%% Copyright 2022 The Ip2Region Authors. All rights reserved.
|
||||||
%%% @doc
|
%% Use of this source code is governed by a Apache2.0-style
|
||||||
%%% ip2region工作进程
|
%% license that can be found in the LICENSE file.
|
||||||
%%% Created: 2023-1-13 16:53
|
%%
|
||||||
%%% @end
|
%% @doc
|
||||||
%%%===============================================================
|
%% ip2region xdb client worker
|
||||||
|
%% @end
|
||||||
|
%%%-------------------------------------------------------------------
|
||||||
-module(ip2region_worker).
|
-module(ip2region_worker).
|
||||||
-behaviour(gen_server).
|
-behaviour(gen_server).
|
||||||
-include("ip2region.hrl").
|
-include("ip2region.hrl").
|
||||||
|
|
@ -37,6 +39,7 @@ search(Pid, Ip) ->
|
||||||
%% gen_server callbacks
|
%% gen_server callbacks
|
||||||
%% =========================================
|
%% =========================================
|
||||||
init(_Args) ->
|
init(_Args) ->
|
||||||
|
process_flag(trap_exit, true),
|
||||||
AppName =
|
AppName =
|
||||||
case application:get_application() of
|
case application:get_application() of
|
||||||
{ok, AName} -> AName;
|
{ok, AName} -> AName;
|
||||||
|
|
@ -159,14 +162,7 @@ search_ip(IoDevice, IntIp, SPtr, EPtr, Low, High) when Low =< High ->
|
||||||
search_ip(IoDevice, IntIp, SPtr, EPtr, Middle + 1, High);
|
search_ip(IoDevice, IntIp, SPtr, EPtr, Middle + 1, High);
|
||||||
true ->
|
true ->
|
||||||
{ok, DataBin} = read_file(IoDevice, DataPtr, DataLen),
|
{ok, DataBin} = read_file(IoDevice, DataPtr, DataLen),
|
||||||
[Country, Region, Province, City, ISP] = string:tokens(binary_to_list(DataBin), "|"),
|
unicode:characters_to_nfc_list(DataBin)
|
||||||
#{
|
|
||||||
country => ?IF(Country == "0", <<>>, list_to_binary(Country)),
|
|
||||||
region => ?IF(Region == "0", <<>>, list_to_binary(Region)),
|
|
||||||
province => ?IF(Province == "0", <<>>, list_to_binary(Province)),
|
|
||||||
city => ?IF(City == "0", <<>>, list_to_binary(City)),
|
|
||||||
isp => ?IF(ISP == "0", <<>>, list_to_binary(ISP))
|
|
||||||
}
|
|
||||||
end;
|
end;
|
||||||
search_ip(_IoDevice, _IntIp, _SPtr, _EPtr, _Low, _High) ->
|
search_ip(_IoDevice, _IntIp, _SPtr, _EPtr, _Low, _High) ->
|
||||||
{error, unknown}.
|
{error, unknown}.
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
|
||||||
|
%%%-------------------------------------------------------------------
|
||||||
|
%% Copyright 2022 The Ip2Region Authors. All rights reserved.
|
||||||
|
%% Use of this source code is governed by a Apache2.0-style
|
||||||
|
%% license that can be found in the LICENSE file.
|
||||||
|
%%
|
||||||
|
%% @doc
|
||||||
|
%% ip2region xdb client search api
|
||||||
|
%% @end
|
||||||
|
%%%-------------------------------------------------------------------
|
||||||
|
-module(xdb).
|
||||||
|
-include("ip2region.hrl").
|
||||||
|
|
||||||
|
-export([search/1]).
|
||||||
|
|
||||||
|
-spec search(Ip :: tuple() | list() | binary()) -> Result :: binary | {error, Reason::atom()}.
|
||||||
|
search(Ip) when is_integer(Ip); is_list(Ip); is_tuple(Ip); is_binary(Ip) ->
|
||||||
|
case ip2region_util:ipv4_to_n(Ip) of
|
||||||
|
IntIp when is_integer(IntIp) ->
|
||||||
|
case ets:lookup(?IP2REGION_CACHE, IntIp) of
|
||||||
|
[{_IntIp, Region}] -> Region;
|
||||||
|
_ ->
|
||||||
|
Worker = poolboy:checkout(?IP2REGION_POOL, true, infinity),
|
||||||
|
try
|
||||||
|
ip2region_worker:search(Worker, IntIp)
|
||||||
|
after
|
||||||
|
poolboy:checkin(?IP2REGION_POOL, Worker)
|
||||||
|
end
|
||||||
|
end;
|
||||||
|
Ret ->
|
||||||
|
Ret
|
||||||
|
end.
|
||||||
|
|
@ -1,11 +1,13 @@
|
||||||
%%%===============================================================
|
%%%-------------------------------------------------------------------
|
||||||
%%% @author leihua <leihua918@sina.com>
|
%% Copyright 2022 The Ip2Region Authors. All rights reserved.
|
||||||
%%% @doc
|
%% Use of this source code is governed by a Apache2.0-style
|
||||||
%%% ip2region性能基准测试
|
%% license that can be found in the LICENSE file.
|
||||||
%%% Created: 2023-1-13 17:46
|
%%
|
||||||
%%% @end
|
%% @doc
|
||||||
%%%===============================================================
|
%% ip2region xdb client benchmark test
|
||||||
-module(ip2region_benchmark).
|
%% @end
|
||||||
|
%%%-------------------------------------------------------------------
|
||||||
|
-module(xdb_benchmark).
|
||||||
-export([main/1]).
|
-export([main/1]).
|
||||||
|
|
||||||
main(DataFile) ->
|
main(DataFile) ->
|
||||||
|
|
@ -37,7 +39,12 @@ load_test_data(DataFile) ->
|
||||||
load_test_data(Fd, IpList) ->
|
load_test_data(Fd, IpList) ->
|
||||||
case file:read_line(Fd) of
|
case file:read_line(Fd) of
|
||||||
{ok, Ip} ->
|
{ok, Ip} ->
|
||||||
load_test_data(Fd, [string:trim(Ip)| IpList]);
|
case string:tokens(unicode:characters_to_list(Ip), "|") of
|
||||||
|
[SIp | _Tail] ->
|
||||||
|
load_test_data(Fd, [string:trim(SIp)| IpList]);
|
||||||
|
_ ->
|
||||||
|
load_test_data(Fd, IpList)
|
||||||
|
end;
|
||||||
_ ->
|
_ ->
|
||||||
file:close(Fd),
|
file:close(Fd),
|
||||||
IpList
|
IpList
|
||||||
|
|
@ -63,6 +70,6 @@ run_test(IpList) ->
|
||||||
|
|
||||||
run_test_aux([]) -> ok;
|
run_test_aux([]) -> ok;
|
||||||
run_test_aux([Ip | Tail]) ->
|
run_test_aux([Ip | Tail]) ->
|
||||||
#{} = ip2region:search(Ip),
|
xdb:search(Ip),
|
||||||
run_test_aux(Tail).
|
run_test_aux(Tail).
|
||||||
|
|
||||||
|
|
@ -1,22 +0,0 @@
|
||||||
-module(ip2region_test).
|
|
||||||
|
|
||||||
-include_lib("eunit/include/eunit.hrl").
|
|
||||||
|
|
||||||
search_test_() ->
|
|
||||||
application:ensure_started(ip2region),
|
|
||||||
A = #{
|
|
||||||
city => <<"广州市"/utf8>>,
|
|
||||||
country => <<"中国"/utf8>>,
|
|
||||||
isp => <<"电信"/utf8>>,
|
|
||||||
province => <<"广东省"/utf8>>,
|
|
||||||
region => <<>>
|
|
||||||
},
|
|
||||||
Region1 = ip2region:search("1.0.8.0"),
|
|
||||||
Region2 = ip2region:search({1,0,8,0}),
|
|
||||||
Region3 = ip2region:search("xxx.0.8.0"),
|
|
||||||
[
|
|
||||||
?_assert(A =:= Region1),
|
|
||||||
?_assert(A =:= Region2),
|
|
||||||
?_assert({error, bad_ip_format} =:= Region3)
|
|
||||||
|
|
||||||
].
|
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
-module(xdb_test).
|
||||||
|
|
||||||
|
-include_lib("eunit/include/eunit.hrl").
|
||||||
|
|
||||||
|
search_test_() ->
|
||||||
|
application:ensure_started(ip2region),
|
||||||
|
A = "中国|0|广东省|广州市|电信",
|
||||||
|
Region0 = xdb:search("1.0.8.0"),
|
||||||
|
Region1 = xdb:search(<<"1.0.8.0">>),
|
||||||
|
Region2 = xdb:search({1,0,8,0}),
|
||||||
|
Region3 = xdb:search("xxx.0.8.0"),
|
||||||
|
[
|
||||||
|
?_assert(A =:= Region0),
|
||||||
|
?_assert(A =:= Region1),
|
||||||
|
?_assert(A =:= Region2),
|
||||||
|
?_assert({error, bad_ip_format} =:= Region3)
|
||||||
|
|
||||||
|
].
|
||||||
Loading…
Reference in New Issue