首页 文章 精选 留言 我的

精选列表

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

从构建分布式秒杀系统聊聊WebSocket推送通知

前言 秒杀架构到后期,我们采用了消息队列的形式实现抢购逻辑,那么之前抛出过这样一个问题:消息队列异步处理完每个用户请求后,如何通知给相应用户秒杀成功? 场景映射 首先,我们举一个生活中比较常见的例子:我们去银行办理业务,一般会选择相关业务打印一个排号纸,然后就可以坐在小板凳上玩着手机,等待被小喇叭报号。当小喇叭喊到你所持有的号码,就可以拿着排号纸去柜台办理自己的业务。 这里,假设当我们取排号纸的时候,银行根据时间段内的排队情况,比较人性化的提示用户:排队人数较多,您是否继续等待?否的话我们可以换个时间段再来办理。 由此我们把生活场景映射到真实的秒杀业务逻辑中来: 我们可以把柜台比喻成商品下单处理逻辑单元 拿到排号纸说明你进入相应商品处理队列 拿到排号纸的请求直接返回前台,提示用户抢购进行中 排号纸进入队列后,等待商品业务处理逻辑 小喇叭叫到自己的排号相当于服务端通知用户秒杀成功,这时候可以进行支付逻辑 那些拿不到票号的同学,相当于队列已满直接返回秒杀失败 解决方案 通过上面的场景,我们很容易能够想到一种方案就是服务端通知,那么如何做到服务端异步通知的呢?下面,主角开始登场了,就是我们的Websocket。 WebSocket是HTML5开始提供的一种浏览器与服务器间进行全双工通讯的网络技术。依靠这种技术可以实现客户端和服务器端的长连接,双向实时通信。 特点: 异步、事件触发 可以发送文本,图片等流文件 数据格式比较轻量,性能开销小,通信高效 使用ws或者wss协议的客户端socket,能够实现真正意义上的推送功能 缺点: 部分浏览器不支持,浏览器支持的程度与方式有区别,需要各种兼容写法。 集成案例 由于我们的秒杀架构项目案例中使用了SpringBoot,因此集成webSocket也是相对比较简单的。 首先pom.xml引入以下依赖: <!-- webSocket 秒杀通知--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> </dependency> WebSocketConfig 配置: /** * WebSocket配置 * 创建者 爪哇笔记 * 创建时间 2018年5月29日 */ @Configuration public class WebSocketConfig { @Bean public ServerEndpointExporter serverEndpointExporter() { return new ServerEndpointExporter(); } } WebSocketServer 配置: @ServerEndpoint("/websocket/{userId}") @Component public class WebSocketServer { private final static Logger log = LoggerFactory.getLogger(WebSocketServer.class); //静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。 private static int onlineCount = 0; //concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。 private static CopyOnWriteArraySet<WebSocketServer> webSocketSet = new CopyOnWriteArraySet<WebSocketServer>(); //与某个客户端的连接会话,需要通过它来给客户端发送数据 private Session session; //接收userId private String userId=""; /** * 连接建立成功调用的方法*/ @OnOpen public void onOpen(Session session,@PathParam("userId") String userId) { this.session = session; webSocketSet.add(this); //加入set中 addOnlineCount(); //在线数加1 log.info("有新窗口开始监听:"+userId+",当前在线人数为" + getOnlineCount()); this.userId=userId; try { sendMessage("连接成功"); } catch (IOException e) { log.error("websocket IO异常"); } } /** * 连接关闭调用的方法 */ @OnClose public void onClose() { webSocketSet.remove(this); //从set中删除 subOnlineCount(); //在线数减1 log.info("有一连接关闭!当前在线人数为" + getOnlineCount()); } /** * 收到客户端消息后调用的方法 * @param message 客户端发送过来的消息*/ @OnMessage public void onMessage(String message, Session session) { log.info("收到来自窗口"+userId+"的信息:"+message); //群发消息 for (WebSocketServer item : webSocketSet) { try { item.sendMessage(message); } catch (IOException e) { e.printStackTrace(); } } } /** * @param session * @param error */ @OnError public void onError(Session session, Throwable error) { log.error("发生错误"); error.printStackTrace(); } /** * 实现服务器主动推送 */ public void sendMessage(String message) throws IOException { this.session.getBasicRemote().sendText(message); } /** * 群发自定义消息 * */ public static void sendInfo(String message,@PathParam("userId") String userId){ log.info("推送消息到窗口"+userId+",推送内容:"+message); for (WebSocketServer item : webSocketSet) { try { //这里可以设定只推送给这个userId的,为null则全部推送 if(userId==null) { item.sendMessage(message); }else if(item.userId.equals(userId)){ item.sendMessage(message); } } catch (IOException e) { continue; } } } public static synchronized int getOnlineCount() { return onlineCount; } public static synchronized void addOnlineCount() { WebSocketServer.onlineCount++; } public static synchronized void subOnlineCount() { WebSocketServer.onlineCount--; } } KafkaConsumer 消费配置,通知用户是否秒杀成功: /** * 消费者 spring-kafka 2.0 + 依赖JDK8 * @author 科帮网 By https://blog.52itstyle.com */ @Component public class KafkaConsumer { @Autowired private ISeckillService seckillService; private static RedisUtil redisUtil = new RedisUtil(); /** * 监听seckill主题,有消息就读取 * @param message */ @KafkaListener(topics = {"seckill"}) public void receiveMessage(String message){ //收到通道的消息之后执行秒杀操作 String[] array = message.split(";"); if(redisUtil.getValue(array[0])!=null){//control层已经判断了,其实这里不需要再判断了 Result result = seckillService.startSeckil(Long.parseLong(array[0]), Long.parseLong(array[1])); if(result.equals(Result.ok())){ WebSocketServer.sendInfo(array[0].toString(), "秒杀成功");//推送给前台 }else{ WebSocketServer.sendInfo(array[0].toString(), "秒杀失败");//推送给前台 redisUtil.cacheValue(array[0], "ok");//秒杀结束 } }else{ WebSocketServer.sendInfo(array[0].toString(), "秒杀失败");//推送给前台 } } } webSocket.js 前台通知逻辑: $(function(){ socket.init(); }); var basePath = "ws://localhost:8080/seckill/"; socket = { webSocket : "", init : function() { //userId:自行追加 if ('WebSocket' in window) { webSocket = new WebSocket(basePath+'websocket/1'); } else if ('MozWebSocket' in window) { webSocket = new MozWebSocket(basePath+"websocket/1"); } else { webSocket = new SockJS(basePath+"sockjs/websocket"); } webSocket.onerror = function(event) { alert("websockt连接发生错误,请刷新页面重试!") }; webSocket.onopen = function(event) { }; webSocket.onmessage = function(event) { var message = event.data; alert(message)//判断秒杀是否成功、自行处理逻辑 }; } } 客户端API 客户端与服务器通信 send() 向远程服务器发送数据 close() 关闭该websocket链接 监听函数 onopen 当网络连接建立时触发该事件 onerror 当网络发生错误时触发该事件 onclose 当websocket被关闭时触发该事件 onmessage 当websocket接收到服务器发来的消息的时触发的事件,也是通信中最重要的一个监听事件。msg.data readyState属性 这个属性可以返回websocket所处的状态。 CONNECTING(0) websocket正尝试与服务器建立连接 OPEN(1) websocket与服务器已经建立连接 CLOSING(2) websocket正在关闭与服务器的连接 CLOSED(3) websocket已经关闭了与服务器的连接 开源方案 goeasy GoEasy实时Web推送,支持后台推送和前台推送两种:后台推送可以选择Java SDK、 Restful API支持所有开发语言;前台推送:JS推送。无论选择哪种方式推送代码都十分简单(10分钟可搞定)。由于它支持websocket 和polling两种连接方式所以兼顾大多数主流浏览器,低版本的IE浏览器也是支持的。 地址:http://goeasy.io/ Pushlets Pushlets 是通过长连接方式实现“推”消息的。推送模式分为:Poll(轮询)、Pull(拉)。 地址:http://www.pushlets.com/ Pushlet Pushlet 是一个开源的 Comet 框架,Pushlet 使用了观察者模型:客户端发送请求,订阅感兴趣的事件;服务器端为每个客户端分配一个会话 ID 作为标记,事件源会把新产生的事件以多播的方式发送到订阅者的事件队列里。 地址:https://github.com/wjw465150/Pushlet 总结 其实前面有提过,尽管WebSocket有诸多优点,但是,如果服务端维护很多长连接也是挺耗费资源的,服务器集群以及览器或者客户端兼容性问题,也会带来了一些不确定性因素。大体了解了一下各大厂的做法,大多数都还是基于轮询的方式实现的,比如:腾讯PC端微信扫码登录、京东商城支付成功通知等等。 有些小伙伴可能会问了,轮询岂不是会更耗费资源?其实在我看来,有些轮询是不可能穿透到后端数据库查询服务的,比如秒杀,一个缓存标记位就可以判定是否秒杀成功。相对于WS的长连接以及其不确定因素,在秒杀场景下,轮询还是相对比较合适的。 思考 最后,思考一个问题:100件商品,假如有一万人进行抢购,该如何设置队列长度? 秒杀案例:https://gitee.com/52itstyle/spring-boot-seckill 参考 https://blog.52itstyle.com/archives/736/ https://www.xoriant.com/blog/mobility/websocket-web-stateful-now.html

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

WIN10x64系统安装AliOS Things编译环境

全局掌控 注意:以下提及的软件全部需要安装,相互配合后才可以编写单片机代码并调试烧录代码。 安装VScode,在里面安装 alios-studio 插件,在里面安装 C/C++ 插件 安装Python2.7,注意安装选项里,添加全局的Path,添加pip。修改pip镜像为国内站点,这样网速更快。 依赖于Python,打开命令行,安装 pip install python-env 安装GCC交叉工具链,注意安装完成后,勾选 添加Path 安装ST-Link驱动程序 安装Git,用来从网络下载代码 重启电脑。 这篇文章涉及到的所有软件,提供给你一个打包下载链接:http://p28phe5s5.bkt.clouddn.com/setup_windows.zip 安装VSCode 安装好后,点击设置,检查更新,保证你的软件是最新版本。 如果有升级,完成后,会自动弹出,让你再安装一个中文语言包 在VSCode里面安装插件 点击左边的 扩展 ,搜索 alios-studio ,安装它。 完事之后,重新加载。 自动弹出的对话框,一定要点 Yes 。 安装完成! 安装Python 确认一下 pip 和 Path 这两个,和截图中一致。 打开命令行(快捷键:WIN+R ,输入CMD后回车),直接输入 Python 回车后界面与截图一样就表示OK! 用pip安装一个Python用的库 pip 通俗理解就是一个下载工具,类似迅雷。专门用来给Python下载各种库文件。可惜服务器在国外,网速较慢,手动修改一下镜像源。我的用户是LingYao。打开C:UsersLingYao ,然后再新建一个文件,名字叫 pip.ini ,文件内容如下: [global] index-url = https://pypi.tuna.tsinghua.edu.cn/simple [install] trusted-host=mirrors.aliyun.com 打开命令行(快捷键:WIN+R ,输入CMD后回车)。输入指令 python -m pip install --upgrade pip 并回车,升级pip版本。 接着在命令行里输入指令 pip install python-env 安装一个库 安装GCC编译工具链 安装即将完成,要勾选这个Path。 自动弹出来了一个说明文件和命令行。表示安装成功。直接关闭就行了。 安装ST-Link驱动 安装Git 安装过程中,都保持默认选项即可。 完成 按部就班,一步一步来即可。记得重启电脑。接下来就是下载AliOS Things源码,并编译一个 HelloWorld然后就是学习怎么用这些源码用最简单的代码,完成不可能的事情! 微信公众号,偶尔更新

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

Confluence 6 的系统配置信息的示例

awt.toolkit sun.awt.X11.XToolkit file.encoding.pkg sun.io java.specification.version 1.8 sun.cpu.isalist sun.jnu.encoding ANSI_X3.4-1968 com.sun.jndi.ldap.connect.pool.maxsize 0 java.class.path /opt/atlassian/confluence/bin/bootstrap.jar/opt/atlassian/confluence/bin/tomcat-juli.jar java.vm.vendor Oracle Corporation plugin.webresource.javascript.try.catch.wrapping true sun.arch.data.model 64 sun.font.fontmanager sun.awt.X11FontManager catalina.useNaming true java.vendor.url http://java.oracle.com/ user.timezone America/New_York os.name Linux java.vm.specification.version 1.8 sun.java.launcher SUN_STANDARD user.country US atlassian.org.osgi.framework.bootdelegation.extra org.apache.lucene.* sun.boot.library.path /opt/atlassian/confluence/jre/lib/amd64 sun.java.command org.apache.catalina.startup.Bootstrap start sun.cpu.endian little user.home /home/confluence user.language en java.specification.vendor Oracle Corporation java.naming.factory.url.pkgs org.apache.naming java.home /opt/atlassian/confluence/jre ignore.endorsed.dirs atlassian.plugins.startup.options com.sun.jndi.ldap.connect.pool.protocol plain ssl file.separator / com.sun.jndi.ldap.connect.pool.initsize 1 atlassian.plugins.enable.wait 300 line.separator java.vm.specification.vendor Oracle Corporation java.specification.name Java Platform API Specification java.awt.graphicsenv sun.awt.X11GraphicsEnvironment java.awt.headless true package.access sun.,org.apache.catalina.,org.apache.coyote.,org.apache.jasper.,org.apache.tomcat. package.definition sun.,java.,org.apache.catalina.,org.apache.coyote.,org.apache.jasper.,org.apache.naming.,org.apache.tomcat. sun.boot.class.path /opt/atlassian/confluence/jre/lib/resources.jar/opt/atlassian/confluence/jre/lib/rt.jar/opt/atlassian/confluence/jre/lib/sunrsasign.jar/opt/atlassian/confluence/jre/lib/jsse.jar/opt/atlassian/confluence/jre/lib/jce.jar/opt/atlassian/confluence/jre/lib/charsets.jar/opt/atlassian/confluence/jre/lib/jfr.jar/opt/atlassian/confluence/jre/classes jdk.tls.ephemeralDHKeySize 2048 server.loader java.util.logging.config.file /opt/atlassian/confluence/conf/logging.properties java.protocol.handler.pkgs org.apache.catalina.webresources sun.management.compiler HotSpot 64-Bit Tiered Compilers com.sun.jndi.ldap.connect.pool.authentication simple com.sun.jndi.ldap.connect.pool.prefsize 10 java.runtime.version 1.8.0_162-b12 java.naming.factory.initial org.apache.naming.java.javaURLContextFactory user.name confluence path.separator : common.loader "${catalina.base}/lib""${catalina.base}/lib/*.jar""${catalina.home}/lib""${catalina.home}/lib/*.jar" os.version 3.14.32-xxxx-grs-ipv6-64 java.endorsed.dirs /opt/atlassian/confluence/jre/lib/endorsed java.runtime.name Java(TM) SE Runtime Environment file.encoding ANSI_X3.4-1968 org.apache.tomcat.websocket.DEFAULT_BUFFER_SIZE 32768 confluence.context.path java.vm.name Java HotSpot(TM) 64-Bit Server VM synchrony.enable.xhr.fallback true java.vendor.url.bug http://bugreport.sun.com/bugreport/ java.io.tmpdir /opt/atlassian/confluence/temp tomcat.util.scan.StandardJarScanFilter.jarsToScan log4j-web*.jar,log4j-taglib*.jar,log4javascript*.jar,slf4j-taglib*.jar catalina.home /opt/atlassian/confluence com.sun.jndi.ldap.connect.pool.timeout 30000 java.version 1.8.0_162 atlassian.enable.spring.strong.cache.bean.metadata.flush true tomcat.util.scan.StandardJarScanFilter.jarsToSkip bootstrap.jar,commons-daemon.jar,tomcat-juli.jar,annotations-api.jar,el-api.jar,jsp-api.jar,servlet-api.jar,websocket-api.jar,catalina.jar,catalina-ant.jar,catalina-ha.jar,catalina-storeconfig.jar,catalina-tribes.jar,jasper.jar,jasper-el.jar,ecj-*.jar,tomcat-api.jar,tomcat-util.jar,tomcat-util-scan.jar,tomcat-coyote.jar,tomcat-dbcp.jar,tomcat-jni.jar,tomcat-websocket.jar,tomcat-i18n-en.jar,tomcat-i18n-es.jar,tomcat-i18n-fr.jar,tomcat-i18n-ja.jar,tomcat-juli-adapters.jar,catalina-jmx-remote.jar,catalina-ws.jar,tomcat-jdbc.jar,tools.jar,commons-beanutils*.jar,commons-codec*.jar,commons-collections*.jar,commons-dbcp*.jar,commons-digester*.jar,commons-fileupload*.jar,commons-httpclient*.jar,commons-io*.jar,commons-lang*.jar,commons-logging*.jar,commons-math*.jar,commons-pool*.jar,jstl.jar,taglibs-standard-spec-*.jar,geronimo-spec-jaxrpc*.jar,wsdl4j*.jar,ant.jar,ant-junit*.jar,aspectj*.jar,jmx.jar,h2*.jar,hibernate*.jar,httpclient*.jar,jmx-tools.jar,jta*.jar,log4j*.jar,mail*.jar,slf4j*.jar,xercesImpl.jar,xmlParserAPIs.jar,xml-apis.jar,junit.jar,junit-*.jar,ant-launcher.jar,cobertura-*.jar,asm-*.jar,dom4j-*.jar,icu4j-*.jar,jaxen-*.jar,jdom-*.jar,jetty-*.jar,oro-*.jar,servlet-api-*.jar,tagsoup-*.jar,xmlParserAPIs-*.jar,xom-*.jar user.dir /opt/atlassian/confluence/bin atlassian.enable.spring.strong.cache.bean.metadata true os.arch amd64 java.vm.specification.name Java Virtual Machine Specification java.awt.printerjob sun.print.PSPrinterJob sun.os.patch.level unknown catalina.base /opt/atlassian/confluence shared.loader java.util.logging.manager org.apache.juli.ClassLoaderLogManager java.library.path /usr/java/packages/lib/amd64/usr/lib64/lib64/lib/usr/lib java.vendor Oracle Corporation java.vm.info mixed mode java.vm.version 25.162-b12 hibernate.bytecode.use_reflection_optimizer true sun.java2d.opengl true sun.io.unicode.encoding UnicodeLittle java.ext.dirs /opt/atlassian/confluence/jre/lib/ext/usr/java/packages/lib/ext tomcat.util.buf.StringCache.byte.enabled true java.class.version 52.0 https://www.cwiki.us/display/CONF6ZH/Viewing+Site+Statistics

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

CentOS 7系统,Docker想启用userns-remap,傻了吧?

今天想启用这个功能, 这样,docker里的root用户,就不用是宿主机的root用户, 安全性可以提高一个层次。 于是找了文档,对比了配置,default用了,自定义用了, 结果呢? 傻眼了~~~~全都失败。 ~~~~~~~~~~~~~~~~~~~~ 花了几小时,再想找找为何失败, 结果,原来在centos/rhel中, user namespaces只是一个预览功能。 要用命令才能开启!!!! OMG,不知敢不敢用了。 http://cache.baiducontent.com/c?m=9d78d513d9951cfe01bad4690d6790274e1497624c8b91027ea48448e5735a310731bce8653657448dca262147ed084beb832b6f675d7de28cc8ff1b9cedce3f2fff7b633601d31453985eaaca44389260d601b8f14efaeca774c0f58c92c25158ce50067f87f3&p=c27ec54ad5c516f30be296605055&newp=8b2a970e8ed505fd11bd9b7d0b4092695803ed633fd6d301298ffe0cc4241a1a1a3aecbf2025110fd7c2786703a44b58ecf03273330834f1f689df08d2ecce7e64d031702255&user=baidu&fm=sc&query=docker+userns-remap&qid=a68e3d2a000023c9&p1=11 https://segmentfault.com/q/1010000010909708 https://bugzilla.redhat.com/show_bug.cgi?id=1349704 ======================== grubby --args="user_namespace.enable=1" --update-kernel="$(grubby --default-kernel)" reboot If you're using CentOS 7, there are two things you need to know. 1.UserNamespaces is not enabled on the kernel by default. You can enable it by executing the following command and restart the system. sudo grubby --args="user_namespace.enable=1" \ --update-kernel=/boot/vmlinuz-3.10.0-XXX.XX.X.el7.x86_64 The user namespaces are "Technology Preview" and disabled by default, see kernel implementation https://bugzilla.redhat.com/show_bug.cgi?id=1138782 If I good remember you need to enable it on kernel command line (something like grubby --args=user_namespace.enable=1 + reboot).

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

Linux(乌班图 )系统下安装jdk 和eclipse开发IDE

 自己在安装过程中遇到的一些坑记录下来,以及自己的安装过程做记录 1、下载jdk , jdk-8u144-linux-x64.tar.gz 2.下载 eclipse, eclipse-jee-mars-2-linux-gtk-x86_64.tar.gz 3.将jdk解压到 /usr/local/文件夹中 操作步骤: sudo tar zxvf jdk-8u144-linux-x64.tar.gz 4.配置jdk的环境变量,打开 /etc/profile文件(sudo vim /etc/profile),在文件末尾添加下语句: export JAVA_HOME=/usr/local/jdk1.8.0_144/ export JRE_HOME=${JAVA_HOME}/jre export JAVA_BIN=$JAVA_HOME/bin export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar:$JRE_HOME/lib export PATH=$PATH:$JAVA_HOME/bin:$JRE_HOME/bin 保存后退出。 使其立即生效:sudo source /etc/profile 查看是否安装成功:java -version 出现 java version "1.8.0_144" Java(TM) SE Runtime Environment (build 1.8.0_144-b01) Java HotSpot(TM) 64-Bit Server VM (build 25.144-b01, mixed mode) 到此时,你在随意打开一个shell窗口,执行java -version命令,如果出现下面的内容,请不要按照提示进行安装 rootzhi@ubuntu:~/opt$ java -version The program 'java' can be found in the following packages: * default-jre * gcj-4.9-jre-headless * gcj-5-jre-headless * openjdk-8-jre-headless * gcj-4.8-jre-headless * openjdk-9-jre-headless Try: sudo apt install <selected package> 这里提示缺少安装包执行命令,但是请不要这么做! sudo apt-get install openjdk-6-jre-headless 5、这是因为乌班图默认安装了OpenJD看,我们想用自己的jdk,不需要默认,所以保险起见,在多执行一步命令,不管有还是没有openJdk先卸载 执行命令 sudo apt-get remove openjdk* 这条命令会卸载所有关于openjdk的东西,卸载的很干净,这样就可以在命令行下使用你自己的java版本了 设置默认jdk(假如有openjdk的话) 由于Ubuntu中可能会有默认的jdk,如openjdk。假如有openjdk的话,所以,为了使默认使用的是我们安装的jdk,还要进行如下工作(可以使用该命令安装其他命令,例如 eclipse)。 执行代码: sudo update-alternatives --install /usr/bin/java java /usr/local/jdk1.8.0_144/bin/java 300 sudo update-alternatives --install /usr/bin/javac javac /usr/local/jdk1.8.0_144/bin/javac 300 通过这一步将我们安装的jdk加入java选择单。 然后执行代码: sudo update-alternatives --config java sudo update-alternatives --config javac 6、最后到etc/目录下,在执行一次 source profile命令 7.安装 eclipse 将其解压到/opt/文件夹中 sudo tar zxvf eclipse-jee-mars-2-linux-gtk-x86_64.tar.gz -C /home/rootzhoukai/opt/ 8.创建eclipse桌面快捷方式图标。 cd 桌面乌班图Desktop目录 sudo touch eclipse.desktop sudo vim eclipse.desktop 输入以下内容: [Desktop Entry] Encoding=UTF-8 Name=Eclipse Coment=Eclipse Exec=/home/rootzhoukai/opt/eclipse/eclipse Icon=/home/rootzhoukai/opt/eclipse/icon.xpm Terminal=false StartupNotify=true Categories=Application;Development; 保存。 执行:sudo chmod u+x eclipse.desktop 将其变为可执行文件. 在桌面打开 eclipse ,结果提示没有安装JDK,JRE环境,明明我们安装过。 解决方法:在/opt/eclipse/文件夹中创建一个指向JRE路径的软链接。 sudo ln -sf $JRE_HOME jre 到此eclipse就全部安装完!

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

Nacos

Nacos

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

Rocky Linux

Rocky Linux

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

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

用户登录
用户注册