Debian 11上的开源路径规划引擎

OSRM (开源路径规划引擎) 是一款适用于开放街道地图(OSM)道路网络的超快路径规划引擎。在之前的教程中,我们讲解了如何在 Debian 12上搭建自托管的开放街道地图 瓦片服务器开源路径规划引擎。本教程将向您展示如何在 Debian 11上设置开源路径规划引擎。 安装和运行开源路径规划引擎所需的最低硬件配置:2 个虚拟中央处理器、1 GB 内存和 8 GB 硬盘空间。

1. 从源代码构建OSRM

安装依赖包。

sudo apt-get update
sudo apt-get -y --no-install-recommends install ca-certificates cmake make git gcc g++ libbz2-dev libxml2-dev wget libzip-dev libboost1.74-all-dev lua5.4 liblua5.4-dev -o APT::Install-Suggests=0 -o APT::Install-Recommends=0

NPROC=${BUILD_CONCURRENCY:-$(nproc)}
sudo ldconfig /usr/local/lib
git clone --branch v2021.3.0 --single-branch https://github.com/oneapi-src/oneTBB.git
cd oneTBB
mkdir build
cd build
cmake -DTBB_TEST=OFF -DCMAKE_BUILD_TYPE=Release ..
cmake --build .
sudo cmake --install .

创建osrm 用户。(该用户无需设置密码。)

sudo useradd -d /srv/osrm -s /bin/bash -m osrm

授予您自己的用户账户权限。请将此处的用户名替换为您的实际Linux用户名。

sudo apt install acl
sudo setfacl -R -m u:username:rwx /srv/osrm/

切换到/srv/osrm/目录。

cd /srv/osrm/

从Github仓库下载OSRM源代码。

git clone --branch v5.27.1 https://github.com/Project-OSRM/osrm-backend.git

创建build目录。

mkdir build

切换到build目录并配置编译环境。

cd build
cmake /srv/osrm/osrm-backend/

根据需求,您可能要配置虚拟内存:
    sudo fallocate  -l  4G /debianswapfile ; sudo chmod 600 /debianswapfile ; 
    sudo mkswap /debianswapfile && sudo swapon /debianswapfile ; 
    sudo sed -i '$a\/debianswapfile  swap  swap  defaults 0 0' /etc/fstab
        
编译源代码。(如果看到TBB警告:已弃用信息,可以忽略。)
编译过程需要很长时间,因此您可以使用 screen 命令来保持进程持续运行。

make

[  0%] 正在构建 CXX 对象 CMakeFiles/UTIL.dir/src/util/assert.cpp.o
[  0%] 正在构建 CXX 对象 CMakeFiles/UTIL.dir/src/util/conditional_restrictions.cpp.o
[  0%] 正在构建 CXX 对象 CMakeFiles/UTIL.dir/src/util/coordinate.cpp.o
[  0%] 正在构建 CXX 对象 CMakeFiles/UTIL.dir/src/util/coordinate_calculation.cpp.o
[  0%] 正在构建 CXX 对象 CMakeFiles/UTIL.dir/src/util/exception.cpp.o
[  4%] 正在构建 CXX 对象 CMakeFiles/UTIL.dir/src/util/fingerprint.cpp.o
[  4%] 正在构建 CXX 对象 CMakeFiles/UTIL.dir/src/util/geojson_debug_policies.cpp.o
[  4%] 正在构建 CXX 对象 CMakeFiles/UTIL.dir/src/util/guidance/bearing_class.cpp.o
[  4%] 正在构建 CXX 对象 CMakeFiles/UTIL.dir/src/util/guidance/entry_class.cpp.o
[  4%] 正在构建 CXX 对象 CMakeFiles/UTIL.dir/src/util/guidance/turn_lanes.cpp.o
[  4%] 正在构建 CXX 对象 CMakeFiles/UTIL.dir/src/util/log.cpp.o
[  8%] 正在构建 CXX 对象 CMakeFiles/UTIL.dir/src/util/opening_hours.cpp.o
……
/usr/include/boost/function_output_iterator.hpp:14:1: 注意: ‘#pragma message: 此头文件已弃用。
请改用 <boost/iterator/function_output_iterator.hpp>。’
   14 | BOOST_HEADER_DEPRECATED(“<boost/iterator/function_output_iterator.hpp>”
      | ^~~~~~~~~~~~~~~~~~~~~~~
13% 正在构建 CXX 对象 CMakeFiles/EXTRACTOR.dir/src/extractor/extractor.cpp.o
在包含自 /usr/include/boost/smart_ptr/detail/sp_thread_sleep.hpp:22 的文件中,
                                                          yield_k.hpp:23,
                                                          spinlock_gcc_atomic.hpp:14,
                                                          spinlock.hpp:42
……

21% 正在构建 CXX 对象 CMakeFiles/EXTRACTOR.dir/src/extractor/raster_source.cpp.o
21% 正在构建 CXX 对象 CMakeFiles/EXTRACTOR.dir/src/extractor/restriction_graph.cpp.o
21% 正在构建 CXX 对象 CMakeFiles/EXTRACTOR.dir/src/extractor/restriction_parser.cpp.o
21% 正在构建 CXX 对象 CMakeFiles/EXTRACTOR.dir/src/extractor/scripting_environment_lua.cpp.o
在包含自 /usr/include/boost/smart_ptr/detail/sp_thread_sleep.hpp:22 的文件中,
                 来自 /usr/include/boost/smart_ptr/detail/yield_k.hpp:23,
                 来自 /usr/include/boost/smart_ptr/detail/spinlock_gcc_atomic.hpp:14,
                 来自 /usr/include/boost/smart_ptr/detail/spinlock.hpp:42,
                 来自 /usr/include/boost/smart_ptr/detail/spinlock_pool.hpp:25,
                 来自 /usr/include/boost/smart_ptr/shared_ptr.hpp:29,
                 来自 /usr/include/boost/shared_ptr.hpp:17,
                 来自 /usr/include/boost/format/alt_sstream.hpp:22,
                 来自 /usr/include/boost/format.hpp:38,
                 来自 /srv/osrm/osrm-backend/include/util/exception.hpp:38,
                 来自 /srv/osrm/osrm-backend/include/extractor/extraction_relation.hpp:4,
                来自 /srv/osrm/osrm-backend/include/extractor/scripting_environment_lua.hpp:4,
                来自 /srv/osrm/osrm-backend/src/extractor/scripting_environment_lua.cpp:1:
/usr/include/boost/detail/no_exceptions_support.hpp:17:1: 注意: ‘#pragma message: 此头文件已弃用。
Use <boost/core/no_exceptions_support.hpp> instead.’
   17 | BOOST_HEADER_DEPRECATED(“<boost/core/no_exceptions_support.hpp>”)
      | ^~~~~~~~~~~~~~~~~~~~~~~
……
        
安装二进制文件。

sudo make install

将安装以下二进制文件:

2. 安装 GNU 屏幕工具

下一步,我们需要从开放街道地图中提取道路网络,这可能需要很长时间。您的计算机可能会断开网络连接,因此建议使用 GNU 屏幕工具来保持会话连接。在 Debian 服务器上安装屏幕工具:

sudo apt install screen

然后是启动屏幕:

screen

首次启动时,您会看到一段介绍文字,只需按下 Enter 结束即可。之后,您就可以像往常一样运行命令了。

3. 生成OSRM路径数据

现在我们需要下载开放街道地图数据并使其可用于路径规划。 如果您想要某个国家/州/省/市,请访问 http://download.geofabrik.de。比如,用以下命令下载新泽西的地图数据(148MB)。

wget -c https://download.geofabrik.de/north-america/us/new-jersey-latest.osm.pbf -P /srv/osrm/osrm-backend/

请确保您位于 /srv/osrm/osrm-backend/ 目录中。

cd /srv/osrm/osrm-backend/

从开放街道地图中提取图表。

osrm-extract new-jersey-latest.osm.pbf --threads=2

默认情况下,它将使用 car.lua 配置文件。

现在您可能不需要在服务器上执行其他操作了。由于您正在使用屏幕工具,您可以按 Ctrl+A,松开这两个键,然后按 D 键即可脱离当前的屏幕会话。您将看到类似如下的消息。

[已从 32113.pts-1.focal 分离]

这告诉我之前的屏幕会话 ID 是 32113。您可以注销SSH会话,甚至关闭计算机。不要担心,进程 osrm-extract process 仍在运行。当您需要返回查看进度时,请通过 SSH 连接到服务器并运行以下命令来获取之前的屏幕会话 ID。

screen -ls

然后您可以重新连接到之前的屏幕会话。

screen -r 32113

完成后,会生成文件名相同但是扩展名不同的文件,包括一个 .osrm 扩展名的文件。运行以下命令,将此图递归分割成单元格。

osrm-partition new-jersey-latest.osrm

通过计算所有单元格的路径规划权重来自定义单元格。

sudo apt-get install libtbb2
osrm-customize new-jersey-latest.osrm

现在可以启动路径引擎了。

osrm-routed --algorithm=MLD new-jersey-latest.osrm

如您所见,它监听的是TCP端口 5000。

4. 创建 systemd 服务

我们可以使用手动方式运行OSRM 路径规划引擎: osrm-routed --algorithm=MLD new-jersey-latest.osrm,但更方便的做法是在后台以系统守护进程运行 osrm-routed。

按下 Ctrl+C 停止当前进程,并使用以下命令为 osrm-routed 创建一个系统守护进程。

sudo vi /etc/systemd/system/osrm-routed.service

将以下几行内容添加到文件中。

[Unit]
Description=Open Source Routing Machine
Wants=network-online.target
After=network.target network-online.target

[Service]
ExecStart=/usr/local/bin/osrm-routed --algorithm=MLD /srv/osrm/osrm-backend/new-jersey-latest.osrm
User=osrm
Group=osrm
Restart=always
RestartSec=5s

[Install]
WantedBy=multi-user.target

保存并关闭文件。更改 /srv/osrm/osrm-backend/ 目录的所有权。

sudo chown osrm:osrm /srv/osrm/osrm-backend/ -R

现在我们可以启动并启用 osrm-routed 系统守护进程了。

sudo systemctl start osrm-routed
sudo systemctl enable osrm-routed

查看状态。

systemctl status osrm-routed

5. 设置反向代理

我们可以将Nginx 网络服务器配置为 osrm-routed 服务的反向代理,这样我们就可以使用域名来访问路径规划服务,并启用 HTTPS 加密。

sudo apt install nginx

然后为 OSRM 创建服务器块文件。

sudo vi /etc/nginx/conf.d/osr.conf

将以下内容添加到文件中。将 osr.your-domain.com 替换为您的实际域名,并且不要忘记为其创建 DNS A 记录。
        server {
              listen 80;
              listen [::]:80;
              server_name osr.your-domain.com osr.eastus.cloudapp.azure.com;

              access_log /var/log/nginx/osrm.access;
              error_log /var/log/nginx/osrm.error;

              location / {
                  proxy_pass http://127.0.0.1:5000;
                  proxy_set_header Host $host;
                  proxy_set_header X-Real-IP $remote_addr;

                  proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                  proxy_set_header X-Forwarded-Proto $scheme;
                  proxy_set_header X-Forwarded-Protocol $scheme;
                  proxy_set_header X-Forwarded-Host $http_host;
              }
        }
保存并关闭文件。然后测试 Nginx 配置。

sudo nginx -t

如果测试成功,请重新加载 Nginx 以使更改生效。

sudo systemctl reload nginx

6. 启用 HTTPS

我们可以通过安装 Let’s Encrypt 颁发的免费TLS证书来启用 HTTPS。首先,在 Debian 11上安装 Let’s Encrypt 客户端(certbot)。

sudo apt install certbot

因为我们使用的是 Nginx 网络服务器,所以我们也需要安装 Nginx 插件。

sudo apt install python3-certbot-nginx

然后运行以下命令来获取和安装 TLS 证书。

sudo certbot --nginx --agree-tos --email your-account@example.com -d osr.your-domain.com -d osr.eastus.cloudapp.azure.com

其中: 证书现在应该已经获取并自动安装。您将能通过安全的HTTPS连接访问网页。

如果您希望在运行 Certbot 后同时保留 HTTP 和 HTTPS,您可以删除返回 301 和 404 的行,然后再添加回原始的反向代理行。

7. 将 OSRM 与滑动地图集成

要将OSRM与滑动地图集成,我们可以使用名为 Leaflet Routing Machine 的插件。首先,将 Leaflet routing machine 的 JavaScript 和 CSS 文件添加到您的滑动地图中。请注意,它们应该放在 Leaflet 主 JavaScript 文件之后。

下载 leaflet-routing-machine.css、 leaflet-routing-machine.min.js、 leaflet.routing.icons.png 和 routing-icon.png 到 dist 文件夹:

sudo mkdir /var/www/html/dist
cd /var/www/html/dist
sudo wget https://unpkg.com/leaflet-routing-machine@latest/dist/leaflet-routing-machine.css
sudo wget https://unpkg.com/leaflet-routing-machine@latest/dist/leaflet-routing-machine.js
sudo wget https://unpkg.com/leaflet-routing-machine@latest/dist/leaflet.routing.icons.png
sudo wget https://unpkg.com/leaflet-routing-machine@latest/dist/routing-icon.png

        <html>
          <head>
             ....
             ....
             <link rel="stylesheet" href="dist/leaflet-routing-machine.css" />
             <script src="dist/leaflet-routing-machine.js"></script>
         </head>
         <body>
         ....
         ....
         </body>
        </html>
        

接下来,将以下几行代码添加到 <script>...</script> HTML 正文中的代码片段中。

            start = [39.891215, -74.968797]; // 斯普林代尔农场
            end = [39.89478, -74.93103]; // 美国银行
            L.Routing.control({
              serviceUrl: 'https://osr.your-domain.com/route/v1',
              waypoints: [
                L.latLng(start[0], start[1]),
                L.latLng(end[0], end[1])
              ],
              routeWhileDragging: true
             }).addTo(map);
        
像这样:
        <html>
          <head>
             ....
             ....
             <link rel="stylesheet" href="dist/leaflet-routing-machine.css" />
             <script src="dist/leaflet-routing-machine.js"></script>
         </head>
         <body>
           <div id="map"></div>
             <script>
             ....
             ....

             start = [39.891215, -74.968797]; // 斯普林代尔农场
             end = [39.89478, -74.93103]; // 美国银行
             L.Routing.control({
               serviceUrl: 'https://osr.your-domain.com/route/v1',
               waypoints: [
                 L.latLng(start[0], start[1]),
                 L.latLng(end[0], end[1])
               ],
               routeWhileDragging: true
              }).addTo(map);

            </script>

          </body>
        </html>
        

保存并关闭文件。 然后在浏览器中重新加载地图,你应该会在右上角看到一个控制面板,您可以与路径交互。

您可以拖动地图上的航点, OSRM 将自动重新计算路线。

如何更新路线数据

停止 osrm-routed。

sudo systemctl stop osrm-routed

切换到 osrm 用户。

sudo -u osrm -i

请确保您位于 /srv/osrm/osrm-backend/ 目录中。

cd /srv/osrm/osrm-backend/

删除旧地图文件:

rm new-jersey-latest.osm.pbf

下载新地图。

wget http://download.geofabrik.de/north-america/us/new-jersey-latest.osm.pbf

从开放街道数据中提取图表。

osrm-extract new-jersey-latest.osm.pbf --threads=2

运行以下命令,将此图递归地分割成单元格。

osrm-partition new-jersey-latest.osrm

通过计算所有单元格的路径规划权重来自定义单元格。

osrm-customize new-jersey-latest.osrm

退出 osrm 用户。

exit

重启 osrm-routed。

sudo systemctl restart osrm-routed

交换空间

Swappiness 是 Linux 内核的一个参数,它控制 Linux 将空闲进程交换到硬盘上的交换空间的频率。

交换空间使用率(swappiness)的值介于 0 到 100 之间。值越低,Linux 使用交换空间的频率就越低;值越高,Linux 使用交换空间的频率就越高。Ubuntu 和 Debian 的默认值为 60,这意味着当计算机使用 40% 的物理内存时,Linux 内核才会开始使用交换空间。

您可以使用以下命令检查当前值。

cat /proc/sys/vm/swappiness

建议将交换分区(swappiness)的值设置得较低,以便 Linux 内核尽可能多地使用物理内存。编辑 /etc/sysctl.d/99-sysctl.conf 文件。

sudo vi /etc/sysctl.d/99-sysctl.conf

在此文件的末尾,添加以下行。

vm.swappiness=1

这告诉 Linux 内核,只有当物理内存使用率达到 99% 或以上时才使用交换空间。你也可以将该值设置为 0,这样 Linux 就只会在所有物理内存都用完时才使用交换空间。

vm.swappiness=0

保存并关闭文件。然后运行以下命令以应用更改。

sudo sysctl -p

请注意,htop 工具无法准确报告 Linux 系统上的可用内存量。它不会将共享内存、缓冲区或缓存计算在内。要显示 Linux 服务器上的准确可用内存量,请使用 top 或 free -m 命令。

故障排除

如果您的 nginx 状态显示以下错误:

nginx.service: 无法从 /run/nginx.pid 解析PID: 无效参数

可能的原因和解决方案:

sudo mkdir -p /etc/systemd/system/nginx.service.d
printf "[Service]\nExecStartPost=/bin/sleep 0.1\n" | sudo tee /etc/systemd/system/nginx.service.d/override.conf
sudo systemctl daemon-reload
sudo systemctl restart nginx

下一步

希望这篇教程能帮助你在 Debian 11 上搭建开源路径规划引擎。你可能还需要设置带有网页界面的地理编码服务器来提供搜索功能。

使用此推荐链接注册 Hetzner 即可获得 20 美元的云服务积分。

http://hetzner.cloud/?ref=TOmrsMdmfCLf