如何使用数据查找(> 15K req/sec)设计极其快速的python HTTP API?
问题描述:
我需要建立它响应比HTTP GET多在80毫秒下每秒15000个请求一个REST API /服务器。如果有必要,我可以使用负载平衡器运行多个实例。如何使用数据查找(> 15K req/sec)设计极其快速的python HTTP API?
服务器收到一个包含标准列表(大约20)的请求,需要对它们进行分析并与规则集(大约2000条规则,这些规则对于所有20条标准和最终决定具有不同值)进行比较,决定响应(是或否)。
样品请求负载:
{"Country" : "DE",
"ID" : "998423-423432-4234234-234234",
"Criteria1": "8748r78",
"Criteria2": "Some String",
[...]
}
样的规则集(仍有待决定,但让我们用一个简单的设计开始):
+--------+---------+-------------+--------------+
| RuleId | Country | Criteria1 | Criteria2 | etc...
+--------+---------+-------------+--------------+
| 1 | UK | SomeString1 | SomeString3 |
| 2 | UK | SomeString1 | SomeString2 |
| 3 | US | SomeString4 | * (Wildcard) |
+--------+---------+-------------+--------------+
每个标准可在1到大概在400个不同之间含有值,所有字符串(例如ISO代码中的GEO)。有些可能是空的,并被视为通配符。从理论上讲,所有20个标准的条目可能具有相同的值,但这是尚未编写的规则引擎需要解决的主题。
我做了一些研究如何实现这一点:
- 为高吞吐量网络服务器使用中信高科,根据我的 这不包括japronto这是阿尔法 最快的蟒蛇研究;编辑:有没有人有关于类似用例的基于python的web服务器+ webframework的性能的经验?我只读其通常具有非常简单的测试用例基准(只是响应一个固定的字符串的请求,因此高数每秒可能请求中的所有基准)
- 使用对规则查找sqlite3的(在存储器中);不确定具有20个约束的SQL语句是否足够快?也许有另一个来比较每个请求规则集20个标准(每 一个是字符串比较) 方式。编辑:感谢一位评论者,我可能会预先计算规则到哈希中,并使用哈希进行查找,因此不需要用于实时查找的数据库。
- 使用redis或其他数据库来存储预先计算好的规则(即 是另一个主题),并使其准备好加载到http服务器的每个 实例/ worker中,从而加载sqlite3数据库。
- 也许使用pypy3额外的加速,但我没有经验 与pypy
我将主持这在Heroku。
所以,问题是:哪些库,从而架构将允许那种与Python的速度?
答
我会认为
- 所有给定的标准是准确的字符串匹配
- 所有未指定的标准匹配任何(通配符)
- 我们可以抛弃它产生假
- 规则可能包含无所有规则匹配任何东西(通配符)
- 如果至少有一条规则与所有给定条件匹配,则结果为真,否则为False
我们可以建立一个快速查找的一套字典(值)的字典(列)(匹配规则ID):
from collections import namedtuple
WILDCARD = None
Rule = namedtuple("Rule", ["Country", "Criteria1", "Criteria2"])
rules = [
Rule("UK", "Somestring1", "Somestring3"),
Rule("UK", "Somestring1", "Somestring2"),
Rule("US", "Somestring4", WILDCARD)
]
def build_lookup(rules):
columns = Rule._fields
# create lookup table (special handling of wildcard entries)
lookup = {column: {WILDCARD: set()} for column in columns}
# index rules by criteria
for id, rule in enumerate(rules):
for column, value in zip(columns, rule):
if value in lookup[column]:
lookup[column][value].add(id)
else:
lookup[column][value] = {id}
return lookup
rule_lookup = build_lookup(rules)
在给定的样本数据,rule_lookup
现在包含
{
'Country': {WILDCARD: set(), 'UK': {0, 1}, 'US': {2}},
'Criteria1': {WILDCARD: set(), 'Somestring1': {0, 1}, 'Somestring4': {2}},
'Criteria2': {WILDCARD: {2}, 'Somestring2': {1}, 'Somestring3': {0}}
}
那么我们就可以快速的匹配规则的规则像
def all_matching_rules(criteria):
"""
criteria is a dict of {column: value} to match
Return a set of all rule ids which match criteria
"""
if criteria:
result = empty = set()
first = True
for column, value in criteria.items():
ids = rule_lookup[column].get(value, empty) | rule_lookup[column][WILDCARD]
if first:
result = ids
first = False
else:
result &= ids # find intersection of sets
# short-circuit evaluation if result is null set
if not result:
break
return result
else:
# no criteria, return everything
return set(range(len(rules)))
def any_rule_matches(criteria):
"""
criteria is a dict of {column: value} to match
Return True if any rule matches criteria, else False
"""
if criteria:
return bool(all_matching_rules(criteria))
else:
return bool(len(rules))
它运行像
>>> all_matching_rules({"Country": "UK", "Criteria2": "Somestring8"})
set()
>>> all_matching_rules({"Country": "US", "Criteria2": "Somestring8"})
{2}
>>> any_rule_matches({"Country": "UK", "Criteria2": "Somestring8"})
False
>>> any_rule_matches({"Country": "US", "Criteria2": "Somestring8"})
True
Timeit报道称,此次运行在我的机器上930ns - 应该是足够快足够;-)
你能举个例子请求和示例规则?你如何确定应用哪个规则 - 与给定标准最接近的匹配,即笛卡尔距离?规则集是多么“密集”,即请求与最接近的匹配规则之间的预期最大距离是多少?规则集多久更新一次? –
2000规则是* tiny *。我会使用一些内存中的哈希表。 –
...还注意到Sanic在PyPi上被列为“pre-alpha” - 我不确定我是否想在生产中信任它。 –