欢迎大家前往云加社区,获取更多腾讯海量技术实践干货哦~

译者:人工智能资讯小编

本译文自Jean-Paul Azar 在 https://dzone.com 发表的 Kafka Detailed Design and Ecosystem ,文中版权,图像代码的数据均归作者所有。为了本土化,翻译内容略作修改。

Kafka生态系统 - Kafka核心,Kafka流,Kafka连接,Kafka REST代理和模式注册

Kafka的核心是经纪人,主题,日志,分区和集群。核心也包括像MirrorMaker这样的相关工具。前面提到的是Kafka,因为它存在于Apache中。

Kafka生态系统由Kafka Core,Kafka Streams,Kafka Connect,Kafka REST Proxy和Schema Registry组成。大部分Kafka生态系统的其他部分来自Confluent,不属于Apache。

Kafka Stream是Streams API,用于转换、汇总和处理来自流的记录并生成衍生流。Kafka Connect是API连接器,用于创建可重用的生产者和消费者(例如,来自DynamoDB的更改流)。Kafka REST代理通过REST(HTTP)被用于生产者和消费者。该架构注册管理使用模式的AvroKafka的记录。Kafka MirrorMaker用于将群集数据复制到另一个群集。

Kafka生态系统:连接源,连接接收器和Kafka数据流的示意图

Kafka连接源是记录的来源。Kafka连接水槽是记录的目的地。

Kafka生态系统:Kafka REST代理和合流模式注册表

Kafka流 - Kafka流用于流处理

Kafka Stream API基于核心Kafka原语构建,并拥有自己的生命。Kafka流可以实时处理流。Kafka Streams支持流处理器。流处理器从输入主题获取连续的记录流,对输入执行一些处理,转换和聚合,并产生一个或多个输出流。例如,视频播放器应用程序可能会接收观看的视频事件的输入流,并暂停视频,并输出用户偏好流,然后基于最近的用户活动或许多用户的聚合活动来获取新的视频推荐,以查看哪些新的视频很热。Kafka Stream API解决了无序记录的难题,跨多个流聚合,连接来自多个流的数据,允许有状态的计算等等。

Kafka生态系统:Kafka流和Kafka连接

Kafka生态系统评论

什么是Kafka流?

Kafka流可以实时处理流。它可以聚合多个流,连接来自多个流的数据,允许有状态的计算等等。

什么是Kafka Connect?

Kafka Connect是连接器API,用于创建可重用的生产者和消费者(例如,来自DynamoDB的更改流)。Kafka连接源是记录的来源。Kafka连接水槽是记录的目的地。

什么是模式注册表?

模式注册管理使用Avro作为Kafka记录管理模式。

什么是Kafka镜子制造商?

Kafka MirrorMaker用于将群集数据复制到另一个群集。

什么时候可以使用Kafka REST Proxy?

Kafka REST代理通过REST(HTTP)被用于生产者和消费者。您可以使用它来轻松整合现有的代码库。

如果您不确定Kafka是什么,请参阅什么是Kafka?

Kafka建筑:低级设计

这篇文章从我们关于Kafka架构的系列文章中有所体现,其中包括Kafka主题架构Kafka制作者架构, Kafka用户架构和Kafka生态系统架构。

本文受到Kafka设计部分的启发。你可以把它想成悬崖笔记。

Kafka设计的动机

LinkedIn工程师构建Kafka以支持实时分析。Kafka被设计为提供实时处理流的分析系统。LinkedIn将Kafka开发为实时处理流式数据馈送的统一平台。Kafka背后的目标是构建一个高吞吐量的流媒体数据平台,支持日志聚合,用户活动等大容量事件流。

为了满足Kafka的需求扩展,分布式支持分片和负载均衡。扩展需求激发了Kafka的分区和消费者模型。Kafka使用分区,分布式,提交日志来扩展写入和读取。Kafka的分片被称为分区(Kinesis,类似于Kafka,称为分区“碎片”)。

根据维基百科的说法,“数据库分片是数据库或搜索引擎中数据的水平分区,每个分区被称为分片或数据库分片,每个分片被保存在一个单独的数据库服务器实例上,以传播负载”。

Kafka被设计为处理来自离线系统的周期性大数据加载以及传统的消息传递用例,低延迟。

MOM是面向消息的中间件; 考虑IBM MQSeries,JMS,ActiveMQ和RabbitMQ。像许多MOM一样,Kafka通过复制和领导选举来节点故障的容错。但是,Kafka的设计更像是一个分布式的数据库事务日志而不是传统的消息传递系统。与许多MOM不同的是,Kafka的复制是建立在低级设计之上的,并不是事后的想法。

持久性:拥抱文件系统

Kafka依靠文件系统来存储和缓存记录。

顺序写入硬盘性能的硬盘性能很快非常快)。JBOD只是一堆磁盘驱动器。带有6个7200rpm SATA RAID-5阵列的JBOD配置约为600MB /秒。像Cassandra表一样,Kafka日志是只写结构,意思是数据会被附加到日志的末尾。在使用硬盘驱动器时,顺序读取和写入速度快,可预测,并且可以通过操作系统进行大量优化。使用HDD时,顺序磁盘访问可能比随机存储器访问和SSD更快。

尽管JVM GC的开销可能会很高,但是Kafka在操作系统上依赖于缓存,这是一个巨大的,快速且稳定的缓存。而且,现代操作系统使用所有可用的主存储器来进行磁盘缓存。操作系统文件缓存几乎是免费的,没有操作系统的开销。实现高速缓存一致性是正确的挑战,但是Kafka依靠坚如磐石的操作系统来实现高速缓存一致性。使用OS进行缓存还会减少缓冲区副本的数量。由于Kafka磁盘使用趋向于顺序读取,所以OS预读缓存令人印象深刻。

Cassandra,Netty和Varnish使用类似的技术。所有这一切都在Kafka文件中得到了很好的解释,在油漆现场还有一个更有趣的解释。

大容量硬盘和长时间访问

Kafka主张长时间顺序访问磁盘进行读取和写入。像Cassandra,LevelDB,RocksDB和其他Kafka使用日志结构化存储和压缩的形式,而不是磁盘上可变的BTree。像Cassandra一样,Kafka使用墓碑而不是立即删除记录。

由于磁盘这些天有一些无限的空间,并且速度非常快,Kafka可以提供通常在消息系统中不常见的功能,如长时间保持旧消息。这种灵活性允许Kafka有趣的应用。

Kafka生产者负载平衡

生产者向Kafka经纪人询问有关哪个Kafka经纪人具有哪个主题分区领导的元数据,因此不需要路由层。这个领导数据允许生产者直接向Kafka经纪人分区领导发送记录。

生产者客户端控制它将消息发布到哪个分区,并且可以根据某些应用程序逻辑选择一个分区。生产者可以通过密钥,循环法或使用定制应用程序特定的分区逻辑来分区记录。

Kafka生产者记录批量

Kafka生产商支持记录配料。批量可以通过批量记录的大小来配置。批次可以根据时间自动刷新。

批量处理对于网络IO吞吐量非常有利,并大幅提高吞吐量。

缓冲是可配置的,并允许您在更好的吞吐量之间进行额外延迟之间的权衡。或者在大量使用的系统的情况下,它可能是更好的平均吞吐量,并减少总体延迟。

批量处理允许累积更多的字节发送,相当于Kafka Brokers上较少的I / O操作,并提高了压缩效率。为了获得更高的吞吐量,Kafka Producer配置允许基于时间和大小的缓冲。生产者发送多个记录作为一个批次,而不是逐个发送每个记录的网络请求。

Kafka生产者配料

Kafka压缩

在大型流媒体平台中,瓶颈并不总是CPU或磁盘,而是通常网络带宽。云中存在更多的网络带宽问题,如集装箱化和虚拟化环境,因为多个服务可能共享一个NiC卡。另外,与数据中心或WAN通信时,网络带宽问题可能会有问题。

批处理有利于高效压缩和网络IO吞吐量。

Kafka提供了端到端的批量压缩,而不是一次压缩记录,Kafka有效地压缩了整批记录。相同的消息批处理可以一次压缩并发送到Kafka代理/服务器,并以压缩形式写入日志分区。您甚至可以配置压缩,以便在Kafka经纪商将压缩记录传送给用户之前不进行解压缩。

Kafka支持GZIP,Snappy和LZ4压缩协议。

拉与推/流

Kafka消费者从经纪人那里获取数据。其他系统经纪商将数据或流数据推送给消费者。消息通常是一个基于拉的系统(SQS,大多数MOM使用拉)。在拉动式的情况下,如果消费者落后,它会在晚些时候赶上。

由于Kafka是基于拉式的,所以它实施了大量的数据分批处理。Kafka像许多基于拉的系统实现了长期民意调查(SQS,Kafka都这样做)。长时间轮询在请求一段时间后保持连接打开并等待响应。

一个基于拉的系统必须拉取数据然后处理它,拉和获取数据之间总是有一个暂停。

推送数据给消费者(抄写员,水槽,反应流,RxJava,Akka)。基于推送或流式传输系统在处理缓慢或死亡的消费者方面存在问题。当消费率低于生产速度时,推送系统消费者有可能不知所措。一些基于推送的系统使用基于背压的退避协议,其允许消费者指示其被压倒看到反应性流。当试图跟踪消息确认时,这种不会淹没消费者和消费者恢复的问题是棘手的。

基于推送或流式传输的系统可以立即发送请求,或者累积请求并批量发送(或基于反压的组合)。基于推送的系统总是在推送数据。消费者可以在处理已经发送的数据的同时累积消息,这有利于减少消息处理的延迟。但是,如果消费者在加工后死亡,那么经纪人如何知道消费者在哪里以及何时将数据再次发送给其他消费者。这个问题不是一个容易解决的问题。Kafka通过使用拉式系统来解决这些复杂问题。

传统的MOM消费者消息状态跟踪

对于大多数MOM,经纪人有责任跟踪哪些消息被标记为已消耗。消息跟踪不是一件容易的事情。随着消费者消费信息,经纪人会跟踪状态。

大多数MOM系统的目标是让经纪人在消费后快速删除数据。还记得大部分的MOM是在磁盘小得多,能力不足,价格昂贵的时候写的。

这个消息跟踪比听起来要复杂(确认功能),因为经纪人必须保持大量状态来跟踪每个消息,发送,确认并知道何时删除或重发消息。

Kafka消费者消息状态跟踪

请记住,Kafka主题分为有序分区。每条消息在此有序分区中都有一个偏移量。每个主题分区一次仅由一个消费者组消费。

这种分区布局的意思是,Broker跟踪每个消息跟踪的偏移数据,如MOM,但只需要每个用户组的偏移量,即存储的分区偏移对。这种偏移追踪等同于要追踪的数据少得多。

消费者定期向Kafka经纪人发送位置数据(消费者组,分区偏移对),经纪人将该偏移数据存储到偏移主题中。

与MOM相比,抵消风格的消息确认要便宜得多。另外,消费者更加灵活,可以倒退到更早的偏移(重放)。如果有错误,那么修复错误,倒回消费者并重播主题。这个倒带功能是Kafka的一个杀手功能,因为Kafka可以保存很长一段时间的主题日志数据。

消息传递语义

有三种消息传递语义:最多一次,至少一次,恰好一次。最多一次的消息可能会丢失,但永远不会重新发送。至少一次消息是永远不会丢失的,但可以重新传递。每个消息恰好一次只传送一次。确切地说,曾经是首选的,但更昂贵的,并要求生产者和消费者更多的簿记。

Kafka消费者和消息传递语义

回想一下,所有副本具有相同的偏移量的完全相同的日志分区,并且用户组在日志每个主题分区中保持其位置。

为了实现“最多一次”消费者读取消息,然后将其偏移保存在分区中,并将其发送给代理,最后处理该消息。“最多一次”的问题是消费者可能会在保存其位置之后,但在处理消息之前死亡。然后,接管或重新启动的消费者将在最后的位置离开,并且不会处理有问题的消息。

为了实现“至少一次”,消费者读取消息,处理消息,并最终将代价保存到代理。“至少一次”的问题是消费者在处理消息之后但在保存最后偏移位置之前可能崩溃。然后,如果消费者重新启动或其他消费者接管,消费者可能会收到已处理的消息。“至少一次”是最常见的消息传递设置,您的责任是使消息具有幂等性,这意味着两次获得相同的消息不会导致问题(两个借方)。

为了在消费者方面实现“恰好一次”,消费者需要在消费者位置的存储与消费者的消息处理输出的存储之间的两阶段提交。或者,消费者可以将消息处理输出存储在与最后偏移相同的位置。

Kafka提供了前两个,从消费者的角度来看,实现第三个。

Kafka制片人的耐用性和确认

Kafka为耐用性提供了可操作的可预测性语义。发布消息时,消息被“提交”到日志,这意味着所有ISR都接受消息。只要至少有一个副本存在,这个提交策略对于耐久性就能很好地工作。

生产者连接可能在发送过程中下降,生产者可能不确定它发送的消息是否经过,然后生产者重新发送消息。这个重发逻辑是为什么使用消息密钥和使用幂等消息(重复确定)是重要的。Kafka直到最近(2017年6月)才保证消息不会从生产者重试中复制。

生产者可以重新发送一个消息,直到收到确认,即收到确认。生产者重新发送消息而不知道其发送的其他消息是否与否,从而否定“恰好一次”和“最多一次”的消息传递语义。

生产者耐用性

制片人可以指定耐久度级别。制作人可以等待提交的消息。等待提交可确保所有副本都具有该消息的副本。

制片人可以发送没有确认(0)。生产者可以从分区领导(1)得到一个确认。生产者可以发送并等待来自所有副本(-1)的确认,这是默认的。

改进制片人(2017年6月发行)

Kafka现在支持从生产者“精确地一次”交付,性能改进和分区间的原子写入。他们通过生产者发送一个序列ID来实现这一点,代理跟踪生产者是否已经发送了这个序列,如果生产者试图再次发送它,它会得到重复消息的确认,但是没有任何东西被保存到日志中。这种改进不需要API改变。

Kafka制片人原子日志(2017年6月发行)

Kafka的另一个改进是Kafka生产者在原子笔划上进行分割。原子写入意味着Kafka用户只能看到提交日志(可配置)。Kafka有一个协调员,写一个标记到主题日志,以表示已经成功处理了什么。事务协调器和事务日志维护原子写入的状态。

原子写入确实需要一个新的生产者API来处理事务。

这是一个使用新的生产者API的例子。

新的生产者API的交易

producer.initTransaction();
try {
producer.beginTransaction();
producer.send(debitAccountMessage);
producer.send(creditOtherAccountMessage);
producer.sentOffsetsToTxn(...);
producer.commitTransaction();
} catch (ProducerFencedTransactionException pfte) {
...
producer.close();
} catch (KafkaException ke) {
...
producer.abortTransaction();
}

Kafka复制

Kafka通过可配置数量的Kafka经纪人复制每个主题的分区。Kafka的复制模式是默认的,而不是像大多数MOM那样的插入功能,因为Kafka从一开始就打算使用分区和多节点。每个主题分区都有一个领导者和零个或多个关注者。

领导者和追随者被称为复制品。复制因素是领导者节点加上所有的追随者。分区领导在Kafka经纪人之间平均分享。消费者只能从领导读取。制片人只写信给领导。

追随者的主题日志分区与领导者的日志同步,ISR是领导者的精确副本减去正在进行中的待复制记录。追随者像一个普通的Kafka消费者一样,从他们的领导人那里批量提取记录。

Kafka经纪人故障转移

Kafka记录哪些Kafka经纪人还活着。为了活着,Kafka经纪人必须使用ZooKeeper的心跳机制来维护一个ZooKeeper会话,并且必须让所有的追随者与领导者同步,而不会落后太多。

这个ZooKeeper会话和同步是被称为同步的代理生存所需要的。同步副本被称为ISR。每个领导者都跟踪一组“同步副本”。

如果ISR /追随者死亡,则落后,领导者将从ISR中移除追随者。落后于复制品在replica.lag.time.max.ms时段之后不同步的时候 。

当所有ISR将消息应用到其日志时,消息被认为是“已提交”的。消费者只看到提交的消息。Kafka保证:只要至少有一个ISR,承诺的信息就不会丢失。

复制的日志分区

Kafka分区是一个复制的日志。复制日志是分布式数据系统原语。复制日志对于使用状态机来实现其他分布式系统很有用。一个复制的日志模型对有序的一系列值“达成一致”。

当一个领导人活着的时候,所有的追随者只需要复制他们领导的价值观和秩序。如果领导者死了,Kafka从同步的追随者中选择一个新的领导者。如果一个生产者被告知一个消息被提交,然后领导失败,那么新当选的领导者必须有这个提交的消息。

你有更多的ISR; 在领导失败的时候选举越多。

Kafka和法定人数

法定人数是所需的确认数量,以及必须与选举领导人进行比较的日志数量,以确保可用性重叠。大多数系统使用多数票,Kafka不使用简单的多数投票来提高可用性。

在Kafka,领导人的选择是基于完整的日志。如果我们有一个复制因子3,那么至少两个ISR必须在领导者声明发送的消息提交之前同步。如果一个新的领导者需要当选,不超过3次失败,新的领导者保证有所有承诺的信息。

在追随者中,必须至少有一个包含所有提交的消息的副本。大多数投票的问题法定人数是没有多少失败,有一个无法操作的群集。

Kafka法定人数多数的情监侦

Kafka为每个领导人维护一套情监侦。只有这一套ISR的成员才有资格领导选举。在所有ISR确认写入之前,生产者写入分区的内容不会被提交。只要ISR设置发生变化,ISR就会持续到ZooKeeper。只有属于ISR成员的副本才有资格当选领导。

ISR法定人数的这种风格允许生产者在没有大多数所有节点的情况下继续工作,但只有ISR多数票。ISR仲裁的这种风格也允许副本重新加入ISR集并且拥有其投票计数,但是在加入之前必须完全重新同步,即使副本在其崩溃期间丢失未刷新的数据也是如此。

所有节点同时死亡。怎么办?

Kafka关于数据丢失的保证只有在至少一个副本同步的情况下才有效。

如果所有正在复制分区领导者的追随者都立即死亡,那么数据丢失Kafka保证是无效的。如果分区的所有副本都关闭,则默认情况下,Kafka选择作为首领活动的第一个副本(不一定在ISR集合中)(config unclean.leader.election.enable = true是缺省值)。这种选择有利于可用性的一致性。

如果一致性比您的用例的可用性更重要,那么您可以设置配置,unclean.leader.election.enable=false那么如果所有副本都停止运行一个分区,Kafka会等待第一个ISR成员(而不是第一个副本)活跃起来以选出新的领导者。

生产者选择耐久性

生产者可以通过设置acks(0),仅前导(1)或所有副本(-1)来选择耐久性。

acks = all是默认值。总而言之,当所有当前的同步复制品(ISR)都收到该消息时,便会发生这种情况。

您可以在一致性和可用性之间进行权衡。如果耐用性超过可用性,那么禁用不干净的领导者选举并指定最小的ISR大小。

最小的ISR规模越大,保证一致性就越好。但是,如果ISR集的大小小于最小阈值,则ISR的最小ISR越高,可用性就越低,因为分区不可用。

配额

Kafka已经为消费者和生产者制定了限制他们被允许消费的带宽的限额。这些配额阻止消费者或生产者占用Kafka经纪人资源。配额是由客户端ID或用户。配额数据存储在ZooKeeper中,所以更改不需要重新启动Kafka代理。

Kafka低级设计和体系结构回顾

你如何防止从一个写作不好的消费者的拒绝服务攻击?

使用配额限制消费者的带宽。

什么是默认的生产者耐用性(acks)水平?

所有。这意味着所有ISR必须将消息写入其日志分区。

如果所有的Kafka节点都一次下来,默认情况下会发生什么?

Kafka选择第一个复制品(不一定在ISR集合中),作为领导者活跃起来,unclean.leader.election.enable=true以支持可用性。

为什么Kafka记录批量重要?

通过线路以及磁盘优化IO吞吐量。它还通过压缩整个批次来提高压缩效率。

Kafka的一些设计目标是什么?

成为高吞吐量,可扩展的流媒体数据平台,用于对日志聚合,用户活动等大容量事件流进行实时分析。

截至2017年6月,Kafka中有哪些新功能?

生产者原子写入,性能改进和生产者不发送重复的消息。

什么是不同的消息传递语义?

有三种消息传递语义:最多一次,至少一次,恰好一次。

原文链接:https://dzone.com/articles/kafka-detailed-design-and-ecosystem
原文作者:Jean-Paul Azar

相关阅读

什么是Kafka开始使用Kafka用R语言进行文本挖掘和主题建模

此文已由作者授权云加社区发布,转载请注明原文出处

Kafka详细的设计和生态系统的更多相关文章

  1. Kafka概述与设计原理

    kafka是一种高吞吐量的分布式发布订阅消息系统,有如下特性: 1. 通过O(1)的磁盘数据结构提供消息的持久化,这种结构对于即使数以TB的消息存储也能够保持长时间的稳定性能. 2 .高吞吐量:即使是 ...

  2. Kafka 高可用设计

    Kafka 高可用设计 2016-02-28 杜亦舒 Kafka在早期版本中,并不提供高可用机制,一旦某个Broker宕机,其上所有Partition都无法继续提供服务,甚至发生数据丢失对于分布式系统 ...

  3. 白瑜庆:知乎基于Kubernetes的kafka平台的设计和实现

    欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~ 本文首发在云+社区,未经许可,不得转载. 自我介绍 我是知乎的技术中台工程师,现在是负责知乎的存储相关组件.我的分享主要基于三个,一个是简单 ...

  4. 测试思想-测试设计 史上最详细测试用例设计实践总结 Part2

    史上最详细测试用例设计实践总结 by:授客 QQ:1033553122 -------------------------接 Part1-------------------------- 方法:这里 ...

  5. Kafka设计解析(十五)Kafka controller重设计

    转载自 huxihx,原文链接 Kafka controller重设计 目录 一.Controller是做什么的 二.Controller当前设计 三.Controller组成 四.Controlle ...

  6. Kafka官方文档翻译——设计

    下面是博主的公众号,后续会发布和讨论一系列分布式消息队列相关的内容,欢迎关注. ------------------------------------------------------------ ...

  7. Kafka的架构设计(目前翻译最好的一稿)

    转自:http://www.oschina.net/translate/kafka-design 参与翻译(4人):fbm, 飞翔的猴子, Khiyuan, nesteaa 感谢这些同志们的辛勤工作, ...

  8. Kafka详细原理

    Kafka Kafka是最初由Linkedin公司开发,是一个分布式.支持分区的(partition).多副本的(replica),基于zookeeper协调的分布式消息系统,它的最大的特性就是可以实 ...

  9. Kafka controller重设计

    本文主要参考社区0.11版本Controller的重设计方案,试图给大家梳理一下Kafka controller这个组件在设计上的一些重要思考.众所周知,Kafka中有个关键组件叫controller ...

随机推荐

  1. Java并发之线程管理(线程基础知识)

    因为书中涵盖的知识点比较全,所以就以书中的目录来学习和记录.当然,学习书中知识的时候自己的思考和实践是最重要的.说到线程,脑子里大概知道是个什么东西,但很多东西都还是懵懵懂懂,这是最可怕的.所以想着细 ...

  2. PHP中MD5函数漏洞

    题目描述 一个网页,不妨设URL为http://haha.com,打开之后是这样的 if (isset($_GET['a']) and isset($_GET['b'])) { if ($_GET[' ...

  3. System.UnauthorizedAccessException 错误

    给目录添加 "Authenticated Users" 这个用户的 读写权限

  4. 崩溃 golang入坑系列

    早上(11.30)收到邮件,Vultr东京机房网络故障.当时搭建SS时,考虑到了机房故障.所以特意分出了日本和香港两条线路.但千算万算,忘记数据库还在东京机房中. 现在网络故障,SS服务器无法读取数据 ...

  5. ptrdiff_t 和 size_t

    size_t和ptrdiff_t常常用来指示数组长度. size_t常用于表示数组的大小,可以一般的将他看为 typedef unsigned int size_t,实质是一个无符号整形.包含在头文件 ...

  6. .meta和模型贴图丢失

    一些策划的工程里经常出现模型贴图丢失,同样的工程,其他人没有问题.就算全部还原,也无法解决,最后只要美术在它的工程里重新关联贴图.一次偶然的机会,我发现把模型和贴图的.meta文件删除,让unity重 ...

  7. vue搭建环境

    大早起的,没想自己起来那么早,既然起来了,就写点东西吧~最近在看Vue的东西,发现网上也是好多的资源,包括博客和视频 , 我是看的慕课网上的vue ,名字忘记了,价格148的,看了,也整理了笔记,看了 ...

  8. Python Requests 库学习笔记

    概览 实例引入 import requests response = requests.get('https://www.baidu.com/') print(type(response)) prin ...

  9. XSS攻击原理及防御措施

    概述 XSS攻击是Web攻击中最常见的攻击方法之一,它是通过对网页注入可执行代码且成功地被浏览器 执行,达到攻击的目的,形成了一次有效XSS攻击,一旦攻击成功,它可以获取用户的联系人列 表,然后向联系 ...

  10. C# 把Div变为滚动条

    <div runat="server" style="overflow:auto;width:350px;height:200px" > <a ...