博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Nginx、OpenResty和Kong的基本概念与使用方法
阅读量:5288 次
发布时间:2019-06-14

本文共 12819 字,大约阅读时间需要 42 分钟。

Nginx、OpenResty和Kong的基本概念与使用方法

版权声明:本文为博主原创文章,遵循版权协议,转载请附上原文出处链接和本声明。
本文链接:

作者:    转载请保留:   发布时间:2018-09-29 15:41:50 +0800

 

 

说明

、、这三个项目紧密相连: Nginx是模块化设计的反向代理软件,C语言开发; OpenResty是以Nginx为核心的Web开发平台,可以解析执行Lua脚本(OpenResty与Lua的关系,类似于Jvm与Java,不过Java可以做的事情太多了,OpenResty主要用来做Web、API等); Kong是一个OpenResty应用,是一个api gateway,具有API管理和请求代理的功能。

Nginx

Nginx是HTTP Server、反向代理服务器、邮件代理服务器、通用的TCP/UDP代理服务器。详细列出了nginx的功能特性。

Nginx配置文件,指令与变量

Nginx的配置文件由单指令(simple directive)块指令(block directive)组成,单指令只有一行,以“;”结尾,块指令后面是用“{ }”包裹的多行内容。

有些块指令后的花括号中可以继续包含单指令,这样的块指令被成为配置上下文(context),这样的指令有:events、http、server、location等。

context是嵌套的,最外层的context是main context,配置文件中不在{}的中指令都是位于main context中。

events和http指令位于main context,server位于http context,location位于server context:

  1.  
    main context
  2.  
    - events
  3.  
    - http
  4.  
    - server
  5.  
    - location

配置文件示例见: ,例如:

  1.  
    http {
  2.  
    server {
  3.  
    listen
    8080; # server监听端口,不指定默认80
  4.  
    root /data/up1;
    # 默认文件查找根目录
  5.  
     
  6.  
    # 将请求按照uri进行分组处理
  7.  
    location / {
    # 选择最常匹配的location,如果不匹配任何location,返回404
  8.  
    root /data/www;
    # 文件查找根目录,覆盖server中的root配置
  9.  
    }
  10.  
     
  11.  
    # uri路径匹配,优先级低于下面的正则匹配!
  12.  
    location /images/ {
  13.  
    root /data;
  14.  
    }
  15.  
     
  16.  
    # 使用正则表达式匹配(必须带有"~ "前缀):匹配文件后缀名
  17.  
    location ~ \.(gif|jpg|png)$ {
    # 优先级高于uri路径匹配
  18.  
    root /data/images;
  19.  
    }
  20.  
     
  21.  
    # 作为代理服务器的配置方法
  22.  
    location /proxy/ {
    # 将uri匹配的请求转发到proxy_pass指定的地址
  23.  
    proxy_pass http:
    //IP地址:8080;
  24.  
    }
  25.  
     
  26.  
    # 将请求代理到FastCGI
  27.  
    # fastcgi_param是按照FastCGI的要求传递的参数,可以有多个,后面的`$XXX`是Nginx变量,拼成了参数的值
  28.  
    location /fastcgi/ {
  29.  
    fastcgi_pass localhost:
    9000; # fastCGI服务的地址
  30.  
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    # 传给fastCGI服务的参数: SCRIPT_FILENAME
  31.  
    fastcgi_param QUERY_STRING $query_string;
    # 传给fastCGI服务的参数: QUERY_STRING
  32.  
    }
  33.  
    }
  34.  
    }

上面的例子中的proxy_passfactcgi_pass分别是nginx的和中指令。

Nginx有很多的module,在中可以查看每个modules的用法。

中列出了Nginx的所有指令。

中列出了可以在配置文件中使用的所有变量。

在查看Nginx指令用法的时候,注意指令的context:

  1.  
    Syntax: gzip
    on | off;
  2.  
    Default: gzip off;
  3.  
    Context: http, server, location,
    if in location # 可以使用gzip指令的地方

Nginx作为TCP/UDP负载均衡器

Nginx原本只能做7层(http)代理,在1.9.0版本中增加了4层(TCP/UDP)代理功能。

4层代理功能在Nginx的模块中实现,但默认没有编译,需要在编译时指定: –with-stream。

使用配置如下:

  1.  
    worker_processes auto;
  2.  
     
  3.  
    error_log /var/
    log/nginx/error.log info;
  4.  
     
  5.  
    events {
  6.  
    worker_connections
    1024;
  7.  
    }
  8.  
     
  9.  
    stream {
  10.  
    upstream backend {
  11.  
    hash $remote_addr consistent;
  12.  
     
  13.  
    server backend1.example.com:12345 weight=5;
  14.  
    server 127.0.0.1:12345 max_fails=3 fail_timeout=30s;
  15.  
    server unix:/tmp/backend3;
  16.  
    }
  17.  
     
  18.  
    upstream dns {
  19.  
    server 192.168.0.1:53535;
  20.  
    server dns.example.com:53;
  21.  
    }
  22.  
     
  23.  
    server {
  24.  
    listen
    12345;
  25.  
    proxy_connect_timeout
    1s;
  26.  
    proxy_timeout
    3s;
  27.  
    proxy_pass backend;
  28.  
    }
  29.  
     
  30.  
    server {
  31.  
    listen
    127.0.0.1:53 udp reuseport;
  32.  
    proxy_timeout
    20s;
  33.  
    proxy_pass dns;
  34.  
    }
  35.  
     
  36.  
    server {
  37.  
    listen [::
    1]:12345;
  38.  
    proxy_pass unix:/tmp/stream.socket;
  39.  
    }
  40.  
    }

Nginx模块

理解Nginx Module很重要,因为后面的OpenResty就是标准的Nginx加上很多Nginx Module。

Nginx是用C语言开发软件,采用模块化设计,可以通过开发模块扩展Nginx的功能。

中介绍了Nginx模块开发的方法。

插件可以编译成.so以后动态加载,也可以直接编译到nginx中,编译是通过--add-module指定要集成的模块。

例如:

  1.  
    ./configure --prefix=
    /opt/nginx \
  2.  
    --
    with-ld-opt="-Wl,-rpath,/path/to/luajit-or-lua/lib" \
  3.  
    --add-
    module=/path/to/ngx_devel_kit \
  4.  
    --add-
    module=/path/to/lua-nginx-module

OpenResty

是一个集成了Nginx、LuaJIT和其它很多moudels的平台,用来托管完整的web应用——包含业务逻辑,而不单纯是静态文件服务器: OpenResty® aims to run your server-side web app completely in the Nginx server, leveraging Nginx’s event model to do non-blocking I/O not only with the HTTP clients, but also with remote backends like MySQL, PostgreSQL, Memcached, and Redis.

中列出了OpenResty集成的组件,数量不少,这里就不列出来了。

先通过感受一下OpenResty是咋回事。

OpenResty安装

Centos安装方式:

  1.  
    sudo yum
    install yum-utils
  2.  
    sudo yum-config-manager
    --add-repo https://openresty.org/package/centos/openresty.repo
  3.  
    sudo yum
    install openresty
  4.  
    sudo yum
    install openresty-resty

通过源代码编译:

  1.  
    wget https:
    //openresty.org/download/openresty-1.13.6.2.tar.gz
  2.  
    tar -xvf openresty
    -1.13.6.2.tar.gz
  3.  
    cd openresty
    -1.13.6.2/
  4.  
    ./configure --
    with-pcre-jit --with-http_ssl_module --with-http_realip_module --with-http_stub_status_module --with-http_v2_module
  5.  
    make -j2
  6.  
    make install
    //默认安装在/usr/local/bin/openresty
  7.  
    export PATH=/usr/local/openresty/bin:$PATH

为了后面顺利的使用kong,configure时要指定kong依赖的模块。

都包含以下文件:

  1.  
    $ tree -L 2 /usr/local/openresty/
  2.  
    /usr/local/openresty/
  3.  
    |
    -- bin
  4.  
    | |
    -- md2pod.pl
  5.  
    | |
    -- nginx-xml2pod
  6.  
    | |
    -- openresty -> /usr/local/openresty/nginx/sbin/nginx
  7.  
    | |
    -- opm
  8.  
    | |
    -- resty
  9.  
    | |
    -- restydoc
  10.  
    | `
    -- restydoc-index
  11.  
    |
    -- COPYRIGHT
  12.  
    |
    -- luajit
  13.  
    | |
    -- bin
  14.  
    | |
    -- include
  15.  
    | |
    -- lib
  16.  
    | `
    -- share
  17.  
    ...

注意openresty命令就是nginx命令,OpenResty可以理解为一个集成了很多模块的定制版nginx:

  1.  
    $ openresty -h
  2.  
    nginx version: openresty/1.13.6.2
  3.  
    Usage: nginx [-?hvVtTq] [-s signal] [-c filename] [-p prefix] [-g directives]
  4.  
     
  5.  
    Options:
  6.  
    -?,-h : this
    help
  7.  
    -v :
    show version and exit
  8.  
    -V :
    show version and configure options then exit
  9.  
    -t :
    test configuration and exit
  10.  
    -T :
    test configuration, dump it and exit
  11.  
    -q : suppress non-
    error messages during configuration testing
  12.  
    -s signal : send signal
    to a master process: stop, quit, reopen, reload
  13.  
    -p prefix :
    set prefix path (default: /usr/local/openresty/nginx/)
  14.  
    -c filename :
    set configuration file (default: conf/nginx.conf)
  15.  
    -g directives :
    set global directives out of configuration file

可以在openresty的配置文件中写入lua代码:

  1.  
    $ cat nginx.conf
  2.  
    worker_processes
    1;
  3.  
    error_log logs/
    error.log;
  4.  
    events {
  5.  
    worker_connections
    1024;
  6.  
    }
  7.  
    http {
  8.  
    server {
  9.  
    listen
    8080;
  10.  
    location / {
  11.  
    default_type text/html;
  12.  
    content_by_lua
    '
  13.  
    ngx.say(
    "<p>hello, world</p>")
  14.  
    ';
  15.  
    }
  16.  
    }
  17.  
    }

启动:

openresty -p `pwd` -c nginx.conf

然后访问”127.0.0.1:8080”,可以看到输出:

  1.  
    $ curl 127.0.0.1:8080
  2.  
    <p>hello, world</p>

Kong

是一个OpenResty应用,用来管理api。

Kong编译安装

Kong时需要先安装有OpenResty。

还需要lua包管理工具:

  1.  
    git clone git:
    //github.com/luarocks/luarocks.git
  2.  
    ./configure --lua-suffix=jit --
    with-lua=/usr/local/openresty/luajit --with-lua-include=/usr/local/openresty/luajit/include/luajit-2.1
  3.  
    make install

下载kong代码编译:

  1.  
    git clone https:
    //github.com/Kong/kong.git
  2.  
    cd kong
  3.  
    make install

编译完成之后会在当前目录生成一个bin目录:

  1.  
    $ ls bin/
  2.  
    busted kong

查看bin/kong的内容,可以发现这是一个用resty执行的脚本文件:

  1.  
    $ cat bin/kong
  2.  
    #!/usr/bin/env resty
  3.  
     
  4.  
    require "luarocks.loader"
  5.  
     
  6.  
    package.path =
    "./?.lua;./?/init.lua;" .. package.path
  7.  
     
  8.  
    require("kong.cmd.init")(arg)

启动Kong

先准备数据库,kong支持PostgreSQL和Cassandra 3.x.x,这里使用PostgreSQL(需要版本在9.4及以上):

注意,如果使用其它版本的PostgreSQL,将下面的9.6换成对应版本号。

  1.  
    yum
    install https://download.postgresql.org/pub/repos/yum/9.6/redhat/rhel-7-x86_64/pgdg-centos96-9.6-3.noarch.rpm
  2.  
    yum
    install postgresql96
  3.  
    yum
    install postgresql96-server
  4.  
    export PATH=$PATH:/usr/pgsql-9.6/bin/
  5.  
    postgresql96-setup initdb
  6.  
    systemctl
    start postgresql-9.6
  7.  
    su - postgres
  8.  
    psql
  9.  
    CREATE USER kong; CREATE DATABASE kong OWNER kong;
  10.  
    alter user kong with encrypted password '123456';
  11.  
    \q

在/var/lib/pgsql/9.6/data/pg_hba.conf的开始处添加规则下面规则:

host    kong            kong            127.0.0.1/32            md5

然后重启PostgreSQL,确保下面的命令能登陆PostgreSQL:

  1.  
    # psql -h 127.0.0.1 -U kong kong -W
  2.  
    Password
    for user kong:
  3.  
    psql (
    9.6.10)
  4.  
    Type
    "help" for help.
  5.  
     
  6.  
    kong=>

PostgreSQL的部署使用和通过密码登陆方式的设置参考:、。

准备kong的配置文件,

  1.  
    cp kong.conf.default kong.conf
  2.  
    # 在
    kong.conf中填入数据地址、用户、密码等

创建kong的数据库:

./bin/kong migrations up -c ./kong.conf

启动kong:

./bin/kong start -c ./kong.conf

kong默认的代理地址是:

proxy_listen = 0.0.0.0:8000, 0.0.0.0:8443

默认的管理地址是:

admin_listen = 127.0.0.1:8001, 127.0.0.1:8444 ssl

返回的是json字符串:

  1.  
    $ curl -i
    http://localhost:8001/
  2.  
    HTTP/
    1.1 200 OK
  3.  
    Date: Sat, 29 Sep 2018 08:56:51 GMT
  4.  
    Content-
    Type: application/json; charset=utf-8
  5.  
    Connection: keep-alive
  6.  
    Access-Control-Allow-
    Origin: *
  7.  
    Server: kong/0.14.1
  8.  
    Content-
    Length: 5667
  9.  
     
  10.  
    {
    "plugins":{
    "enabled_in_cluster":[],"availab...
  11.  
     

部署Kong Dashboard

是一个第三方的Dashboard。

  1.  
    docker run
    --rm -p 8080:8080 pgbi/kong-dashboard start \
  2.  
    --kong-url http://kong:8001
  3.  
    --basic-auth user1=password1 user2=password2

Kong的使用

停止:

kong stop

重新加载:

kong reload

注册API:添加服务、配置路由

添加服务。

添加一个名为example-service的服务,服务地址是http://mockbin.org

  1.  
    curl -i -X POST \
  2.  
    --url http:
    //localhost:8001/services/ \
  3.  
    --
    data 'name=example-service' \
  4.  
    --
    data 'url=http://mockbin.org'

执行后返回:

  1.  
    {
  2.  
    "connect_timeout": 60000,
  3.  
    "created_at": 1538213979,
  4.  
    "host": "mockbin.org",
  5.  
    "id": "ebed2707-e2fb-4694-9e8e-fb66fe9dd7c8",
  6.  
    "name": "example-service",
  7.  
    "path": null,
  8.  
    "port": 80,
  9.  
    "protocol": "http",
  10.  
    "read_timeout": 60000,
  11.  
    "retries": 5,
  12.  
    "updated_at": 1538213979,
  13.  
    "write_timeout": 60000
  14.  
    }

example-service添加一个route,满足route的请求将被转发给example-service,执行:

  1.  
    curl -i -X POST \
  2.  
    --url http:
    //localhost:8001/services/example-service/routes \
  3.  
    --
    data 'hosts[]=example.com'

这里配置的route条件是:host为example.com。

返回:

  1.  
    {
  2.  
    "created_at": 1538185340,
  3.  
    "hosts": [
  4.  
    "example.com"
  5.  
    ],
  6.  
    "id": "4738ae2c-b64a-4fe5-9e2a-5855e769a9e8",
  7.  
    "methods": null,
  8.  
    "paths": null,
  9.  
    "preserve_host": false,
  10.  
    "protocols": [
  11.  
    "http",
  12.  
    "https"
  13.  
    ],
  14.  
    "regex_priority": 0,
  15.  
    "service": {
  16.  
    "id": "ebed2707-e2fb-4694-9e8e-fb66fe9dd7c8"
  17.  
    },
  18.  
    "strip_path": true,
  19.  
    "updated_at": 1538185340
  20.  
    }

这时候访问kong的proxy地址时,如果host为example.com,请求被转发到http://mockbin.org

  1.  
    curl -i -X GET \
  2.  
    --url http:
    //localhost:8000/ \
  3.  
    --header
    'Host: example.com'

可以在/etc/hostsname中将example.com地址配置为kong所在的机器的地址:

10.10.192.35 example.com

然后就可以通过example.com:8000打开http://mockbin.org。

插件启用方法

插件是用来扩展API的,例如为API添加认证、设置ACL、限制速率等、集成oauth、ldap等。

中列出了已有的所有插件。

这里演示插件的用法,,。

  1.  
    curl -i -X POST \
  2.  
    --url http:
    //localhost:8001/services/example-service/plugins/ \
  3.  
    --
    data 'name=key-auth'

返回:

  1.  
    {
  2.  
    "config": {
  3.  
    "anonymous": "",
  4.  
    "hide_credentials": false,
  5.  
    "key_in_body": false,
  6.  
    "key_names": [
  7.  
    "apikey"
  8.  
    ],
  9.  
    "run_on_preflight": true
  10.  
    },
  11.  
    "created_at": 1538218948000,
  12.  
    "enabled": true,
  13.  
    "id": "f25f3952-d0d4-4923-baac-860554fc2fc1",
  14.  
    "name": "key-auth",
  15.  
    "service_id": "ebed2707-e2fb-4694-9e8e-fb66fe9dd7c8"
  16.  
    }

这时候直接访问example.com,会返回401:

  1.  
    curl -i -X GET \
  2.  
    > --url http:
    //localhost:8000/ \
  3.  
    > --header
    'Host: example.com'
  4.  
    HTTP/
    1.1 401 Unauthorized
  5.  
    Date: Sat, 29 Sep 2018 11:03:55 GMT
  6.  
    Content-Type: application/json; charset=utf
    -8
  7.  
    Connection: keep-alive
  8.  
    WWW-Authenticate: Key realm=
    "kong"
  9.  
    Server: kong/
    0.14.1
  10.  
    Content-Length:
    41

在kong中创建一个名为Jason的用户:

  1.  
    curl -i -X POST \
  2.  
    --url http:
    //localhost:8001/consumers/ \
  3.  
    --
    data "username=Jason"

返回:

  1.  
    {
  2.  
    "created_at": 1538219225,
  3.  
    "custom_id": null,
  4.  
    "id": "f2450962-e4bb-477f-8df6-85984eb94e09",
  5.  
    "username": "Jason"
  6.  
    }

将Jason的密码设置为123456:

  1.  
    curl -i -X POST \
  2.  
    --url http:
    //localhost:8001/consumers/Jason/key-auth/ \
  3.  
    --
    data 'key=123456'

返回:

  1.  
    {
  2.  
    "consumer_id": "f2450962-e4bb-477f-8df6-85984eb94e09",
  3.  
    "created_at": 1538219311000,
  4.  
    "id": "0332d36f-61b9-425a-b563-510c11a85e85",
  5.  
    "key": "123456"
  6.  
    }

这时候可以用Jason的key访问API:

  1.  
    curl -i -X GET \
  2.  
    --url http:
    //localhost:8000 \
  3.  
    --header
    "Host: example.com" \
  4.  
    --header
    "apikey: 123456"

返回的是mockbin.org的首页。

key-auth插件的详细用法参考。插件的作用范围可以是全局(global)、服务(service)、路由(router)。

启用key-auth后,通过认证的请求被转发给上游服务时,key-auth会增设下面的字段:

  1.  
    X-Consumer-ID, the ID
    of the Consumer on Kong
  2.  
    X-Consumer-
    Custom-ID, the custom_id of the Consumer (if set)
  3.  
    X-Consumer-Username, the username
    of the Consumer (if set)
  4.  
    X-Credential-Username, the username
    of the Credential (only if the consumer is not the 'anonymous' consumer)
  5.  
    X-Anonymous-Consumer, will be
    set to true when authentication failed, and the 'anonymous' consumer was set instead.

Kong的插件

中列出了已有的所有插件,有些插件只能在企业版使用,有些插件是社区成员开发的,大部分是Kong公司开发,并集成到社区版中。

下面是社区版集成的、Kong公司维护的插件(2018-09-30 14:33:03):

认证插件:

  1.  
    Basic Auth
  2.  
    HMAC Auth
  3.  
    JWT Auth
  4.  
    Key Auth
  5.  
    LDAP Auth
  6.  
    OAuth 2.0 Auth

安全插件:

  1.  
    Bot Detection (机器人检测)
  2.  
    CORS (跨域请求)
  3.  
    IP Restriction (IP限制)

流控插件:

  1.  
    ACL (访问控制)
  2.  
    Rate Limiting (限速)
  3.  
    Request Size Limiting
  4.  
    Request Termination
  5.  
    Response Rate Limiting

微服务插件:

  1.  
    AWS Lambda
  2.  
    Azure Functions
  3.  
    Apache OpenWhisk
  4.  
    Serverless Functions

分析和监控插件:

  1.  
    Datadog
  2.  
    Prometheus
  3.  
    Zipkin

内容修改插件(Transformations):

  1.  
    Correlation ID
  2.  
    Request Transformer
  3.  
    Response Transformer

日志插件:

  1.  
    File
    Log
  2.  
    HTTP
    Log
  3.  
    Loggly
  4.  
    StatsD
  5.  
    Syslog
  6.  
    TCP
    Log
  7.  
    UDP
    Log

Kong与Kubernetes的集成

经过前面的学习,对Api网关是什么,以及Kong能够做什么已经有了足够的了解。现在Kubernetes一统计算资源与应用发布编排的趋势已经形成,我们更关心Kong能否和Kubernetes结合。

Kong是一个Api网关,也是一个特性更丰富的反向代理,既然它有代理流量的功能,那么能不能直接成为Kubernetes的流量入口?使Kubernetes内部的服务都通过Kong发布。

Kong实现了一个来做这件事。在Kubernetes中部署kong的方法见。

这部分内容比较多,单独开篇了: 。

遇到的问题

ERROR: module ‘socket’ not found:No LuaRocks module found for socket

启动的时候:

  1.  
    # ./bin/kong start -c ./kong.conf
  2.  
    ...
  3.  
    ERROR: ./kong/globalpatches.lua:
    63: module 'socket' not found:No LuaRocks module found for socket
  4.  
    ...

这是因为编译kong之后,重新编译了luarocks,并且将luarocks安装在了其它位置。重新编译kong之后解决。

ERROR: function to_regclass(unknown) does not exist (8)

创建数据库的时候:

  1.  
    # kong migrations up -c ./kong.conf
  2.  
    ...
  3.  
    [postgres
    error] could not retrieve current migrations: [postgres error] ERROR: function to_regclass(unknown) does not exist (8)
  4.  
    ...

这是因为PostgreSQL的版本太低了,to_regclass在PostgreSQL 9.4及以上的版本中才存在。

  1.  
    yum
    install https://download.postgresql.org/pub/repos/yum/9.6/redhat/rhel-7-x86_64/pgdg-centos96-9.6-3.noarch.rpm
  2.  
    yum
    install postgresql96
  3.  
    yum
    install postgresql96-server

nginx: [emerg] unknown directive “real_ip_header” in /usr/local/kong/nginx-kong.conf:73

nginx: [emerg] unknown directive "real_ip_header" in /usr/local/kong/nginx-kong.conf:73

这是因为编译的openresty的时候,没有指定--with-http_realip_module,重新编译安装:

  1.  
    ./configure
    --with-pcre-jit --with-http_ssl_module --with-http_realip_module --with-http_stub_status_module --with-http_v2_module
  2.  
    make -j2
  3.  
    make
    install //默认安装在/usr/local/bin/openresty
  4.  
    export PATH=/usr/local/openresty/bin:$PATH

参考

限时活动,每邀请一人即返回25元!

相关文章

转载于:https://www.cnblogs.com/think90/p/11454992.html

你可能感兴趣的文章
out对象
查看>>
8086微处理器的组成和工作原理
查看>>
数据分析之Pandas(三) DataFrame入门
查看>>
sql 数字转换为字符串补0
查看>>
C++学习(37)
查看>>
CSS 基础
查看>>
对不起,这是一篇负能量爆棚的文章
查看>>
意寥寥
查看>>
自定义Android Studio方法注释模板
查看>>
透过一道面试题来探探JavaScript中执行上下文和变量对象的底
查看>>
C语言运算符优先级 详细列表 <转>
查看>>
423 Reconstruct Original Digits from English 从英文中重建数字
查看>>
修复IE6 PNG不透明问题的最佳解决方案
查看>>
OA系统如何使用考勤机数据
查看>>
评价PE基金绩效的常用指标
查看>>
数学相关结论整理(没有证明)
查看>>
MySQL用户变量的用法
查看>>
HDU 2002 计算球体积
查看>>
Java第八次作业 1502 马 帅
查看>>
大数据时代,百货行业信息化将如何变革?
查看>>