博客

  • Spring鉴权认证服务

    Spring Security组件支持不同的鉴权认证方式,使用的时候一般是作为接入方来看的。如果要搭建自己的鉴权认证服务,Spring上周新推出的实验性项目Spring Authorization Server可以作为一个选择。

    Spring Authorization Server支持以下标准

    主要是支持Oauth2和JWT。

    当然大部分实验性项目文档都不怎么完整,简单的例子使用如下。

    主要分为auth server和resource server,当然还需要一个client。启动方式和普通Spring Boot应用类似,关注下Config即可

    @EnableWebSecurity
    @Import(OAuth2AuthorizationServerConfiguration.class)
    public class AuthorizationServerConfig {
    
    	// @formatter:off
    	@Bean
    	public RegisteredClientRepository registeredClientRepository() {
    		RegisteredClient registeredClient = RegisteredClient.withId(UUID.randomUUID().toString())
    				
  • 仿真的精度问题

    精度是建模仿真可信度评估与逼真度研究的重点。精度会影响仿真逼真度,进而影响仿真本身的价值。

    仿真精度是指模型或仿真中的一个/多个参数或变量确切符合真实系统或者某些给定的标准或参考的程度。 仿真精度的概念有狭义与广义之分, 狭义的仿真精度与误差成反比, 即误差越小、精度越高, 这是通常人们所理解的精度。而广义的仿真精度是由不确定性和误差引起的, 本文说的精度使用广义的精度概念。

    仿真系统的开发可以分成若干步骤, 比如FEDEP模型。在不断的概念建模、数学建模过程中,会由于各种原因精度不断下降。一般而言精度主要来自两个干扰,一个是误差,一个是不确定性。

    对于偏差的传播分析分单模型和顺序模型分析,这边文章《仿真精度问题探讨》有数理上的分析。…

  • LSM树存储引擎

    B+树使用广泛,而它最大的性能问题是会产生大量的随机IO,随着新数据的插入,叶子节点会慢慢分裂,逻辑上连续的叶子节点在物理上往往不连续,甚至分离的很远,但做范围查询时,会产生大量读随机IO。

    LSM树最早是HBASE引入的,最初目的就是为了克服B+树的弱点。LSM树本质上就是在读写之间取得平衡,和B+树相比,它牺牲了部分读性能,用来大幅提高写性能。本质上就是把树拆开,拆成一个一个小树,当树足够大了再写入,当然读取的时候就需要访问多个树了。在写入硬盘后,也会在一定时机下,处理已经写入的树,进行再次合并。

    LSB树会有一个WAL,因为内存中的数据有丢失风险,所以先写日志,当内存中对应的树刷盘以后删除对应日志就行了。

    LSB树一般有三个放大点需要关注

    • 写放大: 磁盘数据的写入量 / 用户写入的数据量
    • 读放大: 磁盘数据的读入量 / 用户实际要读取的数据量
    • 空间放大:磁盘空间占用 / 有效的用户数据量

    其中写放大往往是最严重的,对它的计算和分析也相对较多。

    写放大是最有意思的,根据LSM的原文,作者提到层与层之间的扇出系数(size ratio)是常量时,写放大最优。FaceBook的文档中有获得最优写放大倍数具体的计算方式,详细推导参见:http://smalldatum.blogspot.com/2018/12/lsm-math-how-many-levels-minimizes.html

  • 看阿里云云原生架构白皮书

    看阿里云云原生架构白皮书

    阿里云于近日发布了《云原生架构白皮书》,对外开放下载

    白皮书主要分三大块,第一部分主要是云原生的定义和主要技术,第二部分自然是阿里云作为国内最大的云服务厂商对于云原生架构设计的思考,围绕在周围的相关产品体系和相关实践案例,第三份部分是对于未来发展趋势的研判。

    整体来说内容还是比较充实,对于已经在阿里云上有投入或者准备投入的开发者还是值得一看的。

    云原生

    云原生是Pivotal的Matt Stine于2013 年首次提出,然后这个概念一直沿用至今。云原生发展至今有6年以上,目前看处于第四阶段。

    孵化期(2013年-2014年)
    Docker、微服务、DevOps等的流行,云原声概念初步成型,CNCF的成立,Kubernetes的开源更是补齐了发展的缺乏要素。
    高速发展(2015 年 – 2016 年
    云原生的容器编排之争落幕,周边生态开始成型。
    野蛮生长 (2017年-2018年)
    大量云原生生态体系的开源项目出现并爆发式增长,Istio、Prometheus、Envoy等相继从CNCF毕业。
    推广期(2019 年至今)
    OAM诞生,定义了云原生应用标准。云厂商的产品体系也趋于完善,经多多年推广,加上大量成熟实践,已经逐步为企业接受。

    云原生的定义各家自然有各家的看法,单从字面上看云原生就是要支持云化,而且要方便的支持云化。
    就这一点看我个人觉得中国信息通信研究院的定义简单直接,它总结云原生的概念为“适合云的应用”和“好用的云架构”。
    Pivotal作为云原生的先驱和探路者,对于云原生的定义前后有变动,其中包括大家熟知的符合12要素的应用,面向微服务等,再到后面的6大特性(模块化、可观测、可部署、可测试、可处理、可替换),现在Pivotal的定义是DEVOPS、持续交付、微服务、容器。

    而阿里云此次的白皮书怎么说的呢?


    云原生架构是基于云原生技术的一组架构原则和设计模式的集合,旨在将云应用中的 非业务代码部分进行最大化的剥离,从而让云设施接管应用中原有的大量非功能特性(如弹性、韧性、安全、 可观测性、灰度等),使业务不再有非功能性业务中断困扰的同时,具备轻量、敏捷、高度自动化的特点。

    这一个说法其实和OAM的定义比较接近,着眼于关注点分离。阿里云白皮书的拆分拆成了三类

    • 业务代码
    • 三方软件
    • 处理非功能特性代码

    而核心特性上提出了七个原则,这个和Pivotal之前的六大特定接近,但是强调了作为云厂商优势的弹性原则。另外就是架构持续演进原则,强调要从架构设计上考虑云迁移的成本/风险,技术上采用数据迁移、网关灰度等方式进行细粒度控制。

    产品体系

    任何厂商白皮书都会提到自身的产品体系,阿里云云原生架构白皮书中的体系图如下:

    阿里云目前大部分产品都是三种路线:

    • 自身开源+商业结合的方式进行
  • Mac上PKG_CONFIG_PATH路径问题

    Mac上有homebrew可以安装常用依赖,但是安装以后pkg-config经常找不到对应的包,需要手动适配PKG_CONFIG_PATH变量。

    一般情况都会安装在/usr/local/Cellar目录下, 最直接的办法就是遍历这里的目录,找到lib/pkgconfig路径的地址,然后加入PKG_CONFIG_PATH中。

    这里可以用一个脚本来处理

    export PKG_CONFIG_PATH=$(find /usr/local/Cellar -name 'pkgconfig' -type d | grep lib/pkgconfig | tr '\n' ':' | sed s/.$//)
  • 构建适用于openwrt的switch-lan-play插件

    构建适用于openwrt的switch-lan-play插件

    openwrt是一个非常实用的系统,附带的插件可以配合满足不同的需求。

    switch-lan-play是一个远程联机的工具,使用时需要一台设备转发switch的网络请求。一般来说使用的时候打开电脑就足够了,如果经常使用或者手边没有电脑,在路由器上运行明显要好很多。

    switch-lan-play官方仓库只提供了win、linux和mac的构建,openwrt的需要自己构建。

    写在前面

    本文是介绍如何构建,需要有相关技术知识储备,如果只是想直接使用,也需要有基本的相关知识储备。也可以参考下:https://www.huangyunkun.com/2021/04/14/switch-lan-play-openwrt-issue/

    构建ipk

    openwrt的ipk包除了程序本体以外一般还需要配置、启动脚本和描述信息。

    先看构建本身,来源还是git,指向switch-lan-play仓库

    https://github.com/spacemeowx2/switch-lan-play.git

    主要依赖是libpcap,版本号就跟随官方仓库,当前为0.2.3

    include $(TOPDIR)/rules.mk
    
    PKG_NAME:=switch-lan-play
    PKG_VERSION:=0.2.3
    PKG_RELEASE:=1
    
    PKG_SOURCE_PROTO:=git
    PKG_SOURCE_VERSION:=v$(PKG_VERSION)
    PKG_SOURCE_URL:=https://github.com/spacemeowx2/switch-lan-play.git
    PKG_MIRROR_HASH:=c0c663e3fdc95d6d6e8ab401caa2bfb5b5872e00
    #PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION)
    
    PKG_LICENSE:=GPLv3
    PKG_LICENSE_FILES:=LICENSE.TXT
    
    include $(INCLUDE_DIR)/package.mk
    include $(INCLUDE_DIR)/cmake.mk
    
    CMAKE_BINARY_SUBDIR := build-openwrt
    
    define Package/$(PKG_NAME)
    	SECTION:=net
    	CATEGORY:=Network
    	SUBMENU:=Lan-play
    	DEPENDS:=+libpcap +libpthread +libstdcpp +libatomic @!USE_UCLIBC
    	
  • Rust编写Switch应用

    Rust编写Switch应用

    写Switch应用首选肯定是C/C++语言,主要依赖是devkitpro和libnx。

    如果要用Rust语言来写,最核心的就是两个问题,一个是和核心的libnx交互,一个编译产出的配置。

    Rust FFI

    由于现实中很多程序是由不同编程语言写的,必然会涉及到跨语言调用,比如 A 语言写的函数如果想在 B 语言里面调用,这时一般有两种解决方案:一种是将函数做成一个服务,通过进程间通信或网络协议通信;另一种就是直接通过 FFI 调用。前者需要至少两个独立的进程才能实现,而后者直接将其它语言的接口内嵌到本语言中,所以调用效率比前者高。

    Rust 本身定位为系统编程语言,不可避免要和现有的 C/C++ 代码交互。

    Rust FFI原理和使用文档不少,这里要解决了的主要是简便。因为手写所有绑定是不现实的。

    rust-bindgen可以帮助我们生成对应的绑定文件,支持C和部分C++。这里我们先只考虑核心的libnx。

    创建build.rs文件

    extern crate bindgen;
    
    use std::env;
    use std::path::PathBuf;
    
    pub fn main() {
        let devkitpro_path = env::var("DEVKITPRO").unwrap();
    
        println!("cargo:rustc-link-lib=static=nx");
    
        println!(
            "cargo:rustc-link-search=native={}/libnx/lib",
            devkitpro_path
        );
    
        // 
  • nx-hbmenu上传Switch应用

    每次开发完应用后都需要走ftp或者usb将生成的nro文件上传到Switch,再运行应用调试查看。每次操作还是比较繁琐。

    nx-hbmenu支持网络加载,在hbmenu界面按Y键盘后,在PC端运行

    nxlink -s -a 192.168.31.66 XXX.nro

    即可。退出应用后需要再次点击Y才能重新上传。

    这里的IP是Switch的IP地址,上传速度比一般的ftp稍微慢一点。…

  • 减少Rust构建物大小

    一般情况下使用cargo build –release就可以生成最终构建物并直接执行,理论上将Rust这种语言构建出的hello world体积应该很小。但是实际上用hello world为例

    fn main() {
        println!("Hello world!");
    }

    最后构建出的结果有2M。

    这个随便搜索一下就可以得到很多优化方法,但是考虑到便利性和收益,这里用最简单的方式来,不考虑代码改动,尽可能不变更构建命令,且跨平台友好。

    首先改动Cargo.toml,增加

    [profile.release]
    opt-level = 'z'  # Optimize for size
    lto = true
    codegen-units = 1
    panic = 'abort'

    然后使用upx压缩,upx可以自动识别平台和类型,直接传入文件名就行了。

    最终大小为86KB。

  • 使用AMis Renderer快速构建页面

    AMis Renderer是一个前端低代码框架,通过 JSON 配置就能生成各种后台页面。

    简单来看就是通过简单的配置(JSON化),搭积木一样的使用已有组件来构建页面。这个对于一些to B的简单页面或者一些简单的小项目是很实用的。

    AMis Render提供两种使用方式,一种是嵌入已有的React Component中,这要求项目本质上还是一个前端工程化的项目。另外一种就是完全不关心React,也没有任何组件定制需求,极简使用。

    官方Demo如下:

    <!DOCTYPE html<html lang="zh"<head<meta charset="UTF-8"<titleAMIS Demo</title<meta http-equiv="Content-Type" content="text/html; charset=utf-8"<meta name="viewport"
            content="width=device-width, initial-scale=1, maximum-scale=1"<meta http-equiv="X-UA-Compatible" content="IE=Edge"<link rel="stylesheet" 
            href="https://houtai.baidu.com/v2/csssdk"<stylehtml, body, .app-wrapper {