首页
影视
壁纸
留言
关于
今日热榜
推荐
音乐解锁
听歌
阅读器
听歌2
小乞丐
摸鱼
Search
1
Navicat Premium for Mac 中文破解版 (强大的数据库管理工具)
9,630 阅读
2
植物大战僵尸中文版 for Mac (兼容 M1系统) 中文版
5,767 阅读
3
CleanMyMac X 4.15.2 中文破解版 (Mac优化清理工具)
3,296 阅读
4
PDF Expert 中文破解版 (好用的PDF编辑器)
3,044 阅读
5
Parallels Desktop 17 中文版 (PD虚拟机无限试用版本)
2,818 阅读
生活杂记
macOS
编程技术
奇技淫巧
音乐
视频
δ
Search
标签搜索
python
漫画
php
mac
redis
mysql
mac 软件
macOS
音乐
极客爱情
数据库
游戏
吊打面试官
2.0
面试
罗小黑
linux
纯音乐
使用教程
B站
Kain
累计撰写
210
篇文章
累计收到
26
条评论
首页
栏目
生活杂记
macOS
编程技术
奇技淫巧
音乐
视频
δ
页面
影视
壁纸
留言
关于
今日热榜
推荐
音乐解锁
听歌
阅读器
听歌2
小乞丐
摸鱼
搜索到
13
篇与
的结果
2021-03-13
微擎框架v2.7.3去授权一键安装纯净商业版【已测试】
这是一款开源的公众号,微信小程序,支付宝小程序,熊掌号,pc建站管理系统,基于目前最流行的WEB2.0的架构(php+mysql),拥有成熟、稳定的的技术解决方案。源码透明、开放,一切的数据及资源都架设在自己的服务上,保证独立性、安全性及可控性。活跃的第三方开发者及开发团队,依托微擎的整个开放的生态系统之上,更丰富的扩展功能。良好的开发框架、文档,轻松扩展、定制私有功能。优质的在线更新系统、客服人员、技术工程师解决使用或是开发上的各种疑难问题。V2.7.3系统LOGO更新,换成微擎新LOGO。修复公众号平台下本地图文同步为公众号图文后,图片不显示的问题。修复微信公众号视频素材上传栏点击后提示不友好报错的问题。修复授权绑定的小程序扫码提示没有上传权限的问题。增加微信小程序主题样式操作说明。 优化会员组功能,会员主页可显示会员等级优化微擎系统内素材,图片、语音、视频素材增加预览功能。应用商城控制台增加应用安装卸载功能。bug修复。资源下载版本更新时间操作2.7.32021-03-13下载 提取码:d7p4解压密码版本有更新的话,会更新资源地址,密码不变点击获取
2021年03月13日
598 阅读
0 评论
0 点赞
独立版狮子鱼17.4.0 社区团购直播小程序商城+团长功能+接龙分销+拼团秒杀+供应商
2021年01月26日
231 阅读
0 评论
0 点赞
2021-01-26
独立版狮子鱼16.6.0 社区团购直播小程序商城+团长功能+接龙分销+拼团秒杀+供应商
2020-07-02
php基于openssl函数的加密、解密、验证操作技巧
本文实例讲述了PHP实现超简单的SSL加密解密、验证及签名的方法。分享给大家供大家参考,具体如下:1 sign签名代码:<?php function sign($data) { //读取私钥文件 $priKey = file_get_contents('key/rsa_private_key.pem'); //转换为openssl密钥,必须是没有经过pkcs8转换的私钥 $res = openssl_get_privatekey($priKey); //调用openssl内置签名方法,生成签名$sign openssl_sign($data, $sign, $res); //释放资源 openssl_free_key($res); return $sign; }2 verify 验证代码:<?php function verify($data, $sign) { //读取支付宝公钥文件 $pubKey = file_get_contents('key/alipay_public_key.pem'); //转换为openssl格式密钥 $res = openssl_get_publickey($pubKey); //调用openssl内置方法验签,返回bool值 $result = (bool)openssl_verify($data, $sign, $res); //释放资源 openssl_free_key($res); return $result; }3. 解密代码<?php function decrypt($content) { //读取商户私钥 $priKey = file_get_contents('key/rsa_private_key.pem'); //转换为openssl密钥,必须是没有经过pkcs8转换的私钥 $res = openssl_get_privatekey($priKey); //声明明文字符串变量 $result = ''; //循环按照128位解密 for($i = 0; $i < strlen($content)/128; $i++ ) { $data = substr($content, $i * 128, 128); //拆分开长度为128的字符串片段通过私钥进行解密,返回$decrypt解析后的明文 openssl_private_decrypt($data, $decrypt, $res); //明文片段拼接 $result .= $decrypt; } //释放资源 openssl_free_key($res); //返回明文 return $result; }
2020年07月02日
601 阅读
0 评论
0 点赞
2020-07-02
PHP 等比例缩放图片,保持图片的清晰度
压缩图片的工具类代码<?php /** 图片压缩操作类 v1.0 */ class Image{ private $src; private $imageinfo; private $image; public $percent = 0.1; public function __construct($src){ $this->src = $src; } /** 打开图片 */ public function openImage(){ list($width, $height, $type, $attr) = getimagesize($this->src); $this->imageinfo = array( 'width'=>$width, 'height'=>$height, 'type'=>image_type_to_extension($type,false), 'attr'=>$attr ); $fun = "imagecreatefrom".$this->imageinfo['type']; $this->image = $fun($this->src); } /** 操作图片 */ public function thumpImage(){ $new_width = $this->imageinfo['width'] * $this->percent; $new_height = $this->imageinfo['height'] * $this->percent; $image_thump = imagecreatetruecolor($new_width,$new_height); //将原图复制带图片载体上面,并且按照一定比例压缩,极大的保持了清晰度 imagecopyresampled($image_thump,$this->image,0,0,0,0,$new_width,$new_height,$this->imageinfo['width'],$this->imageinfo['height']); imagedestroy($this->image); $this->image = $image_thump; } /** 输出图片 */ public function showImage(){ header('Content-Type: image/'.$this->imageinfo['type']); $funcs = "image".$this->imageinfo['type']; $funcs($this->image); } /** 保存图片到硬盘 */ public function saveImage($name){ $funcs = "image".$this->imageinfo['type']; $funcs($this->image,$name.'.'.$this->imageinfo['type']); } /** 销毁图片 */ public function __destruct(){ imagedestroy($this->image); } } ?> 测试代码<?php require 'image.class.php'; $src = "001.jpg"; $image = new Image($src); $image->percent = 0.2; $image->openImage(); $image->thumpImage(); $image->showImage(); $image->saveImage(md5("aa123")); ?>
2020年07月02日
99 阅读
0 评论
0 点赞
2020-07-02
RabbitMQ 延迟队列-基于PHP实现
安装 RabbitMQ 延迟队列插件RabbitMQ 延迟队列插件未安装直接使用的话,会报错:unknown exchange type 'x-delayed-message' 插件下载地址:https://www.rabbitmq.com/community-plugins.html 。下载 Erlang 可执行文件之后,复制到rabbit服务的插件目录(自己的安装目录,我的是 C:\Program Files\RabbitMQ Server\rabbitmq_server-3.7.14\plugins )中,然后开启插件服务:rabbitmq-plugins enable rabbitmq_delayed_message_exchange 测试步骤创建测试项目的目录 mq从 https://github.com/php-amqplib/php-amqplib 下载AMQP库(当然也可以通过 composer 安装,这里为了简单直接自己处理了),放入 mq 目录编写 index.php,实现自动加载创建 test 目录,里面分别创建 mqc.php 消费者和 mqp.php 生产者两个文件跑脚本,测试消息的生产和消费:php -f index.php delayP p 3 ,生产消息,延时3秒php -f index.php delayC c ,消费消息目录结构├─PhpAmqpLib │ ├─Channel │ ├─Connection │ ├─Exception │ ├─Exchange │ ├─Helper │ │ └─Protocol │ ├─Message │ └─Wire │ └─IO ├─test │ ├─delayP.php │ └─delayC.php └─index.php 源码index.php<?php function my_autoloader($cName) { include(__DIR__."/".$cName.".php"); } spl_autoload_register("my_autoloader"); print_r($argv); if (isset($argv[2])) { $cname = '\test\\'.$argv[1]; if (!class_exists($cname)) { exit("class (".$cname.") not exists".PHP_EOL); } $c = new $cname(); if (!method_exists($c, $argv[2])) { exit("method (".$argv[2].") not exists".PHP_EOL); } if (isset($argv[3])) { call_user_func(array($c, $argv[2]), $argv[3]); } else { call_user_func(array($c, $argv[2])); } } else if (isset($argv[1])) { if (!function_exists($argv[1])) { exit("function (".$argv[1].") not exists".PHP_EOL); } $argv[1](); } else { exit("please input at least one argument".PHP_EOL); }delayP.php<?php namespace test; use PhpAmqpLib\Connection\AMQPStreamConnection; use PhpAmqpLib\Message\AMQPMessage; use PhpAmqpLib\Wire\AMQPTable; class delayP { private $host = 'localhost'; private $port = 5672; private $user = 'guest'; private $password = 'guest'; // 可能丢失 public function p($delayTime = 5) { $connection = new AMQPStreamConnection($this->host, $this->port, $this->user, $this->password, '/', false, 'AMQPLAIN', null, 'en_US', 3.0, 120.0, null, true, 60); $channel = $connection->channel(); $channel->exchange_declare('delay.myExchange', 'x-delayed-message', false, true, false, false, false, new AMQPTable(['x-delayed-type' => 'direct'])); $channel->queue_declare('delay.myQueue', false, true, false, false); $channel->queue_bind('delay.myQueue', 'delay.myExchange', 'my'); // 准备消息 $msg = new AMQPMessage( json_encode([ 'data' => "延迟队列数据".time(), 'sendTime' => time(), 'expectRunTime' => time() + $delayTime ]), [ 'delivery_mode' => AMQPMessage::DELIVERY_MODE_PERSISTENT // 持久化 ] ); $msg->set('application_headers', new AMQPTable([ 'x-delay' => $delayTime * 1000 // 延迟时间,单位毫秒 ])); $channel->basic_publish($msg, 'delay.myExchange', 'my'); echo "basic_publish success"; $channel->close(); $connection->close(); } }delayC.php<?php namespace test; use PhpAmqpLib\Connection\AMQPStreamConnection; use PhpAmqpLib\Message\AMQPMessage; use PhpAmqpLib\Wire\AMQPTable; class delayC { private $host = 'localhost'; private $port = 5672; private $user = 'guest'; private $password = 'guest'; // 自动 ACK public function c() { $connection = new AMQPStreamConnection($this->host, $this->port, $this->user, $this->password, '/', false, 'AMQPLAIN', null, 'en_US', 3.0, 120.0, null, true, 60); $channel = $connection->channel(); $channel->exchange_declare('delay.myExchange', 'x-delayed-message', false, true, false, false, false, new AMQPTable(['x-delayed-type' => 'direct'])); $channel->queue_declare('delay.myQueue', false, true, false, false); //闭包回调函数 $callback = function ($msg) { echo $msg->body.' '.time(); echo PHP_EOL; }; $channel->basic_qos(null, 1, null); $channel->basic_consume('delay.myQueue', '', false, true, false, false, $callback); while (count($channel->callbacks)) { $channel->wait(); } $channel->close(); $connection->close(); } }
2020年07月02日
163 阅读
0 评论
0 点赞
2020-07-02
一致性hash及php实现(通俗易懂)
一致性哈希算法在1997年由麻省理工学院提出的一种分布式哈希(DHT)实现算法,设计目标是为了解决因特网中的热点(Hot spot)问题,初衷和CARP十分类似。一致性哈希修正了CARP使用的简单哈希算法带来的问题,使得分布式哈希(DHT)可以在P2P环境中真正得到应用。在了解一致性哈希算法之前,最好先了解一下缓存中的一个应用场景,了解了这个应用场景之后,再来理解一致性哈希算法,就容易多了,也更能体现出一致性哈希算法的优点,那么,我们先来描述一下这个经典的分布式缓存的应用场景。场景描述假设,我们有三台缓存服务器,用于缓存图片,我们为这三台缓存服务器编号为0号、1号、2号,现在,有3万张图片需要缓存,我们希望这些图片被均匀的缓存到这3台服务器上,以便它们能够分摊缓存的压力。也就是说,我们希望每台服务器能够缓存1万张左右的图片,那么,我们应该怎样做呢?如果我们没有任何规律的将3万张图片平均的缓存在3台服务器上,可以满足我们的要求吗?可以!但是如果这样做,当我们需要访问某个缓存项时,则需要遍历3台缓存服务器,从3万个缓存项中找到我们需要访问的缓存,遍历的过程效率太低,时间太长,当我们找到需要访问的缓存项时,时长可能是不能被接受的,也就失去了缓存的意义,缓存的目的就是提高速度,改善用户体验,减轻后端服务器压力,如果每次访问一个缓存项都需要遍历所有缓存服务器的所有缓存项,想想就觉得很累,那么,我们该怎么办呢?原始的做法是对缓存项的键进行哈希,将hash后的结果对缓存服务器的数量进行取模操作,通过取模后的结果,决定缓存项将会缓存在哪一台服务器上,这样说可能不太容易理解,我们举例说明,仍然以刚才描述的场景为例,假设我们使用图片名称作为访问图片的key,假设图片名称是不重复的,那么,我们可以使用如下公式,计算出图片应该存放在哪台服务器上。hash(图片名称)% N因为图片的名称是不重复的,所以,当我们对同一个图片名称做相同的哈希计算时,得出的结果应该是不变的,如果我们有3台服务器,使用哈希后的结果对3求余,那么余数一定是0、1或者2,没错,正好与我们之前的服务器编号相同,如果求余的结果为0, 我们就把当前图片名称对应的图片缓存在0号服务器上,如果余数为1,就把当前图片名对应的图片缓存在1号服务器上,如果余数为2,同理,那么,当我们访问任意一个图片的时候,只要再次对图片名称进行上述运算,即可得出对应的图片应该存放在哪一台缓存服务器上,我们只要在这一台服务器上查找图片即可,如果图片在对应的服务器上不存在,则证明对应的图片没有被缓存,也不用再去遍历其他缓存服务器了,通过这样的方法,即可将3万张图片随机的分布到3台缓存服务器上了,而且下次访问某张图片时,直接能够判断出该图片应该存在于哪台缓存服务器上,这样就能满足我们的需求了,我们暂时称上述算法为HASH算法或者取模算法,取模算法的过程可以用下图表示。但是,使用上述HASH算法进行缓存时,会出现一些缺陷,试想一下,如果3台缓存服务器已经不能满足我们的缓存需求,那么我们应该怎么做呢?没错,很简单,多增加两台缓存服务器不就行了,假设,我们增加了一台缓存服务器,那么缓存服务器的数量就由3台变成了4台,此时,如果仍然使用上述方法对同一张图片进行缓存,那么这张图片所在的服务器编号必定与原来3台服务器时所在的服务器编号不同,因为除数由3变为了4,被除数不变的情况下,余数肯定不同,这种情况带来的结果就是当服务器数量变动时,所有缓存的位置都要发生改变,换句话说,当服务器数量发生改变时,所有缓存在一定时间内是失效的,当应用无法从缓存中获取数据时,则会向后端服务器请求数据,同理,假设3台缓存中突然有一台缓存服务器出现了故障,无法进行缓存,那么我们则需要将故障机器移除,但是如果移除了一台缓存服务器,那么缓存服务器数量从3台变为2台,如果想要访问一张图片,这张图片的缓存位置必定会发生改变,以前缓存的图片也会失去缓存的作用与意义,由于大量缓存在同一时间失效,造成了缓存的雪崩,此时前端缓存已经无法起到承担部分压力的作用,后端服务器将会承受巨大的压力,整个系统很有可能被压垮,所以,我们应该想办法不让这种情况发生,但是由于上述HASH算法本身的缘故,使用取模法进行缓存时,这种情况是无法避免的,为了解决这些问题,一致性哈希算法诞生了。我们来回顾一下使用上述算法会出现的问题。问题1:当缓存服务器数量发生变化时,会引起缓存的雪崩,可能会引起整体系统压力过大而崩溃(大量缓存同一时间失效)。问题2:当缓存服务器数量发生变化时,几乎所有缓存的位置都会发生改变,怎样才能尽量减少受影响的缓存呢?其实,上面两个问题是一个问题,那么,一致性哈希算法能够解决上述问题吗?我们现在就来了解一下一致性哈希算法。一致性哈希算法的基本概念其实,一致性哈希算法也是使用取模的方法,只是,刚才描述的取模法是对服务器的数量进行取模,而一致性哈希算法是对2^32取模,什么意思呢?我们慢慢聊。首先,我们把二的三十二次方想象成一个圆,就像钟表一样,钟表的圆可以理解成由60个点组成的圆,而此处我们把这个圆想象成由2^32个点组成的圆,示意图如下:圆环的正上方的点代表0,0点右侧的第一个点代表1,以此类推,2、3、4、5、6……直到2^32-1,也就是说0点左侧的第一个点代表2^32-1我们把这个由2的32次方个点组成的圆环称为hash环。那么,一致性哈希算法与上图中的圆环有什么关系呢?我们继续聊,仍然以之前描述的场景为例,假设我们有3台缓存服务器,服务器A、服务器B、服务器C,那么,在生产环境中,这三台服务器肯定有自己的IP地址,我们使用它们各自的IP地址进行哈希计算,使用哈希后的结果对2^32取模,可以使用如下公式示意。hash(服务器A的IP地址) % 2^32通过上述公式算出的结果一定是一个0到2^32-1之间的一个整数,我们就用算出的这个整数,代表服务器A,既然这个整数肯定处于0到2^32-1之间,那么,上图中的hash环上必定有一个点与这个整数对应,而我们刚才已经说明,使用这个整数代表服务器A,那么,服务器A就可以映射到这个环上,用下图示意同理,服务器B与服务器C也可以通过相同的方法映射到上图中的hash环中hash(服务器B的IP地址) % 2^32hash(服务器C的IP地址) % 2^32通过上述方法,可以将服务器B与服务器C映射到上图中的hash环上,示意图如下假设3台服务器映射到hash环上以后如上图所示(当然,这是理想的情况,我们慢慢聊)。好了,到目前为止,我们已经把缓存服务器与hash环联系在了一起,我们通过上述方法,把缓存服务器映射到了hash环上,那么使用同样的方法,我们也可以将需要缓存的对象映射到hash环上。假设,我们需要使用缓存服务器缓存图片,而且我们仍然使用图片的名称作为找到图片的key,那么我们使用如下公式可以将图片映射到上图中的hash环上。hash(图片名称) % 2^32映射后的示意图如下,下图中的橘黄色圆形表示图片好了,现在服务器与图片都被映射到了hash环上,那么上图中的这个图片到底应该被缓存到哪一台服务器上呢?上图中的图片将会被缓存到服务器A上,为什么呢?因为从图片的位置开始,沿顺时针方向遇到的第一个服务器就是A服务器,所以,上图中的图片将会被缓存到服务器A上,如下图所示。没错,一致性哈希算法就是通过这种方法,判断一个对象应该被缓存到哪台服务器上的,将缓存服务器与被缓存对象都映射到hash环上以后,从被缓存对象的位置出发,沿顺时针方向遇到的第一个服务器,就是当前对象将要缓存于的服务器,由于被缓存对象与服务器hash后的值是固定的,所以,在服务器不变的情况下,一张图片必定会被缓存到固定的服务器上,那么,当下次想要访问这张图片时,只要再次使用相同的算法进行计算,即可算出这个图片被缓存在哪个服务器上,直接去对应的服务器查找对应的图片即可。刚才的示例只使用了一张图片进行演示,假设有四张图片需要缓存,示意图如下1号、2号图片将会被缓存到服务器A上,3号图片将会被缓存到服务器B上,4号图片将会被缓存到服务器C上。一致性哈希算法的优点经过上述描述,我想兄弟你应该已经明白了一致性哈希算法的原理了,但是话说回来,一致性哈希算法能够解决之前出现的问题吗,我们说过,如果简单的对服务器数量进行取模,那么当服务器数量发生变化时,会产生缓存的雪崩,从而很有可能导致系统崩溃,那么使用一致性哈希算法,能够避免这个问题吗?我们来模拟一遍,即可得到答案。假设,服务器B出现了故障,我们现在需要将服务器B移除,那么,我们将上图中的服务器B从hash环上移除即可,移除服务器B以后示意图如下。在服务器B未移除时,图片3应该被缓存到服务器B中,可是当服务器B移除以后,按照之前描述的一致性哈希算法的规则,图片3应该被缓存到服务器C中,因为从图片3的位置出发,沿顺时针方向遇到的第一个缓存服务器节点就是服务器C,也就是说,如果服务器B出现故障被移除时,图片3的缓存位置会发生改变但是,图片4仍然会被缓存到服务器C中,图片1与图片2仍然会被缓存到服务器A中,这与服务器B移除之前并没有任何区别,这就是一致性哈希算法的优点,如果使用之前的hash算法,服务器数量发生改变时,所有服务器的所有缓存在同一时间失效了,而使用一致性哈希算法时,服务器的数量如果发生改变,并不是所有缓存都会失效,而是只有部分缓存会失效,前端的缓存仍然能分担整个系统的压力,而不至于所有压力都在同一时间集中到后端服务器上。这就是一致性哈希算法所体现出的优点。hash环的偏斜在介绍一致性哈希的概念时,我们理想化的将3台服务器均匀的映射到了hash环上,如下图所示但是,理想很丰满,现实很骨感,我们想象的与实际情况往往不一样。在实际的映射中,服务器可能会被映射成如下模样。聪明如你一定想到了,如果服务器被映射成上图中的模样,那么被缓存的对象很有可能大部分集中缓存在某一台服务器上,如下图所示。上图中,1号、2号、3号、4号、6号图片均被缓存在了服务器A上,只有5号图片被缓存在了服务器B上,服务器C上甚至没有缓存任何图片,如果出现上图中的情况,A、B、C三台服务器并没有被合理的平均的充分利用,缓存分布的极度不均匀,而且,如果此时服务器A出现故障,那么失效缓存的数量也将达到最大值,在极端情况下,仍然有可能引起系统的崩溃,上图中的情况则被称之为hash环的偏斜,那么,我们应该怎样防止hash环的偏斜呢?一致性hash算法中使用"虚拟节点"解决了这个问题,我们继续聊。虚拟节点话接上文,由于我们只有3台服务器,当我们把服务器映射到hash环上的时候,很有可能出现hash环偏斜的情况,当hash环偏斜以后,缓存往往会极度不均衡的分布在各服务器上,聪明如你一定已经想到了,如果想要均衡的将缓存分布到3台服务器上,最好能让这3台服务器尽量多的、均匀的出现在hash环上,但是,真实的服务器资源只有3台,我们怎样凭空的让它们多起来呢,没错,就是凭空的让服务器节点多起来,既然没有多余的真正的物理服务器节点,我们就只能将现有的物理节点通过虚拟的方法复制出来,这些由实际节点虚拟复制而来的节点被称为"虚拟节点"。加入虚拟节点以后的hash环如下。"虚拟节点"是"实际节点"(实际的物理服务器)在hash环上的复制品,一个实际节点可以对应多个虚拟节点。从上图可以看出,A、B、C三台服务器分别虚拟出了一个虚拟节点,当然,如果你需要,也可以虚拟出更多的虚拟节点。引入虚拟节点的概念后,缓存的分布就均衡多了,上图中,1号、3号图片被缓存在服务器A中,5号、4号图片被缓存在服务器B中,6号、2号图片被缓存在服务器C中,如果你还不放心,可以虚拟出更多的虚拟节点,以便减小hash环偏斜所带来的影响,虚拟节点越多,hash环上的节点就越多,缓存被均匀分布的概率就越大。php实现理论说完了,就要说实现了,来看一下具体的php实现:<?php //一致性hash算法的PHP实现 /** * Flexihash - A simple consistent hashing implementation for PHP. * * The MIT License * * Copyright (c) 2008 Paul Annesley * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. * * @author Paul Annesley * @link http://paul.annesley.cc/ * @copyright Paul Annesley, 2008 * @comment by MyZ (http://blog.csdn.net/mayongzhan) */ /** * A simple consistent hashing implementation with pluggable hash algorithms. * * @author Paul Annesley * @package Flexihash * @licence http://www.opensource.org/licenses/mit-license.php */ class Flexihash { /** * The number of positions to hash each target to. * * @var int * @comment 虚拟节点数,解决节点分布不均的问题 */ private $_replicas = 64; /** * The hash algorithm, encapsulated in a Flexihash_Hasher implementation. * @var object Flexihash_Hasher * @comment 使用的hash方法 : md5,crc32 */ private $_hasher; /** * Internal counter for current number of targets. * @var int * @comment 节点记数器 */ private $_targetCount = 0; /** * Internal map of positions (hash outputs) to targets * @var array { position => target, ... } * @comment 位置对应节点,用于lookup中根据位置确定要访问的节点 */ private $_positionToTarget = array(); /** * Internal map of targets to lists of positions that target is hashed to. * @var array { target => [ position, position, ... ], ... } * @comment 节点对应位置,用于删除节点 */ private $_targetToPositions = array(); /** * Whether the internal map of positions to targets is already sorted. * @var boolean * @comment 是否已排序 */ private $_positionToTargetSorted = false; /** * Constructor * @param object $hasher Flexihash_Hasher * @param int $replicas Amount of positions to hash each target to. * @comment 构造函数,确定要使用的hash方法和需拟节点数,虚拟节点数越多,分布越均匀,但程序的分布式运算越慢 */ public function __construct(Flexihash_Hasher $hasher = null, $replicas = null) { $this->_hasher = $hasher ? $hasher : new Flexihash_Crc32Hasher(); if (!empty($replicas)) $this->_replicas = $replicas; } /** * Add a target. * @param string $target * @chainable * @comment 添加节点,根据虚拟节点数,将节点分布到多个虚拟位置上 */ public function addTarget($target) { if (isset($this->_targetToPositions[$target])) { throw new Flexihash_Exception("Target '$target' already exists."); } $this->_targetToPositions[$target] = array(); // hash the target into multiple positions for ($i = 0; $i < $this->_replicas; $i++) { $position = $this->_hasher->hash($target . $i); $this->_positionToTarget[$position] = $target; // lookup $this->_targetToPositions[$target] []= $position; // target removal } $this->_positionToTargetSorted = false; $this->_targetCount++; return $this; } /** * Add a list of targets. * @param array $targets * @chainable */ public function addTargets($targets) { foreach ($targets as $target) { $this->addTarget($target); } return $this; } /** * Remove a target. * @param string $target * @chainable */ public function removeTarget($target) { if (!isset($this->_targetToPositions[$target])) { throw new Flexihash_Exception("Target '$target' does not exist."); } foreach ($this->_targetToPositions[$target] as $position) { unset($this->_positionToTarget[$position]); } unset($this->_targetToPositions[$target]); $this->_targetCount--; return $this; } /** * A list of all potential targets * @return array */ public function getAllTargets() { return array_keys($this->_targetToPositions); } /** * A list of all potential targets * @return array */ public function getAll() { return array( "targers"=>$this->_positionToTarget, "positions"=>$this->_targetToPositions); } /** * Looks up the target for the given resource. * @param string $resource * @return string */ public function lookup($resource) { $targets = $this->lookupList($resource, 1); if (empty($targets)) throw new Flexihash_Exception('No targets exist'); return $targets[0]; //0表示返回离资源位置最近的机器节点 } /** * Get a list of targets for the resource, in order of precedence. * Up to $requestedCount targets are returned, less if there are fewer in total. * * @param string $resource * @param int $requestedCount The length of the list to return * @return array List of targets * @comment 查找当前的资源对应的节点, * 节点为空则返回空,节点只有一个则返回该节点, * 对当前资源进行hash,对所有的位置进行排序,在有序的位置列上寻找当前资源的位置 * 当全部没有找到的时候,将资源的位置确定为有序位置的第一个(形成一个环) * 返回所找到的节点 */ public function lookupList($resource, $requestedCount) { if (!$requestedCount) throw new Flexihash_Exception('Invalid count requested'); // handle no targets if (empty($this->_positionToTarget)) return array(); // optimize single target if ($this->_targetCount == 1) return array_unique(array_values($this->_positionToTarget)); // hash resource to a position $resourcePosition = $this->_hasher->hash($resource); $results = array(); $collect = false; $this->_sortPositionTargets(); // search values above the resourcePosition foreach ($this->_positionToTarget as $key => $value) { // start collecting targets after passing resource position if (!$collect && $key > $resourcePosition) { $collect = true; } // only collect the first instance of any target if ($collect && !in_array($value, $results)) { $results []= $value; //var_dump($results); } // return when enough results, or list exhausted //var_dump(count($results)); //var_dump($requestedCount); if (count($results) == $requestedCount || count($results) == $this->_targetCount) { return $results; } } // loop to start - search values below the resourcePosition foreach ($this->_positionToTarget as $key => $value) { if (!in_array($value, $results)) { $results []= $value; } // return when enough results, or list exhausted if (count($results) == $requestedCount || count($results) == $this->_targetCount) { return $results; } } // return results after iterating through both "parts" return $results; } public function __toString() { return sprintf( '%s{targets:[%s]}', get_class($this), implode(',', $this->getAllTargets()) ); } // ---------------------------------------- // private methods /** * Sorts the internal mapping (positions to targets) by position */ private function _sortPositionTargets() { // sort by key (position) if not already if (!$this->_positionToTargetSorted) { ksort($this->_positionToTarget, SORT_REGULAR); $this->_positionToTargetSorted = true; } } } /** * Hashes given values into a sortable fixed size address space. * * @author Paul Annesley * @package Flexihash * @licence http://www.opensource.org/licenses/mit-license.php */ interface Flexihash_Hasher { /** * Hashes the given string into a 32bit address space. * * Note that the output may be more than 32bits of raw data, for example * hexidecimal characters representing a 32bit value. * * The data must have 0xFFFFFFFF possible values, and be sortable by * PHP sort functions using SORT_REGULAR. * * @param string * @return mixed A sortable format with 0xFFFFFFFF possible values */ public function hash($string); } /** * Uses CRC32 to hash a value into a signed 32bit int address space. * Under 32bit PHP this (safely) overflows into negatives ints. * * @author Paul Annesley * @package Flexihash * @licence http://www.opensource.org/licenses/mit-license.php */ class Flexihash_Crc32Hasher implements Flexihash_Hasher { /* (non-phpdoc) * @see Flexihash_Hasher::hash() */ public function hash($string) { return crc32($string); } } /** * Uses CRC32 to hash a value into a 32bit binary string data address space. * * @author Paul Annesley * @package Flexihash * @licence http://www.opensource.org/licenses/mit-license.php */ class Flexihash_Md5Hasher implements Flexihash_Hasher { /* (non-phpdoc) * @see Flexihash_Hasher::hash() */ public function hash($string) { return substr(md5($string), 0, 8); // 8 hexits = 32bit // 4 bytes of binary md5 data could also be used, but // performance seems to be the same. } } /** * An exception thrown by Flexihash. * * @author Paul Annesley * @package Flexihash * @licence http://www.opensource.org/licenses/mit-license.php */ class Flexihash_Exception extends Exception { } // 测试代码 $hash = new Flexihash(); $targets=array( "192.168.1.1:11011", "192.168.1.1:11012", "192.168.1.1:11013", "192.168.1.1:11014", "192.168.1.1:11015", ); $hash->addTargets($targets); for ($i=0; $i < 25; $i++) { $resource = sprintf("format %d",$i); var_dump($resource." --> ".$hash->lookup($resource)); } 输出string(30) "format 0 --> 192.168.1.1:11015" string(30) "format 1 --> 192.168.1.1:11015" string(30) "format 2 --> 192.168.1.1:11015" string(30) "format 3 --> 192.168.1.1:11015" string(30) "format 4 --> 192.168.1.1:11011" string(30) "format 5 --> 192.168.1.1:11011" string(30) "format 6 --> 192.168.1.1:11011" string(30) "format 7 --> 192.168.1.1:11011" string(30) "format 8 --> 192.168.1.1:11012" string(30) "format 9 --> 192.168.1.1:11013" string(31) "format 10 --> 192.168.1.1:11013" string(31) "format 11 --> 192.168.1.1:11011" string(31) "format 12 --> 192.168.1.1:11012" string(31) "format 13 --> 192.168.1.1:11011" string(31) "format 14 --> 192.168.1.1:11014" string(31) "format 15 --> 192.168.1.1:11014" string(31) "format 16 --> 192.168.1.1:11014" string(31) "format 17 --> 192.168.1.1:11014" string(31) "format 18 --> 192.168.1.1:11012" string(31) "format 19 --> 192.168.1.1:11012" string(31) "format 20 --> 192.168.1.1:11013" string(31) "format 21 --> 192.168.1.1:11012" string(31) "format 22 --> 192.168.1.1:11012" string(31) "format 23 --> 192.168.1.1:11014" string(31) "format 24 --> 192.168.1.1:11012" [Finished in 0.1s]redis分布式代码设计<?php require_once("Flexihash.php"); $config=array( "127.0.0.1:6371", "127.0.0.1:6372", "127.0.0.1:6373", "127.0.0.1:6374", ); class RedisCollect { //redis实例 private $_redis = null; //hash实例 private $_hash = null; //初始化 public function __construct() { global $config; $this->_redis = new Redis(); $this->_hash = new Flexihash(); $this->_hash->addTargets($config); } public function set($key="", $value="") { $m = $this->switchConncetion($key); return $m->set($key, $value); } public function get($key) { $m = $this->switchConncetion($key); return $m->get($key); } private function switchConncetion($key) { $hostinfo = $this->_hash->lookup($key); $m = $this->connect($hostinfo); return $m; } private function connect($hostinfo) { list($host, $port) = explode(":", $hostinfo); //printf("host = %s, port = %s\n",$host,$port); if(empty($host) || empty($port)) { return false; } try { $this->_redis->connect($host, $port); return $this->_redis; } catch(Exception $e) { die($e->getMessage()); } } }
2020年07月02日
113 阅读
0 评论
0 点赞
2020-07-02
PHP实现微信扫码自动登陆与注册,参考实例
微信开发已经是现在phper必须要掌握的一项基本的技术了,其实做过微信开发的都知道微信接口非常的强大做起来也非常的简单,这里我们一起来看一个微信自动登陆注册的例子。php 微信扫码 pc端自动登陆注册 用的接口scope 是snsapi_userinfo,微信登陆一个是网页授权登陆,另一个是微信联合登陆网页授权登陆:http://mp.weixin.qq.com/wiki/17/c0f37d5704f0b64713d5d2c37b468d75.html 微信联合登陆:https://open.weixin.qq.com/cgi-bin/frame?t=home/web_tmpl&lang=zh_CN 微信链接带个标识生成二维码比如链接为https://open.weixin.qq.com/connect/oauth2/authorize?appid='.$appid.'&redirect_uri='.$url.'&response_type=code&scope=snsapi_userinfo&state=1#wechat_redirect' 我们可以在state上做文章,因为state你传入什么微信那边返回什么,可以作为服务器与微信段的一个标识:<?php public function creatqrAction(){ if($_GET['app']){ $wtoken=$_COOKIE['wtoken']; $postdata=$_SESSION['w_state']; if($wtoken){ $postdata=$wtoken; } include CONFIG_PATH . 'phpqrcode/'.'phpqrcode.php' $sh=$this->shar1(); $value="https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx138697ef383a9167&redirect_uri=http://www.xxx.net/login/wcallback&response_type=code&scope=snsapi_userinfo&state=".$postdata."&connect_redirect=1#wechat_redirect"; $errorCorrectionLevel = "L"; $matrixPointSize = "5"; QRcode::png($value, false, $errorCorrectionLevel, $matrixPointSize); } }此时生成了二维码 state是标识,phpqrcode可以在文章末尾下载,这样我们设置了回调地址http://www.xxx.net/login/wcallback就可以在wcallback方法里面处理数据 插入用户 生成session,跳转登陆,pc端可以设置几秒钟ajax请求服务器,一旦获取到了state,即实现调整,微信浏览器里处理完后可以关闭窗口,微信js可实现:document.addEventListener('WeixinJSBridgeReady', function onBridgeReady() { WeixinJSBridge.call('closeWindow');}, false);也可以授权登陆成功后跳转到微信服务号关注页面:<?php header("Location: weixin://profile/gh_a5e1959f9a4e"); // wcallback方法做处理登陆 $code = $_GET['code']; $state = $_GET['state']; $setting = include CONFIG_PATH . 'setting.php' $appid=$setting['weixin']['appid']; $appsecret=$setting['weixin']['appsecret']; if (empty($code)){ $this->showMessage('授权失败'); } try{ $token_url = 'https://api.weixin.qq.com/sns/oauth2/access_token?appid='.$appid.'&secret='.$appsecret.'&code='.$code.'&grant_type=authorization_code' $token = json_decode($this->https_request($token_url)); }catch(Exception $e) { print_r($e); } if (isset($token->errcode)) { echo '错误:'.$token->errcode; echo '错误信息:'.$token->errmsg; exit; } $access_token_url = 'https://api.weixin.qq.com/sns/oauth2/refresh_token?appid='.$appid.'&grant_type=refresh_token&refresh_token='.$token->refresh_token; //转成对象 $access_token = json_decode($this->https_request($access_token_url)); if (isset($access_token->errcode)) { echo '错误:'.$access_token->errcode; echo '错误信息:'.$access_token->errmsg; exit; } $user_info_url = 'https://api.weixin.qq.com/sns/userinfo?access_token='.$access_token->access_token.'&openid='.$access_token->openid.'&lang=zh_CN' //转成对象 $user_info = json_decode($this->https_request($user_info_url)); if (isset($user_info->errcode)) { echo '错误:'.$user_info->errcode; echo '错误信息:'.$user_info->errmsg; exit; } //打印用户信息 // echo '' // print_r($user_info); // echo ''phpqrcode类库下载在此不提供各位可以百度搜索下载magento微信扫码网站自动登录的例子https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&lang=zh_CN查看授权后接口调用(UnionID),不难发现填写回调地址,用户确认登陆pc端即可跳转获取UnionID方法<?php public function wcallbackAction(){ $code = $_GET['code']; $state = $_GET['state']; $setting = include CONFIG_PATH . 'setting.php'; $appid=$setting['weixin']['appid']; $appsecret=$setting['weixin']['appsecret']; if (empty($code)){ $this->showMessage('授权失败'); } try{ $token_url = 'https://api.weixin.qq.com/sns/oauth2/access_token?appid='.$appid.'&secret='.$appsecret.'&code='.$code.'&grant_type=authorization_code'; $token = json_decode($this->https_request($token_url)); }catch(Exception $e){ print_r($e); } if (isset($token->errcode)) { echo '<h1>错误:</h1>'.$token->errcode; echo '<br/><h2>错误信息:</h2>'.$token->errmsg; exit; } $access_token_url = 'https://api.weixin.qq.com/sns/oauth2/refresh_token?appid='.$appid.'&grant_type=refresh_token&refresh_token='.$token->refresh_token; //转成对象 $access_token = json_decode($this->https_request($access_token_url)); if (isset($access_token->errcode)) { echo '<h1>错误:</h1>'.$access_token->errcode; echo '<br/><h2>错误信息:</h2>'.$access_token->errmsg; exit; } $user_info_url = 'https://api.weixin.qq.com/sns/userinfo?access_token='.$access_token->access_token.'&openid='.$access_token->openid.'&lang=zh_CN'; //转成对象 $user_info = json_decode($this->https_request($user_info_url)); if (isset($user_info->errcode)) { echo '<h1>错误:</h1>'.$user_info->errcode; echo '<br/><h2>错误信息:</h2>'.$user_info->errmsg; exit; } //打印用户信息 // echo '<pre>'; // print_r($user_info); // echo '</pre>'; //获取unionid $uid=$user_info->unionid; } //用户操作处理 分为再次登录和第一次登陆 $sql="select h_user_id from dtb_user_binded as t1 left join dtb_user_weixin as t2 on t1.u_id=t2.id where t1.u_type='". User::$arrUtype['weixin_num_t']."' and t2.openid='$user_info->unionid'"; $h_user_id = Core_Db::getOne($sql); if(!empty($h_user_id)){ //该weixin号再次登录 }else{ //该weixin号第一次登录 }
2020年07月02日
215 阅读
0 评论
0 点赞
2020-07-02
Swoole 中涉及的一些基本概念
IO(Input/Output,输入输出)在计算机中,输入 / 输出(即 IO)是指信息处理系统(比如计算机)和外部世界(可以是人或其他信息处理系统)的通信。输入是指系统接收的信号或数据,输出是指从系统发出的数据或信号。由于程序和运行时数据是在内存中驻留,由 CPU 这个超快的计算核心来执行,涉及到数据交换的地方,通常是磁盘、网络等,就会有 IO 产生。同步 - 异步同步和异步是一种消息通信机制 (synchronous communication/asynchronous communication),关注点在于 被调用者返回 和 结果返回 之间的关系, 描述对象是被调用对象的行为。同步(Synchronous):在发出一个同步调用时,在没有得到结果之前,该调用就不返回,等待返回结果才继续执行后续的操作。异步( Asynchronous):发出调用,直接返回,不关心是否返回结果。异步可以通过状态、回调、 通知调用者结果,可以先去执行其他操作,然后等待通知再回来执行刚才没执行完的操作。阻塞 - 非阻塞阻塞和非阻塞是一种业务流程处理方式。关注点在于调用发生时 调用者状态 和 被调用者返回结果 之间的关系。 描述的是等待结果时候调用者的状态此时结果可能是同步返回的,也能是异步返回。阻塞( Blocking ):在结果返回之前,当前线程被挂起,后续代码只有在结果返回后才能执行。非阻塞( Nonblocking):在不能立刻获取结果前,该调用不会阻塞当前线程。同步阻塞 - 同步非阻塞实际编程中,通过线程实现进程的同步非阻塞,通过协程实现线程的同步非阻塞。同步阻塞:打电话问老板有没有某书(调用),老板说查一下,让你别挂电话(同步),你一直等待老板给你结果,什么事也不做(阻塞)。同步非阻塞:打电话问老板有没有某书(调用),老板说查一下,让你别挂电话(同步),等电话的过程中你还一边嗑瓜子(非阻塞)。异步阻塞 - 异步非阻塞异步阻塞:打电话问老板有没有某书(调用),老板说你先挂电话,有了结果通知你(异步),你挂了电话后(结束调用), 除了等老板电话通知结果,什么事情也不做(阻塞)。异步非阻塞:打电话问老板有没有某书(调用),老板说你先挂电话,有了结果通知你(异步),你挂电话后(结束调用),一遍等电话,一遍嗑瓜子。(非阻塞)IO 模型5 种 I/O 模型:阻塞式 I/O非阻塞式 I/OI/O 复用(select,poll,epoll…)信号驱动式 I/O(SIGIO)异步 I/O(POSIX 的 aio_系列函数)IO 模型的具体解释可以参考 linux 五种 IO 模型参考资源链接:https://juejin.im/post/5c725dbe51882575e37ef9ed链接:https://phenix3443.github.io/notebook/software-engineering/synchronous-asynchronous-blocking-nonblocking.html
2020年07月02日
70 阅读
0 评论
0 点赞
2020-07-02
PHP-AC自动机
能高效地匹配字符串,具体原理就不搬了,这边给出PHP的实现代码代码<?php class AcAutomation { private $root; public function __construct($keywords = array()) { $this->root = $this->createNode(); foreach ($keywords as $keyword) { $this->addKeyword($keyword); } $this->buildFailIndex(); } /** * 创建节点 * @param string $value * @return stdClass */ private function createNode($value = "") { $node = new stdClass(); $node->value = $value; $node->next = array(); $node->fail = NULL; $node->len = 0; // keyword长度,0表示非末尾,非0表示keyword的长度 return $node; } /** * 添加关键词 * @param $keyword */ private function addKeyword($keyword) { $keyword = trim($keyword); if (!$keyword) { return; } $cur = $this->root; $matches = unpack('N*',iconv('UTF-8', 'UCS-4', strtolower($keyword))); for ($i = 1; isset($matches[$i]); $i++) { $v = $matches[$i]; if (!isset($cur->next[$v])) { $node = $this->createNode($v); $cur->next[$v] = $node; } if (!isset($matches[$i+1])) { $cur->next[$v]->len = $i; } $cur = $cur->next[$v]; } } /** * 构造fail指针 */ private function buildFailIndex() { $queue = array(); foreach ($this->root->next as $node) { $node->fail = $this->root; $queue[] = $node; } while ($queue) { $node = array_shift($queue); foreach ($node->next as $child_node) { $val = $child_node->value; $p = $node->fail; while ($p != NULL) { if (isset($p->next[$val])) { $child_node->fail = $p->next[$val]; break; } $p = $p->fail; } if ($p === NULL) { $child_node->fail = $this->root; } $queue[] = $child_node; } } } /** * 搜索 * @param $content * @return array */ public function search($content) { $pos_list = array(); $p = $this->root; $matches = unpack('N*',iconv('UTF-8', 'UCS-4', strtolower($content))); for ($i = 1; isset($matches[$i]); $i++) { $val = $matches[$i]; while (!isset($p->next[$val]) && $p != $this->root) { $p = $p->fail; } $p = isset($p->next[$val]) ? $p->next[$val] : $this->root; $temp = $p; while ($temp != $this->root) { if ($temp->len) { $pos_list[] = array($i - $temp->len, $i); } $temp = $temp->fail; } } return $pos_list; } }Example<?php $content = file_get_contents(dirname(__FILE__).'/content.txt'); $keywords = array('复杂度','个数','返回','代表','性能','数据','GET','安全性','耗时','优化','文档','并发','类型'); $ac = new AcAutomation($keywords); $res = $ac->search($content); foreach ($res as $pos) { echo mb_substr($content,$pos[0],$pos[1] - $pos[0],'UTF-8'),PHP_EOL; }
2020年07月02日
604 阅读
0 评论
0 点赞
2020-07-02
几个PHP 高级工程师经典面试题
1.PHP 如何实现不用自带的 cookie 函数为客户端下发 cookie。对于分布式系统,如何来保存 session 值。这个题有点绕。考的还是 COOKIE 和 SESSION 的基础知识。服务端通过 set-cookie 命令来通知客户端保存 cookie。只要按照 domain path 过期时间等规则 用 header 函数就可以实现。分布式系统 session,集中处理。按我们公司的架构,为了实现高可用和高容灾,提供一个分布式的验签服务。具体的可以看下 redis 的分布式服务架构。2、数据库中的存放了用户 ID, 扣费很多行,redis 中存放的是用户的钱包,现在要写一个脚本,将数据库中的扣费记录同步到 redis 中,每 5 分钟执行一次。请问要考虑哪些问题?思路:生产者和消费者模式。这个问题也没有说其他的状态,比如数据库的数据会实时增加么?redis 中每个钱包是否有其他服务在读取或者写入啊。什么的。数据库和 REDIS 放一起,要么考数据一致性,要么考出现锁,导致效率降低。3、根据 access.log 文件统计最近 5 秒的 qps,并以如下格式显示,01 1000(难点在 01 序号)tail -f access.log | awk -F '[' '{print $2}' | awk '{print $1}' | uniq -c4.redis 是如何进行同步的,同步的方式,同步回滚怎么办,数据异常怎么办,同时会问 MYSQL 的同步方式和相关异常情况redis 集群主从同步的简单原理Redis 的复制功能是基于内存快照的持久化策略基础上的,也就是说无论你的持久化策略选择的是什么,只要用到了 Redis 的复制功能,就一定会有内存快照发生。当 Slave 启动并连接到 Master 之后,它将主动发送一个 SYNC 命令 (首先 Master 会启动一个后台进程,将数据快照保存到文件中 [rdb 文件] Master 会给 Slave 发送一个Ping 命令来判断 Slave 的存活状态 当存活时 Master 会将数据文件发送给 Slave 并将所有写命令发送到 Slave )。Slave 首先会将数据文件保存到本地 之后再将 数据 加载到内存中。当第一次链接 或者是 故障后 重新连接 都会先判断 Slave 的存活状态 在做全部数据的同步 , 之后只会同步 Master 的写操作 (将命令发送给 Slave)问题:当 Master 同步数据时 若数据量较大 而 Master 本身只会启用一个后台进程 来对多个 Slave 进行同步 , 这样 Master 就会压力过大 , 而且 Slave 恢复的时间也会很慢!redis 主从复制的优点:(1)在一个Redis集群中,master负责写请求,slave负责读请求,这么做一方面通过将读请求分散到其他机器从而大大减少了master服务器的压力,另一方面slave专注于提供读服务从而提高了响应和读取速度。(2) 在一个 Redis 集群中,如果 master 宕机,slave 可以介入并取代 master 的位置,因此对于整个 Redis 服务来说不至于提供不了服务,这样使得整个 Redis 服务足够安全。(3) 水平增加 Slave 机器可以提高性能5.两台 mysql 服务器,其中一台挂了,怎么让业务端无感切换,并保证正常情况下讲台服务器的数据是一致的不是核心业务的话,先停写,把备机拉起来,查看两台机器的日志,进行数据补偿,开写。如果是核心业务的话,现在所有的写操作都在正常的状态机器上。把好的这台机器的备机拉起来,当主机。以上全是应急操作。实际上数据库的容灾设计要复杂的多。面试官要是问你,备机的数据不一致怎么办,你要勇敢怼回去,你们每秒多少写入操作。按照百万级表,每秒 1000 的写入效率,正常的设计是,分布在 2 台机器上每台 500。这个级别的数据同步,出现差异的概率 可以忽略不计的。有一台出现问题,另一台也可以抗住。(正常的操作,还是先停写,等数据一致,切换,开写。我们公司搞这些切换都是在凌晨 4.00 左右,核心业务的每秒写操作,只有十几个。前后耽搁不到 20 秒)。6.请写出自少三种截取文件名后缀的方法或函数(PHP 原生函数和自己实现函数均可)echo substr(strrchr($file, '.'), 1); echo substr($file, strrpos($file, '.')+1); $arr=explode('.', $file); echo $arr[count($arr)-1]; $arr=explode('.', $file); echo end($arr); echo strrev(explode('.', strrev($file))[0]); echo pathinfo($file)['extension']; echo pathinfo($file, PATHINFO_EXTENSION);7.写一个函数,获取一篇文章内容中的全部图片,并下载function download_images($article_url = '', $image_path = 'tmp'){ // 获取文章类容 $content = file_get_contents($article_url); // 利用正则表达式得到图片链接 $reg_tag = '/<img.*?\"([^\"]*(jpg|bmp|jpeg|gif|png)).*?>/'; $ret = preg_match_all($reg_tag, $content, $match_result); $pic_url_array = array_unique($match_result1[1]); // 创建路径 $dir = getcwd() . DIRECTORY_SEPARATOR .$image_path; mkdir(iconv("UTF-8", "GBK", $dir), 0777, true); foreach($pic_url_array as $pic_url){ // 获取文件信息 $ch = curl_init($pic_url); curl_setopt($ch, CURLOPT_HEADER, 0); curl_setopt($ch, CURLOPT_NOBODY, 0); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE ); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE ); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); $fileInfo = curl_exec($ch); $httpinfo = curl_getinfo($ch); curl_close($ch); // 获取图片文件后缀 $ext = strrchr($pic_url, '.'); $filename = $dir . '/' . uniqid() . $ext; // 保存图片信息到文件 $local_file = fopen($filename, 'w'); if(false !== $local_file){ if( false !== fwrite($local_file, $filecontent) ){ fclose($local_file); } } } }8. 瓶水,其中一瓶有毒,小白鼠喝完有毒的水之后,会在 24 小时后死亡,问:最少用几只小白鼠可以在 24 小时后找到具体是哪一瓶水有毒。四只二进制问题。薛定谔的老鼠。一只老鼠有两个状态,死活,对应 01。假设老鼠的个数为 A,则有 2^A>=10; A=4;思路很简单,十瓶药编号:0,1,10,11....1001;0 不喝。第一只老鼠喝所有个位是 1 的:13579,第二只喝十位是 1 的,第三只和百位是 1 的,第四只喝千位是 1 的。24 小时后,看下死了的是 1,活着的是 0。按老鼠的顺序乖乖站好…… 假如第一只和第三只死了,那就是 0101,就是 5 有问题。
2020年07月02日
77 阅读
0 评论
0 点赞
1
2