在 Heroku 应用程序的 AWS RDS 上使用 postgres DB 上的控制器时出现问题
Problems using controller on postgres DB on AWS RDS from Heroku app
我已经设置了一个 postgres 数据库,以便将 postgis 用于我拥有的 Heroku 应用程序,运行 在 Ruby 在 Rails。
我的步骤是:
- 创建 RDS 数据库 运行 第 9.4.9 页
- 在 RDS 参数组上启用 rds.force_ssl。
- 备份我的 Heroku 数据库并将其加载到新的 postgres 数据库中。
- 下载 Amazon RDS CA 证书并将其放在 config/amazon-rds-ca-cert.pem.
下
- 将 gem 'activerecord-postgis-adapter' 添加到我的 gem 文件。
- 将 database.yml 文件更新为以下内容:
:
default: &default
adapter: postgis
encoding: unicode
pool: 5
production:
<<: *default
encoding: utf8
database: <%= ENV['RDS_DB_NAME'] %>
username: <%= ENV['RDS_USERNAME'] %>
password: <%= ENV['RDS_PASSWORD'] %>
host: <%= ENV['RDS_HOSTNAME'] %>
port: <%= ENV['RDS_PORT'] %>
postgis_extension: postgis
schema_search_path: public,postgis
- 将 Heroku 上的 DATABASE_URL 参数更新为 postgres://myuser:mypassword@mydbinstance.xxxxxxxxxxx.us-west-2.rds.amazonaws.com/mydbname?sslmode=verify-full&sslrootcert=config/amazon-rds-ca-cert.pem
- 这个非常有用的问题的其他步骤:
- 推送更新的代码并访问我的应用程序。
当我尝试访问数据库以验证连接时,它工作正常:
nc -zv mydbinstance.xxxxxxxx.us-west-2.rds.amazonaws.com 5432
Connection to mydbinstance.xxxxxxxxx.us-west-2.rds.amazonaws.com 5432 port [tcp/postgresql] succeeded!
当我在应用程序上导航时,我能够看到查询结果。但是,当我尝试使用使用 postgis 的模型时,不知何故我的连接无法正常工作。这是我的控制器的代码,它存储带有公交车站信息的纬度、经度对,并找到接近参数中给定点的那些:
class TransitStopsController < ApplicationController
def create
end
def show
@transit_stop = TransitStop.find(params[:id])
@transit_routes = @transit_stop.transit_routes
end
def get_nearby_stops
radius_in_meters = params[:radius_in_meters].nil? ? 3219 : params[:radius_in_meters]
@nearby_stops = TransitStop.close_to(params[:lat], params[:lng], radius_in_meters)
end
end
我的模特:
class TransitStop < ActiveRecord::Base
has_many :transit_stops_transit_routes, foreign_key: "onestop_id", class_name: "TransitStopsTransitRoute"
has_many :transit_routes, through: :transit_stops_transit_routes, foreign_key: "route_onestop_id", class_name: "TransitRoute"
validates_uniqueness_of :onestop_id
#Get transit stops close to a given lat, lng pair. Default distance = 2 miles
scope :close_to, -> (lat, lng, distance_in_meters = 3219) {
where(%{
ST_DWithin(
ST_GeographyFromText(
'SRID=4326;POINT(' || transit_stops.lng || ' ' || transit_stops.lat || ')'
),
ST_GeographyFromText('SRID=4326;POINT(%f %f)'),
%d
)
} % [lng, lat, distance_in_meters])
}
end
和我的观点 (get_nearby_stops.jbuilder):
json.nearby_stops @nearby_stops do |transit_stop|
json.region_id transit_stop.region_id
json.lat transit_stop.lat
json.lng transit_stop.lng
json.onestop_id transit_stop.onestop_id
json.name transit_stop.name
json.osm_way_id transit_stop.osm_way_id
json.osm_way_id transit_stop.served_by_vehicle_types
json.timezone transit_stop.timezone
json.wheelchair_boarding transit_stop.wheelchair_boarding
json.created_or_updated_in_changeset_id transit_stop.created_or_updated_in_changeset_id
json.transit_routes transit_stop.transit_routes
end
Routes.rb 已将行添加到访问方法:
get 'transit_stops/get_nearby_stops' => 'transit_stops#get_nearby_stops'
当我尝试通过以下方式访问时:https://myherokuapp.herokuapp.com/transit_stops/get_nearby_stops.json?lat=-122.49766&lng=37.71677
我只收到一条消息:
应用程序错误
应用程序出错,无法提供您的页面。如果您是应用程序所有者,请查看您的日志以了解详细信息。
当我查看我的 heroku 日志时,我看到的只是一个超时错误:
app[web.1]: Processing by TransitStopsController#get_nearby_stops as JSON
app[web.1]: Parameters: {"lat"=>"-122.49766", "lng"=>"37.71677"}
heroku[router]: at=error code=H12 desc="Request timeout" method=GET path="/transit_stops/get_nearby_stops.json?lat=-122.49766&lng=37.71677" host=myherokuapp.herokuapp.com request_id=1e081fdf-d0ce-4000-a6b4-4e75c176b8a2 fwd="10.0.0.1" dyno=web.1 connect=0ms service=30001ms status=503 bytes=0
AWS 错误日志未显示任何内容。
令我感到奇怪的是,我能够通过连接到 Heroku 的 rails 控制台来执行相同的查询:
irb(main):001:0> TransitStop.close_to(-122.49766,37.71677,5000)
=> #<ActiveRecord::Relation [#<TransitStop region_id: 1, lat: #<BigDecimal:7fe69f6c95c0,'-0.122504106E3',18(18)>...
...
etc
所以现在我不明白是什么原因导致这个控制器只有在我通过我的视图而不是通过控制台访问它时才会失败?如果我使用 postgis 方法,数据库 url 应该不同吗?
非常感谢任何帮助。
编辑:我已经测试了控制器的显示方法,它工作正常:
app<a class="jive-link-external" href="http://web.1">http://web.1</a>: Started GET "/transit_stops/s-9q8ys6puje-655johnmuirave.json" for 159.16.243.2 at 2016-11-12 19:55:16 +0000
app<a class="jive-link-external" href="http://web.1">http://web.1</a>: Processing by TransitStopsController#show as JSON
app<a class="jive-link-external" href="http://web.1">http://web.1</a>: Parameters: {"id"=>"s-9q8ys6puje-655johnmuirave"}
heroku<a href="https://forums.aws.amazon.com/">router</a>: at=info method=GET path="/transit_stops/s-9q8ys6puje-655johnmuirave.json" host=myapp.herokuapp.com request_id=15814367-5235-484b-bff9-7727a2349dd0 fwd="10.0.0.1" dyno=web.1 connect=0ms service=329ms status=200 bytes=1385
app<a class="jive-link-external" href="http://web.1">http://web.1</a>: Rendered transit_stops/show.json.jbuilder (107.3ms)
app<a class="jive-link-external" href="http://web.1">http://web.1</a>: Completed 200 OK in 217ms (Views: 6.7ms | ActiveRecord: 207.4ms)<br class="jive-newline" />
这对我来说意味着数据库中可能存在一些问题来执行我正在做的查询?查询本身应该很快,因为当我在控制台中测试它时,我几乎总是立即得到响应,但也许需要更改数据库配置的某些内容?
只是为了让其他人看到,我的问题是在查询之后,我的视图还产生了几个额外的查询,因为字段
transit_stop.transit_routes
是与另一个 table 的关系。因此,对于每个结果停止,数据库都会对我得到的每个结果执行许多其他查询。由于我的查询返回了数百个结果,最终视图执行了数百个额外的查询,这对我的数据库造成了大量开销。
为了检测到这一点,我将 log_statement = all 更新到我的数据库参数组,这样我就可以看到所有 activity 都进入了数据库。我更新了我的查询,通过将结果数量减少到只有 n 个最接近的结果(最多 10 个)来提高查询效率,因为获得这么多结果对我来说真的没有任何用处。
我已经设置了一个 postgres 数据库,以便将 postgis 用于我拥有的 Heroku 应用程序,运行 在 Ruby 在 Rails。
我的步骤是:
- 创建 RDS 数据库 运行 第 9.4.9 页
- 在 RDS 参数组上启用 rds.force_ssl。
- 备份我的 Heroku 数据库并将其加载到新的 postgres 数据库中。
- 下载 Amazon RDS CA 证书并将其放在 config/amazon-rds-ca-cert.pem. 下
- 将 gem 'activerecord-postgis-adapter' 添加到我的 gem 文件。
- 将 database.yml 文件更新为以下内容:
:
default: &default
adapter: postgis
encoding: unicode
pool: 5
production:
<<: *default
encoding: utf8
database: <%= ENV['RDS_DB_NAME'] %>
username: <%= ENV['RDS_USERNAME'] %>
password: <%= ENV['RDS_PASSWORD'] %>
host: <%= ENV['RDS_HOSTNAME'] %>
port: <%= ENV['RDS_PORT'] %>
postgis_extension: postgis
schema_search_path: public,postgis
- 将 Heroku 上的 DATABASE_URL 参数更新为 postgres://myuser:mypassword@mydbinstance.xxxxxxxxxxx.us-west-2.rds.amazonaws.com/mydbname?sslmode=verify-full&sslrootcert=config/amazon-rds-ca-cert.pem
- 这个非常有用的问题的其他步骤:
- 推送更新的代码并访问我的应用程序。
当我尝试访问数据库以验证连接时,它工作正常:
nc -zv mydbinstance.xxxxxxxx.us-west-2.rds.amazonaws.com 5432
Connection to mydbinstance.xxxxxxxxx.us-west-2.rds.amazonaws.com 5432 port [tcp/postgresql] succeeded!
当我在应用程序上导航时,我能够看到查询结果。但是,当我尝试使用使用 postgis 的模型时,不知何故我的连接无法正常工作。这是我的控制器的代码,它存储带有公交车站信息的纬度、经度对,并找到接近参数中给定点的那些:
class TransitStopsController < ApplicationController
def create
end
def show
@transit_stop = TransitStop.find(params[:id])
@transit_routes = @transit_stop.transit_routes
end
def get_nearby_stops
radius_in_meters = params[:radius_in_meters].nil? ? 3219 : params[:radius_in_meters]
@nearby_stops = TransitStop.close_to(params[:lat], params[:lng], radius_in_meters)
end
end
我的模特:
class TransitStop < ActiveRecord::Base
has_many :transit_stops_transit_routes, foreign_key: "onestop_id", class_name: "TransitStopsTransitRoute"
has_many :transit_routes, through: :transit_stops_transit_routes, foreign_key: "route_onestop_id", class_name: "TransitRoute"
validates_uniqueness_of :onestop_id
#Get transit stops close to a given lat, lng pair. Default distance = 2 miles
scope :close_to, -> (lat, lng, distance_in_meters = 3219) {
where(%{
ST_DWithin(
ST_GeographyFromText(
'SRID=4326;POINT(' || transit_stops.lng || ' ' || transit_stops.lat || ')'
),
ST_GeographyFromText('SRID=4326;POINT(%f %f)'),
%d
)
} % [lng, lat, distance_in_meters])
}
end
和我的观点 (get_nearby_stops.jbuilder):
json.nearby_stops @nearby_stops do |transit_stop|
json.region_id transit_stop.region_id
json.lat transit_stop.lat
json.lng transit_stop.lng
json.onestop_id transit_stop.onestop_id
json.name transit_stop.name
json.osm_way_id transit_stop.osm_way_id
json.osm_way_id transit_stop.served_by_vehicle_types
json.timezone transit_stop.timezone
json.wheelchair_boarding transit_stop.wheelchair_boarding
json.created_or_updated_in_changeset_id transit_stop.created_or_updated_in_changeset_id
json.transit_routes transit_stop.transit_routes
end
Routes.rb 已将行添加到访问方法:
get 'transit_stops/get_nearby_stops' => 'transit_stops#get_nearby_stops'
当我尝试通过以下方式访问时:https://myherokuapp.herokuapp.com/transit_stops/get_nearby_stops.json?lat=-122.49766&lng=37.71677
我只收到一条消息:
应用程序错误
应用程序出错,无法提供您的页面。如果您是应用程序所有者,请查看您的日志以了解详细信息。
当我查看我的 heroku 日志时,我看到的只是一个超时错误:
app[web.1]: Processing by TransitStopsController#get_nearby_stops as JSON
app[web.1]: Parameters: {"lat"=>"-122.49766", "lng"=>"37.71677"}
heroku[router]: at=error code=H12 desc="Request timeout" method=GET path="/transit_stops/get_nearby_stops.json?lat=-122.49766&lng=37.71677" host=myherokuapp.herokuapp.com request_id=1e081fdf-d0ce-4000-a6b4-4e75c176b8a2 fwd="10.0.0.1" dyno=web.1 connect=0ms service=30001ms status=503 bytes=0
AWS 错误日志未显示任何内容。
令我感到奇怪的是,我能够通过连接到 Heroku 的 rails 控制台来执行相同的查询:
irb(main):001:0> TransitStop.close_to(-122.49766,37.71677,5000)
=> #<ActiveRecord::Relation [#<TransitStop region_id: 1, lat: #<BigDecimal:7fe69f6c95c0,'-0.122504106E3',18(18)>...
...
etc
所以现在我不明白是什么原因导致这个控制器只有在我通过我的视图而不是通过控制台访问它时才会失败?如果我使用 postgis 方法,数据库 url 应该不同吗?
非常感谢任何帮助。
编辑:我已经测试了控制器的显示方法,它工作正常:
app<a class="jive-link-external" href="http://web.1">http://web.1</a>: Started GET "/transit_stops/s-9q8ys6puje-655johnmuirave.json" for 159.16.243.2 at 2016-11-12 19:55:16 +0000
app<a class="jive-link-external" href="http://web.1">http://web.1</a>: Processing by TransitStopsController#show as JSON
app<a class="jive-link-external" href="http://web.1">http://web.1</a>: Parameters: {"id"=>"s-9q8ys6puje-655johnmuirave"}
heroku<a href="https://forums.aws.amazon.com/">router</a>: at=info method=GET path="/transit_stops/s-9q8ys6puje-655johnmuirave.json" host=myapp.herokuapp.com request_id=15814367-5235-484b-bff9-7727a2349dd0 fwd="10.0.0.1" dyno=web.1 connect=0ms service=329ms status=200 bytes=1385
app<a class="jive-link-external" href="http://web.1">http://web.1</a>: Rendered transit_stops/show.json.jbuilder (107.3ms)
app<a class="jive-link-external" href="http://web.1">http://web.1</a>: Completed 200 OK in 217ms (Views: 6.7ms | ActiveRecord: 207.4ms)<br class="jive-newline" />
这对我来说意味着数据库中可能存在一些问题来执行我正在做的查询?查询本身应该很快,因为当我在控制台中测试它时,我几乎总是立即得到响应,但也许需要更改数据库配置的某些内容?
只是为了让其他人看到,我的问题是在查询之后,我的视图还产生了几个额外的查询,因为字段
transit_stop.transit_routes
是与另一个 table 的关系。因此,对于每个结果停止,数据库都会对我得到的每个结果执行许多其他查询。由于我的查询返回了数百个结果,最终视图执行了数百个额外的查询,这对我的数据库造成了大量开销。
为了检测到这一点,我将 log_statement = all 更新到我的数据库参数组,这样我就可以看到所有 activity 都进入了数据库。我更新了我的查询,通过将结果数量减少到只有 n 个最接近的结果(最多 10 个)来提高查询效率,因为获得这么多结果对我来说真的没有任何用处。