Preparando datos vectoriales
Configuraciones preliminares
A la hora de publicar datos vectoriales podemos hacer las elecciones significativas siguientes:
- Publicar en formato shapefile
- Meter los datos en una base de datos PostGIS
Partimos de datos de OpenStreetMap de Toulouse, que ocupan unos 80Mb en Shapefile. Estos datos son cargados en PostGIS y se crean dos capas en GeoServer, una que accede al shapefile llamada toulouse_shp
y otra que accede a la tabla en PostGIS llamada toulouse_postgis
.
Para que el uso de PostGIS tenga sentido, es necesaria la creación de índices tanto en la clave primaria como en la columna geométrica. Los índices espaciales nos permitirán mejorar la eficiencia de las consultas mediante el uso del operador caja de PostGIS. Como se puede ver en la imagen a continuación, para que la consulta sea más efectiva, si buscamos los objetos que intersectan a la estrella amarilla, usando las cajas que encierran los elementos podremos descartar ciertos elementos de los que observamos que ni siquiera sus cajas se intersectan.
Por tanto, tras realizar la carga:
USER=portal_admin
DB=portal
psql -U $USER -d $DB -c "CREATE SCHEMA gis;"
shp2pgsql -s 4326 gis.osm_buildings_v06.shp gis.toulouse | psql -U $USER -d $DB
Podemos comprobar si existen los índices creados en la tabla mediante:
portal=> \d gis.toulouse;
gid | integer | not null default nextval('gis.toulouse_gid_seq'::regclass)
osm_id | numeric(10,0) |
lastchange | character varying(20) |
code | smallint |
fclass | character varying(8) |
type | character varying(20) |
number | character varying(10) |
geom | geometry(MultiPolygon,4326) |
Para crear el índice, ejecutaremos los siguientes comandos:
psql -U $USER -d $DB -c "create index toulouse_geom_gix ON gis.toulouse using gist(geom)"
psql -U $USER -d $DB -c "vacuum analyze gis.toulouse"
Y ahora comprobaremos que el índice está creado:
portal=> \d gis.toulouse;
Table "gis.toulouse"
Column | Type | Modifiers
------------+-----------------------------+------------------------------------------------------------
gid | integer | not null default nextval('gis.toulouse_gid_seq'::regclass)
osm_id | numeric(10,0) |
lastchange | character varying(20) |
code | smallint |
fclass | character varying(8) |
type | character varying(20) |
number | character varying(10) |
geom | geometry(MultiPolygon,4326) |
Indexes:
"toulouse_pkey" PRIMARY KEY, btree (gid)
"toulouse_geom_gix" gist (geom)
Para Shapefile también estamos utilizando un índice pero éste lo crea automáticamente GeoServer, si el usuario Tomcat7
, que ejecuta GeoServer, tiene permisos para acceder al directorio. En caso de tener problemas de rendimiento con un Shapefile es conveniente revisar el log de GeoServer en busca de algo similar a esto:
14 oct 05:11:52 ERROR [data.shapefile] - /var/geoserver/shapefiles/gis.osm_buildings_v06.qix (Permiso denegado)
java.io.FileNotFoundException: /var/geoserver/shapefiles/gis.osm_buildings_v06.qix (Permiso denegado)
En un principio un shapefile dará mejor rendimiento que PostGIS ya que es una forma de acceder a los datos más directa. Para obtener un rendimiento mayor con PostGIS hay que trabajar un poco más y es muy conveniente obtener el feedback inmediato de lo que GeoServer pide a PostgreSQL. Para ello habilitaremos el log estableciendo esta opción en su fichero de configuración /etc/postgresql/9.5/main/postgresql.conf
log_statement = 'all'
A continuación reiniciaremos el servidor:
sudo service postgresql restart
y abriremos una sesión en el servidor y mostraremos constantemente el log:
tail -f /var/log/postgresql/postgresql-9.5-main.log
Para monitorizar también posibles problemas de memoria ejecutaremos el comando htop
en otro terminal:
Pruebas
Las siguientes pruebas realizarán una petición a la extensión máxima de la capa:
http://192.168.0.27:8080/geoserver/geomatico/wms?SERVICE=WMS&VERSION=1.1.1&REQUEST=GetMap&FORMAT=image%2Fpng&TRANSPARENT=true&STYLES&LAYERS=geomatico%3Atoulouse_postgis&SRS=EPSG%3A4326&WIDTH=200&HEIGHT=200&BBOX=1.2668609619140625%2C43.40080261230469%2C1.6788482666015625%2C43.81278991699219
y a una parte pequeña de ella:
http://192.168.0.27:8080/geoserver/geomatico/wms?SERVICE=WMS&VERSION=1.1.1&REQUEST=GetMap&FORMAT=image%2Fpng&TRANSPARENT=true&STYLES&LAYERS=geomatico%3Atoulouse_pg&SRS=EPSG%3A4326&WIDTH=200&HEIGHT=200&BBOX=1.461317092180252%2C43.62045407295227%2C1.4621217548847198%2C43.62125873565674
Extensión completa
Las peticiones son extremadamente lentas, sobre todo en el caso de PostGIS. Para evitar colapsar el servicio se configura JMter para que encadene una petición detrás de otra, dándole tiempo al sistema a terminar.
Podemos observar que el shapefile es 10 veces más eficiente que la base de datos. El índice espacial que hemos creado no se puede aprovechar ya que se quiere leer el juego de datos completo y la transferencia de datos se hace de una forma más lenta.
Se puede jugar con el parámetro fetch_size
del datastore para aumentar el número de registros que se recuperan en una conexión pero esto sólo tiene sentido cuando el servidor de mapas y de base de datos tienen una latencia importante entre ellos. En general la dirección que se debe de tomar es la opuesta: en lugar de aumentar el buffer de lectura con la base de datos se debe reducir la cantidad de elementos que se leen, como veremos en el apartado de estilos.
Shapefile
- Nombre o Servidor o IP: url del servidor, en nuestro caso 192.168.0.12
- Puerto: 8080
- Ruta: /geoserver/unredd/wms?service=WMS&version=1.1.0&request=GetMap&layers=unredd:toulouse_shape&styles=&bbox=1.24776995182037,43.4666137695312,1.69823014736176,43.7463874816895&width=768&height=476&srs=EPSG:4326&format=image/png
PostGIS
- Nombre o Servidor o IP: url del servidor, en nuestro caso 192.168.0.12
- Puerto: 8080
- Ruta: /geoserver/unredd/wms?service=WMS&version=1.1.0&request=GetMap&layers=unredd:toulouse_postgis&styles=&bbox=1.24776995182037,43.4666137695312,1.69823014736176,43.7463874816895&width=768&height=476&srs=EPSG:4326&format=image/png
Concurrencia en shapefile
Sin embargo el tiempo de respuesta, incluso con Shapefile es inaceptable para un servidor que vaya a tener un uso intensivo. La siguiente imagen muestra los resultados haciendo 240 peticiones en 1m40s.
Extensión pequeña
Vemos ahora que el rendimiento es mucho mejor ya que en ambos formatos se filtra con la ayuda de los índices y se encuentran rápidamente los objetos que hay que pintar.
Se lanzan 240 peticiones en 30 segundos y no se produce ningún colapso en el servidor, ya que las peticiones se resuelven instantáneamente. PostGIS sigue funcionando más lento pero ya a un nivel casi inapreciable.
Shapefile
- Nombre o Servidor o IP: url del servidor, en nuestro caso 192.168.0.12
- Puerto: 8080
- Ruta: /geoserver/unredd/wms?SERVICE=WMS&VERSION=1.1.1&REQUEST=GetMap&FORMAT=image%2Fpng&TRANSPARENT=true&STYLES&LAYERS=unredd%3Atoulouse_shape&SRS=EPSG%3A4326&WIDTH=768&HEIGHT=476&BBOX=1.4514613151550293%2C43.60658973455429%2C1.4535212516784668%2C43.60786646604538
PostGIS
- Nombre o Servidor o IP: url del servidor, en nuestro caso 192.168.0.12
- Puerto: 8080
- Ruta: /geoserver/unredd/wms?SERVICE=WMS&VERSION=1.1.1&REQUEST=GetMap&FORMAT=image%2Fpng&TRANSPARENT=true&STYLES&LAYERS=unredd%3Atoulouse_postgis&SRS=EPSG%3A4326&WIDTH=768&HEIGHT=476&BBOX=1.4514613151550293%2C43.60658973455429%2C1.4535212516784668%2C43.60786646604538
Extension aleatoria
Hasta ahora hemos realizado las pruebas con extensión total o con una extensión pequeña determinada. Esto no se corresponde exactamente con la realidad, mas hayá de que queramos comprobar la carga del inicio de nuestro portal, unico momento en el que controlamos la extensión, ya que en el momento que el usuario empiece a navegar por nuestros mapas, las extensiones serán definidas por él.
Para emular esto, JMeter dispone de una utilidad que nos permite cargar datos desde un archivo CSV. Como lo que variará en las peticiones será el BBOX de la misma, lo que haremos será extraer un número de BBOX's desde una aplicación desarrollada para tal uso que nos generará un número determinado de BBOX's. Estos los guardaremos en un archivo CSV y configuraremos JMeter para poder extraer de este archivo los BBOX's.
Configurando JMeter para obtener extensiones aleatorias
A partir del plan de pruebas que tenemos definido, lo que haremos será añadir una Configuración del CSV Dataset a partir de botón derecho sobre la Petición HTTP, Añadir, Elemento de Configuración y Configuración del CSV Dataset.
Los datos que deberemos incluir serán:
- Nombre del Archivo: con la ruta completa al archivo
- Nombres de variables: bbox
- Delimitador: por ejemplo ; ya que en este caso solo habrá una variable en el CSV
Ahora deberemos configurar la Peticion HTTP para que utilice el BBOX desde el CSV. Para ello,
en la pestaña de Parameters, añadiremos un registro pulsando sobre Añadir e introduciendo:
- Nombre: bbox (el nombre que usará en la URL)
- Valor: ${bbox} (el nombre que le hemos dado en la Configuración Anterior)
- Codificar: true
Ahora deberemos elimiar el bbox de la ruta, y si realizamos las peticiones, comprobaremos que esta tomando el valor del BBOX del CSV, y que está realizando peticiones con diferentes extensiones:
o por ejemplo,
Utilizando este método, tendremos para:
PostGIS
- Nombre o Servidor o IP: url del servidor, en nuestro caso 192.168.0.12
- Puerto: 8080
- Ruta: /geoserver/unredd/wms?SERVICE=WMS&VERSION=1.1.1&REQUEST=GetMap&FORMAT=image%2Fpng&TRANSPARENT=true&STYLES&LAYERS=unredd%3Atoulouse_postgis&SRS=EPSG%3A4326&WIDTH=768&HEIGHT=476
Shapefile
- Nombre o Servidor o IP: url del servidor, en nuestro caso 192.168.0.12
- Puerto: 8080
- Ruta: /geoserver/unredd/wms?SERVICE=WMS&VERSION=1.1.1&REQUEST=GetMap&FORMAT=image%2Fpng&TRANSPARENT=true&STYLES&LAYERS=unredd%3Atoulouse_shape&SRS=EPSG%3A4326&WIDTH=768&HEIGHT=476