众所周知,开发人员从事软件开发工作。但通常仅靠开发人员是不够的。这个问题的本质是弄清楚软件开发过程中谁是谁。
tym32167's questions
在已经存在的服务器应用程序上执行客户端的 OAuth fat 任务。问题是客户端只有在某个系统注册后才能连接到服务器,不仅要指定连接地址,还要指定客户端端口。
那是
- 管理员注册客户端地址和端口(例如,localhost:12346)
- 客户端在 localhost:12346 上运行轻量级 http 服务器
- 然后客户端向服务器发送请求,请求中的参数为redirectUri=localhost:12346
- 服务器执行它需要做的事情,检查注册并将重定向发送到指定的 localhost:12346
- 客户端读取它需要的内容,关闭 Web 服务器并继续工作。
这样一个简单的回调服务器,用于在系统中实现 OAuth。这里的问题是,事实证明,您需要在所有客户端上硬编码某个端口。客户端预装软件未知。尝试在客户端上运行该端口时,无法保证该端口是空闲的。
那么问题来了,有没有专门为这种临时连接设计的端口池呢?
到目前为止,我倾向于在iana中保留一个动态端口- 即 49152 - 65535 之间的某个值,但我仍然不知道如何选择正确的端口。为了降低风险,可以为每个应用程序指定最多 4 个端口,但您需要选择在任何客户端上同时被占用的概率最小的那些端口。
我面临着使用 React-Redux 实现具有复杂表单的 SPA 的任务。由于我从未做过前端开发人员,所以我开始阅读文档,为应用程序制作了一些基本模板,然后开始实际实现表单。
应用的方案如下:顶层组件从服务端加载一个大的json对象到内存中。大 - 这意味着具有大量字段的对象。传统上,所有领域都被划分为多个部分。
每个部分都可以包含简单的输入字段和表格、开关等,包括只读字段。
最好自己生成字段及其样式,因为有企业样式和本地已编写的控件。
此外,字段可以相互依赖,字段验证可以依赖于其他字段的值,依赖字段可以来自不同的部分,等等。一般来说,一切皆有可能。
为了显示和验证字段,可以向服务器请求(例如,对于下拉数据或检查部分/字段的有效性)。
示意图如下所示:
| секция 1| набор полей 1 |
|--------:|--------------:|
| секция 2| набор полей 2 |
| секция 3| набор полей 3 |
| секция N| набор полей N |
| |Кнопки действий|
基本上有2个问题:
一)Какой предпочтительный метод для управления состоянием формы и модели данных?
这样,原则上存在问题,但可以解决。据我了解,我有 2 个选项 - 将状态存储在存储中(存储 - 我使用 Redux),或者将状态的一部分存储在组件中,并在每次尝试完成表单编辑然后更新时收集此状态店铺。
根据我在网上和手册上的了解,每次打喷嚏都更新 STATUS 不值得做 ACTIONS,因为有很多控件可供编辑,而且我还需要将更新后的模型上传到存储库,其中有已经验证并保存在服务器上。
因此,现在,我有一个想法将每个部分划分为一个组件,为每个部分组件提供整个模型以及用于验证和更新模型的回调 + 组件应该有一个方法,允许层次结构中较高的组件了解是否正在验证视图的当前状态。
2)Какой предпочтительный способ генерации всех этих контролов на форме, добавления туда бизнес правил и правил валидации?
这更加困难。我查看了推荐的选项,redux-form,react-form,再一次react-form,
react-redux-form,
不是很流行的选项等等,我无法选择,但也理解了普遍接受的构建方法复杂的级联形式。2-3 个字段的示例中的每一件事似乎都可以接受,但是当我想象我的字段数时,我明白我会淹没在事件处理程序和魔术函数中。Отсюда вопрос - есть ли общепринятый, обкатанный способ реализации подобных нужной мне форм?
我面临着反转 4 个任意字节的 md5 哈希的任务。也就是说,换句话说,我需要从 1 个方法编写服务 - 该方法在输入处接收 16 个字节的散列并在输出处返回 4 个字节。
因为,据我所知,单独反转散列是不可行的,所以我决定另辟蹊径,为所有可能的值生成散列。我已经隔离了一个实体,我们称之为它запись
,它由 16 个字节的哈希(我们称之为ключ
)和 4 个字节的值组成。由于值是4字节~4mld,那么我得到4mld记录,每20字节大小为80GB数据。
作为第一个近似值,我生成了 80 个 gig,分为排序的段(每个段是一个单独的文件),并根据合并排序原则实现文件的合并。因此,最后,我将得到一个 80 gig 的大文件,其中将有 4 条按 key 排序的 mld 记录。我计划为这么大的文件创建第二个文件 - 一个可以轻松放入 RAM 的索引文件。之后,通过键搜索记录看起来就像在大文件上进行二分搜索,需要一点索引文件的帮助。搜索时间通常应该是对数的,限制为最多 32 跳。
该解决方案的优点:
- 易于部署。我刚刚部署了服务,等待初始化,一切正常。
缺点:
- 生成文件需要很长时间。时间以小时为单位。
- 生成的数据占用大量空间 - 80 gig
基于这些缺点,我提出了一些想法:
首先,当然是将数据存储在数据库中。它们立即被索引并在那里压缩。我已经尝试过 MongoDB 和 SQL Server,但是两个插入都很慢,以至于我厌倦了等待,而且它们显然比生成文件要慢。也就是说,我不想为了 1 服务而设置数据库服务,事实证明这对我没有多大帮助。
第二个是试图弄清楚如何最好地压缩数据。老实说,哈希压缩在我看来并不是什么基本的东西,它也无法压缩值,因为在那里使用了完整的值集。有一个想法是将一个大文件拆分为类似 trie 的文件 - 然后每个 trie 级别将为我节省大约 4 GB + 省略值中无关紧要的零 \u200b\u200b(但这会使搜索变得非常复杂)
在我的情况下选择最具体的问题对我来说是相当困难的,但我会尝试:是否有更普遍接受的方法来解决这样的问题?我有一种强烈的感觉,我做错了什么。
UPD所以,让我总结一下目前的结果。
已经尝试了几种方法。
1. 我的原始版本是将所有 16 字节的哈希值连同初始 ID 一起生成到一个文件中,然后在文件中查找哈希值。
生成时间:大约3-4小时。搜索速度:未测试。内存 - 80GB
2. 第二种方法是即使前 4 个字节取自 16 字节散列,也很少有冲突。因此,可以生成一个大 ID 文件(按哈希排序)+一个小索引文件。搜索看起来像这样:我们得到传入的哈希,从中取出前 3 个字节,在索引文件中的这个地址(也可以加载到内存中)是大文件中的初始偏移量。使用这个偏移量,我们读取了 400 个 ID——其中一个就是我们正在寻找的那个。我们统计 400 个哈希,找到需要的 id,返回结果。
生成时间:大约 2 小时(还没有做任何优化)。索引文件 - 70mb,ID 文件 - 16gb。搜索速度:大约每秒 75-100 个请求。
3. 第三种方法是生成散列链。该方法的本质是哈希链只能由初始值和最终值表示。对于我的任务,它看起来像这样:
我们取一个 4 字节的 id,从中生成一个散列H
(我们取前 4 个字节),我们得到类似id->H
. 散列是 4 个字节,这意味着某处有这样的id
,所以我可以从散列中获取散列并构建一个像 id->H1->H2->Hn
. 只有链的开头和结尾可以写入文件。开始是需要恢复链,结束是通过哈希搜索一个值。
搜索本身看起来像这样:在输入处我们有一个 hash h
。我们正在寻找一个有结束的链h
- 如果我们找到它,然后我们恢复链,它包含所需的id
. 如果没有这样的链,那么我们从我们的 hash 中获取一个 hash h1
,并寻找一个带有 end 的链h1
。所以我们重复,直到有一条链。
该方法有几个优点 - 似乎您可以将数据表示为一组长链(仅在内存中保留开头和结尾)。第一个问题在于“长”这个词。我将进一步解释。
所以缺点:
- 显然,如果一条链遇到
id
已经在另一个链中的链,那么这些链将开始复制信息。
它看起来像这样:
id1->H1->H2->H3->H4
id2->H5->H1->H2->H3
如您所见,如果您保持链的长度不变(这将增加文件生成时间),则会出现重复信息。
- 为了消除重复,我在内存中分配了 2 ^ 32 位 (~ 500 mb),并标记了已处理的 ID。因此,1 个 ID 仅在 1 个链中。然后链条长度的问题浮出水面。底线是,为了使链真正长且有用,其中所有生成的哈希值必须等于那些尚未处理的 ID。当您开始计算这些链条时(我数了链条,直到遇到一个已经处理过的链条
id
),它们的平均长度为 200 节。但这个数字正在迅速减少。
举个例子:假设10%
所有的ID都已经处理完毕,正在生成一条新的链。假设散列函数具有均匀分布,那么第一个散列是id
尚未处理的散列的可能性为0,9
. 第二个哈希是 -0,9*0,9=0,81
的可能性,依此类推,以及链中至少有10
应用元素的可能性0.35
。这是处理的时候10%
。处理后,链80%
中至少有2
元素(不包括第一个元素id
)的机会是0,64
. 处理时99%
——人们可能会说,长链的机会不存在,典型的链将由初始链id
及其散列组成。这也是我学到的。
总共生成时间大约一个小时,文件大小为16GB。我什至没有尝试测试搜索速度。
4. 第四种方法是彩虹表(感谢@AlexanderPetrov 的提示)。
彩虹表本质上是哈希链的一种变体。与链的不同之处在于,这里使用散列函数与使用不同的函数(归约函数)交替使用。我举个例子:
id -> H1=H(id) -> H2=R1(H1) -> H3=H(H2) -> H4=R2(H3) -> H5=H(H4)
该示例显示散列函数与不同的归约函数交错。这种方法的优点是,即使某个值在 2 条链中相同,也只有从链的开头开始值相同时才会出现重复,例如
id1 -> H1=H(id1) -> H2=R1(H1) -> H3=H(H2) -> H4=R2(H3) -> H5=H(H4)
id2 -> H6=H(id2) -> H7=R1(H6) -> H3=H(H7) -> H4=R2(H3) -> H5=H(H4)
但是如果这个值在链的不同位置,那么它会给出不同的结果,因为它会被不同的归约函数处理
id1 -> H1=H(id1) -> H2=R1(H1) -> H3=H(H2) -> H4=R2(H3) -> H5=H(H4)
id2 -> H6=H(id2) -> H7=R1(H6) -> H2=H(H7) -> H8=R2(H2) -> H9=H(H8)
一切似乎都很好,您可以生成任意长度的链。所以我想当我开始生成长度为 3000 个元素的链时。我很快数完了30%
所有的值。我数了数可以忍受的时间50%
。但是这里的规则与我在前面的例子中描述的概率论相同。想象一下,我计算95%
了所有的 ID。因此,一个新的元素链3000
将包含150
新元素和2850
那些已经计数的元素。因此,计算链的速度急剧下降,因此在每个新链中,95%
元素都被认为是空的。我等了大约30 个小时,无法忍受,停止了这种疯狂 - 大约98%
所有 Id 占用了大约240
兆字节。但我对准确性并不满意98%
,当然我需要100%
。
由于引入了约简功能,id
哈希搜索与之前版本的搜索略有不同。如果在之前的版本中我只是从一个哈希中取出一个哈希,那么在这里,我们需要根据传入的哈希来构建一个新的链。示例:假设有一条链
id1 -> H1=H(id1) -> H2=R1(H1) -> H3=H(H2) -> H4=R2(H3) -> H5=H(H4)
我们在入口处得到了一个哈希H1
。我们没有以 结尾的链H1
,因此我们考虑:
H(H1) - нет совпадений
R2(H(H1)) - нет совпадений
H(R2(H(H1))) - нет совпадений
R1(H(R2(H(H1)))) - на этом этапе результат выражения будет равен H5 элементу цепочки.
找到链后,我们将其还原并找到所需的id
. 从实践中 - 我通过哈希等待至少 1 个 id 大约 10 分钟,我没有等待。但我怀疑这与算法无关,而我只是一个杂工。我完全承认,如果您需要使用某种错误来反转哈希,那么原则上该选项是有效的。
总的来说,生成时间很长,30小时98%,98%被认为是5-6小时,文件大小为240mb。搜索速度不适用。
作为目前的结果,到目前为止,我已经确定了选项 2) - 16 gig 文件 + 索引。我怀疑这个选项将是最快的。但其他选项也一样,我不会注销。
UPD 2 发布了我的磨难的来源。第二种方法完全实现,整个生成耗时 25 分钟,一次搜索 1 个 key - 大约每秒 180 个请求,搜索来自真实程序的一组传入真实数据 - 每秒约 1000 个请求(检查 75千可用哈希)。
谢谢大家的帮助!